소스 검색

ignore idea

haitao 9 달 전
부모
커밋
7b3b4fb044
79개의 변경된 파일22176개의 추가작업 그리고 12개의 파일을 삭제
  1. 0 0
      .clion.source.upload.marker
  2. 1 2
      .gitignore
  3. 9 0
      CMakeLists.txt
  4. 6 0
      cmake-build-debug/CMakeCache.txt
  5. 1 1
      cmake-build-debug/mqtt/common/source/CMakeFiles/mqtt_common.dir/flags.make
  6. 1 1
      cmake-build-debug/mqtt/log/source/CMakeFiles/mqtt_log.dir/flags.make
  7. 1 1
      cmake-build-debug/mqtt/mbedtls/CMakeFiles/mqtt_mbedtls.dir/flags.make
  8. 1 1
      cmake-build-debug/mqtt/mqtt/source/CMakeFiles/mqtt.dir/flags.make
  9. 1 1
      cmake-build-debug/mqtt/mqttclient/source/CMakeFiles/mqtt_client.dir/flags.make
  10. 1 1
      cmake-build-debug/mqtt/network/source/CMakeFiles/mqtt_network.dir/flags.make
  11. 42 0
      cmake-build-debug/mqtt/platform/source/CMakeFiles/mqtt_platform.dir/C.includecache
  12. 1 1
      cmake-build-debug/mqtt/platform/source/CMakeFiles/mqtt_platform.dir/flags.make
  13. 1 1
      cmake-build-debug/mqtt/sys_mqtt/source/CMakeFiles/sys_mqtt.dir/flags.make
  14. 1 1
      cmake-build-debug/system/CMakeFiles/mqtt_test.dir/flags.make
  15. 1 1
      cmake-build-debug/system/CMakeFiles/mqtt_test.dir/link.txt
  16. 11 0
      sx1302/CMakeLists.txt
  17. 17 0
      sx1302/include/config.h
  18. 43 0
      sx1302/include/loragw_ad5338r.h
  19. 84 0
      sx1302/include/loragw_agc_params.h
  20. 134 0
      sx1302/include/loragw_aux.h
  21. 59 0
      sx1302/include/loragw_cal.h
  22. 123 0
      sx1302/include/loragw_com.h
  23. 62 0
      sx1302/include/loragw_debug.h
  24. 596 0
      sx1302/include/loragw_hal.h
  25. 85 0
      sx1302/include/loragw_i2c.h
  26. 65 0
      sx1302/include/loragw_lbt.h
  27. 195 0
      sx1302/include/loragw_mcu.h
  28. 1503 0
      sx1302/include/loragw_reg.h
  29. 113 0
      sx1302/include/loragw_spi.h
  30. 65 0
      sx1302/include/loragw_stts751.h
  31. 49 0
      sx1302/include/loragw_sx1250.h
  32. 148 0
      sx1302/include/loragw_sx125x.h
  33. 66 0
      sx1302/include/loragw_sx1261.h
  34. 456 0
      sx1302/include/loragw_sx1302.h
  35. 121 0
      sx1302/include/loragw_sx1302_rx.h
  36. 148 0
      sx1302/include/loragw_sx1302_timestamp.h
  37. 98 0
      sx1302/include/loragw_usb.h
  38. 46 0
      sx1302/include/sx1250_com.h
  39. 93 0
      sx1302/include/sx1250_defs.h
  40. 45 0
      sx1302/include/sx1250_spi.h
  41. 45 0
      sx1302/include/sx1250_usb.h
  42. 45 0
      sx1302/include/sx125x_com.h
  43. 43 0
      sx1302/include/sx125x_spi.h
  44. 73 0
      sx1302/include/sx1261_com.h
  45. 109 0
      sx1302/include/sx1261_defs.h
  46. 247 0
      sx1302/include/tinymt32.h
  47. 515 0
      sx1302/readme.md
  48. 515 0
      sx1302/source/agc_fw_sx1250.var
  49. 515 0
      sx1302/source/agc_fw_sx1257.var
  50. 515 0
      sx1302/source/arb_fw.var
  51. 515 0
      sx1302/source/cal_fw.var
  52. 93 0
      sx1302/source/loragw_ad5338r.c
  53. 218 0
      sx1302/source/loragw_aux.c
  54. 1037 0
      sx1302/source/loragw_cal.c
  55. 383 0
      sx1302/source/loragw_com.c
  56. 183 0
      sx1302/source/loragw_debug.c
  57. 1701 0
      sx1302/source/loragw_hal.c
  58. 180 0
      sx1302/source/loragw_i2c.c
  59. 235 0
      sx1302/source/loragw_lbt.c
  60. 694 0
      sx1302/source/loragw_mcu.c
  61. 1423 0
      sx1302/source/loragw_reg.c
  62. 382 0
      sx1302/source/loragw_spi.c
  63. 183 0
      sx1302/source/loragw_stts751.c
  64. 261 0
      sx1302/source/loragw_sx1250.c
  65. 295 0
      sx1302/source/loragw_sx125x.c
  66. 687 0
      sx1302/source/loragw_sx1261.c
  67. 2826 0
      sx1302/source/loragw_sx1302.c
  68. 426 0
      sx1302/source/loragw_sx1302_rx.c
  69. 634 0
      sx1302/source/loragw_sx1302_timestamp.c
  70. 505 0
      sx1302/source/loragw_usb.c
  71. 94 0
      sx1302/source/sx1250_com.c
  72. 146 0
      sx1302/source/sx1250_spi.c
  73. 134 0
      sx1302/source/sx1250_usb.c
  74. 98 0
      sx1302/source/sx125x_com.c
  75. 140 0
      sx1302/source/sx125x_spi.c
  76. 390 0
      sx1302/source/sx1261_pram.var
  77. 438 0
      sx1302/source/test_loragw_hal_rx.c
  78. 615 0
      sx1302/source/test_loragw_hal_tx.c
  79. 145 0
      sx1302/source/tinymt32.c

+ 0 - 0
.clion.source.upload.marker


+ 1 - 2
.gitignore

@@ -8,7 +8,6 @@
 # Precompiled Headers
 *.gch
 *.pch
-
 # Libraries
 *.lib
 *.a
@@ -22,7 +21,6 @@
 *.dylib
 
 # Executables
-*.exe
 *.out
 *.app
 *.i*86
@@ -34,6 +32,7 @@
 
 .vscode/
 build/
+cmake-build-debug/
 libmqttclient/
 mqtt-client/
 *.deb

+ 9 - 0
CMakeLists.txt

@@ -1,5 +1,6 @@
 cmake_minimum_required(VERSION 3.15)
 project(lora_sx1302)
+set (CMAKE_C_FLAGS "-std=c99")
 # 设置版本信息
 set(PROJECT_MAJOR_VERSION 1) # 架版本信息
 set(PROJECT_MINOR_VERSION 2) # 主版本信息
@@ -12,12 +13,20 @@ set(PROJECT_VERSION ${PROJECT_MAJOR_VERSION}.${PROJECT_MINOR_VERSION}.${PROJECT_
 set(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 set(EXECUTABLE_OUTPUT_PATH ${PROJECT_ROOT_DIR}/build/bin)       #设置可执行文件的输出目录
 set(LIBRARY_OUTPUT_PATH ${PROJECT_ROOT_DIR}/build/lib)           #设置库文件的输出目录
+
 #MQTT提供给外部掉用的头文件路径和供第三方打包使用源文件路径
 set(MQTT_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mqtt/sys_mqtt/include)
 set(MQTT_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/mqtt/sys_mqtt/source)
 set(LIB_SYSTEM_MQTT sys_mqtt)
 
+#sx1302的库
+set(SX1302_)
+
+
+
+
 set(EXENAME mqtt_test)
 
 add_subdirectory(mqtt)
+#add_subdirectory(sx1302)硬件无暂时注释
 add_subdirectory(system)

+ 6 - 0
cmake-build-debug/CMakeCache.txt

@@ -217,6 +217,12 @@ ProcessorCount_cmd_nproc:FILEPATH=/usr/bin/nproc
 //Path to a program.
 ProcessorCount_cmd_sysctl:FILEPATH=/sbin/sysctl
 
+//Value Computed by CMake
+lora-sx1302_BINARY_DIR:STATIC=/home/book/hisi3518_lora/cmake-build-debug/sx1302
+
+//Value Computed by CMake
+lora-sx1302_SOURCE_DIR:STATIC=/home/book/hisi3518_lora/sx1302
+
 //Value Computed by CMake
 lora_sx1302_BINARY_DIR:STATIC=/home/book/hisi3518_lora/cmake-build-debug
 

+ 1 - 1
cmake-build-debug/mqtt/common/source/CMakeFiles/mqtt_common.dir/flags.make

@@ -2,7 +2,7 @@
 # Generated by "Unix Makefiles" Generator, CMake Version 3.15
 
 # compile C with /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc
-C_FLAGS = -g  
+C_FLAGS = -std=c99 -g  
 
 C_DEFINES = 
 

+ 1 - 1
cmake-build-debug/mqtt/log/source/CMakeFiles/mqtt_log.dir/flags.make

@@ -2,7 +2,7 @@
 # Generated by "Unix Makefiles" Generator, CMake Version 3.15
 
 # compile C with /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc
-C_FLAGS = -g  
+C_FLAGS = -std=c99 -g  
 
 C_DEFINES = 
 

+ 1 - 1
cmake-build-debug/mqtt/mbedtls/CMakeFiles/mqtt_mbedtls.dir/flags.make

@@ -2,7 +2,7 @@
 # Generated by "Unix Makefiles" Generator, CMake Version 3.15
 
 # compile C with /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc
-C_FLAGS = -g  
+C_FLAGS = -std=c99 -g  
 
 C_DEFINES = 
 

+ 1 - 1
cmake-build-debug/mqtt/mqtt/source/CMakeFiles/mqtt.dir/flags.make

@@ -2,7 +2,7 @@
 # Generated by "Unix Makefiles" Generator, CMake Version 3.15
 
 # compile C with /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc
-C_FLAGS = -g  
+C_FLAGS = -std=c99 -g  
 
 C_DEFINES = 
 

+ 1 - 1
cmake-build-debug/mqtt/mqttclient/source/CMakeFiles/mqtt_client.dir/flags.make

@@ -2,7 +2,7 @@
 # Generated by "Unix Makefiles" Generator, CMake Version 3.15
 
 # compile C with /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc
-C_FLAGS = -g  
+C_FLAGS = -std=c99 -g  
 
 C_DEFINES = 
 

+ 1 - 1
cmake-build-debug/mqtt/network/source/CMakeFiles/mqtt_network.dir/flags.make

@@ -2,7 +2,7 @@
 # Generated by "Unix Makefiles" Generator, CMake Version 3.15
 
 # compile C with /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc
-C_FLAGS = -g  
+C_FLAGS = -std=c99 -g  
 
 C_DEFINES = 
 

+ 42 - 0
cmake-build-debug/mqtt/platform/source/CMakeFiles/mqtt_platform.dir/C.includecache

@@ -6,3 +6,45 @@
 
 #IncludeRegexTransform: 
 
+../mqtt/common/include/mqtt_error.h
+
+../mqtt/platform/include/platform_net_socket.h
+sys/types.h
+-
+sys/socket.h
+-
+sys/param.h
+-
+sys/time.h
+-
+sys/select.h
+-
+netinet/in.h
+-
+netinet/tcp.h
+-
+arpa/inet.h
+-
+netdb.h
+-
+stdio.h
+-
+unistd.h
+-
+errno.h
+-
+fcntl.h
+-
+stdlib.h
+-
+string.h
+-
+signal.h
+-
+
+/home/book/hisi3518_lora/mqtt/platform/source/platform_net_socket.c
+platform_net_socket.h
+/home/book/hisi3518_lora/mqtt/platform/source/platform_net_socket.h
+mqtt_error.h
+/home/book/hisi3518_lora/mqtt/platform/source/mqtt_error.h
+

+ 1 - 1
cmake-build-debug/mqtt/platform/source/CMakeFiles/mqtt_platform.dir/flags.make

@@ -2,7 +2,7 @@
 # Generated by "Unix Makefiles" Generator, CMake Version 3.15
 
 # compile C with /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc
-C_FLAGS = -g  
+C_FLAGS = -std=c99 -g  
 
 C_DEFINES = 
 

+ 1 - 1
cmake-build-debug/mqtt/sys_mqtt/source/CMakeFiles/sys_mqtt.dir/flags.make

@@ -2,7 +2,7 @@
 # Generated by "Unix Makefiles" Generator, CMake Version 3.15
 
 # compile C with /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc
-C_FLAGS = -g  
+C_FLAGS = -std=c99 -g  
 
 C_DEFINES = 
 

+ 1 - 1
cmake-build-debug/system/CMakeFiles/mqtt_test.dir/flags.make

@@ -2,7 +2,7 @@
 # Generated by "Unix Makefiles" Generator, CMake Version 3.15
 
 # compile C with /opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc
-C_FLAGS = -g  
+C_FLAGS = -std=c99 -g  
 
 C_DEFINES = 
 

+ 1 - 1
cmake-build-debug/system/CMakeFiles/mqtt_test.dir/link.txt

@@ -1 +1 @@
-/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc -g   CMakeFiles/mqtt_test.dir/source/main.c.o  -o ../../build/bin/mqtt_test ../../build/lib/libsys_mqtt.a -lpthread-0.9.33.2 ../../build/lib/libmqtt_client.a ../../build/lib/libmqtt.a ../../build/lib/libmqtt_network.a ../../build/lib/libmqtt_mbedtls.a ../../build/lib/libmqtt_platform.a ../../build/lib/libmqtt_common.a ../../build/lib/libmqtt_log.a 
+/opt/hisi-linux/x86-arm/arm-hisiv300-linux/bin/arm-hisiv300-linux-uclibcgnueabi-gcc -std=c99 -g   CMakeFiles/mqtt_test.dir/source/main.c.o  -o ../../build/bin/mqtt_test ../../build/lib/libsys_mqtt.a -lpthread-0.9.33.2 ../../build/lib/libmqtt_client.a ../../build/lib/libmqtt.a ../../build/lib/libmqtt_network.a ../../build/lib/libmqtt_mbedtls.a ../../build/lib/libmqtt_platform.a ../../build/lib/libmqtt_common.a ../../build/lib/libmqtt_log.a 

+ 11 - 0
sx1302/CMakeLists.txt

@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.15)
+project(lora-sx1302)
+set(SX1302_INCLUDE_PATH ${PROJECT_SOURCE_DIR}/include)
+set(SX1302_SOURCE_PATH ${PROJECT_SOURCE_DIR}/source)
+include_directories(${SX1302_INCLUDE_PATH})
+
+foreach(FOREACH_SRC_DIR ${SX1302_SOURCE_PATH})
+    aux_source_directory(${FOREACH_SRC_DIR} SRC)
+endforeach()
+
+add_library(${LORA_SX1302} STATIC ${SRC})

+ 17 - 0
sx1302/include/config.h

@@ -0,0 +1,17 @@
+#ifndef _LORAGW_CONFIGURATION_H
+#define _LORAGW_CONFIGURATION_H
+#define LIBLORAGW_VERSION       "2.1.0"
+#define DEBUG_AUX               0
+#define DEBUG_COM               0
+#define DEBUG_MCU               0
+#define DEBUG_I2C               0
+#define DEBUG_REG               0
+#define DEBUG_HAL               0
+#define DEBUG_GPS               0
+#define DEBUG_GPIO
+#define DEBUG_LBT               0
+#define DEBUG_RAD               0
+#define DEBUG_CAL               0
+#define DEBUG_SX1302    0
+#define DEBUG_FTIME             0
+#endif

+ 43 - 0
sx1302/include/loragw_ad5338r.h

@@ -0,0 +1,43 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    Basic driver for Analog AD5338R DAC.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_AD5338R_H
+#define _LORAGW_AD5338R_H
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define VOLTAGE2HEX_H(a) ( (a)*1024/5/4 )
+#define VOLTAGE2HEX_L(a) ( (((int)((a)*1024/5)) & 0x3) * 64 )
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define I2C_PORT_DAC_AD5338R 0x0C
+
+#define AD5338R_CMD_SIZE 3
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS ----------------------------------------------------- */
+
+int ad5338r_configure(int i2c_fd, uint8_t i2c_addr);
+int ad5338r_write(int i2c_fd, uint8_t i2c_addr, uint8_t buf[static AD5338R_CMD_SIZE]);
+
+#endif

+ 84 - 0
sx1302/include/loragw_agc_params.h

@@ -0,0 +1,84 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    SX1302 AGC parameters definition.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_AGC_PARAMS_H
+#define _LORAGW_AGC_PARAMS_H
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE TYPES -------------------------------------------------------- */
+
+struct agc_gain_params_s {
+    uint8_t ana_min;
+    uint8_t ana_max;
+    uint8_t ana_thresh_l;
+    uint8_t ana_thresh_h;
+    uint8_t dec_attn_min;
+    uint8_t dec_attn_max;
+    uint8_t dec_thresh_l;
+    uint8_t dec_thresh_h1;
+    uint8_t dec_thresh_h2;
+    uint8_t chan_attn_min;
+    uint8_t chan_attn_max;
+    uint8_t chan_thresh_l;
+    uint8_t chan_thresh_h;
+    uint8_t deviceSel;      /* sx1250 only */
+    uint8_t hpMax;          /* sx1250 only */
+    uint8_t paDutyCycle;    /* sx1250 only */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+const struct agc_gain_params_s agc_params_sx1250 = {
+    .ana_min = 1,
+    .ana_max = 13,
+    .ana_thresh_l = 3,
+    .ana_thresh_h = 12,
+    .dec_attn_min = 4,
+    .dec_attn_max = 15,
+    .dec_thresh_l = 40,
+    .dec_thresh_h1 = 80,
+    .dec_thresh_h2 = 90,
+    .chan_attn_min = 4,
+    .chan_attn_max = 14,
+    .chan_thresh_l = 52,
+    .chan_thresh_h = 132,
+    .deviceSel = 0,
+    .hpMax = 7,
+    .paDutyCycle = 4
+};
+
+const struct agc_gain_params_s agc_params_sx125x = {
+    .ana_min = 0,
+    .ana_max = 9,
+    .ana_thresh_l = 16,
+    .ana_thresh_h = 35,
+    .dec_attn_min = 7,
+    .dec_attn_max = 11,
+    .dec_thresh_l = 45,
+    .dec_thresh_h1 = 100,
+    .dec_thresh_h2 = 115,
+    .chan_attn_min = 4,
+    .chan_attn_max = 14,
+    .chan_thresh_l = 52,
+    .chan_thresh_h = 132,
+    .deviceSel = 0,
+    .hpMax = 0,
+    .paDutyCycle = 0
+};
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 134 - 0
sx1302/include/loragw_aux.h

@@ -0,0 +1,134 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+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 <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+#include <sys/time.h>   /* gettimeofday, structtimeval */
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define DEBUG_PERF 0   /* Debug timing performances: level [0..4] */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+/**
+@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))
+
+/**
+@brief Substract struct timeval values
+@param a [in]   struct timeval a
+@param b [in]   struct timeval b
+@param b [out]  struct timeval resulting from (a - b)
+*/
+#define TIMER_SUB(a, b, result)                                                \
+    do  {                                                                      \
+        (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                          \
+        (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                       \
+        if ((result)->tv_usec < 0) {                                           \
+            --(result)->tv_sec;                                                \
+            (result)->tv_usec += 1000000;                                      \
+        }                                                                      \
+    } while (0)
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Wait for a certain time (millisecond accuracy)
+@param t number of milliseconds to wait.
+*/
+void wait_ms(unsigned long t);
+
+/**
+@brief Wait for a certain time (microsencond accuracy)
+@param t number of microseconds to wait.
+*/
+void wait_us(unsigned long t);
+
+/**
+@brief Calculate the time on air of a LoRa packet in microseconds
+@param bw packet bandwidth
+@param sf packet spreading factor
+@param cr packet coding rate
+@param n_symbol_preamble packet preamble length (number of symbols)
+@param no_header true if packet has no header
+@param no_crc true if packet has no CRC
+@param size packet size in bytes
+@param nb_symbols pointer to return the total number of symbols in packet
+@param nb_symbols_payload pointer to return the number of symbols in packet payload
+@param t_symbol_us pointer to return the duration of a symbol in microseconds
+@return the packet time on air in microseconds
+*/
+uint32_t lora_packet_time_on_air( const uint8_t bw,
+                                  const uint8_t sf,
+                                  const uint8_t cr,
+                                  const uint16_t n_symbol_preamble,
+                                  const bool no_header,
+                                  const bool no_crc,
+                                  const uint8_t size,
+                                  double * nb_symbols,
+                                  uint32_t * nb_symbols_payload,
+                                  uint16_t * t_symbol_us);
+
+/**
+@brief Record the current time, for measure start
+@param tm Pointer to the current time value
+*/
+void _meas_time_start(struct timeval *tm);
+
+/**
+@brief Measure the ellapsed time since given time
+@param debug_level  debug print debug level to be used
+@param start_time   start time of the measure to be used
+@param str          string to be used for debug print
+*/
+void _meas_time_stop(int debug_level, struct timeval start_time, const char *str);
+
+/**
+@brief Get the current time for later timeout check
+@param start contains the current time to be used as start time for timeout
+*/
+void timeout_start(struct timeval * start);
+
+/**
+@brief Check if the given timeout time in milliseconds has ellapsed compared to start time
+@param start reference start time
+@param timeout_ms the timeout duration in milliseconds
+@return -1 if the timeout has exceeded, 0 otherwise
+*/
+int timeout_check(struct timeval start, uint32_t timeout_ms);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 59 - 0
sx1302/include/loragw_cal.h

@@ -0,0 +1,59 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    LoRa concentrator radio calibration functions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_CAL_H
+#define _LORAGW_CAL_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+struct lgw_sx125x_cal_rx_result_s {
+    int8_t amp;
+    int8_t phi;
+    uint16_t rej;
+    uint16_t rej_init;
+    uint16_t snr;
+};
+
+struct lgw_sx125x_cal_tx_result_s {
+    uint8_t dac_gain;
+    uint8_t mix_gain;
+    int8_t offset_i;
+    int8_t offset_q;
+    uint16_t rej;
+    uint16_t sig;
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int sx1302_cal_start(uint8_t version, struct lgw_conf_rxrf_s * rf_chain_cfg, struct lgw_tx_gain_lut_s * txgain_lut);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 123 - 0
sx1302/include/loragw_com.h

@@ -0,0 +1,123 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    Functions to abstract the communication interface used to communicate with
+    the concentrator.
+    Single-byte read/write and burst read/write.
+
+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_SPI_MUX_TARGET_SX1302   0x00
+#define LGW_SPI_MUX_TARGET_RADIOA   0x01
+#define LGW_SPI_MUX_TARGET_RADIOB   0x02
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+typedef enum com_type_e {
+    LGW_COM_SPI,
+    LGW_COM_USB,
+    LGW_COM_UNKNOWN
+} lgw_com_type_t;
+
+typedef enum com_write_mode_e {
+    LGW_COM_WRITE_MODE_SINGLE,
+    LGW_COM_WRITE_MODE_BULK,
+    LGW_COM_WRITE_MODE_UNKNOWN
+} lgw_com_write_mode_t;
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+ *
+*/
+int lgw_com_open(lgw_com_type_t com_type, const char *com_path);
+
+/**
+ *
+*/
+int lgw_com_close(void);
+
+/**
+ *
+*/
+int lgw_com_w(uint8_t spi_mux_target, uint16_t address, uint8_t data);
+
+/**
+ *
+*/
+int lgw_com_r(uint8_t spi_mux_target, uint16_t address, uint8_t *data);
+
+/**
+ *
+*/
+int lgw_com_rmw(uint8_t spi_mux_target, uint16_t address, uint8_t offs, uint8_t leng, uint8_t data);
+
+/**
+ *
+*/
+int lgw_com_wb(uint8_t spi_mux_target, uint16_t address, const uint8_t *data, uint16_t size);
+
+/**
+ *
+*/
+int lgw_com_rb(uint8_t spi_mux_target, uint16_t address, uint8_t *data, uint16_t size);
+
+/**
+ *
+*/
+int lgw_com_set_write_mode(lgw_com_write_mode_t write_mode);
+
+/**
+ *
+*/
+int lgw_com_flush(void);
+
+/**
+ *
+*/
+uint16_t lgw_com_chunk_size(void);
+
+/**
+ *
+ **/
+int lgw_com_get_temperature(float * temperature);
+
+/**
+ *
+ **/
+void* lgw_com_target(void);
+
+/**
+ *
+ **/
+lgw_com_type_t lgw_com_type(void);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 62 - 0
sx1302/include/loragw_debug.h

@@ -0,0 +1,62 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    LoRa concentrator HAL debug functions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_DBG_H
+#define _LORAGW_DBG_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include "config.h"    /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief
+@param
+*/
+void dbg_log_buffer_to_file(FILE * file, uint8_t * buffer, uint16_t size);
+
+/**
+@brief
+@param
+*/
+void dbg_log_payload_diff_to_file(FILE * file, uint8_t * buffer1, uint8_t * buffer2, uint16_t size);
+
+/**
+@brief
+@param
+*/
+void dbg_init_random(void);
+
+/**
+@brief
+@param
+*/
+void dbg_generate_random_payload(uint32_t pkt_cnt, uint8_t * buffer_expected, uint8_t size);
+
+/**
+@brief
+@param
+*/
+int dbg_check_payload(struct lgw_conf_debug_s * context, FILE * file, uint8_t * payload_received, uint8_t size, uint8_t ref_payload_idx, uint8_t sf);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 596 - 0
sx1302/include/loragw_hal.h

@@ -0,0 +1,596 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+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 "loragw_com.h"
+
+#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_DR(dr)          ((dr == DR_LORA_SF5) || (dr == DR_LORA_SF6) || (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_CR(cr)          ((cr == CR_LORA_4_5) || (cr == CR_LORA_4_6) || (cr == CR_LORA_4_7) || (cr == CR_LORA_4_8))
+
+#define IS_FSK_BW(bw)           ((bw >= 1) && (bw <= 7))
+#define IS_FSK_DR(dr)           ((dr >= DR_FSK_MIN) && (dr <= DR_FSK_MAX))
+
+#define IS_TX_MODE(mode)        ((mode == IMMEDIATE) || (mode == TIMESTAMPED) || (mode == ON_GPS))
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* return status code */
+#define LGW_HAL_SUCCESS     0
+#define LGW_HAL_ERROR       -1
+#define LGW_LBT_NOT_ALLOWED 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 */
+
+/* concentrator chipset-specific parameters */
+#define LGW_IF_CHAIN_NB     10      /* number of IF+modem RX chains */
+#define LGW_REF_BW          125000  /* typical bandwidth of data channel */
+#define LGW_MULTI_NB        8       /* number of LoRa 'multi SF' chains */
+#define LGW_MULTI_SF_EN     0xFF    /* bitmask to enable/disable SF for multi-sf correlators  (12 11 10 9 8 7 6 5) */
+
+/* values available for the 'modulation' parameters */
+/* NOTE: arbitrary values */
+#define MOD_UNDEFINED   0
+#define MOD_CW          0x08
+#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       0x06
+#define BW_250KHZ       0x05
+#define BW_125KHZ       0x04
+
+/* 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_SF5     5
+#define DR_LORA_SF6     6
+#define DR_LORA_SF7     7
+#define DR_LORA_SF8     8
+#define DR_LORA_SF9     9
+#define DR_LORA_SF10    10
+#define DR_LORA_SF11    11
+#define DR_LORA_SF12    12
+/* 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   /* CR0 exists but is not recommended, so consider it as invalid */
+#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
+
+/* 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
+
+/* Listen-Before-Talk */
+#define LGW_LBT_CHANNEL_NB_MAX 16 /* Maximum number of LBT channels */
+
+/* Spectral Scan */
+#define LGW_SPECTRAL_SCAN_RESULT_SIZE 33 /* The number of results returned by spectral scan function, to be used for memory allocation */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/**
+@enum lgw_radio_type_t
+@brief Radio types that can be found on the LoRa Gateway
+*/
+typedef enum {
+    LGW_RADIO_TYPE_NONE,
+    LGW_RADIO_TYPE_SX1255,
+    LGW_RADIO_TYPE_SX1257,
+    LGW_RADIO_TYPE_SX1272,
+    LGW_RADIO_TYPE_SX1276,
+    LGW_RADIO_TYPE_SX1250
+} lgw_radio_type_t;
+
+/**
+@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 */
+    bool            full_duplex;    /*!> Indicates if the gateway operates in full duplex mode or not */
+    lgw_com_type_t  com_type;       /*!> The COMmunication interface (SPI/USB) to connect to the SX1302 */
+    char            com_path[64];   /*!> Path to access the COM device to connect to the SX1302 */
+};
+
+/**
+@struct lgw_rssi_tcomp_s
+@brief Structure containing all coefficients necessary to compute the offset to be applied on RSSI for current temperature
+*/
+struct lgw_rssi_tcomp_s {
+    float coeff_a;
+    float coeff_b;
+    float coeff_c;
+    float coeff_d;
+    float coeff_e;
+};
+
+/**
+@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 */
+    struct lgw_rssi_tcomp_s rssi_tcomp;         /*!> Board-specific RSSI temperature compensation coefficients */
+    lgw_radio_type_t        type;               /*!> Radio type for that RF chain (SX1255, SX1257....) */
+    bool                    tx_enable;          /*!> enable or disable TX on that RF chain */
+    bool                    single_input_mode;  /*!> Configure the radio in single or differential input mode (SX1250 only) */
+};
+
+/**
+@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) */
+    bool        implicit_hdr;               /*!> LoRa Service implicit header */
+    uint8_t     implicit_payload_length;    /*!> LoRa Service implicit header payload length (number of bytes, 0 for default) */
+    bool        implicit_crc_en;            /*!> LoRa Service implicit header CRC enable */
+    uint8_t     implicit_coderate;          /*!> LoRa Service implicit header coding rate  */
+};
+
+/**
+@struct lgw_conf_demod_s
+@brief Configuration structure for LoRa/FSK demodulators
+*/
+struct lgw_conf_demod_s {
+    uint8_t     multisf_datarate;   /*!> bitmask to enable spreading-factors for correlators (SF12 - SF5) */
+};
+
+/**
+@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 */
+    int32_t     freq_offset;
+    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     modem_id;
+    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       rssic;          /*!> average RSSI of the channel in dB */
+    float       rssis;          /*!> average RSSI of the signal 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 */
+    bool        ftime_received; /*!> a fine timestamp has been received */
+    uint32_t    ftime;          /*!> packet fine timestamp (nanoseconds since last PPS) */
+};
+
+/**
+@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 */
+    int8_t      freq_offset;    /*!> frequency offset from Radio Tx frequency (CW mode) */
+    uint8_t     bandwidth;      /*!> modulation bandwidth (LoRa only) */
+    uint32_t    datarate;       /*!> TX datarate (baudrate for FSK, SF for LoRa) */
+    uint8_t     coderate;       /*!> error-correcting code of the packet (LoRa only) */
+    bool        invert_pol;     /*!> invert signal polarity, for orthogonal downlinks (LoRa only) */
+    uint8_t     f_dev;          /*!> frequency deviation, in kHz (FSK only) */
+    uint16_t    preamble;       /*!> set the preamble length, 0 for default */
+    bool        no_crc;         /*!> if true, do not send a CRC in the packet */
+    bool        no_header;      /*!> if true, enable implicit header mode (LoRa), fixed length (FSK) */
+    uint16_t    size;           /*!> payload size in bytes */
+    uint8_t     payload[256];   /*!> buffer containing the payload */
+};
+
+/**
+@struct lgw_tx_gain_s
+@brief Structure containing all gains of Tx chain
+*/
+struct lgw_tx_gain_s {
+    int8_t  rf_power;   /*!> measured TX power at the board connector, in dBm */
+    uint8_t dig_gain;   /*!> (sx125x) 2 bits: control of the digital gain of SX1302 */
+    uint8_t pa_gain;    /*!> (sx125x) 2 bits: control of the external PA (SX1302 I/O)
+                             (sx1250) 1 bits: enable/disable the external PA (SX1302 I/O) */
+    uint8_t dac_gain;   /*!> (sx125x) 2 bits: control of the radio DAC */
+    uint8_t mix_gain;   /*!> (sx125x) 4 bits: control of the radio mixer */
+    int8_t offset_i;    /*!> (sx125x) calibrated I offset */
+    int8_t offset_q;    /*!> (sx125x) calibrated Q offset */
+    uint8_t pwr_idx;    /*!> (sx1250) 6 bits: control the radio power index to be used for configuration */
+};
+
+/**
+@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 */
+};
+
+/**
+@struct lgw_conf_debug_s
+@brief Configuration structure for debug
+*/
+struct conf_ref_payload_s {
+    uint32_t id;
+    uint8_t payload[255];
+    uint32_t prev_cnt;
+};
+struct lgw_conf_debug_s {
+    uint8_t                     nb_ref_payload;
+    struct conf_ref_payload_s   ref_payload[16];
+    char log_file_name[128];
+};
+
+/**
+@enum lgw_ftime_mode_t
+@brief Fine timestamping modes
+*/
+typedef enum {
+    LGW_FTIME_MODE_HIGH_CAPACITY,   /*!> fine timestamps for SF5 -> SF10 */
+    LGW_FTIME_MODE_ALL_SF           /*!> fine timestamps for SF5 -> SF12 */
+} lgw_ftime_mode_t;
+
+/**
+@struct lgw_conf_ftime_s
+@brief Configuration structure for fine timestamping
+*/
+struct lgw_conf_ftime_s {
+    bool enable;              /*!> Enable / Disable fine timestamping */
+    lgw_ftime_mode_t mode;    /*!> Fine timestamping mode */
+};
+
+/**
+@enum lgw_lbt_scan_time_t
+@brief Radio types that can be found on the LoRa Gateway
+*/
+typedef enum {
+    LGW_LBT_SCAN_TIME_128_US    = 128,
+    LGW_LBT_SCAN_TIME_5000_US   = 5000,
+} lgw_lbt_scan_time_t;
+
+/**
+@brief Structure containing a Listen-Before-Talk channel configuration
+*/
+struct lgw_conf_chan_lbt_s{
+    uint32_t            freq_hz;           /*!> LBT channel frequency */
+    uint8_t             bandwidth;         /*!> LBT channel bandwidth */
+    lgw_lbt_scan_time_t scan_time_us;      /*!> LBT channel carrier sense time */
+    uint16_t            transmit_time_ms;  /*!> LBT channel transmission duration when allowed */
+};
+
+/**
+@struct lgw_conf_lbt_s
+@brief Configuration structure for listen-before-talk
+*/
+struct lgw_conf_lbt_s {
+    bool                        enable;             /*!> enable or disable LBT */
+    int8_t                      rssi_target;        /*!> RSSI threshold to detect if channel is busy or not (dBm) */
+    uint8_t                     nb_channel;         /*!> number of LBT channels */
+    struct lgw_conf_chan_lbt_s  channels[LGW_LBT_CHANNEL_NB_MAX];  /*!> LBT channels configuration */
+};
+
+/**
+@struct lgw_conf_sx1261_s
+@brief Configuration structure for additional SX1261 radio used for LBT and Spectral Scan
+*/
+struct lgw_conf_sx1261_s {
+    bool                        enable;             /*!> enable or disable SX1261 radio */
+    char                        spi_path[64];       /*!> Path to access the SPI device to connect to the SX1261 (not used for USB com type) */
+    int8_t                      rssi_offset;        /*!> value to be applied to the sx1261 RSSI value (dBm) */
+    struct lgw_conf_lbt_s       lbt_conf;           /*!> listen-before-talk configuration */
+};
+
+/**
+@struct lgw_context_s
+@brief Configuration context shared across modules
+*/
+typedef struct lgw_context_s {
+    /* Global context */
+    bool                        is_started;
+    struct lgw_conf_board_s     board_cfg;
+    /* RX context */
+    struct lgw_conf_rxrf_s      rf_chain_cfg[LGW_RF_CHAIN_NB];
+    struct lgw_conf_rxif_s      if_chain_cfg[LGW_IF_CHAIN_NB];
+    struct lgw_conf_demod_s     demod_cfg;
+    struct lgw_conf_rxif_s      lora_service_cfg;                       /* LoRa service channel config parameters */
+    struct lgw_conf_rxif_s      fsk_cfg;                                /* FSK channel config parameters */
+    /* TX context */
+    struct lgw_tx_gain_lut_s    tx_gain_lut[LGW_RF_CHAIN_NB];
+    /* Misc */
+    struct lgw_conf_ftime_s     ftime_cfg;
+    struct lgw_conf_sx1261_s    sx1261_cfg;
+    /* Debug */
+    struct lgw_conf_debug_s     debug_cfg;
+} lgw_context_t;
+
+/**
+@struct lgw_spectral_scan_status_t
+@brief Spectral Scan status
+*/
+typedef enum lgw_spectral_scan_status_e {
+    LGW_SPECTRAL_SCAN_STATUS_NONE,
+    LGW_SPECTRAL_SCAN_STATUS_ON_GOING,
+    LGW_SPECTRAL_SCAN_STATUS_ABORTED,
+    LGW_SPECTRAL_SCAN_STATUS_COMPLETED,
+    LGW_SPECTRAL_SCAN_STATUS_UNKNOWN
+} lgw_spectral_scan_status_t;
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 LoRa/FSK demodulators
+@param conf structure containing the configuration parameters
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_demod_setconf(struct lgw_conf_demod_s * conf);
+
+/**
+@brief Configure the Tx gain LUT
+@param conf pointer to structure defining the LUT
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_txgain_setconf(uint8_t rf_chain, struct lgw_tx_gain_lut_s * conf);
+
+/**
+@brief Configure the fine timestamping
+@param conf pointer to structure defining the config to be applied
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_ftime_setconf(struct lgw_conf_ftime_s * conf);
+
+/*
+@brief Configure the SX1261 radio for LBT/Spectral Scan
+@param pointer to structure defining the config to be applied
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_sx1261_setconf(struct lgw_conf_sx1261_s * conf);
+
+/**
+@brief Configure the debug context
+@param conf pointer to structure defining the config to be applied
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_debug_setconf(struct lgw_conf_debug_s * conf);
+
+/**
+@brief Connect to the LoRa concentrator, reset it and configure it according to previously set parameters
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_start(void);
+
+/**
+@brief Stop the LoRa concentrator and disconnect it
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_stop(void);
+
+/**
+@brief A non-blocking function that will fetch up to 'max_pkt' packets from the LoRa concentrator FIFO and data buffer
+@param max_pkt maximum number of packet that must be retrieved (equal to the size of the array of struct)
+@param pkt_data pointer to an array of struct that will receive the packet metadata and payload pointers
+@return LGW_HAL_ERROR id the operation failed, else the number of packets retrieved
+*/
+int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s * pkt_data);
+
+/**
+@brief Schedule a packet to be send immediately or after a delay depending on tx_mode
+@param pkt_data structure containing the data and metadata for the packet to send
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+
+/!\ When sending a packet, there is a delay (approx 1.5ms) for the analog
+circuitry to start and be stable. This delay is adjusted by the HAL depending
+on the board version (lgw_i_tx_start_delay_us).
+
+In 'timestamp' mode, this is transparent: the modem is started
+lgw_i_tx_start_delay_us microseconds before the user-set timestamp value is
+reached, the preamble of the packet start right when the internal timestamp
+counter reach target value.
+
+In 'immediate' mode, the packet is emitted as soon as possible: transferring the
+packet (and its parameters) from the host to the concentrator takes some time,
+then there is the lgw_i_tx_start_delay_us, then the packet is emitted.
+
+In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is
+emitted lgw_i_tx_start_delay_us microsenconds after a rising edge of the
+trigger signal. Because there is no way to anticipate the triggering event and
+start the analog circuitry beforehand, that delay must be taken into account in
+the protocol.
+*/
+int lgw_send(struct lgw_pkt_tx_s * pkt_data);
+
+/**
+@brief Give the the status of different part of the LoRa concentrator
+@param select is used to select what status we want to know
+@param code is used to return the status code
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_status(uint8_t rf_chain, 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(uint8_t rf_chain);
+
+/**
+@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 Return instateneous value of internal counter
+@param inst_cnt_us pointer to receive timestamp value
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_get_instcnt(uint32_t * inst_cnt_us);
+
+/**
+@brief Return the LoRa concentrator EUI
+@param eui pointer to receive eui
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_get_eui(uint64_t * eui);
+
+/**
+@brief Return the temperature measured by the LoRa concentrator sensor
+@param temperature The temperature measured, in degree celcius
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_get_temperature(float * temperature);
+
+/**
+@brief Allow user to check the version/options of the library once compiled
+@return pointer on a human-readable null terminated string
+*/
+const char* lgw_version_info(void);
+
+/**
+@brief Return time on air of given packet, in milliseconds
+@param packet is a pointer to the packet structure
+@return the packet time on air in milliseconds
+*/
+uint32_t lgw_time_on_air(const struct lgw_pkt_tx_s * packet);
+
+/**
+@brief Start scaning the channel centered on the given frequency
+@param freq_hz channel center frequency
+@param nb_scan number of measures to be done for the scan
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_spectral_scan_start(uint32_t freq_hz, uint16_t nb_scan);
+
+/**
+@brief Get the current scan status
+@param status a pointer to the returned status
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_spectral_scan_get_status(lgw_spectral_scan_status_t * status);
+
+/**
+@brief Get the channel scan results
+@param levels an array containing the power levels for which the scan results are given
+@param values ar array containing the results of the scan for each power levels
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_spectral_scan_get_results(int16_t levels_dbm[static LGW_SPECTRAL_SCAN_RESULT_SIZE], uint16_t results[static LGW_SPECTRAL_SCAN_RESULT_SIZE]);
+
+/**
+@brief Abort the current scan
+@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
+*/
+int lgw_spectral_scan_abort();
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 85 - 0
sx1302/include/loragw_i2c.h

@@ -0,0 +1,85 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Host specific functions to address the LoRa concentrator I2C peripherals.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_I2C_H
+#define _LORAGW_I2C_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>        /* C99 types*/
+
+#include "config.h"    /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_I2C_SUCCESS     0
+#define LGW_I2C_ERROR       -1
+
+#define I2C_DEVICE          "/dev/i2c-1"
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Open I2C port
+@param path         Path to the I2C device driver (absolute or relative)
+@param device_addr  Address of the device
+@param i2c_fd      Pointer to receive I2C port file descriptor index
+@return 0 if I2C port was open successfully, -1 else
+*/
+int i2c_linuxdev_open(const char *path, uint8_t device_addr, int *i2c_fd);
+
+/**
+@brief Close I2C port
+@param i2c_fd      I2C port file descriptor index
+@return 0 if I2C port was closed successfully, -1 else
+*/
+int i2c_linuxdev_close(int i2c_fd);
+
+/**
+@brief Read data from an I2C port
+@param i2c_fd      I2C port file descriptor index
+@param device_addr  I2C device address
+@param reg_addr     Address of the register to be read
+@param data         Pointer to a buffer to store read data
+@return 0 if I2C data read is successful, -1 else
+*/
+int i2c_linuxdev_read(int i2c_fd, uint8_t device_addr, uint8_t reg_addr, uint8_t *data);
+
+/**
+@brief Write data to an I2C port
+@param i2c_fd      I2C port file descriptor index
+@param device_addr  I2C device address
+@param reg_addr     Address of the register to write to
+@param data         byte to write in the register
+@return 0 if I2C data write is successful, -1 else
+*/
+int i2c_linuxdev_write(int i2c_fd, uint8_t device_addr, uint8_t reg_addr, uint8_t data);
+
+/**
+@brief Write a raw buffer to an I2C port
+@param i2c_fd       I2C port file descriptor index
+@param device_addr  I2C device address
+@param buffer       Buffer to be written to the device
+@param size         Size of the buffer to be written
+@return 0 if I2C data write is successful, -1 else
+*/
+int i2c_linuxdev_write_buffer(int i2c_fd, uint8_t device_addr, uint8_t *buffer, uint8_t size);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 65 - 0
sx1302/include/loragw_lbt.h

@@ -0,0 +1,65 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    LoRa concentrator Listen-Before-Talk functions
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_LBT_H
+#define _LORAGW_LBT_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+
+#include "loragw_hal.h"
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Configure the SX1261 and start LBT channel scanning
+@param sx1261_context the sx1261 radio parameters to take into account for scanning
+@param pkt description of the packet to be transmitted
+@return 0 for success, -1 for failure
+*/
+int lgw_lbt_start(const struct lgw_conf_sx1261_s * sx1261_context, const struct lgw_pkt_tx_s * pkt);
+
+/**
+@brief Stop LBT scanning
+@return 0 for success, -1 for failure
+*/
+int lgw_lbt_stop(void);
+
+/**
+@brief Check if packet was allowed to be transmitted or not
+@param rf_chain the TX path on which TX was requested
+@param tx_ok pointer to return if the packet was allowed to be transmitted or not.
+@return 0 for success, -1 for failure
+*/
+int lgw_lbt_tx_status(uint8_t rf_chain, bool * tx_ok);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 195 - 0
sx1302/include/loragw_mcu.h

@@ -0,0 +1,195 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    Host specific functions to address the LoRa concentrator MCU for USB
+    interface.
+    Single-byte read/write and burst read/write.
+
+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) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+static const char mcu_version_string[] = "01.00.00";
+
+#define MAX_SIZE_COMMAND ( 4200 )
+#define MAX_SPI_COMMAND ( MAX_SIZE_COMMAND - CMD_OFFSET__DATA - 1 )
+
+#define LGW_USB_BURST_CHUNK ( 4096 )
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+typedef enum order_id_e
+{
+    ORDER_ID__REQ_PING            = 0x00,
+    ORDER_ID__REQ_GET_STATUS      = 0x01,
+    ORDER_ID__REQ_BOOTLOADER_MODE = 0x02,
+    ORDER_ID__REQ_RESET           = 0x03,
+    ORDER_ID__REQ_WRITE_GPIO      = 0x04,
+    ORDER_ID__REQ_MULTIPLE_SPI    = 0x05,
+
+    ORDER_ID__ACK_PING            = 0x40,
+    ORDER_ID__ACK_GET_STATUS      = 0x41,
+    ORDER_ID__ACK_BOOTLOADER_MODE = 0x42,
+    ORDER_ID__ACK_RESET           = 0x43,
+    ORDER_ID__ACK_WRITE_GPIO      = 0x44,
+    ORDER_ID__ACK_MULTIPLE_SPI    = 0x45,
+
+    ORDER_ID__CMD_ERROR = 0xFF
+} order_id_t;
+
+typedef enum
+{
+    CMD_OFFSET__ID,
+    CMD_OFFSET__SIZE_MSB,
+    CMD_OFFSET__SIZE_LSB,
+    CMD_OFFSET__CMD,
+    CMD_OFFSET__DATA
+} e_cmd_order_offset;
+
+typedef enum
+{
+    REQ_RESET__TYPE,
+    REQ_RESET_SIZE
+} e_cmd_offset_req_reset;
+
+typedef enum
+{
+    REQ_WRITE_GPIO__PORT,
+    REQ_WRITE_GPIO__PIN,
+    REQ_WRITE_GPIO__STATE,
+    REQ_WRITE_GPIO_SIZE
+} e_cmd_offset_req_write_gpio;
+
+typedef enum
+{
+    ACK_PING__UNIQUE_ID_0,  ACK_PING__UNIQUE_ID_1,  ACK_PING__UNIQUE_ID_2,  ACK_PING__UNIQUE_ID_3,
+    ACK_PING__UNIQUE_ID_4,  ACK_PING__UNIQUE_ID_5,  ACK_PING__UNIQUE_ID_6,  ACK_PING__UNIQUE_ID_7,
+    ACK_PING__UNIQUE_ID_8,  ACK_PING__UNIQUE_ID_9,  ACK_PING__UNIQUE_ID_10, ACK_PING__UNIQUE_ID_11,
+    ACK_PING__VERSION_0,    ACK_PING__VERSION_1,    ACK_PING__VERSION_2,    ACK_PING__VERSION_3,    ACK_PING__VERSION_4,
+    ACK_PING__VERSION_5,    ACK_PING__VERSION_6,    ACK_PING__VERSION_7,    ACK_PING__VERSION_8,
+    ACK_PING_SIZE,
+} e_cmd_offset_ack_ping;
+
+typedef enum
+{
+    ACK_GET_STATUS__SYSTEM_TIME_31_24,      ACK_GET_STATUS__SYSTEM_TIME_23_16,      ACK_GET_STATUS__SYSTEM_TIME_15_8,   ACK_GET_STATUS__SYSTEM_TIME_7_0,
+    ACK_GET_STATUS__TEMPERATURE_15_8,       ACK_GET_STATUS__TEMPERATURE_7_0,
+    ACK_GET_STATUS_SIZE
+} e_cmd_offset_ack_get_status;
+
+typedef enum
+{
+    ACK_GPIO_WRITE__STATUS,
+    ACK_GPIO_WRITE_SIZE
+} e_cmd_offset_ack_gpio_write;
+
+typedef enum
+{
+    ACK_RESET__STATUS,
+    ACK_RESET_SIZE
+} e_cmd_offset_ack_reset;
+
+typedef enum
+{
+    MCU_SPI_TARGET_SX1302,  /* SX1302 + SX1250 */
+    MCU_SPI_TARGET_SX1261   /* LBT/Spectral Scan additional radio */
+} e_cmd_spi_target;
+
+typedef enum
+{
+    MCU_SPI_REQ_TYPE_READ_WRITE         = 0x01, /* Read/Write SPI request */
+    MCU_SPI_REQ_TYPE_READ_MODIFY_WRITE  = 0x02  /* Read-Modify-Write SPI request */
+} e_cmd_spi_req_type;
+
+typedef enum
+{
+    RESET_TYPE__GTW
+} e_reset_type;
+
+typedef enum
+{
+    SPI_STATUS_OK,
+    SPI_STATUS_FAIL,
+    SPI_STATUS_WRONG_PARAM,
+    SPI_STATUS_TIMEOUT
+} e_spi_status;
+
+typedef struct {
+    uint32_t unique_id_high;
+    uint32_t unique_id_mid;
+    uint32_t unique_id_low;
+    char version[10]; /* format is V00.00.00\0 */
+} s_ping_info;
+
+typedef struct {
+    uint32_t system_time_ms;
+    float temperature;
+} s_status;
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+ *
+*/
+int mcu_ping(int fd, s_ping_info * info);
+
+/**
+ *
+*/
+int mcu_boot(int fd);
+
+/**
+ *
+*/
+int mcu_get_status(int fd, s_status * status);
+
+/**
+ *
+*/
+int mcu_gpio_write(int fd, uint8_t gpio_port, uint8_t gpio_id, uint8_t gpio_value);
+
+/**
+@brief Send a SX1302 read/write SPI request to the MCU
+@param fd File descriptor of the device used to access the MCU
+@param in_out_buf The buffer containing the multiple requests to be sent to the
+SX1302 with the SPI header (r/w, target mux). This buffer will also contain the
+SPI answer when the function exits.
+@param buf_size The size of the given input/output buffer
+@return 0 for SUCCESS, -1 for failure
+*/
+int mcu_spi_write(int fd, uint8_t * in_out_buf, size_t buf_size);
+
+/**
+ *
+*/
+int mcu_spi_store(uint8_t * in_out_buf, size_t buf_size);
+
+/**
+ *
+*/
+int mcu_spi_flush(int fd);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1503 - 0
sx1302/include/loragw_reg.h


+ 113 - 0
sx1302/include/loragw_spi.h

@@ -0,0 +1,113 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Host specific functions to address the LoRa concentrator registers through
+    a SPI interface.
+    Single-byte read/write and burst read/write.
+    Could be used with multiple SPI ports in parallel (explicit file descriptor)
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_SPI_H
+#define _LORAGW_SPI_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>        /* C99 types*/
+
+#include "config.h"    /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_SPI_SUCCESS     0
+#define LGW_SPI_ERROR       -1
+
+#define SPI_SPEED       2000000
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief LoRa concentrator SPI setup (configure I/O and peripherals)
+@param com_path path to the SPI device to be used to connect to the SX1302
+@param spi_target_ptr pointer on a generic pointer to SPI target (implementation dependant)
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+
+int lgw_spi_open(const char * com_path, void **com_target_ptr);
+
+/**
+@brief LoRa concentrator SPI close
+@param spi_target generic pointer to SPI target (implementation dependant)
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+
+int lgw_spi_close(void *com_target);
+
+/**
+@brief LoRa concentrator SPI single-byte write
+@param spi_target generic pointer to SPI target (implementation dependant)
+@param address 7-bit register address
+@param data data byte to write
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+int lgw_spi_w(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t data);
+
+/**
+@brief LoRa concentrator SPI single-byte read
+@param spi_target generic pointer to SPI target (implementation dependant)
+@param address 7-bit register address
+@param data data byte to write
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+int lgw_spi_r(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data);
+
+/**
+@brief LoRa concentrator SPI single-byte read-modify-write
+@param spi_target generic pointer to SPI target (implementation dependant)
+@param address 7-bit register address
+@param offs start offset of the bits to be modified
+@param leng number of bits to be modified
+@param data value to be written in the selected bits
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+int lgw_spi_rmw(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t offs, uint8_t leng, uint8_t data);
+
+/**
+@brief LoRa concentrator SPI burst (multiple-byte) write
+@param spi_target generic pointer to SPI target (implementation dependant)
+@param address 7-bit register address
+@param data pointer to byte array that will be sent to the LoRa concentrator
+@param size size of the transfer, in byte(s)
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+int lgw_spi_wb(void *com_target, uint8_t spi_mux_target, uint16_t address, const uint8_t *data, uint16_t size);
+
+/**
+@brief LoRa concentrator SPI burst (multiple-byte) read
+@param spi_target generic pointer to SPI target (implementation dependant)
+@param address 7-bit register address
+@param data pointer to byte array that will be written from the LoRa concentrator
+@param size size of the transfer, in byte(s)
+@return status of register operation (LGW_SPI_SUCCESS/LGW_SPI_ERROR)
+*/
+int lgw_spi_rb(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data, uint16_t size);
+
+/**
+ *
+ **/
+uint16_t lgw_spi_chunk_size(void);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 65 - 0
sx1302/include/loragw_stts751.h

@@ -0,0 +1,65 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Basic driver for ST ts751 temperature sensor
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_STTS751_H
+#define _LORAGW_STTS751_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED TYPES ------------------------------------------------ */
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED FUNCTIONS -------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/*
+  0x39: STTS751-0DP3F
+  0x3B: STTS751-1DP3F
+  0x38: STTS751-0DP3F on full duplex CN490 ref design
+  */
+static const uint8_t I2C_PORT_TEMP_SENSOR[] = {0x39, 0x3B, 0x38};
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS ----------------------------------------------------- */
+
+/**
+@brief Configure the temperature sensor (ST TS751)
+@param i2c_fd file descriptor to access the sensor through I2C
+@param i2c_addr the I2C device address of the sensor
+@return LGW_I2C_ERROR if fails, LGW_I2C_SUCCESS otherwise
+*/
+int stts751_configure(int i2c_fd, uint8_t i2c_addr);
+
+/**
+@brief Get the temperature from the sensor
+@param i2c_fd file descriptor to access the sensor through I2C
+@param i2c_addr the I2C device address of the sensor
+@param temperature pointer to store the temerature read from sensor
+@return LGW_I2C_ERROR if fails, LGW_I2C_SUCCESS otherwise
+*/
+int stts751_get_temperature(int i2c_fd, uint8_t i2c_addr, float * temperature);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 49 - 0
sx1302/include/loragw_sx1250.h

@@ -0,0 +1,49 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1250 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_SX1250_H
+#define _LORAGW_SX1250_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+#include <stdbool.h>    /* bool type */
+
+#include "sx1250_defs.h"
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int sx1250_calibrate(uint8_t rf_chain, uint32_t freq_hz);
+int sx1250_setup(uint8_t rf_chain, uint32_t freq_hz, bool single_input_mode);
+
+int sx1250_reg_w(sx1250_op_code_t op_code, uint8_t *data, uint16_t size, uint8_t rf_chain);
+int sx1250_reg_r(sx1250_op_code_t op_code, uint8_t *data, uint16_t size, uint8_t rf_chain);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 148 - 0
sx1302/include/loragw_sx125x.h

@@ -0,0 +1,148 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1255/SX1257 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+#ifndef _LORAGW_SX125X_H
+#define _LORAGW_SX125X_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED TYPES ------------------------------------------------ */
+
+struct radio_reg_s
+{
+	uint8_t addr; /* base address of the register */
+	uint8_t offs; /* position of the register LSB (between 0 to 7) */
+	uint8_t leng; /* number of bits in the register */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+#define SX1257_FREQ_TO_REG(f)       (uint32_t)((uint64_t)f * (1 << 19) / 32000000U)
+#define SX1255_FREQ_TO_REG(f)       (uint32_t)((uint64_t)f * (1 << 20) / 32000000U)
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_REG_SUCCESS 0
+#define LGW_REG_ERROR -1
+
+#define SX125x_32MHz_FRAC 15625 /* irreductible fraction for PLL register caculation */
+
+#define SX125x_TX_DAC_CLK_SEL   0   /* 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       15  /* 0 to 15 , 15 highest gain */
+#define SX125x_LNA_ZIN          0   /* 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 */
+
+typedef enum {
+    SX125x_REG_MODE = 0,
+    SX125x_REG_MODE__PA_DRIVER_EN = 1,
+    SX125x_REG_MODE__TX_EN = 2,
+    SX125x_REG_MODE__RX_EN = 3,
+    SX125x_REG_MODE__STANDBY_EN = 4,
+    SX125x_REG_FRF_RX_MSB = 5,
+    SX125x_REG_FRF_RX_MID = 6,
+    SX125x_REG_FRF_RX_LSB = 7,
+    SX125x_REG_FRF_TX_MSB = 8,
+    SX125x_REG_FRF_TX_MID = 9,
+    SX125x_REG_FRF_TX_LSB = 10,
+    SX125x_REG_VERSION = 11,
+    SX125x_REG_TX_GAIN = 12,
+    SX125x_REG_TX_GAIN__DAC_GAIN = 13,
+    SX125x_REG_TX_GAIN__MIX_GAIN = 14,
+    SX125x_REG_TX_BW = 15,
+    SX125x_REG_TX_BW__PLL_BW = 16,
+    SX125x_REG_TX_BW__ANA_BW = 17,
+    SX125x_REG_TX_DAC_BW = 18,
+    SX125x_REG_RX_ANA_GAIN = 19,
+    SX125x_REG_RX_ANA_GAIN__LNA_GAIN = 20,
+    SX125x_REG_RX_ANA_GAIN__BB_GAIN = 21,
+    SX125x_REG_RX_ANA_GAIN__LNA_ZIN = 22,
+    SX125x_REG_RX_BW = 23,
+    SX125x_REG_RX_BW__ADC_BW = 24,
+    SX125x_REG_RX_BW__ADC_TRIM = 25,
+    SX125x_REG_RX_BW__BB_BW = 26,
+    SX125x_REG_RX_PLL_BW = 27,
+    SX125x_REG_RX_PLL_BW__PLL_BW = 28,
+    SX125x_REG_RX_PLL_BW__ADC_TEMP_EN = 29,
+    SX125x_REG_DIO_MAPPING = 30,
+    SX125x_REG_DIO_MAPPING__DIO_0_MAPPING = 31,
+    SX125x_REG_DIO_MAPPING__DIO_1_MAPPING = 32,
+    SX125x_REG_DIO_MAPPING__DIO_2_MAPPING = 33,
+    SX125x_REG_DIO_MAPPING__DIO_3_MAPPING = 34,
+    SX125x_REG_CLK_SELECT = 35,
+    SX125x_REG_CLK_SELECT__DIG_LOOPBACK_EN = 36,
+    SX125x_REG_CLK_SELECT__RF_LOOPBACK_EN = 37,
+    SX125x_REG_CLK_SELECT__CLK_OUT = 38,
+    SX125x_REG_CLK_SELECT__DAC_CLK_SELECT = 39,
+    SX125x_REG_MODE_STATUS = 40,
+    SX125x_REG_MODE_STATUS__LOW_BAT_EN = 41,
+    SX125x_REG_MODE_STATUS__RX_PLL_LOCKED = 42,
+    SX125x_REG_MODE_STATUS__TX_PLL_LOCKED = 43,
+    SX125x_REG_LOW_BAT_THRESH = 44,
+    SX125x_REG_SX1257_XOSC_TEST = 45,
+    SX125x_REG_SX1257_XOSC_TEST__DISABLE = 46,
+    SX125x_REG_SX1257_XOSC_TEST__GM_STARTUP = 47,
+    SX125x_REG_SX1255_XOSC_TEST = 48,
+    SX125x_REG_SX1255_XOSC_TEST__DISABLE = 49,
+    SX125x_REG_SX1255_XOSC_TEST__GM_STARTUP = 50
+}
+radio_reg_t;
+
+#define RADIO_TOTALREGS 51
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+/*
+
+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
+*/
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int sx125x_setup(uint8_t rf_chain, uint8_t rf_clkout, bool rf_enable, uint8_t rf_radio_type, uint32_t freq_hz);
+
+int sx125x_reg_w(radio_reg_t idx, uint8_t data, uint8_t rf_chain);
+int sx125x_reg_r(radio_reg_t idx, uint8_t *data, uint8_t rf_chain);
+
+#endif
+/* --- EOF ------------------------------------------------------------------ */

+ 66 - 0
sx1302/include/loragw_sx1261.h

@@ -0,0 +1,66 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1261 radio used to handle LBT
+    and Spectral Scan.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_SX1261_H
+#define _LORAGW_SX1261_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+#include <stdbool.h>    /* bool type */
+
+#include "loragw_hal.h"
+#include "sx1261_defs.h"
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+static const char sx1261_pram_version_string[] = "2D06";
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int sx1261_connect(lgw_com_type_t com_type, const char *com_path);
+int sx1261_disconnect(void);
+
+int sx1261_reg_w(sx1261_op_code_t op_code, uint8_t *data, uint16_t size);
+int sx1261_reg_r(sx1261_op_code_t op_code, uint8_t *data, uint16_t size);
+
+int sx1261_load_pram(void);
+int sx1261_calibrate(uint32_t freq_hz);
+int sx1261_setup(void);
+int sx1261_set_rx_params(uint32_t freq_hz, uint8_t bandwidth);
+
+int sx1261_lbt_start(lgw_lbt_scan_time_t scan_time_us, int8_t threshold_dbm);
+int sx1261_lbt_stop(void);
+
+int sx1261_spectral_scan_start(uint16_t nb_scan);
+int sx1261_spectral_scan_status(lgw_spectral_scan_status_t * status);
+int sx1261_spectral_scan_get_results(int8_t rssi_offset, int16_t * levels_dbm, uint16_t * results);
+int sx1261_spectral_scan_abort(void);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 456 - 0
sx1302/include/loragw_sx1302.h

@@ -0,0 +1,456 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    SX1302 Hardware Abstraction Layer entry functions.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+#ifndef _LORAGW_SX1302_H
+#define _LORAGW_SX1302_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* Default values */
+#define SX1302_AGC_RADIO_GAIN_AUTO  0xFF
+#define TX_START_DELAY_DEFAULT      1500    /* Calibrated value for 500KHz BW */
+
+/* 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 */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+#define REG_SELECT(rf_chain, a, b) ((rf_chain == 0) ? a : b)
+
+#define SET_PPM_ON(bw,dr)   (((bw == BW_125KHZ) && ((dr == DR_LORA_SF11) || (dr == DR_LORA_SF12))) || ((bw == BW_250KHZ) && (dr == DR_LORA_SF12)))
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/**
+@enum sx1302_model_id_t
+@brief
+*/
+typedef enum {
+    CHIP_MODEL_ID_SX1302 = 0x02, /* SX1302 can be 0x00 or 0x02 */
+    CHIP_MODEL_ID_SX1303 = 0x03,
+    CHIP_MODEL_ID_UNKNOWN
+} sx1302_model_id_t;
+
+/**
+@enum sx1302_rx_frequency_tracking_t
+@brief Frequency Tracking mode
+*/
+typedef enum {
+    RX_FREQ_TRACK_OFF  = 0x00,
+    RX_FREQ_TRACK_ON   = 0x01,
+    RX_FREQ_TRACK_AUTO = 0x03
+} sx1302_rx_frequency_tracking_t;
+
+/**
+@enum sx1302_rx_fine_timing_mode_t
+@brief Fine Timing mode
+*/
+typedef enum {
+    RX_FINE_TIMING_MODE_ABS     = 0x01,
+    RX_FINE_TIMING_MODE_LINEAR  = 0x02,
+    RX_FINE_TIMING_MODE_AUTO    = 0x03
+} sx1302_rx_fine_timing_mode_t;
+
+/**
+@enum sx1302_rx_dft_peak_mode_t
+@brief DFT peak mode
+*/
+typedef enum {
+    RX_DFT_PEAK_MODE_DISABLED    = 0x00,
+    RX_DFT_PEAK_MODE_FULL        = 0x01,
+    RX_DFT_PEAK_MODE_TRACK       = 0x02,
+    RX_DFT_PEAK_MODE_AUTO        = 0x03
+} sx1302_rx_dft_peak_mode_t;
+
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Initialize sx1302 for operating, and needed internal structures (rx_buffer,....)
+@param conf a pointer to the fine timestamp configuration context
+@return LGW_REG_SUCCESS if no error, LGW_REG_ERROR otherwise
+*/
+int sx1302_init(const struct lgw_conf_ftime_s *conf);
+
+/**
+@brief Get the SX1302 unique identifier
+@param eui  pointerto the memory holding the concentrator EUI
+@return LGW_REG_SUCCESS if no error, LGW_REG_ERROR otherwise
+*/
+int sx1302_get_eui(uint64_t * eui);
+
+/**
+@brief Get the SX1302/SX1303 Chip Model ID
+@param model_id pointer to the memory holding the Chip Model ID
+@return LGW_REG_SUCCESS if no error, LGW_REG_ERROR otherwise
+*/
+int sx1302_get_model_id(sx1302_model_id_t * model_id);
+
+/**
+@brief Check AGC & ARB MCUs parity error, and update timestamp counter wraping status
+@brief This function needs to be called regularly (every few seconds) by the upper layer
+@param N/A
+@return LGW_REG_SUCCESS if no error, LGW_REG_ERROR otherwise
+*/
+int sx1302_update(void);
+
+/**
+@brief Select the clock source radio
+@param rf_chain The RF chain index from which to get the clock source
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_radio_clock_select(uint8_t rf_chain);
+
+/**
+@brief Apply the radio reset sequence to the required RF chain index
+@param rf_chain The RF chain index of the radio to be reset
+@param type     The type of radio to be reset
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_radio_reset(uint8_t rf_chain, lgw_radio_type_t type);
+
+/**
+@brief Configure the radio type for the given RF chain
+@param rf_chain The RF chain index to be configured
+@param type     The type of radio to be set for the given RF chain
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_radio_set_mode(uint8_t rf_chain, lgw_radio_type_t type);
+
+/**
+@brief Give/Release control over the radios to/from the Host
+@param host_ctrl    Set to true to give control to the host, false otherwise
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_radio_host_ctrl(bool host_ctrl);
+
+/**
+@brief Perform the radio calibration sequence and fill the TX gain LUT with calibration offsets
+@param context_rf_chain The RF chains array from which to get RF chains current configuration
+@param clksrc           The RF chain index which provides the clock source
+@param txgain_lut       A pointer to the TX gain LUT to be filled
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_radio_calibrate(struct lgw_conf_rxrf_s * context_rf_chain, uint8_t clksrc, struct lgw_tx_gain_lut_s * txgain_lut);
+
+/**
+@brief Configure the PA and LNA LUTs
+@param context_board A pointer to the current board configuration context
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_pa_lna_lut_configure(struct lgw_conf_board_s * context_board);
+
+/**
+@brief Configure the Radio Front-End stage of the SX1302
+@param N/A
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_radio_fe_configure(void);
+
+/**
+@brief Returns the type of the given modem index (LoRa MultiSF, LoRa SingleSF, FSK)
+@param if_chain the index if the IF chain
+@return The IF chain type
+*/
+uint8_t sx1302_get_ifmod_config(uint8_t if_chain);
+
+/**
+@brief Configure the channelizer stage of the SX1302
+@param if_cfg   A pointer to the channels configuration
+@param fix_gain Set to true to force the channelizer to a fixed gain, false to let the AGC controlling it
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_channelizer_configure(struct lgw_conf_rxif_s * if_cfg, bool fix_gain);
+
+/**
+@brief Configure the correlator stage of the SX1302 LoRa multi-SF modems
+@param if_cfg       A pointer to the channels configuration
+@param demod_cfg    A pointer to the demodulators configuration
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_lora_correlator_configure(struct lgw_conf_rxif_s * if_cfg, struct lgw_conf_demod_s * demod_cfg);
+
+/**
+@brief Configure the correlator stage of the SX1302 LoRa single-SF modem
+@param cfg  A pointer to the channel configuration
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_lora_service_correlator_configure(struct lgw_conf_rxif_s * cfg);
+
+/**
+@brief Configure the syncword to be used by LoRa modems (public:0x34, private:0x12)
+@param public           Set to true to use the "public" syncword, false to use the private one
+@param lora_service_sf  The spreading factor configured for the single-SF LoRa modem
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_lora_syncword(bool public, uint8_t lora_service_sf);
+
+/**
+@brief Configure the LoRa multi-SF modems
+@param radio_freq_hz    The center frequency of the RF chain (0 or 1)
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_lora_modem_configure(uint32_t radio_freq_hz);
+
+/**
+@brief Configure the LoRa single-SF modem
+@param cfg              A pointer to the channel configuration
+@param radio_freq_hz    The center frequency of the RF chain (0 or 1)
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_lora_service_modem_configure(struct lgw_conf_rxif_s * cfg, uint32_t radio_freq_hz);
+
+/**
+@brief Configure the FSK modem
+@param cfg  A pointer to the channel configuration
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_fsk_configure(struct lgw_conf_rxif_s * cfg);
+
+/**
+@brief Enable the modems
+@param N/A
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_modem_enable(void);
+
+/**
+@brief Enable/Disable the GPS to allow PPS trigger and counter sampling
+@param enbale   Set to true to enable, false otherwise
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_gps_enable(bool enable);
+
+/**
+@brief Get the current SX1302 internal counter value
+@param pps      True for getting the counter value at last PPS
+@return the counter value in mciroseconds (32-bits)
+*/
+uint32_t sx1302_timestamp_counter(bool pps);
+
+/**
+@brief Load firmware to AGC MCU memory
+@param firmware A pointer to the fw binary to be loaded
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_agc_load_firmware(const uint8_t *firmware);
+
+/**
+@brief Read the AGC status register for current status
+@param status A pointer to store the current status returned
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_agc_status(uint8_t* status);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_agc_wait_status(uint8_t status);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_agc_mailbox_read(uint8_t mailbox, uint8_t* value);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_agc_mailbox_write(uint8_t mailbox, uint8_t value);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_agc_start(uint8_t version, lgw_radio_type_t radio_type, uint8_t ana_gain, uint8_t dec_gain, bool full_duplex, bool lbt_enable);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_arb_load_firmware(const uint8_t *firmware);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_arb_status(uint8_t* status);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_arb_wait_status(uint8_t status);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_arb_debug_read(uint8_t reg_id, uint8_t* value);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_arb_debug_write(uint8_t reg_id, uint8_t value);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_arb_start(uint8_t version, const struct lgw_conf_ftime_s * ftime_context);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+uint8_t sx1302_arb_get_debug_stats_detect(uint8_t channel);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+uint8_t sx1302_arb_get_debug_stats_alloc(uint8_t channel);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+void sx1302_arb_print_debug_stats(void);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+uint16_t sx1302_lora_payload_crc(const uint8_t * data, uint8_t size);
+
+/**
+@brief Get the number of packets available in rx_buffer and fetch data from ...
+@brief ... the SX1302 if rx_buffer is empty.
+@param  nb_pkt A pointer to allocated memory to hold the number of packet fetched
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_fetch(uint8_t * nb_pkt);
+
+/**
+@brief Parse and return the next packet available in rx_buffer.
+@param context      Gateway configuration context
+@param p            The structure to get the packet parsed
+@return LGW_REG_SUCCESS if a packet could be parsed, LGW_REG_ERROR otherwise
+*/
+int sx1302_parse(lgw_context_t * context, struct lgw_pkt_rx_s * p);
+
+/**
+@brief Configure the delay to be applied by the SX1302 for TX to start
+@param rf_chain      RF chain index to be configured
+@param radio_type    Type of radio for this RF chain
+@param modulation    Modulation used for the TX
+@param bandwidth     Bandwidth used for the TX
+@param chirp_lowpass Chirp Low Pass filtering configuration
+@param delay         TX start delay calculated and applied
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_tx_set_start_delay(uint8_t rf_chain, lgw_radio_type_t radio_type, uint8_t modulation, uint8_t bandwidth, uint8_t chirp_lowpass, uint16_t * delay);
+
+/**
+@brief Compute the offset to be applied on RSSI for temperature compensation
+@param context  a pointer to the memory that holds the current temp comp context
+@param temperature  the temperature for which to compute the offset to be applied
+@return the offset to be applied to RSSI
+*/
+float sx1302_rssi_get_temperature_offset(struct lgw_rssi_tcomp_s * context, float temperature);
+
+/**
+@brief Get current TX status of the SX1302
+@param rf_chain the TX chain we want to get the status from
+@return current status
+*/
+uint8_t sx1302_tx_status(uint8_t rf_chain);
+
+/**
+@brief Get current RX status of the SX1302
+@param rf_chain the RX chain we want to get the status from
+@return current status
+@note NOT IMPLEMENTED
+*/
+uint8_t sx1302_rx_status(uint8_t rf_chain);
+
+/**
+@brief Abort current transmit
+@param rf_chain the TX chain on which we want to abort transmit
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int sx1302_tx_abort(uint8_t rf_chain);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_tx_configure(lgw_radio_type_t radio_type);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_send(lgw_radio_type_t radio_type, struct lgw_tx_gain_lut_s * tx_lut, bool lwan_public, struct lgw_conf_rxif_s * context_fsk, struct lgw_pkt_tx_s * pkt_data);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+int sx1302_set_gpio(uint8_t gpio_reg_val);
+
+/**
+@brief TODO
+@param TODO
+@return TODO
+*/
+double sx1302_dc_notch_delay(double if_freq_hz);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 121 - 0
sx1302/include/loragw_sx1302_rx.h

@@ -0,0 +1,121 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    SX1302 RX buffer Hardware Abstraction Layer
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_SX1302_RX_H
+#define _LORAGW_SX1302_RX_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/**
+@struct rx_packet_s
+@brief packet structure as contained in the sx1302 RX packet engine
+*/
+typedef struct rx_packet_s {
+    uint8_t     rxbytenb_modem;
+    uint8_t     rx_channel_in;
+    bool        crc_en;
+    uint8_t     coding_rate;                /* LoRa only */
+    uint8_t     rx_rate_sf;                 /* LoRa only */
+    uint8_t     modem_id;
+    int32_t     frequency_offset_error;     /* LoRa only */
+    uint8_t     payload[255];
+    bool        payload_crc_error;
+    bool        sync_error;                 /* LoRa only */
+    bool        header_error;               /* LoRa only */
+    bool        timing_set;                 /* LoRa only */
+    int8_t      snr_average;                /* LoRa only */
+    uint8_t     rssi_chan_avg;
+    uint8_t     rssi_signal_avg;            /* LoRa only */
+    uint8_t     rssi_chan_max_neg_delta;
+    uint8_t     rssi_chan_max_pos_delta;
+    uint8_t     rssi_sig_max_neg_delta;     /* LoRa only */
+    uint8_t     rssi_sig_max_pos_delta;     /* LoRa only */
+    uint32_t    timestamp_cnt;
+    uint16_t    rx_crc16_value;             /* LoRa only */
+    uint8_t     num_ts_metrics_stored;      /* LoRa only */
+    int8_t      timestamp_avg[255];         /* LoRa only */
+    int8_t      timestamp_stddev[255];      /* LoRa only */
+    uint8_t     packet_checksum;
+} rx_packet_t;
+
+/**
+@struct rx_buffer_s
+@brief buffer to hold the data fetched from the sx1302 RX buffer
+*/
+typedef struct rx_buffer_s {
+    uint8_t buffer[4096];   /*!> byte array to hald the data fetched from the RX buffer */
+    uint16_t buffer_size;   /*!> The number of bytes currently stored in the buffer */
+    int buffer_index;       /*!> Current parsing index in the buffer */
+    uint8_t buffer_pkt_nb;
+} rx_buffer_t;
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+@brief Initialize the rx_buffer instance
+@param self     A pointer to a rx_buffer handler
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int rx_buffer_new(rx_buffer_t * self);
+
+/**
+@brief Reset the rx_buffer instance
+@param self     A pointer to a rx_buffer handler
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int rx_buffer_del(rx_buffer_t * self);
+
+/**
+@brief Fetch packets from the SX1302 internal RX buffer, and count packets available.
+@param self     A pointer to a rx_buffer handler
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int rx_buffer_fetch(rx_buffer_t * self);
+
+/**
+@brief Parse the rx_buffer and return the first packet available in the given structure.
+@param self     A pointer to a rx_buffer handler
+@param pkt      A pointer to the structure to receive the packet parsed
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int rx_buffer_pop(rx_buffer_t * self, rx_packet_t * pkt);
+
+/* -------------------------------------------------------------------------- */
+/* --- DEBUG FUNCTIONS PROTOTYPES ------------------------------------------- */
+
+uint16_t rx_buffer_read_ptr_addr(void);
+
+uint16_t rx_buffer_write_ptr_addr(void);
+
+void rx_buffer_dump(FILE * file, uint16_t start_addr, uint16_t end_addr);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 148 - 0
sx1302/include/loragw_sx1302_timestamp.h

@@ -0,0 +1,148 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    SX1302 timestamp counter Hardware Abstraction Layer
+    Handles the conversion of a 32-bits 32MHz counter into a 32-bits 1 MHz counter.
+    This modules MUST be called regularly by the application to maintain counter
+    wrapping handling for conversion in 1MHz counter.
+    Provides function to compute the correction to be applied to the received
+    timestamp for demodulation processing time.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_SX1302_TIMESTAMP_H
+#define _LORAGW_SX1302_TIMESTAMP_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+#include <stdbool.h>    /* boolean type */
+
+#include "loragw_hal.h"
+#include "loragw_sx1302.h"
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/**
+@struct timestamp_counter_s
+@brief context to maintain the internal counters (inst and pps trig) rollover status
+*/
+struct timestamp_info_s {
+    uint32_t counter_us_27bits_ref;     /* reference value (last read) */
+    uint8_t  counter_us_27bits_wrap;    /* rollover/wrap status */
+};
+typedef struct timestamp_counter_s {
+    struct timestamp_info_s inst; /* holds current reference of the instantaneous counter */
+    struct timestamp_info_s pps;  /* holds current reference of the pps-trigged counter */
+} timestamp_counter_t;
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS ----------------------------------------------------- */
+
+/**
+@brief Initialize the timestamp_counter instance
+@param self     Pointer to the counter handler
+@return N/A
+*/
+void timestamp_counter_new(timestamp_counter_t * self);
+
+/**
+@brief Reset the timestamp_counter instance
+@param self     Pointer to the counter handler
+@return N/A
+*/
+void timestamp_counter_delete(timestamp_counter_t * self);
+
+/**
+@brief Update the counter wrapping status based on given current counter
+@param self     Pointer to the counter handler
+@param pps      Current value of the pps counter to be used for the update
+@param cnt      Current value of the freerun counter to be used for the update
+@return N/A
+*/
+void timestamp_counter_update(timestamp_counter_t * self, uint32_t pps, uint32_t cnt);
+
+/**
+@brief Convert the 27-bits counter given by the SX1302 to a 32-bits counter which wraps on a uint32_t.
+@param self     Pointer to the counter handler
+@param pps      Set to true to expand the counter based on the PPS trig wrapping status
+@param cnt_us   The 27-bits counter to be expanded
+@return the 32-bits counter
+*/
+uint32_t timestamp_counter_expand(timestamp_counter_t * self, bool pps, uint32_t cnt_us);
+
+/**
+@brief Convert the 27-bits packet timestamp to a 32-bits counter which wraps on a uint32_t.
+@param self     Pointer to the counter handler
+@param cnt_us   The packet 27-bits counter to be expanded
+@return the 32-bits counter
+*/
+uint32_t timestamp_pkt_expand(timestamp_counter_t * self, uint32_t cnt_us);
+
+/**
+@brief Reads the SX1302 internal counter register, and return the 32-bits 1 MHz counter
+@param self     Pointer to the counter handler
+@param pps      Current value of the freerun counter
+@param pps      Current value of the PPS counter
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int timestamp_counter_get(timestamp_counter_t * self, uint32_t * inst, uint32_t * pps);
+
+/**
+@brief Get the correction to applied to the LoRa packet timestamp (count_us)
+@param context          gateway configuration context
+@param bandwidth        modulation bandwidth
+@param datarate         modulation datarate
+@param coderate         modulation coding rate
+@param crc_en           indicates if CRC is enabled or disabled
+@param payload_length   payload length
+@param dft_peak_mode    DFT peak mode configuration of the modem
+@return The correction to be applied to the packet timestamp, in microseconds
+*/
+int32_t timestamp_counter_correction(lgw_context_t * context, uint8_t bandwidth, uint8_t datarate, uint8_t coderate, bool crc_en, uint8_t payload_length, sx1302_rx_dft_peak_mode_t dft_peak_mode);
+
+/**
+@brief Configure the SX1302 to output legacy timestamp or precision timestamp
+@note  Legacy timestamp gives a timestamp latched at the end of the packet
+@note  Precision timestamp gives a timestamp latched at the end of the header
+@note  and additionally supplies metrics every N symbols troughout the payload.
+@param enable_precision_ts  A boolean to enable precision timestamp output.
+@param max_ts_metrics       The number of timestamp metrics to be returned when precision timestamp is enabled
+@param nb_symbols           The sampling rate of timestamp metrics
+@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
+*/
+int timestamp_counter_mode(bool ftime_enable);
+
+/**
+@brief Compute a precise timestamp (fine timestamp) based on given coarse timestamp, metrics given by sx1302 and current GW xtal drift
+@param ts_metrics_nb The number of timestamp metrics given in ts_metrics array
+@param ts_metrics An array containing timestamp metrics to compute fine timestamp
+@param pkt_coarse_tmst The packet coarse timestamp
+@param sf packet spreading factor, used to shift timestamp from end of header to end of preamble
+@param if_freq_hz the IF frequency, to take into account DC noth delay
+@param result_ftime A pointer to store the resulting fine timestamp
+@return 0 if success, -1 otherwise
+*/
+int precise_timestamp_calculate(uint8_t ts_metrics_nb, const int8_t * ts_metrics, uint32_t pkt_coarse_tmst, uint8_t sf, int32_t if_freq_hz, double pkt_freq_error, uint32_t * result_ftime);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 98 - 0
sx1302/include/loragw_usb.h

@@ -0,0 +1,98 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    Host specific functions to address the LoRa concentrator registers through
+    a USB interface.
+    Single-byte read/write and burst read/write.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _LORAGW_USB_H
+#define _LORAGW_USB_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>   /* C99 types*/
+
+#include "loragw_com.h"
+
+#include "config.h"   /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+#define LGW_USB_SUCCESS     0
+#define LGW_USB_ERROR       -1
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+ *
+*/
+
+int lgw_usb_open(const char * com_path, void **com_target_ptr);
+
+/**
+ *
+*/
+
+int lgw_usb_close(void *com_target);
+
+/**
+ *
+*/
+int lgw_usb_w(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t data);
+
+/**
+ *
+*/
+int lgw_usb_r(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data);
+
+/**
+ *
+*/
+int lgw_usb_wb(void *com_target, uint8_t spi_mux_target, uint16_t address, const uint8_t *data, uint16_t size);
+
+/**
+ *
+*/
+int lgw_usb_rb(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data, uint16_t size);
+
+/**
+ *
+*/
+int lgw_usb_rmw(void *com_target, uint16_t address, uint8_t offs, uint8_t leng, uint8_t data);
+
+/**
+ *
+ **/
+int lgw_usb_set_write_mode(lgw_com_write_mode_t write_mode);
+
+/**
+ *
+ **/
+int lgw_usb_flush(void *com_target);
+
+/**
+ *
+ **/
+uint16_t lgw_usb_chunk_size(void);
+
+/**
+ *
+ **/
+int lgw_usb_get_temperature(void *com_target, float * temperature);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 46 - 0
sx1302/include/sx1250_com.h

@@ -0,0 +1,46 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1250 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _SX1250_COM_H
+#define _SX1250_COM_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "loragw_com.h"
+#include "sx1250_defs.h"
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int sx1250_com_w(lgw_com_type_t com_type, void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size);
+int sx1250_com_r(lgw_com_type_t com_type, void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 93 - 0
sx1302/include/sx1250_defs.h

@@ -0,0 +1,93 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1250 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _SX1250_DEFS_H
+#define _SX1250_DEFS_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+#define SX1250_FREQ_TO_REG(f) (uint32_t)((uint64_t)f * (1 << 25) / 32000000U)
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+typedef enum {
+    CALIBRATE               = 0x89,
+    CALIBRATE_IMAGE         = 0x98,
+    CLR_IRQ_STATUS          = 0x02,
+    STOP_TIMER_ON_PREAMBLE  = 0x9F,
+    SET_RFSWITCHMODE        = 0x9D,
+    GET_IRQ_STATUS          = 0x12,
+    GET_RX_BUFFER_STATUS    = 0x13,
+    GET_PACKET_STATUS       = 0x14,
+    READ_BUFFER             = 0x1E,
+    READ_REGISTER           = 0x1D,
+    SET_DIO_IRQ_PARAMS      = 0x08,
+    SET_MODULATION_PARAMS   = 0x8B,
+    SET_PA_CONFIG           = 0x95,
+    SET_PACKET_PARAMS       = 0x8C,
+    SET_PACKET_TYPE         = 0x8A,
+    SET_RF_FREQUENCY        = 0x86,
+    SET_BUFFER_BASE_ADDRESS = 0x8F,
+    SET_SLEEP               = 0x84,
+    SET_STANDBY             = 0x80,
+    SET_RX                  = 0x82,
+    SET_TX                  = 0x83,
+    SET_TX_PARAMS           = 0x8E,
+    WRITE_BUFFER            = 0x0E,
+    WRITE_REGISTER          = 0x0D,
+    SET_TXCONTINUOUSWAVE    = 0xD1,
+    SET_TXCONTINUOUSPREAMBLE= 0xD2,
+    GET_STATUS              = 0xC0,
+    SET_REGULATORMODE       = 0x96,
+    SET_FS                  = 0xC1,
+    GET_DEVICE_ERRORS       = 0x17
+} sx1250_op_code_t;
+
+typedef enum {
+    STDBY_RC                = 0x00,
+    STDBY_XOSC              = 0x01
+} sx1250_standby_modes_t;
+
+typedef enum {
+    PACKET_TYPE_GFSK        = 0x00,
+    PACKET_TYPE_LORA        = 0x01
+} sx1250_packet_type_t;
+
+typedef enum {
+    SET_RAMP_10U            = 0x00,
+    SET_RAMP_20U            = 0x01,
+    SET_RAMP_40U            = 0x02,
+    SET_RAMP_80U            = 0x03,
+    SET_RAMP_200U           = 0x04,
+    SET_RAMP_800U           = 0x05,
+    SET_RAMP_1700U          = 0x06,
+    SET_RAMP_3400U          = 0x07
+} sx1250_ramp_time_t;
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 45 - 0
sx1302/include/sx1250_spi.h

@@ -0,0 +1,45 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1250 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _SX1250_SPI_H
+#define _SX1250_SPI_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "sx1250_defs.h"
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int sx1250_spi_w(void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size);
+int sx1250_spi_r(void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 45 - 0
sx1302/include/sx1250_usb.h

@@ -0,0 +1,45 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1250 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _SX1250_USB_H
+#define _SX1250_USB_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "sx1250_defs.h"
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int sx1250_usb_w(void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size);
+int sx1250_usb_r(void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 45 - 0
sx1302/include/sx125x_com.h

@@ -0,0 +1,45 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1255/SX1257 radios SPI access.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+#ifndef _SX125X_COM_H
+#define _SX125X_COM_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+
+#include "loragw_com.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED TYPES ------------------------------------------------ */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int sx125x_com_r(lgw_com_type_t com_type, void *com_target, uint8_t spi_mux_target, uint8_t address, uint8_t *data);
+int sx125x_com_w(lgw_com_type_t com_type, void *com_target, uint8_t spi_mux_target, uint8_t address, uint8_t data);
+
+#endif
+/* --- EOF ------------------------------------------------------------------ */

+ 43 - 0
sx1302/include/sx125x_spi.h

@@ -0,0 +1,43 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1255/SX1257 radios SPI access.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+#ifndef _SX125X_SPI_H
+#define _SX125X_SPI_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+
+/* -------------------------------------------------------------------------- */
+/* --- INTERNAL SHARED TYPES ------------------------------------------------ */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+int sx125x_spi_r(void *com_target, uint8_t spi_mux_target, uint8_t address, uint8_t *data);
+int sx125x_spi_w(void *com_target, uint8_t spi_mux_target, uint8_t address, uint8_t data);
+
+#endif
+/* --- EOF ------------------------------------------------------------------ */

+ 73 - 0
sx1302/include/sx1261_com.h

@@ -0,0 +1,73 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle the sx1261 radio used for LBT/Spectral Scan.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _SX1261_COM_H
+#define _SX1261_COM_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "loragw_com.h"
+#include "sx1261_defs.h"
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
+
+/**
+ *
+*/
+int sx1261_com_open(lgw_com_type_t com_type, const char *com_path);
+
+/**
+ *
+*/
+int sx1261_com_close(void);
+
+/**
+ *
+*/
+int sx1261_com_w(sx1261_op_code_t op_code, uint8_t *data, uint16_t size);
+
+/**
+ *
+*/
+int sx1261_com_r(sx1261_op_code_t op_code, uint8_t *data, uint16_t size);
+
+/**
+ *
+*/
+int sx1261_com_set_write_mode(lgw_com_write_mode_t write_mode);
+
+/**
+ *
+*/
+int sx1261_com_flush(void);
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 109 - 0
sx1302/include/sx1261_defs.h

@@ -0,0 +1,109 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1261 radio.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+#ifndef _SX1261_DEFS_H
+#define _SX1261_DEFS_H
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types*/
+
+#include "config.h"     /* library configuration options (dynamically generated) */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC MACROS -------------------------------------------------------- */
+
+#define SX1261_FREQ_TO_REG(f) (uint32_t)((uint64_t)f * (1 << 25) / 32000000U)
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC CONSTANTS ----------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC TYPES --------------------------------------------------------- */
+
+typedef enum {
+    SX1261_CALIBRATE_IMAGE          = 0x98,
+    SX1261_CLR_IRQ_STATUS           = 0x02,
+    SX1261_STOP_TIMER_ON_PREAMBLE   = 0x9F,
+    SX1261_SET_RFSWITCHMODE         = 0x9D,
+    SX1261_GET_IRQ_STATUS           = 0x12,
+    SX1261_GET_RX_BUFFER_STATUS     = 0x13,
+    SX1261_GET_PACKET_STATUS        = 0x14,
+    SX1261_GET_RSSI_INST            = 0x15,
+    SX1261_READ_BUFFER              = 0x1E,
+    SX1261_READ_REGISTER            = 0x1D,
+    SX1261_SET_DIO_IRQ_PARAMS       = 0x08,
+    SX1261_SET_MODULATION_PARAMS    = 0x8B,
+    SX1261_SET_PA_CONFIG            = 0x95,
+    SX1261_SET_PACKET_PARAMS        = 0x8C,
+    SX1261_SET_PACKET_TYPE          = 0x8A,
+    SX1261_SET_RF_FREQUENCY         = 0x86,
+    SX1261_SET_BUFFER_BASE_ADDRESS  = 0x8F,
+    SX1261_SET_SLEEP                = 0x84,
+    SX1261_SET_STANDBY              = 0x80,
+    SX1261_SET_RX                   = 0x82,
+    SX1261_SET_TX                   = 0x83,
+    SX1261_SET_TX_PARAMS            = 0x8E,
+    SX1261_WRITE_BUFFER             = 0x0E,
+    SX1261_WRITE_REGISTER           = 0x0D,
+    SX1261_SET_TXCONTINUOUSWAVE     = 0xD1,
+    SX1261_SET_TXCONTINUOUSPREAMBLE = 0xD2,
+    SX1261_GET_STATUS               = 0xC0,
+    SX1261_SET_REGULATORMODE        = 0x96,
+    SX1261_SET_FS                   = 0xC1,
+    SX1261_GET_DEVICE_ERRORS        = 0x17
+} sx1261_op_code_t;
+
+typedef enum {
+    SX1261_STDBY_RC                 = 0x00,
+    SX1261_STDBY_XOSC               = 0x01
+} sx1261_standby_modes_t;
+
+typedef enum {
+    SX1261_PACKET_TYPE_GFSK         = 0x00,
+    SX1261_PACKET_TYPE_LORA         = 0x01
+} sx1261_packet_type_t;
+
+typedef enum {
+    SX1261_SET_RAMP_10U             = 0x00,
+    SX1261_SET_RAMP_20U             = 0x01,
+    SX1261_SET_RAMP_40U             = 0x02,
+    SX1261_SET_RAMP_80U             = 0x03,
+    SX1261_SET_RAMP_200U            = 0x04,
+    SX1261_SET_RAMP_800U            = 0x05,
+    SX1261_SET_RAMP_1700U           = 0x06,
+    SX1261_SET_RAMP_3400U           = 0x07
+} sx1261_ramp_time_t;
+
+typedef enum {
+    SX1261_STATUS_MODE_STBY_RC      = 0x20, /* 0x02 - bits 6:4 */
+    SX1261_STATUS_MODE_STBY_XOSC    = 0x30, /* 0x03 - bits 6:4 */
+    SX1261_STATUS_MODE_FS           = 0x40, /* 0x04 - bits 6:4 */
+    SX1261_STATUS_MODE_RX           = 0x50, /* 0x05 - bits 6:4 */
+    SX1261_STATUS_MODE_TX           = 0x60  /* 0x06 - bits 6:4 */
+} sx1261_status_mode_t;
+
+typedef enum {
+    SX1261_STATUS_READY             = 0x02, /* 0x02 - bits 3:1 */
+    SX1261_STATUS_TIMEOUT           = 0x03, /* 0x03 - bits 3:1 */
+    SX1261_STATUS_PROCESSING_ERROR  = 0x04, /* 0x04 - bits 3:1 */
+    SX1261_STATUS_EXECUTION_FAILED  = 0x05, /* 0x05 - bits 3:1 */
+    SX1261_STATUS_TX_DONE           = 0x06  /* 0x06 - bits 3:1 */
+} sx1261_status_command_status_t;
+
+#endif
+
+/* --- EOF ------------------------------------------------------------------ */

+ 247 - 0
sx1302/include/tinymt32.h

@@ -0,0 +1,247 @@
+#ifndef TINYMT32_H
+#define TINYMT32_H
+/**
+ * @file tinymt32.h
+ *
+ * @brief Tiny Mersenne Twister only 127 bit internal state
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (University of Tokyo)
+ *
+ * Copyright (C) 2011 Mutsuo Saito, Makoto Matsumoto,
+ * Hiroshima University and The University of Tokyo.
+ * All rights reserved.
+ *
+ * The 3-clause BSD License is applied to this software, see
+ * LICENSE.txt
+ */
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#define TINYMT32_MEXP 127
+#define TINYMT32_SH0 1
+#define TINYMT32_SH1 10
+#define TINYMT32_SH8 8
+#define TINYMT32_MASK UINT32_C(0x7fffffff)
+#define TINYMT32_MUL (1.0f / 16777216.0f)
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * tinymt32 internal state vector and parameters
+ */
+struct TINYMT32_T {
+    uint32_t status[4];
+    uint32_t mat1;
+    uint32_t mat2;
+    uint32_t tmat;
+};
+
+typedef struct TINYMT32_T tinymt32_t;
+
+void tinymt32_init(tinymt32_t * random, uint32_t seed);
+void tinymt32_init_by_array(tinymt32_t * random, uint32_t init_key[],
+                            int key_length);
+
+#if defined(__GNUC__)
+/**
+ * This function always returns 127
+ * @param random not used
+ * @return always 127
+ */
+inline static int tinymt32_get_mexp(
+    tinymt32_t * random  __attribute__((unused))) {
+    return TINYMT32_MEXP;
+}
+#else
+inline static int tinymt32_get_mexp(tinymt32_t * random) {
+    return TINYMT32_MEXP;
+}
+#endif
+
+/**
+ * This function changes internal state of tinymt32.
+ * Users should not call this function directly.
+ * @param random tinymt internal status
+ */
+inline static void tinymt32_next_state(tinymt32_t * random) {
+    uint32_t x;
+    uint32_t y;
+
+    y = random->status[3];
+    x = (random->status[0] & TINYMT32_MASK)
+        ^ random->status[1]
+        ^ random->status[2];
+    x ^= (x << TINYMT32_SH0);
+    y ^= (y >> TINYMT32_SH0) ^ x;
+    random->status[0] = random->status[1];
+    random->status[1] = random->status[2];
+    random->status[2] = x ^ (y << TINYMT32_SH1);
+    random->status[3] = y;
+    random->status[1] ^= -((int32_t)(y & 1)) & random->mat1;
+    random->status[2] ^= -((int32_t)(y & 1)) & random->mat2;
+}
+
+/**
+ * This function outputs 32-bit unsigned integer from internal state.
+ * Users should not call this function directly.
+ * @param random tinymt internal status
+ * @return 32-bit unsigned pseudorandom number
+ */
+inline static uint32_t tinymt32_temper(tinymt32_t * random) {
+    uint32_t t0, t1;
+    t0 = random->status[3];
+#if defined(LINEARITY_CHECK)
+    t1 = random->status[0]
+        ^ (random->status[2] >> TINYMT32_SH8);
+#else
+    t1 = random->status[0]
+        + (random->status[2] >> TINYMT32_SH8);
+#endif
+    t0 ^= t1;
+    t0 ^= -((int32_t)(t1 & 1)) & random->tmat;
+    return t0;
+}
+
+/**
+ * This function outputs floating point number from internal state.
+ * Users should not call this function directly.
+ * @param random tinymt internal status
+ * @return floating point number r (1.0 <= r < 2.0)
+ */
+inline static float tinymt32_temper_conv(tinymt32_t * random) {
+    uint32_t t0, t1;
+    union {
+        uint32_t u;
+        float f;
+    } conv;
+
+    t0 = random->status[3];
+#if defined(LINEARITY_CHECK)
+    t1 = random->status[0]
+        ^ (random->status[2] >> TINYMT32_SH8);
+#else
+    t1 = random->status[0]
+        + (random->status[2] >> TINYMT32_SH8);
+#endif
+    t0 ^= t1;
+    conv.u = ((t0 ^ (-((int32_t)(t1 & 1)) & random->tmat)) >> 9)
+              | UINT32_C(0x3f800000);
+    return conv.f;
+}
+
+/**
+ * This function outputs floating point number from internal state.
+ * Users should not call this function directly.
+ * @param random tinymt internal status
+ * @return floating point number r (1.0 < r < 2.0)
+ */
+inline static float tinymt32_temper_conv_open(tinymt32_t * random) {
+    uint32_t t0, t1;
+    union {
+        uint32_t u;
+        float f;
+    } conv;
+
+    t0 = random->status[3];
+#if defined(LINEARITY_CHECK)
+    t1 = random->status[0]
+        ^ (random->status[2] >> TINYMT32_SH8);
+#else
+    t1 = random->status[0]
+        + (random->status[2] >> TINYMT32_SH8);
+#endif
+    t0 ^= t1;
+    conv.u = ((t0 ^ (-((int32_t)(t1 & 1)) & random->tmat)) >> 9)
+              | UINT32_C(0x3f800001);
+    return conv.f;
+}
+
+/**
+ * This function outputs 32-bit unsigned integer from internal state.
+ * @param random tinymt internal status
+ * @return 32-bit unsigned integer r (0 <= r < 2^32)
+ */
+inline static uint32_t tinymt32_generate_uint32(tinymt32_t * random) {
+    tinymt32_next_state(random);
+    return tinymt32_temper(random);
+}
+
+/**
+ * This function outputs floating point number from internal state.
+ * This function is implemented using multiplying by (1 / 2^24).
+ * floating point multiplication is faster than using union trick in
+ * my Intel CPU.
+ * @param random tinymt internal status
+ * @return floating point number r (0.0 <= r < 1.0)
+ */
+inline static float tinymt32_generate_float(tinymt32_t * random) {
+    tinymt32_next_state(random);
+    return (tinymt32_temper(random) >> 8) * TINYMT32_MUL;
+}
+
+/**
+ * This function outputs floating point number from internal state.
+ * This function is implemented using union trick.
+ * @param random tinymt internal status
+ * @return floating point number r (1.0 <= r < 2.0)
+ */
+inline static float tinymt32_generate_float12(tinymt32_t * random) {
+    tinymt32_next_state(random);
+    return tinymt32_temper_conv(random);
+}
+
+/**
+ * This function outputs floating point number from internal state.
+ * This function is implemented using union trick.
+ * @param random tinymt internal status
+ * @return floating point number r (0.0 <= r < 1.0)
+ */
+inline static float tinymt32_generate_float01(tinymt32_t * random) {
+    tinymt32_next_state(random);
+    return tinymt32_temper_conv(random) - 1.0f;
+}
+
+/**
+ * This function outputs floating point number from internal state.
+ * This function may return 1.0 and never returns 0.0.
+ * @param random tinymt internal status
+ * @return floating point number r (0.0 < r <= 1.0)
+ */
+inline static float tinymt32_generate_floatOC(tinymt32_t * random) {
+    tinymt32_next_state(random);
+    return 1.0f - tinymt32_generate_float(random);
+}
+
+/**
+ * This function outputs floating point number from internal state.
+ * This function returns neither 0.0 nor 1.0.
+ * @param random tinymt internal status
+ * @return floating point number r (0.0 < r < 1.0)
+ */
+inline static float tinymt32_generate_floatOO(tinymt32_t * random) {
+    tinymt32_next_state(random);
+    return tinymt32_temper_conv_open(random) - 1.0f;
+}
+
+/**
+ * This function outputs double precision floating point number from
+ * internal state. The returned value has 32-bit precision.
+ * In other words, this function makes one double precision floating point
+ * number from one 32-bit unsigned integer.
+ * @param random tinymt internal status
+ * @return floating point number r (0.0 <= r < 1.0)
+ */
+inline static double tinymt32_generate_32double(tinymt32_t * random) {
+    tinymt32_next_state(random);
+    return tinymt32_temper(random) * (1.0 / 4294967296.0);
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif

+ 515 - 0
sx1302/readme.md

@@ -0,0 +1,515 @@
+	 / _____)             _              | |
+	( (____  _____ ____ _| |_ _____  ____| |__
+	 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+	 _____) ) ____| | | || |_| ____( (___| | | |
+	(______/|_____)_|_|_| \__)_____)\____)_| |_|
+	  (C)2020 Semtech
+
+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 the following modules:
+
+1. abstraction layer
+  * loragw_hal
+  * loragw_reg
+  * loragw_aux
+  * loragw_cal
+  * loragw_lbt
+  * loragw_sx1302
+  * loragw_sx1302_rx
+  * loragw_sx1302_timestamp
+  * loragw_sx125x
+  * loragw_sx1250
+  * loragw_sx1261
+
+2. communication layer for sx1302
+  * loragw_com
+  * loragw_spi
+  * loragw_usb
+
+3. communication layer for sx1255/SX1257 radios
+  * sx125x_com
+  * sx125x_spi
+
+4. communication layer for sx1250 radios
+  * sx1250_com
+  * sx1250_spi
+  * sx1250_usb
+
+5. communication layer for STM32 MCU (USB)
+  * loragw_mcu
+
+6. communication layer for sx1261 radio (LBT / Spectral Scan)
+  * sx1261_com
+  * sx1261_spi
+  * sx1261_usb
+
+7. peripherals
+  * loragw_i2c
+  * loragw_gps
+  * loragw_stts751
+  * loragw_ad5338r
+
+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
+* lgw_get_trigcnt, to get the value of the sx1302 internal counter at last PPS
+* lgw_get_instcnt, to get the value of the sx1302 internal counter
+* lgw_get_eui, to get the sx1302 chip EUI
+* lgw_get_temperature, to get the current temperature
+* lgw_time_on_air, to get the Time On Air of a packet
+* lgw_spectral_scan_start, to start scaning a particular channel
+* lgw_spectral_scan_get_status, to get the status of the current scan
+* lgw_spectral_scan_get_results, to get the results of the completed scan
+* lgw_spectral_scan_abort, to abort curretn scan
+
+For an standard application, include only this module.
+The use of this module is detailed on the usage section.
+
+/!\ When sending a packet, there is a delay (approx 1.5ms) for the analog
+circuitry to start and be stable. This delay is adjusted by the HAL depending
+on the board version (lgw_i_tx_start_delay_us).
+
+In 'timestamp' mode, this is transparent: the modem is started
+lgw_i_tx_start_delay_us microseconds before the user-set timestamp value is
+reached, the preamble of the packet start right when the internal timestamp
+counter reach target value.
+
+In 'immediate' mode, the packet is emitted as soon as possible: transferring the
+packet (and its parameters) from the host to the concentrator takes some time,
+then there is the lgw_i_tx_start_delay_us, then the packet is emitted.
+
+In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is
+emitted lgw_i_tx_start_delay_us microsenconds after a rising edge of the
+trigger signal. Because there is no way to anticipate the triggering event and
+start the analog circuitry beforehand, that delay must be taken into account in
+the protocol.
+
+### 2.2. loragw_reg
+
+This module is used to access to the LoRa concentrator registers by name instead
+of by address:
+
+* lgw_connect, to initialise and check the connection with the hardware
+* lgw_disconnect, to disconnect the hardware
+* lgw_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
+* lgw_mem_rb, read from a memory section in burst
+* lgw_mem_wb, write to a memory section in burst
+
+This module handles 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/USB maximum
+burst length constraints.
+
+It make the code much easier to read and to debug.
+Moreover, if registers are relocated between different hardware revisions but
+keep the same function, the code written using register names can be reused "as
+is".
+
+If you need access to all the registers, include this module in your
+application.
+
+**/!\ Warning** please be sure to have a good understanding of the LoRa
+concentrator inner working before accessing the internal registers directly.
+
+### 2.3. loragw_com
+
+This module contains the functions to access the LoRa concentrator register
+array through the SPI or USB interfaces:
+
+* 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
+
+This modules is an abstract interface, it then relies on the following modules
+to actually perform the interfacing:
+
+* loragw_spi : for SPI interface
+* loragw_usb : for USB interface
+
+Please *do not* include that module directly into your application.
+
+**/!\ Warning** Accessing the LoRa concentrator register array without the
+checks and safety provided by the functions in loragw_reg is not recommended.
+
+### 2.4. loragw_aux
+
+This module contains a single host-dependant function wait_ms to pause for a
+defined amount of milliseconds.
+
+The procedure to start and configure the LoRa concentrator hardware contained in
+the loragw_hal module requires to wait for several milliseconds at certain
+steps, typically to allow for supply voltages or clocks to stabilize after been
+switched on.
+
+An accuracy of 1 ms or less is ideal.
+If your system does not allow that level of accuracy, make sure that the actual
+delay is *longer* that the time specified when the function is called (ie.
+wait_ms(X) **MUST NOT** before X milliseconds under any circumstance).
+
+If the minimum delays are not guaranteed during the configuration and start
+procedure, the hardware might not work at nominal performance.
+Most likely, it will not work at all.
+
+### 2.5. loragw_gps
+
+This module contains functions to synchronize the concentrator internal
+counter with an absolute time reference, in our case a GPS satellite receiver.
+
+The internal concentrator counter is used to timestamp incoming packets and to
+triggers outgoing packets with a microsecond accuracy.
+In some cases, it might be useful to be able to transform that internal
+timestamp (that is independent for each concentrator running in a typical
+networked system) into an absolute GPS time.
+
+In a typical implementation a GPS specific thread will be called, doing the
+following things after opening the serial port:
+
+* blocking reads on the serial port (using system read() function)
+* parse UBX messages (using lgw_parse_ubx) to get actual native GPS time
+* parse NMEA sentences (using lgw_parse_nmea) to get location and UTC time
+Note: the RMC sentence gives UTC time, not native GPS time.
+
+And each time an NAV-TIMEGPS UBX message has been received:
+
+* get the concentrator timestamp (using lgw_get_trigcnt, mutex needed to
+  protect access to the concentrator)
+* get the GPS time contained in the UBX message (using lgw_gps_get)
+* call the lgw_gps_sync function (use mutex to protect the time reference that
+  should be a global shared variable).
+
+Then, in other threads, you can simply used that continuously adjusted time
+reference to convert internal timestamps to GPS time (using lgw_cnt2gps) or
+the other way around (using lgw_gps2cnt). Inernal concentrator timestamp can
+also be converted to/from UTC time using lgw_cnt2utc/lgw_utc2cnt functions.
+
+### 2.6. loragw_sx125x
+
+This module contains functions to handle the configuration of SX1255 and
+SX1257 radios. In order to communicate with the radio, it relies on the
+following modules:
+
+* sx125x_com : abstract interfacing to select USB or SPI interface
+* sx125x_spi : implementation of the SPI interface
+
+### 2.7. loragw_sx1250
+
+This module contains functions to handle the configuration of SX1250 radios. In
+order to communicate with the radio, it relies on the following modules:
+
+* sx1250_com : abstract interfacing to select USB or SPI interface
+* sx1250_spi : implementation of the SPI interface
+* sx1250_usb : implementation of the USB interface
+
+### 2.8. loragw_sx1302
+
+This module contains functions to abstract SX1302 concentrator capabilities.
+
+### 2.9. loragw_sx1302_rx
+
+This module is a sub-module of the loragw_sx1302 module focusing on abstracting
+the RX buffer of the SX1302.
+
+### 2.10. loragw_sx1302_timestamp
+
+This module is a sub-module of the loragw_sx1302 module focusing on abstracting
+the timestamp counter of the SX1302.
+It converts the 32-bits 32MHz internal counter of the SX1302 to a 32-bits 1MHz
+counter.
+This module needs to be called regularly by upper layers to maintain counter
+wrapping when converting from 32MHz to 1MHz.
+It also provides function to add correction to the timestamp counter to take
+into account the LoRa demodulation processing time.
+
+### 2.11. loragw_stts751
+
+This module contains a very basic driver for the STmicroelectronics ST751
+temperature sensor which is on the CoreCell reference design.
+
+### 2.12. loragw_ad5338r
+
+This module contains a very basic driver for the Analog Devices AD5338R DAC used
+on the Semtech CN490 Full Duplex reference design to set the PA fixed gain.
+
+### 2.13. loragw_i2c
+
+This module provides basic function to communicate with I2C devices on the board.
+It is used in this project for accessing the temperature sensor, the AD5338R DAC...
+
+### 2.14. loragw_sx1261
+
+This module contains functions to handle the configuration of SX1261 radio for
+Listen-Before-Talk or Spectral Scan functionnalities. In order to communicate
+with the radio, it relies on the following modules:
+
+* sx1261_com : abstract interfacing to select USB or SPI interface
+* sx1261_spi : implementation of the SPI interface
+* sx1261_usb : implementation of the USB interface
+
+This module will also load the sx1261 firmware patch RAM, necessary to support
+Listen-Before-Talk and spectral scan features, from the sx1261_pram.var file.
+
+### 2.15. loragw_lbt
+
+This module contains functions to start and stop the Listen-Before-Talk feature
+when it is enabled. Those functions are called by the lgw_send() function to
+ensure that the concentrator is allowed to transmit.
+
+Listen-Before-Talk (LBT) and Spectral Scan features need an additional sx1261
+radio to be configured.
+
+The Listen-Before-Talk feature works as follows:
+
+* the HAL configures the sx1261 for scanning the channel on which it needs to
+transmit.
+* the SX1261 will scan the channel and set a GPIO to high or low depending if
+the channel is busy or not (according to scanning parameters)
+* the sx1302 AGC firmware will check the status of this GPIO before actually
+starting the transmit, to ensure it is allowed. The AGC fw sets its status
+register to inform if the transmit could be done or not.
+* the HAL waits for the transmit to be initiated and checks if it was allowed or
+not.
+* the HAL stops the scanning, and return the tramsit status to the caller.
+
+### 2.16. loragw_mcu
+
+This module contains the functions to setup the communication interface with the
+STM32 MCU, and to communicate with the sx1302 and the radios when the host and
+the concentrator are connected through USB llink.
+
+The MCU acts as a simple USB <-> SPI bridge. This means that the HAL running on
+the host is the same, for both SPI or USB gateways.
+
+But, as the USB communication link brings a 1ms latency for each transfer, the
+MCU provides a mean to group register write requests in one single USB transfer.
+It is necessary when a particular configuration has to be done in a time
+critical task.
+
+For this, 2 new functions has been added:
+* lgw_com_set_write_mode, to indicate if the following calls to lgw_com_w(b)
+need to be grouped on a single USB transfer (BULK mode) or not (SINGLE mode).
+* lgw_com_flush, to actually perform the USB transfer of all grouped commands
+if BULK mode was selected.
+
+Both functions will do nothing in case of SPI.
+
+The same mechanism can be used to configure the sx1261 radio.
+
+## 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 SX1302 chip
+* Semtech SX1250, 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. GPS receiver (or other GNSS system)
+
+To use the GPS module of the library, the host must be connected to a GPS
+receiver via a serial link (or an equivalent receiver using a different
+satellite constellation).
+The serial link must appear as a "tty" device in the /dev/ directory, and the
+user launching the program must have the proper system rights to read and
+write on that device.
+Use `chmod a+rw` to allow all users to access that specific tty device, or use
+sudo to run all your programs (eg. `sudo ./test_loragw_gps`).
+
+In the current revision, the library only reads data from the serial port,
+expecting to receive NMEA frames that are generally sent by GPS receivers as
+soon as they are powered up, and UBX messages which are proprietary to u-blox
+modules.
+
+The GPS receiver **MUST** send UBX messages shortly after sending a PPS pulse
+on to allow internal concentrator timestamps to be converted to absolute GPS time.
+If the GPS receiver sends a GGA NMEA sentence, the gateway 3D position will
+also be available.
+
+### 4.3. Additionnal SX1261 radio
+
+In order to perform Listen-Before-Talk and/or Spectral Scan, an additional SX1261
+radio is required. Its internal firmware also needs to be patched (patch RAM) to
+support those particular features.
+
+## 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. Notes
+
+### 6.1. Spreading factor SF5 & SF6
+
+The sx1302 supports SF5 and SF6 spreading factors, and the HAL also. But it is
+important to note that the only syncword supported for SF5 and SF6 is 0x12
+(also known as "private").
+
+This is true whatever how of the "lorawan_public" field of lgw_conf_board_s is
+set.
+
+## 7. License
+
+Copyright (c) 2019, 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*

+ 515 - 0
sx1302/source/agc_fw_sx1250.var

@@ -0,0 +1,515 @@
+static uint8_t agc_firmware_sx1250[8192] = { 
+0x8A, 0x51, 0xF0, 0x6F, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xE3, 0x40, 
+0xC8, 0xC0, 0x5F, 0xC8, 0xC9, 0x00, 0x60, 0xC8, 0xCA, 0x00, 0x61, 0x08, 0xCB, 0x40, 0x48, 0x30, 
+0xDA, 0x40, 0x62, 0x08, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x6F, 0xE1, 0x00, 0xC1, 0x70, 0xC8, 0xC0, 
+0x48, 0x30, 0xDA, 0x40, 0x61, 0x08, 0xDB, 0x80, 0x01, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x07, 0x70, 
+0xE0, 0xC0, 0x3A, 0xB0, 0xDF, 0xC0, 0xDF, 0x8B, 0x23, 0x68, 0xE0, 0x8B, 0x23, 0x68, 0x00, 0x00, 
+0x0D, 0x70, 0x83, 0x52, 0x03, 0x53, 0xC8, 0xC0, 0x05, 0x30, 0xC9, 0x00, 0x84, 0x30, 0xCA, 0x00, 
+0x48, 0x30, 0xCB, 0x81, 0xDA, 0x40, 0x61, 0x08, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 
+0x0D, 0x70, 0xC8, 0xC0, 0x05, 0x30, 0xC9, 0x00, 0x85, 0x70, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 
+0xDA, 0x40, 0x61, 0x08, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x0D, 0x70, 0xC8, 0xC0, 
+0x05, 0x30, 0xC9, 0x00, 0x82, 0x30, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xDA, 0x40, 0x61, 0x08, 
+0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x0D, 0x70, 0xC8, 0xC0, 0x05, 0x30, 0xC9, 0x00, 
+0x83, 0x70, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xDA, 0x40, 0x61, 0x08, 0xDB, 0x80, 0x04, 0xF0, 
+0x5C, 0x27, 0x8A, 0x51, 0x61, 0x8B, 0x66, 0xA8, 0x9C, 0x91, 0x67, 0xE8, 0x1C, 0x51, 0x0D, 0x70, 
+0xC8, 0xC0, 0x05, 0x30, 0xC9, 0x00, 0x80, 0xF0, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xDA, 0x40, 
+0x61, 0x08, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x05, 0x30, 0xDF, 0xC0, 0xDF, 0x8B, 
+0x77, 0x28, 0x0D, 0x70, 0x83, 0x52, 0x03, 0x53, 0xC8, 0xC0, 0x05, 0x30, 0xC9, 0x00, 0x87, 0xB0, 
+0xCA, 0x00, 0x0B, 0x70, 0xCB, 0x40, 0x48, 0x30, 0xDA, 0x40, 0x61, 0x08, 0xDB, 0x80, 0x04, 0xF0, 
+0x5C, 0x27, 0x8A, 0x51, 0x00, 0xB0, 0xE1, 0x48, 0x03, 0x9D, 0xA9, 0xA8, 0x54, 0xE7, 0x8A, 0x51, 
+0xC5, 0x00, 0xF3, 0x30, 0xC5, 0x85, 0x45, 0x08, 0xDA, 0x40, 0x00, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 
+0x00, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0xFE, 0xF9, 0x01, 0x38, 0xC5, 0x00, 0xDA, 0x40, 
+0x00, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x00, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0xC5, 0x50, 
+0xC3, 0xA8, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x3F, 0x30, 0xC5, 0x85, 0x45, 0x08, 0xDA, 0x40, 
+0x00, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x00, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0xEF, 0xF9, 
+0x10, 0x38, 0xC5, 0x00, 0xDA, 0x40, 0x00, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x00, 0xB0, 0x54, 0xE7, 
+0x8A, 0x51, 0xC5, 0x00, 0xC5, 0x92, 0x45, 0x08, 0xDA, 0x40, 0x00, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 
+0x86, 0x70, 0xC8, 0xC0, 0xE1, 0x48, 0x03, 0x9D, 0xDC, 0xE8, 0x83, 0x96, 0x3E, 0x88, 0x83, 0x52, 
+0xC9, 0x00, 0x83, 0x96, 0x3D, 0x88, 0x83, 0x52, 0xCA, 0x00, 0x83, 0x96, 0x3C, 0x48, 0x83, 0x52, 
+0xCB, 0x40, 0x83, 0x96, 0x3B, 0x88, 0xEA, 0xE8, 0x83, 0x96, 0x42, 0xC8, 0x83, 0x52, 0xC9, 0x00, 
+0x83, 0x96, 0x41, 0xC8, 0x83, 0x52, 0xCA, 0x00, 0x83, 0x96, 0x40, 0x88, 0x83, 0x52, 0xCB, 0x40, 
+0x83, 0x96, 0x3F, 0xC8, 0x83, 0x52, 0xCC, 0x00, 0x48, 0x30, 0xDA, 0x40, 0x61, 0x08, 0xDB, 0x80, 
+0x05, 0x30, 0x5C, 0x27, 0x8A, 0x51, 0x0D, 0x70, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0x8F, 0xF0, 
+0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xCC, 0x41, 0xCD, 0x81, 0xDA, 0x40, 0x61, 0x08, 0xDB, 0x80, 
+0x06, 0x30, 0x5C, 0x27, 0x8A, 0x51, 0x82, 0x30, 0xC8, 0xC0, 0xFF, 0xB0, 0xC9, 0x00, 0xCA, 0x00, 
+0xCB, 0x40, 0x48, 0x30, 0xDA, 0x40, 0x61, 0x08, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 
+0x82, 0x30, 0xC8, 0xC0, 0xFF, 0xB0, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x40, 0x48, 0x30, 0xDA, 0x40, 
+0x61, 0x08, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0xC7, 0xF0, 0xDF, 0xC0, 0x00, 0x00, 
+0xDF, 0x8B, 0x1F, 0x29, 0x23, 0xA9, 0x00, 0x00, 0x08, 0x40, 0xEC, 0x40, 0xC1, 0x70, 0xC8, 0xC0, 
+0x48, 0x30, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x01, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x9F, 0x30, 
+0xE0, 0xC0, 0xE0, 0x8B, 0x31, 0xA9, 0x34, 0xA9, 0x95, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xC8, 0xC0, 
+0x3F, 0xC8, 0xC9, 0x00, 0x3E, 0x88, 0xCA, 0x00, 0x3C, 0x48, 0xCB, 0x40, 0x48, 0x30, 0xCC, 0x41, 
+0xCC, 0x8A, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x5C, 0x27, 0x8A, 0x51, 0x1D, 0xB0, 
+0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xE2, 0xB0, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xCC, 0x41, 
+0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x95, 0x27, 0x8A, 0x51, 0x48, 0xC8, 0xCD, 0x40, 
+0x13, 0x70, 0xCD, 0xC5, 0x0D, 0x70, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xE2, 0xB0, 0xCA, 0x00, 
+0x4D, 0x48, 0xCB, 0x40, 0x48, 0x30, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 
+0x8A, 0x51, 0xEC, 0x88, 0x03, 0x9D, 0x6E, 0x29, 0x25, 0x70, 0x6F, 0x69, 0x2A, 0x70, 0x54, 0xE7, 
+0x8A, 0x51, 0xEB, 0x80, 0xEA, 0x40, 0x3F, 0x30, 0xEA, 0xC5, 0x8E, 0xB0, 0xC8, 0xC0, 0x6A, 0x48, 
+0xC9, 0x00, 0x48, 0x30, 0xCA, 0x41, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x03, 0x30, 0x5C, 0x27, 
+0x8A, 0x51, 0x6B, 0x88, 0xE0, 0xC0, 0x06, 0x30, 0x03, 0xD0, 0xE0, 0x4C, 0xFF, 0x7E, 0x03, 0x9D, 
+0x84, 0x69, 0x60, 0xC8, 0xEA, 0x40, 0x03, 0x30, 0xEA, 0xC5, 0x00, 0xB0, 0xEC, 0x88, 0x03, 0x9D, 
+0x9D, 0x29, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x6A, 0x48, 0xE0, 0xC0, 0x03, 0xD0, 0xE0, 0x8D, 
+0x03, 0xD0, 0xE0, 0x8D, 0x45, 0x08, 0xF3, 0xB9, 0xAA, 0xE9, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 
+0x6A, 0x48, 0xE0, 0xC0, 0x06, 0x30, 0x03, 0xD0, 0xE0, 0x8D, 0xFF, 0x7E, 0x03, 0x9D, 0xA3, 0xE9, 
+0x45, 0x08, 0x3F, 0xB9, 0x60, 0xC4, 0xC5, 0x00, 0xDA, 0x40, 0x00, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 
+0xEC, 0x88, 0x03, 0x9D, 0xBD, 0x69, 0x27, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xEA, 0x40, 0x28, 0x30, 
+0x54, 0xE7, 0x8A, 0x51, 0xEB, 0x80, 0x29, 0x70, 0xC6, 0xE9, 0x2C, 0x70, 0x54, 0xE7, 0x8A, 0x51, 
+0xEA, 0x40, 0x2D, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xEB, 0x80, 0x2E, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 
+0xE3, 0x40, 0x86, 0x70, 0xC8, 0xC0, 0x03, 0xD0, 0x6A, 0x8C, 0xC9, 0x00, 0x6B, 0x88, 0xE0, 0xC0, 
+0x03, 0xD0, 0xE0, 0x4C, 0x6A, 0x48, 0xE1, 0x00, 0x06, 0x30, 0x03, 0xD0, 0xE1, 0xCD, 0xFF, 0x7E, 
+0x03, 0xD0, 0x03, 0x9D, 0xD6, 0x29, 0x61, 0x8D, 0x60, 0xC4, 0xCA, 0x00, 0x63, 0x48, 0xE0, 0xC0, 
+0x03, 0xD0, 0xE0, 0x4C, 0x6B, 0x88, 0xE1, 0x00, 0x06, 0x30, 0x03, 0xD0, 0xE1, 0xCD, 0xFF, 0x7E, 
+0x03, 0xD0, 0x03, 0x9D, 0xE6, 0x29, 0x61, 0x8D, 0x60, 0xC4, 0xCB, 0x40, 0x63, 0x48, 0xE0, 0xC0, 
+0x06, 0x30, 0x03, 0xD0, 0xE0, 0x8D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0xF2, 0x29, 0x60, 0x4D, 
+0xCC, 0x00, 0x48, 0x30, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x5C, 0x27, 0x8A, 0x51, 
+0xE7, 0xC1, 0x02, 0xF0, 0x67, 0x82, 0x03, 0x18, 0x21, 0x6A, 0xC7, 0xF0, 0xE0, 0xC0, 0x00, 0x00, 
+0xE0, 0x8B, 0x07, 0xAA, 0x0B, 0xAA, 0x00, 0x00, 0x1D, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xC8, 0xC0, 
+0x08, 0xF0, 0xC9, 0x00, 0xC8, 0x70, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xCC, 0x41, 0xDA, 0x40, 
+0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x95, 0x27, 0x8A, 0x51, 0xC8, 0x9A, 0x21, 0x6A, 0xE7, 0x0A, 
+0x01, 0x2A, 0x48, 0xC8, 0x20, 0x79, 0x67, 0x84, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 
+0x1D, 0xB0, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xDD, 0x30, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 
+0xCC, 0x41, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x95, 0x27, 0x8A, 0x51, 0x48, 0xC8, 
+0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x48, 0xC8, 0xE9, 0x40, 0x07, 0x70, 0xE9, 0xC5, 
+0x04, 0xF0, 0x69, 0x42, 0x03, 0x5C, 0x46, 0xAA, 0x04, 0xF0, 0xE9, 0x40, 0xEC, 0x88, 0x03, 0x9D, 
+0x50, 0x6A, 0x69, 0x48, 0xDA, 0x40, 0x1D, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x26, 0x70, 0x57, 0x2A, 
+0x69, 0xCE, 0xF0, 0x39, 0xDA, 0x40, 0x1D, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x2B, 0xB0, 0x54, 0xE7, 
+0x8A, 0x51, 0xEA, 0x40, 0xEA, 0x9F, 0x19, 0xEB, 0x3D, 0xF0, 0x54, 0xE7, 0x8A, 0x51, 0xEB, 0x80, 
+0x3E, 0xF0, 0x54, 0xE7, 0xEA, 0x40, 0x06, 0x30, 0xDA, 0x40, 0x69, 0x48, 0x8A, 0x95, 0x81, 0x22, 
+0x8A, 0x51, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0xE8, 0x00, 0x06, 0x30, 
+0xDA, 0x40, 0x69, 0x48, 0x8A, 0x95, 0x81, 0x22, 0x8A, 0x51, 0x02, 0xBE, 0x84, 0x80, 0x8A, 0x95, 
+0x00, 0x60, 0x8A, 0x51, 0xE6, 0x40, 0x6B, 0x88, 0x68, 0x02, 0x03, 0x5C, 0x87, 0xEA, 0x6B, 0x88, 
+0x68, 0x46, 0x03, 0x9D, 0xA9, 0xEA, 0x6A, 0x48, 0x66, 0x42, 0x03, 0x18, 0xA9, 0xEA, 0x1D, 0xB0, 
+0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xC1, 0x70, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xCC, 0x41, 
+0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x95, 0x27, 0x8A, 0x51, 0x48, 0xC8, 0xEB, 0x80, 
+0x1F, 0x79, 0xE0, 0xB8, 0xEB, 0x80, 0x0D, 0x70, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xC1, 0x70, 
+0xCA, 0x00, 0x6B, 0x88, 0xCB, 0x40, 0x48, 0x30, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 
+0x5C, 0x27, 0x06, 0x30, 0xDA, 0x40, 0x69, 0x48, 0x8A, 0x95, 0x81, 0x22, 0x8A, 0x51, 0x03, 0xFE, 
+0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0xE8, 0x00, 0x06, 0x30, 0xDA, 0x40, 0x69, 0x48, 
+0x8A, 0x95, 0x81, 0x22, 0x8A, 0x51, 0x04, 0xBE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 
+0xE6, 0x40, 0x6B, 0x88, 0x68, 0x02, 0x03, 0x5C, 0xCD, 0x2A, 0x6B, 0x88, 0x68, 0x46, 0x03, 0x9D, 
+0xDF, 0xEB, 0x6A, 0x48, 0x66, 0x42, 0x03, 0x18, 0xDF, 0xEB, 0x06, 0x30, 0xDA, 0x40, 0x69, 0x48, 
+0x8A, 0x95, 0x81, 0x22, 0x8A, 0x51, 0x05, 0xFE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 
+0xE8, 0x00, 0x06, 0x30, 0xDA, 0x40, 0x69, 0x48, 0x8A, 0x95, 0x81, 0x22, 0x8A, 0x51, 0x06, 0xFE, 
+0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0xE6, 0x40, 0x6B, 0x88, 0x68, 0x02, 0x03, 0x5C, 
+0xF1, 0x2A, 0x6B, 0x88, 0x68, 0x46, 0x03, 0x9D, 0x05, 0xAB, 0x6A, 0x48, 0x66, 0x42, 0x03, 0x18, 
+0x05, 0xAB, 0x1D, 0xB0, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xC2, 0x70, 0xCA, 0x00, 0x48, 0x30, 
+0xCB, 0x81, 0xCC, 0x41, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x95, 0x27, 0x8A, 0x51, 
+0x48, 0xC8, 0xEB, 0x80, 0xE1, 0x39, 0x0E, 0xB8, 0xCF, 0xAB, 0x1D, 0xB0, 0xC8, 0xC0, 0x08, 0xF0, 
+0xC9, 0x00, 0xC2, 0x70, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xCC, 0x41, 0xDA, 0x40, 0x6C, 0x48, 
+0xDB, 0x80, 0x05, 0x30, 0x95, 0x27, 0x8A, 0x51, 0x48, 0xC8, 0xEB, 0x80, 0xE1, 0x39, 0x06, 0x78, 
+0xCF, 0xAB, 0x07, 0x70, 0xEA, 0xC5, 0x05, 0x30, 0x6A, 0x42, 0x03, 0x18, 0x29, 0xEB, 0x69, 0x48, 
+0x3C, 0x7E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0xE4, 0x00, 0x69, 0x48, 0x2D, 0x7E, 
+0x44, 0xAB, 0x6A, 0x48, 0x05, 0xBA, 0x03, 0x9D, 0x37, 0x6B, 0x69, 0x48, 0x41, 0xFE, 0x84, 0x80, 
+0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 0xE4, 0x00, 0x69, 0x48, 0x32, 0x3E, 0x44, 0xAB, 0x06, 0x30, 
+0x6A, 0x42, 0x03, 0x5C, 0x49, 0xEB, 0x69, 0x48, 0x46, 0x3E, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 
+0x8A, 0x51, 0xE4, 0x00, 0x69, 0x48, 0x37, 0xBE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x51, 
+0xE5, 0x40, 0x0D, 0x70, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0x89, 0x70, 0xCA, 0x00, 0x06, 0x30, 
+0x6A, 0x42, 0x03, 0x5C, 0x55, 0x2B, 0x09, 0x30, 0x56, 0x2B, 0x0D, 0x70, 0xCB, 0x40, 0x48, 0x30, 
+0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x06, 0x30, 0x6A, 0x42, 
+0x03, 0x5C, 0x85, 0xEB, 0x1D, 0xB0, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xC2, 0x70, 0xCA, 0x00, 
+0x48, 0x30, 0xCB, 0x81, 0xCC, 0x41, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x95, 0x27, 
+0x8A, 0x51, 0x48, 0xC8, 0xEB, 0x80, 0x9F, 0xB9, 0x20, 0x38, 0xEB, 0x80, 0x0D, 0x70, 0xC8, 0xC0, 
+0x08, 0xF0, 0xC9, 0x00, 0xC2, 0x70, 0xCA, 0x00, 0x6B, 0x88, 0xCB, 0x40, 0x48, 0x30, 0xDA, 0x40, 
+0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x64, 0x08, 0x03, 0x59, 0xB4, 0x2B, 
+0x1D, 0xB0, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xC1, 0x70, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 
+0xCC, 0x41, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x95, 0x27, 0x8A, 0x51, 0x48, 0xC8, 
+0xEB, 0x80, 0x64, 0x08, 0xE0, 0xC0, 0x05, 0x30, 0x03, 0xD0, 0xE0, 0x8D, 0xFF, 0x7E, 0x03, 0x9D, 
+0x9C, 0x2B, 0x6B, 0x88, 0x1F, 0x79, 0x60, 0xC4, 0xEB, 0x80, 0x0D, 0x70, 0xC8, 0xC0, 0x08, 0xF0, 
+0xC9, 0x00, 0xC1, 0x70, 0xCA, 0x00, 0x6B, 0x88, 0xCB, 0x40, 0x48, 0x30, 0xDA, 0x40, 0x6C, 0x48, 
+0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x65, 0x48, 0x03, 0x59, 0xDF, 0xEB, 0x1D, 0xB0, 
+0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xC2, 0x70, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xCC, 0x41, 
+0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x05, 0x30, 0x95, 0x27, 0x8A, 0x51, 0x48, 0xC8, 0xEB, 0x80, 
+0x65, 0x48, 0xE0, 0xC0, 0x03, 0xD0, 0xE0, 0x8D, 0x6B, 0x88, 0xE1, 0x39, 0x60, 0xC4, 0xEB, 0x80, 
+0x0D, 0x70, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0xC2, 0x70, 0xCA, 0x00, 0x6B, 0x88, 0xCB, 0x40, 
+0x48, 0x30, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x5F, 0xC8, 
+0x03, 0x9D, 0x9D, 0x5B, 0xE4, 0x2B, 0xA4, 0xAC, 0xE2, 0x41, 0xE2, 0x8A, 0x6C, 0xCB, 0xEE, 0xAB, 
+0x00, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x45, 0x52, 0xF3, 0xAB, 0x00, 0xB0, 0x54, 0xE7, 
+0x8A, 0x51, 0xC5, 0x00, 0x45, 0x10, 0x45, 0x08, 0xDA, 0x40, 0x00, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 
+0x05, 0x30, 0xE0, 0xC0, 0xE0, 0x8B, 0xFA, 0xAB, 0x00, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 
+0xFD, 0xF9, 0x02, 0x38, 0xC5, 0x00, 0xDA, 0x40, 0x00, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x00, 0xB0, 
+0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0xDF, 0xF9, 0x20, 0x38, 0xC5, 0x00, 0xDA, 0x40, 0x00, 0xB0, 
+0x4C, 0xE7, 0x8A, 0x51, 0xE7, 0xC1, 0x40, 0x88, 0x67, 0x82, 0x03, 0x18, 0x23, 0xAC, 0xE4, 0xB0, 
+0xE0, 0xC0, 0x1A, 0xAC, 0x1B, 0xEC, 0xE0, 0x8B, 0x19, 0xAC, 0x1E, 0xEC, 0x00, 0x00, 0x83, 0x52, 
+0x03, 0x53, 0xE7, 0x0A, 0x13, 0xAC, 0x0D, 0x70, 0xC8, 0xC0, 0x05, 0x30, 0xC9, 0x00, 0x84, 0x30, 
+0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 
+0x8A, 0x51, 0x0D, 0x70, 0xC8, 0xC0, 0x05, 0x30, 0xC9, 0x00, 0x85, 0x70, 0xCA, 0x00, 0x48, 0x30, 
+0xCB, 0x81, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x0D, 0x70, 
+0xC8, 0xC0, 0x05, 0x30, 0xC9, 0x00, 0x82, 0x30, 0xCA, 0x00, 0x3F, 0x30, 0xCB, 0x40, 0x48, 0x30, 
+0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x0D, 0x70, 0xC8, 0xC0, 
+0x05, 0x30, 0xC9, 0x00, 0x80, 0xF0, 0xCA, 0x00, 0x3E, 0xF0, 0xCB, 0x40, 0x48, 0x30, 0xDA, 0x40, 
+0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x0D, 0x70, 0xC8, 0xC0, 0x05, 0x30, 
+0xC9, 0x00, 0x83, 0x70, 0xCA, 0x00, 0x3E, 0xF0, 0xCB, 0x40, 0x48, 0x30, 0xDA, 0x40, 0x6C, 0x48, 
+0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0x6C, 0x83, 0x03, 0x9D, 0x71, 0xEC, 0x9C, 0xD5, 
+0x72, 0xEC, 0x1C, 0x95, 0x05, 0x30, 0xE0, 0xC0, 0xE0, 0x8B, 0x74, 0xEC, 0x0D, 0x70, 0x83, 0x52, 
+0x03, 0x53, 0xC8, 0xC0, 0x05, 0x30, 0xC9, 0x00, 0x87, 0xB0, 0xCA, 0x00, 0x09, 0x30, 0xCB, 0x40, 
+0x48, 0x30, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x04, 0xF0, 0x5C, 0x27, 0x8A, 0x51, 0xE4, 0xB0, 
+0xE0, 0xC0, 0x8A, 0xAC, 0x8B, 0xEC, 0xE0, 0x8B, 0x89, 0xAC, 0x8E, 0xEC, 0x00, 0x00, 0xD1, 0xB0, 
+0x83, 0x52, 0x03, 0x53, 0xC8, 0xC0, 0x48, 0x30, 0xDA, 0x40, 0x6C, 0x48, 0xDB, 0x80, 0x01, 0xF0, 
+0x5C, 0x27, 0x8A, 0x51, 0x04, 0xF0, 0xE1, 0x00, 0x1C, 0x70, 0xE0, 0xC0, 0xE0, 0x8B, 0x9E, 0x2C, 
+0xE1, 0xCB, 0x9E, 0x2C, 0x00, 0x00, 0xA5, 0xEC, 0xE2, 0x41, 0x83, 0x52, 0x03, 0x53, 0x62, 0x08, 
+0x08, 0x40, 0x55, 0xB0, 0x83, 0x52, 0x9B, 0x40, 0xC4, 0x01, 0x02, 0xF0, 0x44, 0xC2, 0x03, 0x18, 
+0x6D, 0x6D, 0x44, 0xC8, 0x01, 0xBE, 0x9B, 0x40, 0x44, 0xC8, 0xB4, 0x7E, 0x84, 0x80, 0x83, 0x93, 
+0x80, 0x81, 0x44, 0xC8, 0xB4, 0x7E, 0x84, 0x80, 0x80, 0x88, 0x03, 0x9D, 0xE5, 0x2C, 0x3C, 0xB0, 
+0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x44, 0x18, 0xD1, 0xEC, 0x44, 0xC8, 0xB4, 0x7E, 0x84, 0x80, 
+0x45, 0x08, 0xDC, 0x40, 0x07, 0x70, 0x03, 0xD0, 0xDC, 0xCC, 0xFF, 0x7E, 0x03, 0x9D, 0xCB, 0x2C, 
+0xDC, 0x2C, 0x44, 0xC8, 0xB4, 0x7E, 0x84, 0x80, 0x45, 0x08, 0xDC, 0x40, 0x05, 0x30, 0x03, 0xD0, 
+0xDC, 0xCC, 0xFF, 0x7E, 0x03, 0x9D, 0xD7, 0x6C, 0x5C, 0x48, 0x83, 0x93, 0x80, 0x40, 0x44, 0xC8, 
+0xB4, 0x7E, 0x84, 0x80, 0x01, 0xF0, 0x80, 0xC5, 0xB9, 0x2C, 0x3E, 0xF0, 0x54, 0xE7, 0x8A, 0x51, 
+0xC5, 0x00, 0x45, 0x08, 0x03, 0x59, 0x05, 0xAD, 0x10, 0xF0, 0x45, 0x02, 0x03, 0x18, 0x05, 0xAD, 
+0x44, 0xC8, 0xB0, 0x3E, 0x84, 0x80, 0x45, 0x08, 0x83, 0x93, 0x80, 0x40, 0x44, 0xC8, 0xB0, 0x3E, 
+0x84, 0x80, 0x00, 0x48, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x44, 0xC8, 0xAE, 0xBE, 
+0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x80, 0xCA, 0x24, 0xAD, 0x45, 0x08, 0xFF, 0x3A, 0x03, 0x9D, 
+0x11, 0xAD, 0x44, 0xC8, 0xB0, 0x3E, 0x84, 0x80, 0x04, 0xF0, 0x83, 0x93, 0x80, 0x40, 0xFF, 0xB0, 
+0x1B, 0x2D, 0x44, 0xC8, 0xB0, 0x3E, 0x84, 0x80, 0x04, 0xF0, 0x83, 0x93, 0x80, 0x40, 0x44, 0xC8, 
+0xB0, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x44, 0xC8, 
+0xAE, 0xBE, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x3F, 0x30, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 
+0x45, 0x08, 0x03, 0x59, 0x44, 0xAD, 0x0E, 0x70, 0x45, 0x02, 0x03, 0x18, 0x44, 0xAD, 0x44, 0xC8, 
+0xAA, 0x7E, 0x84, 0x80, 0x45, 0x08, 0x83, 0x93, 0x80, 0x40, 0x44, 0xC8, 0xAA, 0x7E, 0x84, 0x80, 
+0x00, 0x48, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x44, 0xC8, 0xA8, 0x3E, 0x84, 0x80, 
+0x83, 0x93, 0x80, 0x81, 0x80, 0xCA, 0x63, 0x2D, 0x45, 0x08, 0xFF, 0x3A, 0x03, 0x9D, 0x50, 0xAD, 
+0x44, 0xC8, 0xAA, 0x7E, 0x84, 0x80, 0x0D, 0x70, 0x83, 0x93, 0x80, 0x40, 0xFF, 0xB0, 0x5A, 0x2D, 
+0x44, 0xC8, 0xAA, 0x7E, 0x84, 0x80, 0x0D, 0x70, 0x83, 0x93, 0x80, 0x40, 0x44, 0xC8, 0xAA, 0x7E, 
+0x84, 0x80, 0x00, 0x48, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x44, 0xC8, 0xA8, 0x3E, 
+0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x44, 0xC8, 0xB2, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xDA, 0x40, 
+0x1A, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0xC4, 0x4A, 0xAD, 0x2C, 0x03, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 
+0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x03, 0xBA, 0x03, 0x9D, 0x6F, 0xAD, 0x3E, 0xF0, 0x54, 0xE7, 
+0x8A, 0x51, 0xA8, 0xC0, 0x3F, 0x30, 0x54, 0xE7, 0x8A, 0x51, 0xAA, 0x00, 0x28, 0xC2, 0x03, 0x5C, 
+0x97, 0x6D, 0x0E, 0x70, 0x28, 0xC2, 0x03, 0x18, 0x97, 0x6D, 0x2A, 0x08, 0x03, 0x59, 0x97, 0x6D, 
+0x28, 0xC8, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x2A, 0x08, 0xDA, 0x40, 0x1C, 0x70, 
+0x4C, 0xE7, 0x8A, 0x51, 0x28, 0xC8, 0xA7, 0x40, 0x2A, 0x08, 0xA9, 0x00, 0xA5, 0x2D, 0x0D, 0x70, 
+0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x1C, 0x70, 0xDA, 0x81, 0xDA, 0xCA, 0x4C, 0xE7, 
+0x8A, 0x51, 0x0D, 0x70, 0xA7, 0x40, 0xA9, 0x41, 0xA9, 0x8A, 0x04, 0xF0, 0x9B, 0x40, 0x3C, 0xB0, 
+0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x04, 0x7A, 0x03, 0x9D, 0xA7, 0x6D, 0x3E, 0xF0, 0x54, 0xE7, 
+0x8A, 0x51, 0xAC, 0x00, 0x3F, 0x30, 0x54, 0xE7, 0x8A, 0x51, 0xAE, 0x40, 0x2C, 0x02, 0x03, 0x5C, 
+0xCB, 0x6D, 0x02, 0xF0, 0x2E, 0x42, 0x03, 0x5C, 0xCB, 0x6D, 0x2C, 0x08, 0xDA, 0x40, 0x1B, 0xB0, 
+0x4C, 0xE7, 0x8A, 0x51, 0x2E, 0x48, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x2C, 0x08, 
+0xAB, 0x40, 0x2E, 0x48, 0xD8, 0x2D, 0x0C, 0x30, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 
+0x03, 0x30, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x0C, 0x30, 0xAB, 0x40, 0x03, 0x30, 
+0xAD, 0x40, 0x05, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x05, 0xBA, 
+0x03, 0x9D, 0xDB, 0xAD, 0x3E, 0xF0, 0x54, 0xE7, 0x8A, 0x51, 0xB4, 0x00, 0x3F, 0x30, 0x54, 0xE7, 
+0x8A, 0x51, 0xB6, 0x40, 0x34, 0x02, 0x03, 0x5C, 0x02, 0x6E, 0x10, 0xF0, 0x34, 0x02, 0x03, 0x18, 
+0x02, 0x6E, 0x36, 0x48, 0x03, 0x59, 0x02, 0x6E, 0x34, 0x08, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 
+0x8A, 0x51, 0x36, 0x48, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x34, 0x08, 0xB3, 0x40, 
+0x36, 0x48, 0x0F, 0x2E, 0x0F, 0xB0, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x04, 0xF0, 
+0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x0F, 0xB0, 0xB3, 0x40, 0x04, 0xF0, 0xB5, 0x40, 
+0x06, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x06, 0xBA, 0x03, 0x9D, 
+0x12, 0xAE, 0x3D, 0xF0, 0x54, 0xE7, 0x8A, 0x51, 0xB9, 0x40, 0x3E, 0xF0, 0x54, 0xE7, 0x8A, 0x51, 
+0xB8, 0x00, 0x3F, 0x30, 0x54, 0xE7, 0x8A, 0x51, 0xBB, 0x80, 0x38, 0x08, 0x39, 0x42, 0x03, 0x5C, 
+0x47, 0x2E, 0x3B, 0x88, 0x38, 0x02, 0x03, 0x5C, 0x47, 0x2E, 0x3B, 0x88, 0x03, 0x59, 0x47, 0x2E, 
+0x39, 0x48, 0xDA, 0x40, 0x1A, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x38, 0x08, 0xDA, 0x40, 0x1B, 0xB0, 
+0x4C, 0xE7, 0x8A, 0x51, 0x3B, 0x88, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x39, 0x48, 
+0x83, 0x96, 0xBA, 0x40, 0x83, 0x52, 0x38, 0x08, 0xB7, 0x80, 0x3B, 0x88, 0x5D, 0x6E, 0x5A, 0xB0, 
+0xDA, 0x40, 0x1A, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x50, 0x30, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 
+0x8A, 0x51, 0x28, 0x30, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x5A, 0xB0, 0x83, 0x96, 
+0xBA, 0x40, 0x50, 0x30, 0x83, 0x52, 0xB7, 0x80, 0x28, 0x30, 0xBA, 0x40, 0x07, 0x70, 0x9B, 0x40, 
+0x3C, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x07, 0xFA, 0x03, 0x9D, 0x60, 0xAE, 0x3E, 0xF0, 
+0x54, 0xE7, 0x8A, 0x51, 0xAF, 0x80, 0x3F, 0x30, 0x54, 0xE7, 0x8A, 0x51, 0xB0, 0xC0, 0x2F, 0x82, 
+0x03, 0x5C, 0x8A, 0xEE, 0x10, 0xF0, 0x2F, 0x82, 0x03, 0x18, 0x8A, 0xEE, 0x30, 0xC8, 0x03, 0x59, 
+0x8A, 0xEE, 0x2F, 0x88, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x30, 0xC8, 0xDA, 0x40, 
+0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x2F, 0x88, 0x83, 0x96, 0xB6, 0x40, 0x83, 0x52, 0x30, 0xC8, 
+0x83, 0x96, 0x98, 0xEE, 0x0E, 0x70, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x04, 0xF0, 
+0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x0E, 0x70, 0x83, 0x96, 0xB6, 0x40, 0x04, 0xF0, 
+0xB7, 0x80, 0x08, 0xF0, 0x83, 0x52, 0x9B, 0x40, 0x3C, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 
+0x08, 0x7A, 0x03, 0x9D, 0x9C, 0x2E, 0x3E, 0xF0, 0x54, 0xE7, 0x8A, 0x51, 0xB1, 0x00, 0x3F, 0x30, 
+0x54, 0xE7, 0x8A, 0x51, 0xB2, 0x00, 0x31, 0x08, 0x32, 0x02, 0x03, 0x18, 0xC4, 0xEE, 0x02, 0xF0, 
+0x32, 0x02, 0x03, 0x5C, 0xC4, 0xEE, 0x31, 0x08, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 
+0x32, 0x08, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x31, 0x08, 0x83, 0x96, 0xB8, 0x00, 
+0x83, 0x52, 0x32, 0x08, 0x83, 0x96, 0xD2, 0x2E, 0x84, 0x30, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 
+0x8A, 0x51, 0x34, 0x70, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x84, 0x30, 0x83, 0x96, 
+0xB8, 0x00, 0x34, 0x70, 0xB9, 0x40, 0x09, 0x30, 0x83, 0x52, 0x9B, 0x40, 0x3C, 0xB0, 0x54, 0xE7, 
+0x8A, 0x51, 0xC5, 0x00, 0x09, 0xBA, 0x03, 0x9D, 0xD6, 0x6E, 0x3D, 0xF0, 0x54, 0xE7, 0x8A, 0x51, 
+0xBF, 0xC0, 0x3E, 0xF0, 0x54, 0xE7, 0x8A, 0x51, 0xBE, 0x80, 0x3F, 0x30, 0x54, 0xE7, 0x8A, 0x51, 
+0xBC, 0x40, 0x07, 0x70, 0x3F, 0xC2, 0x03, 0x18, 0x05, 0xEF, 0x08, 0xF0, 0x3E, 0x82, 0x03, 0x18, 
+0x05, 0xEF, 0x02, 0xF0, 0x3C, 0x42, 0x03, 0x18, 0x05, 0xEF, 0x3F, 0xC8, 0xDA, 0x40, 0x1A, 0x70, 
+0x4C, 0xE7, 0x8A, 0x51, 0x3E, 0x88, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x3C, 0x48, 
+0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 0x8A, 0x51, 0x18, 0xEF, 0x1A, 0x70, 0xDA, 0x81, 0xDA, 0xCA, 
+0x4C, 0xE7, 0x8A, 0x51, 0x02, 0xF0, 0xDA, 0x40, 0x1B, 0xB0, 0x4C, 0xE7, 0x8A, 0x51, 0x1C, 0x70, 
+0xDA, 0x81, 0x4C, 0xE7, 0x8A, 0x51, 0x02, 0xF0, 0xBF, 0x01, 0xBF, 0x4A, 0xBE, 0x80, 0xBC, 0x81, 
+0x0A, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x0A, 0xBA, 0x03, 0x9D, 
+0x1A, 0x2F, 0x3F, 0x30, 0x54, 0xE7, 0x8A, 0x51, 0xC0, 0x80, 0xDA, 0x40, 0x1C, 0x70, 0x4C, 0xE7, 
+0x8A, 0x51, 0x0B, 0x70, 0x9B, 0x40, 0x3C, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 0x0B, 0xFA, 
+0x03, 0x9D, 0x2B, 0x6F, 0x3F, 0x30, 0x54, 0xE7, 0x8A, 0x51, 0xBD, 0x80, 0x3D, 0x88, 0x03, 0x59, 
+0x3D, 0xAF, 0x3D, 0x0B, 0x3C, 0x6F, 0x3D, 0xAF, 0xBD, 0xC1, 0x3D, 0x88, 0xDA, 0x40, 0x1C, 0x70, 
+0x4C, 0xE7, 0x8A, 0x51, 0x0F, 0xB0, 0x9B, 0x40, 0x3C, 0xB0, 0x54, 0xE7, 0x8A, 0x51, 0xC5, 0x00, 
+0x0F, 0x3A, 0x03, 0x59, 0x08, 0x40, 0x44, 0xEF, 0xDB, 0x80, 0x5A, 0x48, 0x96, 0x00, 0x5B, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x08, 0x40, 0x83, 0x52, 0x03, 0x53, 0xDA, 0x40, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0x08, 0x40, 0xDD, 0x80, 0x5B, 0xD8, 0x7A, 0xAF, 0xDE, 0xC1, 
+0x5D, 0x88, 0x5E, 0x82, 0x03, 0x18, 0x6F, 0xEF, 0x5E, 0x88, 0x5A, 0xC7, 0xDC, 0x40, 0x84, 0x80, 
+0x83, 0x93, 0x00, 0x48, 0x99, 0x00, 0x18, 0x14, 0x18, 0xD0, 0xDE, 0x0A, 0x60, 0xEF, 0x18, 0x55, 
+0x18, 0x11, 0x83, 0x52, 0x03, 0x53, 0x11, 0x5C, 0x08, 0x40, 0x05, 0x30, 0xDC, 0x40, 0xDC, 0x0B, 
+0x77, 0xEF, 0x71, 0x6F, 0xDE, 0xC1, 0x5D, 0x88, 0x5E, 0x82, 0x03, 0x18, 0x8A, 0x2F, 0x5E, 0x88, 
+0x5A, 0xC7, 0xDC, 0x40, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x9A, 0x00, 0x98, 0x95, 0x98, 0x51, 
+0xDE, 0x0A, 0x7B, 0xEF, 0x98, 0x96, 0x98, 0x52, 0x83, 0x52, 0x03, 0x53, 0x91, 0x9C, 0x08, 0x40, 
+0x05, 0x30, 0xDC, 0x40, 0xDC, 0x0B, 0x92, 0x2F, 0x8C, 0x2F, 0xDD, 0x80, 0x5B, 0xD8, 0xC4, 0x2F, 
+0xDE, 0xC1, 0x5D, 0x88, 0x5E, 0x82, 0x03, 0x18, 0xA8, 0x2F, 0x5E, 0x88, 0x5A, 0xC7, 0xDC, 0x40, 
+0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x99, 0x00, 0x18, 0x14, 0x18, 0xD0, 0xDE, 0x0A, 0x99, 0x6F, 
+0x18, 0x55, 0x18, 0x11, 0x83, 0x52, 0x03, 0x53, 0x11, 0x5C, 0xB4, 0x6F, 0x2A, 0x70, 0xDC, 0x40, 
+0xDC, 0x0B, 0xB0, 0x2F, 0x00, 0x00, 0xAA, 0x6F, 0xDE, 0xC1, 0x5D, 0x88, 0x5E, 0x82, 0x03, 0x18, 
+0x08, 0x40, 0x5E, 0x88, 0x5A, 0xC7, 0xDC, 0x40, 0x84, 0x80, 0x0F, 0x48, 0x83, 0x93, 0x80, 0x40, 
+0x98, 0x54, 0x98, 0x10, 0xDE, 0x0A, 0xB5, 0xAF, 0xDE, 0xC1, 0x5D, 0x88, 0x5E, 0x82, 0x03, 0x18, 
+0xD4, 0x6F, 0x5E, 0x88, 0x5A, 0xC7, 0xDC, 0x40, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x9A, 0x00, 
+0x98, 0x95, 0x98, 0x51, 0xDE, 0x0A, 0xC5, 0x6F, 0x98, 0x96, 0x98, 0x52, 0x83, 0x52, 0x03, 0x53, 
+0x91, 0x9C, 0xE0, 0x2F, 0x2A, 0x70, 0xDC, 0x40, 0xDC, 0x0B, 0xDC, 0xAF, 0x00, 0x00, 0xD6, 0xAF, 
+0xDE, 0xC1, 0x5D, 0x88, 0x5E, 0x82, 0x03, 0x18, 0x08, 0x40, 0x5E, 0x88, 0x5A, 0xC7, 0xDC, 0x40, 
+0x84, 0x80, 0x10, 0x88, 0x83, 0x93, 0x80, 0x40, 0x18, 0x56, 0x18, 0x12, 0xDE, 0x0A, 0xE1, 0x6F, 
+0xEF, 0x01, 0x83, 0x93, 0x21, 0x30, 0x84, 0x80, 0x5A, 0xB0, 0x8A, 0x95, 0x79, 0xE2, 0x8A, 0x51, 
+0xA0, 0x30, 0x84, 0x80, 0xC8, 0x70, 0x8A, 0x95, 0x79, 0xE2, 0x83, 0x01, 0x8A, 0x95, 0x34, 0xEB, 
+0x08, 0xF0, 0x8A, 0xC0, 0x04, 0x88, 0x84, 0x0A, 0x82, 0x47, 0x00, 0xF4, 0x01, 0x34, 0x48, 0x74, 
+0x02, 0x34, 0x3D, 0x34, 0x03, 0x74, 0x33, 0xF4, 0x00, 0xF4, 0xA4, 0xB4, 0x00, 0xF4, 0xF6, 0x74, 
+0x03, 0x74, 0x33, 0xF4, 0x00, 0xF4, 0x52, 0xB4, 0x00, 0xF4, 0x52, 0xB4, 0x00, 0xF4, 0xCD, 0x34, 
+0x00, 0xF4, 0x29, 0xB4, 0x00, 0xF4, 0x29, 0xB4, 0x00, 0xF4, 0x66, 0xF4, 0x00, 0xF4, 0x15, 0xB4, 
+0x00, 0xF4, 0x15, 0xB4, 0x00, 0xF4, 0x29, 0xB4, 0x7F, 0xB4, 0x34, 0xB4, 0x2F, 0x34, 0x2A, 0xB4, 
+0x26, 0xB4, 0x21, 0x74, 0x1A, 0xB4, 0x16, 0xB4, 0x0F, 0xF4, 0x09, 0x74, 0x04, 0x34, 0x02, 0x34, 
+0x01, 0x34, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF4, 0x03, 0x74, 0x03, 0x74, 0x00, 0xF4, 
+0x00, 0xF4, 0x03, 0x74, 0x03, 0x74, 0x07, 0xB4, 0x01, 0x34, 0x01, 0x34, 0x01, 0x34, 0x07, 0xB4, 
+0x07, 0xB4, 0x00, 0xF4, 0x00, 0xF4, 0x07, 0xB4, 0x07, 0xB4, 0x07, 0xB4, 0x00, 0xF4, 0x07, 0xB4, 
+0x07, 0xB4, 0x07, 0xB4, 0x07, 0xB4, 0x07, 0xB4, 0x07, 0xB4, 0x07, 0xB4, 0x07, 0xB4, 0x07, 0xB4, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 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, 
+0x7A, 0x2A, 0xDC, 0x40, 0xDB, 0xC1, 0x5A, 0x48, 0x5C, 0x98, 0xDB, 0x47, 0x03, 0xD0, 0xDA, 0x0D, 
+0x5A, 0x48, 0xDC, 0xD8, 0xDB, 0x47, 0x03, 0xD0, 0xDA, 0x0D, 0x5A, 0x48, 0x5C, 0xD9, 0xDB, 0x47, 
+0x03, 0xD0, 0xDA, 0x0D, 0x5A, 0x48, 0xDC, 0x19, 0xDB, 0x47, 0x03, 0xD0, 0xDA, 0x0D, 0x5A, 0x48, 
+0x5C, 0xDA, 0xDB, 0x47, 0x03, 0xD0, 0xDA, 0x0D, 0x5A, 0x48, 0xDC, 0x1A, 0xDB, 0x47, 0x03, 0xD0, 
+0xDA, 0x0D, 0x5A, 0x48, 0x5C, 0x1B, 0xDB, 0x47, 0x03, 0xD0, 0xDA, 0x0D, 0x5A, 0x48, 0xDC, 0x5B, 
+0xDB, 0x47, 0x5B, 0x88, 0x08, 0x40, 0x1D, 0xB0, 0xC8, 0xC0, 0x08, 0xF0, 0xC9, 0x00, 0x8B, 0xB0, 
+0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xCC, 0x41, 0xCD, 0x81, 0xCE, 0x81, 0xCF, 0xC1, 0xDA, 0x40, 
+0x08, 0xF0, 0xDB, 0xC1, 0x8A, 0x51, 0x95, 0x27, 0x8A, 0x95, 0x4B, 0x48, 0x83, 0x96, 0xBE, 0x80, 
+0x83, 0x52, 0x4A, 0x08, 0x83, 0x96, 0xBD, 0x80, 0x83, 0x52, 0x49, 0x08, 0x83, 0x96, 0xBC, 0x40, 
+0x83, 0x52, 0x48, 0xC8, 0x83, 0x96, 0xBB, 0x80, 0x1D, 0xB0, 0x83, 0x52, 0xC8, 0xC0, 0x08, 0xF0, 
+0xC9, 0x00, 0x8B, 0xB0, 0xCA, 0x00, 0x48, 0x30, 0xCB, 0x81, 0xCC, 0x41, 0xCD, 0x81, 0xCE, 0x81, 
+0xCF, 0xC1, 0xDA, 0x40, 0x08, 0xF0, 0xDB, 0xC1, 0xDB, 0x0A, 0x8A, 0x51, 0x95, 0x27, 0x4B, 0x48, 
+0x83, 0x96, 0xC2, 0xC0, 0x83, 0x52, 0x4A, 0x08, 0x83, 0x96, 0xC1, 0xC0, 0x83, 0x52, 0x49, 0x08, 
+0x83, 0x96, 0xC0, 0x80, 0x83, 0x52, 0x48, 0xC8, 0x83, 0x96, 0xBF, 0xC0, 0x08, 0x40, 0xC4, 0x01, 
+0x02, 0xF0, 0x44, 0xC2, 0x03, 0x18, 0x0F, 0x2B, 0x44, 0xC8, 0xB2, 0x7E, 0x84, 0x80, 0x83, 0x93, 
+0x80, 0x81, 0x44, 0xC8, 0xB0, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x44, 0xC8, 0xAA, 0x7E, 0x84, 0x80, 
+0x80, 0x81, 0x44, 0xC8, 0xB4, 0x7E, 0x84, 0x80, 0x80, 0x81, 0x44, 0xC8, 0xA8, 0x3E, 0x84, 0x80, 
+0x80, 0x81, 0x44, 0xC8, 0xAE, 0xBE, 0x84, 0x80, 0x80, 0x81, 0xC4, 0x4A, 0xF0, 0xEA, 0x0D, 0x70, 
+0xA9, 0x41, 0xA9, 0x8A, 0xA7, 0x40, 0x03, 0x30, 0xAD, 0x40, 0x0C, 0x30, 0xAB, 0x40, 0x04, 0xF0, 
+0xB5, 0x40, 0x0F, 0xB0, 0xB3, 0x40, 0x28, 0x30, 0xBA, 0x40, 0x50, 0x30, 0xB7, 0x80, 0x5A, 0xB0, 
+0x83, 0x96, 0xBA, 0x40, 0x04, 0xF0, 0xB7, 0x80, 0x0E, 0x70, 0xB6, 0x40, 0x34, 0x70, 0xB9, 0x40, 
+0x84, 0x30, 0xB8, 0x00, 0x83, 0x52, 0x02, 0xF0, 0xBF, 0x01, 0xBF, 0x4A, 0xBE, 0x80, 0x0A, 0x30, 
+0xBC, 0x81, 0xC0, 0x80, 0xBD, 0xC1, 0x08, 0x40, 0x9B, 0x81, 0x0A, 0x30, 0xA0, 0x80, 0x95, 0x41, 
+0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, 0x9E, 0x81, 
+0x9B, 0x81, 0xDA, 0x40, 0x1C, 0x70, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x8A, 0x95, 0xEF, 0x62, 
+0x8A, 0x95, 0x3D, 0xF0, 0x8A, 0x51, 0x54, 0xE7, 0x8A, 0x95, 0xC5, 0x00, 0xF7, 0xFA, 0x03, 0x9D, 
+0x54, 0xEB, 0x83, 0x96, 0xC3, 0x41, 0x57, 0x6B, 0x83, 0x96, 0xC3, 0x41, 0xC3, 0x8A, 0x43, 0x08, 
+0x03, 0x59, 0x5E, 0x6B, 0x8A, 0x51, 0xA9, 0xA4, 0x8A, 0x95, 0x61, 0xEB, 0x01, 0xF0, 0x83, 0x52, 
+0x9B, 0x40, 0x8A, 0x95, 0xAB, 0xE2, 0x8A, 0x95, 0x00, 0xB0, 0x8A, 0x51, 0x54, 0xE7, 0x8A, 0x95, 
+0xC5, 0x00, 0xFE, 0xF9, 0x01, 0x38, 0xC5, 0x00, 0xDA, 0x40, 0x00, 0xB0, 0x8A, 0x51, 0x4C, 0xE7, 
+0x8A, 0x95, 0x00, 0xB0, 0x8A, 0x51, 0x54, 0xE7, 0x8A, 0x95, 0xC5, 0x00, 0xEF, 0xF9, 0x10, 0x38, 
+0xC5, 0x00, 0x45, 0x08, 0xDA, 0x40, 0x00, 0xB0, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x1C, 0x54, 
+0x9C, 0x94, 0x9C, 0xD6, 0x35, 0xB0, 0xED, 0x80, 0xED, 0x4B, 0x84, 0xAB, 0x83, 0x52, 0x03, 0x53, 
+0x9C, 0x92, 0x9C, 0x17, 0x35, 0xB0, 0xED, 0x80, 0xED, 0x4B, 0x8C, 0xEB, 0x83, 0x52, 0x03, 0x53, 
+0x9C, 0xD3, 0xC4, 0x01, 0x02, 0xF0, 0x44, 0xC2, 0x03, 0x18, 0x5F, 0x6C, 0x08, 0xF0, 0xDF, 0xC0, 
+0xAC, 0xB0, 0xE0, 0xC0, 0x97, 0xF0, 0xE1, 0x00, 0x44, 0xC8, 0xE2, 0x00, 0x0D, 0x70, 0x8A, 0x51, 
+0x07, 0x20, 0x8A, 0x95, 0x44, 0xC8, 0xA8, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0xCB, 0xB2, 0x2B, 
+0x44, 0xC8, 0xAA, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xED, 0x80, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 
+0x6D, 0x88, 0xB6, 0x6B, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x27, 0x48, 0x80, 0x40, 0x44, 0xC8, 
+0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x1F, 0xBE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x95, 
+0xED, 0x80, 0x44, 0xC8, 0x25, 0x3E, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x08, 0xF0, 0xDF, 0xC0, 
+0xB6, 0xF0, 0xE0, 0xC0, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x20, 0x38, 0xE1, 0x00, 
+0x44, 0xC8, 0xE2, 0x00, 0x0D, 0x70, 0x8A, 0x51, 0x07, 0x20, 0x8A, 0x95, 0x44, 0xC8, 0xAE, 0xBE, 
+0x84, 0x80, 0x83, 0x93, 0x00, 0xCB, 0xE6, 0x6B, 0x44, 0xC8, 0xB0, 0x3E, 0x84, 0x80, 0x00, 0x48, 
+0xED, 0x80, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x6D, 0x88, 0xEA, 0x6B, 0x44, 0xC8, 0x58, 0x3E, 
+0x84, 0x80, 0x35, 0x48, 0x80, 0x40, 0x06, 0x30, 0xDA, 0x40, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 
+0x35, 0x48, 0x00, 0x42, 0x8A, 0x95, 0x81, 0x22, 0x8A, 0x95, 0xED, 0x80, 0x44, 0xC8, 0xAC, 0x7E, 
+0x84, 0x80, 0x6D, 0x88, 0x83, 0x93, 0x80, 0x40, 0x44, 0xC8, 0xAC, 0x7E, 0x84, 0x80, 0x00, 0x48, 
+0xED, 0x80, 0x44, 0xC8, 0x25, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x6D, 0x07, 0xEE, 0x80, 0x44, 0xC8, 
+0x23, 0x3E, 0x84, 0x80, 0x6E, 0x88, 0x80, 0x40, 0x44, 0xC8, 0x23, 0x3E, 0x84, 0x80, 0x7F, 0x70, 
+0x00, 0x42, 0x03, 0x5C, 0x18, 0x6C, 0x44, 0xC8, 0x23, 0x3E, 0x84, 0x80, 0x7F, 0x70, 0x80, 0x40, 
+0x44, 0x18, 0x21, 0x6C, 0x44, 0xC8, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xDA, 0x40, 0x03, 0x30, 
+0x27, 0xEC, 0x44, 0xC8, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xDA, 0x40, 0x04, 0xF0, 0x8A, 0x51, 
+0x4C, 0xE7, 0x8A, 0x95, 0x44, 0x18, 0x43, 0xAC, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x83, 0x93, 
+0x00, 0x48, 0xED, 0x80, 0x01, 0xF0, 0x03, 0xD0, 0xED, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 
+0x34, 0xAC, 0x6D, 0x0D, 0x02, 0xBE, 0xC5, 0x00, 0xDA, 0x40, 0x01, 0xF0, 0x8A, 0x51, 0x4C, 0xE7, 
+0x8A, 0x95, 0x01, 0xF0, 0x59, 0xEC, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0xED, 0x80, 0x01, 0xF0, 0x03, 0xD0, 0xED, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0x4B, 0xEC, 
+0x6D, 0x0D, 0x02, 0xBE, 0xC5, 0x00, 0xDA, 0x40, 0x02, 0xF0, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 
+0x02, 0xF0, 0xDA, 0x81, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0xC4, 0x4A, 0x92, 0xEB, 0xC2, 0x01, 
+0x08, 0xF0, 0x42, 0xC2, 0x03, 0x18, 0x84, 0x6C, 0x42, 0xC8, 0xDA, 0x40, 0x05, 0x30, 0x8A, 0x51, 
+0x4C, 0xE7, 0x8A, 0x95, 0x42, 0xC8, 0xA0, 0xFE, 0x84, 0x80, 0x83, 0x96, 0x37, 0x88, 0x83, 0x93, 
+0x80, 0x40, 0x83, 0x52, 0x42, 0xC8, 0xA0, 0xFE, 0x84, 0x80, 0x03, 0x14, 0x00, 0xCD, 0xC5, 0x00, 
+0xDA, 0x40, 0x06, 0x30, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x06, 0x30, 0xDA, 0x81, 0x8A, 0x51, 
+0x4C, 0xE7, 0x8A, 0x95, 0xC2, 0x4A, 0x60, 0x6C, 0x9B, 0x81, 0x3F, 0x30, 0x8A, 0x51, 0x54, 0xE7, 
+0x8A, 0x95, 0xC5, 0x00, 0xFF, 0x3A, 0x03, 0x59, 0x9B, 0x81, 0x12, 0x18, 0x1C, 0x9C, 0xA5, 0xEC, 
+0x1C, 0x10, 0x3D, 0x88, 0xDF, 0xC0, 0x00, 0xB0, 0x8A, 0x51, 0x25, 0x61, 0x8A, 0x95, 0xC6, 0x00, 
+0x46, 0x8B, 0x9F, 0x6C, 0x1B, 0x48, 0xBF, 0xF9, 0x01, 0x38, 0x9B, 0x40, 0xA5, 0xEC, 0x41, 0x30, 
+0x9B, 0x84, 0x00, 0xB0, 0x8A, 0x51, 0x15, 0x20, 0x8A, 0x95, 0x83, 0x52, 0x03, 0x53, 0x12, 0x5C, 
+0x1C, 0x58, 0xB4, 0xEC, 0x46, 0x8B, 0xB1, 0xEC, 0xC6, 0x41, 0x00, 0xB0, 0x8A, 0x51, 0x15, 0x20, 
+0x8A, 0x95, 0x83, 0x52, 0x03, 0x53, 0x1C, 0x54, 0x92, 0x58, 0x9C, 0xDC, 0xCC, 0xEC, 0x9C, 0x50, 
+0x3D, 0x88, 0xDF, 0xC0, 0x01, 0xF0, 0x8A, 0x51, 0x25, 0x61, 0x8A, 0x95, 0xC7, 0x40, 0x47, 0xCB, 
+0xC6, 0xEC, 0x1B, 0x48, 0x7F, 0xF9, 0x02, 0x38, 0x9B, 0x40, 0xCC, 0xEC, 0x82, 0x30, 0x9B, 0x84, 
+0x01, 0xF0, 0x8A, 0x51, 0x15, 0x20, 0x8A, 0x95, 0x83, 0x52, 0x03, 0x53, 0x92, 0x9C, 0x9C, 0x98, 
+0xDB, 0x6C, 0x47, 0xCB, 0xD8, 0xEC, 0xC7, 0x81, 0x01, 0xF0, 0x8A, 0x51, 0x15, 0x20, 0x8A, 0x95, 
+0x83, 0x52, 0x03, 0x53, 0x9C, 0x94, 0xC2, 0x01, 0x08, 0xF0, 0x42, 0xC2, 0x03, 0x18, 0x2D, 0x2D, 
+0x42, 0xC8, 0xDA, 0x40, 0x05, 0x30, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x24, 0x30, 0x8A, 0x51, 
+0x54, 0xE7, 0x8A, 0x95, 0x83, 0x96, 0xC4, 0xC0, 0x38, 0x02, 0x03, 0x18, 0x00, 0x2D, 0x83, 0x52, 
+0x42, 0xC8, 0xA0, 0xFE, 0x84, 0x80, 0x83, 0x96, 0x36, 0x48, 0x83, 0x93, 0x00, 0x42, 0x03, 0x18, 
+0x00, 0x2D, 0x83, 0x52, 0x42, 0xC8, 0xA0, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0x14, 0xAD, 
+0x39, 0x48, 0x44, 0xC2, 0x03, 0x18, 0x2A, 0xED, 0x83, 0x52, 0x42, 0xC8, 0xA0, 0xFE, 0x84, 0x80, 
+0x83, 0x93, 0x00, 0x48, 0x83, 0x96, 0x37, 0x82, 0x03, 0x18, 0x2A, 0xED, 0x83, 0x52, 0x42, 0xC8, 
+0xA0, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xED, 0x80, 0x42, 0xC8, 0xA0, 0xFE, 0x84, 0x80, 
+0x6D, 0x88, 0x80, 0x40, 0x42, 0xC8, 0xA0, 0xFE, 0x84, 0x80, 0x03, 0x14, 0x00, 0xCD, 0xC5, 0x00, 
+0xDA, 0x40, 0x06, 0x30, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x06, 0x30, 0xDA, 0x81, 0x8A, 0x51, 
+0x4C, 0xE7, 0x8A, 0x95, 0x83, 0x52, 0xC2, 0x4A, 0xDC, 0x2C, 0x83, 0x96, 0xC6, 0x41, 0x83, 0x52, 
+0x21, 0x30, 0xC4, 0x01, 0x8A, 0x51, 0x54, 0xE7, 0x8A, 0x95, 0xC3, 0x00, 0x20, 0xF0, 0x8A, 0x51, 
+0x54, 0xE7, 0x8A, 0x95, 0xC1, 0xC0, 0x94, 0x9C, 0x8F, 0x6D, 0x44, 0xC8, 0xA8, 0x3E, 0x84, 0x80, 
+0x83, 0x93, 0x80, 0x88, 0x03, 0x9D, 0x84, 0xAD, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 
+0x29, 0x02, 0x03, 0x18, 0x84, 0xAD, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 
+0xED, 0x80, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x08, 0xF0, 0xDF, 0xC0, 
+0xB6, 0xF0, 0xE0, 0xC0, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x20, 0x38, 0xE1, 0x00, 
+0x44, 0xC8, 0xE2, 0x00, 0x0D, 0x70, 0x8A, 0x51, 0x07, 0x20, 0x8A, 0x95, 0x01, 0xF0, 0xDA, 0x81, 
+0xDA, 0xCA, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x01, 0xF0, 0xDA, 0x81, 0x8A, 0x51, 0x4C, 0xE7, 
+0x8A, 0x95, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x1F, 0xBE, 0x84, 0x80, 
+0x8A, 0x95, 0x00, 0x60, 0x8A, 0x95, 0xED, 0x80, 0x44, 0xC8, 0x25, 0x3E, 0x84, 0x80, 0x6D, 0x88, 
+0x80, 0x40, 0x83, 0x96, 0xC6, 0x41, 0xC6, 0x8A, 0x83, 0x52, 0x9C, 0x92, 0x1C, 0x96, 0x05, 0x30, 
+0xED, 0x80, 0xED, 0x4B, 0x89, 0xED, 0x83, 0x52, 0x03, 0x53, 0x1C, 0x52, 0x6B, 0x6E, 0x44, 0xC8, 
+0xAE, 0xBE, 0x84, 0x80, 0x83, 0x93, 0x80, 0x88, 0x03, 0x9D, 0x0F, 0x2E, 0x44, 0xC8, 0x21, 0xFE, 
+0x84, 0x80, 0x00, 0x48, 0x27, 0x86, 0x03, 0x9D, 0xA0, 0xAD, 0x37, 0x88, 0x83, 0x96, 0xA2, 0xED, 
+0x83, 0x96, 0x3A, 0x48, 0xC5, 0x00, 0x83, 0x52, 0x43, 0x08, 0x83, 0x96, 0x45, 0x02, 0x03, 0x18, 
+0xC9, 0x2D, 0x83, 0x52, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x33, 0x48, 0x00, 0x42, 0x03, 0x18, 
+0xC9, 0x2D, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0xED, 0x80, 0x44, 0xC8, 
+0x58, 0x3E, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 
+0xED, 0x80, 0x01, 0xF0, 0x03, 0xD0, 0xED, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0xC3, 0x2D, 
+0xEC, 0x6D, 0x83, 0x52, 0x3A, 0x48, 0x43, 0x02, 0x44, 0xC8, 0x03, 0x18, 0x10, 0x6E, 0x58, 0x3E, 
+0x84, 0x80, 0x00, 0x48, 0x35, 0x42, 0x44, 0xC8, 0x03, 0x18, 0x10, 0x6E, 0x58, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0xFF, 0x7E, 0xED, 0x80, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 
+0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xED, 0x80, 0x01, 0xF0, 0x03, 0xD0, 0xED, 0x4D, 
+0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0xE7, 0xAD, 0x6D, 0x0D, 0x02, 0xBE, 0xC5, 0x00, 0xDA, 0x40, 
+0x01, 0xF0, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x01, 0xF0, 0xDA, 0x81, 0x8A, 0x51, 0x4C, 0xE7, 
+0x8A, 0x95, 0x83, 0x96, 0x06, 0x30, 0xC6, 0x41, 0xC6, 0x8A, 0x83, 0x52, 0xDA, 0x40, 0x44, 0xC8, 
+0x58, 0x3E, 0x84, 0x80, 0x35, 0x48, 0x83, 0x93, 0x00, 0x42, 0x8A, 0x95, 0x81, 0x22, 0x8A, 0x95, 
+0xED, 0x80, 0x44, 0xC8, 0xAC, 0x7E, 0x84, 0x80, 0x6D, 0x88, 0x83, 0x93, 0x80, 0x40, 0x44, 0xC8, 
+0xA8, 0x3E, 0x84, 0x80, 0x80, 0x88, 0x03, 0x9D, 0x6B, 0x6E, 0x41, 0xC8, 0x2B, 0x42, 0x03, 0x18, 
+0x26, 0xEE, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x29, 0x02, 0x03, 0x18, 0x26, 0xEE, 
+0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0x36, 0x2E, 0x2D, 0x48, 0x41, 0xC2, 
+0x03, 0x18, 0x6B, 0x6E, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x27, 0x48, 0x00, 0x42, 0x03, 0x18, 
+0x6B, 0x6E, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0xED, 0x80, 0x44, 0xC8, 
+0x21, 0xFE, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x08, 0xF0, 0xDF, 0xC0, 0xB6, 0xF0, 0xE0, 0xC0, 
+0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x20, 0x38, 0xE1, 0x00, 0x44, 0xC8, 0xE2, 0x00, 
+0x0D, 0x70, 0x8A, 0x51, 0x07, 0x20, 0x8A, 0x95, 0x01, 0xF0, 0xDA, 0x81, 0xDA, 0xCA, 0x8A, 0x51, 
+0x4C, 0xE7, 0x8A, 0x95, 0x01, 0xF0, 0xDA, 0x81, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x83, 0x96, 
+0xC6, 0x41, 0xC6, 0x8A, 0x83, 0x52, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0x1F, 0xBE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x95, 0xED, 0x80, 0x44, 0xC8, 0x25, 0x3E, 
+0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x83, 0x96, 0x46, 0x8B, 0x95, 0x2E, 0x83, 0x52, 0x44, 0xC8, 
+0xAC, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xED, 0x80, 0x44, 0xC8, 0x25, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0x6D, 0x07, 0xEE, 0x80, 0x44, 0xC8, 0x23, 0x3E, 0x84, 0x80, 0x6E, 0x88, 0x80, 0x40, 
+0x44, 0xC8, 0x23, 0x3E, 0x84, 0x80, 0x7F, 0x70, 0x00, 0x42, 0x44, 0xC8, 0x03, 0x5C, 0x8D, 0x2E, 
+0x23, 0x3E, 0x84, 0x80, 0x7F, 0x70, 0x80, 0x40, 0x44, 0xC8, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 
+0xDA, 0x40, 0x03, 0x30, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x83, 0x52, 0x23, 0x70, 0xC4, 0x01, 
+0xC4, 0x4A, 0x8A, 0x51, 0x54, 0xE7, 0x8A, 0x95, 0xC3, 0x00, 0x22, 0x30, 0x8A, 0x51, 0x54, 0xE7, 
+0x8A, 0x95, 0xC1, 0xC0, 0x83, 0x96, 0xC7, 0x81, 0x83, 0x52, 0x94, 0xDD, 0xF9, 0xAE, 0x44, 0xC8, 
+0xA8, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x88, 0x03, 0x9D, 0xEE, 0xAE, 0x44, 0xC8, 0x21, 0xFE, 
+0x84, 0x80, 0x00, 0x48, 0x29, 0x02, 0x03, 0x18, 0xEE, 0xAE, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 
+0x00, 0x48, 0xFF, 0x7E, 0xED, 0x80, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 
+0x08, 0xF0, 0xDF, 0xC0, 0xB6, 0xF0, 0xE0, 0xC0, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 
+0x20, 0x38, 0xE1, 0x00, 0x44, 0xC8, 0xE2, 0x00, 0x0D, 0x70, 0x8A, 0x51, 0x07, 0x20, 0x8A, 0x95, 
+0x02, 0xF0, 0xDA, 0x81, 0xDA, 0xCA, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x02, 0xF0, 0xDA, 0x81, 
+0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0x1F, 0xBE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x95, 0xED, 0x80, 0x44, 0xC8, 0x25, 0x3E, 
+0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x83, 0x96, 0xC7, 0x81, 0xC7, 0xCA, 0x83, 0x52, 0x9C, 0xD3, 
+0x1C, 0xD7, 0x05, 0x30, 0xED, 0x80, 0xED, 0x4B, 0xF3, 0xAE, 0x83, 0x52, 0x03, 0x53, 0x1C, 0x93, 
+0xD5, 0xAF, 0x44, 0xC8, 0xAE, 0xBE, 0x84, 0x80, 0x83, 0x93, 0x80, 0x88, 0x03, 0x9D, 0x79, 0xAF, 
+0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x27, 0x86, 0x03, 0x9D, 0x0A, 0xEF, 0x37, 0x88, 
+0x83, 0x96, 0x0C, 0xEF, 0x83, 0x96, 0x3A, 0x48, 0xC5, 0x00, 0x83, 0x52, 0x43, 0x08, 0x83, 0x96, 
+0x45, 0x02, 0x03, 0x18, 0x33, 0x6F, 0x83, 0x52, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x33, 0x48, 
+0x00, 0x42, 0x03, 0x18, 0x33, 0x6F, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 
+0xED, 0x80, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x44, 0xC8, 0x58, 0x3E, 
+0x84, 0x80, 0x00, 0x48, 0xED, 0x80, 0x01, 0xF0, 0x03, 0xD0, 0xED, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 
+0x03, 0x9D, 0x2D, 0x6F, 0x56, 0x6F, 0x83, 0x52, 0x3A, 0x48, 0x43, 0x02, 0x44, 0xC8, 0x03, 0x18, 
+0x7A, 0xAF, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x35, 0x42, 0x44, 0xC8, 0x03, 0x18, 0x7A, 0xAF, 
+0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xED, 0x80, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 
+0x6D, 0x88, 0x80, 0x40, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xED, 0x80, 0x01, 0xF0, 
+0x03, 0xD0, 0xED, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0x51, 0x2F, 0x6D, 0x0D, 0x02, 0xBE, 
+0xC5, 0x00, 0xDA, 0x40, 0x02, 0xF0, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x02, 0xF0, 0xDA, 0x81, 
+0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x83, 0x96, 0x06, 0x30, 0xC7, 0x81, 0xC7, 0xCA, 0x83, 0x52, 
+0xDA, 0x40, 0x44, 0xC8, 0x58, 0x3E, 0x84, 0x80, 0x35, 0x48, 0x83, 0x93, 0x00, 0x42, 0x8A, 0x95, 
+0x81, 0x22, 0x8A, 0x95, 0xED, 0x80, 0x44, 0xC8, 0xAC, 0x7E, 0x84, 0x80, 0x6D, 0x88, 0x83, 0x93, 
+0x80, 0x40, 0x44, 0xC8, 0xA8, 0x3E, 0x84, 0x80, 0x80, 0x88, 0x03, 0x9D, 0xD5, 0xAF, 0x41, 0xC8, 
+0x2B, 0x42, 0x03, 0x18, 0x90, 0xEF, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x29, 0x02, 
+0x03, 0x18, 0x90, 0xEF, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xA0, 0xEF, 
+0x2D, 0x48, 0x41, 0xC2, 0x03, 0x18, 0xD5, 0xAF, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x27, 0x48, 
+0x00, 0x42, 0x03, 0x18, 0xD5, 0xAF, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 
+0xED, 0x80, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x08, 0xF0, 0xDF, 0xC0, 
+0xB6, 0xF0, 0xE0, 0xC0, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x20, 0x38, 0xE1, 0x00, 
+0x44, 0xC8, 0xE2, 0x00, 0x0D, 0x70, 0x8A, 0x51, 0x07, 0x20, 0x8A, 0x95, 0x02, 0xF0, 0xDA, 0x81, 
+0xDA, 0xCA, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x02, 0xF0, 0xDA, 0x81, 0x8A, 0x51, 0x4C, 0xE7, 
+0x8A, 0x95, 0x83, 0x96, 0xC7, 0x81, 0xC7, 0xCA, 0x83, 0x52, 0x44, 0xC8, 0x21, 0xFE, 0x84, 0x80, 
+0x83, 0x93, 0x00, 0x48, 0x1F, 0xBE, 0x84, 0x80, 0x8A, 0x95, 0x00, 0x60, 0x8A, 0x95, 0xED, 0x80, 
+0x44, 0xC8, 0x25, 0x3E, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x83, 0x96, 0x47, 0xCB, 0x85, 0xAC, 
+0x83, 0x52, 0x44, 0xC8, 0xAC, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xED, 0x80, 0x44, 0xC8, 
+0x25, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x6D, 0x07, 0xEE, 0x80, 0x44, 0xC8, 0x23, 0x3E, 0x84, 0x80, 
+0x6E, 0x88, 0x80, 0x40, 0x44, 0xC8, 0x23, 0x3E, 0x84, 0x80, 0x7F, 0x70, 0x00, 0x42, 0x44, 0xC8, 
+0x03, 0x5C, 0xF7, 0x2F, 0x23, 0x3E, 0x84, 0x80, 0x7F, 0x70, 0x80, 0x40, 0x44, 0xC8, 0x23, 0x3E, 
+0x84, 0x80, 0x00, 0x48, 0xDA, 0x40, 0x04, 0xF0, 0x8A, 0x51, 0x4C, 0xE7, 0x8A, 0x95, 0x85, 0xAC 
+ }; 
+ 

+ 515 - 0
sx1302/source/agc_fw_sx1257.var

@@ -0,0 +1,515 @@
+static uint8_t agc_firmware_sx125x[8192] = { 
+0x8A, 0x51, 0xCF, 0xEF, 0x00, 0xB0, 0x8A, 0xC0, 0x04, 0x88, 0x84, 0x0A, 0x82, 0x47, 0x00, 0xF4, 
+0x0F, 0xF4, 0x0C, 0x74, 0x09, 0x74, 0x09, 0x74, 0x09, 0x74, 0x0C, 0x74, 0x0F, 0xF4, 0x0C, 0x74, 
+0x0F, 0xF4, 0x0C, 0x74, 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, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 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, 0x8C, 0xA9, 0xDE, 0x80, 0xDD, 0xC1, 0x5C, 0x48, 0x5E, 0xD8, 0xDD, 0x47, 
+0x03, 0xD0, 0xDC, 0x0D, 0x5C, 0x48, 0xDE, 0x18, 0xDD, 0x47, 0x03, 0xD0, 0xDC, 0x0D, 0x5C, 0x48, 
+0x5E, 0x19, 0xDD, 0x47, 0x03, 0xD0, 0xDC, 0x0D, 0x5C, 0x48, 0xDE, 0x59, 0xDD, 0x47, 0x03, 0xD0, 
+0xDC, 0x0D, 0x5C, 0x48, 0x5E, 0x1A, 0xDD, 0x47, 0x03, 0xD0, 0xDC, 0x0D, 0x5C, 0x48, 0xDE, 0x5A, 
+0xDD, 0x47, 0x03, 0xD0, 0xDC, 0x0D, 0x5C, 0x48, 0x5E, 0x5B, 0xDD, 0x47, 0x03, 0xD0, 0xDC, 0x0D, 
+0x5C, 0x48, 0xDE, 0x9B, 0xDD, 0x47, 0x5D, 0x88, 0x08, 0x40, 0xD7, 0xC1, 0x02, 0xF0, 0x57, 0x82, 
+0x03, 0x18, 0xDD, 0x69, 0x57, 0x88, 0x2B, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x57, 0x88, 
+0x29, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x57, 0x88, 0x25, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x57, 0x88, 
+0x31, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x57, 0x88, 0xA8, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x57, 0x88, 
+0xAC, 0x7E, 0x84, 0x80, 0x80, 0x81, 0xD7, 0x0A, 0xBE, 0x69, 0x09, 0x30, 0xB5, 0x81, 0xB3, 0x40, 
+0x10, 0xF0, 0xB9, 0x40, 0x23, 0x70, 0xB7, 0x80, 0x07, 0x70, 0xC5, 0x00, 0x0B, 0x70, 0xC3, 0x00, 
+0x2D, 0xB0, 0xCB, 0x40, 0x64, 0x70, 0xC7, 0x40, 0x73, 0xF0, 0xC9, 0x00, 0x04, 0xF0, 0xBD, 0x80, 
+0x0E, 0x70, 0xBB, 0x80, 0x34, 0x70, 0xC1, 0xC0, 0x84, 0x30, 0xBF, 0xC0, 0x0A, 0x30, 0xCF, 0x80, 
+0xCD, 0x81, 0x08, 0x40, 0x06, 0x30, 0xA0, 0x80, 0x95, 0x41, 0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 
+0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, 0x9E, 0x81, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0xFE, 0xF9, 0x01, 0x38, 
+0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0xEF, 0xF9, 0x10, 0x38, 0xEF, 0xC0, 0x6F, 0xC8, 
+0xDC, 0x40, 0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x1C, 0x54, 0x9C, 0x94, 0x83, 0x96, 0xAE, 0x81, 0xAF, 0xC1, 0x83, 0x52, 0xB1, 0x41, 
+0xB2, 0x41, 0x9B, 0x81, 0x06, 0x30, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 
+0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x8A, 0x51, 0xBD, 0x21, 0x8A, 0x51, 0x3D, 0xF0, 
+0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 
+0xF7, 0xFA, 0x03, 0x9D, 0x55, 0xEA, 0xCE, 0x81, 0x57, 0x2A, 0xCE, 0x81, 0xCE, 0xCA, 0x4E, 0x48, 
+0x03, 0x59, 0x5E, 0x2A, 0x8A, 0x95, 0x61, 0x64, 0x8A, 0x51, 0x60, 0x6A, 0x01, 0xF0, 0x9B, 0x40, 
+0xD7, 0xC1, 0x02, 0xF0, 0x57, 0x82, 0x03, 0x18, 0x6C, 0x2B, 0x57, 0x88, 0xA8, 0x3E, 0x84, 0x80, 
+0x83, 0x93, 0x00, 0xCB, 0x75, 0x2A, 0x57, 0x88, 0x25, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xEB, 0x80, 
+0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x6B, 0x88, 0x79, 0x2A, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 
+0x35, 0x48, 0x80, 0x40, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x0F, 0x39, 0xEB, 0x80, 0x03, 0xD0, 0xEB, 0x4D, 0x57, 0x88, 
+0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x15, 0x3E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 
+0x07, 0xF9, 0xEC, 0x40, 0x04, 0xF0, 0x03, 0xD0, 0xEC, 0x0D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 
+0x94, 0xAA, 0x6C, 0xCD, 0x6B, 0x84, 0xED, 0x80, 0x57, 0x88, 0x21, 0xFE, 0x84, 0x80, 0x6D, 0x88, 
+0x80, 0x40, 0x8C, 0x70, 0x83, 0x96, 0xB8, 0x00, 0x83, 0x52, 0x57, 0x88, 0x21, 0xFE, 0x84, 0x80, 
+0x00, 0x48, 0x83, 0x96, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x57, 0x88, 0xDD, 0x80, 
+0x02, 0xF0, 0x8A, 0x95, 0xC5, 0xE3, 0x8A, 0x51, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x83, 0x93, 
+0x00, 0x48, 0x0B, 0x3E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xEB, 0x80, 0x57, 0x88, 
+0x2F, 0xBE, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x57, 0x88, 0xAC, 0x7E, 0x84, 0x80, 0x00, 0xCB, 
+0xD3, 0x2A, 0x57, 0x88, 0x29, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xEB, 0x80, 0x57, 0x88, 0x58, 0x3E, 
+0x84, 0x80, 0x6B, 0x88, 0xD7, 0x6A, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x45, 0x08, 0x80, 0x40, 
+0x06, 0x30, 0xDC, 0x40, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x45, 0x08, 0x00, 0x42, 0x8A, 0x51, 
+0x93, 0xA1, 0x8A, 0x51, 0xEB, 0x80, 0x57, 0x88, 0x27, 0x7E, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 
+0x57, 0x88, 0x27, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xEB, 0x80, 0x57, 0x88, 0x2F, 0xBE, 0x84, 0x80, 
+0x00, 0x48, 0x6B, 0x07, 0xEC, 0x40, 0x57, 0x88, 0x2D, 0x7E, 0x84, 0x80, 0x6C, 0x48, 0x80, 0x40, 
+0x57, 0x88, 0x2D, 0x7E, 0x84, 0x80, 0x7F, 0x70, 0x00, 0x42, 0x03, 0x5C, 0x04, 0x6B, 0x57, 0x88, 
+0x2D, 0x7E, 0x84, 0x80, 0x7F, 0x70, 0x80, 0x40, 0x57, 0xD8, 0x3A, 0x2B, 0x57, 0x88, 0x2D, 0x7E, 
+0x84, 0x80, 0x00, 0x48, 0xDC, 0x40, 0x03, 0x30, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x57, 0xD8, 0x48, 0xAB, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 
+0x83, 0x93, 0x00, 0x48, 0xEB, 0x80, 0x01, 0xF0, 0x03, 0xD0, 0xEB, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 
+0x03, 0x9D, 0x1D, 0x2B, 0x6B, 0x0D, 0x02, 0xBE, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 0x01, 0xF0, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 
+0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0xD7, 0x0A, 0x61, 0xAA, 0x57, 0x88, 0x2D, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xDC, 0x40, 0x04, 0xF0, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x13, 0xEB, 
+0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xEB, 0x80, 0x01, 0xF0, 0x03, 0xD0, 
+0xEB, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0x50, 0xAB, 0x6B, 0x0D, 0x02, 0xBE, 0xEF, 0xC0, 
+0x6F, 0xC8, 0xDC, 0x40, 0x02, 0xF0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x02, 0xF0, 0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x38, 0xEB, 0xD1, 0x41, 0x51, 0x08, 0xDC, 0x40, 0x05, 0x30, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x51, 0x08, 
+0xA0, 0xFE, 0x84, 0x80, 0x3D, 0x88, 0x83, 0x93, 0x80, 0x40, 0x51, 0x08, 0xA0, 0xFE, 0x84, 0x80, 
+0x03, 0x14, 0x00, 0xCD, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 0x06, 0x30, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x06, 0x30, 0xDC, 0x81, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x08, 0xF0, 0xD1, 0x8A, 
+0x51, 0x02, 0x03, 0x5C, 0x6D, 0x6B, 0x9B, 0x81, 0x6E, 0x90, 0x3F, 0x30, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0xFF, 0x3A, 0x03, 0x59, 
+0x9B, 0x81, 0x12, 0x18, 0x1C, 0x9C, 0xBF, 0xEB, 0x1C, 0x10, 0x4D, 0x48, 0x03, 0x9D, 0x9D, 0x5B, 
+0xB2, 0x2B, 0xBC, 0x6B, 0xEE, 0x14, 0x1B, 0x48, 0xBF, 0xF9, 0x01, 0x38, 0x9B, 0x40, 0x00, 0xB0, 
+0x8A, 0x95, 0xB1, 0xA1, 0x8A, 0x51, 0xBF, 0xEB, 0xEE, 0xD0, 0x41, 0x30, 0x9B, 0x84, 0x12, 0x5C, 
+0x1C, 0x58, 0xCA, 0x2B, 0xEE, 0x5C, 0xC9, 0x2B, 0xEE, 0xD0, 0x00, 0xB0, 0x8A, 0x95, 0x17, 0xA1, 
+0x8A, 0x51, 0x1C, 0x54, 0x92, 0x58, 0x9C, 0xDC, 0xE0, 0xEB, 0x9C, 0x50, 0x4D, 0x48, 0x03, 0x9D, 
+0x9D, 0x5B, 0xD3, 0x6B, 0xDD, 0xAB, 0x6E, 0x15, 0x1B, 0x48, 0x7F, 0xF9, 0x02, 0x38, 0x9B, 0x40, 
+0x01, 0xF0, 0x8A, 0x95, 0xB1, 0xA1, 0x8A, 0x51, 0xE0, 0xEB, 0x6E, 0xD1, 0x82, 0x30, 0x9B, 0x84, 
+0x92, 0x9C, 0x9C, 0x98, 0xEB, 0xAB, 0x6E, 0x5D, 0xEA, 0x6B, 0x6E, 0xD1, 0x01, 0xF0, 0x8A, 0x95, 
+0x17, 0xA1, 0x8A, 0x51, 0x9C, 0x94, 0xD1, 0x41, 0x51, 0x08, 0xDC, 0x40, 0x05, 0x30, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x24, 0x30, 0xDC, 0x40, 
+0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD2, 0x00, 0x52, 0x08, 0x3F, 0xC2, 
+0x03, 0x18, 0x51, 0xAC, 0x51, 0x08, 0xA0, 0xFE, 0x84, 0x80, 0x3B, 0x88, 0x83, 0x93, 0x00, 0x42, 
+0x03, 0x18, 0x51, 0xAC, 0x51, 0x08, 0xA0, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0xEB, 0x80, 
+0x51, 0x08, 0xA0, 0xFE, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x51, 0x08, 0xA0, 0xFE, 0x84, 0x80, 
+0x03, 0x14, 0x00, 0xCD, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 0x06, 0x30, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x06, 0x30, 0xDC, 0x81, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x08, 0xF0, 0xD1, 0x8A, 
+0x51, 0x02, 0x03, 0x5C, 0xEC, 0x6B, 0x58, 0x8E, 0xF0, 0x39, 0x23, 0x04, 0x9E, 0x40, 0x21, 0x30, 
+0xD7, 0xC1, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD3, 0x40, 
+0x20, 0xF0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD0, 0xC0, 
+0xD5, 0x81, 0x57, 0x88, 0xAC, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x88, 0x03, 0x59, 0x82, 0x6C, 
+0x11, 0xAD, 0x41, 0xC8, 0x52, 0x02, 0x03, 0x18, 0x2E, 0xEC, 0x51, 0x08, 0xA0, 0xFE, 0x84, 0x80, 
+0x83, 0x93, 0x00, 0x48, 0x3D, 0x82, 0x03, 0x18, 0x2E, 0xEC, 0x51, 0x08, 0xA0, 0xFE, 0x84, 0x80, 
+0x00, 0x48, 0xFF, 0x7E, 0xEB, 0x80, 0x51, 0x08, 0xA0, 0xFE, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 
+0x51, 0x08, 0xA0, 0xFE, 0x84, 0x80, 0x03, 0x14, 0x00, 0xCD, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 
+0x06, 0x30, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x06, 0x30, 0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x2E, 0xEC, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x35, 0x86, 0x03, 0x9D, 
+0x8B, 0xEC, 0x47, 0x48, 0x8C, 0xAC, 0x49, 0x08, 0xD4, 0x00, 0x53, 0x48, 0x54, 0x02, 0x03, 0x18, 
+0xC6, 0xEC, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x43, 0x08, 0x00, 0x42, 0x03, 0x18, 0xC6, 0xEC, 
+0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0xEB, 0x80, 0x57, 0x88, 0x58, 0x3E, 
+0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xEB, 0x80, 
+0x01, 0xF0, 0x03, 0xD0, 0xEB, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0xAA, 0xEC, 0x6B, 0x0D, 
+0x02, 0xBE, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 0x01, 0xF0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 
+0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xFE, 0xAC, 0x4B, 0x48, 0x53, 0x42, 
+0x57, 0x88, 0x03, 0x18, 0x12, 0xAD, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x45, 0x02, 0x57, 0x88, 
+0x03, 0x18, 0x12, 0xAD, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xEB, 0x80, 0x57, 0x88, 
+0x58, 0x3E, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 
+0xEB, 0x80, 0x01, 0xF0, 0x03, 0xD0, 0xEB, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0xE3, 0x2C, 
+0x6B, 0x0D, 0x02, 0xBE, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 0x01, 0xF0, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 0xDC, 0x81, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x06, 0x30, 0xD5, 0x81, 
+0xD5, 0xCA, 0xDC, 0x40, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x45, 0x08, 0x83, 0x93, 0x00, 0x42, 
+0x8A, 0x51, 0x93, 0xA1, 0x8A, 0x51, 0xEB, 0x80, 0x57, 0x88, 0x27, 0x7E, 0x84, 0x80, 0x6B, 0x88, 
+0x80, 0x40, 0x57, 0x88, 0xA8, 0x3E, 0x84, 0x80, 0x80, 0x88, 0x03, 0x9D, 0xF0, 0x2D, 0x50, 0xC8, 
+0x37, 0x82, 0x03, 0x18, 0x7B, 0xAD, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x33, 0x48, 0x00, 0x42, 
+0x03, 0x18, 0x7B, 0xAD, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0xEB, 0x80, 
+0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x0F, 0x39, 0xEB, 0x80, 
+0x03, 0xD0, 0xEB, 0x4D, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x15, 0x3E, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x07, 0xF9, 0xEC, 0x40, 0x04, 0xF0, 0x03, 0xD0, 0xEC, 0x0D, 
+0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0x47, 0x2D, 0x6C, 0xCD, 0x6B, 0x84, 0xED, 0x80, 0x57, 0x88, 
+0x21, 0xFE, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x8C, 0x70, 0x83, 0x96, 0xB8, 0x00, 0x83, 0x52, 
+0x57, 0x88, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x83, 0x96, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 
+0xDC, 0x40, 0x57, 0x88, 0xDD, 0x80, 0x02, 0xF0, 0x8A, 0x95, 0xC5, 0xE3, 0x8A, 0x51, 0x01, 0xF0, 
+0xDC, 0x81, 0xDC, 0xCA, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x01, 0xF0, 0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0xDE, 0xAD, 0x39, 0x48, 0x50, 0xC2, 0x03, 0x18, 0xF0, 0x2D, 0x57, 0x88, 
+0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x35, 0x42, 0x03, 0x18, 0xF0, 0x2D, 0x57, 0x88, 0x23, 0x3E, 
+0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xEB, 0x80, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x6B, 0x88, 
+0x80, 0x40, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 
+0x02, 0xA0, 0x8A, 0x51, 0x0F, 0x39, 0xEB, 0x80, 0x03, 0xD0, 0xEB, 0x4D, 0x57, 0x88, 0x23, 0x3E, 
+0x84, 0x80, 0x00, 0x48, 0x15, 0x3E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x07, 0xF9, 
+0xEC, 0x40, 0x04, 0xF0, 0x03, 0xD0, 0xEC, 0x0D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0xAB, 0x6D, 
+0x6C, 0xCD, 0x6B, 0x84, 0xED, 0x80, 0x57, 0x88, 0x21, 0xFE, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 
+0x8C, 0x70, 0x83, 0x96, 0xB8, 0x00, 0x83, 0x52, 0x57, 0x88, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 
+0x83, 0x96, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x57, 0x88, 0xDD, 0x80, 0x02, 0xF0, 
+0x8A, 0x95, 0xC5, 0xE3, 0x8A, 0x51, 0x01, 0xF0, 0xDC, 0x81, 0xDC, 0xCA, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 0xDC, 0x81, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xD5, 0x81, 0xD5, 0xCA, 
+0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x0B, 0x3E, 0x84, 0x80, 0x8A, 0x51, 
+0x02, 0xA0, 0x8A, 0x51, 0xEB, 0x80, 0x57, 0x88, 0x2F, 0xBE, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 
+0x55, 0xCB, 0x1B, 0x2E, 0x57, 0x88, 0x27, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xEB, 0x80, 0x57, 0x88, 
+0x2F, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x6B, 0x07, 0xEC, 0x40, 0x57, 0x88, 0x2D, 0x7E, 0x84, 0x80, 
+0x6C, 0x48, 0x80, 0x40, 0x57, 0x88, 0x2D, 0x7E, 0x84, 0x80, 0x7F, 0x70, 0x00, 0x42, 0x57, 0x88, 
+0x03, 0x5C, 0x0F, 0x2E, 0x2D, 0x7E, 0x84, 0x80, 0x7F, 0x70, 0x80, 0x40, 0x57, 0x88, 0x2D, 0x7E, 
+0x84, 0x80, 0x00, 0x48, 0xDC, 0x40, 0x03, 0x30, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x23, 0x70, 0xD7, 0xC1, 0xD7, 0x0A, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD3, 0x40, 0x22, 0x30, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD0, 0xC0, 0xD6, 0x81, 0x57, 0x88, 0xAC, 0x7E, 
+0x84, 0x80, 0x83, 0x93, 0x80, 0x88, 0x03, 0x9D, 0xC4, 0xEE, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0x35, 0x86, 0x03, 0x9D, 0x3E, 0x6E, 0x47, 0x48, 0x3F, 0xAE, 0x49, 0x08, 0xD4, 0x00, 
+0x53, 0x48, 0x54, 0x02, 0x03, 0x18, 0x79, 0x6E, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x43, 0x08, 
+0x00, 0x42, 0x03, 0x18, 0x79, 0x6E, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 
+0xEB, 0x80, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x57, 0x88, 0x58, 0x3E, 
+0x84, 0x80, 0x00, 0x48, 0xEB, 0x80, 0x01, 0xF0, 0x03, 0xD0, 0xEB, 0x4D, 0xFF, 0x7E, 0x03, 0xD0, 
+0x03, 0x9D, 0x5D, 0x6E, 0x6B, 0x0D, 0x02, 0xBE, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 0x02, 0xF0, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x02, 0xF0, 
+0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0xB1, 0x2E, 0x4B, 0x48, 0x53, 0x42, 0x57, 0x88, 0x03, 0x18, 0xC5, 0x2E, 0x58, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0x45, 0x02, 0x57, 0x88, 0x03, 0x18, 0xC5, 0x2E, 0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 
+0xFF, 0x7E, 0xEB, 0x80, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x57, 0x88, 
+0x58, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xEB, 0x80, 0x01, 0xF0, 0x03, 0xD0, 0xEB, 0x4D, 0xFF, 0x7E, 
+0x03, 0xD0, 0x03, 0x9D, 0x96, 0x2E, 0x6B, 0x0D, 0x02, 0xBE, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 
+0x02, 0xF0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x02, 0xF0, 0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x06, 0x30, 0xD6, 0x81, 0xD6, 0xCA, 0xDC, 0x40, 0x57, 0x88, 0x58, 0x3E, 0x84, 0x80, 
+0x45, 0x08, 0x83, 0x93, 0x00, 0x42, 0x8A, 0x51, 0x93, 0xA1, 0x8A, 0x51, 0xEB, 0x80, 0x57, 0x88, 
+0x27, 0x7E, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x57, 0x88, 0xA8, 0x3E, 0x84, 0x80, 0x80, 0x88, 
+0x03, 0x9D, 0xA3, 0x6F, 0x50, 0xC8, 0x37, 0x82, 0x03, 0x18, 0x2E, 0x6F, 0x57, 0x88, 0x23, 0x3E, 
+0x84, 0x80, 0x33, 0x48, 0x00, 0x42, 0x03, 0x18, 0x2E, 0x6F, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0x01, 0xBE, 0xEB, 0x80, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 
+0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 
+0x8A, 0x51, 0x0F, 0x39, 0xEB, 0x80, 0x03, 0xD0, 0xEB, 0x4D, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0x15, 0x3E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x07, 0xF9, 0xEC, 0x40, 
+0x04, 0xF0, 0x03, 0xD0, 0xEC, 0x0D, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0xFA, 0xAE, 0x6C, 0xCD, 
+0x6B, 0x84, 0xED, 0x80, 0x57, 0x88, 0x21, 0xFE, 0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x8C, 0x70, 
+0x83, 0x96, 0xB8, 0x00, 0x83, 0x52, 0x57, 0x88, 0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x83, 0x96, 
+0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x57, 0x88, 0xDD, 0x80, 0x02, 0xF0, 0x8A, 0x95, 
+0xC5, 0xE3, 0x8A, 0x51, 0x02, 0xF0, 0xDC, 0x81, 0xDC, 0xCA, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 
+0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x02, 0xF0, 0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x91, 0x2F, 0x39, 0x48, 0x50, 0xC2, 
+0x03, 0x18, 0xA3, 0x6F, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x35, 0x42, 0x03, 0x18, 
+0xA3, 0x6F, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xFF, 0x7E, 0xEB, 0x80, 0x57, 0x88, 
+0x23, 0x3E, 0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 
+0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x0F, 0x39, 0xEB, 0x80, 0x03, 0xD0, 
+0xEB, 0x4D, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x15, 0x3E, 0x84, 0x80, 0x8A, 0x51, 
+0x02, 0xA0, 0x8A, 0x51, 0x07, 0xF9, 0xEC, 0x40, 0x04, 0xF0, 0x03, 0xD0, 0xEC, 0x0D, 0xFF, 0x7E, 
+0x03, 0xD0, 0x03, 0x9D, 0x5E, 0xAF, 0x6C, 0xCD, 0x6B, 0x84, 0xED, 0x80, 0x57, 0x88, 0x21, 0xFE, 
+0x84, 0x80, 0x6D, 0x88, 0x80, 0x40, 0x8C, 0x70, 0x83, 0x96, 0xB8, 0x00, 0x83, 0x52, 0x57, 0x88, 
+0x21, 0xFE, 0x84, 0x80, 0x00, 0x48, 0x83, 0x96, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 
+0x57, 0x88, 0xDD, 0x80, 0x02, 0xF0, 0x8A, 0x95, 0xC5, 0xE3, 0x8A, 0x51, 0x02, 0xF0, 0xDC, 0x81, 
+0xDC, 0xCA, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x02, 0xF0, 0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0xD6, 0x81, 0xD6, 0xCA, 0x57, 0x88, 0x23, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0x0B, 0x3E, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xEB, 0x80, 0x57, 0x88, 0x2F, 0xBE, 
+0x84, 0x80, 0x6B, 0x88, 0x80, 0x40, 0x56, 0xCB, 0x9D, 0x6B, 0x57, 0x88, 0x27, 0x7E, 0x84, 0x80, 
+0x00, 0x48, 0xEB, 0x80, 0x57, 0x88, 0x2F, 0xBE, 0x84, 0x80, 0x00, 0x48, 0x6B, 0x07, 0xEC, 0x40, 
+0x57, 0x88, 0x2D, 0x7E, 0x84, 0x80, 0x6C, 0x48, 0x80, 0x40, 0x57, 0x88, 0x2D, 0x7E, 0x84, 0x80, 
+0x7F, 0x70, 0x00, 0x42, 0x57, 0x88, 0x03, 0x5C, 0xC2, 0x2F, 0x2D, 0x7E, 0x84, 0x80, 0x7F, 0x70, 
+0x80, 0x40, 0x57, 0x88, 0x2D, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xDC, 0x40, 0x04, 0xF0, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x9D, 0x6B, 0xEE, 0xC1, 
+0x83, 0x93, 0x23, 0x70, 0x84, 0x80, 0x5C, 0xB0, 0x8A, 0x51, 0x8B, 0xA1, 0x8A, 0x51, 0xA0, 0x30, 
+0x84, 0x80, 0xD8, 0xB0, 0x8A, 0x51, 0x8B, 0xA1, 0x83, 0x96, 0x38, 0x70, 0xD8, 0x00, 0x3A, 0xB0, 
+0xD9, 0x40, 0x3C, 0xB0, 0xDA, 0x40, 0x78, 0xB0, 0xDB, 0x80, 0x7A, 0xF0, 0xDC, 0x40, 0x7C, 0xF0, 
+0xDD, 0x80, 0x7D, 0x30, 0xDE, 0x80, 0x7F, 0x70, 0xDF, 0xC0, 0xB9, 0xF0, 0xE0, 0xC0, 0xBA, 0xF0, 
+0xE1, 0x00, 0xBB, 0x30, 0xE2, 0x00, 0xFA, 0x30, 0xE3, 0x40, 0xFB, 0x70, 0xE4, 0x00, 0xFC, 0x30, 
+0xE5, 0x40, 0xFD, 0x70, 0xE6, 0x40, 0xFF, 0xB0, 0xE7, 0x80, 0x83, 0x01, 0x8A, 0x51, 0xFA, 0x69, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xE3, 0x40, 
+0x63, 0xDC, 0x7F, 0xA9, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xEF, 0xC0, 0x3F, 0x30, 0xEF, 0x45, 0x6F, 0xC8, 0xDC, 0x40, 0x00, 0xB0, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xE4, 0xB0, 0xE1, 0x00, 
+0x31, 0xA9, 0x32, 0xA9, 0xE1, 0xCB, 0x30, 0x69, 0x35, 0xE9, 0x00, 0x00, 0x83, 0x52, 0x03, 0x53, 
+0x63, 0xDC, 0x94, 0xA9, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0xEF, 0xF9, 0x10, 0x38, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 
+0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x80, 0xF0, 0x83, 0x96, 0xB8, 0x00, 0x03, 0x30, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 
+0x63, 0x48, 0xDD, 0x80, 0x02, 0xF0, 0xC5, 0xE3, 0x8A, 0x95, 0x04, 0xF0, 0xE2, 0x00, 0x1C, 0x70, 
+0xE1, 0x00, 0xE1, 0xCB, 0x61, 0xA9, 0xE2, 0xCB, 0x61, 0xA9, 0x00, 0x00, 0x91, 0x70, 0x83, 0x96, 
+0x03, 0x53, 0xB8, 0x00, 0x83, 0x52, 0x63, 0x48, 0xB0, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0x83, 0x96, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x63, 0x48, 0xDD, 0x80, 0x02, 0xF0, 
+0xC5, 0xE3, 0x8A, 0x95, 0x83, 0x96, 0xB0, 0x9C, 0xB1, 0x98, 0xAB, 0x29, 0xAE, 0x29, 0x00, 0xB0, 
+0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0xF3, 0x30, 
+0xEF, 0x45, 0x6F, 0xC8, 0xDC, 0x40, 0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2E, 0xE9, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0xFE, 0xF9, 0x01, 0x38, 0xEF, 0xC0, 
+0x6F, 0xC8, 0xDC, 0x40, 0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x50, 0x69, 0x83, 0x52, 0x1B, 0x92, 0x08, 0x40, 0x83, 0x52, 0x1B, 0xD6, 
+0x08, 0x40, 0xEA, 0x40, 0x6A, 0x98, 0xBC, 0x29, 0x25, 0x70, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC3, 0xE9, 0x2A, 0x70, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE6, 0x40, 0xE9, 0x40, 0x3F, 0x30, 0xE9, 0xC5, 0x88, 0x30, 
+0x83, 0x96, 0xB8, 0x00, 0x83, 0x52, 0x69, 0x48, 0x83, 0x96, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 
+0xDC, 0x40, 0x6A, 0x48, 0xDD, 0x80, 0x02, 0xF0, 0xC5, 0xE3, 0x8A, 0x95, 0x66, 0x48, 0xE2, 0x00, 
+0x06, 0x30, 0x03, 0xD0, 0xE2, 0x8C, 0xFF, 0x7E, 0x03, 0x9D, 0xD9, 0x29, 0x62, 0x08, 0xE9, 0x40, 
+0x03, 0x30, 0xE9, 0xC5, 0x6A, 0x98, 0x0A, 0x6A, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x69, 0x48, 0xE2, 0x00, 0x03, 0xD0, 0xE2, 0xCD, 
+0x03, 0xD0, 0xE2, 0xCD, 0x6F, 0xC8, 0xF3, 0xB9, 0x62, 0x04, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 
+0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x6A, 0x98, 0x29, 0xAA, 0x26, 0x70, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0x30, 0x6A, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xEF, 0xC0, 0x69, 0x48, 0xE2, 0x00, 0x06, 0x30, 0x03, 0xD0, 0xE2, 0xCD, 0xFF, 0x7E, 
+0x03, 0x9D, 0x15, 0xAA, 0x6F, 0xC8, 0x3F, 0xB9, 0x62, 0x04, 0xEF, 0xC0, 0x6F, 0xC8, 0xDC, 0x40, 
+0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x00, 0xEA, 0x2B, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xE9, 0x40, 0x07, 0x70, 0xE9, 0xC5, 0x06, 0x30, 0x69, 0x42, 0x03, 0x5C, 0x49, 0xAA, 0x8A, 0x70, 
+0x83, 0x96, 0xB8, 0x00, 0x6A, 0xB0, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x6A, 0x48, 
+0xDD, 0x80, 0x02, 0xF0, 0xC5, 0xE3, 0x8A, 0x95, 0x8B, 0xB0, 0x83, 0x96, 0xB8, 0x00, 0x04, 0xF0, 
+0x62, 0xAA, 0x69, 0x48, 0x05, 0xBA, 0x8A, 0x70, 0x03, 0x9D, 0x53, 0xEA, 0x83, 0x96, 0xB8, 0x00, 
+0x20, 0xF0, 0xB9, 0x40, 0x56, 0xEA, 0x83, 0x96, 0xB8, 0x00, 0xB9, 0x81, 0xB8, 0xB0, 0x83, 0x52, 
+0xDC, 0x40, 0x6A, 0x48, 0xDD, 0x80, 0x02, 0xF0, 0xC5, 0xE3, 0x8A, 0x95, 0x8B, 0xB0, 0x83, 0x96, 
+0xB8, 0x00, 0x05, 0x30, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x6A, 0x48, 0xDD, 0x80, 
+0x02, 0xF0, 0xC5, 0xE3, 0x8A, 0x95, 0x6A, 0x98, 0x85, 0xAA, 0x27, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE4, 0x00, 0x28, 0x30, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE9, 0x40, 0x29, 0x70, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0x9C, 0xEA, 0x2C, 0x70, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE4, 0x00, 0x2D, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE9, 0x40, 0x2E, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE7, 0x80, 0x69, 0x48, 0xE2, 0x00, 0x07, 0x70, 
+0x03, 0xD0, 0xE2, 0x8C, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 0xA1, 0xAA, 0x64, 0x8D, 0x62, 0x04, 
+0xE8, 0x00, 0x84, 0x30, 0x83, 0x96, 0xB8, 0x00, 0x83, 0x52, 0x68, 0x08, 0x83, 0x96, 0xB9, 0x40, 
+0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x6A, 0x48, 0xDD, 0x80, 0x02, 0xF0, 0xC5, 0xE3, 0x8A, 0x95, 
+0x67, 0x88, 0xE2, 0x00, 0x07, 0x70, 0x03, 0xD0, 0xE2, 0x8C, 0xFF, 0x7E, 0x03, 0xD0, 0x03, 0x9D, 
+0xBC, 0x2A, 0x69, 0xCD, 0x62, 0x04, 0xE8, 0x00, 0x85, 0x70, 0x83, 0x96, 0xB8, 0x00, 0x83, 0x52, 
+0x68, 0x08, 0x83, 0x96, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x6A, 0x48, 0xDD, 0x80, 
+0x02, 0xF0, 0xC5, 0xE3, 0x8A, 0x95, 0x03, 0xD0, 0x67, 0x0D, 0xE8, 0x00, 0x86, 0x70, 0x83, 0x96, 
+0xB8, 0x00, 0x83, 0x52, 0x68, 0x08, 0x83, 0x96, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 
+0x6A, 0x48, 0xDD, 0x80, 0x02, 0xF0, 0xC5, 0xE3, 0x8A, 0x95, 0x6A, 0x48, 0x2B, 0x7E, 0x84, 0x80, 
+0x83, 0x93, 0x80, 0x88, 0x03, 0x59, 0xF1, 0x2A, 0x6A, 0x48, 0x5A, 0x7E, 0x84, 0x80, 0x03, 0x30, 
+0xF5, 0x6A, 0x6A, 0x48, 0x5A, 0x7E, 0x84, 0x80, 0x01, 0xF0, 0x80, 0x40, 0x80, 0xF0, 0x83, 0x96, 
+0xB8, 0x00, 0x83, 0x52, 0x6A, 0x48, 0x5A, 0x7E, 0x84, 0x80, 0x00, 0x48, 0x04, 0x38, 0x83, 0x96, 
+0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x6A, 0x48, 0xDD, 0x80, 0x02, 0xF0, 0xC5, 0xE3, 
+0x8A, 0x95, 0x03, 0x30, 0xE3, 0x40, 0x7D, 0x30, 0xE2, 0x00, 0xE2, 0xCB, 0x0D, 0xEB, 0xE3, 0x0B, 
+0x0D, 0xEB, 0x83, 0x52, 0x03, 0x53, 0x6A, 0x48, 0x2B, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0x03, 0x9D, 0x43, 0xEB, 0x6A, 0xDC, 0x30, 0xAB, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0x12, 0x6F, 0xC8, 0xDC, 0x40, 0x00, 0xB0, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x43, 0xEB, 
+0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 
+0x6F, 0xD0, 0x6F, 0xC8, 0xDC, 0x40, 0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x05, 0x30, 0xE2, 0x00, 0xE2, 0xCB, 0x45, 0xEB, 0x83, 0x52, 
+0x03, 0x53, 0x6A, 0xDC, 0x63, 0x2B, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0xDF, 0xF9, 0x20, 0x38, 0xEF, 0xC0, 0x6F, 0xC8, 
+0xDC, 0x40, 0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0xE5, 0x81, 0x85, 0xEB, 0x00, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0xFD, 0xF9, 0x02, 0x38, 0xEF, 0xC0, 0x6F, 0xC8, 
+0xDC, 0x40, 0x00, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x61, 0xEB, 0xE4, 0xB0, 0xE2, 0x00, 0x7D, 0xAB, 0x7E, 0xAB, 0xE2, 0xCB, 0x7C, 0x6B, 
+0x81, 0xAB, 0x00, 0x00, 0x83, 0x52, 0x03, 0x53, 0xE5, 0xCA, 0x4F, 0x88, 0x65, 0x42, 0x03, 0x5C, 
+0x7A, 0x6B, 0x80, 0xF0, 0x83, 0x96, 0xB8, 0x00, 0x83, 0x52, 0x6A, 0x48, 0x5A, 0x7E, 0x84, 0x80, 
+0x83, 0x93, 0x00, 0x48, 0x0C, 0x78, 0x83, 0x96, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 
+0x6A, 0x48, 0xDD, 0x80, 0x02, 0xF0, 0xC5, 0xE3, 0x8A, 0x95, 0x04, 0xF0, 0xE3, 0x40, 0x1C, 0x70, 
+0xE2, 0x00, 0xE2, 0xCB, 0xA1, 0xEB, 0xE3, 0x0B, 0xA1, 0xEB, 0x00, 0x00, 0x11, 0x30, 0x83, 0x96, 
+0x03, 0x53, 0xB8, 0x00, 0x55, 0xB0, 0xB9, 0x40, 0xB8, 0xB0, 0x83, 0x52, 0xDC, 0x40, 0x6A, 0x48, 
+0xDD, 0x80, 0x02, 0xF0, 0xFE, 0xA3, 0x8A, 0x95, 0x6A, 0x48, 0xB0, 0x3E, 0x84, 0x80, 0x83, 0x96, 
+0x38, 0x08, 0x83, 0x93, 0x80, 0x40, 0x83, 0x52, 0x6A, 0x48, 0xB0, 0x3E, 0x84, 0x80, 0x00, 0xDC, 
+0xC3, 0x2B, 0x9B, 0xD2, 0x08, 0x40, 0x9B, 0x16, 0x08, 0x40, 0xDF, 0xC0, 0x5D, 0xD8, 0xE3, 0x6B, 
+0xE0, 0x01, 0x5F, 0xC8, 0x60, 0xC2, 0x03, 0x18, 0xD8, 0x2B, 0x60, 0xC8, 0x5C, 0xC7, 0xDE, 0x80, 
+0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x99, 0x00, 0x18, 0x14, 0x18, 0xD0, 0xE0, 0x4A, 0xC9, 0x2B, 
+0x18, 0x55, 0x18, 0x11, 0x83, 0x52, 0x03, 0x53, 0x11, 0x5C, 0x08, 0x40, 0x05, 0x30, 0xDE, 0x80, 
+0xDE, 0x4B, 0xE0, 0xEB, 0xDA, 0x6B, 0xE0, 0x01, 0x5F, 0xC8, 0x60, 0xC2, 0x03, 0x18, 0xF3, 0xAB, 
+0x60, 0xC8, 0x5C, 0xC7, 0xDE, 0x80, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x9A, 0x00, 0x98, 0x95, 
+0x98, 0x51, 0xE0, 0x4A, 0xE4, 0x2B, 0x98, 0x96, 0x98, 0x52, 0x83, 0x52, 0x03, 0x53, 0x91, 0x9C, 
+0x08, 0x40, 0x05, 0x30, 0xDE, 0x80, 0xDE, 0x4B, 0xFB, 0xEB, 0xF5, 0xAB, 0xDF, 0xC0, 0x10, 0xF0, 
+0x5F, 0xC2, 0x03, 0x5C, 0x05, 0x6C, 0x10, 0xF0, 0x06, 0x6C, 0x5F, 0xC8, 0xE0, 0xC0, 0x5D, 0xD8, 
+0x35, 0xEC, 0xE1, 0x41, 0x60, 0xC8, 0x61, 0x02, 0x03, 0x18, 0x19, 0xAC, 0x61, 0x08, 0x5C, 0xC7, 
+0xDE, 0x80, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x99, 0x00, 0x18, 0x14, 0x18, 0xD0, 0xE1, 0x8A, 
+0x0A, 0x6C, 0x18, 0x55, 0x18, 0x11, 0x83, 0x52, 0x03, 0x53, 0x11, 0x5C, 0x25, 0xAC, 0x2A, 0x70, 
+0xDE, 0x80, 0xDE, 0x4B, 0x21, 0x6C, 0x00, 0x00, 0x1B, 0xEC, 0xE1, 0x41, 0x60, 0xC8, 0x61, 0x02, 
+0x03, 0x18, 0x08, 0x40, 0x61, 0x08, 0x5C, 0xC7, 0xDE, 0x80, 0x84, 0x80, 0x0F, 0x48, 0x83, 0x93, 
+0x80, 0x40, 0x98, 0x54, 0x98, 0x10, 0xE1, 0x8A, 0x26, 0xAC, 0xE1, 0x41, 0x60, 0xC8, 0x61, 0x02, 
+0x03, 0x18, 0x45, 0xAC, 0x61, 0x08, 0x5C, 0xC7, 0xDE, 0x80, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0x9A, 0x00, 0x98, 0x95, 0x98, 0x51, 0xE1, 0x8A, 0x36, 0xEC, 0x98, 0x96, 0x98, 0x52, 0x83, 0x52, 
+0x03, 0x53, 0x91, 0x9C, 0x51, 0xAC, 0x2A, 0x70, 0xDE, 0x80, 0xDE, 0x4B, 0x4D, 0xEC, 0x00, 0x00, 
+0x47, 0xEC, 0xE1, 0x41, 0x60, 0xC8, 0x61, 0x02, 0x03, 0x18, 0x08, 0x40, 0x61, 0x08, 0x5C, 0xC7, 
+0xDE, 0x80, 0x84, 0x80, 0x10, 0x88, 0x83, 0x93, 0x80, 0x40, 0x18, 0x56, 0x18, 0x12, 0xE1, 0x8A, 
+0x52, 0xAC, 0x55, 0xB0, 0x9B, 0x40, 0xD7, 0xC1, 0x02, 0xF0, 0x57, 0x82, 0x03, 0x18, 0x79, 0x6D, 
+0x57, 0x88, 0x01, 0xBE, 0x9B, 0x40, 0x57, 0x88, 0x31, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 
+0x57, 0x88, 0x31, 0x3E, 0x84, 0x80, 0x80, 0x88, 0x03, 0x9D, 0x9C, 0xEC, 0x3C, 0xB0, 0xDC, 0x40, 
+0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x57, 0xD8, 0x8C, 0xAC, 
+0x57, 0x88, 0x31, 0x3E, 0x84, 0x80, 0x6F, 0xC8, 0xDE, 0x80, 0x07, 0x70, 0x03, 0xD0, 0xDE, 0x0C, 
+0xFF, 0x7E, 0x03, 0x9D, 0x86, 0xAC, 0x97, 0x2C, 0x57, 0x88, 0x31, 0x3E, 0x84, 0x80, 0x6F, 0xC8, 
+0xDE, 0x80, 0x05, 0x30, 0x03, 0xD0, 0xDE, 0x0C, 0xFF, 0x7E, 0x03, 0x9D, 0x92, 0xAC, 0x5E, 0x88, 
+0x01, 0x79, 0x83, 0x93, 0x80, 0x40, 0x70, 0xAC, 0x3D, 0xF0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0x03, 0x59, 0xA9, 0xEC, 0x6F, 0x4B, 
+0xC8, 0xAC, 0x57, 0x88, 0x2B, 0x7E, 0x84, 0x80, 0x6F, 0xC8, 0x83, 0x93, 0x80, 0x40, 0x57, 0x88, 
+0x2B, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xDC, 0x40, 0x1A, 0x70, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 
+0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3E, 0xF0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0x03, 0x9D, 0xDB, 0x6C, 0xF9, 0x6C, 
+0x57, 0x88, 0x2B, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x57, 0x88, 0x2B, 0x7E, 0x84, 0x80, 
+0x00, 0x48, 0xDC, 0x40, 0x1A, 0x70, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0xBC, 0x2C, 0x10, 0xF0, 0x6F, 0xC2, 0x03, 0x18, 0xF9, 0x6C, 0x57, 0x88, 
+0x29, 0x3E, 0x84, 0x80, 0x6F, 0xC8, 0x83, 0x93, 0x80, 0x40, 0x57, 0x88, 0x29, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x57, 0x88, 0xAC, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x80, 0xCA, 
+0x26, 0xED, 0x6F, 0xC8, 0xFF, 0x3A, 0x03, 0x9D, 0x0E, 0xED, 0x57, 0x88, 0x29, 0x3E, 0x84, 0x80, 
+0x07, 0x70, 0x83, 0x93, 0x80, 0x40, 0xFF, 0xB0, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x21, 0xAD, 0x57, 0x88, 0x29, 0x3E, 
+0x84, 0x80, 0x07, 0x70, 0x83, 0x93, 0x80, 0x40, 0x57, 0x88, 0x29, 0x3E, 0x84, 0x80, 0x00, 0x48, 
+0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x57, 0x88, 0xAC, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x3F, 0x30, 0xDC, 0x40, 
+0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x0A, 0x30, 0x6F, 0xC2, 
+0x03, 0x18, 0x4C, 0xED, 0x57, 0x88, 0x25, 0x3E, 0x84, 0x80, 0x6F, 0xC8, 0x83, 0x93, 0x80, 0x40, 
+0x57, 0x88, 0x25, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x57, 0x88, 0xA8, 0x3E, 0x84, 0x80, 
+0x83, 0x93, 0x80, 0x81, 0x80, 0xCA, 0x77, 0xAD, 0x6F, 0xC8, 0xFF, 0x3A, 0x03, 0x9D, 0x60, 0xAD, 
+0x57, 0x88, 0x25, 0x3E, 0x84, 0x80, 0xFF, 0xB0, 0x83, 0x93, 0x80, 0x81, 0xDC, 0x40, 0x1C, 0x70, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x72, 0x2D, 
+0x57, 0x88, 0x25, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x57, 0x88, 0x25, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x57, 0x88, 0xA8, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0xD7, 0x0A, 
+0x64, 0xAC, 0x03, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0x03, 0xBA, 0x03, 0x9D, 0x7B, 0xAD, 0x3E, 0xF0, 
+0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xB4, 0x00, 0x3F, 0x30, 
+0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xB6, 0x40, 0x34, 0x02, 
+0x03, 0x5C, 0xB7, 0xAD, 0x0A, 0x30, 0x34, 0x02, 0x03, 0x18, 0xB7, 0xAD, 0x34, 0x08, 0xDC, 0x40, 
+0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x36, 0x48, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x34, 0x08, 0xB3, 0x40, 0x36, 0x48, 0xB5, 0x40, 0xCD, 0x6D, 0x09, 0x30, 
+0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x1C, 0x70, 0xDC, 0x81, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x09, 0x30, 0xB3, 0x40, 0xB5, 0x81, 0x04, 0xF0, 0x9B, 0x40, 0x3C, 0xB0, 
+0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 
+0x04, 0x7A, 0x03, 0x9D, 0xCF, 0xAD, 0x3E, 0xF0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xB8, 0x00, 0x3F, 0x30, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xBA, 0x40, 0x38, 0x02, 0x03, 0x5C, 0x0A, 0xAE, 0x02, 0xF0, 0x3A, 0x42, 
+0x03, 0x5C, 0x0A, 0xAE, 0x38, 0x08, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 
+0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3A, 0x48, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x38, 0x08, 0xB7, 0x80, 
+0x3A, 0x48, 0x21, 0xAE, 0x23, 0x70, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 
+0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x10, 0xF0, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x23, 0x70, 0xB7, 0x80, 
+0x10, 0xF0, 0xB9, 0x40, 0x05, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0x05, 0xBA, 0x03, 0x9D, 0x24, 0xAE, 
+0x3E, 0xF0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC4, 0xC0, 
+0x3F, 0x30, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC6, 0x00, 
+0x44, 0xC2, 0x03, 0x5C, 0x62, 0xEE, 0x10, 0xF0, 0x44, 0xC2, 0x03, 0x18, 0x62, 0xEE, 0x46, 0x08, 
+0x03, 0x59, 0x62, 0xEE, 0x44, 0xC8, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 
+0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x46, 0x08, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x44, 0xC8, 0xC3, 0x00, 
+0x46, 0x08, 0x79, 0x6E, 0x0B, 0x70, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 
+0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x07, 0x70, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 
+0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x0B, 0x70, 0xC3, 0x00, 
+0x07, 0x70, 0xC5, 0x00, 0x06, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0x06, 0xBA, 0x03, 0x9D, 0x7C, 0x6E, 
+0x3D, 0xF0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xCA, 0x00, 
+0x3E, 0xF0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC8, 0xC0, 
+0x3F, 0x30, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xCC, 0x00, 
+0x48, 0xC8, 0x4A, 0x02, 0x03, 0x5C, 0xCF, 0xAE, 0x4C, 0x08, 0x48, 0xC2, 0x03, 0x5C, 0xCF, 0xAE, 
+0x4C, 0x08, 0x03, 0x59, 0xCF, 0xAE, 0x4A, 0x08, 0xDC, 0x40, 0x1A, 0x70, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x48, 0xC8, 0xDC, 0x40, 0x1B, 0xB0, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x4C, 0x08, 
+0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x4A, 0x08, 0xC9, 0x00, 0x48, 0xC8, 0xC7, 0x40, 0x4C, 0x08, 0xF2, 0x6E, 0x73, 0xF0, 
+0xDC, 0x40, 0x1A, 0x70, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x64, 0x70, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2D, 0xB0, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x73, 0xF0, 0xC9, 0x00, 0x64, 0x70, 
+0xC7, 0x40, 0x2D, 0xB0, 0xCB, 0x40, 0x07, 0x70, 0x9B, 0x40, 0x3C, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0x07, 0xFA, 0x03, 0x9D, 
+0xF5, 0xAE, 0x3E, 0xF0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xBC, 0x40, 0x3F, 0x30, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xBE, 0x80, 0x3C, 0x42, 0x03, 0x5C, 0x33, 0x6F, 0x10, 0xF0, 0x3C, 0x42, 0x03, 0x18, 0x33, 0x6F, 
+0x3E, 0x88, 0x03, 0x59, 0x33, 0x6F, 0x3C, 0x48, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3E, 0x88, 0xDC, 0x40, 0x1C, 0x70, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3C, 0x48, 
+0xBB, 0x80, 0x3E, 0x88, 0x4A, 0x2F, 0x0E, 0x70, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x04, 0xF0, 0xDC, 0x40, 0x1C, 0x70, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x0E, 0x70, 
+0xBB, 0x80, 0x04, 0xF0, 0xBD, 0x80, 0x08, 0xF0, 0x9B, 0x40, 0x3C, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0x08, 0x7A, 0x03, 0x9D, 
+0x4D, 0x6F, 0x3E, 0xF0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xC0, 0x80, 0x3F, 0x30, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xC2, 0xC0, 0x40, 0x88, 0x42, 0xC2, 0x03, 0x18, 0x89, 0x2F, 0x02, 0xF0, 0x42, 0xC2, 0x03, 0x5C, 
+0x89, 0x2F, 0x40, 0x88, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x42, 0xC8, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x40, 0x88, 0xBF, 0xC0, 0x42, 0xC8, 
+0xA0, 0xEF, 0x84, 0x30, 0xDC, 0x40, 0x1B, 0xB0, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x34, 0x70, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x84, 0x30, 0xBF, 0xC0, 0x34, 0x70, 
+0xC1, 0xC0, 0x09, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0x0A, 0xBA, 0x03, 0x9D, 0xA3, 0x6F, 0x3F, 0x30, 
+0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xCF, 0x80, 0xDC, 0x40, 
+0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x0B, 0x70, 0x9B, 0x40, 0x3C, 0xB0, 0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 0x0B, 0xFA, 0x03, 0x9D, 0xC2, 0x2F, 0x3F, 0x30, 0xDC, 0x40, 
+0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xCD, 0x40, 0x4D, 0x48, 0x03, 0x59, 
+0xDB, 0xEF, 0x4D, 0xCB, 0xF4, 0xAF, 0x4D, 0x48, 0xDC, 0x40, 0x1C, 0x70, 0xDD, 0x80, 0x5C, 0x48, 
+0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x0F, 0xB0, 0x9B, 0x40, 0x3C, 0xB0, 
+0xDC, 0x40, 0x5C, 0x48, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xEF, 0xC0, 0x6F, 0xC8, 
+0x0F, 0x3A, 0x03, 0x59, 0x08, 0x40, 0xE7, 0xEF, 0xCD, 0x81, 0x4D, 0x48, 0xDC, 0x40, 0x1C, 0x70, 
+0xDD, 0x80, 0x5C, 0x48, 0x96, 0x00, 0x5D, 0x88, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xE5, 0xAF 
+ }; 
+ 

+ 515 - 0
sx1302/source/arb_fw.var

@@ -0,0 +1,515 @@
+static uint8_t arb_firmware[8192] = { 
+0x8A, 0x51, 0xE9, 0xAF, 0x00, 0xB0, 0x8A, 0xC0, 0x04, 0x88, 0x84, 0x0A, 0x82, 0x47, 0x00, 0xF4, 
+0x01, 0x34, 0x02, 0x34, 0x04, 0x34, 0x08, 0x34, 0x10, 0x34, 0x20, 0x34, 0x40, 0x34, 0x80, 0x34, 
+0x01, 0x34, 0x02, 0x34, 0x04, 0x34, 0x08, 0x34, 0x10, 0x34, 0x20, 0x34, 0x40, 0x34, 0x80, 0x34, 
+0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF4, 0x01, 0x34, 0x03, 0x74, 0x07, 0xB4, 
+0x0F, 0xF4, 0x1F, 0x34, 0x3F, 0x74, 0x7F, 0xB4, 0xFF, 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, 0x64, 0xC0, 
+0x80, 0x81, 0x84, 0x0A, 0x04, 0xC6, 0x03, 0x59, 0x00, 0xF4, 0x04, 0xC6, 0x08, 0x2C, 0x95, 0x41, 
+0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, 0x9E, 0x81, 
+0xDC, 0x81, 0x10, 0xF0, 0x5C, 0x42, 0x03, 0x18, 0x38, 0xAC, 0x5C, 0x48, 0x22, 0xFE, 0x84, 0x80, 
+0x80, 0x81, 0x5C, 0x48, 0xB0, 0x3E, 0x84, 0x80, 0x80, 0x81, 0x5C, 0x48, 0xD0, 0x3E, 0x84, 0x80, 
+0x80, 0x81, 0x5C, 0x48, 0xA0, 0xFE, 0x84, 0x80, 0x80, 0x81, 0x5C, 0x48, 0xC0, 0xFE, 0x84, 0x80, 
+0x80, 0x81, 0x5C, 0x48, 0xE0, 0x3E, 0x84, 0x80, 0xFF, 0xB0, 0x80, 0x40, 0xDC, 0xCA, 0x19, 0xAC, 
+0xC6, 0x41, 0xC7, 0x81, 0xC9, 0x41, 0xC4, 0x01, 0xC8, 0x01, 0x6F, 0xD0, 0xEF, 0x10, 0xA1, 0x01, 
+0xDC, 0x81, 0x40, 0xF0, 0x5C, 0x42, 0x03, 0x18, 0x4D, 0xEC, 0x5C, 0x48, 0xA0, 0xFE, 0x84, 0x80, 
+0xFF, 0xB0, 0x83, 0xD7, 0x80, 0x40, 0xDC, 0xCA, 0x41, 0x6C, 0xC5, 0x41, 0x08, 0xF0, 0x45, 0x02, 
+0x03, 0x18, 0x08, 0x40, 0x45, 0x08, 0x3A, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, 0x45, 0x08, 
+0x32, 0x3E, 0x84, 0x80, 0x80, 0x81, 0xC5, 0x8A, 0x4E, 0xEC, 0x02, 0xF0, 0xA0, 0x80, 0x8A, 0x51, 
+0x0F, 0xA4, 0x8A, 0x51, 0x03, 0x30, 0x9E, 0x40, 0x02, 0xF0, 0x9E, 0x40, 0x01, 0xF0, 0x9E, 0x40, 
+0x9E, 0x81, 0x9B, 0x81, 0x02, 0xF0, 0xE1, 0x00, 0x01, 0xF0, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 
+0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2A, 0x70, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 
+0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xDF, 0xC0, 0x5F, 0xC8, 0xF7, 0xFA, 
+0x03, 0x9D, 0x84, 0x6C, 0xEE, 0xC1, 0x86, 0xAC, 0xEE, 0xC1, 0xEE, 0x0A, 0x6E, 0x88, 0x03, 0x59, 
+0xCC, 0xEC, 0x01, 0xF0, 0x9B, 0x40, 0x29, 0x70, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xDF, 0xC0, 0x5F, 0x4B, 0x8B, 0xEC, 0x28, 0x30, 
+0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xCA, 0x00, 0x0D, 0x70, 0x4A, 0x02, 0x03, 0x18, 0xAC, 0xEC, 0x05, 0x30, 0x4A, 0x02, 0xD5, 0x81, 
+0x03, 0x5C, 0xAD, 0x2C, 0xD5, 0xCA, 0xAD, 0x2C, 0xD5, 0x81, 0x2A, 0x70, 0x83, 0x52, 0x03, 0x53, 
+0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD6, 0x40, 0x10, 0xF0, 
+0x56, 0x42, 0x03, 0x5C, 0xBD, 0x6C, 0x10, 0xF0, 0xD6, 0x40, 0xF0, 0xB0, 0xD6, 0x0E, 0xD6, 0xC5, 
+0x2B, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xE0, 0xC0, 0x9B, 0x81, 0xD5, 0x2C, 0x07, 0x70, 0xD5, 0x81, 0xD5, 0xCA, 0xCA, 0x00, 
+0x30, 0x30, 0xD6, 0x40, 0xE0, 0x01, 0x01, 0xF0, 0x9B, 0x40, 0x0E, 0x58, 0xD5, 0x2C, 0x25, 0x70, 
+0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xD7, 0x80, 0x07, 0x70, 0xD7, 0x05, 0x57, 0x88, 0xC5, 0x00, 0x08, 0xF0, 0x45, 0x02, 0x03, 0x18, 
+0xD5, 0x2C, 0x45, 0x08, 0x8A, 0x51, 0xF1, 0xE4, 0x8A, 0x51, 0x0E, 0x58, 0xD5, 0x2C, 0xC5, 0x8A, 
+0xE5, 0x2C, 0xED, 0x80, 0xE1, 0x00, 0x00, 0xB0, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x8E, 0xDC, 0x08, 0x40, 0x18, 0x14, 0x05, 0x30, 0xE8, 0x00, 
+0xE8, 0xCB, 0x00, 0x2D, 0x21, 0x30, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC6, 0x00, 0x22, 0x30, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 
+0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC7, 0x40, 0x24, 0x30, 0x83, 0x52, 
+0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC9, 0x00, 
+0x20, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xC4, 0xC0, 0x23, 0x70, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC8, 0xC0, 0x18, 0xD0, 0x55, 0xCB, 0x40, 0x6D, 0x48, 0xC8, 
+0xE8, 0x00, 0xE9, 0x81, 0xE8, 0x1B, 0xE9, 0xC3, 0x4A, 0x46, 0x69, 0x44, 0x03, 0x59, 0x4A, 0xED, 
+0x0A, 0x30, 0x49, 0x02, 0x03, 0x5C, 0x77, 0xAD, 0x44, 0xC8, 0x80, 0x7A, 0x78, 0x7E, 0x03, 0x5C, 
+0x6B, 0x6D, 0x77, 0xAD, 0x44, 0xC8, 0x80, 0x7A, 0x78, 0x7E, 0x03, 0x5C, 0xC4, 0xDB, 0x40, 0x6D, 
+0x44, 0xC8, 0x3A, 0x7E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x01, 0xBE, 0xE8, 0x00, 0x44, 0xC8, 
+0x3A, 0x7E, 0x84, 0x80, 0x68, 0x08, 0x80, 0x40, 0x44, 0xC8, 0x3A, 0x7E, 0x84, 0x80, 0x00, 0x48, 
+0xE1, 0x00, 0x44, 0xC8, 0x01, 0xBE, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x40, 0x6D, 0xC4, 0xDB, 0x77, 0xAD, 0x48, 0xC8, 0x80, 0x7A, 0x73, 0xBE, 
+0x03, 0x18, 0x77, 0xAD, 0x48, 0xC8, 0x80, 0x7A, 0x7B, 0xFE, 0x03, 0x18, 0x79, 0x6D, 0x6F, 0x55, 
+0x1A, 0xEE, 0x6F, 0x11, 0x48, 0xC8, 0x11, 0xFE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 
+0xC7, 0xC5, 0x48, 0xC8, 0xE8, 0x00, 0x03, 0xD0, 0xE8, 0xCD, 0x03, 0xD0, 0xE8, 0xCD, 0x03, 0xD0, 
+0xE8, 0xCD, 0x44, 0xC8, 0x68, 0x87, 0xD8, 0x7E, 0xDE, 0x80, 0xA0, 0xFE, 0x84, 0x80, 0x83, 0xD7, 
+0x00, 0x48, 0xDC, 0x40, 0x3E, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC2, 0xC0, 0x3F, 0x30, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 
+0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC3, 0x00, 0x6F, 0x11, 0xDC, 0x81, 
+0x08, 0xF0, 0x5C, 0x42, 0x03, 0x18, 0xDF, 0xED, 0x5C, 0x48, 0xE0, 0x3E, 0x84, 0x80, 0x83, 0x93, 
+0x00, 0x48, 0x5E, 0xC6, 0x03, 0x9D, 0xDB, 0xAD, 0x5C, 0x48, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 
+0x02, 0xA0, 0x8A, 0x51, 0x42, 0x05, 0x03, 0x59, 0xDB, 0xAD, 0x46, 0x08, 0xE1, 0x00, 0x5C, 0x48, 
+0xB0, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xE2, 0x00, 0x5C, 0x48, 0x22, 0xFE, 0x84, 0x80, 0x00, 0x48, 
+0xE3, 0x40, 0x56, 0x48, 0xE4, 0x00, 0x48, 0xC8, 0xE5, 0x40, 0x47, 0x48, 0x52, 0xE7, 0x8A, 0x51, 
+0xE8, 0x00, 0x68, 0x4C, 0x03, 0x5C, 0xD8, 0x2D, 0x83, 0x52, 0x03, 0x53, 0x6F, 0x55, 0xDB, 0xAD, 
+0x83, 0x52, 0x03, 0x53, 0x6F, 0x11, 0x6F, 0x59, 0xDF, 0xED, 0xDC, 0xCA, 0xA8, 0xED, 0x6F, 0x59, 
+0x1A, 0xEE, 0x08, 0xF0, 0xDC, 0x40, 0x10, 0xF0, 0x5C, 0x42, 0x03, 0x18, 0x1A, 0xEE, 0x5C, 0x48, 
+0xE0, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x5E, 0xC6, 0x03, 0x9D, 0x16, 0xEE, 0x5C, 0x48, 
+0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0x43, 0x45, 0x03, 0x59, 0x16, 0xEE, 
+0x46, 0x08, 0xE1, 0x00, 0x5C, 0x48, 0xB0, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xE2, 0x00, 0x5C, 0x48, 
+0x22, 0xFE, 0x84, 0x80, 0x00, 0x48, 0xE3, 0x40, 0x56, 0x48, 0xE4, 0x00, 0x48, 0xC8, 0xE5, 0x40, 
+0x47, 0x48, 0x52, 0xE7, 0x8A, 0x51, 0xE8, 0x00, 0x68, 0x4C, 0x03, 0x5C, 0x13, 0xEE, 0x83, 0x52, 
+0x03, 0x53, 0x6F, 0x55, 0x16, 0xEE, 0x83, 0x52, 0x03, 0x53, 0x6F, 0x11, 0x6F, 0x59, 0x1A, 0xEE, 
+0xDC, 0xCA, 0xE3, 0x6D, 0x6F, 0x59, 0x08, 0x40, 0x48, 0xC8, 0xFB, 0x3E, 0xE8, 0x00, 0x01, 0xF0, 
+0xE8, 0x8A, 0xE9, 0x40, 0x00, 0xB0, 0xEA, 0x40, 0x28, 0xAE, 0x03, 0xD0, 0xE9, 0x0D, 0xEA, 0x0D, 
+0xE8, 0xCB, 0x25, 0xEE, 0x60, 0xC8, 0x69, 0x85, 0xEB, 0x80, 0xEC, 0x81, 0xE0, 0xDB, 0xEC, 0xC3, 
+0x83, 0x52, 0x03, 0x53, 0x6A, 0x48, 0xEC, 0xC5, 0x6C, 0x48, 0x6B, 0x84, 0x03, 0x9D, 0x3B, 0x6E, 
+0xDD, 0xC1, 0xDD, 0x0A, 0x3D, 0x6E, 0x02, 0xF0, 0xDD, 0x80, 0xDB, 0xC1, 0x5D, 0x88, 0x5B, 0x82, 
+0x03, 0x18, 0x08, 0x40, 0x11, 0x30, 0xDC, 0x40, 0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xE1, 0x00, 
+0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD8, 0x00, 0x3D, 0xF0, 0x83, 0x52, 
+0x03, 0x53, 0xE1, 0x00, 0x61, 0x08, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD9, 0x40, 
+0x48, 0xC8, 0x80, 0x7A, 0x75, 0xBE, 0x03, 0x5C, 0x65, 0x2E, 0x58, 0x08, 0x80, 0x7A, 0x70, 0x3E, 
+0x03, 0x5C, 0xD8, 0x1B, 0x75, 0x6E, 0x58, 0x08, 0x6C, 0x2E, 0x59, 0x48, 0x80, 0x7A, 0x70, 0x3E, 
+0x03, 0x5C, 0xD9, 0x5B, 0x6E, 0x6E, 0x59, 0x48, 0xDC, 0x40, 0x75, 0x6E, 0x58, 0x08, 0x80, 0x7A, 
+0x70, 0x3E, 0x03, 0x18, 0x75, 0x6E, 0xD8, 0x5F, 0x63, 0x2E, 0x10, 0xF0, 0x5C, 0x42, 0x03, 0x18, 
+0x50, 0xEF, 0x5C, 0x48, 0x22, 0xFE, 0x84, 0x80, 0x46, 0x08, 0x83, 0x93, 0x80, 0x40, 0x5C, 0x48, 
+0xB0, 0x3E, 0x84, 0x80, 0x47, 0x48, 0x80, 0x40, 0x5C, 0x48, 0xD0, 0x3E, 0x84, 0x80, 0x49, 0x08, 
+0x80, 0x40, 0x5C, 0x48, 0xA0, 0xFE, 0x84, 0x80, 0x44, 0xC8, 0x80, 0x40, 0x5C, 0x48, 0xC0, 0xFE, 
+0x84, 0x80, 0x48, 0xC8, 0x80, 0x40, 0x5C, 0x48, 0xE0, 0x3E, 0x84, 0x80, 0x5E, 0x88, 0x80, 0x40, 
+0x5E, 0x88, 0xA0, 0xFE, 0x84, 0x80, 0x5C, 0x48, 0x83, 0xD7, 0x80, 0x40, 0x48, 0xC8, 0xE1, 0x00, 
+0x17, 0xB0, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x44, 0xC8, 0xE1, 0x00, 0x18, 0x30, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x46, 0x08, 0xE1, 0x00, 0x19, 0x70, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 
+0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x47, 0x48, 0xE1, 0x00, 0x1A, 0x70, 0xE2, 0x00, 
+0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x5C, 0x48, 0xE1, 0x00, 
+0x16, 0x70, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x49, 0x08, 0xE1, 0x00, 0x1B, 0xB0, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x5B, 0x88, 0xE1, 0x00, 0x11, 0x30, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 
+0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x08, 0xF0, 0x5C, 0x42, 0x5C, 0x48, 0x03, 0x18, 
+0x12, 0xEF, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xE1, 0x00, 0x12, 0x30, 
+0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x05, 0x30, 
+0xE8, 0x00, 0xE8, 0xCB, 0xF9, 0xAE, 0x83, 0x52, 0x12, 0x30, 0x03, 0x53, 0xE1, 0x41, 0xE2, 0x00, 
+0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x55, 0xCB, 0x50, 0xEF, 
+0x48, 0xC8, 0xE8, 0x00, 0xE9, 0x81, 0xE8, 0x1B, 0xE9, 0xC3, 0x4A, 0x46, 0x69, 0x44, 0x03, 0x59, 
+0x30, 0xEF, 0x50, 0xEF, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xE1, 0x00, 
+0x13, 0x70, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x05, 0x30, 0xE8, 0x00, 0xE8, 0xCB, 0x22, 0xEF, 0x83, 0x52, 0x13, 0x70, 0x03, 0x53, 0xE1, 0x41, 
+0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x06, 0xEF, 
+0x44, 0xC8, 0x80, 0x7A, 0x78, 0x7E, 0x03, 0x5C, 0xC4, 0xDB, 0x50, 0xEF, 0x44, 0xC8, 0x32, 0x3E, 
+0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x01, 0xBE, 0xE8, 0x00, 0x44, 0xC8, 0x32, 0x3E, 0x84, 0x80, 
+0x68, 0x08, 0x80, 0x40, 0x44, 0xC8, 0x32, 0x3E, 0x84, 0x80, 0x00, 0x48, 0xE1, 0x00, 0x44, 0xC8, 
+0x09, 0xFE, 0xE2, 0x00, 0x61, 0x08, 0x96, 0x00, 0x62, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0xDB, 0x0A, 0x3E, 0x6E, 0xE7, 0x80, 0x62, 0x02, 0x62, 0x08, 0x03, 0x18, 0x9D, 0xAF, 0x67, 0x82, 
+0xD0, 0xC0, 0x63, 0x48, 0x61, 0x02, 0x03, 0x5C, 0x61, 0x2F, 0x63, 0x48, 0x61, 0x02, 0xCC, 0x00, 
+0x68, 0x2F, 0x61, 0x08, 0x63, 0x42, 0xCC, 0x00, 0xFF, 0xB0, 0xD0, 0x87, 0xCC, 0x86, 0xCC, 0x8A, 
+0x65, 0x48, 0x11, 0xFE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xE6, 0x40, 0x67, 0x88, 
+0x66, 0x42, 0xD2, 0x00, 0x61, 0x49, 0xCE, 0x40, 0x62, 0x08, 0x52, 0x87, 0xD1, 0x00, 0x4E, 0x89, 
+0xE6, 0x40, 0x63, 0x48, 0x66, 0x42, 0x03, 0x5C, 0x80, 0xAF, 0x63, 0x48, 0x4E, 0xC7, 0x84, 0xEF, 
+0xD1, 0x8A, 0x4E, 0x89, 0xCD, 0x40, 0x63, 0x42, 0xCD, 0x40, 0x50, 0xC8, 0x51, 0x02, 0x03, 0x5C, 
+0xD3, 0xAF, 0x51, 0x08, 0x50, 0xC2, 0x03, 0x5C, 0x91, 0x2F, 0x4D, 0x48, 0x4C, 0x02, 0x03, 0x18, 
+0xD3, 0xAF, 0xDA, 0x81, 0x5A, 0x48, 0x03, 0x59, 0x99, 0x6F, 0x51, 0x08, 0xCF, 0x80, 0x4D, 0x48, 
+0xE0, 0x2F, 0x50, 0xC8, 0xCF, 0x80, 0x4C, 0x08, 0xE0, 0x2F, 0x67, 0x82, 0x03, 0x18, 0xD6, 0xAF, 
+0x67, 0x88, 0x62, 0x02, 0xD0, 0xC0, 0x61, 0x08, 0x63, 0x42, 0x03, 0x5C, 0xAB, 0xAF, 0x61, 0x08, 
+0x63, 0x42, 0xCC, 0x00, 0xB2, 0x6F, 0x63, 0x48, 0x61, 0x02, 0xCC, 0x00, 0xFF, 0xB0, 0xD0, 0x87, 
+0xCC, 0x86, 0xCC, 0x8A, 0x65, 0x48, 0x11, 0xFE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 
+0xE6, 0x40, 0x62, 0x08, 0x66, 0x42, 0xD2, 0x00, 0x63, 0x89, 0xCE, 0x40, 0x67, 0x88, 0x52, 0x87, 
+0xD1, 0x00, 0x4E, 0x89, 0xE6, 0x40, 0x61, 0x08, 0x66, 0x42, 0x03, 0x5C, 0xCA, 0x6F, 0x61, 0x08, 
+0x4E, 0xC7, 0xCE, 0xAF, 0xD1, 0x8A, 0x4E, 0x89, 0xCD, 0x40, 0x61, 0x02, 0xCD, 0x40, 0x50, 0xC8, 
+0x51, 0x02, 0x03, 0x18, 0x89, 0x2F, 0xDA, 0x81, 0xDA, 0xCA, 0x92, 0x2F, 0xCF, 0xC1, 0x63, 0x48, 
+0x61, 0x02, 0x03, 0x5C, 0xDE, 0xEF, 0x63, 0x48, 0x61, 0x02, 0xE0, 0x2F, 0x61, 0x08, 0x63, 0x42, 
+0xCB, 0x40, 0xCF, 0xC8, 0x03, 0x9D, 0x00, 0xF4, 0x64, 0x08, 0x4B, 0x42, 0x03, 0x5C, 0x01, 0x34, 
+0x00, 0xF4, 0xEF, 0x01, 0x83, 0x93, 0x22, 0x30, 0x84, 0x80, 0x61, 0x70, 0x8A, 0x51, 0x07, 0x64, 
+0x8A, 0x51, 0xA0, 0x30, 0x84, 0x80, 0xF0, 0xB0, 0x8A, 0x51, 0x07, 0x64, 0x8A, 0x51, 0x83, 0xD7, 
+0xA0, 0x30, 0x84, 0x80, 0xE0, 0x70, 0x8A, 0x51, 0x07, 0x64, 0x83, 0x01, 0x8A, 0x51, 0x5D, 0x2C, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF 
+ }; 
+ 

+ 515 - 0
sx1302/source/cal_fw.var

@@ -0,0 +1,515 @@
+static uint8_t cal_firmware_sx125x[8192] = { 
+0x8A, 0x51, 0xF0, 0x6F, 0x00, 0xB0, 0x8A, 0xC0, 0x04, 0x88, 0x84, 0x0A, 0x82, 0x47, 0x00, 0xF4, 
+0x40, 0x34, 0x2B, 0xF4, 0x1C, 0xB4, 0x13, 0xB4, 0x0D, 0xB4, 0x08, 0x34, 0x06, 0x74, 0x04, 0x34, 
+0x02, 0x34, 0x10, 0x34, 0x0B, 0xB4, 0x07, 0xB4, 0x05, 0x74, 0x03, 0x74, 0x02, 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, 0x64, 0xC0, 
+0x80, 0x81, 0x84, 0x0A, 0x04, 0xC6, 0x03, 0x59, 0x00, 0xF4, 0x04, 0xC6, 0x30, 0x69, 0xB1, 0x00, 
+0x04, 0xF0, 0xA2, 0xC0, 0x10, 0xF0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x2A, 0x08, 0xA2, 0xC0, 0x14, 0x30, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2B, 0x48, 0xA2, 0xC0, 0x15, 0x70, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2C, 0x08, 0xA2, 0xC0, 
+0x11, 0x30, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x2D, 0x48, 0xA2, 0xC0, 0x12, 0x30, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x29, 0x08, 0xA2, 0xC0, 0x13, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x31, 0x58, 0xB5, 0x29, 0x2E, 0x48, 0xB0, 0xC0, 
+0x01, 0xF0, 0xD7, 0xA7, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC3, 0x39, 0x30, 0xC4, 0xA2, 0xC0, 0x01, 0xF0, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 0x83, 0x52, 
+0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD3, 0x67, 
+0x8A, 0x51, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x01, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xA2, 0xC0, 0x01, 0xF0, 0xA2, 0x10, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xB4, 0x41, 0x1B, 0xEA, 0x2E, 0x48, 0xB0, 0xC0, 0x02, 0xF0, 
+0xD7, 0xA7, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xC3, 0x39, 0x30, 0xC4, 0xA2, 0xC0, 0x02, 0xF0, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x02, 0xF0, 0x83, 0x52, 0x03, 0x53, 
+0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xCF, 0xA7, 0x8A, 0x51, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x02, 0xF0, 
+0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xA2, 0xC0, 0x02, 0xF0, 0xA2, 0x10, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0xB3, 0x29, 0x2F, 0x88, 0xA4, 0xC0, 0x32, 0x70, 0x2D, 0x27, 0x8A, 0x51, 
+0x32, 0x08, 0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x33, 0x48, 0xA2, 0xC0, 0x1C, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x07, 0x70, 0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 
+0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xB4, 0x00, 
+0x06, 0xBA, 0x03, 0x59, 0x0E, 0xAA, 0x34, 0x08, 0x07, 0xFA, 0x03, 0x59, 0x2F, 0x2A, 0x06, 0x30, 
+0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xB4, 0x00, 0x06, 0xBA, 0x03, 0x59, 0xF3, 0x69, 0x21, 0x6A, 0x10, 0xF0, 
+0xA2, 0x01, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x08, 0x40, 0xB3, 0x40, 0x04, 0xF0, 0xA2, 0xC0, 0x10, 0xF0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2D, 0x48, 0xA2, 0xC0, 0x14, 0x30, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2E, 0x48, 0xA2, 0xC0, 
+0x15, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x2C, 0x08, 0xA2, 0xC0, 0x13, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x30, 0xC8, 0x20, 0x38, 0xD5, 0x40, 0xA2, 0xC0, 0x18, 0x30, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 0xB9, 0x81, 
+0xC2, 0x01, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xFF, 0x3A, 0x01, 0xBE, 0xBA, 0x40, 
+0x01, 0xF0, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xFF, 0x3A, 0x01, 0xBE, 0xC3, 0x00, 
+0x01, 0xF0, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xFF, 0x3A, 0x01, 0xBE, 0xBB, 0x80, 
+0x01, 0xF0, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xC4, 0xC0, 0x01, 0xF0, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xBC, 0x40, 0x01, 0xF0, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 
+0x8A, 0x51, 0xFF, 0x3A, 0x01, 0xBE, 0xC5, 0x00, 0x01, 0xF0, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 
+0x8A, 0x51, 0xBD, 0x80, 0x01, 0xF0, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xC6, 0x00, 
+0x0B, 0x70, 0xD7, 0x80, 0x57, 0x88, 0xB4, 0x00, 0x33, 0x98, 0x06, 0xAB, 0x57, 0x88, 0xB1, 0x00, 
+0x01, 0xF0, 0xE1, 0x27, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC3, 0x39, 0x31, 0x04, 0xA2, 0xC0, 0x01, 0xF0, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 0x83, 0x52, 
+0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD3, 0x67, 
+0x8A, 0x51, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x01, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xA2, 0xC0, 0x01, 0xF0, 0xA2, 0x10, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x39, 0x48, 0xA2, 0xC0, 0x11, 0x30, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x42, 0xC8, 0xA2, 0xC0, 0x12, 0x30, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x30, 0xC8, 
+0xA4, 0xC0, 0x4B, 0xB0, 0x2D, 0x27, 0x8A, 0x51, 0xD6, 0x81, 0x69, 0x2B, 0x57, 0x88, 0xB1, 0x00, 
+0x02, 0xF0, 0xE1, 0x27, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC3, 0x39, 0x31, 0x04, 0xA2, 0xC0, 0x02, 0xF0, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x02, 0xF0, 0x83, 0x52, 
+0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xCF, 0xA7, 
+0x8A, 0x51, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x02, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xA2, 0xC0, 0x02, 0xF0, 0xA2, 0x10, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xEB, 0x6A, 0x56, 0x48, 0xCA, 0x27, 0x8A, 0x51, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xB1, 0x27, 0x8A, 0x51, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x30, 0xC8, 
+0xA4, 0xC0, 0x51, 0x70, 0x2D, 0x27, 0x8A, 0x51, 0x4B, 0xB0, 0xA1, 0xC0, 0x51, 0x70, 0x79, 0x67, 
+0x8A, 0x51, 0xCD, 0x40, 0x4D, 0x48, 0x03, 0x59, 0x69, 0x2B, 0x51, 0x08, 0xCB, 0x40, 0x52, 0x08, 
+0xCC, 0x00, 0x05, 0x30, 0xD6, 0xCA, 0x56, 0x42, 0x03, 0x5C, 0x44, 0xAB, 0x2F, 0x88, 0xD1, 0x00, 
+0x51, 0x70, 0xD2, 0x41, 0xA1, 0xC0, 0x4B, 0xB0, 0x79, 0x67, 0x8A, 0x51, 0xCD, 0x40, 0x4D, 0x48, 
+0x03, 0x9D, 0x7F, 0xEB, 0x07, 0x70, 0xD7, 0x03, 0x57, 0x82, 0x03, 0x18, 0xAA, 0xEA, 0x4B, 0x48, 
+0xB7, 0x80, 0x4C, 0x08, 0xB8, 0x00, 0xD3, 0x81, 0xD4, 0x41, 0xD7, 0xC1, 0x53, 0x48, 0xB9, 0x40, 
+0x54, 0x08, 0xC2, 0xC0, 0x57, 0x88, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 
+0xA1, 0xC0, 0x53, 0x48, 0xDD, 0x66, 0x83, 0x52, 0x03, 0x53, 0xBA, 0x40, 0x57, 0x88, 0x01, 0xBE, 
+0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xA1, 0xC0, 0x54, 0x08, 0xDD, 0x66, 0x83, 0x52, 
+0x03, 0x53, 0xC3, 0x00, 0x57, 0x88, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 
+0xA1, 0xC0, 0x53, 0x48, 0xDD, 0x66, 0x83, 0x52, 0x03, 0x53, 0xBB, 0x80, 0x57, 0x88, 0x01, 0xBE, 
+0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xEB, 0xA7, 0x8A, 0x51, 0xDD, 0x66, 0x83, 0x52, 
+0x03, 0x53, 0xC4, 0xC0, 0x57, 0x88, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 
+0xDC, 0x67, 0x8A, 0x51, 0xDD, 0x66, 0x83, 0x52, 0x03, 0x53, 0xBC, 0x40, 0x57, 0x88, 0x01, 0xBE, 
+0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xA1, 0xC0, 0x54, 0x08, 0xDD, 0x66, 0x83, 0x52, 
+0x03, 0x53, 0xC5, 0x00, 0x57, 0x88, 0x01, 0xBE, 0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 
+0xDC, 0x67, 0x8A, 0x51, 0xDD, 0x66, 0x83, 0x52, 0x03, 0x53, 0xBD, 0x80, 0x57, 0x88, 0x01, 0xBE, 
+0x84, 0x80, 0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x51, 0xEB, 0xA7, 0x8A, 0x51, 0xDD, 0x66, 0x8A, 0x51, 
+0x83, 0x52, 0x03, 0x53, 0xC6, 0x00, 0x39, 0x48, 0xA2, 0xC0, 0x11, 0x30, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x42, 0xC8, 0xA2, 0xC0, 0x12, 0x30, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x30, 0xC8, 
+0xA4, 0xC0, 0x4F, 0xF0, 0x2D, 0x27, 0x8A, 0x51, 0x05, 0x30, 0xCE, 0x81, 0xA1, 0xC0, 0x57, 0x88, 
+0x96, 0x27, 0x8A, 0x51, 0xA0, 0xFE, 0x84, 0x80, 0x4F, 0x88, 0xE6, 0x67, 0x8A, 0x51, 0x96, 0x27, 
+0x8A, 0x51, 0xA0, 0xFE, 0x84, 0x80, 0x50, 0xC8, 0x83, 0xD7, 0x80, 0x40, 0xD6, 0x81, 0x05, 0x30, 
+0xD6, 0xCA, 0x56, 0x42, 0x03, 0x18, 0x5A, 0xEC, 0x56, 0x48, 0x39, 0x7E, 0x84, 0x80, 0x83, 0x93, 
+0x00, 0x48, 0xA2, 0xC0, 0x11, 0x30, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0xB1, 0x27, 0x8A, 0x51, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x30, 0xC8, 0xA4, 0xC0, 0x51, 0x70, 0x2D, 0x27, 0x8A, 0x51, 
+0x51, 0x70, 0xA1, 0xC0, 0x4F, 0xF0, 0x79, 0x67, 0x8A, 0x51, 0xCD, 0x40, 0x4D, 0x48, 0x03, 0x59, 
+0x44, 0x6C, 0x51, 0x08, 0xBE, 0xA7, 0x8A, 0x51, 0x05, 0x30, 0xA1, 0xC0, 0x57, 0x88, 0x96, 0x27, 
+0x8A, 0x51, 0xA0, 0xFE, 0x56, 0xC7, 0xB1, 0x00, 0x84, 0x80, 0x51, 0x08, 0xE6, 0x67, 0x8A, 0x51, 
+0x96, 0x27, 0x8A, 0x51, 0xA0, 0xFE, 0x56, 0xC7, 0xB1, 0x00, 0x84, 0x80, 0x52, 0x08, 0x83, 0xD7, 
+0x80, 0x40, 0x17, 0xEC, 0x57, 0x88, 0xE0, 0x3E, 0x84, 0x80, 0x4E, 0x48, 0x83, 0x93, 0x80, 0x40, 
+0x4E, 0x48, 0x39, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xD3, 0x40, 0xC4, 0xE7, 0x8A, 0x51, 0x09, 0x30, 
+0xD7, 0x0A, 0x57, 0x82, 0x03, 0x5C, 0x86, 0xEB, 0xA1, 0x01, 0xA1, 0x43, 0x53, 0x48, 0xDD, 0x66, 
+0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xB9, 0x40, 0xA1, 0x01, 0xA1, 0x43, 0x54, 0x08, 0xDD, 0x66, 
+0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xC2, 0xC0, 0xA1, 0x01, 0xA1, 0x43, 0x53, 0x48, 0xDD, 0x66, 
+0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xBA, 0x40, 0x54, 0x08, 0xC3, 0x00, 0xA1, 0x01, 0xA1, 0x43, 
+0x53, 0x48, 0xDD, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xBB, 0x80, 0xA1, 0x01, 0xA1, 0x4A, 
+0x54, 0x08, 0xDD, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xC4, 0xC0, 0x53, 0x48, 0xBC, 0x40, 
+0xA1, 0x01, 0xA1, 0x43, 0x54, 0x08, 0xDD, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xC5, 0x00, 
+0x53, 0x48, 0xBD, 0x80, 0x54, 0x08, 0xC6, 0x00, 0x53, 0x48, 0xBE, 0x80, 0xA1, 0x01, 0xA1, 0x4A, 
+0x54, 0x08, 0xDD, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xC7, 0x40, 0xA1, 0x01, 0xA1, 0x4A, 
+0x53, 0x48, 0xDD, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xBF, 0xC0, 0xA1, 0x01, 0xA1, 0x43, 
+0x54, 0x08, 0xDD, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xC8, 0xC0, 0xA1, 0x01, 0xA1, 0x4A, 
+0x53, 0x48, 0xDD, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xC0, 0x80, 0x54, 0x08, 0xC9, 0x00, 
+0xA1, 0x01, 0xA1, 0x4A, 0x53, 0x48, 0xDD, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xC1, 0xC0, 
+0xA1, 0x01, 0xA1, 0x4A, 0x54, 0x08, 0xDD, 0x66, 0x8A, 0x51, 0x83, 0x52, 0x03, 0x53, 0xCA, 0x00, 
+0xCE, 0x81, 0x39, 0x48, 0xA2, 0xC0, 0x11, 0x30, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x42, 0xC8, 0xA2, 0xC0, 0x12, 0x30, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x30, 0xC8, 0xA4, 0xC0, 0x4F, 0xF0, 
+0x2D, 0x27, 0x8A, 0x51, 0xD6, 0x81, 0x09, 0x30, 0xD6, 0xCA, 0x56, 0x42, 0x03, 0x18, 0x1D, 0x2D, 
+0x56, 0x48, 0xCA, 0x27, 0x8A, 0x51, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0xB1, 0x27, 0x8A, 0x51, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x30, 0xC8, 0xA4, 0xC0, 0x51, 0x70, 0x2D, 0x27, 0x8A, 0x51, 
+0x51, 0x70, 0xA1, 0xC0, 0x4F, 0xF0, 0x79, 0x67, 0x8A, 0x51, 0xCD, 0x40, 0x4D, 0x48, 0x03, 0x59, 
+0xF3, 0x6C, 0x51, 0x08, 0xBE, 0xA7, 0x8A, 0x51, 0xF3, 0x6C, 0x4E, 0x48, 0x39, 0x7E, 0x84, 0x80, 
+0x00, 0x48, 0xD3, 0x40, 0xC4, 0xE7, 0x8A, 0x51, 0x53, 0x48, 0xA2, 0xC0, 0x11, 0x30, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x54, 0x08, 0xA2, 0xC0, 
+0x12, 0x30, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x4F, 0x88, 0xB5, 0x40, 0x50, 0xC8, 0xB6, 0x40, 0x2F, 0x88, 0xA2, 0xC0, 0x19, 0x70, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x34, 0x08, 0xA2, 0xC0, 
+0x1A, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x37, 0x88, 0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x38, 0x08, 0xA2, 0xC0, 0x1C, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x06, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 
+0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD5, 0x40, 
+0x9E, 0x40, 0x55, 0x48, 0x06, 0xBA, 0x03, 0x9D, 0x66, 0x2D, 0x35, 0x48, 0xA2, 0xC0, 0x19, 0x70, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x36, 0x48, 
+0xA2, 0xC0, 0x1A, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x53, 0x48, 0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x54, 0x08, 0xA2, 0xC0, 0x1C, 0x70, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x07, 0x70, 0x9B, 0x40, 0x3C, 0xB0, 
+0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xD5, 0x40, 0x9E, 0x40, 0x55, 0x48, 0x07, 0xFA, 0x03, 0x9D, 0x9F, 0xAD, 0x83, 0x96, 0x60, 0xC8, 
+0x83, 0x52, 0xA2, 0xC0, 0x19, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x83, 0x96, 0x61, 0x08, 0x83, 0x52, 0xA2, 0xC0, 0x1A, 0x70, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x83, 0x96, 0x62, 0x08, 
+0x83, 0x52, 0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x83, 0x96, 0x63, 0x48, 0x83, 0x52, 0xA2, 0xC0, 0x1C, 0x70, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x08, 0xF0, 0x9B, 0x40, 
+0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xD5, 0x40, 0x9E, 0x40, 0x55, 0x48, 0x08, 0x7A, 0x03, 0x9D, 0xE0, 0xED, 0x83, 0x96, 
+0x64, 0x08, 0x83, 0x52, 0xA2, 0xC0, 0x19, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x83, 0x96, 0x65, 0x48, 0x83, 0x52, 0xA2, 0xC0, 0x1A, 0x70, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x83, 0x96, 
+0x66, 0x48, 0x83, 0x52, 0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x83, 0x96, 0x67, 0x88, 0x83, 0x52, 0xA2, 0xC0, 0x1C, 0x70, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x09, 0x30, 
+0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xD5, 0x40, 0x9E, 0x40, 0x55, 0x48, 0x09, 0xBA, 0x03, 0x9D, 0x21, 0xAE, 
+0x83, 0x96, 0x68, 0x08, 0x83, 0x52, 0xA2, 0xC0, 0x19, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x83, 0x96, 0x69, 0x48, 0x83, 0x52, 0xA2, 0xC0, 
+0x1A, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x83, 0x96, 0x6A, 0x48, 0x83, 0x52, 0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x83, 0x96, 0x6B, 0x88, 0x83, 0x52, 0xA2, 0xC0, 
+0x1C, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x0A, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD5, 0x40, 0x9E, 0x40, 0x55, 0x48, 0x0A, 0xBA, 0x03, 0x9D, 
+0x62, 0xEE, 0xD7, 0xC1, 0x03, 0xD0, 0x57, 0x0D, 0xA0, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0xA2, 0xC0, 0x19, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x03, 0xD0, 0x57, 0x0D, 0xA0, 0xFE, 0x84, 0x80, 0x83, 0xD7, 0x00, 0x48, 0xA2, 0xC0, 
+0x1A, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x03, 0xD0, 0x57, 0x0D, 0xA1, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA2, 0xC0, 0x1B, 0xB0, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x03, 0xD0, 
+0x57, 0x0D, 0xA1, 0x3E, 0x84, 0x80, 0x83, 0xD7, 0x00, 0x48, 0xA2, 0xC0, 0x1C, 0x70, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x57, 0x88, 0x0C, 0xFE, 
+0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xA4, 0xE7, 0x8A, 0x51, 0x03, 0x9D, 0xB1, 0x2E, 0x14, 0x30, 0xD7, 0x0A, 
+0x57, 0x82, 0x03, 0x5C, 0x73, 0x6E, 0x57, 0x88, 0x0C, 0xFE, 0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 
+0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xA4, 0xE7, 
+0x8A, 0x51, 0x03, 0x9D, 0xC6, 0x2E, 0x10, 0xF0, 0xA2, 0x01, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x08, 0x40, 0xAB, 0x40, 0xAB, 0x9F, 0x09, 0xEF, 
+0xA1, 0x1F, 0x04, 0xAF, 0x2B, 0x48, 0xA2, 0xC0, 0xA3, 0x41, 0xA2, 0xDB, 0xA3, 0x83, 0x80, 0xF0, 
+0xA4, 0xC0, 0xFF, 0xB0, 0xA5, 0x00, 0x22, 0xC8, 0x24, 0xC2, 0xA6, 0x00, 0x23, 0x08, 0x03, 0x5C, 
+0x23, 0x4A, 0x25, 0x02, 0xA7, 0x40, 0x21, 0xC8, 0xA8, 0xC0, 0xA9, 0x41, 0xA8, 0xDB, 0xA9, 0x83, 
+0x29, 0x08, 0x80, 0x7A, 0xAA, 0x00, 0x27, 0x48, 0x80, 0x7A, 0x2A, 0x02, 0x03, 0x9D, 0x02, 0xAF, 
+0x26, 0x08, 0x28, 0xC2, 0x03, 0x5C, 0x80, 0x34, 0x83, 0x52, 0x03, 0x53, 0x21, 0xC8, 0x2B, 0xC7, 
+0x08, 0x40, 0x21, 0xC8, 0x80, 0x7A, 0x7F, 0x3E, 0x03, 0x5C, 0x04, 0xAF, 0x21, 0xC8, 0xA2, 0xC0, 
+0xA3, 0x41, 0xA2, 0xDB, 0xA3, 0x83, 0x2B, 0x48, 0xA4, 0xC0, 0xA5, 0x41, 0xA4, 0xDB, 0xA5, 0x83, 
+0x7F, 0x70, 0xA6, 0x00, 0x24, 0xC8, 0x26, 0x02, 0xA7, 0x40, 0x25, 0x49, 0x03, 0x18, 0x01, 0xBE, 
+0xA8, 0xC0, 0x80, 0x7A, 0xA9, 0x00, 0x23, 0x08, 0x80, 0x7A, 0x29, 0x02, 0x03, 0x9D, 0x2A, 0x2F, 
+0x22, 0xC8, 0x27, 0x42, 0x03, 0x5C, 0x7F, 0xB4, 0x04, 0xAF, 0xA8, 0xC0, 0x24, 0xC8, 0x20, 0x38, 
+0xA7, 0x40, 0xA2, 0xC0, 0x18, 0x30, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x05, 0x30, 0xA5, 0x00, 0xA5, 0xCB, 0x3C, 0x6F, 0x83, 0x52, 0x03, 0x53, 
+0x24, 0xC8, 0x30, 0x78, 0xA7, 0x40, 0xA2, 0xC0, 0x18, 0x30, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x05, 0x30, 0xA5, 0x00, 0xA5, 0xCB, 0x4E, 0x6F, 
+0x39, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xA6, 0x00, 0x55, 0xB0, 0x9E, 0x40, 0x26, 0x9C, 0x50, 0xEF, 0x28, 0xC8, 0x84, 0x80, 
+0x3A, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0x83, 0x93, 0x80, 0x40, 0x28, 0x0A, 0x84, 0x80, 0x3B, 0xF0, 0x83, 0x52, 0x03, 0x53, 
+0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0x83, 0x93, 0x80, 0x40, 
+0x08, 0x40, 0xA4, 0xC0, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA2, 0xC0, 0x21, 0xC8, 0xB8, 0x27, 
+0x8A, 0x51, 0x03, 0x5C, 0x01, 0x34, 0x21, 0xC8, 0x84, 0x80, 0x00, 0x48, 0xA2, 0xC0, 0x24, 0xC8, 
+0xB8, 0x27, 0x8A, 0x51, 0x03, 0x5C, 0x00, 0xF4, 0x24, 0x0A, 0x84, 0x80, 0x00, 0x48, 0xA2, 0xC0, 
+0x21, 0x0A, 0xB8, 0x27, 0x8A, 0x51, 0x03, 0x5C, 0x01, 0x34, 0x00, 0xF4, 0xA3, 0x00, 0xA2, 0x01, 
+0x21, 0xC8, 0x23, 0x58, 0xA2, 0x87, 0x03, 0xD0, 0xA1, 0x8D, 0x03, 0xD0, 0xA3, 0x8C, 0xA3, 0x48, 
+0x03, 0x9D, 0x98, 0x2F, 0x22, 0xC8, 0x08, 0x40, 0xD5, 0x40, 0x9E, 0x40, 0x57, 0x88, 0x0C, 0xFE, 
+0xB1, 0x00, 0x00, 0xB0, 0x03, 0x18, 0x01, 0xF0, 0xB2, 0x00, 0x55, 0x48, 0x31, 0x46, 0x32, 0x04, 
+0x08, 0x40, 0x56, 0x48, 0x42, 0xFE, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xA2, 0xC0, 0x12, 0x74, 
+0x84, 0x80, 0x00, 0x48, 0xA3, 0x00, 0x22, 0xC8, 0x23, 0x02, 0x08, 0x40, 0xCF, 0x80, 0x52, 0x08, 
+0xD0, 0xC0, 0x56, 0x48, 0xCE, 0x40, 0x08, 0x40, 0x4E, 0x48, 0x42, 0xFE, 0x84, 0x80, 0x00, 0x48, 
+0xD4, 0x00, 0x08, 0x40, 0x39, 0x7E, 0x84, 0x80, 0x00, 0x48, 0xA2, 0xC0, 0x11, 0x74, 0xFD, 0xF9, 
+0x02, 0x38, 0xA2, 0xC0, 0x02, 0x34, 0xFD, 0xF9, 0x02, 0x38, 0xA2, 0xC0, 0x01, 0x34, 0x03, 0xD0, 
+0xB0, 0x8D, 0x03, 0xD0, 0xB0, 0x8D, 0x08, 0x40, 0xFF, 0x3A, 0x01, 0xBE, 0xA1, 0xC0, 0x53, 0x48, 
+0x08, 0x40, 0x03, 0xD0, 0xB1, 0xCD, 0x03, 0xD0, 0xB1, 0xCD, 0x08, 0x40, 0x80, 0x40, 0x05, 0x30, 
+0xA1, 0xC0, 0x57, 0x88, 0x08, 0x40, 0xFF, 0x3A, 0x01, 0xBE, 0xA1, 0xC0, 0x54, 0x08, 0x08, 0x40, 
+0xA0, 0x30, 0x83, 0x93, 0x84, 0x80, 0xF0, 0xB0, 0x8A, 0x51, 0x2F, 0xE1, 0x8A, 0x51, 0xA0, 0x30, 
+0x83, 0xD7, 0x84, 0x80, 0xE0, 0x70, 0x8A, 0x51, 0x2F, 0xE1, 0x83, 0x01, 0x8A, 0x95, 0xD5, 0x2A, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 
+0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0xFF, 0xBF, 0x01, 0xF0, 0xA0, 0x80, 0x95, 0x41, 
+0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9A, 0x41, 0x9B, 0x81, 0x9C, 0x41, 0x9E, 0x81, 
+0x9B, 0x81, 0x1C, 0x70, 0xA2, 0x01, 0xA2, 0x4A, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 
+0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE5, 0x40, 0x65, 0x48, 
+0x03, 0x59, 0xED, 0x6A, 0x9B, 0x81, 0x10, 0xF0, 0xA2, 0x01, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 
+0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE5, 0x40, 0x9E, 0x40, 0x65, 0xCB, 
+0x04, 0x6B, 0x3D, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xE2, 0x00, 0xA2, 0xC0, 0x1A, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3E, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 
+0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE3, 0x40, 0xA2, 0xC0, 0x1B, 0xB0, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3F, 0x30, 
+0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xE4, 0x00, 0x03, 0x30, 0xE4, 0x85, 0x64, 0x08, 0xA2, 0xC0, 0x1C, 0x70, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 0x9E, 0x40, 0x9B, 0x40, 
+0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xE5, 0x40, 0x9E, 0x40, 0x65, 0x48, 0x02, 0x7A, 0x03, 0x9D, 0x50, 0xAB, 0x3D, 0xF0, 
+0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xDF, 0xC0, 0xA2, 0xC0, 0x1A, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x3E, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE0, 0xC0, 0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x02, 0xF0, 0x9E, 0x40, 0x9B, 0x40, 
+0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xE5, 0x40, 0x9E, 0x40, 0x65, 0x48, 0x03, 0xBA, 0x03, 0x9D, 0x88, 0xAB, 0x3D, 0xF0, 
+0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xDC, 0x40, 0xA2, 0xC0, 0x1A, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x3E, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 
+0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xDD, 0x80, 0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x03, 0x30, 0x9E, 0x40, 0x9B, 0x40, 
+0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xE5, 0x40, 0x9E, 0x40, 0x65, 0x48, 0x04, 0x7A, 0x03, 0x9D, 0xC0, 0xAB, 0x9E, 0x81, 
+0x9B, 0x81, 0x3D, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 
+0x97, 0x90, 0x0D, 0x08, 0xDE, 0x80, 0xA2, 0xC0, 0x1A, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3E, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 
+0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xE1, 0x00, 0xA2, 0xC0, 0x1B, 0xB0, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xE2, 0x48, 
+0x03, 0x9D, 0x02, 0x2C, 0x63, 0x48, 0x56, 0xA4, 0x00, 0xB0, 0x8A, 0x95, 0x5C, 0xA4, 0x8A, 0x95, 
+0x11, 0x30, 0x3B, 0x2C, 0x62, 0x8B, 0x0C, 0x6C, 0x63, 0x48, 0x56, 0xA4, 0x01, 0xF0, 0x8A, 0x95, 
+0x5C, 0xA4, 0x8A, 0x95, 0x22, 0x30, 0x3B, 0x2C, 0x62, 0x08, 0x02, 0x7A, 0x03, 0x9D, 0x18, 0x6C, 
+0x63, 0x48, 0x4C, 0x64, 0x00, 0xB0, 0x8A, 0x51, 0x39, 0xA2, 0x8A, 0x95, 0x33, 0xB0, 0x3B, 0x2C, 
+0x62, 0x08, 0x03, 0xBA, 0x03, 0x9D, 0x24, 0x6C, 0x63, 0x48, 0x4C, 0x64, 0x01, 0xF0, 0x8A, 0x51, 
+0x39, 0xA2, 0x8A, 0x95, 0x44, 0x30, 0x3B, 0x2C, 0x62, 0x08, 0x04, 0x7A, 0x03, 0x9D, 0x30, 0x6C, 
+0x63, 0x48, 0x3E, 0xE4, 0x00, 0xB0, 0x8A, 0x51, 0x37, 0xE1, 0x8A, 0x95, 0x55, 0xB0, 0x3B, 0x2C, 
+0x62, 0x08, 0x05, 0xBA, 0x03, 0x9D, 0x04, 0x6B, 0x63, 0x48, 0x3E, 0xE4, 0x01, 0xF0, 0x8A, 0x51, 
+0x37, 0xE1, 0x8A, 0x95, 0x66, 0xB0, 0x9B, 0x40, 0x9E, 0x40, 0x04, 0x6B, 0xA9, 0x00, 0x5F, 0xC8, 
+0xAA, 0x00, 0x60, 0xC8, 0xAB, 0x40, 0x5C, 0x48, 0xAC, 0x00, 0x5D, 0x88, 0xAD, 0x40, 0x5E, 0x88, 
+0xAE, 0x40, 0x64, 0x08, 0xAF, 0x80, 0x08, 0x40, 0xAC, 0x00, 0x5F, 0xC8, 0xAD, 0x40, 0x60, 0xC8, 
+0xAE, 0x40, 0x61, 0x08, 0xAF, 0x80, 0x64, 0x08, 0xB0, 0xC0, 0x08, 0x40, 0xA9, 0x00, 0x61, 0x08, 
+0xAA, 0x00, 0x64, 0x08, 0xAB, 0x40, 0x08, 0x40, 0xB3, 0x40, 0x04, 0xF0, 0xA2, 0xC0, 0x10, 0xF0, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x29, 0x08, 
+0xA2, 0xC0, 0x13, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x14, 0x30, 0xA2, 0x01, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x15, 0x70, 0xA2, 0x01, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2A, 0x08, 0xD6, 0x40, 0x0B, 0x70, 0xD7, 0xC1, 0xDB, 0x80, 
+0x5B, 0x88, 0xB4, 0x00, 0x33, 0x98, 0xE0, 0xAC, 0x5B, 0x88, 0xAC, 0x00, 0x01, 0xF0, 0xFB, 0xE7, 
+0x8A, 0x95, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0xC3, 0x39, 0x2C, 0x04, 0xA2, 0xC0, 0x01, 0xF0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 
+0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0x8A, 0x51, 0xD3, 0x67, 0x8A, 0x95, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x01, 0xF0, 
+0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 
+0xA2, 0xC0, 0x01, 0xF0, 0xA2, 0x10, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x2B, 0x48, 0xA4, 0xC0, 0x53, 0xB0, 0x8A, 0x51, 0x2D, 0x27, 0x8A, 0x95, 
+0x56, 0xB0, 0xA1, 0xC0, 0x53, 0xB0, 0x8A, 0x51, 0x79, 0x67, 0x8A, 0x95, 0xD0, 0xC0, 0x50, 0xC8, 
+0x03, 0x9D, 0x1F, 0x6D, 0x07, 0x70, 0xDB, 0x03, 0x5B, 0x82, 0x03, 0x5C, 0x1F, 0x6D, 0x88, 0x6C, 
+0x5B, 0x88, 0xAC, 0x00, 0x02, 0xF0, 0xFB, 0xE7, 0x8A, 0x95, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 
+0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xC3, 0x39, 0x2C, 0x04, 0xA2, 0xC0, 
+0x02, 0xF0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x02, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 
+0x0D, 0x08, 0x8A, 0x51, 0xCF, 0xA7, 0x8A, 0x95, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x02, 0xF0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 
+0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xA2, 0xC0, 0x02, 0xF0, 0xA2, 0x10, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xCA, 0xEC, 0x53, 0x48, 
+0xB5, 0x40, 0x54, 0x08, 0xB6, 0x40, 0xF3, 0xA7, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2B, 0x48, 0xA4, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x2D, 0x27, 
+0x8A, 0x95, 0x56, 0x48, 0xB9, 0x40, 0x57, 0x88, 0xBA, 0x40, 0x29, 0x08, 0xFE, 0xFC, 0xAD, 0x40, 
+0x29, 0x49, 0xAE, 0x40, 0x29, 0x08, 0x01, 0x7C, 0xAF, 0x80, 0x29, 0x08, 0x02, 0x7C, 0xB0, 0xC0, 
+0x14, 0x30, 0xA2, 0x01, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x15, 0x70, 0xA2, 0x01, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x2D, 0x48, 0xA2, 0xC0, 0x13, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2B, 0x48, 0xA4, 0xC0, 0x53, 0xB0, 0x8A, 0x51, 
+0x2D, 0x27, 0x8A, 0x95, 0xDB, 0xC1, 0xDB, 0x0A, 0x5B, 0x88, 0x2D, 0x7E, 0x84, 0x80, 0x00, 0x48, 
+0xA2, 0xC0, 0x13, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x2B, 0x48, 0xA4, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x2D, 0x27, 0x8A, 0x95, 0x53, 0xB0, 
+0xA1, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x79, 0x67, 0x8A, 0x95, 0xD0, 0xC0, 0x50, 0xC8, 0x03, 0x59, 
+0x85, 0xED, 0x56, 0x48, 0xD3, 0x40, 0x57, 0x88, 0xD4, 0x00, 0x04, 0xF0, 0xDB, 0x0A, 0x5B, 0x82, 
+0x03, 0x5C, 0x64, 0xED, 0x53, 0x48, 0xB7, 0x80, 0x54, 0x08, 0xB8, 0x00, 0xF3, 0xA7, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xD8, 0x41, 0xD9, 0x81, 
+0xDB, 0xC1, 0x58, 0x08, 0xBD, 0x80, 0x59, 0x48, 0xC6, 0x00, 0x5B, 0x88, 0x0A, 0xFE, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0x58, 0x87, 0xBE, 0x80, 0x5B, 0x88, 0x0A, 0xFE, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0x59, 0xC7, 0xC7, 0x40, 0x5B, 0x88, 0x0A, 0xFE, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0x58, 0x87, 0xBF, 0xC0, 0x5B, 0x88, 0x0A, 0xFE, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0x59, 0x42, 0xC8, 0xC0, 0x5B, 0x88, 0x0A, 0xFE, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0x58, 0x02, 0xC0, 0x80, 0x5B, 0x88, 0x0A, 0xFE, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0x59, 0xC7, 0xC9, 0x00, 0x5B, 0x88, 0x0A, 0xFE, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0x58, 0x02, 0xC1, 0xC0, 0x5B, 0x88, 0x0A, 0xFE, 0x84, 0x80, 
+0x8A, 0x51, 0x02, 0xA0, 0x8A, 0x95, 0x59, 0x42, 0xCA, 0x00, 0xE1, 0x27, 0x8A, 0x95, 0x97, 0x67, 
+0x8A, 0x95, 0xDA, 0x67, 0x8A, 0x95, 0x97, 0x67, 0x8A, 0x95, 0xF7, 0xE7, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x46, 0x08, 0xA2, 0xC0, 0x15, 0x70, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2B, 0x48, 
+0xA4, 0xC0, 0x51, 0x70, 0x8A, 0x51, 0x2D, 0x27, 0x8A, 0x95, 0xCF, 0xC1, 0xDA, 0x81, 0x05, 0x30, 
+0xDA, 0xCA, 0x5A, 0x42, 0x03, 0x18, 0x32, 0xEE, 0x1F, 0xF0, 0xCB, 0x67, 0x8A, 0x95, 0x97, 0x67, 
+0x8A, 0x95, 0xAE, 0x67, 0x8A, 0x95, 0x97, 0x67, 0x8A, 0x95, 0xBE, 0xA7, 0x8A, 0x95, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xD3, 0x67, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2B, 0x48, 0xA4, 0xC0, 
+0x56, 0xB0, 0x8A, 0x51, 0x2D, 0x27, 0x8A, 0x95, 0x56, 0xB0, 0xA1, 0xC0, 0x51, 0x70, 0x8A, 0x51, 
+0x79, 0x67, 0x8A, 0x95, 0xD0, 0xC0, 0x50, 0xC8, 0x03, 0x59, 0xFF, 0x2D, 0x56, 0x48, 0xE7, 0xA7, 
+0x8A, 0x95, 0xFF, 0x2D, 0x4F, 0x88, 0x3D, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xD8, 0x00, 0xED, 0xA7, 
+0x8A, 0x95, 0x06, 0x30, 0xDB, 0x0A, 0x5B, 0x82, 0x58, 0x08, 0x03, 0x5C, 0x9A, 0x2D, 0xFF, 0x7E, 
+0xBD, 0x80, 0x59, 0x48, 0xFF, 0x7E, 0xC6, 0x00, 0x58, 0x08, 0xFF, 0x7E, 0xBE, 0x80, 0x59, 0x48, 
+0xC7, 0x40, 0x58, 0x08, 0xFF, 0x7E, 0xBF, 0xC0, 0x59, 0x48, 0x01, 0xBE, 0xC8, 0xC0, 0x58, 0x08, 
+0xC0, 0x80, 0x59, 0x48, 0xFF, 0x7E, 0xC9, 0x00, 0x58, 0x08, 0xC1, 0xC0, 0x59, 0x48, 0xCA, 0x00, 
+0x58, 0x08, 0xC2, 0xC0, 0x59, 0x48, 0x01, 0xBE, 0xCB, 0x40, 0x58, 0x08, 0x01, 0xBE, 0xC3, 0x00, 
+0x59, 0x48, 0xFF, 0x7E, 0xCC, 0x00, 0x58, 0x08, 0x01, 0xBE, 0xC4, 0xC0, 0x59, 0x48, 0xCD, 0x40, 
+0x58, 0x08, 0x01, 0xBE, 0xC5, 0x00, 0x59, 0x48, 0x01, 0xBE, 0xCE, 0x40, 0xE1, 0x27, 0x8A, 0x95, 
+0x97, 0x67, 0x8A, 0x95, 0xDA, 0x67, 0x8A, 0x95, 0x97, 0x67, 0x8A, 0x95, 0xF7, 0xE7, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x46, 0x08, 0xA2, 0xC0, 
+0x15, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x2B, 0x48, 0xA4, 0xC0, 0x51, 0x70, 0x8A, 0x51, 0x2D, 0x27, 0x8A, 0x95, 0xCF, 0xC1, 0xDA, 0x81, 
+0x09, 0x30, 0xDA, 0xCA, 0x5A, 0x42, 0x03, 0x18, 0xC3, 0x2E, 0x1F, 0xF0, 0xCB, 0x67, 0x8A, 0x95, 
+0x97, 0x67, 0x8A, 0x95, 0xAE, 0x67, 0x8A, 0x95, 0x97, 0x67, 0x8A, 0x95, 0xBE, 0xA7, 0x8A, 0x95, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0xD3, 0x67, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x2B, 0x48, 
+0xA4, 0xC0, 0x56, 0xB0, 0x8A, 0x51, 0x2D, 0x27, 0x8A, 0x95, 0x56, 0xB0, 0xA1, 0xC0, 0x51, 0x70, 
+0x8A, 0x51, 0x79, 0x67, 0x8A, 0x95, 0xD0, 0xC0, 0x50, 0xC8, 0x03, 0x59, 0x90, 0xAE, 0x56, 0x48, 
+0xE7, 0xA7, 0x8A, 0x95, 0x90, 0xAE, 0x4F, 0x88, 0x3D, 0xBE, 0x84, 0x80, 0x00, 0x48, 0xD8, 0x00, 
+0xED, 0xA7, 0x8A, 0x95, 0x51, 0x08, 0xBB, 0x80, 0x52, 0x08, 0xBC, 0x40, 0x58, 0x08, 0xA2, 0xC0, 
+0x14, 0x30, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x59, 0x48, 0xA2, 0xC0, 0x15, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x2A, 0x08, 0xA2, 0xC0, 0x19, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x34, 0x08, 0xA2, 0xC0, 0x1A, 0x70, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x35, 0x48, 0xA2, 0xC0, 
+0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x36, 0x48, 0xA2, 0xC0, 0x1C, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x06, 0x30, 0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 0xA1, 0xC0, 
+0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD5, 0x40, 0x9E, 0x40, 0x55, 0x48, 
+0x06, 0xBA, 0x03, 0x9D, 0x0C, 0xEF, 0x39, 0x48, 0xA2, 0xC0, 0x19, 0x70, 0xA3, 0x00, 0x22, 0xC8, 
+0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3A, 0x48, 0xA2, 0xC0, 0x1A, 0x70, 
+0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x58, 0x08, 
+0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 
+0x17, 0x50, 0x59, 0x48, 0xA2, 0xC0, 0x1C, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 
+0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x07, 0x70, 0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 0x03, 0x53, 
+0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD5, 0x40, 0x9E, 0x40, 
+0x55, 0x48, 0x07, 0xFA, 0x03, 0x9D, 0x45, 0x2F, 0x3B, 0x88, 0xA2, 0xC0, 0x19, 0x70, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x3C, 0x48, 0xA2, 0xC0, 
+0x1A, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 
+0x37, 0x88, 0xA2, 0xC0, 0x1B, 0xB0, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 
+0x17, 0x94, 0x17, 0x50, 0x38, 0x08, 0xA2, 0xC0, 0x1C, 0x70, 0xA3, 0x00, 0x22, 0xC8, 0x96, 0x00, 
+0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x08, 0xF0, 0x9B, 0x40, 0x3C, 0xB0, 0x83, 0x52, 
+0x03, 0x53, 0xA1, 0xC0, 0x21, 0xC8, 0x95, 0x00, 0x97, 0xD4, 0x97, 0x90, 0x0D, 0x08, 0xD5, 0x40, 
+0x9E, 0x40, 0x55, 0x48, 0x08, 0x7A, 0x03, 0x9D, 0x7E, 0xEF, 0x10, 0xF0, 0xA2, 0x01, 0xA3, 0x00, 
+0x22, 0xC8, 0x96, 0x00, 0x23, 0x08, 0x95, 0x00, 0x17, 0x94, 0x17, 0x50, 0x08, 0x40, 0xA4, 0xC0, 
+0x21, 0xC8, 0x80, 0x7A, 0xA3, 0x00, 0x24, 0xC8, 0x80, 0x7A, 0xA3, 0x42, 0x03, 0x18, 0xA2, 0x2F, 
+0x21, 0xC8, 0x08, 0x40, 0x24, 0xC8, 0x80, 0x7A, 0xA3, 0x00, 0x22, 0xC8, 0x80, 0x7A, 0xA3, 0x42, 
+0x03, 0x18, 0xAC, 0x6F, 0x22, 0xC8, 0x08, 0x40, 0x24, 0xC8, 0x08, 0x40, 0xAC, 0x00, 0x5A, 0x48, 
+0x3D, 0xBE, 0x84, 0x80, 0x2C, 0x08, 0x83, 0x93, 0x80, 0x40, 0x1F, 0xF0, 0xA1, 0xC0, 0xE0, 0x70, 
+0xA2, 0xC0, 0x5A, 0x48, 0x46, 0x3E, 0x84, 0x80, 0x00, 0x48, 0x08, 0x40, 0xAC, 0x00, 0x5A, 0x48, 
+0x46, 0x3E, 0x84, 0x80, 0x2C, 0x08, 0x83, 0x93, 0x80, 0x40, 0x5A, 0x48, 0x3D, 0xBE, 0x84, 0x80, 
+0x00, 0x48, 0xA2, 0xC0, 0x14, 0x74, 0xA1, 0xC0, 0xE0, 0x70, 0xA2, 0xC0, 0x5A, 0x48, 0x3D, 0xBE, 
+0x84, 0x80, 0x00, 0x48, 0x08, 0x40, 0x5A, 0x48, 0x46, 0x3E, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 
+0xA2, 0xC0, 0x15, 0xB4, 0xBD, 0x80, 0x1F, 0xF0, 0xA1, 0xC0, 0xE0, 0x70, 0xA2, 0xC0, 0x46, 0x08, 
+0x08, 0x40, 0x1F, 0xF0, 0xA1, 0xC0, 0xE0, 0x70, 0xA2, 0xC0, 0x3D, 0x88, 0x08, 0x40, 0xD1, 0x00, 
+0x57, 0x88, 0xD2, 0x00, 0x5A, 0x48, 0xCF, 0x80, 0x08, 0x40, 0x4F, 0x88, 0x46, 0x3E, 0x84, 0x80, 
+0x00, 0x48, 0xD9, 0x40, 0x08, 0x40, 0x29, 0x43, 0xFF, 0x3A, 0xA2, 0xC0, 0x13, 0xB4, 0xC6, 0x00, 
+0x3D, 0x88, 0xA2, 0xC0, 0x14, 0x74, 0x03, 0xD0, 0xAC, 0xCD, 0x03, 0xD0, 0xAC, 0xCD, 0x08, 0x40 
+ }; 
+ 

+ 93 - 0
sx1302/source/loragw_ad5338r.c

@@ -0,0 +1,93 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    Basic driver for Analog AD5338R DAC.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* bool type */
+#include <stdio.h>      /* printf fprintf */
+
+#include "loragw_i2c.h"
+#include "loragw_ad5338r.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#if DEBUG_I2C == 1
+    #define DEBUG_MSG(str)              fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)  fprintf(stdout,"%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_I2C_ERROR;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)               if(a==NULL){return LGW_I2C_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int ad5338r_configure(int i2c_fd, uint8_t i2c_addr) {
+    int err;
+    uint8_t cmd_soft_reset[AD5338R_CMD_SIZE] = {0x69, 0x00, 0x00};
+    uint8_t cmd_power_up_dn[AD5338R_CMD_SIZE] = {0x40, 0x00, 0x00};
+    uint8_t cmd_internal_ref[AD5338R_CMD_SIZE] = {0x70, 0x00, 0x00};
+
+    /* Check Input Params */
+    if (i2c_fd <= 0) {
+        printf("ERROR: invalid I2C file descriptor\n");
+        return LGW_I2C_ERROR;
+    }
+
+    DEBUG_PRINTF("INFO: configuring AD5338R DAC on 0x%02X...\n", i2c_addr);
+
+    /* Sofwtare reset of DAC A & B */
+    /* TODO: LSB data bytes seems not acknoledged by AD5338R, leading to an error if sent.
+        Only send MSB data byte */
+    err = i2c_linuxdev_write(i2c_fd, i2c_addr, cmd_soft_reset[0], cmd_soft_reset[1]);
+    if (err != 0) {
+        printf("ERROR: AD5338R software reset failed\n");
+        return LGW_I2C_ERROR;
+    }
+
+    /* Normal operation */
+    err = ad5338r_write(i2c_fd, i2c_addr, cmd_power_up_dn);
+    if (err != 0) {
+        printf("ERROR: AD5338R failed to set to normal operation\n");
+        return LGW_I2C_ERROR;
+    }
+
+    /* Internal reference ON */
+    err = ad5338r_write(i2c_fd, i2c_addr, cmd_internal_ref);
+    if (err != 0) {
+        printf("ERROR: AD5338R failed to set internal reference ON\n");
+        return LGW_I2C_ERROR;
+    }
+
+    printf("INFO: AD5338R is configured\n");
+
+    return LGW_I2C_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int ad5338r_write(int i2c_fd, uint8_t i2c_addr, uint8_t buf[static AD5338R_CMD_SIZE]) {
+    int err;
+
+    /* Write AD5338R command buffer */
+    err = i2c_linuxdev_write_buffer(i2c_fd, i2c_addr, buf, AD5338R_CMD_SIZE);
+    if (err != 0) {
+        printf("ERROR: failed to write AD5338R command\n");
+        return LGW_I2C_ERROR;
+    }
+
+    return LGW_I2C_SUCCESS;
+}

+ 218 - 0
sx1302/source/loragw_aux.c

@@ -0,0 +1,218 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+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 */
+#include <math.h>   /* pow, ceil */
+
+#include "loragw_aux.h"
+#include "loragw_hal.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#if DEBUG_AUX == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+void wait_us(unsigned long delay_us) {
+    struct timespec dly;
+    struct timespec rem;
+
+    dly.tv_sec = delay_us / 1000000;
+    dly.tv_nsec = (delay_us % 1000000) * 1000;
+
+    DEBUG_PRINTF("NOTE dly: %ld sec %ld ns\n", dly.tv_sec, dly.tv_nsec);
+
+    while ((dly.tv_sec > 0) || (dly.tv_nsec > 1000)) {
+        /*
+        rem is set ONLY if clock_nanosleep is interrupted (eg. by a signal).
+        Must be zeroed each time or will get into an infinite loop after an IT.
+        */
+        rem.tv_sec = 0;
+        rem.tv_nsec = 0;
+        clock_nanosleep(CLOCK_MONOTONIC, 0, &dly, &rem);
+        DEBUG_PRINTF("NOTE remain: %ld sec %ld ns\n", rem.tv_sec, rem.tv_nsec);
+        dly = rem;
+    }
+
+    return;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void wait_ms(unsigned long delay_ms) {
+    struct timespec dly;
+    struct timespec rem;
+
+    dly.tv_sec = delay_ms / 1000;
+    dly.tv_nsec = ((long)delay_ms % 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;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint32_t lora_packet_time_on_air(const uint8_t bw, const uint8_t sf, const uint8_t cr, const uint16_t n_symbol_preamble,
+                                 const bool no_header, const bool no_crc, const uint8_t size,
+                                 double * out_nb_symbols, uint32_t * out_nb_symbols_payload, uint16_t * out_t_symbol_us) {
+    uint8_t H, DE, n_bit_crc;
+    uint8_t bw_pow;
+    uint16_t t_symbol_us;
+    double n_symbol;
+    uint32_t toa_us, n_symbol_payload;
+
+    /* Check input parameters */
+    if (IS_LORA_DR(sf) == false) {
+        printf("ERROR: wrong datarate - %s\n", __FUNCTION__);
+        return 0;
+    }
+    if (IS_LORA_BW(bw) == false) {
+        printf("ERROR: wrong bandwidth - %s\n", __FUNCTION__);
+        return 0;
+    }
+    if (IS_LORA_CR(cr) == false) {
+        printf("ERROR: wrong coding rate - %s\n", __FUNCTION__);
+        return 0;
+    }
+
+    /* Get bandwidth 125KHz divider*/
+    switch (bw) {
+        case BW_125KHZ:
+            bw_pow = 1;
+            break;
+        case BW_250KHZ:
+            bw_pow = 2;
+            break;
+        case BW_500KHZ:
+            bw_pow = 4;
+            break;
+        default:
+            printf("ERROR: unsupported bandwith 0x%02X (%s)\n", bw, __FUNCTION__);
+            return 0;
+    }
+
+    /* Duration of 1 symbol */
+    t_symbol_us = (1 << sf) * 8 / bw_pow; /* 2^SF / BW , in microseconds */
+
+    /* Packet parameters */
+    H = (no_header == false) ? 1 : 0; /* header is always enabled, except for beacons */
+    DE = (sf >= 11) ? 1 : 0; /* Low datarate optimization enabled for SF11 and SF12 */
+    n_bit_crc = (no_crc == false) ? 16 : 0;
+
+    /* Number of symbols in the payload */
+    n_symbol_payload = ceil( MAX( (double)( 8 * size + n_bit_crc - 4*sf + ((sf >= 7) ? 8 : 0) + 20*H ), 0.0) /
+                                  (double)( 4 * (sf - 2*DE)) )
+                       * ( cr + 4 ); /* Explicitely cast to double to keep precision of the division */
+
+    /* number of symbols in packet */
+    n_symbol = (double)n_symbol_preamble + ((sf >= 7) ? 4.25 : 6.25) + 8.0 + (double)n_symbol_payload;
+
+    /* Duration of packet in microseconds */
+    toa_us = (uint32_t)( (double)n_symbol * (double)t_symbol_us );
+
+    DEBUG_PRINTF("INFO: LoRa packet ToA: %u us (n_symbol:%f, t_symbol_us:%u)\n", toa_us, n_symbol, t_symbol_us);
+
+    /* Return details if required */
+    if (out_nb_symbols != NULL) {
+        *out_nb_symbols = n_symbol;
+    }
+    if (out_nb_symbols_payload != NULL) {
+        *out_nb_symbols_payload = n_symbol_payload;
+    }
+    if (out_t_symbol_us != NULL) {
+        *out_t_symbol_us = t_symbol_us;
+    }
+
+    return toa_us;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+void _meas_time_start(struct timeval *tm)
+{
+#if (DEBUG_PaERF > 0) && (DEBUG_PERF <= 5)
+    gettimeofday(tm, NULL);
+#endif
+}
+
+void _meas_time_stop(int debug_level, struct timeval start_time, const char *str)
+{
+#if (DEBUG_PERF > 0) && (DEBUG_PERF <= 5)
+    struct timeval tm;
+    double time_ms;
+    char *indent[] = { "", " ..", " ....", " ......", " ........" };
+
+    gettimeofday(&tm, NULL);
+
+    time_ms = (tm.tv_sec - start_time.tv_sec) * 1000.0 + (tm.tv_usec - start_time.tv_usec) / 1000.0;
+    if ((debug_level > 0) && (debug_level <= DEBUG_PERF)) {
+        printf("PERF:%s %s %f ms\n", indent[debug_level - 1], str, time_ms);
+    }
+#endif
+}
+#pragma GCC diagnostic pop
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void timeout_start(struct timeval * start) {
+    gettimeofday(start, NULL);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int timeout_check(struct timeval start, uint32_t timeout_ms) {
+    struct timeval tm;
+    struct timeval diff;
+    uint32_t ms;
+
+    gettimeofday(&tm, NULL);
+
+    TIMER_SUB(&tm, &start, &diff);
+
+    ms = diff.tv_sec * 1000 + diff.tv_usec / 1000;
+    if (ms >= timeout_ms) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/* --- EOF ------------------------------------------------------------------ */

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1037 - 0
sx1302/source/loragw_cal.c


+ 383 - 0
sx1302/source/loragw_com.c

@@ -0,0 +1,383 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    Functions to abstract the communication interface used to communicate with
+    the concentrator.
+    Single-byte read/write and burst read/write.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdio.h>      /* printf fprintf */
+
+#include "loragw_com.h"
+#include "loragw_usb.h"
+#include "loragw_spi.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_COM == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%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 CONSTANTS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+/**
+@brief The current communication type in use (SPI, USB)
+*/
+static lgw_com_type_t _lgw_com_type = LGW_COM_UNKNOWN;
+
+/**
+@brief A generic pointer to the COM device (file descriptor)
+*/
+static void* _lgw_com_target = NULL;
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lgw_com_open(lgw_com_type_t com_type, const char * com_path) {
+    int com_stat;
+
+    /* Check input parameters */
+    CHECK_NULL(com_path);
+    if ((com_type != LGW_COM_SPI) && (com_type != LGW_COM_USB)) {
+        DEBUG_MSG("ERROR: COMMUNICATION INTERFACE TYPE IS NOT SUPPORTED\n");
+        return LGW_COM_ERROR;
+    }
+
+    if (_lgw_com_target != NULL) {
+        DEBUG_MSG("WARNING: CONCENTRATOR WAS ALREADY CONNECTED\n");
+        lgw_com_close();
+    }
+
+    /* set current com type */
+    _lgw_com_type = com_type;
+
+    switch (com_type) {
+        case LGW_COM_SPI:
+            printf("Opening SPI communication interface\n");
+            com_stat = lgw_spi_open(com_path, &_lgw_com_target);
+            break;
+        case LGW_COM_USB:
+            printf("Opening USB communication interface\n");
+            com_stat = lgw_usb_open(com_path, &_lgw_com_target);
+            break;
+        default:
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* SPI release */
+int lgw_com_close(void) {
+    int com_stat;
+
+    if (_lgw_com_target == NULL) {
+        printf("ERROR: concentrator is not connected\n");
+        return -1;
+    }
+
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            printf("Closing SPI communication interface\n");
+            com_stat = lgw_spi_close(_lgw_com_target);
+            break;
+        case LGW_COM_USB:
+            printf("Closing USB communication interface\n");
+            com_stat = lgw_usb_close(_lgw_com_target);
+            break;
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    _lgw_com_target = NULL;
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple write */
+int lgw_com_w(uint8_t spi_mux_target, uint16_t address, uint8_t data) {
+    int com_stat;
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Check input parameters */
+    CHECK_NULL(_lgw_com_target);
+
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            com_stat = lgw_spi_w(_lgw_com_target, spi_mux_target, address, data);
+            break;
+        case LGW_COM_USB:
+            com_stat = lgw_usb_w(_lgw_com_target, spi_mux_target, address, data);
+            break;
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    /* Compute time spent in this function */
+    _meas_time_stop(5, tm, __FUNCTION__);
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple read */
+int lgw_com_r(uint8_t spi_mux_target, uint16_t address, uint8_t *data) {
+    int com_stat;
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Check input parameters */
+    CHECK_NULL(_lgw_com_target);
+    CHECK_NULL(data);
+
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            com_stat = lgw_spi_r(_lgw_com_target, spi_mux_target, address, data);
+            break;
+        case LGW_COM_USB:
+            com_stat = lgw_usb_r(_lgw_com_target, spi_mux_target, address, data);
+            break;
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    /* Compute time spent in this function */
+    _meas_time_stop(5, tm, __FUNCTION__);
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_rmw(uint8_t spi_mux_target, uint16_t address, uint8_t offs, uint8_t leng, uint8_t data) {
+    int com_stat;
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Check input parameters */
+    CHECK_NULL(_lgw_com_target);
+
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            com_stat = lgw_spi_rmw(_lgw_com_target, spi_mux_target, address, offs, leng, data);
+            break;
+        case LGW_COM_USB:
+            com_stat = lgw_usb_rmw(_lgw_com_target, address, offs, leng, data);
+            break;
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    /* Compute time spent in this function */
+    _meas_time_stop(5, tm, __FUNCTION__);
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) write */
+int lgw_com_wb(uint8_t spi_mux_target, uint16_t address, const uint8_t *data, uint16_t size) {
+    int com_stat;
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Check input parameters */
+    CHECK_NULL(_lgw_com_target);
+    CHECK_NULL(data);
+
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            com_stat = lgw_spi_wb(_lgw_com_target, spi_mux_target, address, data, size);
+            break;
+        case LGW_COM_USB:
+            com_stat = lgw_usb_wb(_lgw_com_target, spi_mux_target, address, data, size);
+            break;
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    /* Compute time spent in this function */
+    _meas_time_stop(5, tm, __FUNCTION__);
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) read */
+int lgw_com_rb(uint8_t spi_mux_target, uint16_t address, uint8_t *data, uint16_t size) {
+    int com_stat;
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Check input parameters */
+    CHECK_NULL(_lgw_com_target);
+    CHECK_NULL(data);
+
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            com_stat = lgw_spi_rb(_lgw_com_target, spi_mux_target, address, data, size);
+            break;
+        case LGW_COM_USB:
+            com_stat = lgw_usb_rb(_lgw_com_target, spi_mux_target, address, data, size);
+            break;
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    /* Compute time spent in this function */
+    _meas_time_stop(5, tm, __FUNCTION__);
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_set_write_mode(lgw_com_write_mode_t write_mode) {
+    int com_stat = LGW_COM_SUCCESS;
+
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            /* Do nothing: only single mode is supported on SPI */
+            break;
+        case LGW_COM_USB:
+            com_stat = lgw_usb_set_write_mode(write_mode);
+            break;
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_flush(void) {
+    int com_stat = LGW_COM_SUCCESS;
+
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            /* Do nothing: only single mode is supported on SPI */
+            break;
+        case LGW_COM_USB:
+            com_stat = lgw_usb_flush(_lgw_com_target);
+            break;
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint16_t lgw_com_chunk_size(void) {
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            return lgw_spi_chunk_size();
+        case LGW_COM_USB:
+            return lgw_usb_chunk_size();
+            break;
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            return 0;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_com_get_temperature(float * temperature) {
+    /* Check input parameters */
+    CHECK_NULL(_lgw_com_target);
+    CHECK_NULL(temperature);
+
+    switch (_lgw_com_type) {
+        case LGW_COM_SPI:
+            printf("ERROR(%s:%d): not supported for SPI com\n", __FUNCTION__, __LINE__);
+            return -1;
+        case LGW_COM_USB:
+            return lgw_usb_get_temperature(_lgw_com_target, temperature);
+        default:
+            printf("ERROR(%s:%d): wrong communication type (SHOULD NOT HAPPEN)\n", __FUNCTION__, __LINE__);
+            return LGW_COM_ERROR;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void* lgw_com_target(void) {
+    return _lgw_com_target;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+lgw_com_type_t lgw_com_type(void) {
+    return _lgw_com_type;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 183 - 0
sx1302/source/loragw_debug.c

@@ -0,0 +1,183 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    LoRa concentrator debug functions
+
+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>     /* memcmp */
+#include <time.h>
+
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_hal.h"
+#include "loragw_debug.h"
+
+#include "tinymt32.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- DEBUG CONSTANTS ------------------------------------------------------ */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS & TYPES -------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+static tinymt32_t tinymt;
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+void dbg_init_random(void) {
+    tinymt.mat1 = 0x8f7011ee;
+    tinymt.mat2 = 0xfc78ff1f;
+    tinymt.tmat = 0x3793fdff;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void dbg_log_buffer_to_file(FILE * file, uint8_t * buffer, uint16_t size) {
+    int i;
+    char stat_timestamp[24];
+    time_t t;
+
+    t = time(NULL);
+    strftime(stat_timestamp, sizeof stat_timestamp, "%F %T %Z", gmtime(&t));
+    fprintf(file, "---------(%s)------------\n", stat_timestamp);
+    for (i = 0; i < size; i++) {
+        fprintf(file, "%02X ", buffer[i]);
+    }
+    fprintf(file, "\n");
+
+    fflush(file);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void dbg_log_payload_diff_to_file(FILE * file, uint8_t * buffer1, uint8_t * buffer2, uint16_t size) {
+    int i, j;
+    uint16_t nb_bits_diff = 0;
+    uint8_t debug_payload_diff[255];
+
+    fprintf(file, "Diff: ");
+    /* bit comparison of payloads */
+    for (j = 0; j < size; j++) {
+        debug_payload_diff[j] = buffer1[j] ^ buffer2[j];
+        fprintf(file, "%02X ", debug_payload_diff[j]);
+    }
+    fprintf(file, "\n");
+
+    /* count number of bits flipped, and display bit by bit */
+    for (j = 0; j < size; j++) {
+        for (i = 7; i >= 0; i--) {
+            fprintf(file, "%u", TAKE_N_BITS_FROM(debug_payload_diff[j], i, 1));
+            if (TAKE_N_BITS_FROM(debug_payload_diff[j], i, 1) == 1) {
+                nb_bits_diff += 1;
+            }
+        }
+        fprintf(file, " ");
+    }
+    fprintf(file, "\n");
+    fprintf(file, "%u bits flipped\n", nb_bits_diff);
+
+    fflush(file);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void dbg_generate_random_payload(uint32_t pkt_cnt, uint8_t * buffer_expected, uint8_t size) {
+    int k;
+
+    /* construct payload we should get for this packet counter */
+    tinymt32_init(&tinymt, (int)pkt_cnt);
+    buffer_expected[4] = (uint8_t)(pkt_cnt >> 24);
+    buffer_expected[5] = (uint8_t)(pkt_cnt >> 16);
+    buffer_expected[6] = (uint8_t)(pkt_cnt >> 8);
+    buffer_expected[7] = (uint8_t)(pkt_cnt >> 0);
+    tinymt32_generate_uint32(&tinymt); /* dummy: for sync with random size generation */
+    for (k = 8; k < (int)size; k++) {
+        buffer_expected[k] = (uint8_t)tinymt32_generate_uint32(&tinymt);
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int dbg_check_payload(struct lgw_conf_debug_s * context, FILE * file, uint8_t * payload_received, uint8_t size, uint8_t ref_payload_idx, uint8_t sf) {
+    int k;
+    uint32_t debug_payload_cnt;
+
+    /* If the 4 first bytes of received payload match with the expected ones, go on with comparison */
+    if (memcmp((void*)payload_received, (void*)(context->ref_payload[ref_payload_idx].payload), 4) == 0) {
+        /* get counter to initialize random seed */
+        debug_payload_cnt = (unsigned int)(payload_received[4] << 24) | (unsigned int)(payload_received[5] << 16) | (unsigned int)(payload_received[6] << 8) | (unsigned int)(payload_received[7] << 0);
+
+        /* check if we missed some packets */
+        if (debug_payload_cnt > (context->ref_payload[ref_payload_idx].prev_cnt + 1)) {
+            printf("ERROR: 0x%08X missed %u pkt before %u (SF%u, size:%u)\n", context->ref_payload[ref_payload_idx].id, debug_payload_cnt - context->ref_payload[ref_payload_idx].prev_cnt - 1, debug_payload_cnt, sf, size);
+            if (file != NULL) {
+                fprintf(file, "ERROR: 0x%08X missed %u pkt before %u (SF%u, size:%u)\n", context->ref_payload[ref_payload_idx].id, debug_payload_cnt - context->ref_payload[ref_payload_idx].prev_cnt - 1, debug_payload_cnt, sf, size);
+                fflush(file);
+            }
+        } else if (debug_payload_cnt < context->ref_payload[ref_payload_idx].prev_cnt) {
+            if (file != NULL) {
+                fprintf(file, "INFO:  0x%08X got missing pkt %u (SF%u, size:%u) ?\n", context->ref_payload[ref_payload_idx].id, debug_payload_cnt, sf, size);
+                fflush(file);
+            }
+        } else {
+#if 0
+            if (file != NULL) {
+                fprintf(file, "0x%08X %u (SF%u, size:%u)\n", context.ref_payload[ref_payload_idx].id, debug_payload_cnt, sf, size);
+            }
+#endif
+        }
+        context->ref_payload[ref_payload_idx].prev_cnt = debug_payload_cnt;
+
+        /* generate the random payload which is expected for this packet count */
+        dbg_generate_random_payload(debug_payload_cnt, context->ref_payload[ref_payload_idx].payload, size);
+
+        /* compare expected with received */
+        if (memcmp((void *)payload_received, (void *)(context->ref_payload[ref_payload_idx].payload), size) != 0) {
+            if (file != NULL) {
+                fprintf(file, "RECEIVED:");
+                for (k = 0; k < (int)size; k++) {
+                    fprintf(file, "%02X ", payload_received[k]);
+                }
+                fprintf(file, "\n");
+                fprintf(file, "EXPECTED:");
+                for (k = 0; k < (int)size; k++) {
+                    fprintf(file, "%02X ", context->ref_payload[ref_payload_idx].payload[k]);
+                }
+                fprintf(file, "\n");
+            }
+            return -1;
+        } else {
+            return 1; /* matches */
+        }
+    }
+
+    return 0; /* ignored */
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1701 - 0
sx1302/source/loragw_hal.c


+ 180 - 0
sx1302/source/loragw_i2c.c

@@ -0,0 +1,180 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Host specific functions to address the LoRa concentrator I2C peripherals.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdio.h>      /* printf fprintf */
+#include <unistd.h>     /* lseek, close */
+#include <fcntl.h>      /* open */
+#include <errno.h>      /* errno */
+
+#include <sys/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#include "loragw_i2c.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_I2C == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%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_I2C_ERROR;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return LGW_I2C_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int i2c_linuxdev_open(const char *path, uint8_t device_addr, int *i2c_fd) {
+    int dev;
+
+    /* Check input variables */
+    if (path == NULL) {
+        DEBUG_MSG("ERROR: null pointer path\n");
+        return LGW_I2C_ERROR;
+    }
+    if (i2c_fd == NULL) {
+        DEBUG_MSG("ERROR: null pointer i2c_fd\n");
+        return LGW_I2C_ERROR;
+    }
+
+    /* Open I2C device */
+    dev = open(path, O_RDWR);
+    if (dev < 0) {
+        DEBUG_PRINTF("ERROR: Failed to open I2C %s - %s\n", path, strerror(errno));
+        return LGW_I2C_ERROR;
+    }
+
+    /* Setting I2C device mode to slave */
+    if (ioctl(dev, I2C_SLAVE, device_addr) < 0) {
+        DEBUG_PRINTF("ERROR: Failed to acquire bus access and/or talk to slave - %s\n", strerror(errno));
+        return LGW_I2C_ERROR;
+    }
+
+    DEBUG_PRINTF("INFO: I2C port opened successfully (%s, 0x%02X)\n", path, device_addr);
+    *i2c_fd = dev; /* return file descriptor index */
+
+    return LGW_I2C_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int i2c_linuxdev_read(int i2c_fd, uint8_t device_addr, uint8_t reg_addr, uint8_t *data) {
+    uint8_t *inbuff, outbuff;
+    struct i2c_rdwr_ioctl_data packets;
+    struct i2c_msg messages[2];
+
+    outbuff = reg_addr;
+    messages[0].addr = device_addr;
+    messages[0].flags= 0;
+    messages[0].len = sizeof(outbuff);
+    messages[0].buf = &outbuff;
+
+    inbuff = data;
+    messages[1].addr = device_addr;
+    messages[1].flags = I2C_M_RD;
+    messages[1].len = sizeof(*inbuff);
+    messages[1].buf = inbuff;
+
+    packets.msgs = messages;
+    packets.nmsgs = 2;
+
+    if (ioctl(i2c_fd, I2C_RDWR, &packets) < 0) {
+        DEBUG_PRINTF("ERROR: Read from I2C Device failed (%d, 0x%02x, 0x%02x) - %s\n", i2c_fd, device_addr, reg_addr, strerror(errno));
+        return LGW_I2C_ERROR;
+    }
+
+    return LGW_I2C_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int i2c_linuxdev_write(int i2c_fd, uint8_t device_addr, uint8_t reg_addr, uint8_t data) {
+    unsigned char buff[2];
+    struct i2c_rdwr_ioctl_data packets;
+    struct i2c_msg messages[1];
+
+    buff[0] = reg_addr;
+    buff[1] = data;
+
+    messages[0].addr = device_addr;
+    messages[0].flags = 0;
+    messages[0].len = sizeof(buff);
+    messages[0].buf = buff;
+
+    packets.msgs = messages;
+    packets.nmsgs = 1;
+
+    if (ioctl(i2c_fd, I2C_RDWR, &packets) < 0) {
+        DEBUG_PRINTF("ERROR: Write to I2C Device failed (%d, 0x%02x, 0x%02x) - %s\n", i2c_fd, device_addr, reg_addr, strerror(errno));
+        return LGW_I2C_ERROR;
+    }
+
+    return LGW_I2C_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int i2c_linuxdev_write_buffer(int i2c_fd, uint8_t device_addr, uint8_t *buffer, uint8_t size) {
+    struct i2c_rdwr_ioctl_data packets;
+    struct i2c_msg messages[1];
+
+    /* Check input parameters */
+    CHECK_NULL(buffer);
+
+    messages[0].addr = device_addr;
+    messages[0].flags = 0;
+    messages[0].len = size;
+    messages[0].buf = buffer;
+
+    packets.msgs = messages;
+    packets.nmsgs = 1;
+
+    if (ioctl(i2c_fd, I2C_RDWR, &packets) < 0) {
+        DEBUG_PRINTF("ERROR: Write buffer to I2C Device failed (%d, 0x%02x) - %s\n", i2c_fd, device_addr, strerror(errno));
+        return LGW_I2C_ERROR;
+    }
+
+    return LGW_I2C_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int i2c_linuxdev_close(int i2c_fd) {
+    int i;
+
+    i = close(i2c_fd);
+    if (i == 0) {
+        DEBUG_MSG("INFO: I2C port closed successfully\n");
+        return LGW_I2C_SUCCESS;
+    } else {
+        DEBUG_PRINTF("ERROR: Failed to close I2C - %s\n", strerror(errno));
+        return LGW_I2C_ERROR;
+    }
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 235 - 0
sx1302/source/loragw_lbt.c

@@ -0,0 +1,235 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    LoRa concentrator Listen-Before-Talk 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 */
+#include <stdlib.h>     /* llabs */
+
+#include "loragw_aux.h"
+#include "loragw_lbt.h"
+#include "loragw_sx1261.h"
+#include "loragw_sx1302.h"
+#include "loragw_hal.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#if DEBUG_LBT == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* As given frequencies have been converted from float to integer, some aliasing
+issues can appear, so we can't simply check for equality, but have to take some
+margin */
+static bool is_equal_freq(uint32_t a, uint32_t b) {
+    int64_t diff;
+    int64_t a64 = (int64_t)a;
+    int64_t b64 = (int64_t)b;
+
+    /* Calculate the difference */
+    diff = llabs(a64 - b64);
+
+    /* Check for acceptable diff range */
+    return ((diff <= 10000) ? true : false);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+static int is_lbt_channel(const struct lgw_conf_lbt_s * lbt_context, uint32_t freq_hz, uint8_t bandwidth) {
+    int i;
+    int lbt_channel_match = -1;
+
+    for (i = 0; i <  lbt_context->nb_channel; i++) {
+        if ((is_equal_freq(freq_hz, lbt_context->channels[i].freq_hz) == true) && (bandwidth == lbt_context->channels[i].bandwidth)) {
+            DEBUG_PRINTF("LBT: select channel %d (freq:%u Hz, bw:0x%02X)\n", i, lbt_context->channels[i].freq_hz, lbt_context->channels[i].bandwidth);
+            lbt_channel_match = i;
+            break;
+        }
+    }
+
+    /* Return the index of the LBT channel which matched */
+    return lbt_channel_match;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lgw_lbt_start(const struct lgw_conf_sx1261_s * sx1261_context, const struct lgw_pkt_tx_s * pkt) {
+    int err;
+    int lbt_channel_selected;
+    uint32_t toa_ms;
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Check if we have a LBT channel for this transmit frequency */
+    lbt_channel_selected = is_lbt_channel(&(sx1261_context->lbt_conf), pkt->freq_hz, pkt->bandwidth);
+    if (lbt_channel_selected == -1) {
+        printf("ERROR: Cannot start LBT - wrong channel\n");
+        return -1;
+    }
+
+    /* Check if the packet Time On Air exceeds the maximum allowed transmit time on this channel */
+    /* Channel sensing is checked 1.5ms before the packet departure time, so need to take this into account */
+    if (sx1261_context->lbt_conf.channels[lbt_channel_selected].transmit_time_ms * 1000 <= 1500) {
+        printf("ERROR: Cannot start LBT - channel transmit_time_ms must be > 1.5ms\n");
+        return -1;
+    }
+    toa_ms = lgw_time_on_air(pkt);
+    if ((toa_ms * 1000) > (uint32_t)(sx1261_context->lbt_conf.channels[lbt_channel_selected].transmit_time_ms * 1000 - 1500)) {
+        printf("ERROR: Cannot start LBT - packet time on air exceeds allowed transmit time (toa:%ums, max:%ums)\n", toa_ms, sx1261_context->lbt_conf.channels[lbt_channel_selected].transmit_time_ms);
+        return -1;
+    }
+
+    /* Set LBT scan frequency */
+    err = sx1261_set_rx_params(pkt->freq_hz, pkt->bandwidth);
+    if (err != 0) {
+        printf("ERROR: Cannot start LBT - unable to set sx1261 RX parameters\n");
+        return -1;
+    }
+
+    /* Start LBT */
+    err = sx1261_lbt_start(sx1261_context->lbt_conf.channels[lbt_channel_selected].scan_time_us, sx1261_context->lbt_conf.rssi_target + sx1261_context->rssi_offset);
+    if (err != 0) {
+        printf("ERROR: Cannot start LBT - sx1261 LBT start\n");
+        return -1;
+    }
+
+    _meas_time_stop(3, tm, __FUNCTION__);
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_lbt_tx_status(uint8_t rf_chain, bool * tx_ok) {
+    int err;
+    uint8_t status;
+    bool tx_timeout = false;
+    struct timeval tm_start;
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Wait for transmit to be initiated */
+    /* Bit 0 in status: TX has been initiated on Radio A */
+    /* Bit 1 in status: TX has been initiated on Radio B */
+    timeout_start(&tm_start);
+    do {
+        /* handle timeout */
+        if (timeout_check(tm_start, 500) != 0) {
+            printf("ERROR: %s: TIMEOUT on TX start, not started\n", __FUNCTION__);
+            tx_timeout = true;
+            /* we'll still perform the AGC clear status and return an error to upper layer */
+            break;
+        }
+
+        /* get tx status */
+        err = sx1302_agc_status(&status);
+        if (err != 0) {
+            printf("ERROR: %s: failed to get AGC status\n", __FUNCTION__);
+            return -1;
+        }
+        wait_ms(1);
+    } while ((status & (1 << rf_chain)) == 0x00);
+
+    if (tx_timeout == false) {
+        /* Check if the packet has been transmitted or blocked by LBT */
+        /* Bit 6 in status: Radio A is not allowed to transmit */
+        /* Bit 7 in status: Radio B is not allowed to transmit */
+        if (TAKE_N_BITS_FROM(status, ((rf_chain == 0) ? 6 : 7), 1) == 0) {
+            *tx_ok = true;
+        } else {
+            *tx_ok = false;
+        }
+    }
+
+    /* Clear AGC transmit status */
+    sx1302_agc_mailbox_write(0, 0xFF);
+
+    /* Wait for transmit status to be cleared */
+    timeout_start(&tm_start);
+    do {
+        /* handle timeout */
+        if (timeout_check(tm_start, 500) != 0) {
+            printf("ERROR: %s: TIMEOUT on TX start (AGC clear status)\n", __FUNCTION__);
+            tx_timeout = true;
+            break;
+        }
+
+        /* get tx status */
+        err = sx1302_agc_status(&status);
+        if (err != 0) {
+            printf("ERROR: %s: failed to get AGC status\n", __FUNCTION__);
+            return -1;
+        }
+        wait_ms(1);
+    } while (status != 0x00);
+
+    /* Acknoledge */
+    sx1302_agc_mailbox_write(0, 0x00);
+
+    _meas_time_stop(3, tm, __FUNCTION__);
+
+    if (tx_timeout == true) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_lbt_stop(void) {
+    int err;
+
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    err = sx1261_lbt_stop();
+    if (err != 0) {
+        printf("ERROR: Cannot stop LBT - failed\n");
+        return -1;
+    }
+
+    _meas_time_stop(3, tm, __FUNCTION__);
+
+    return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 694 - 0
sx1302/source/loragw_mcu.c

@@ -0,0 +1,694 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    Host specific functions to address the LoRa concentrator registers through
+    a USB interface.
+    Single-byte read/write and burst read/write.
+
+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 <stdlib.h>     /* rand */
+#include <unistd.h>     /* lseek, close */
+#include <string.h>     /* memset */
+#include <errno.h>      /* Error number definitions */
+#include <termios.h>    /* POSIX terminal control definitions */
+
+#include "loragw_mcu.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_MCU == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout, fmt, args)
+    #define CHECK_NULL(a)                if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return -1;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return -1;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#if DEBUG_MCU == 1
+#define DEBUG_VERBOSE 0
+#endif
+
+#define HEADER_CMD_SIZE 4
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE TYPES -------------------------------------------------------- */
+
+typedef struct spi_req_bulk_s {
+    uint16_t size;
+    uint8_t nb_req;
+    uint8_t buffer[LGW_USB_BURST_CHUNK];
+} spi_req_bulk_t;
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES  --------------------------------------------------- */
+
+static uint8_t buf_hdr[HEADER_CMD_SIZE];
+
+static spi_req_bulk_t spi_bulk_buffer = {
+    .size = 0,
+    .nb_req = 0,
+    .buffer = { 0 }
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+int spi_req_bulk_insert(spi_req_bulk_t * bulk_buffer, uint8_t * req, uint16_t req_size) {
+    /* Check input parameters */
+    CHECK_NULL(bulk_buffer);
+    CHECK_NULL(req);
+
+    if (bulk_buffer->nb_req == 255) {
+        printf("ERROR: cannot insert a new SPI request in bulk buffer - too many requests\n");
+        return -1;
+    }
+
+    if ((bulk_buffer->size + req_size) > LGW_USB_BURST_CHUNK) {
+        printf("ERROR: cannot insert a new SPI request in bulk buffer - buffer full\n");
+        return -1;
+    }
+
+    /* Add a new request entry in storage buffer */
+    memcpy(bulk_buffer->buffer + bulk_buffer->size, req, req_size);
+
+    bulk_buffer->nb_req += 1;
+    bulk_buffer->size += req_size;
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint32_t bytes_be_to_uint32_le(const uint8_t * bytes) {
+    uint32_t val = 0;
+
+    if (bytes != NULL) {
+        /* Big endian to Little Endian */
+        val  = (uint32_t)(bytes[0] << 24);
+        val |= (uint32_t)(bytes[1] << 16);
+        val |= (uint32_t)(bytes[2] << 8);
+        val |= (uint32_t)(bytes[3] << 0);
+    }
+
+    return val;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int32_t bytes_be_to_int32_le(const uint8_t * bytes) {
+    int32_t val = 0;
+
+    if (bytes != NULL) {
+        /* Big endian to Little Endian */
+        val  = (int32_t)(bytes[0] << 24);
+        val |= (int32_t)(bytes[1] << 16);
+        val |= (int32_t)(bytes[2] << 8);
+        val |= (int32_t)(bytes[3] << 0);
+    }
+
+    return val;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+const char * cmd_get_str(const uint8_t cmd) {
+    switch (cmd) {
+        case ORDER_ID__REQ_PING:
+            return "REQ_PING";
+        case ORDER_ID__REQ_GET_STATUS:
+            return "REQ_GET_STATUS";
+        case ORDER_ID__REQ_BOOTLOADER_MODE:
+            return "REQ_BOOTLOADER_MODE";
+        case ORDER_ID__REQ_RESET:
+            return "REQ_RESET";
+        case ORDER_ID__REQ_WRITE_GPIO:
+            return "REQ_WRITE_GPIO";
+        case ORDER_ID__REQ_MULTIPLE_SPI:
+            return "REQ_MULTIPLE_SPI";
+        default:
+            return "UNKNOWN";
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint8_t cmd_get_id(const uint8_t * bytes) {
+    return bytes[0];
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint16_t cmd_get_size(const uint8_t * bytes) {
+    return (uint16_t)(bytes[1] << 8) | bytes[2];
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint8_t cmd_get_type(const uint8_t * bytes) {
+    return bytes[3];
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+const char * spi_status_get_str(const uint8_t status) {
+    switch (status) {
+        case SPI_STATUS_OK:
+            return "SPI_STATUS_OK";
+        case SPI_STATUS_FAIL:
+            return "SPI_STATUS_FAIL";
+        case SPI_STATUS_WRONG_PARAM:
+            return "SPI_STATUS_WRONG_PARAM";
+        case SPI_STATUS_TIMEOUT:
+            return "SPI_STATUS_TIMEOUT";
+        default:
+            return "SPI_STATUS_UNKNOWN";
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int write_req(int fd, order_id_t cmd, const uint8_t * payload, uint16_t payload_size ) {
+    uint8_t buf_w[HEADER_CMD_SIZE];
+    int n;
+    /* performances variables */
+    struct timeval tm;
+    /* debug variables */
+#if DEBUG_MCU == 1
+    struct timeval write_tv;
+#endif
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Check input params */
+    if (payload_size > MAX_SIZE_COMMAND) {
+        printf("ERROR: payload size exceeds maximum transfer size (req:%u, max:%d)\n", payload_size, MAX_SIZE_COMMAND);
+        return -1;
+    }
+
+    /* Write command header */
+    buf_w[0] = rand() % 255;
+    buf_w[1] = (uint8_t)(payload_size >> 8); /* MSB */
+    buf_w[2] = (uint8_t)(payload_size >> 0); /* LSB */
+    buf_w[3] = cmd;
+    n = write(fd, buf_w, HEADER_CMD_SIZE);
+    if (n < 0) {
+        printf("ERROR: failed to write command header to com port\n");
+        return -1;
+    }
+
+    /* Write command payload */
+    if (payload_size > 0) {
+        if (payload == NULL) {
+            printf("ERROR: invalid payload\n");
+            return -1;
+        }
+        n = write(fd, payload, payload_size);
+        if (n < 0) {
+            printf("ERROR: failed to write command payload to com port\n");
+            return -1;
+        }
+    }
+
+#if DEBUG_MCU == 1
+    gettimeofday(&write_tv, NULL);
+#endif
+    DEBUG_PRINTF("\nINFO: %ld.%ld: write_req 0x%02X (%s) done, id:0x%02X, size:%u\n", write_tv.tv_sec, write_tv.tv_usec, cmd, cmd_get_str(cmd), buf_w[0], payload_size);
+
+#if DEBUG_VERBOSE
+    int i;
+    for (i = 0; i < 4; i++) {
+        printf("%02X ", buf_w[i]);
+    }
+    for (i = 0; i < payload_size; i++) {
+        printf("%02X ", payload[i]);
+    }
+    printf("\n");
+#endif
+
+    /* Compute time spent in this function */
+    _meas_time_stop(5, tm, __FUNCTION__);
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int read_ack(int fd, uint8_t * hdr, uint8_t * buf, size_t buf_size) {
+#if DEBUG_VERBOSE
+    int i;
+#endif
+    int n;
+    size_t size;
+    int nb_read = 0;
+    /* performances variables */
+    struct timeval tm;
+    /* debug variables */
+#if DEBUG_MCU == 1
+    struct timeval read_tv;
+#endif
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Read message header first, handle EINTR as it is a blocking call */
+    do {
+        n = read(fd, &hdr[0], (size_t)HEADER_CMD_SIZE);
+    } while (n == -1 && errno == EINTR);
+
+    if (n == -1) {
+        perror("ERROR: Unable to read /dev/ttyACMx - ");
+        return -1;
+    } else {
+#if DEBUG_MCU == 1
+        gettimeofday(&read_tv, NULL);
+#endif
+        DEBUG_PRINTF("INFO: %ld.%ld: read %d bytes for header from gateway\n", read_tv.tv_sec, read_tv.tv_usec, n);
+    }
+
+    /* Compute time spent in this function */
+    _meas_time_stop(5, tm, "read_ack(hdr)");
+
+#if DEBUG_VERBOSE
+    printf("read_ack(hdr):");
+    /* debug print */
+    for (i = 0; i < (int)(HEADER_CMD_SIZE); i++) {
+        printf("%02X ", hdr[i]);
+    }
+    printf("\n");
+#endif
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Check if the command id is valid */
+    if ((cmd_get_type(hdr) < 0x40) || (cmd_get_type(hdr) > 0x46)) {
+        printf("ERROR: received wrong ACK type (0x%02X)\n", cmd_get_type(hdr));
+        return -1;
+    }
+
+    /* Get remaining payload size (metadata + pkt payload) */
+    size = (size_t)cmd_get_size(hdr);
+    if (size > buf_size) {
+        printf("ERROR: not enough memory to store all data (%zd)\n", size);
+        return -1;
+    }
+
+    /* Read payload if any */
+    if (size > 0) {
+        do {
+            /* handle EINTR as it is a blocking call */
+            do {
+                n = read(fd, &buf[nb_read], size - nb_read);
+            } while (n == -1 && errno == EINTR);
+
+            if (n == -1) {
+                perror("ERROR: Unable to read /dev/ttyACMx - ");
+                return -1;
+            } else {
+#if DEBUG_MCU == 1
+                gettimeofday(&read_tv, NULL);
+#endif
+                DEBUG_PRINTF("INFO: %ld.%ld: read %d bytes from gateway\n", read_tv.tv_sec, read_tv.tv_usec, n);
+                nb_read += n;
+            }
+        } while (nb_read < (int)size); /* we want to read only the expected payload, not more */
+
+#if DEBUG_VERBOSE
+        /* debug print */
+        printf("read_ack(pld):");
+        for (i = 0; i < (int)size; i++) {
+            printf("%02X ", buf[i]);
+        }
+        printf("\n");
+#endif
+    }
+
+    /* Compute time spent in this function */
+    _meas_time_stop(5, tm, "read_ack(payload)");
+
+    return nb_read;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int decode_ack_ping(const uint8_t * hdr, const uint8_t * payload, s_ping_info * info) {
+    /* sanity checks */
+    if ((hdr == NULL) || (payload == NULL) || (info == NULL)) {
+        printf("ERROR: invalid parameter\n");
+        return -1;
+    }
+
+    if (cmd_get_type(hdr) != ORDER_ID__ACK_PING) {
+        printf("ERROR: wrong ACK type for PING (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_PING, cmd_get_type(hdr));
+        return -1;
+    }
+
+    /* payload info */
+    info->unique_id_high = bytes_be_to_uint32_le(&payload[ACK_PING__UNIQUE_ID_0]);
+    info->unique_id_mid  = bytes_be_to_uint32_le(&payload[ACK_PING__UNIQUE_ID_4]);
+    info->unique_id_low  = bytes_be_to_uint32_le(&payload[ACK_PING__UNIQUE_ID_8]);
+
+    memcpy(info->version, &payload[ACK_PING__VERSION_0], (sizeof info->version) - 1);
+    info->version[(sizeof info->version) - 1] = '\0'; /* terminate string */
+
+#if DEBUG_VERBOSE
+    DEBUG_MSG   ("## ACK_PING\n");
+    DEBUG_PRINTF("   id:           0x%02X\n", cmd_get_id(hdr));
+    DEBUG_PRINTF("   size:         %u\n", cmd_get_size(hdr));
+    DEBUG_PRINTF("   unique_id:    0x%08X%08X%08X\n", info->unique_id_high, info->unique_id_mid, info->unique_id_low);
+    DEBUG_PRINTF("   FW version:   %s\n", info->version);
+#endif
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int decode_ack_bootloader_mode(const uint8_t * hdr) {
+     /* sanity checks */
+    if (hdr == NULL) {
+        printf("ERROR: invalid parameter\n");
+        return -1;
+    }
+
+    if (cmd_get_type(hdr) != ORDER_ID__ACK_BOOTLOADER_MODE) {
+        printf("ERROR: wrong ACK type for ACK_BOOTLOADER_MODE (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_BOOTLOADER_MODE, cmd_get_type(hdr));
+        return -1;
+    }
+
+#if DEBUG_VERBOSE
+    DEBUG_MSG   ("## ACK_BOOTLOADER_MODE\n");
+    DEBUG_PRINTF("   id:           0x%02X\n", cmd_get_id(hdr));
+    DEBUG_PRINTF("   size:         %u\n", cmd_get_size(hdr));
+#endif
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int decode_ack_get_status(const uint8_t * hdr, const uint8_t * payload, s_status * status) {
+    int16_t temperature_sensor;
+
+    /* sanity checks */
+    if ((payload == NULL) || (status == NULL)) {
+        printf("ERROR: invalid parameter\n");
+        return -1;
+    }
+
+    if (cmd_get_type(hdr) != ORDER_ID__ACK_GET_STATUS) {
+        printf("ERROR: wrong ACK type for GET_STATUS (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_GET_STATUS, cmd_get_type(hdr));
+        return -1;
+    }
+
+    /* payload info */
+    status->system_time_ms = bytes_be_to_uint32_le(&payload[ACK_GET_STATUS__SYSTEM_TIME_31_24]);
+
+    temperature_sensor = (int16_t)(payload[ACK_GET_STATUS__TEMPERATURE_15_8] << 8) |
+                         (int16_t)(payload[ACK_GET_STATUS__TEMPERATURE_7_0]  << 0);
+    status->temperature = (float)temperature_sensor / 100.0;
+
+
+#if DEBUG_VERBOSE
+    DEBUG_MSG   ("## ACK_GET_STATUS\n");
+    DEBUG_PRINTF("   id:            0x%02X\n", cmd_get_id(hdr));
+    DEBUG_PRINTF("   size:          %u\n", cmd_get_size(hdr));
+    DEBUG_PRINTF("   sys_time:      %u\n", status->system_time_ms);
+    DEBUG_PRINTF("   temperature:   %.1f\n", status->temperature);
+#endif
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int decode_ack_gpio_access(const uint8_t * hdr, const uint8_t * payload, uint8_t * write_status) {
+    if ((hdr == NULL) || (payload == NULL) || (write_status == NULL)) {
+        printf("ERROR: invalid parameter\n");
+        return -1;
+    }
+
+    if (cmd_get_type(hdr) != ORDER_ID__ACK_WRITE_GPIO) {
+        printf("ERROR: wrong ACK type for WRITE_GPIO (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_WRITE_GPIO, cmd_get_type(hdr));
+        return -1;
+    }
+
+    /* payload info */
+    *write_status = payload[ACK_GPIO_WRITE__STATUS];
+
+#if DEBUG_VERBOSE
+    DEBUG_MSG   ("## ACK_WRITE_GPIO\n");
+    DEBUG_PRINTF("   id:           0x%02X\n", cmd_get_id(hdr));
+    DEBUG_PRINTF("   size:         %u\n", cmd_get_size(hdr));
+    DEBUG_PRINTF("   status:       %u\n", *write_status);
+#endif
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int decode_ack_spi_bulk(const uint8_t * hdr, const uint8_t * payload) {
+    uint8_t req_id, req_type, req_status;
+    uint16_t frame_size;
+    int i;
+
+    /* sanity checks */
+    if ((hdr == NULL) || (payload == NULL)) {
+        printf("ERROR: invalid parameter\n");
+        return -1;
+    }
+
+    if (cmd_get_type(hdr) != ORDER_ID__ACK_MULTIPLE_SPI) {
+        printf("ERROR: wrong ACK type for ACK_MULTIPLE_SPI (expected:0x%02X, got 0x%02X)\n", ORDER_ID__ACK_MULTIPLE_SPI, cmd_get_type(hdr));
+        return -1;
+    }
+
+#if DEBUG_VERBOSE
+    DEBUG_MSG   ("## ACK_SPI_BULK\n");
+    DEBUG_PRINTF("   id:           0x%02X\n", cmd_get_id(hdr));
+    DEBUG_PRINTF("   size:         %u\n", cmd_get_size(hdr));
+#endif
+
+    i = 0;
+    while (i < cmd_get_size(hdr)) {
+        /* parse the request */
+        req_id      = payload[i + 0];
+        req_type    = payload[i + 1];
+        if (req_type != MCU_SPI_REQ_TYPE_READ_WRITE && req_type != MCU_SPI_REQ_TYPE_READ_MODIFY_WRITE) {
+            printf("ERROR: %s: wrong type for SPI request %u (0x%02X)\n", __FUNCTION__, req_id, req_type);
+            return -1;
+        }
+        req_status  = payload[i + 2];
+        if (req_status != 0) {
+            /* Exit if any of the requests failed */
+            printf("ERROR: %s: SPI request %u failed with %u - %s\n", __FUNCTION__, req_id, req_status, spi_status_get_str(req_status));
+            return -1;
+        }
+#if DEBUG_VERBOSE
+        DEBUG_PRINTF("   ----- REQ_SPI %u -----\n", req_id);
+        DEBUG_PRINTF("   type %s\n", (req_type == MCU_SPI_REQ_TYPE_READ_WRITE) ? "read/write" : "read-modify-write");
+        DEBUG_PRINTF("   status %u\n", req_status);
+#endif
+        /* Move to the next REQ */
+        if (req_type == MCU_SPI_REQ_TYPE_READ_WRITE) {
+            frame_size = (uint16_t)(payload[i + 3] << 8) | (uint16_t)(payload[i + 4]);
+#if DEBUG_VERBOSE
+            int j;
+            DEBUG_PRINTF("   RAW SPI frame (sz:%u): ", frame_size);
+            for (j = 0; j < frame_size; j++) {
+                DEBUG_PRINTF(" %02X", payload[i + 5 + j]);
+            }
+            DEBUG_MSG("\n");
+#endif
+            i += (5 + frame_size); /* REQ ACK metadata + SPI raw frame */
+        } else {
+#if DEBUG_VERBOSE
+            DEBUG_PRINTF("   read value     0x%02X\n", payload[i + 3]);
+            DEBUG_PRINTF("   modified value 0x%02X\n", payload[i + 4]);
+#endif
+            i += 5;
+        }
+    }
+
+    return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int mcu_ping(int fd, s_ping_info * info) {
+    uint8_t buf_ack[ACK_PING_SIZE];
+
+    CHECK_NULL(info);
+
+    if (write_req(fd, ORDER_ID__REQ_PING, NULL, 0) != 0) {
+        printf("ERROR: failed to write PING request\n");
+        return -1;
+    }
+
+    if (read_ack(fd, buf_hdr, buf_ack, sizeof buf_ack) < 0) {
+        printf("ERROR: failed to read PING ack\n");
+        return -1;
+    }
+
+    if (decode_ack_ping(buf_hdr, buf_ack, info) != 0) {
+        printf("ERROR: invalid PING ack\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int mcu_boot(int fd) {
+    if (write_req(fd, ORDER_ID__REQ_BOOTLOADER_MODE, NULL, 0) != 0) {
+        printf("ERROR: failed to write BOOTLOADER_MODE request\n");
+        return -1;
+    }
+
+    if (read_ack(fd, buf_hdr, NULL, 0) < 0) {
+        printf("ERROR: failed to read BOOTLOADER_MODE ack\n");
+        return -1;
+    }
+
+    if (decode_ack_bootloader_mode(buf_hdr) != 0) {
+        printf("ERROR: invalid BOOTLOADER_MODE ack\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int mcu_get_status(int fd, s_status * status) {
+    uint8_t buf_ack[ACK_GET_STATUS_SIZE];
+
+    CHECK_NULL(status);
+
+    if (write_req(fd, ORDER_ID__REQ_GET_STATUS, NULL, 0) != 0) {
+        printf("ERROR: failed to write GET_STATUS request\n");
+        return -1;
+    }
+
+    if (read_ack(fd, buf_hdr, buf_ack, sizeof buf_ack) < 0) {
+        printf("ERROR: failed to read GET_STATUS ack\n");
+        return -1;
+    }
+
+    if (decode_ack_get_status(buf_hdr, buf_ack, status) != 0) {
+        printf("ERROR: invalid GET_STATUS ack\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int mcu_gpio_write(int fd, uint8_t gpio_port, uint8_t gpio_id, uint8_t gpio_value) {
+    uint8_t status;
+    uint8_t buf_req[REQ_WRITE_GPIO_SIZE];
+    uint8_t buf_ack[ACK_GPIO_WRITE_SIZE];
+
+    buf_req[REQ_WRITE_GPIO__PORT]   = gpio_port;
+    buf_req[REQ_WRITE_GPIO__PIN]    = gpio_id;
+    buf_req[REQ_WRITE_GPIO__STATE]  = gpio_value;
+    if (write_req(fd, ORDER_ID__REQ_WRITE_GPIO, buf_req, REQ_WRITE_GPIO_SIZE) != 0) {
+        printf("ERROR: failed to write REQ_WRITE_GPIO request\n");
+        return -1;
+    }
+
+    if (read_ack(fd, buf_hdr, buf_ack, sizeof buf_ack) < 0) {
+        printf("ERROR: failed to read PING ack\n");
+        return -1;
+    }
+
+    if (decode_ack_gpio_access(buf_hdr, buf_ack, &status) != 0) {
+        printf("ERROR: invalid REQ_WRITE_GPIO ack\n");
+        return -1;
+    }
+
+    if (status != 0) {
+        printf("ERROR: Failed to write GPIO (port:%u id:%u value:%u)\n", gpio_port, gpio_id, gpio_value);
+        return -1;
+    }
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int mcu_spi_write(int fd, uint8_t * in_out_buf, size_t buf_size) {
+    /* Check input parameters */
+    CHECK_NULL(in_out_buf);
+
+    if (write_req(fd, ORDER_ID__REQ_MULTIPLE_SPI, in_out_buf, buf_size) != 0) {
+        printf("ERROR: failed to write REQ_MULTIPLE_SPI request\n");
+        return -1;
+    }
+
+    if (read_ack(fd, buf_hdr, in_out_buf, buf_size) < 0) {
+        printf("ERROR: failed to read REQ_MULTIPLE_SPI ack\n");
+        return -1;
+    }
+
+    if (decode_ack_spi_bulk(buf_hdr, in_out_buf) != 0) {
+        printf("ERROR: invalid REQ_MULTIPLE_SPI ack\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int mcu_spi_store(uint8_t * in_out_buf, size_t buf_size) {
+    CHECK_NULL(in_out_buf);
+
+    return spi_req_bulk_insert(&spi_bulk_buffer, in_out_buf, buf_size);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int mcu_spi_flush(int fd) {
+    /* Write pending SPI requests to MCU */
+    if (mcu_spi_write(fd, spi_bulk_buffer.buffer, spi_bulk_buffer.size) != 0) {
+        printf("ERROR: %s: failed to write SPI requests to MCU\n", __FUNCTION__);
+        return -1;
+    }
+
+    /* Reset bulk storage buffer */
+    spi_bulk_buffer.nb_req = 0;
+    spi_bulk_buffer.size = 0;
+
+    return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1423 - 0
sx1302/source/loragw_reg.c


+ 382 - 0
sx1302/source/loragw_spi.c

@@ -0,0 +1,382 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Host specific functions to address the LoRa concentrator registers through
+    a SPI interface.
+    Single-byte read/write and burst read/write.
+    Could be used with multiple SPI ports in parallel (explicit file descriptor)
+
+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 <sys/ioctl.h>
+#include <linux/spi/spidev.h>
+
+#include "loragw_spi.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_COM == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+    #define CHECK_NULL(a)                if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return LGW_SPI_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define READ_ACCESS     0x00
+#define WRITE_ACCESS    0x80
+
+#define LGW_BURST_CHUNK     1024
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/* SPI initialization and configuration */
+int lgw_spi_open(const char * com_path, void **com_target_ptr) {
+    int *spi_device = NULL;
+    int dev;
+    int a=0, b=0;
+    int i;
+
+    /* check input variables */
+    CHECK_NULL(com_path);
+    CHECK_NULL(com_target_ptr);
+
+    /* allocate memory for the device descriptor */
+    spi_device = malloc(sizeof(int));
+    if (spi_device == NULL) {
+        DEBUG_MSG("ERROR: MALLOC FAIL\n");
+        return LGW_SPI_ERROR;
+    }
+
+    /* open SPI device */
+    dev = open(com_path, O_RDWR);
+    if (dev < 0) {
+        DEBUG_PRINTF("ERROR: failed to open SPI device %s\n", com_path);
+        return LGW_SPI_ERROR;
+    }
+
+    /* setting SPI mode to 'mode 0' */
+    i = SPI_MODE_0;
+    a = ioctl(dev, SPI_IOC_WR_MODE, &i);
+    b = ioctl(dev, SPI_IOC_RD_MODE, &i);
+    if ((a < 0) || (b < 0)) {
+        DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n");
+        close(dev);
+        free(spi_device);
+        return LGW_SPI_ERROR;
+    }
+
+    /* setting SPI max clk (in Hz) */
+    i = SPI_SPEED;
+    a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i);
+    b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i);
+    if ((a < 0) || (b < 0)) {
+        DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n");
+        close(dev);
+        free(spi_device);
+        return LGW_SPI_ERROR;
+    }
+
+    /* setting SPI to MSB first */
+    i = 0;
+    a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i);
+    b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i);
+    if ((a < 0) || (b < 0)) {
+        DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n");
+        close(dev);
+        free(spi_device);
+        return LGW_SPI_ERROR;
+    }
+
+    /* setting SPI to 8 bits per word */
+    i = 0;
+    a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i);
+    b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i);
+    if ((a < 0) || (b < 0)) {
+        DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n");
+        close(dev);
+        return LGW_SPI_ERROR;
+    }
+
+    *spi_device = dev;
+    *com_target_ptr = (void *)spi_device;
+    DEBUG_MSG("Note: SPI port opened and configured ok\n");
+    return LGW_SPI_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* SPI release */
+int lgw_spi_close(void *com_target) {
+    int spi_device;
+    int a;
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+
+    /* close file & deallocate file descriptor */
+    spi_device = *(int *)com_target; /* must check that spi_target is not null beforehand */
+    a = close(spi_device);
+    free(com_target);
+
+    /* determine return code */
+    if (a < 0) {
+        DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n");
+        return LGW_SPI_ERROR;
+    } else {
+        DEBUG_MSG("Note: SPI port closed\n");
+        return LGW_SPI_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple write */
+int lgw_spi_w(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t data) {
+    int spi_device;
+    uint8_t out_buf[4];
+    uint8_t command_size;
+    struct spi_ioc_transfer k;
+    int a;
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+
+    spi_device = *(int *)com_target; /* must check that spi_target is not null beforehand */
+
+    /* prepare frame to be sent */
+    out_buf[0] = spi_mux_target;
+    out_buf[1] = WRITE_ACCESS | ((address >> 8) & 0x7F);
+    out_buf[2] =                ((address >> 0) & 0xFF);
+    out_buf[3] = data;
+    command_size = 4;
+
+    /* I/O transaction */
+    memset(&k, 0, sizeof(k)); /* clear k */
+    k.tx_buf = (unsigned long) out_buf;
+    k.len = command_size;
+    k.speed_hz = SPI_SPEED;
+    k.cs_change = 0;
+    k.bits_per_word = 8;
+    a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+
+    /* determine return code */
+    if (a != (int)k.len) {
+        DEBUG_MSG("ERROR: SPI WRITE FAILURE\n");
+        return LGW_SPI_ERROR;
+    } else {
+        DEBUG_MSG("Note: SPI write success\n");
+        return LGW_SPI_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple read */
+int lgw_spi_r(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data) {
+    int spi_device;
+    uint8_t out_buf[5];
+    uint8_t command_size;
+    uint8_t in_buf[ARRAY_SIZE(out_buf)];
+    struct spi_ioc_transfer k;
+    int a;
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    spi_device = *(int *)com_target; /* must check that com_target is not null beforehand */
+
+    /* prepare frame to be sent */
+    out_buf[0] = spi_mux_target;
+    out_buf[1] = READ_ACCESS | ((address >> 8) & 0x7F);
+    out_buf[2] =               ((address >> 0) & 0xFF);
+    out_buf[3] = 0x00;
+    out_buf[4] = 0x00;
+    command_size = 5;
+
+    /* I/O transaction */
+    memset(&k, 0, sizeof(k)); /* clear k */
+    k.tx_buf = (unsigned long) out_buf;
+    k.rx_buf = (unsigned long) in_buf;
+    k.len = command_size;
+    k.cs_change = 0;
+    a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+
+    /* determine return code */
+    if (a != (int)k.len) {
+        DEBUG_MSG("ERROR: SPI READ FAILURE\n");
+        return LGW_SPI_ERROR;
+    } else {
+        DEBUG_MSG("Note: SPI read success\n");
+        *data = in_buf[command_size - 1];
+        return LGW_SPI_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Single Byte Read-Modify-Write */
+int lgw_spi_rmw(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t offs, uint8_t leng, uint8_t data) {
+    int spi_stat = LGW_SPI_SUCCESS;
+    uint8_t buf[4] = "\x00\x00\x00\x00";
+
+    /* Read */
+    spi_stat += lgw_spi_r(com_target, spi_mux_target, address, &buf[0]);
+
+    /* Modify */
+    buf[1] = ((1 << leng) - 1) << offs; /* bit mask */
+    buf[2] = ((uint8_t)data) << offs; /* new data offsetted */
+    buf[3] = (~buf[1] & buf[0]) | (buf[1] & buf[2]); /* mixing old & new data */
+
+    /* Write */
+    spi_stat += lgw_spi_w(com_target, spi_mux_target, address, buf[3]);
+
+    return spi_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) write */
+int lgw_spi_wb(void *com_target, uint8_t spi_mux_target, uint16_t address, const uint8_t *data, uint16_t size) {
+    int spi_device;
+    uint8_t command[3];
+    uint8_t command_size;
+    struct spi_ioc_transfer k[2];
+    int size_to_do, chunk_size, offset;
+    int byte_transfered = 0;
+    int i;
+
+    /* check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+    if (size == 0) {
+        DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+        return LGW_SPI_ERROR;
+    }
+
+    spi_device = *(int *)com_target; /* must check that com_target is not null beforehand */
+
+    /* prepare command byte */
+    command[0] = spi_mux_target;
+    command[1] = WRITE_ACCESS | ((address >> 8) & 0x7F);
+    command[2] =                ((address >> 0) & 0xFF);
+    command_size = 3;
+    size_to_do = size;
+
+    /* I/O transaction */
+    memset(&k, 0, sizeof(k)); /* clear k */
+    k[0].tx_buf = (unsigned long) &command[0];
+    k[0].len = command_size;
+    k[0].cs_change = 0;
+    k[1].cs_change = 0;
+    for (i=0; size_to_do > 0; ++i) {
+        chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK;
+        offset = i * LGW_BURST_CHUNK;
+        k[1].tx_buf = (unsigned long)(data + offset);
+        k[1].len = chunk_size;
+        byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len );
+        DEBUG_PRINTF("BURST WRITE: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered);
+        size_to_do -= chunk_size; /* subtract the quantity of data already transferred */
+    }
+
+    /* determine return code */
+    if (byte_transfered != size) {
+        DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n");
+        return LGW_SPI_ERROR;
+    } else {
+        DEBUG_MSG("Note: SPI burst write success\n");
+        return LGW_SPI_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) read */
+int lgw_spi_rb(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data, uint16_t size) {
+    int spi_device;
+    uint8_t command[4];
+    uint8_t command_size;
+    struct spi_ioc_transfer k[2];
+    int size_to_do, chunk_size, offset;
+    int byte_transfered = 0;
+    int i;
+
+    /* check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+    if (size == 0) {
+        DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n");
+        return LGW_SPI_ERROR;
+    }
+
+    spi_device = *(int *)com_target; /* must check that com_target is not null beforehand */
+
+    /* prepare command byte */
+    command[0] = spi_mux_target;
+    command[1] = READ_ACCESS | ((address >> 8) & 0x7F);
+    command[2] =               ((address >> 0) & 0xFF);
+    command[3] = 0x00;
+    command_size = 4;
+    size_to_do = size;
+
+    /* I/O transaction */
+    memset(&k, 0, sizeof(k)); /* clear k */
+    k[0].tx_buf = (unsigned long) &command[0];
+    k[0].len = command_size;
+    k[0].cs_change = 0;
+    k[1].cs_change = 0;
+    for (i=0; size_to_do > 0; ++i) {
+        chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK;
+        offset = i * LGW_BURST_CHUNK;
+        k[1].rx_buf = (unsigned long)(data + offset);
+        k[1].len = chunk_size;
+        byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len );
+        DEBUG_PRINTF("BURST READ: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered);
+        size_to_do -= chunk_size;  /* subtract the quantity of data already transferred */
+    }
+
+    /* determine return code */
+    if (byte_transfered != size) {
+        DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n");
+        return LGW_SPI_ERROR;
+    } else {
+        DEBUG_MSG("Note: SPI burst read success\n");
+        return LGW_SPI_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint16_t lgw_spi_chunk_size(void) {
+    return (uint16_t)LGW_BURST_CHUNK;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 183 - 0
sx1302/source/loragw_stts751.c

@@ -0,0 +1,183 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Basic driver for ST ts751 temperature sensor
+
+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_i2c.h"
+#include "loragw_stts751.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_I2C == 1
+    #define DEBUG_MSG(str)              fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)  fprintf(stdout,"%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 STTS751_REG_TEMP_H      0x00
+#define STTS751_REG_STATUS      0x01
+#define STTS751_STATUS_TRIPT    BIT(0)
+#define STTS751_STATUS_TRIPL    BIT(5)
+#define STTS751_STATUS_TRIPH    BIT(6)
+#define STTS751_REG_TEMP_L      0x02
+#define STTS751_REG_CONF        0x03
+#define STTS751_CONF_RES_MASK   0x0C
+#define STTS751_CONF_RES_SHIFT  2
+#define STTS751_CONF_EVENT_DIS  BIT(7)
+#define STTS751_CONF_STOP       BIT(6)
+#define STTS751_REG_RATE        0x04
+#define STTS751_REG_HLIM_H      0x05
+#define STTS751_REG_HLIM_L      0x06
+#define STTS751_REG_LLIM_H      0x07
+#define STTS751_REG_LLIM_L      0x08
+#define STTS751_REG_TLIM        0x20
+#define STTS751_REG_HYST        0x21
+#define STTS751_REG_SMBUS_TO    0x22
+
+#define STTS751_REG_PROD_ID     0xFD
+#define STTS751_REG_MAN_ID      0xFE
+#define STTS751_REG_REV_ID      0xFF
+
+#define STTS751_0_PROD_ID       0x00
+#define STTS751_1_PROD_ID       0x01
+#define ST_MAN_ID               0x53
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int stts751_configure(int i2c_fd, uint8_t i2c_addr) {
+    int err;
+    uint8_t val;
+
+    /* Check Input Params */
+    if (i2c_fd <= 0) {
+        printf("ERROR: invalid I2C file descriptor\n");
+        return LGW_I2C_ERROR;
+    }
+
+    DEBUG_PRINTF("INFO: configuring STTS751 temperature sensor on 0x%02X...\n", i2c_addr);
+
+    /* Get product ID  and test which sensor is mounted */
+    err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_PROD_ID, &val);
+    if (err != 0) {
+        DEBUG_PRINTF("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err);
+        return LGW_I2C_ERROR;
+    }
+    switch (val) {
+        case STTS751_0_PROD_ID:
+            DEBUG_MSG("INFO: Product ID: STTS751-0\n");
+            break;
+        case STTS751_1_PROD_ID:
+            DEBUG_MSG("INFO: Product ID: STTS751-1\n");
+            break;
+        default:
+            printf("ERROR: Product ID: UNKNOWN\n");
+            return LGW_I2C_ERROR;
+    }
+
+    /* Get Manufacturer ID */
+    err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_MAN_ID, &val);
+    if (err != 0) {
+        DEBUG_PRINTF("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err);
+        return LGW_I2C_ERROR;
+    }
+    if (val != ST_MAN_ID) {
+        printf("ERROR: Manufacturer ID: UNKNOWN\n");
+        return LGW_I2C_ERROR;
+    } else {
+        DEBUG_PRINTF("INFO: Manufacturer ID: 0x%02X\n", val);
+    }
+
+    /* Get revision number */
+    err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_REV_ID, &val);
+    if (err != 0) {
+        DEBUG_PRINTF("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err);
+        return LGW_I2C_ERROR;
+    }
+    DEBUG_PRINTF("INFO: Revision number: 0x%02X\n", val);
+
+    /* Set conversion resolution to 12 bits */
+    err = i2c_linuxdev_write(i2c_fd, i2c_addr, STTS751_REG_CONF, 0x8C); /* TODO: do not hardcode the whole byte */
+    if (err != 0) {
+        DEBUG_PRINTF("ERROR: failed to write I2C device 0x%02X (err=%i)\n", i2c_addr, err);
+        return LGW_I2C_ERROR;
+    }
+
+    /* Set conversion rate to 1 / second */
+    err = i2c_linuxdev_write(i2c_fd, i2c_addr, STTS751_REG_RATE, 0x04);
+    if (err != 0) {
+        DEBUG_PRINTF("ERROR: failed to write I2C device 0x%02X (err=%i)\n", i2c_addr, err);
+        return LGW_I2C_ERROR;
+    }
+
+    return LGW_I2C_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int stts751_get_temperature(int i2c_fd, uint8_t i2c_addr, float * temperature) {
+    int err;
+    uint8_t high_byte, low_byte;
+    int8_t h;
+
+    /* Check Input Params */
+    if (i2c_fd <= 0) {
+        printf("ERROR: invalid I2C file descriptor\n");
+        return LGW_I2C_ERROR;
+    }
+
+    /* Read Temperature LSB */
+    err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_TEMP_L, &low_byte);
+    if (err != 0) {
+        printf("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err);
+        return LGW_I2C_ERROR;
+    }
+
+    /* Read Temperature MSB */
+    err = i2c_linuxdev_read(i2c_fd, i2c_addr, STTS751_REG_TEMP_H, &high_byte);
+    if (err != 0) {
+        printf("ERROR: failed to read I2C device 0x%02X (err=%i)\n", i2c_addr, err);
+        return LGW_I2C_ERROR;
+    }
+
+    h = (int8_t)high_byte;
+    *temperature = ((h << 8) | low_byte) / 256.0;
+
+    DEBUG_PRINTF("Temperature: %f C (h:0x%02X l:0x%02X)\n", *temperature, high_byte, low_byte);
+
+    return LGW_I2C_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 261 - 0
sx1302/source/loragw_sx1250.c

@@ -0,0 +1,261 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1250 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdio.h>      /* printf fprintf */
+
+#include "loragw_sx1250.h"
+#include "loragw_com.h"
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_hal.h"
+
+#include "sx1250_com.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_RAD == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%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 ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int sx1250_reg_w(sx1250_op_code_t op_code, uint8_t *data, uint16_t size, uint8_t rf_chain) {
+    int com_stat;
+
+    /* checking input parameters */
+    if (rf_chain >= LGW_RF_CHAIN_NB) {
+        DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
+        return LGW_REG_ERROR;
+    }
+
+    com_stat = sx1250_com_w(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), op_code, data, size);
+
+    if (com_stat != LGW_COM_SUCCESS) {
+        DEBUG_MSG("ERROR: COM ERROR DURING RADIO REGISTER WRITE\n");
+        return LGW_REG_ERROR;
+    } else {
+        return LGW_REG_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1250_reg_r(sx1250_op_code_t op_code, uint8_t *data, uint16_t size, uint8_t rf_chain) {
+    int com_stat;
+
+    /* checking input parameters */
+    if (rf_chain >= LGW_RF_CHAIN_NB) {
+        DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
+        return LGW_REG_ERROR;
+    }
+
+    com_stat = sx1250_com_r(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), op_code, data, size);
+
+    if (com_stat != LGW_COM_SUCCESS) {
+        DEBUG_MSG("ERROR: COM ERROR DURING RADIO REGISTER READ\n");
+        return LGW_REG_ERROR;
+    } else {
+        return LGW_REG_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1250_calibrate(uint8_t rf_chain, uint32_t freq_hz) {
+    int err = LGW_REG_SUCCESS;
+    uint8_t buff[16];
+
+    buff[0] = 0x00;
+    err |= sx1250_reg_r(GET_STATUS, buff, 1, rf_chain);
+
+    /* Run calibration */
+    if ((freq_hz > 430E6) && (freq_hz < 440E6)) {
+        buff[0] = 0x6B;
+        buff[1] = 0x6F;
+    } else if ((freq_hz > 470E6) && (freq_hz < 510E6)) {
+        buff[0] = 0x75;
+        buff[1] = 0x81;
+    } else if ((freq_hz > 779E6) && (freq_hz < 787E6)) {
+        buff[0] = 0xC1;
+        buff[1] = 0xC5;
+    } else if ((freq_hz > 863E6) && (freq_hz < 870E6)) {
+        buff[0] = 0xD7;
+        buff[1] = 0xDB;
+    } else if ((freq_hz > 902E6) && (freq_hz < 928E6)) {
+        buff[0] = 0xE1;
+        buff[1] = 0xE9;
+    } else {
+        printf("ERROR: failed to calibrate sx1250 radio, frequency range not supported (%u)\n", freq_hz);
+        return LGW_REG_ERROR;
+    }
+    err |= sx1250_reg_w(CALIBRATE_IMAGE, buff, 2, rf_chain);
+
+    /* Wait for calibration to complete */
+    wait_ms(10);
+
+    buff[0] = 0x00;
+    buff[1] = 0x00;
+    buff[2] = 0x00;
+    err |= sx1250_reg_r(GET_DEVICE_ERRORS, buff, 3, rf_chain);
+    if (TAKE_N_BITS_FROM(buff[2], 4, 1) != 0) {
+        printf("ERROR: sx1250 Image Calibration Error\n");
+        return LGW_REG_ERROR;
+    }
+
+    return err;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1250_setup(uint8_t rf_chain, uint32_t freq_hz, bool single_input_mode) {
+    int32_t freq_reg;
+    uint8_t buff[16];
+    int err = LGW_REG_SUCCESS;
+
+    /* Set Radio in Standby for calibrations */
+    buff[0] = (uint8_t)STDBY_RC;
+    err |= sx1250_reg_w(SET_STANDBY, buff, 1, rf_chain);
+    wait_ms(10);
+
+    /* Get status to check Standby mode has been properly set */
+    buff[0] = 0x00;
+    err |= sx1250_reg_r(GET_STATUS, buff, 1, rf_chain);
+    if ((uint8_t)(TAKE_N_BITS_FROM(buff[0], 4, 3)) != 0x02) {
+        printf("ERROR: Failed to set SX1250_%u in STANDBY_RC mode\n", rf_chain);
+        return LGW_REG_ERROR;
+    }
+
+    /* Run all calibrations (TCXO) */
+    buff[0] = 0x7F;
+    err |= sx1250_reg_w(CALIBRATE, buff, 1, rf_chain);
+    wait_ms(10);
+
+    /* Set Radio in Standby with XOSC ON */
+    buff[0] = (uint8_t)STDBY_XOSC;
+    err |= sx1250_reg_w(SET_STANDBY, buff, 1, rf_chain);
+    wait_ms(10);
+
+    /* Get status to check Standby mode has been properly set */
+    buff[0] = 0x00;
+    err |= sx1250_reg_r(GET_STATUS, buff, 1, rf_chain);
+    if ((uint8_t)(TAKE_N_BITS_FROM(buff[0], 4, 3)) != 0x03) {
+        printf("ERROR: Failed to set SX1250_%u in STANDBY_XOSC mode\n", rf_chain);
+        return LGW_REG_ERROR;
+    }
+
+    /* Set Bitrate to maximum (to lower TX to FS switch time) */
+    buff[0] = 0x06;
+    buff[1] = 0xA1;
+    buff[2] = 0x01;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain);
+    buff[0] = 0x06;
+    buff[1] = 0xA2;
+    buff[2] = 0x00;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain);
+    buff[0] = 0x06;
+    buff[1] = 0xA3;
+    buff[2] = 0x00;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain);
+
+    /* Configure DIO for Rx */
+    buff[0] = 0x05;
+    buff[1] = 0x82;
+    buff[2] = 0x00;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain); /* Drive strength to min */
+    buff[0] = 0x05;
+    buff[1] = 0x83;
+    buff[2] = 0x00;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain); /* Input enable, all disabled */
+    buff[0] = 0x05;
+    buff[1] = 0x84;
+    buff[2] = 0x00;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain); /* No pull up */
+    buff[0] = 0x05;
+    buff[1] = 0x85;
+    buff[2] = 0x00;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain); /* No pull down */
+    buff[0] = 0x05;
+    buff[1] = 0x80;
+    buff[2] = 0x00;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain); /* Output enable, all enabled */
+
+    /* Set fix gain (??) */
+    buff[0] = 0x08;
+    buff[1] = 0xB6;
+    buff[2] = 0x2A;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain);
+
+    /* Set frequency */
+    freq_reg = SX1250_FREQ_TO_REG(freq_hz);
+    buff[0] = (uint8_t)(freq_reg >> 24);
+    buff[1] = (uint8_t)(freq_reg >> 16);
+    buff[2] = (uint8_t)(freq_reg >> 8);
+    buff[3] = (uint8_t)(freq_reg >> 0);
+    err |= sx1250_reg_w(SET_RF_FREQUENCY, buff, 4, rf_chain);
+
+    /* Set frequency offset to 0 */
+    buff[0] = 0x08;
+    buff[1] = 0x8F;
+    buff[2] = 0x00;
+    buff[3] = 0x00;
+    buff[4] = 0x00;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 5, rf_chain);
+
+    /* Set Radio in Rx mode, necessary to give a clock to SX1302 */
+    buff[0] = 0xFF;
+    buff[1] = 0xFF;
+    buff[2] = 0xFF;
+    err |= sx1250_reg_w(SET_RX, buff, 3, rf_chain); /* Rx Continuous */
+
+    /* Select single input or differential input mode */
+    if (single_input_mode == true) {
+        printf("INFO: Configuring SX1250_%u in single input mode\n", rf_chain);
+        buff[0] = 0x08;
+        buff[1] = 0xE2;
+        buff[2] = 0x0D;
+        err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain);
+    }
+
+    buff[0] = 0x05;
+    buff[1] = 0x87;
+    buff[2] = 0x0B;
+    err |= sx1250_reg_w(WRITE_REGISTER, buff, 3, rf_chain); /* FPGA_MODE_RX */
+
+    /* Check if something went wrong */
+    if (err != LGW_REG_SUCCESS) {
+        printf("ERROR: failed to setup SX1250_%u radio\n", rf_chain);
+        return LGW_REG_ERROR;
+    }
+
+    return LGW_REG_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 295 - 0
sx1302/source/loragw_sx125x.c

@@ -0,0 +1,295 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1255/SX1257 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 "sx125x_com.h"
+#include "loragw_sx125x.h"
+#include "loragw_com.h"
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_hal.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_RAD == 1
+    #define DEBUG_MSG(str)              fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)  fprintf(stdout,"%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 -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define PLL_LOCK_MAX_ATTEMPTS 5
+
+static const struct radio_reg_s sx125x_regs[RADIO_TOTALREGS] = {
+    {0,0,8}, /* MODE */
+    {0,3,1}, /* MODE__PA_DRIVER_EN */
+    {0,2,1}, /* MODE__TX_EN */
+    {0,1,1}, /* MODE__RX_EN */
+    {0,0,1}, /* MODE__STANDBY_EN */
+    {1,0,8}, /* FRF_RX_MSB */
+    {2,0,8}, /* FRF_RX_MID */
+    {3,0,8}, /* FRF_RX_LSB */
+    {4,0,8}, /* FRF_TX_MSB */
+    {5,0,8}, /* FRF_TX_MID */
+    {6,0,8}, /* FRF_TX_LSB */
+    {7,0,8}, /* VERSION */
+    {8,0,8}, /* TX_GAIN */
+    {8,4,3}, /* TX_GAIN__DAC_GAIN */
+    {8,0,4}, /* TX_GAIN__MIX_GAIN */
+    {10,0,8}, /* TX_BW */
+    {10,5,2}, /* TX_BW__PLL_BW */
+    {10,0,5}, /* TX_BW__ANA_BW */
+    {11,0,8}, /* TX_DAC_BW */
+    {12,0,8}, /* RX_ANA_GAIN */
+    {12,5,3}, /* RX_ANA_GAIN__LNA_GAIN */
+    {12,1,4}, /* RX_ANA_GAIN__BB_GAIN */
+    {12,0,1}, /* RX_ANA_GAIN__LNA_ZIN */
+    {13,0,8}, /* RX_BW */
+    {13,5,3}, /* RX_BW__ADC_BW */
+    {13,2,3}, /* RX_BW__ADC_TRIM */
+    {13,0,2}, /* RX_BW__BB_BW */
+    {14,0,8}, /* RX_PLL_BW */
+    {14,1,2}, /* RX_PLL_BW__PLL_BW */
+    {14,0,1}, /* RX_PLL_BW__ADC_TEMP_EN */
+    {15,0,8}, /* DIO_MAPPING */
+    {15,6,2}, /* DIO_MAPPING__DIO_0_MAPPING */
+    {15,4,2}, /* DIO_MAPPING__DIO_1_MAPPING */
+    {15,2,2}, /* DIO_MAPPING__DIO_2_MAPPING */
+    {15,0,2}, /* DIO_MAPPING__DIO_3_MAPPING */
+    {16,0,8}, /* CLK_SELECT */
+    {16,3,1}, /* CLK_SELECT__DIG_LOOPBACK_EN */
+    {16,2,1}, /* CLK_SELECT__RF_LOOPBACK_EN */
+    {16,1,1}, /* CLK_SELECT__CLK_OUT */
+    {16,0,1}, /* CLK_SELECT__DAC_CLK_SELECT */
+    {17,0,8}, /* MODE_STATUS */
+    {17,2,1}, /* MODE_STATUS__LOW_BAT_EN */
+    {17,1,1}, /* MODE_STATUS__RX_PLL_LOCKED */
+    {17,0,1}, /* MODE_STATUS__TX_PLL_LOCKED */
+    {26,0,8}, /* LOW_BAT_THRESH */
+    {38,0,8}, /* SX1257_XOSC_TEST */
+    {38,4,3}, /* SX1257_XOSC_TEST__DISABLE */
+    {38,0,4}, /* SX1257_XOSC_TEST__GM_STARTUP */
+    {40,0,8}, /* SX1255_XOSC_TEST */
+    {40,4,3}, /* SX1255_XOSC_TEST__DISABLE */
+    {40,0,4} /* SX1255_XOSC_TEST__GM_STARTUP */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int sx125x_reg_w(radio_reg_t idx, uint8_t data, uint8_t rf_chain) {
+
+    int com_stat;
+    struct radio_reg_s reg;
+    uint8_t mask;
+    uint8_t r;
+    uint8_t w;
+    uint8_t val_check;
+
+    /* checking input parameters */
+    if (rf_chain >= LGW_RF_CHAIN_NB) {
+        DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
+        return LGW_REG_ERROR;
+    }
+    if (idx >= RADIO_TOTALREGS) {
+        DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+        return LGW_REG_ERROR;
+    }
+
+    reg = sx125x_regs[idx];
+
+    if ((reg.leng == 8) && (reg.offs == 0)){
+        /* direct write */
+        com_stat = sx125x_com_w(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), reg.addr, data);
+    } else {
+        /* read-modify-write */
+        com_stat = sx125x_com_r(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), reg.addr, &r);
+        mask = ((1 << reg.leng) - 1) << reg.offs;
+        w = (r & ~mask) | ((data << reg.offs) & mask);
+        com_stat |= sx125x_com_w(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), reg.addr, w);
+    }
+
+    /* Check that we can read what we have written */
+    sx125x_reg_r(idx, &val_check, rf_chain);
+    if (val_check != data) {
+        printf("ERROR: sx125x register %d write failed (w:%u r:%u)!!\n", idx, data, val_check);
+        com_stat = LGW_COM_ERROR;
+    }
+
+    if (com_stat != LGW_COM_SUCCESS) {
+        DEBUG_MSG("ERROR: COM ERROR DURING RADIO REGISTER WRITE\n");
+        return LGW_REG_ERROR;
+    } else {
+        return LGW_REG_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx125x_reg_r(radio_reg_t idx, uint8_t *data, uint8_t rf_chain) {
+
+    int com_stat;
+    struct radio_reg_s reg;
+    uint8_t mask;
+    uint8_t r;
+
+    /* checking input parameters */
+    if (rf_chain >= LGW_RF_CHAIN_NB) {
+        DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
+        return LGW_REG_ERROR;
+    }
+    if (idx >= RADIO_TOTALREGS) {
+        DEBUG_MSG("ERROR: REGISTER NUMBER OUT OF DEFINED RANGE\n");
+        return LGW_REG_ERROR;
+    }
+
+    reg = sx125x_regs[idx];
+
+    com_stat = sx125x_com_r(lgw_com_type(), lgw_com_target(), ((rf_chain == 0) ? LGW_SPI_MUX_TARGET_RADIOA : LGW_SPI_MUX_TARGET_RADIOB), reg.addr, &r);
+    mask = ((1 << reg.leng) - 1) << reg.offs;
+    *data = (r & mask) >> reg.offs;
+
+    if (com_stat != LGW_COM_SUCCESS) {
+        DEBUG_MSG("ERROR: COM ERROR DURING RADIO REGISTER READ\n");
+        return LGW_REG_ERROR;
+    } else {
+        return LGW_REG_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx125x_setup(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;
+    uint8_t val;
+
+    if (rf_chain >= LGW_RF_CHAIN_NB) {
+        DEBUG_MSG("ERROR: INVALID RF_CHAIN\n");
+        return -1;
+    }
+
+    /* Get version to identify SX1255/57 silicon revision */
+    sx125x_reg_r(SX125x_REG_VERSION, &val, rf_chain);
+    DEBUG_PRINTF("Note: SX125x #%d version register returned 0x%02x\n", rf_chain, val);
+
+    /* General radio setup */
+    if (rf_clkout == rf_chain) {
+        sx125x_reg_w(SX125x_REG_CLK_SELECT, SX125x_TX_DAC_CLK_SEL + 2, rf_chain);
+        DEBUG_PRINTF("Note: SX125x #%d clock output enabled\n", rf_chain);
+    } else {
+        sx125x_reg_w(SX125x_REG_CLK_SELECT, SX125x_TX_DAC_CLK_SEL, rf_chain);
+        DEBUG_PRINTF("Note: SX125x #%d clock output disabled\n", rf_chain);
+    }
+
+    switch (rf_radio_type) {
+        case LGW_RADIO_TYPE_SX1255:
+            sx125x_reg_w(SX125x_REG_SX1255_XOSC_TEST__GM_STARTUP, SX125x_XOSC_GM_STARTUP, rf_chain);
+            sx125x_reg_w(SX125x_REG_SX1255_XOSC_TEST__DISABLE, SX125x_XOSC_DISABLE, rf_chain);
+            break;
+        case LGW_RADIO_TYPE_SX1257:
+            sx125x_reg_w(SX125x_REG_SX1257_XOSC_TEST__GM_STARTUP, SX125x_XOSC_GM_STARTUP, rf_chain);
+            sx125x_reg_w(SX125x_REG_SX1257_XOSC_TEST__DISABLE, SX125x_XOSC_DISABLE, rf_chain);
+            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_reg_w(SX125x_REG_TX_GAIN__MIX_GAIN, SX125x_TX_MIX_GAIN, rf_chain);
+        sx125x_reg_w(SX125x_REG_TX_GAIN__DAC_GAIN, SX125x_TX_DAC_GAIN, rf_chain);
+
+        sx125x_reg_w(SX125x_REG_TX_BW__ANA_BW, SX125x_TX_ANA_BW, rf_chain);
+        sx125x_reg_w(SX125x_REG_TX_BW__PLL_BW, SX125x_TX_PLL_BW, rf_chain);
+
+        sx125x_reg_w(SX125x_REG_TX_DAC_BW, SX125x_TX_DAC_BW, rf_chain);
+
+        /* Rx gain and trim */
+        sx125x_reg_w(SX125x_REG_RX_ANA_GAIN__LNA_ZIN, SX125x_LNA_ZIN, rf_chain);
+        sx125x_reg_w(SX125x_REG_RX_ANA_GAIN__BB_GAIN, SX125x_RX_BB_GAIN, rf_chain);
+        sx125x_reg_w(SX125x_REG_RX_ANA_GAIN__LNA_GAIN, SX125x_RX_LNA_GAIN, rf_chain);
+
+        sx125x_reg_w(SX125x_REG_RX_BW__BB_BW, SX125x_RX_BB_BW, rf_chain);
+        sx125x_reg_w(SX125x_REG_RX_BW__ADC_TRIM, SX125x_RX_ADC_TRIM, rf_chain);
+        sx125x_reg_w(SX125x_REG_RX_BW__ADC_BW, SX125x_RX_ADC_BW, rf_chain);
+
+        sx125x_reg_w(SX125x_REG_RX_PLL_BW__ADC_TEMP_EN, SX125x_ADC_TEMP, rf_chain);
+        sx125x_reg_w(SX125x_REG_RX_PLL_BW__PLL_BW, SX125x_RX_PLL_BW, rf_chain);
+
+        /* 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_reg_w(SX125x_REG_FRF_RX_MSB, 0xFF & part_int, rf_chain);
+        sx125x_reg_w(SX125x_REG_FRF_RX_MID, 0xFF & (part_frac >> 8), rf_chain);
+        sx125x_reg_w(SX125x_REG_FRF_RX_LSB, 0xFF & part_frac, rf_chain);
+
+        /* start and PLL lock */
+        do {
+            if (cpt_attempts >= PLL_LOCK_MAX_ATTEMPTS) {
+                DEBUG_MSG("ERROR: FAIL TO LOCK PLL\n");
+                return -1;
+            }
+            sx125x_reg_w(SX125x_REG_MODE, 1, rf_chain);
+            sx125x_reg_w(SX125x_REG_MODE, 3, rf_chain);
+            ++cpt_attempts;
+            DEBUG_PRINTF("Note: SX125x #%d PLL start (attempt %d)\n", rf_chain, cpt_attempts);
+            wait_ms(1);
+            sx125x_reg_r(SX125x_REG_MODE_STATUS, &val, rf_chain);
+        } while ((val & 0x02) == 0);
+    } else {
+        DEBUG_PRINTF("Note: SX125x #%d kept in standby mode\n", rf_chain);
+    }
+
+    return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 687 - 0
sx1302/source/loragw_sx1261.c

@@ -0,0 +1,687 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1261 radio used to handle LBT
+    and Spectral Scan.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdio.h>      /* printf fprintf */
+#include <string.h>     /* strncmp */
+
+#include "loragw_sx1261.h"
+#include "loragw_spi.h"
+#include "loragw_com.h"
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_hal.h"
+
+#include "sx1261_com.h"
+
+#include "sx1261_pram.var"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_LBT == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+    #define CHECK_NULL(a)                if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return LGW_REG_ERROR;}
+#endif
+
+#define CHECK_ERR(a)                    if(a==-1){return LGW_REG_ERROR;}
+
+#define DEBUG_SX1261_GET_STATUS 0
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define SX1261_PRAM_VERSION_FULL_SIZE 16 /* 15 bytes + terminating char */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+int sx1261_pram_get_version(char * version_str) {
+    uint8_t buff[3 + SX1261_PRAM_VERSION_FULL_SIZE] = { 0 };
+    int x;
+
+    /* Check input parameter */
+    CHECK_NULL(version_str);
+
+    /* Get version string (15 bytes) at address 0x320 */
+    buff[0] = 0x03;
+    buff[1] = 0x20;
+    buff[2] = 0x00; /* status */
+    x = sx1261_reg_r(SX1261_READ_REGISTER, buff, 18);
+    if (x != LGW_REG_SUCCESS) {
+        printf("ERROR: failed to read SX1261 PRAM version\n");
+        return x;
+    }
+
+    /* Return full PRAM version string */
+    buff[18] = '\0';
+    strncpy(version_str, (char*)(buff + 3), 16); /* 15 bytes + terminating char */
+    version_str[16] = '\0';
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_get_status(uint8_t * status) {
+    uint8_t buff[1];
+
+    buff[0] = 0x00;
+    sx1261_reg_r(SX1261_GET_STATUS, buff, 1);
+
+    *status = buff[0] & 0x7E; /* ignore bit 0 & 7 */
+
+    DEBUG_PRINTF("SX1261: %s: get_status: 0x%02X (0x%02X)\n", __FUNCTION__, *status, buff[0]);
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_check_status(uint8_t expected_status) {
+    int err;
+    uint8_t status;
+
+    err = sx1261_get_status(&status);
+    if (err != LGW_REG_SUCCESS) {
+        printf("ERROR: %s: failed to get status\n", __FUNCTION__);
+        return LGW_REG_ERROR;
+    }
+
+    if (status != expected_status) {
+        printf("ERROR: %s: SX1261 status is not as expected: got:0x%02X expected:0x%02X\n", __FUNCTION__, status, expected_status);
+        return LGW_REG_ERROR;
+    }
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+const char * get_scan_status_str(const lgw_spectral_scan_status_t status) {
+    switch (status) {
+        case LGW_SPECTRAL_SCAN_STATUS_NONE:
+            return "LGW_SPECTRAL_SCAN_STATUS_NONE";
+        case LGW_SPECTRAL_SCAN_STATUS_ON_GOING:
+            return "LGW_SPECTRAL_SCAN_STATUS_ON_GOING";
+        case LGW_SPECTRAL_SCAN_STATUS_ABORTED:
+            return "LGW_SPECTRAL_SCAN_STATUS_ABORTED";
+        case LGW_SPECTRAL_SCAN_STATUS_COMPLETED:
+            return "LGW_SPECTRAL_SCAN_STATUS_COMPLETED";
+        default:
+            return "LGW_SPECTRAL_SCAN_STATUS_UNKNOWN";
+    }
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int sx1261_connect(lgw_com_type_t com_type, const char *com_path) {
+    if (com_type == LGW_COM_SPI && com_path == NULL) {
+        printf("ERROR: %s: unspecified COM path to connect to sx1261 radio\n", __FUNCTION__);
+        return LGW_REG_ERROR;
+    }
+    return sx1261_com_open(com_type, com_path);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_disconnect(void) {
+    return sx1261_com_close();
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_reg_w(sx1261_op_code_t op_code, uint8_t *data, uint16_t size) {
+    int com_stat;
+
+    /* checking input parameters */
+    CHECK_NULL(data);
+
+    com_stat = sx1261_com_w(op_code, data, size);
+    if (com_stat != LGW_COM_SUCCESS) {
+        printf("ERROR: COM ERROR DURING SX1261 RADIO REGISTER WRITE\n");
+        return LGW_REG_ERROR;
+    } else {
+        return LGW_REG_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_reg_r(sx1261_op_code_t op_code, uint8_t *data, uint16_t size) {
+    int com_stat;
+
+    /* checking input parameters */
+    CHECK_NULL(data);
+
+    com_stat = sx1261_com_r(op_code, data, size);
+    if (com_stat != LGW_COM_SUCCESS) {
+        printf("ERROR: COM ERROR DURING SX1261 RADIO REGISTER READ\n");
+        return LGW_REG_ERROR;
+    } else {
+        return LGW_REG_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_load_pram(void) {
+    int i, err;
+    uint8_t buff[32];
+    char pram_version[SX1261_PRAM_VERSION_FULL_SIZE];
+    uint32_t val, addr;
+
+    /* Set Radio in Standby mode */
+    buff[0] = (uint8_t)SX1261_STDBY_RC;
+    sx1261_reg_w(SX1261_SET_STANDBY, buff, 1);
+
+    /* Check status */
+    err = sx1261_check_status(SX1261_STATUS_MODE_STBY_RC | SX1261_STATUS_READY);
+    if (err != LGW_REG_SUCCESS) {
+        printf("ERROR: %s: SX1261 status error\n", __FUNCTION__);
+        return -1;
+    }
+
+    err = sx1261_pram_get_version(pram_version);
+    if (err != LGW_REG_SUCCESS) {
+        printf("ERROR: %s: SX1261 failed to get pram version\n", __FUNCTION__);
+        return -1;
+    }
+    printf("SX1261: PRAM version: %s\n", pram_version);
+
+    /* Enable patch update */
+    buff[0] = 0x06;
+    buff[1] = 0x10;
+    buff[2] = 0x10;
+    err = sx1261_reg_w( SX1261_WRITE_REGISTER, buff, 3);
+    CHECK_ERR(err);
+
+    /* Load patch */
+    for (i = 0; i < (int)PRAM_COUNT; i++) {
+        val = pram[i];
+        addr = 0x8000 + 4*i;
+
+        buff[0] = (addr >> 8) & 0xFF;
+        buff[1] = (addr >> 0) & 0xFF;
+        buff[2] = (val >> 24) & 0xFF;
+        buff[3] = (val >> 16) & 0xFF;
+        buff[4] = (val >> 8)  & 0xFF;
+        buff[5] = (val >> 0)  & 0xFF;
+        err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 6);
+        CHECK_ERR(err);
+    }
+
+    /* Disable patch update */
+    buff[0] = 0x06;
+    buff[1] = 0x10;
+    buff[2] = 0x00;
+    err = sx1261_reg_w( SX1261_WRITE_REGISTER, buff, 3);
+    CHECK_ERR(err);
+
+    /* Update pram */
+    buff[0] = 0;
+    err = sx1261_reg_w(0xd9, buff, 0);
+    CHECK_ERR(err);
+
+    err = sx1261_pram_get_version(pram_version);
+    if (err != LGW_REG_SUCCESS) {
+        printf("ERROR: %s: SX1261 failed to get pram version\n", __FUNCTION__);
+        return -1;
+    }
+    printf("SX1261: PRAM version: %s\n", pram_version);
+
+    /* Check PRAM version (only last 4 bytes) */
+    if (strncmp(pram_version + 11, sx1261_pram_version_string, 4) != 0) {
+        printf("ERROR: SX1261 PRAM version mismatch (got:%s expected:%s)\n", pram_version + 11, sx1261_pram_version_string);
+        return -1;
+    }
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_calibrate(uint32_t freq_hz) {
+    int err = LGW_REG_SUCCESS;
+    uint8_t buff[16];
+
+    buff[0] = 0x00;
+    err = sx1261_reg_r(SX1261_GET_STATUS, buff, 1);
+    CHECK_ERR(err);
+
+    /* Run calibration */
+    if ((freq_hz > 430E6) && (freq_hz < 440E6)) {
+        buff[0] = 0x6B;
+        buff[1] = 0x6F;
+    } else if ((freq_hz > 470E6) && (freq_hz < 510E6)) {
+        buff[0] = 0x75;
+        buff[1] = 0x81;
+    } else if ((freq_hz > 779E6) && (freq_hz < 787E6)) {
+        buff[0] = 0xC1;
+        buff[1] = 0xC5;
+    } else if ((freq_hz > 863E6) && (freq_hz < 870E6)) {
+        buff[0] = 0xD7;
+        buff[1] = 0xDB;
+    } else if ((freq_hz > 902E6) && (freq_hz < 928E6)) {
+        buff[0] = 0xE1;
+        buff[1] = 0xE9;
+    } else {
+        printf("ERROR: failed to calibrate sx1261 radio, frequency range not supported (%u)\n", freq_hz);
+        return LGW_REG_ERROR;
+    }
+    err = sx1261_reg_w(SX1261_CALIBRATE_IMAGE, buff, 2);
+    CHECK_ERR(err);
+
+    /* Wait for calibration to complete */
+    wait_ms(10);
+
+    buff[0] = 0x00;
+    buff[1] = 0x00;
+    buff[2] = 0x00;
+    err = sx1261_reg_r(SX1261_GET_DEVICE_ERRORS, buff, 3);
+    CHECK_ERR(err);
+    if (TAKE_N_BITS_FROM(buff[2], 4, 1) != 0) {
+        printf("ERROR: sx1261 Image Calibration Error\n");
+        return LGW_REG_ERROR;
+    }
+
+    return err;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_setup(void) {
+    int err;
+    uint8_t buff[32];
+
+    /* Set Radio in Standby mode */
+    buff[0] = (uint8_t)SX1261_STDBY_RC;
+    err = sx1261_reg_w(SX1261_SET_STANDBY, buff, 1);
+    CHECK_ERR(err);
+
+    /* Check radio status */
+    err = sx1261_check_status(SX1261_STATUS_MODE_STBY_RC | SX1261_STATUS_READY);
+    CHECK_ERR(err);
+
+    /* Set Buffer Base address */
+    buff[0] = 0x80;
+    buff[1] = 0x80;
+    err = sx1261_reg_w(SX1261_SET_BUFFER_BASE_ADDRESS, buff, 2);
+    CHECK_ERR(err);
+
+    /* sensi adjust */
+    buff[0] = 0x08;
+    buff[1] = 0xAC;
+    buff[2] = 0xCB;
+    err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 3);
+    CHECK_ERR(err);
+
+    DEBUG_MSG("SX1261: setup for LBT / Spectral Scan done\n");
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_set_rx_params(uint32_t freq_hz, uint8_t bandwidth) {
+    int err;
+    uint8_t buff[16];
+    int32_t freq_reg;
+    uint8_t fsk_bw_reg;
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Set SPI write bulk mode to optimize speed on USB */
+    err = sx1261_com_set_write_mode(LGW_COM_WRITE_MODE_BULK);
+    CHECK_ERR(err);
+
+    /* Disable any on-going spectral scan to free the sx1261 radio for LBT */
+    err = sx1261_spectral_scan_abort();
+    CHECK_ERR(err);
+
+    /* Set FS */
+    err = sx1261_reg_w(SX1261_SET_FS, buff, 0);
+    CHECK_ERR(err);
+
+#if DEBUG_SX1261_GET_STATUS /* need to disable spi bulk mode if enable this check */
+    /* Check radio status */
+    err = sx1261_check_status(SX1261_STATUS_MODE_FS | SX1261_STATUS_READY);
+    CHECK_ERR(err);
+#endif
+
+    /* Set frequency */
+    freq_reg = SX1261_FREQ_TO_REG(freq_hz);
+    buff[0] = (uint8_t)(freq_reg >> 24);
+    buff[1] = (uint8_t)(freq_reg >> 16);
+    buff[2] = (uint8_t)(freq_reg >> 8);
+    buff[3] = (uint8_t)(freq_reg >> 0);
+    err = sx1261_reg_w(SX1261_SET_RF_FREQUENCY, buff, 4);
+    CHECK_ERR(err);
+
+    /* Configure RSSI averaging window */
+    buff[0] = 0x08;
+    buff[1] = 0x9B;
+    buff[2] = 0x05 << 2;
+    err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 3);
+    CHECK_ERR(err);
+
+    /* Set PacketType */
+    buff[0] = 0x00; /* FSK */
+    err = sx1261_reg_w(SX1261_SET_PACKET_TYPE, buff, 1);
+    CHECK_ERR(err);
+
+    /* Set GFSK bandwidth */
+    switch (bandwidth) {
+        case BW_125KHZ:
+            fsk_bw_reg = 0x0A; /* RX_BW_234300 Hz */
+            break;
+        case BW_250KHZ:
+            fsk_bw_reg = 0x09; /* RX_BW_467000 Hz */
+            break;
+        default:
+            printf("ERROR: %s: Cannot configure sx1261 for bandwidth %u\n", __FUNCTION__, bandwidth);
+            return LGW_REG_ERROR;
+    }
+
+    /* Set modulation params for FSK */
+    buff[0] = 0;    // BR
+    buff[1] = 0x14; // BR
+    buff[2] = 0x00; // BR
+    buff[3] = 0x00; // Gaussian BT disabled
+    buff[4] = fsk_bw_reg;
+    buff[5] = 0x02; // FDEV
+    buff[6] = 0xE9; // FDEV
+    buff[7] = 0x0F; // FDEV
+    err = sx1261_reg_w(SX1261_SET_MODULATION_PARAMS, buff, 8);
+    CHECK_ERR(err);
+
+    /* Set packet params for FSK */
+    buff[0] = 0x00; /* Preamble length MSB */
+    buff[1] = 0x20; /* Preamble length LSB 32 bits*/
+    buff[2] = 0x05; /* Preamble detector lenght 16 bits */
+    buff[3] = 0x20; /* SyncWordLength 32 bits*/
+    buff[4] = 0x00; /* AddrComp disabled */
+    buff[5] = 0x01; /* PacketType variable size */
+    buff[6] = 0xff; /* PayloadLength 255 bytes */
+    buff[7] = 0x00; /* CRCType 1 Byte */
+    buff[8] = 0x00; /* Whitening disabled*/
+    err = sx1261_reg_w(SX1261_SET_PACKET_PARAMS, buff, 9);
+    CHECK_ERR(err);
+
+    /* Set Radio in Rx continuous mode */
+    buff[0] = 0xFF;
+    buff[1] = 0xFF;
+    buff[2] = 0xFF;
+    err = sx1261_reg_w(SX1261_SET_RX, buff, 3);
+    CHECK_ERR(err);
+
+    /* Flush write (USB BULK mode) */
+    err = sx1261_com_flush();
+    if (err != 0) {
+        printf("ERROR: %s: Failed to flush sx1261 SPI\n", __FUNCTION__);
+        return -1;
+    }
+
+    /* Setting back to SINGLE BULK write mode */
+    err = sx1261_com_set_write_mode(LGW_COM_WRITE_MODE_SINGLE);
+    CHECK_ERR(err);
+
+#if DEBUG_SX1261_GET_STATUS
+    /* Check radio status */
+    err = sx1261_check_status(SX1261_STATUS_MODE_RX | SX1261_STATUS_READY);
+    CHECK_ERR(err);
+#endif
+
+    DEBUG_PRINTF("SX1261: RX params set to %u Hz (bw:0x%02X)\n", freq_hz, bandwidth);
+
+    _meas_time_stop(4, tm, __FUNCTION__);
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_lbt_start(lgw_lbt_scan_time_t scan_time_us, int8_t threshold_dbm) {
+    int err;
+    uint8_t buff[16];
+    uint16_t nb_scan;
+    uint8_t threshold_reg = -2 * threshold_dbm;
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    switch (scan_time_us) {
+        case LGW_LBT_SCAN_TIME_128_US:
+            nb_scan = 24;
+            break;
+        case LGW_LBT_SCAN_TIME_5000_US:
+            nb_scan = 715;
+            break;
+        default:
+            printf("ERROR: wrong scan_time_us value\n");
+            return -1;
+    }
+
+#if DEBUG_SX1261_GET_STATUS
+    /* Check radio status */
+    err = sx1261_check_status(SX1261_STATUS_MODE_RX | SX1261_STATUS_READY);
+    CHECK_ERR(err);
+#endif
+
+    /* Configure LBT scan */
+    buff[0] = 11; // intervall_rssi_read (10 => 7.68 usec,11 => 8.2 usec, 12 => 8.68 usec)
+    buff[1] = (nb_scan >> 8) & 0xFF;
+    buff[2] = (nb_scan >> 0) & 0xFF;
+    buff[3] = threshold_reg;
+    buff[4] = 1; // gpioId
+    err = sx1261_reg_w(0x9a, buff, 5);
+    CHECK_ERR(err);
+
+    /* Wait for Scan Time before TX trigger request */
+    wait_us((uint16_t)scan_time_us);
+
+    DEBUG_PRINTF("SX1261: LBT started: scan time = %uus, threshold = %ddBm\n", (uint16_t)scan_time_us, threshold_dbm);
+
+    _meas_time_stop(4, tm, __FUNCTION__);
+
+    return LGW_REG_SUCCESS;
+
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_lbt_stop(void) {
+    int err;
+    uint8_t buff[16];
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Disable LBT */
+    buff[0] = 0x08;
+    buff[1] = 0x9B;
+    buff[2] = 0x00;
+    err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 3);
+    CHECK_ERR(err);
+
+    /* Set FS */
+    err = sx1261_reg_w(SX1261_SET_FS, buff, 0);
+    CHECK_ERR(err);
+
+    DEBUG_MSG("SX1261: LBT stopped\n");
+
+    _meas_time_stop(4, tm, __FUNCTION__);
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_spectral_scan_start(uint16_t nb_scan) {
+    int err;
+    uint8_t buff[4]; /* 66 bytes for spectral scan results + 2 bytes register address + 1 dummy byte for reading */
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Start spectral scan */
+    buff[0] = (nb_scan >> 8) & 0xFF; /* nb_scan MSB */
+    buff[1] = (nb_scan >> 0) & 0xFF; /* nb_scan LSB */
+    buff[2] = 11; /* interval between scans - 8.2 us */
+    err = sx1261_reg_w(0x9b, buff, 9);
+    CHECK_ERR(err);
+
+    DEBUG_MSG("INFO: Spectral Scan started...\n");
+
+    _meas_time_stop(4, tm, __FUNCTION__);
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_spectral_scan_get_results(int8_t rssi_offset, int16_t * levels_dbm, uint16_t * results) {
+    int err, i;
+    uint8_t buff[69]; /* 66 bytes for spectral scan results + 2 bytes register address + 1 dummy byte for reading */
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Check input parameters */
+    CHECK_NULL(levels_dbm);
+    CHECK_NULL(results);
+
+    /* Get the results (66 bytes) */
+    buff[0] = 0x04;
+    buff[1] = 0x01;
+    buff[2] = 0x00; /* dummy */
+    for (i = 3; i < (66 + 3) ; i++) {
+        buff[i] = 0x00;
+    }
+    err = sx1261_reg_r(SX1261_READ_REGISTER, buff, 66 + 3);
+    CHECK_ERR(err);
+
+    /* Copy the results in the given buffers */
+    /* The number of points measured ABOVE each threshold */
+    for (i = 0; i < 32; i++) {
+        levels_dbm[i] = -i*4 + rssi_offset;
+        results[i] = (uint16_t)((buff[3 + i*2] << 8) | buff[3 + i*2 + 1]);
+    }
+    /* The number of points measured BELOW the lower threshold */
+    levels_dbm[32] = -31*4 + rssi_offset;
+    results[32] = (uint16_t)((buff[3 + 32*2] << 8) + buff[3 + 32*2 + 1]);
+
+    _meas_time_stop(4, tm, __FUNCTION__);
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_spectral_scan_status(lgw_spectral_scan_status_t * status) {
+    int err;
+    uint8_t buff[16];
+    /* performances variables */
+    struct timeval tm;
+
+    CHECK_NULL(status);
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Get status */
+    buff[0] = 0x07;
+    buff[1] = 0xCD;
+    buff[2] = 0x00; /* dummy */
+    buff[3] = 0x00; /* read value holder */
+    err = sx1261_reg_r(SX1261_READ_REGISTER, buff, 4);
+    CHECK_ERR(err);
+
+    switch (buff[3]) {
+        case 0x00:
+            *status = LGW_SPECTRAL_SCAN_STATUS_NONE;
+            break;
+        case 0x0F:
+            *status = LGW_SPECTRAL_SCAN_STATUS_ON_GOING;
+            break;
+        case 0xF0:
+            *status = LGW_SPECTRAL_SCAN_STATUS_ABORTED;
+            break;
+        case 0xFF:
+            *status = LGW_SPECTRAL_SCAN_STATUS_COMPLETED;
+            break;
+        default:
+            *status = LGW_SPECTRAL_SCAN_STATUS_UNKNOWN;
+            break;
+    }
+
+    DEBUG_PRINTF("INFO: %s: %s\n", __FUNCTION__, get_scan_status_str(*status));
+
+    _meas_time_stop(4, tm, __FUNCTION__);
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1261_spectral_scan_abort(void) {
+    int err;
+    uint8_t buff[16];
+    /* performances variables */
+    struct timeval tm;
+
+    /* Record function start time */
+    _meas_time_start(&tm);
+
+    /* Disable LBT */
+    buff[0] = 0x08;
+    buff[1] = 0x9B;
+    buff[2] = 0x00;
+    err = sx1261_reg_w(SX1261_WRITE_REGISTER, buff, 3);
+    CHECK_ERR(err);
+
+    DEBUG_MSG("SX1261: spectral scan aborted\n");
+
+    _meas_time_stop(4, tm, __FUNCTION__);
+
+    return LGW_REG_SUCCESS;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2826 - 0
sx1302/source/loragw_sx1302.c


+ 426 - 0
sx1302/source/loragw_sx1302_rx.c

@@ -0,0 +1,426 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    SX1302 RX buffer Hardware Abstraction Layer
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdio.h>      /* printf fprintf */
+#include <string.h>     /* memset */
+#include <assert.h>     /* assert */
+
+#include "loragw_aux.h"
+#include "loragw_reg.h"
+#include "loragw_sx1302_rx.h"
+#include "loragw_sx1302_timestamp.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_SX1302 == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout, fmt, args)
+    #define CHECK_NULL(a)                if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_REG_ERROR;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return LGW_REG_ERROR;}
+#endif
+
+#define SX1302_PKT_PAYLOAD_LENGTH(buffer, start_index)          TAKE_N_BITS_FROM(buffer[start_index +  2], 0, 8)
+#define SX1302_PKT_CHANNEL(buffer, start_index)                 TAKE_N_BITS_FROM(buffer[start_index +  3], 0, 8)
+#define SX1302_PKT_CRC_EN(buffer, start_index)                  TAKE_N_BITS_FROM(buffer[start_index +  4], 0, 1)
+#define SX1302_PKT_CODING_RATE(buffer, start_index)             TAKE_N_BITS_FROM(buffer[start_index +  4], 1, 3)
+#define SX1302_PKT_DATARATE(buffer, start_index)                TAKE_N_BITS_FROM(buffer[start_index +  4], 4, 4)
+#define SX1302_PKT_MODEM_ID(buffer, start_index)                TAKE_N_BITS_FROM(buffer[start_index +  5], 0, 8)
+#define SX1302_PKT_FREQ_OFFSET_7_0(buffer, start_index)         TAKE_N_BITS_FROM(buffer[start_index +  6], 0, 8)
+#define SX1302_PKT_FREQ_OFFSET_15_8(buffer, start_index)        TAKE_N_BITS_FROM(buffer[start_index +  7], 0, 8)
+#define SX1302_PKT_FREQ_OFFSET_19_16(buffer, start_index)       TAKE_N_BITS_FROM(buffer[start_index +  8], 0, 4)
+#define SX1302_PKT_CRC_ERROR(buffer, start_index)               TAKE_N_BITS_FROM(buffer[start_index +  9], 0, 1)
+#define SX1302_PKT_SYNC_ERROR(buffer, start_index)              TAKE_N_BITS_FROM(buffer[start_index +  9], 2, 1)
+#define SX1302_PKT_HEADER_ERROR(buffer, start_index)            TAKE_N_BITS_FROM(buffer[start_index +  9], 3, 1)
+#define SX1302_PKT_TIMING_SET(buffer, start_index)              TAKE_N_BITS_FROM(buffer[start_index +  9], 4, 1)
+#define SX1302_PKT_SNR_AVG(buffer, start_index)                 TAKE_N_BITS_FROM(buffer[start_index + 10], 0, 8)
+#define SX1302_PKT_RSSI_CHAN(buffer, start_index)               TAKE_N_BITS_FROM(buffer[start_index + 11], 0, 8)
+#define SX1302_PKT_RSSI_SIG(buffer, start_index)                TAKE_N_BITS_FROM(buffer[start_index + 12], 0, 8)
+#define SX1302_PKT_RSSI_CHAN_MAX_NEG_DELTA(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 13], 0, 4)
+#define SX1302_PKT_RSSI_CHAN_MAX_POS_DELTA(buffer, start_index) TAKE_N_BITS_FROM(buffer[start_index + 13], 4, 4)
+#define SX1302_PKT_RSSI_SIG_MAX_NEG_DELTA(buffer, start_index)  TAKE_N_BITS_FROM(buffer[start_index + 14], 0, 4)
+#define SX1302_PKT_RSSI_SIG_MAX_POS_DELTA(buffer, start_index)  TAKE_N_BITS_FROM(buffer[start_index + 14], 4, 4)
+#define SX1302_PKT_TIMESTAMP_7_0(buffer, start_index)           TAKE_N_BITS_FROM(buffer[start_index + 15], 0, 8)
+#define SX1302_PKT_TIMESTAMP_15_8(buffer, start_index)          TAKE_N_BITS_FROM(buffer[start_index + 16], 0, 8)
+#define SX1302_PKT_TIMESTAMP_23_16(buffer, start_index)         TAKE_N_BITS_FROM(buffer[start_index + 17], 0, 8)
+#define SX1302_PKT_TIMESTAMP_31_24(buffer, start_index)         TAKE_N_BITS_FROM(buffer[start_index + 18], 0, 8)
+#define SX1302_PKT_CRC_PAYLOAD_7_0(buffer, start_index)         TAKE_N_BITS_FROM(buffer[start_index + 19], 0, 8)
+#define SX1302_PKT_CRC_PAYLOAD_15_8(buffer, start_index)        TAKE_N_BITS_FROM(buffer[start_index + 20], 0, 8)
+#define SX1302_PKT_NUM_TS_METRICS(buffer, start_index)          TAKE_N_BITS_FROM(buffer[start_index + 21], 0, 8)
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE TYPES -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+/* RX buffer packet structure */
+#define SX1302_PKT_SYNCWORD_BYTE_0  0xA5
+#define SX1302_PKT_SYNCWORD_BYTE_1  0xC0
+#define SX1302_PKT_HEAD_METADATA    9
+#define SX1302_PKT_TAIL_METADATA    14
+
+/* modem IDs */
+#define SX1302_LORA_MODEM_ID_MAX    15
+#define SX1302_LORA_STD_MODEM_ID    16
+#define SX1302_FSK_MODEM_ID         17
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int rx_buffer_new(rx_buffer_t * self) {
+    /* Check input params */
+    CHECK_NULL(self);
+
+    /* Initialize members */
+    memset(self->buffer, 0, sizeof self->buffer);
+    self->buffer_size = 0;
+    self->buffer_index = 0;
+    self->buffer_pkt_nb = 0;
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int rx_buffer_del(rx_buffer_t * self) {
+    /* Check input params */
+    CHECK_NULL(self);
+
+    /* Reset index & size */
+    self->buffer_size = 0;
+    self->buffer_index = 0;
+    self->buffer_pkt_nb = 0;
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int rx_buffer_fetch(rx_buffer_t * self) {
+    int i, res;
+    uint8_t buff[2];
+    uint8_t payload_len;
+    uint16_t next_pkt_idx;
+    int idx;
+    uint16_t nb_bytes_1, nb_bytes_2;
+
+    /* Check input params */
+    CHECK_NULL(self);
+
+    /* Check if there is data in the FIFO */
+    lgw_reg_rb(SX1302_REG_RX_TOP_RX_BUFFER_NB_BYTES_MSB_RX_BUFFER_NB_BYTES, buff, sizeof buff);
+    nb_bytes_1 = (buff[0] << 8) | (buff[1] << 0);
+
+    /* Workaround for multi-byte read issue: read again and ensure new read is not lower than the previous one */
+    lgw_reg_rb(SX1302_REG_RX_TOP_RX_BUFFER_NB_BYTES_MSB_RX_BUFFER_NB_BYTES, buff, sizeof buff);
+    nb_bytes_2 = (buff[0] << 8) | (buff[1] << 0);
+
+    self->buffer_size = (nb_bytes_2 > nb_bytes_1) ? nb_bytes_2 : nb_bytes_1;
+
+    /* Fetch bytes from fifo if any */
+    if (self->buffer_size > 0) {
+        DEBUG_MSG   ("-----------------\n");
+        DEBUG_PRINTF("%s: nb_bytes to be fetched: %u (%u %u)\n", __FUNCTION__, self->buffer_size, buff[1], buff[0]);
+
+        memset(self->buffer, 0, sizeof self->buffer);
+        res = lgw_mem_rb(0x4000, self->buffer, self->buffer_size, true);
+        if (res != LGW_REG_SUCCESS) {
+            printf("ERROR: Failed to read RX buffer, SPI error\n");
+            return LGW_REG_ERROR;
+        }
+
+        /* print debug info */
+        DEBUG_MSG("RX_BUFFER: ");
+        for (i = 0; i < self->buffer_size; i++) {
+            DEBUG_PRINTF("%02X ", self->buffer[i]);
+        }
+        DEBUG_MSG("\n");
+
+        /* Sanity check: is there at least 1 complete packet in the buffer */
+        if (self->buffer_size < (SX1302_PKT_HEAD_METADATA + SX1302_PKT_TAIL_METADATA)) {
+            printf("WARNING: not enough data to have a complete packet, discard rx_buffer\n");
+            return rx_buffer_del(self);
+        }
+
+        /* Sanity check: is there a syncword at 0 ? If not, move to the first syncword found */
+        idx = 0;
+        while (idx <= (self->buffer_size - 2)) {
+            if ((self->buffer[idx] == SX1302_PKT_SYNCWORD_BYTE_0) && (self->buffer[idx + 1] == SX1302_PKT_SYNCWORD_BYTE_1)) {
+                DEBUG_PRINTF("INFO: syncword found at idx %d\n", idx);
+                break;
+            } else {
+                printf("INFO: syncword not found at idx %d\n", idx);
+                idx += 1;
+            }
+        }
+        if (idx > self->buffer_size - 2) {
+            printf("WARNING: no syncword found, discard rx_buffer\n");
+            return rx_buffer_del(self);
+        }
+        if (idx != 0) {
+            printf("INFO: re-sync rx_buffer at idx %d\n", idx);
+            memmove((void *)(self->buffer), (void *)(self->buffer + idx), self->buffer_size - idx);
+            self->buffer_size -= idx;
+        }
+
+        /* Rewind and parse buffer to get the number of packet fetched */
+        idx = 0;
+        while (idx < self->buffer_size) {
+            if ((self->buffer[idx] != SX1302_PKT_SYNCWORD_BYTE_0) || (self->buffer[idx + 1] != SX1302_PKT_SYNCWORD_BYTE_1)) {
+                printf("WARNING: syncword not found at idx %d, discard the rx_buffer\n", idx);
+                return rx_buffer_del(self);
+            }
+            /* One packet found in the buffer */
+            self->buffer_pkt_nb += 1;
+
+            /* Compute the number of bytes for this packet */
+            payload_len = SX1302_PKT_PAYLOAD_LENGTH(self->buffer, idx);
+            next_pkt_idx =  SX1302_PKT_HEAD_METADATA +
+                            payload_len +
+                            SX1302_PKT_TAIL_METADATA +
+                            (2 * SX1302_PKT_NUM_TS_METRICS(self->buffer, idx + payload_len));
+
+            /* Move to next packet */
+            idx += (int)next_pkt_idx;
+        }
+    }
+
+    /* Initialize the current buffer index to iterate on */
+    self->buffer_index = 0;
+
+    return LGW_REG_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int rx_buffer_pop(rx_buffer_t * self, rx_packet_t * pkt) {
+    int i;
+    uint8_t checksum_rcv, checksum_calc = 0;
+    uint16_t checksum_idx;
+    uint16_t pkt_num_bytes;
+
+    /* Check input params */
+    CHECK_NULL(self);
+    CHECK_NULL(pkt);
+
+    /* Is there any data to be parsed ? */
+    if (self->buffer_index >= self->buffer_size) {
+        DEBUG_MSG("INFO: No more data to be parsed\n");
+        return LGW_REG_ERROR;
+    }
+
+    /* Get pkt sync words */
+    if ((self->buffer[self->buffer_index] != SX1302_PKT_SYNCWORD_BYTE_0) || (self->buffer[self->buffer_index + 1] != SX1302_PKT_SYNCWORD_BYTE_1)) {
+        return LGW_REG_ERROR;
+    }
+    DEBUG_PRINTF("INFO: pkt syncword found at index %u\n", self->buffer_index);
+
+    /* Get payload length */
+    pkt->rxbytenb_modem = SX1302_PKT_PAYLOAD_LENGTH(self->buffer, self->buffer_index);
+
+    /* Get fine timestamp metrics */
+    pkt->num_ts_metrics_stored = SX1302_PKT_NUM_TS_METRICS(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
+
+    /* Calculate the total number of bytes in the packet */
+    pkt_num_bytes = SX1302_PKT_HEAD_METADATA + pkt->rxbytenb_modem + SX1302_PKT_TAIL_METADATA + (2 * pkt->num_ts_metrics_stored);
+
+    /* Check if we have a complete packet in the rx buffer fetched */
+    if((self->buffer_index + pkt_num_bytes) > self->buffer_size) {
+        printf("WARNING: aborting truncated message (size=%u)\n", self->buffer_size);
+        return LGW_REG_WARNING;
+    }
+
+    /* Get the checksum as received in the RX buffer */
+    checksum_idx = pkt_num_bytes - 1;
+    checksum_rcv = self->buffer[self->buffer_index + pkt_num_bytes - 1];
+
+    /* Calculate the checksum from the actual payload bytes received */
+    for (i = 0; i < (int)checksum_idx; i++) {
+        checksum_calc += self->buffer[self->buffer_index + i];
+    }
+
+    /* Check if the checksum is correct */
+    if (checksum_rcv != checksum_calc) {
+        printf("WARNING: checksum failed (got:0x%02X calc:0x%02X)\n", checksum_rcv, checksum_calc);
+        return LGW_REG_WARNING;
+    } else {
+        DEBUG_PRINTF("Packet checksum OK (0x%02X)\n", checksum_rcv);
+    }
+
+    /* Parse packet metadata */
+    pkt->modem_id = SX1302_PKT_MODEM_ID(self->buffer, self->buffer_index);
+    pkt->rx_channel_in = SX1302_PKT_CHANNEL(self->buffer, self->buffer_index);
+    pkt->crc_en = SX1302_PKT_CRC_EN(self->buffer, self->buffer_index);
+    pkt->payload_crc_error = SX1302_PKT_CRC_ERROR(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
+    pkt->sync_error = SX1302_PKT_SYNC_ERROR(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
+    pkt->header_error = SX1302_PKT_HEADER_ERROR(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
+    pkt->timing_set = SX1302_PKT_TIMING_SET(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
+    pkt->coding_rate = SX1302_PKT_CODING_RATE(self->buffer, self->buffer_index);
+    pkt->rx_rate_sf = SX1302_PKT_DATARATE(self->buffer, self->buffer_index);
+    pkt->rssi_chan_avg = SX1302_PKT_RSSI_CHAN(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
+    pkt->rssi_signal_avg = SX1302_PKT_RSSI_SIG(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
+    pkt->rx_crc16_value  = (uint16_t)((SX1302_PKT_CRC_PAYLOAD_7_0(self->buffer, self->buffer_index + pkt->rxbytenb_modem) <<  0) & 0x00FF);
+    pkt->rx_crc16_value |= (uint16_t)((SX1302_PKT_CRC_PAYLOAD_15_8(self->buffer, self->buffer_index + pkt->rxbytenb_modem) <<  8) & 0xFF00);
+    pkt->snr_average = (int8_t)SX1302_PKT_SNR_AVG(self->buffer, self->buffer_index + pkt->rxbytenb_modem);
+
+    pkt->frequency_offset_error = (int32_t)((SX1302_PKT_FREQ_OFFSET_19_16(self->buffer, self->buffer_index) << 16) | (SX1302_PKT_FREQ_OFFSET_15_8(self->buffer, self->buffer_index) << 8) | (SX1302_PKT_FREQ_OFFSET_7_0(self->buffer, self->buffer_index) << 0));
+    if (pkt->frequency_offset_error >= (1<<19)) { /* Handle signed value on 20bits */
+        pkt->frequency_offset_error = (pkt->frequency_offset_error - (1<<20));
+    }
+
+    /* Packet timestamp (32MHz ) */
+    pkt->timestamp_cnt  = (uint32_t)((SX1302_PKT_TIMESTAMP_7_0(self->buffer, self->buffer_index + pkt->rxbytenb_modem) <<  0) & 0x000000FF);
+    pkt->timestamp_cnt |= (uint32_t)((SX1302_PKT_TIMESTAMP_15_8(self->buffer, self->buffer_index + pkt->rxbytenb_modem) <<  8) & 0x0000FF00);
+    pkt->timestamp_cnt |= (uint32_t)((SX1302_PKT_TIMESTAMP_23_16(self->buffer, self->buffer_index + pkt->rxbytenb_modem) << 16) & 0x00FF0000);
+    pkt->timestamp_cnt |= (uint32_t)((SX1302_PKT_TIMESTAMP_31_24(self->buffer, self->buffer_index + pkt->rxbytenb_modem) << 24) & 0xFF000000);
+
+    /* TS metrics: it is expected the nb_symbols parameter is set to 0 here */
+    for (i = 0; i < (pkt->num_ts_metrics_stored * 2); i++) {
+        pkt->timestamp_avg[i] = (int8_t)SX1302_PKT_NUM_TS_METRICS(self->buffer, self->buffer_index + pkt->rxbytenb_modem + 1 + i);
+        pkt->timestamp_stddev[i] = 0; /* no stddev when nb_symbols == 0 */
+    }
+
+    DEBUG_MSG   ("-----------------\n");
+    DEBUG_PRINTF("  modem:      %u\n", pkt->modem_id);
+    DEBUG_PRINTF("  chan:       %u\n", pkt->rx_channel_in);
+    DEBUG_PRINTF("  size:       %u\n", pkt->rxbytenb_modem);
+    DEBUG_PRINTF("  crc_en:     %u\n", pkt->crc_en);
+    DEBUG_PRINTF("  crc_err:    %u\n", pkt->payload_crc_error);
+    DEBUG_PRINTF("  sync_err:   %u\n", pkt->sync_error);
+    DEBUG_PRINTF("  hdr_err:    %u\n", pkt->header_error);
+    DEBUG_PRINTF("  timing_set: %u\n", pkt->timing_set);
+    DEBUG_PRINTF("  codr:       %u\n", pkt->coding_rate);
+    DEBUG_PRINTF("  datr:       %u\n", pkt->rx_rate_sf);
+    DEBUG_PRINTF("  num_ts:     %u\n", pkt->num_ts_metrics_stored);
+    if (pkt->num_ts_metrics_stored > 0) {
+        DEBUG_MSG("  ts_avg:     ");
+        for (i = 0; i < (pkt->num_ts_metrics_stored * 2); i++) {
+            DEBUG_PRINTF("%d ", pkt->timestamp_avg[i]);
+        }
+        DEBUG_MSG("\n");
+        DEBUG_MSG("  ts_stdev:   NONE (nb_symbols=0)\n");
+    }
+    DEBUG_MSG   ("-----------------\n");
+
+    /* Sanity checks: check the range of few metadata */
+    if (pkt->modem_id > SX1302_FSK_MODEM_ID) {
+        printf("ERROR: modem_id is out of range - %u\n", pkt->modem_id);
+        return LGW_REG_ERROR;
+    } else {
+        if (pkt->modem_id <= SX1302_LORA_STD_MODEM_ID) { /* LoRa modems */
+            if (pkt->rx_channel_in > 9) {
+                printf("ERROR: channel is out of range - %u\n", pkt->rx_channel_in);
+                return LGW_REG_ERROR;
+            }
+            if ((pkt->rx_rate_sf < 5) || (pkt->rx_rate_sf > 12)) {
+                printf("ERROR: SF is out of range - %u\n", pkt->rx_rate_sf);
+                return LGW_REG_ERROR;
+            }
+        } else { /* FSK modem */
+            /* TODO: not checked */
+        }
+    }
+
+    /* Parse & copy payload in packet struct */
+    memcpy((void *)pkt->payload, (void *)(&(self->buffer[self->buffer_index + SX1302_PKT_HEAD_METADATA])), pkt->rxbytenb_modem);
+
+    /* Move buffer index toward next message */
+    self->buffer_index += (SX1302_PKT_HEAD_METADATA + pkt->rxbytenb_modem + SX1302_PKT_TAIL_METADATA + (2 * pkt->num_ts_metrics_stored));
+
+    /* Update the number of packets currently stored in the rx_buffer */
+    self->buffer_pkt_nb -= 1;
+
+    return LGW_REG_SUCCESS;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- DEBUG FUNCTIONS DEFINITION ------------------------------------------- */
+
+uint16_t rx_buffer_read_ptr_addr(void) {
+    int32_t val;
+    uint16_t addr;
+
+    lgw_reg_r(SX1302_REG_RX_TOP_RX_BUFFER_LAST_ADDR_READ_MSB_LAST_ADDR_READ, &val); /* mandatory to read MSB first */
+    addr  = (uint16_t)(val << 8);
+    lgw_reg_r(SX1302_REG_RX_TOP_RX_BUFFER_LAST_ADDR_READ_LSB_LAST_ADDR_READ, &val);
+    addr |= (uint16_t)val;
+
+    return addr;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint16_t rx_buffer_write_ptr_addr(void) {
+    int32_t val;
+    uint16_t addr;
+
+    lgw_reg_r(SX1302_REG_RX_TOP_RX_BUFFER_LAST_ADDR_WRITE_MSB_LAST_ADDR_WRITE, &val);  /* mandatory to read MSB first */
+    addr  = (uint16_t)(val << 8);
+    lgw_reg_r(SX1302_REG_RX_TOP_RX_BUFFER_LAST_ADDR_WRITE_LSB_LAST_ADDR_WRITE, &val);
+    addr |= (uint16_t)val;
+
+    return addr;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void rx_buffer_dump(FILE * file, uint16_t start_addr, uint16_t end_addr) {
+    int i;
+    uint8_t rx_buffer_debug[4096];
+
+    printf("Dumping %u bytes, from 0x%X to 0x%X\n", end_addr - start_addr + 1, start_addr, end_addr);
+
+    memset(rx_buffer_debug, 0, sizeof rx_buffer_debug);
+
+    lgw_reg_w(SX1302_REG_RX_TOP_RX_BUFFER_DIRECT_RAM_IF, 1);
+    lgw_mem_rb(0x4000 + start_addr, rx_buffer_debug, end_addr - start_addr + 1, false);
+    lgw_reg_w(SX1302_REG_RX_TOP_RX_BUFFER_DIRECT_RAM_IF, 0);
+
+    for (i = 0; i < (end_addr - start_addr + 1); i++) {
+        if (file == NULL) {
+            printf("%02X ", rx_buffer_debug[i]);
+        } else {
+            fprintf(file, "%02X ", rx_buffer_debug[i]);
+        }
+    }
+    if (file == NULL) {
+        printf("\n");
+    } else {
+        fprintf(file, "\n");
+    }
+
+    /* Switching to direct-access memory could lead to corruption, so to be done only for debugging */
+    assert(0);
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 634 - 0
sx1302/source/loragw_sx1302_timestamp.c

@@ -0,0 +1,634 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    SX1302 timestamp counter Hardware Abstraction Layer
+    Handles the conversion of a 32-bits 32MHz counter into a 32-bits 1 MHz counter.
+    This modules MUST be called regularly by the application to maintain counter
+    wrapping handling for conversion in 1MHz counter.
+    Provides function to compute the correction to be applied to the received
+    timestamp for demodulation processing time.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdbool.h>    /* boolean type */
+#include <stdio.h>      /* printf fprintf */
+#include <memory.h>     /* memset */
+#include <inttypes.h>   /* PRIx64, PRIu64... */
+#include <assert.h>
+
+#include "loragw_sx1302_timestamp.h"
+#include "loragw_reg.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_FTIME == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout, fmt, 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 -------------------------------------------------------- */
+
+#define MAX_TIMESTAMP_PPS_HISTORY 16
+struct timestamp_pps_history_s {
+    uint32_t history[MAX_TIMESTAMP_PPS_HISTORY];
+    uint8_t idx; /* next slot to be written */
+    uint8_t size; /* current size */
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define PRECISION_TIMESTAMP_TS_METRICS_MAX  32 /* reduce number of metrics to better match GW v2 fine timestamp (max is 255) */
+#define PRECISION_TIMESTAMP_NB_SYMBOLS      0
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+/* history of the last PPS timestamps */
+static struct timestamp_pps_history_s timestamp_pps_history = {
+    .history = { 0 },
+    .idx = 0,
+    .size = 0
+};
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
+
+/**
+@brief TODO
+@param TODO
+@return The correction to be applied to the packet timestamp, in microseconds
+*/
+int32_t legacy_timestamp_correction(uint8_t bandwidth, uint8_t datarate, uint8_t coderate, bool no_crc, uint8_t payload_length, sx1302_rx_dft_peak_mode_t dft_peak_mode);
+
+/**
+@brief TODO
+@param TODO
+@return The correction to be applied to the packet timestamp, in microseconds
+*/
+int32_t precision_timestamp_correction(uint8_t bandwidth, uint8_t datarate, uint8_t coderate, bool crc_en, uint8_t payload_length);
+
+
+/**
+@brief TODO
+@param TODO
+@return The correction to be applied to the packet timestamp, in microseconds
+*/
+void timestamp_pps_history_save(uint32_t timestamp_pps_reg);
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+int32_t legacy_timestamp_correction(uint8_t bandwidth, uint8_t sf, uint8_t cr, bool crc_en, uint8_t payload_length, sx1302_rx_dft_peak_mode_t dft_peak_mode) {
+    uint64_t clk_period, filtering_delay, demap_delay, fft_delay_state3, fft_delay, decode_delay, total_delay;
+    uint32_t nb_nibble, nb_nibble_in_hdr, nb_nibble_in_last_block;
+    uint8_t nb_iter, bw_pow, dft_peak_en = (dft_peak_mode == RX_DFT_PEAK_MODE_DISABLED) ? 0 : 1;
+    uint8_t ppm = SET_PPM_ON(bandwidth, sf) ? 1 : 0;
+    int32_t timestamp_correction;
+    bool payload_fits_in_header = false;
+    uint8_t cr_local = cr;
+
+    switch (bandwidth)
+    {
+        case BW_125KHZ:
+            bw_pow = 1;
+            break;
+        case BW_250KHZ:
+            bw_pow = 2;
+            break;
+        case BW_500KHZ:
+            bw_pow = 4;
+            break;
+        default:
+            printf("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT - %s\n", bandwidth, __FUNCTION__);
+            return 0;
+    }
+
+    /* Prepare variables for delay computing */
+    clk_period = 250E3 / bw_pow;
+
+    nb_nibble = (payload_length + 2 * crc_en) * 2 + 5;
+
+    if ((sf == 5) || (sf == 6)) {
+        nb_nibble_in_hdr = sf;
+    } else {
+        nb_nibble_in_hdr = sf - 2;
+    }
+
+    nb_nibble_in_last_block = nb_nibble - nb_nibble_in_hdr - (sf - 2 * ppm) * ((nb_nibble - nb_nibble_in_hdr) / (sf - 2 * ppm));
+    if (nb_nibble_in_last_block == 0) {
+        nb_nibble_in_last_block = sf - 2 * ppm;
+    }
+
+    nb_iter = (sf + 1) / 2; /* intended to be truncated */
+
+    /* Update some variables if payload fits entirely in the header */
+    if (((int)(2 * (payload_length + 2 * crc_en) - (sf - 7)) <= 0) || ((payload_length == 0) && (crc_en == false))) {
+        /* Payload fits entirely in first 8 symbols (header):
+            - not possible for SF5/SF6, unless payload length is 0 and no CRC
+        */
+        payload_fits_in_header = true;
+
+        /* overwrite some variables accordingly */
+        dft_peak_en = 0;
+
+        cr_local = 4; /* header coding rate is 4 */
+
+        if (sf > 6) {
+            nb_nibble_in_last_block = sf - 2;
+        } else {
+            nb_nibble_in_last_block = sf;
+        }
+    }
+
+    /* Filtering delay : I/Q 32Mhz -> 4Mhz */
+    filtering_delay = 16000E3 / bw_pow + 2031250;
+
+    /* demap delay */
+    if (payload_fits_in_header == true) {
+        demap_delay = clk_period + (1 << sf) * clk_period * 3 / 4 + 3 * clk_period + (sf - 2) * clk_period;
+    } else {
+        demap_delay = clk_period + (1 << sf) * clk_period * (1 - ppm / 4) + 3 * clk_period + (sf - 2 * ppm) * clk_period;
+    }
+
+    /* FFT delays */
+    fft_delay_state3 = clk_period * (((1 << sf) - 6) + 2 * ((1 << sf) * (nb_iter - 1) + 6)) + 4 * clk_period;
+
+    if (dft_peak_en) {
+        fft_delay = (5 - 2 * ppm) * ((1 << sf) * clk_period + 7 * clk_period) + 2 * clk_period;
+    } else {
+        fft_delay = (1 << sf) * 2 * clk_period + 3 * clk_period;
+    }
+
+    /* Decode delay */
+    decode_delay = 5 * clk_period + (9 * clk_period + clk_period * cr_local) * nb_nibble_in_last_block + 3 * clk_period;
+
+    /* Cumulated delays */
+    total_delay = (filtering_delay + fft_delay_state3 + fft_delay + demap_delay + decode_delay + 500E3) / 1E6;
+
+    if (total_delay > INT32_MAX) {
+        printf("ERROR: overflow error for timestamp correction (SHOULD NOT HAPPEN)\n");
+        printf("=> filtering_delay %" PRIu64 "\n", filtering_delay);
+        printf("=> fft_delay_state3 %" PRIu64 "\n", fft_delay_state3);
+        printf("=> fft_delay %" PRIu64 "\n", fft_delay);
+        printf("=> demap_delay %" PRIu64 "\n", demap_delay);
+        printf("=> decode_delay %" PRIu64 "\n", decode_delay);
+        printf("=> total_delay %" PRIu64 "\n", total_delay);
+        assert(0);
+    }
+
+    timestamp_correction = -((int32_t)total_delay); /* compensate all decoding processing delays */
+
+    DEBUG_PRINTF("FTIME OFF : filtering_delay %llu \n", filtering_delay);
+    DEBUG_PRINTF("FTIME OFF : fft_delay_state3 %llu \n", fft_delay_state3);
+    DEBUG_PRINTF("FTIME OFF : fft_delay %llu \n", fft_delay);
+    DEBUG_PRINTF("FTIME OFF : demap_delay %llu \n", demap_delay);
+    DEBUG_PRINTF("FTIME OFF : decode_delay %llu \n", decode_delay);
+    DEBUG_PRINTF("FTIME OFF : timestamp correction %d \n", timestamp_correction);
+
+    return timestamp_correction;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int32_t precision_timestamp_correction(uint8_t bandwidth, uint8_t datarate, uint8_t coderate, bool crc_en, uint8_t payload_length) {
+    uint32_t nb_symbols_payload;
+    uint16_t t_symbol_us;
+    int32_t timestamp_correction;
+    uint8_t bw_pow;
+    uint32_t filtering_delay;
+
+    switch (bandwidth)
+    {
+        case BW_125KHZ:
+            bw_pow = 1;
+            break;
+        case BW_250KHZ:
+            bw_pow = 2;
+            break;
+        case BW_500KHZ:
+            bw_pow = 4;
+            break;
+        default:
+            printf("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT - %s\n", bandwidth, __FUNCTION__);
+            return 0;
+    }
+
+    filtering_delay = 16000000 / bw_pow + 2031250;
+
+    /* NOTE: no need of the preamble size, only the payload duration is needed */
+    /* WARNING: implicit header not supported */
+    if (lora_packet_time_on_air(bandwidth, datarate, coderate, 0, false, !crc_en, payload_length, NULL, &nb_symbols_payload, &t_symbol_us) == 0) {
+        printf("ERROR: failed to compute packet time on air - %s\n", __FUNCTION__);
+        return 0;
+    }
+
+    timestamp_correction = 0;
+    timestamp_correction += (nb_symbols_payload * t_symbol_us); /* shift from end of header to end of packet */
+    timestamp_correction -= (filtering_delay + 500E3) / 1E6; /* compensate the filtering delay */
+
+    DEBUG_PRINTF("FTIME ON : timestamp correction %d \n", timestamp_correction);
+
+    return timestamp_correction;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void timestamp_pps_history_save(uint32_t timestamp_pps_reg) {
+    /* Store it only if different from the previous one */
+    if ((timestamp_pps_reg != timestamp_pps_history.history[timestamp_pps_history.idx] || (timestamp_pps_history.size == 0))) {
+        /* Select next index */
+        if (timestamp_pps_history.size > 0) {
+            timestamp_pps_history.idx += 1;
+        }
+        if (timestamp_pps_history.idx == MAX_TIMESTAMP_PPS_HISTORY) {
+            timestamp_pps_history.idx = 0;
+        }
+
+        /* Set PPS counter value */
+        timestamp_pps_history.history[timestamp_pps_history.idx] = timestamp_pps_reg;
+
+        /* Add one entry to the history */
+        if (timestamp_pps_history.size < MAX_TIMESTAMP_PPS_HISTORY) {
+            timestamp_pps_history.size += 1;
+        }
+
+#if 0
+        printf("---- timestamp PPS history (idx:%u size:%u) ----\n",  timestamp_pps_history.idx,  timestamp_pps_history.size);
+        for (int i = 0; i < timestamp_pps_history.size; i++) {
+            printf("  %u\n", timestamp_pps_history.history[i]);
+        }
+        printf("--------------------------------\n");
+#endif
+    }
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+void timestamp_counter_new(timestamp_counter_t * self) {
+    memset(self, 0, sizeof(*self));
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void timestamp_counter_delete(timestamp_counter_t * self) {
+    memset(self, 0, sizeof(*self));
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void timestamp_counter_update(timestamp_counter_t * self, uint32_t pps, uint32_t inst) {
+    //struct timestamp_info_s* tinfo = (pps == true) ? &self->pps : &self->inst;
+
+    /* Check if counter has wrapped, and update wrap status if necessary */
+    if (pps < self->pps.counter_us_27bits_ref) {
+        self->pps.counter_us_27bits_wrap += 1;
+        self->pps.counter_us_27bits_wrap %= 32;
+    }
+    if (inst < self->inst.counter_us_27bits_ref) {
+        self->inst.counter_us_27bits_wrap += 1;
+        self->inst.counter_us_27bits_wrap %= 32;
+    }
+
+    /* Update counter reference */
+    self->pps.counter_us_27bits_ref = pps;
+    self->inst.counter_us_27bits_ref = inst;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int timestamp_counter_get(timestamp_counter_t * self, uint32_t * inst, uint32_t * pps) {
+    int x;
+    uint8_t buff[8];
+    uint8_t buff_wa[8];
+    uint32_t counter_inst_us_raw_27bits_now;
+    uint32_t counter_pps_us_raw_27bits_now;
+
+    /* Get the freerun and pps 32MHz timestamp counters - 8 bytes
+            0 -> 3 : PPS counter
+            4 -> 7 : Freerun counter (inst)
+    */
+    x = lgw_reg_rb(SX1302_REG_TIMESTAMP_TIMESTAMP_PPS_MSB2_TIMESTAMP_PPS, &buff[0], 8);
+    if (x != LGW_REG_SUCCESS) {
+        printf("ERROR: Failed to get timestamp counter value\n");
+        return -1;
+    }
+
+    /* Workaround concentrator chip issue:
+        - read MSB again
+        - if MSB changed, read the full counter again
+     */
+    x = lgw_reg_rb(SX1302_REG_TIMESTAMP_TIMESTAMP_PPS_MSB2_TIMESTAMP_PPS, &buff_wa[0], 8);
+    if (x != LGW_REG_SUCCESS) {
+        printf("ERROR: Failed to get timestamp counter MSB value\n");
+        return -1;
+    }
+    if ((buff[0] != buff_wa[0]) || (buff[4] != buff_wa[4])) {
+        x = lgw_reg_rb(SX1302_REG_TIMESTAMP_TIMESTAMP_PPS_MSB2_TIMESTAMP_PPS, &buff_wa[0], 8);
+        if (x != LGW_REG_SUCCESS) {
+            printf("ERROR: Failed to get timestamp counter MSB value\n");
+            return -1;
+        }
+        memcpy(buff, buff_wa, 8); /* use the new read value */
+    }
+
+    counter_pps_us_raw_27bits_now  = (buff[0]<<24) | (buff[1]<<16) | (buff[2]<<8) | buff[3];
+    counter_inst_us_raw_27bits_now = (buff[4]<<24) | (buff[5]<<16) | (buff[6]<<8) | buff[7];
+
+    /* Store PPS counter to history, for fine timestamp calculation */
+    timestamp_pps_history_save(counter_pps_us_raw_27bits_now);
+
+    /* Scale to 1MHz */
+    counter_pps_us_raw_27bits_now /= 32;
+    counter_inst_us_raw_27bits_now /= 32;
+
+    /* Update counter wrapping status */
+    timestamp_counter_update(self, counter_pps_us_raw_27bits_now, counter_inst_us_raw_27bits_now);
+
+    /* Convert 27-bits counter to 32-bits counter */
+    *inst = timestamp_counter_expand(self, false, counter_inst_us_raw_27bits_now);
+    *pps  = timestamp_counter_expand(self, true, counter_pps_us_raw_27bits_now);
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint32_t timestamp_counter_expand(timestamp_counter_t * self, bool pps, uint32_t cnt_us) {
+    struct timestamp_info_s* tinfo = (pps == true) ? &self->pps : &self->inst;
+    uint32_t counter_us_32bits;
+
+    counter_us_32bits = (tinfo->counter_us_27bits_wrap << 27) | cnt_us;
+
+#if 0
+    /* DEBUG: to be enabled when running test_loragw_counter test application
+       This generates a CSV log, and can be plotted with gnuplot:
+        > set datafile separator comma
+        > plot for [col=1:2:1] 'log_count.txt' using col with lines
+    */
+    printf("%u,%u,%u\n", cnt_us, counter_us_32bits, tinfo->counter_us_27bits_wrap);
+#endif
+
+    return counter_us_32bits;
+}
+
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint32_t timestamp_pkt_expand(timestamp_counter_t * self, uint32_t pkt_cnt_us) {
+    struct timestamp_info_s* tinfo = &self->inst;
+    uint32_t counter_us_32bits;
+    uint8_t wrap_status;
+
+    /* Check if counter has wrapped since the packet has been received in the sx1302 internal FIFO */
+    /* If the sx1302 counter was greater than the pkt timestamp, it means that the internal counter
+        hasn't rolled over since the packet has been received by the sx1302
+        case 1: --|-P--|----|--R-|----|--||-|----|-- : use current wrap status counter
+        case 2: --|-P-||-|-R--|-- : use previous wrap status counter
+        P : packet received in sx1302 internal FIFO
+        R : read packet from sx1302 internal FIFO
+        | : last update internal counter ref value.
+        ||: sx1302 internal counter rollover (wrap)
+    */
+
+    /* Use current wrap counter or previous ? */
+    wrap_status = tinfo->counter_us_27bits_wrap - ((tinfo->counter_us_27bits_ref >= pkt_cnt_us) ? 0 : 1);
+    wrap_status &= 0x1F; /* [0..31] */
+
+    /* Expand packet counter */
+    counter_us_32bits = (wrap_status << 27) | pkt_cnt_us;
+
+    return counter_us_32bits;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int timestamp_counter_mode(bool ftime_enable) {
+    int x = LGW_REG_SUCCESS;
+
+    if (ftime_enable == false) {
+        printf("INFO: using legacy timestamp\n");
+        /* Latch end-of-packet timestamp (sx1301 compatibility) */
+        x |= lgw_reg_w(SX1302_REG_RX_TOP_RX_BUFFER_LEGACY_TIMESTAMP, 0x01);
+    } else {
+        printf("INFO: using precision timestamp (max_ts_metrics:%u nb_symbols:%u)\n", PRECISION_TIMESTAMP_TS_METRICS_MAX, PRECISION_TIMESTAMP_NB_SYMBOLS);
+
+        /* Latch end-of-preamble timestamp */
+        x |= lgw_reg_w(SX1302_REG_RX_TOP_RX_BUFFER_LEGACY_TIMESTAMP, 0x00);
+        x |= lgw_reg_w(SX1302_REG_RX_TOP_RX_BUFFER_TIMESTAMP_CFG_MAX_TS_METRICS, (int32_t)PRECISION_TIMESTAMP_TS_METRICS_MAX);
+
+        /* LoRa multi-SF modems */
+        x |= lgw_reg_w(SX1302_REG_RX_TOP_TIMESTAMP_ENABLE, 0x01);
+        x |= lgw_reg_w(SX1302_REG_RX_TOP_TIMESTAMP_NB_SYMB, (int32_t)PRECISION_TIMESTAMP_NB_SYMBOLS);
+    }
+
+    return x;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int32_t timestamp_counter_correction(lgw_context_t * context, uint8_t bandwidth, uint8_t datarate, uint8_t coderate, bool crc_en, uint8_t payload_length, sx1302_rx_dft_peak_mode_t dft_peak_mode) {
+    /* Check input parameters */
+    CHECK_NULL(context);
+    if (IS_LORA_DR(datarate) == false) {
+        printf("ERROR: wrong datarate (%u) - %s\n", datarate, __FUNCTION__);
+        return 0;
+    }
+    if (IS_LORA_BW(bandwidth) == false) {
+        printf("ERROR: wrong bandwidth (%u) - %s\n", bandwidth, __FUNCTION__);
+        return 0;
+    }
+    if (IS_LORA_CR(coderate) == false) {
+        printf("ERROR: wrong coding rate (%u) - %s\n", coderate, __FUNCTION__);
+        return 0;
+    }
+
+    /* Calculate the correction to be applied */
+    if (context->ftime_cfg.enable == false) {
+        return legacy_timestamp_correction(bandwidth, datarate, coderate, crc_en, payload_length, dft_peak_mode);
+    } else {
+        return precision_timestamp_correction(bandwidth, datarate, coderate, crc_en, payload_length);
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int precise_timestamp_calculate(uint8_t ts_metrics_nb, const int8_t * ts_metrics, uint32_t timestamp_cnt, uint8_t sf, int32_t if_freq_hz, double pkt_freq_error, uint32_t * result_ftime) {
+    int i, x, timestamp_pps_idx, timestamp_pps_idx_next, timestamp_pps_idx_prev;
+    int32_t ftime_sum;
+    int32_t ftime[256];
+    float ftime_mean;
+    uint32_t timestamp_cnt_end_of_preamble;
+    uint32_t timestamp_pps = 0;
+    uint32_t timestamp_pps_reg = 0;
+    uint32_t offset_preamble_hdr;
+    uint8_t buff[4];
+    uint32_t diff_pps;
+    double pkt_ftime;
+    uint8_t ts_metrics_nb_clipped;
+    double xtal_correct;
+
+    /* Check input parameters */
+    CHECK_NULL(ts_metrics);
+    CHECK_NULL(result_ftime);
+
+    /* Check if we can calculate a ftime */
+    if (timestamp_pps_history.size < MAX_TIMESTAMP_PPS_HISTORY) {
+        printf("INFO: Cannot compute ftime yet, PPS history is too short\n");
+        return -1;
+    }
+
+    /* Coarse timestamp correction to match with GW v2 (end of header -> end of preamble) */
+    offset_preamble_hdr =   256 * (1 << sf) * (8 + 4 + (((sf == 5) || (sf == 6)) ? 2 : 0)) +
+                            256 * ((1 << sf) / 4 - 1); /* 32e6 / 125e3 = 256 */
+
+    /* Take the packet frequency error in account in the offset */
+    offset_preamble_hdr += ((double)offset_preamble_hdr * pkt_freq_error + 0.5);
+
+    timestamp_cnt_end_of_preamble = timestamp_cnt - offset_preamble_hdr + 2138; /* 2138 is the number of 32MHz clock cycle offset b/w GW_V2 and SX1303 decimation/filtering group delay */
+
+    /* Shift the packet coarse timestamp which is used to get ref PPS counter */
+    timestamp_cnt = timestamp_cnt_end_of_preamble;
+
+    /* Clip the number of metrics depending on Spreading Factor, reduce fine timestamp variation versus packet duration */
+    switch (sf) {
+        case 12:
+            ts_metrics_nb_clipped = MIN(4, ts_metrics_nb);
+            break;
+        case 11:
+            ts_metrics_nb_clipped = MIN(8, ts_metrics_nb);
+            break;
+        case 10:
+            ts_metrics_nb_clipped = MIN(16, ts_metrics_nb);
+            break;
+        default:
+            ts_metrics_nb_clipped = MIN(32, ts_metrics_nb);
+            break;
+    }
+
+#if 0
+    printf("%s\n", __FUNCTION__);
+    printf("ts_metrics_nb_clipped*2: %u\n", ts_metrics_nb_clipped * 2);
+    for (i = 0; i < (2 * ts_metrics_nb_clipped); i++) {
+        printf("%d ", ts_metrics[i]);
+    }
+    printf("\n");
+#endif
+
+    /* Compute the ftime cumulative sum */
+    ftime[0] = (int32_t)ts_metrics[0];
+    ftime_sum = ftime[0];
+    for (i = 1; i < (2 * ts_metrics_nb_clipped); i++) {
+        ftime[i] = ftime[i-1] + ts_metrics[i];
+        ftime_sum += ftime[i];
+    }
+
+    /* Compute the mean of the cumulative sum */
+    ftime_mean = (float)ftime_sum / (float)(2 * ts_metrics_nb_clipped);
+
+    /* Find the last timestamp_pps before packet to use as reference for ftime */
+    x = lgw_reg_rb(SX1302_REG_TIMESTAMP_TIMESTAMP_PPS_MSB2_TIMESTAMP_PPS , &buff[0], 4);
+    if (x != LGW_REG_SUCCESS) {
+        printf("ERROR: Failed to get timestamp counter value\n");
+        return 0;
+    }
+    timestamp_pps_reg  = (uint32_t)((buff[0] << 24) & 0xFF000000);
+    timestamp_pps_reg |= (uint32_t)((buff[1] << 16) & 0x00FF0000);
+    timestamp_pps_reg |= (uint32_t)((buff[2] << 8)  & 0x0000FF00);
+    timestamp_pps_reg |= (uint32_t)((buff[3] << 0)  & 0x000000FF);
+
+    /* Ensure that the timestamp PPS history is up-to-date */
+    timestamp_pps_history_save(timestamp_pps_reg);
+
+    /* Check if timestamp_pps_reg we just read is the reference to be used to compute ftime or not */
+    if ((timestamp_cnt - timestamp_pps_reg) > 32e6) {
+        /* The timestamp_pps_reg we just read is after the packet timestamp, we need to rewind */
+        for (timestamp_pps_idx = 0; timestamp_pps_idx < timestamp_pps_history.size; timestamp_pps_idx++) {
+            /* search the pps counter in history */
+            if ((timestamp_cnt - timestamp_pps_history.history[timestamp_pps_idx]) < 32e6) {
+                timestamp_pps = timestamp_pps_history.history[timestamp_pps_idx];
+                DEBUG_PRINTF("==> timestamp_pps found at history[%d] => %u\n", timestamp_pps_idx, timestamp_pps);
+                break;
+            }
+        }
+        if (timestamp_pps_idx == timestamp_pps_history.size) {
+            printf("ERROR: failed to find the reference timestamp_pps, cannot compute ftime\n");
+            return -1;
+        }
+
+        /* Calculate the Xtal error between the reference PPS we just found and the next one */
+        timestamp_pps_idx_next = (timestamp_pps_idx == (MAX_TIMESTAMP_PPS_HISTORY - 1)) ? 0 : timestamp_pps_idx + 1;
+        diff_pps = timestamp_pps_history.history[timestamp_pps_idx_next] - timestamp_pps_history.history[timestamp_pps_idx];
+        xtal_correct = (double)32e6 / (double)(diff_pps);
+    } else {
+        /* The timestamp_pps_reg we just read is the reference we use to calculate the fine timestamp */
+        timestamp_pps = timestamp_pps_reg;
+        DEBUG_PRINTF("==> timestamp_pps => %u\n", timestamp_pps);
+
+        /* Calculate the Xtal error between the reference PPS we just found and the previous one */
+        timestamp_pps_idx = timestamp_pps_history.idx;
+        timestamp_pps_idx_prev = (timestamp_pps_idx == 0) ? (MAX_TIMESTAMP_PPS_HISTORY - 1) : (timestamp_pps_idx - 1);
+        diff_pps = timestamp_pps_history.history[timestamp_pps_idx] - timestamp_pps_history.history[timestamp_pps_idx_prev];
+        xtal_correct = (double)32e6 / (double)(diff_pps);
+    }
+
+    /* Sanity Check on xtal_correct */
+    if ((xtal_correct > 1.2) || (xtal_correct < 0.8)) {
+        printf("ERROR: xtal_error is invalid (%.15lf)\n", xtal_correct);
+        return -1;
+    }
+
+    /* Coarse timestamp based on PPS reference */
+    diff_pps = timestamp_cnt - timestamp_pps;
+
+    DEBUG_PRINTF("timestamp_cnt : %u\n", timestamp_cnt);
+    DEBUG_PRINTF("timestamp_pps : %u\n", timestamp_pps);
+    DEBUG_PRINTF("diff_pps : %d\n", diff_pps);
+
+    /* Compute the fine timestamp */
+    pkt_ftime = (double)diff_pps + (double)ftime_mean;
+    DEBUG_PRINTF("pkt_ftime = %f\n", pkt_ftime);
+
+    /* Add the DC notch filtering delay if necessary */
+    pkt_ftime += sx1302_dc_notch_delay((double)if_freq_hz / 1E3);
+
+    /* Convert fine timestamp from 32 Mhz clock to nanoseconds */
+    pkt_ftime *= 31.25;
+
+    /* Apply current XTAL error correction */
+    pkt_ftime *= xtal_correct;
+
+    *result_ftime = (uint32_t)pkt_ftime;
+    if (*result_ftime > 1E9) {
+        printf("ERROR: fine timestamp is out of range (%u)\n", *result_ftime);
+        return -1;
+    }
+
+    DEBUG_PRINTF("==> ftime = %u ns since last PPS (%.15lf)\n", *result_ftime, pkt_ftime);
+
+    return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 505 - 0
sx1302/source/loragw_usb.c

@@ -0,0 +1,505 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2020 Semtech
+
+Description:
+    Host specific functions to address the LoRa concentrator registers through
+    a USB interface.
+    Single-byte read/write and burst read/write.
+
+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 <stdlib.h>     /* malloc free */
+#include <unistd.h>     /* lseek, close */
+#include <fcntl.h>      /* open */
+#include <string.h>     /* strncmp */
+#include <errno.h>      /* Error number definitions */
+#include <termios.h>    /* POSIX terminal control definitions */
+
+#include "loragw_com.h"
+#include "loragw_usb.h"
+#include "loragw_mcu.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_COM == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout, fmt, args)
+    #define CHECK_NULL(a)                if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_USB_ERROR;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return LGW_USB_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE TYPES -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES  --------------------------------------------------- */
+
+static lgw_com_write_mode_t _lgw_write_mode = LGW_COM_WRITE_MODE_SINGLE;
+static uint8_t _lgw_spi_req_nb = 0;
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
+
+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_USB_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] = 0;                        /* 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_USB_ERROR;
+    }
+
+    return LGW_USB_SUCCESS;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* configure serial interface to be 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_USB_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_USB_ERROR;
+    }
+
+    return LGW_USB_SUCCESS;
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int lgw_usb_open(const char * com_path, void **com_target_ptr) {
+    int *usb_device = NULL;
+    char portname[50];
+    int x;
+    int fd;
+    s_ping_info gw_info;
+    s_status mcu_status;
+    uint8_t data;
+    ssize_t n;
+
+    /*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_USB_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 {
+        printf("INFO: Configuring TTY\n");
+        x = set_interface_attribs_linux(fd, B115200);
+        if (x != 0) {
+            printf("ERROR: failed to configure COM port %s\n", portname);
+            free(usb_device);
+            return LGW_USB_ERROR;
+        }
+
+        /* flush tty port before setting it as blocking */
+        printf("INFO: Flushing TTY\n");
+        do {
+            n = read(fd, &data, 1);
+            if (n > 0) {
+                printf("NOTE: flushing serial port (0x%2X)\n", data);
+            }
+        } while (n > 0);
+
+        /* set tty port blocking */
+        printf("INFO: Setting TTY in blocking mode\n");
+        x = set_blocking_linux(fd, true);
+        if (x != 0) {
+            printf("ERROR: failed to configure COM port %s\n", portname);
+            free(usb_device);
+            return LGW_USB_ERROR;
+        }
+
+        *usb_device = fd;
+        *com_target_ptr = (void*)usb_device;
+
+        /* Initialize pseudo-random generator for MCU request ID */
+        srand(0);
+
+        /* Check MCU version (ignore first char of the received version (release/debug) */
+        printf("INFO: Connect to MCU\n");
+        if (mcu_ping(fd, &gw_info) != 0) {
+            printf("ERROR: failed to ping the concentrator MCU\n");
+            return LGW_USB_ERROR;
+        }
+        if (strncmp(gw_info.version + 1, mcu_version_string, sizeof mcu_version_string) != 0) {
+            printf("WARNING: MCU version mismatch (expected:%s, got:%s)\n", mcu_version_string, gw_info.version);
+        }
+        printf("INFO: Concentrator MCU version is %s\n", gw_info.version);
+
+        /* Get MCU status */
+        if (mcu_get_status(fd, &mcu_status) != 0) {
+            printf("ERROR: failed to get status from the concentrator MCU\n");
+            return LGW_USB_ERROR;
+        }
+        printf("INFO: MCU status: sys_time:%u temperature:%.1foC\n", mcu_status.system_time_ms, mcu_status.temperature);
+
+        /* Reset SX1302 */
+        x  = mcu_gpio_write(fd, 0, 1, 1); /*   set PA1 : POWER_EN */
+        x |= mcu_gpio_write(fd, 0, 2, 1); /*   set PA2 : SX1302_RESET active */
+        x |= mcu_gpio_write(fd, 0, 2, 0); /* unset PA2 : SX1302_RESET inactive */
+        /* Reset SX1261 (LBT / Spectral Scan) */
+        x |= mcu_gpio_write(fd, 0, 8, 0); /*   set PA8 : SX1261_NRESET active */
+        x |= mcu_gpio_write(fd, 0, 8, 1); /* unset PA8 : SX1261_NRESET inactive */
+        if (x != 0) {
+            printf("ERROR: failed to reset SX1302\n");
+            free(usb_device);
+            return LGW_USB_ERROR;
+        }
+
+        return LGW_USB_SUCCESS;
+    }
+
+    free(usb_device);
+    return LGW_USB_ERROR;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* SPI release */
+int lgw_usb_close(void *com_target) {
+    int usb_device;
+    int x, err = LGW_USB_SUCCESS;
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+
+    usb_device = *(int *)com_target;
+
+    /* Reset SX1302 before closing */
+    x  = mcu_gpio_write(usb_device, 0, 1, 1); /*   set PA1 : POWER_EN */
+    x |= mcu_gpio_write(usb_device, 0, 2, 1); /*   set PA2 : SX1302_RESET active */
+    x |= mcu_gpio_write(usb_device, 0, 2, 0); /* unset PA2 : SX1302_RESET inactive */
+    /* Reset SX1261 (LBT / Spectral Scan) */
+    x |= mcu_gpio_write(usb_device, 0, 8, 0); /*   set PA8 : SX1261_NRESET active */
+    x |= mcu_gpio_write(usb_device, 0, 8, 1); /* unset PA8 : SX1261_NRESET inactive */
+    if (x != 0) {
+        printf("ERROR: failed to reset SX1302\n");
+        err = LGW_USB_ERROR;
+    }
+
+    /* close file & deallocate file descriptor */
+    x = close(usb_device);
+    free(com_target);
+    if (x != 0) {
+        printf("ERROR: failed to close USB file\n");
+        err = LGW_USB_ERROR;
+    }
+
+    /* determine return code */
+    if (err != 0) {
+        printf("ERROR: USB PORT FAILED TO CLOSE\n");
+        return LGW_USB_ERROR;
+    } else {
+        DEBUG_MSG("Note: USB port closed\n");
+        return LGW_USB_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple write */
+int lgw_usb_w(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t data) {
+    return lgw_usb_wb(com_target, spi_mux_target, address, &data, 1);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Simple read */
+int lgw_usb_r(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data) {
+    return lgw_usb_rb(com_target, spi_mux_target, address, data, 1);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Single Byte Read-Modify-Write */
+int lgw_usb_rmw(void *com_target, uint16_t address, uint8_t offs, uint8_t leng, uint8_t data) {
+    int usb_device;
+    uint8_t command_size = 6;
+    uint8_t in_out_buf[command_size];
+    int a = 0;
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+
+    usb_device = *(int *)com_target;
+
+    DEBUG_PRINTF("==> RMW register @ 0x%04X, offs:%u leng:%u value:0x%02X\n", address, offs, leng, data);
+
+    /* prepare frame to be sent */
+    in_out_buf[0] = _lgw_spi_req_nb; /* Req ID */
+    in_out_buf[1] = MCU_SPI_REQ_TYPE_READ_MODIFY_WRITE; /* Req type */
+    in_out_buf[2] = (uint8_t)(address >> 8); /* Register address MSB */
+    in_out_buf[3] = (uint8_t)(address >> 0); /* Register address LSB */
+    in_out_buf[4] = ((1 << leng) - 1) << offs; /* Register bitmask */
+    in_out_buf[5] = data << offs;
+
+    if (_lgw_write_mode == LGW_COM_WRITE_MODE_BULK) {
+        a = mcu_spi_store(in_out_buf, command_size);
+        _lgw_spi_req_nb += 1;
+    } else {
+        a = mcu_spi_write(usb_device, in_out_buf, command_size);
+    }
+
+    /* determine return code */
+    if (a != 0) {
+        DEBUG_MSG("ERROR: USB WRITE FAILURE\n");
+        return -1;
+    } else {
+        DEBUG_MSG("Note: USB write success\n");
+        return 0;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) write */
+int lgw_usb_wb(void *com_target, uint8_t spi_mux_target, uint16_t address, const uint8_t *data, uint16_t size) {
+    int usb_device;
+    uint16_t command_size = size + 8; /* 5 bytes: REQ metadata (MCU), 3 bytes: SPI header (SX1302) */
+    uint8_t in_out_buf[command_size];
+    int i;
+    int a = 0;
+
+    /* check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    usb_device = *(int *)com_target;
+
+    /* prepare command */
+    /* Request metadata */
+    in_out_buf[0] = _lgw_spi_req_nb; /* Req ID */
+    in_out_buf[1] = MCU_SPI_REQ_TYPE_READ_WRITE; /* Req type */
+    in_out_buf[2] = MCU_SPI_TARGET_SX1302; /* MCU -> SX1302 */
+    in_out_buf[3] = (uint8_t)((size + 3) >> 8); /* payload size + spi_mux_target + address */
+    in_out_buf[4] = (uint8_t)((size + 3) >> 0); /* payload size + spi_mux_target + address */
+    /* RAW SPI frame */
+    in_out_buf[5] = spi_mux_target; /* SX1302 -> RADIO_A or RADIO_B */
+    in_out_buf[6] = 0x80 | ((address >> 8) & 0x7F);
+    in_out_buf[7] =        ((address >> 0) & 0xFF);
+    for (i = 0; i < size; i++) {
+        in_out_buf[i + 8] = data[i];
+    }
+
+    if (_lgw_write_mode == LGW_COM_WRITE_MODE_BULK) {
+        a = mcu_spi_store(in_out_buf, command_size);
+        _lgw_spi_req_nb += 1;
+    } else {
+        a = mcu_spi_write(usb_device, in_out_buf, command_size);
+    }
+
+    /* determine return code */
+    if (a != 0) {
+        DEBUG_MSG("ERROR: USB WRITE BURST FAILURE\n");
+        return -1;
+    } else {
+        DEBUG_MSG("Note: USB write burst success\n");
+        return 0;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* Burst (multiple-byte) read */
+int lgw_usb_rb(void *com_target, uint8_t spi_mux_target, uint16_t address, uint8_t *data, uint16_t size) {
+    int usb_device;
+    uint16_t command_size = size + 9;  /* 5 bytes: REQ metadata (MCU), 3 bytes: SPI header (SX1302), 1 byte: dummy*/
+    uint8_t in_out_buf[command_size];
+    int i;
+    int a = 0;
+
+    /* check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    usb_device = *(int *)com_target;
+
+    /* prepare command */
+    /* Request metadata */
+    in_out_buf[0] = 0; /* Req ID */
+    in_out_buf[1] = MCU_SPI_REQ_TYPE_READ_WRITE; /* Req type */
+    in_out_buf[2] = MCU_SPI_TARGET_SX1302; /* MCU -> SX1302 */
+    in_out_buf[3] = (uint8_t)((size + 4) >> 8); /* payload size + spi_mux_target + address + dummy byte */
+    in_out_buf[4] = (uint8_t)((size + 4) >> 0); /* payload size + spi_mux_target + address + dummy byte */
+    /* RAW SPI frame */
+    in_out_buf[5] = spi_mux_target; /* SX1302 -> RADIO_A or RADIO_B */
+    in_out_buf[6] = 0x00 | ((address >> 8) & 0x7F);
+    in_out_buf[7] =        ((address >> 0) & 0xFF);
+    in_out_buf[8] = 0x00; /* dummy byte */
+    for (i = 0; i < size; i++) {
+        in_out_buf[i + 9] = data[i];
+    }
+
+    if (_lgw_write_mode == LGW_COM_WRITE_MODE_BULK) {
+        /* makes no sense to read in bulk mode, as we can't get the result */
+        printf("ERROR: USB READ BURST FAILURE - bulk mode is enabled\n");
+        return -1;
+    } else {
+        a = mcu_spi_write(usb_device, in_out_buf, command_size);
+    }
+
+    /* determine return code */
+    if (a != 0) {
+        DEBUG_MSG("ERROR: USB READ BURST FAILURE\n");
+        return -1;
+    } else {
+        DEBUG_MSG("Note: USB read burst success\n");
+        memcpy(data, in_out_buf + 9, size); /* remove the first bytes, keep only the payload */
+        return 0;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_usb_set_write_mode(lgw_com_write_mode_t write_mode) {
+    if (write_mode >= LGW_COM_WRITE_MODE_UNKNOWN) {
+        printf("ERROR: wrong write mode\n");
+        return -1;
+    }
+
+    DEBUG_PRINTF("INFO: setting USB write mode to %s\n", (write_mode == LGW_COM_WRITE_MODE_SINGLE) ? "SINGLE" : "BULK");
+
+    _lgw_write_mode = write_mode;
+
+    return 0;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_usb_flush(void *com_target) {
+    int usb_device;
+    int a = 0;
+
+    /* Check input parameters */
+    CHECK_NULL(com_target);
+    if (_lgw_write_mode != LGW_COM_WRITE_MODE_BULK) {
+        printf("ERROR: %s: cannot flush in single write mode\n", __FUNCTION__);
+        return -1;
+    }
+
+    /* Restore single mode after flushing */
+    _lgw_write_mode = LGW_COM_WRITE_MODE_SINGLE;
+
+    if (_lgw_spi_req_nb == 0) {
+        printf("INFO: no SPI request to flush\n");
+        return 0;
+    }
+
+    usb_device = *(int *)com_target;
+
+    DEBUG_MSG("INFO: flushing USB write buffer\n");
+    a = mcu_spi_flush(usb_device);
+    if (a != 0) {
+        printf("ERROR: Failed to flush USB write buffer\n");
+    }
+
+    /* reset the pending request number */
+    _lgw_spi_req_nb = 0;
+
+    return a;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+uint16_t lgw_usb_chunk_size(void) {
+    return (uint16_t)LGW_USB_BURST_CHUNK;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int lgw_usb_get_temperature(void *com_target, float * temperature) {
+    int usb_device;
+    s_status mcu_status;
+
+    /* check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(temperature);
+
+    usb_device = *(int *)com_target;
+
+    if (mcu_get_status(usb_device, &mcu_status) != 0) {
+        printf("ERROR: failed to get status from the concentrator MCU\n");
+        return -1;
+    }
+    DEBUG_PRINTF("INFO: temperature:%.1foC\n", mcu_status.temperature);
+
+    *temperature = mcu_status.temperature;
+
+    return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 94 - 0
sx1302/source/sx1250_com.c

@@ -0,0 +1,94 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1250 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdio.h>      /* printf fprintf */
+
+#include "sx1250_com.h"
+#include "sx1250_spi.h"
+#include "sx1250_usb.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_RAD == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%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 -1;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return -1;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int sx1250_com_w(lgw_com_type_t com_type, void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size) {
+    int com_stat;
+
+    /* Check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    switch (com_type) {
+        case LGW_COM_SPI:
+            com_stat = sx1250_spi_w(com_target, spi_mux_target, op_code, data, size);
+            break;
+        case LGW_COM_USB:
+            com_stat = sx1250_usb_w(com_target, spi_mux_target, op_code, data, size);
+            break;
+        default:
+            printf("ERROR: wrong communication type (SHOULD NOT HAPPEN)\n");
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1250_com_r(lgw_com_type_t com_type, void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size) {
+    int com_stat;
+
+    /* Check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    switch (com_type) {
+        case LGW_COM_SPI:
+            com_stat = sx1250_spi_r(com_target, spi_mux_target, op_code, data, size);
+            break;
+        case LGW_COM_USB:
+            com_stat = sx1250_usb_r(com_target, spi_mux_target, op_code, data, size);
+            break;
+        default:
+            printf("ERROR: wrong communication type (SHOULD NOT HAPPEN)\n");
+            com_stat = LGW_COM_ERROR;
+            break;
+    }
+
+    return com_stat;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 146 - 0
sx1302/source/sx1250_spi.c

@@ -0,0 +1,146 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1250 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdio.h>      /* printf fprintf */
+#include <unistd.h>     /* lseek, close */
+#include <fcntl.h>      /* open */
+#include <string.h>     /* memset */
+
+#include <sys/ioctl.h>
+#include <linux/spi/spidev.h>
+
+#include "loragw_spi.h"
+#include "loragw_aux.h"
+#include "sx1250_spi.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_RAD == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+    #define CHECK_NULL(a)                if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return LGW_SPI_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define WAIT_BUSY_SX1250_MS  1
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int sx1250_spi_w(void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size) {
+    int com_device;
+    int cmd_size = 2; /* header + op_code */
+    uint8_t out_buf[cmd_size + size];
+    uint8_t command_size;
+    struct spi_ioc_transfer k;
+    int a, i;
+
+    /* wait BUSY */
+    wait_ms(WAIT_BUSY_SX1250_MS);
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    com_device = *(int *)com_target;
+
+    /* prepare frame to be sent */
+    out_buf[0] = spi_mux_target;
+    out_buf[1] = (uint8_t)op_code;
+    for(i = 0; i < (int)size; i++) {
+        out_buf[cmd_size + i] = data[i];
+    }
+    command_size = cmd_size + size;
+
+    /* I/O transaction */
+    memset(&k, 0, sizeof(k)); /* clear k */
+    k.tx_buf = (unsigned long) out_buf;
+    k.len = command_size;
+    k.speed_hz = SPI_SPEED;
+    k.cs_change = 0;
+    k.bits_per_word = 8;
+    a = ioctl(com_device, SPI_IOC_MESSAGE(1), &k);
+
+    /* determine return code */
+    if (a != (int)k.len) {
+        DEBUG_MSG("ERROR: SPI WRITE FAILURE\n");
+        return LGW_SPI_ERROR;
+    } else {
+        DEBUG_MSG("Note: SPI write success\n");
+        return LGW_SPI_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1250_spi_r(void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size) {
+    int com_device;
+    int cmd_size = 2; /* header + op_code + NOP */
+    uint8_t out_buf[cmd_size + size];
+    uint8_t command_size;
+    uint8_t in_buf[ARRAY_SIZE(out_buf)];
+    struct spi_ioc_transfer k;
+    int a, i;
+
+    /* wait BUSY */
+    wait_ms(WAIT_BUSY_SX1250_MS);
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    com_device = *(int *)com_target;
+
+    /* prepare frame to be sent */
+    out_buf[0] = spi_mux_target;
+    out_buf[1] = (uint8_t)op_code;
+    for(i = 0; i < (int)size; i++) {
+        out_buf[cmd_size + i] = data[i];
+    }
+    command_size = cmd_size + size;
+
+    /* I/O transaction */
+    memset(&k, 0, sizeof(k)); /* clear k */
+    k.tx_buf = (unsigned long) out_buf;
+    k.rx_buf = (unsigned long) in_buf;
+    k.len = command_size;
+    k.cs_change = 0;
+    a = ioctl(com_device, SPI_IOC_MESSAGE(1), &k);
+
+    /* determine return code */
+    if (a != (int)k.len) {
+        DEBUG_MSG("ERROR: SPI READ FAILURE\n");
+        return LGW_SPI_ERROR;
+    } else {
+        DEBUG_MSG("Note: SPI read success\n");
+        //*data = in_buf[command_size - 1];
+        memcpy(data, in_buf + cmd_size, size);
+        return LGW_SPI_SUCCESS;
+    }
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 134 - 0
sx1302/source/sx1250_usb.c

@@ -0,0 +1,134 @@
+a/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1250 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdio.h>      /* printf fprintf */
+#include <string.h>     /* memcmp */
+
+#include "loragw_aux.h"
+#include "loragw_mcu.h"
+#include "sx1250_usb.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_RAD == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%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 -1;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return -1;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define WAIT_BUSY_SX1250_MS  1
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int sx1250_usb_w(void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size) {
+    int usb_device;
+    uint8_t command_size = size + 7; /* 5 bytes: REQ metadata, 2 bytes: RAW SPI frame */
+    uint8_t in_out_buf[command_size];
+    int a;
+    int i;
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    usb_device = *(int *)com_target;
+
+    /* wait BUSY */
+    wait_ms(WAIT_BUSY_SX1250_MS);
+
+    /* prepare command */
+    /* Request metadata */
+    in_out_buf[0] = 0; /* Req ID */
+    in_out_buf[1] = MCU_SPI_REQ_TYPE_READ_WRITE; /* Req type */
+    in_out_buf[2] = MCU_SPI_TARGET_SX1302; /* MCU -> SX1302 */
+    in_out_buf[3] = (uint8_t)((size + 2) >> 8); /* payload size + spi_mux_target + op_code */
+    in_out_buf[4] = (uint8_t)((size + 2) >> 0); /* payload size + spi_mux_target + op_code */
+    /* RAW SPI frame */
+    in_out_buf[5] = spi_mux_target; /* SX1302 -> RADIO_A or RADIO_B */
+    in_out_buf[6] = (uint8_t)op_code;
+    for (i = 0; i < size; i++) {
+        in_out_buf[i + 7] = data[i];
+    }
+    a = mcu_spi_write(usb_device, in_out_buf, command_size);
+
+    /* determine return code */
+    if (a != 0) {
+        DEBUG_MSG("ERROR: USB SX1250 WRITE FAILURE\n");
+        return -1;
+    } else {
+        DEBUG_MSG("Note: USB SX1250 write success\n");
+        return 0;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx1250_usb_r(void *com_target, uint8_t spi_mux_target, sx1250_op_code_t op_code, uint8_t *data, uint16_t size) {
+    int usb_device;
+    uint8_t command_size = size + 7; /* 5 bytes: REQ metadata, 2 bytes: RAW SPI frame */
+    uint8_t in_out_buf[command_size];
+    int a;
+    int i;
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    usb_device = *(int *)com_target;
+
+    /* wait BUSY */
+    wait_ms(WAIT_BUSY_SX1250_MS);
+
+    /* prepare command */
+    /* Request metadata */
+    in_out_buf[0] = 0; /* Req ID */
+    in_out_buf[1] = MCU_SPI_REQ_TYPE_READ_WRITE; /* Req type */
+    in_out_buf[2] = MCU_SPI_TARGET_SX1302; /* MCU -> SX1302 */
+    in_out_buf[3] = (uint8_t)((size + 2) >> 8); /* payload size + spi_mux_target + op_code */
+    in_out_buf[4] = (uint8_t)((size + 2) >> 0); /* payload size + spi_mux_target + op_code */
+    /* RAW SPI frame */
+    in_out_buf[5] = spi_mux_target; /* SX1302 -> RADIO_A or RADIO_B */
+    in_out_buf[6] = (uint8_t)op_code;
+    for (i = 0; i < size; i++) {
+        in_out_buf[i + 7] = data[i];
+    }
+    a = mcu_spi_write(usb_device, in_out_buf, command_size);
+
+    /* determine return code */
+    if (a != 0) {
+        DEBUG_MSG("ERROR: USB SX1250 READ FAILURE\n");
+        return -1;
+    } else {
+        DEBUG_MSG("Note: USB SX1250 read success\n");
+        memcpy(data, in_out_buf + 7, size); /* remove the first bytes, keep only the payload */
+        return 0;
+    }
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 98 - 0
sx1302/source/sx125x_com.c

@@ -0,0 +1,98 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1255/SX1257 radios.
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+*/
+
+/* -------------------------------------------------------------------------- */
+/* --- DEPENDANCIES --------------------------------------------------------- */
+
+#include <stdint.h>     /* C99 types */
+#include <stdio.h>      /* printf fprintf */
+
+#include "sx125x_com.h"
+#include "sx125x_spi.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_RAD == 1
+    #define DEBUG_MSG(str)                fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)    fprintf(stdout,"%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 -1;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)                if(a==NULL){return -1;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE TYPES -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+int sx125x_com_r(lgw_com_type_t com_type, void *com_target, uint8_t spi_mux_target, uint8_t address, uint8_t *data) {
+    int com_stat;
+
+    /* Check input parameters */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    switch (com_type) {
+        case LGW_COM_SPI:
+            com_stat = sx125x_spi_r(com_target, spi_mux_target, address, data);
+            break;
+        case LGW_COM_USB:
+            printf("ERROR: USB COM type is not supported for sx125x\n");
+            return -1;
+        default:
+            printf("ERROR: wrong communication type (SHOULD NOT HAPPEN)\n");
+            return -1;
+    }
+
+    return com_stat;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx125x_com_w(lgw_com_type_t com_type, void *com_target, uint8_t spi_mux_target, uint8_t address, uint8_t data) {
+    int com_stat;
+
+    /* Check input parameters */
+    CHECK_NULL(com_target);
+
+    switch (com_type) {
+        case LGW_COM_SPI:
+            com_stat = sx125x_spi_w(com_target, spi_mux_target, address, data);
+            break;
+        case LGW_COM_USB:
+            printf("ERROR: USB COM type is not supported for sx125x\n");
+            return -1;
+        default:
+            printf("ERROR: wrong communication type (SHOULD NOT HAPPEN)\n");
+            return -1;
+    }
+
+    return com_stat;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 140 - 0
sx1302/source/sx125x_spi.c

@@ -0,0 +1,140 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Functions used to handle LoRa concentrator SX1255/SX1257 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 <string.h>     /* memset */
+
+#include <sys/ioctl.h>
+#include <linux/spi/spidev.h>
+
+#include "sx125x_spi.h"
+#include "loragw_spi.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#if DEBUG_RAD == 1
+    #define DEBUG_MSG(str)              fprintf(stdout, str)
+    #define DEBUG_PRINTF(fmt, args...)  fprintf(stdout,"%s:%d: "fmt, __FUNCTION__, __LINE__, args)
+    #define CHECK_NULL(a)               if(a==NULL){fprintf(stderr,"%s:%d: ERROR: NULL POINTER AS ARGUMENT\n", __FUNCTION__, __LINE__);return LGW_SPI_ERROR;}
+#else
+    #define DEBUG_MSG(str)
+    #define DEBUG_PRINTF(fmt, args...)
+    #define CHECK_NULL(a)               if(a==NULL){return LGW_SPI_ERROR;}
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE TYPES -------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define READ_ACCESS     0x00
+#define WRITE_ACCESS    0x80
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE VARIABLES ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
+
+/* Simple read */
+int sx125x_spi_r(void *com_target, uint8_t spi_mux_target, uint8_t address, uint8_t *data) {
+    int com_device;
+    uint8_t out_buf[3];
+    uint8_t command_size;
+    uint8_t in_buf[ARRAY_SIZE(out_buf)];
+    struct spi_ioc_transfer k;
+    int a;
+
+    /* check input variables */
+    CHECK_NULL(com_target);
+    CHECK_NULL(data);
+
+    com_device = *(int *)com_target;
+
+    /* prepare frame to be sent */
+    out_buf[0] = spi_mux_target;
+    out_buf[1] = READ_ACCESS | (address & 0x7F);
+    out_buf[2] = 0x00;
+    command_size = 3;
+
+    /* I/O transaction */
+    memset(&k, 0, sizeof(k)); /* clear k */
+    k.tx_buf = (unsigned long) out_buf;
+    k.rx_buf = (unsigned long) in_buf;
+    k.len = command_size;
+    k.cs_change = 0;
+    a = ioctl(com_device, SPI_IOC_MESSAGE(1), &k);
+
+    /* determine return code */
+    if (a != (int)k.len) {
+        DEBUG_MSG("ERROR: SPI READ FAILURE\n");
+        return LGW_SPI_ERROR;
+    } else {
+        //DEBUG_MSG("Note: SPI read success\n");
+        *data = in_buf[command_size - 1];
+        return LGW_SPI_SUCCESS;
+    }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+int sx125x_spi_w(void *spi_target, uint8_t spi_mux_target, uint8_t address, uint8_t data) {
+    int spi_device;
+    uint8_t out_buf[3];
+    uint8_t command_size;
+    struct spi_ioc_transfer k;
+    int a;
+
+    /* check input variables */
+    CHECK_NULL(spi_target);
+
+    spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */
+
+    /* prepare frame to be sent */
+    out_buf[0] = spi_mux_target;
+    out_buf[1] = WRITE_ACCESS | (address & 0x7F);
+    out_buf[2] = data;
+    command_size = 3;
+
+    /* I/O transaction */
+    memset(&k, 0, sizeof(k)); /* clear k */
+    k.tx_buf = (unsigned long) out_buf;
+    k.len = command_size;
+    k.speed_hz = SPI_SPEED;
+    k.cs_change = 0;
+    k.bits_per_word = 8;
+    a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k);
+
+    /* determine return code */
+    if (a != (int)k.len) {
+        DEBUG_MSG("ERROR: SPI WRITE FAILURE\n");
+        return LGW_SPI_ERROR;
+    } else {
+        //DEBUG_MSG("Note: SPI write success\n");
+        return LGW_SPI_SUCCESS;
+    }
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 390 - 0
sx1302/source/sx1261_pram.var

@@ -0,0 +1,390 @@
+const uint32_t pram[] = {
+0x337fe1,
+0x337fdb,
+0x337fd5,
+0x337fcf,
+0x3a7fc8,
+0x3f3fff,
+0x378ff,
+0x379ff,
+0x3a7fb7,
+0x16a901,
+0x16a801,
+0x23ffff,
+0x378ff,
+0x379ff,
+0x3a7faf,
+0x16a901,
+0x16a801,
+0x23ffff,
+0x378ff,
+0x379ff,
+0x3a7f34,
+0x16a901,
+0x16a801,
+0x23ffff,
+0x378ff,
+0x379ff,
+0x3a7e80,
+0x16a901,
+0x16a801,
+0x23ffff,
+0x378ff,
+0x379ff,
+0x3a7fc3,
+0x16a901,
+0x16a801,
+0x337fc9,
+0x378ff,
+0x379ff,
+0x3a7fc0,
+0x16a901,
+0x16a801,
+0x337fc9,
+0x378ff,
+0x379ff,
+0x3a7fbd,
+0x16a901,
+0x16a801,
+0x337fc9,
+0x378ff,
+0x379ff,
+0x3a7fba,
+0x16a901,
+0x16a801,
+0x337fc9,
+0x23ffff,
+0xea1fc,
+0xea0df,
+0xeafc9,
+0x2cf0e,
+0x23ffff,
+0xeacff,
+0xeabff,
+0x23ffff,
+0xeacff,
+0xeabff,
+0x23ffff,
+0xeacff,
+0xeabff,
+0x23ffff,
+0xeacff,
+0xeabff,
+0x23ffff,
+0x378ff,
+0x379ff,
+0x3a7fc8,
+0xeacfd,
+0xeabff,
+0x16a901,
+0x16a801,
+0x23ffff,
+0x374ff,
+0x375ff,
+0x378ff,
+0x379ff,
+0x16affe,
+0xea5ff,
+0xea465,
+0x1dbb04,
+0xe1bfd,
+0x307fa3,
+0x1caf00,
+0x327fa0,
+0xeacf7,
+0xeabff,
+0x337f3a,
+0x1cad04,
+0xeacfe,
+0xeabff,
+0xdbfdd,
+0x307f97,
+0xdafcc,
+0xdefbb,
+0xdbfdd,
+0x347f9b,
+0xeecef,
+0xcaffc,
+0x4ade8,
+0xcbdcd,
+0x1bde8,
+0x4abe8,
+0xebbbf,
+0x1bbe8,
+0x4abe8,
+0xebbdf,
+0x1bbe8,
+0x1ca800,
+0xea9ff,
+0x4abe3,
+0xe2b01,
+0x1bbe3,
+0x4abee,
+0xe2b01,
+0x1bbee,
+0x1ca202,
+0x1ca301,
+0x2f300,
+0x2f201,
+0xea064,
+0xea1f7,
+0x18ab00,
+0x367f58,
+0xea041,
+0xea1f7,
+0x18ab00,
+0x1c1b03,
+0x317f3f,
+0x1ea201,
+0x1ea300,
+0xcb23f,
+0x327f4a,
+0x1cab04,
+0xeaefe,
+0xdbfbb,
+0x307f6c,
+0xdafee,
+0xdbfbb,
+0x347f6f,
+0x4abee,
+0xcbbeb,
+0x1bbee,
+0xeacff,
+0xeabff,
+0xc1b9f,
+0x327f64,
+0xc1c8f,
+0x317f5c,
+0x3fffff,
+0xd1fcc,
+0xd5fbb,
+0xc1b9f,
+0x327f5d,
+0xc1c8f,
+0x357f63,
+0xea064,
+0xea1f7,
+0x18ab00,
+0x327f7c,
+0x1cad04,
+0xeacfe,
+0xdbfdd,
+0x307f51,
+0xdafcc,
+0xdbfdd,
+0x347f54,
+0xd8fcb,
+0x4acee,
+0xc2bcb,
+0x1bbee,
+0xeacfd,
+0xeabff,
+0x337f3a,
+0x1cad04,
+0xeacfe,
+0xdbfdd,
+0x307f43,
+0xdafcc,
+0xdbfdd,
+0x347f46,
+0xd8fcb,
+0x4acee,
+0xc2bcb,
+0x337f6a,
+0xcb23f,
+0x367f75,
+0xdbf22,
+0xdff33,
+0x337f75,
+0x16af02,
+0x16a901,
+0x16a801,
+0x16a501,
+0x16a401,
+0x23ffff,
+0x374ff,
+0x375ff,
+0x378ff,
+0x379ff,
+0x16afe0,
+0xea5ff,
+0xea465,
+0x1ca802,
+0xea9ff,
+0xeafff,
+0x2ff00,
+0xeaff7,
+0x2ff01,
+0xeafef,
+0x2ff02,
+0xeafe7,
+0x2ff03,
+0xeafdf,
+0x2ff04,
+0xeafd7,
+0x2ff05,
+0xeafcf,
+0x2ff06,
+0xeafc7,
+0x2ff07,
+0xeafbf,
+0x2ff08,
+0xeafb7,
+0x2ff09,
+0xeafaf,
+0x2ff0a,
+0xeafa7,
+0x2ff0b,
+0xeaf9f,
+0x2ff0c,
+0xeaf97,
+0x2ff0d,
+0xeaf8f,
+0x2ff0e,
+0xeaf87,
+0x2ff0f,
+0xeaf7f,
+0x2ff10,
+0xeaf77,
+0x2ff11,
+0xeaf6f,
+0x2ff12,
+0xeaf67,
+0x2ff13,
+0xeaf5f,
+0x2ff14,
+0xeaf57,
+0x2ff15,
+0xeaf4f,
+0x2ff16,
+0xeaf47,
+0x2ff17,
+0xeaf3f,
+0x2ff18,
+0xeaf37,
+0x2ff19,
+0xeaf2f,
+0x2ff1a,
+0xeaf27,
+0x2ff1b,
+0xeaf1f,
+0x2ff1c,
+0xeaf17,
+0x2ff1d,
+0xeaf0f,
+0x2ff1e,
+0xeaf07,
+0x2ff1f,
+0x4abee,
+0xe2b01,
+0x1bbee,
+0xeacff,
+0xeabff,
+0xcafc0,
+0xec0ff,
+0xcafb1,
+0xed1fb,
+0xeafff,
+0x2cf00,
+0xd1fcc,
+0xd5fbb,
+0xe1bff,
+0x327edb,
+0xe1c00,
+0x347ee6,
+0xea2ff,
+0xea3ff,
+0xea032,
+0xea1f8,
+0xeaff0,
+0x2cf00,
+0xea064,
+0xea1f7,
+0x18ad00,
+0x1c1300,
+0x327ece,
+0x1c1201,
+0x317e9b,
+0xe1dff,
+0x367e9b,
+0xea041,
+0xea1f7,
+0x18ab00,
+0xeebdf,
+0xcafbc,
+0xeabff,
+0xccccc,
+0xcdbbb,
+0xcafc0,
+0xec0ff,
+0xcafb1,
+0xed1fb,
+0x18ab01,
+0xeacff,
+0x18ae02,
+0xeadff,
+0xccecc,
+0xcddbb,
+0xd1fcc,
+0xd5fbb,
+0xcafbe,
+0xeadff,
+0x2ce01,
+0x2cc02,
+0xd1f22,
+0xd5f33,
+0xea064,
+0xea1f7,
+0x18ad00,
+0xeacff,
+0xeabff,
+0xc1b9f,
+0x327ea9,
+0xc1c8f,
+0x317ea1,
+0x3fffff,
+0xd1fcc,
+0xd5fbb,
+0xc1b9f,
+0x327ea2,
+0xc1c8f,
+0x357ea8,
+0x1c1300,
+0x327e9e,
+0x1c1201,
+0x317e9b,
+0xe1dff,
+0x327ecb,
+0xe1dff,
+0x367e90,
+0xea032,
+0xea1f8,
+0xeaf00,
+0x2cf00,
+0xea1fb,
+0xea0ff,
+0xeaf00,
+0x2cf00,
+0x337e88,
+0xea032,
+0xea1f8,
+0xeaf0f,
+0x2cf00,
+0xea1fb,
+0xea0ff,
+0xeaf0f,
+0x2cf00,
+0xeacfd,
+0xeabff,
+0x16af20,
+0x16a901,
+0x16a801,
+0x16a501,
+0x16a401,
+0x23ffff,
+0xeacf7,
+0xeabff,
+0x23ffff
+};
+
+#define PRAM_COUNT 386

+ 438 - 0
sx1302/source/test_loragw_hal_rx.c

@@ -0,0 +1,438 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Minimum test program for HAL RX capability
+
+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>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <math.h>
+#include <getopt.h>
+
+#include "loragw_hal.h"
+#include "loragw_reg.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define COM_TYPE_DEFAULT LGW_COM_SPI
+#define COM_PATH_DEFAULT "/dev/spidev0.0"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define RAND_RANGE(min, max) (rand() % (max + 1 - min) + min)
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define DEFAULT_FREQ_HZ     868500000U
+
+/* -------------------------------------------------------------------------- */
+/* --- 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 ---------------------------------------------------- */
+
+static void sig_handler(int sigio) {
+    if (sigio == SIGQUIT) {
+        quit_sig = 1;
+    } else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
+        exit_sig = 1;
+    }
+}
+
+void usage(void) {
+    printf("Library version information: %s\n", lgw_version_info());
+    printf("Available options:\n");
+    printf(" -h print this help\n");
+    printf(" -u            set COM type as USB (default is SPI)\n");
+    printf(" -d <path>     COM path to be used to connect the concentrator\n");
+    printf("               => default path: " COM_PATH_DEFAULT "\n");
+    printf(" -k <uint>     Concentrator clock source (Radio A or Radio B) [0..1]\n");
+    printf(" -r <uint>     Radio type (1255, 1257, 1250)\n");
+    printf(" -a <float>    Radio A RX frequency in MHz\n");
+    printf(" -b <float>    Radio B RX frequency in MHz\n");
+    printf(" -o <float>    RSSI Offset to be applied in dB\n");
+    printf(" -n <uint>     Number of packet received with CRC OK for each HAL start/stop loop\n");
+    printf(" -z <uint>     Size of the RX packet array to be passed to lgw_receive()\n");
+    printf(" -m <uint>     Channel frequency plan mode [0:LoRaWAN-like, 1:Same frequency for all channels (-400000Hz on RF0)]\n");
+    printf(" -j            Set radio in single input mode (SX1250 only)\n");
+    printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
+    printf(" --fdd         Enable Full-Duplex mode (CN490 reference design)\n");
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+    /* SPI interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char * com_path = com_path_default;
+    lgw_com_type_t com_type = COM_TYPE_DEFAULT;
+
+    struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
+
+    int i, j, x;
+    uint32_t fa = DEFAULT_FREQ_HZ;
+    uint32_t fb = DEFAULT_FREQ_HZ;
+    double arg_d = 0.0;
+    unsigned int arg_u;
+    uint8_t clocksource = 0;
+    lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE;
+    uint8_t max_rx_pkt = 16;
+    bool single_input_mode = false;
+    float rssi_offset = 0.0;
+    bool full_duplex = false;
+
+    struct lgw_conf_board_s boardconf;
+    struct lgw_conf_rxrf_s rfconf;
+    struct lgw_conf_rxif_s ifconf;
+
+    unsigned long nb_pkt_crc_ok = 0, nb_loop = 0, cnt_loop;
+    int nb_pkt;
+
+    uint8_t channel_mode = 0; /* LoRaWAN-like */
+
+    const int32_t channel_if_mode0[9] = {
+        -400000,
+        -200000,
+        0,
+        -400000,
+        -200000,
+        0,
+        200000,
+        400000,
+        -200000 /* lora service */
+    };
+
+    const int32_t channel_if_mode1[9] = {
+        -400000,
+        -400000,
+        -400000,
+        -400000,
+        -400000,
+        -400000,
+        -400000,
+        -400000,
+        -400000 /* lora service */
+    };
+
+    const uint8_t channel_rfchain_mode0[9] = { 1, 1, 1, 0, 0, 0, 0, 0, 1 };
+
+    const uint8_t channel_rfchain_mode1[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+    /* Parameter parsing */
+    int option_index = 0;
+    static struct option long_options[] = {
+        {"fdd",  no_argument, 0, 0},
+        {0, 0, 0, 0}
+    };
+
+    /* parse command line options */
+    while ((i = getopt_long(argc, argv, "hja:b:k:r:n:z:m:o:d:u", long_options, &option_index)) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return -1;
+                break;
+            case 'd': /* <char> COM path */
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                break;
+            case 'u': /* Configure USB connection type */
+                com_type = LGW_COM_USB;
+                break;
+            case 'r': /* <uint> Radio type */
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) {
+                    printf("ERROR: argument parsing of -r argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    switch (arg_u) {
+                        case 1255:
+                            radio_type = LGW_RADIO_TYPE_SX1255;
+                            break;
+                        case 1257:
+                            radio_type = LGW_RADIO_TYPE_SX1257;
+                            break;
+                        default: /* 1250 */
+                            radio_type = LGW_RADIO_TYPE_SX1250;
+                            break;
+                    }
+                }
+                break;
+            case 'k': /* <uint> Clock Source */
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || (arg_u > 1)) {
+                    printf("ERROR: argument parsing of -k argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    clocksource = (uint8_t)arg_u;
+                }
+                break;
+            case 'j': /* Set radio in single input mode */
+                single_input_mode = true;
+                break;
+            case 'a': /* <float> Radio A RX frequency in MHz */
+                i = sscanf(optarg, "%lf", &arg_d);
+                if (i != 1) {
+                    printf("ERROR: argument parsing of -f argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    fa = (uint32_t)((arg_d*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+                }
+                break;
+            case 'b': /* <float> Radio B RX frequency in MHz */
+                i = sscanf(optarg, "%lf", &arg_d);
+                if (i != 1) {
+                    printf("ERROR: argument parsing of -f argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    fb = (uint32_t)((arg_d*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+                }
+                break;
+            case 'n': /* <uint> NUmber of packets to be received before exiting */
+                i = sscanf(optarg, "%u", &arg_u);
+                if (i != 1) {
+                    printf("ERROR: argument parsing of -n argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    nb_loop = arg_u;
+                }
+                break;
+            case 'z': /* <uint> Size of the RX packet array to be passed to lgw_receive() */
+                i = sscanf(optarg, "%u", &arg_u);
+                if (i != 1) {
+                    printf("ERROR: argument parsing of -z argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    max_rx_pkt = arg_u;
+                }
+                break;
+            case 'm':
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || (arg_u > 1)) {
+                    printf("ERROR: argument parsing of -m argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    channel_mode = arg_u;
+                }
+                break;
+            case 'o': /* <float> RSSI offset in dB */
+                i = sscanf(optarg, "%lf", &arg_d);
+                if (i != 1) {
+                    printf("ERROR: argument parsing of -o argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    rssi_offset = (float)arg_d;
+                }
+                break;
+            case 0:
+                if (strcmp(long_options[option_index].name, "fdd") == 0) {
+                    full_duplex = true;
+                } else {
+                    printf("ERROR: argument parsing options. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                }
+                break;
+            default:
+                printf("ERROR: argument parsing\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);
+
+    printf("===== sx1302 HAL RX test =====\n");
+
+    /* Configure the gateway */
+    memset( &boardconf, 0, sizeof boardconf);
+    boardconf.lorawan_public = true;
+    boardconf.clksrc = clocksource;
+    boardconf.full_duplex = full_duplex;
+    boardconf.com_type = com_type;
+    strncpy(boardconf.com_path, com_path, sizeof boardconf.com_path);
+    boardconf.com_path[sizeof boardconf.com_path - 1] = '\0'; /* ensure string termination */
+    if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) {
+        printf("ERROR: failed to configure board\n");
+        return EXIT_FAILURE;
+    }
+
+    /* set configuration for RF chains */
+    memset( &rfconf, 0, sizeof rfconf);
+    rfconf.enable = true;
+    rfconf.freq_hz = fa;
+    rfconf.type = radio_type;
+    rfconf.rssi_offset = rssi_offset;
+    rfconf.tx_enable = false;
+    rfconf.single_input_mode = single_input_mode;
+    if (lgw_rxrf_setconf(0, &rfconf) != LGW_HAL_SUCCESS) {
+        printf("ERROR: failed to configure rxrf 0\n");
+        return EXIT_FAILURE;
+    }
+
+    memset( &rfconf, 0, sizeof rfconf);
+    rfconf.enable = true;
+    rfconf.freq_hz = fb;
+    rfconf.type = radio_type;
+    rfconf.rssi_offset = rssi_offset;
+    rfconf.tx_enable = false;
+    rfconf.single_input_mode = single_input_mode;
+    if (lgw_rxrf_setconf(1, &rfconf) != LGW_HAL_SUCCESS) {
+        printf("ERROR: failed to configure rxrf 1\n");
+        return EXIT_FAILURE;
+    }
+
+    /* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */
+    memset(&ifconf, 0, sizeof(ifconf));
+    for (i = 0; i < 8; i++) {
+        ifconf.enable = true;
+        if (channel_mode == 0) {
+            ifconf.rf_chain = channel_rfchain_mode0[i];
+            ifconf.freq_hz = channel_if_mode0[i];
+        } else if (channel_mode == 1) {
+            ifconf.rf_chain = channel_rfchain_mode1[i];
+            ifconf.freq_hz = channel_if_mode1[i];
+        } else {
+            printf("ERROR: channel mode not supported\n");
+            return EXIT_FAILURE;
+        }
+        ifconf.datarate = DR_LORA_SF7;
+        if (lgw_rxif_setconf(i, &ifconf) != LGW_HAL_SUCCESS) {
+            printf("ERROR: failed to configure rxif %d\n", i);
+            return EXIT_FAILURE;
+        }
+    }
+
+    /* set configuration for LoRa Service channel */
+    memset(&ifconf, 0, sizeof(ifconf));
+    ifconf.rf_chain = channel_rfchain_mode0[i];
+    ifconf.freq_hz = channel_if_mode0[i];
+    ifconf.datarate = DR_LORA_SF7;
+    ifconf.bandwidth = BW_250KHZ;
+    if (lgw_rxif_setconf(8, &ifconf) != LGW_HAL_SUCCESS) {
+        printf("ERROR: failed to configure rxif for LoRa service channel\n");
+        return EXIT_FAILURE;
+    }
+
+    /* set the buffer size to hold received packets */
+    struct lgw_pkt_rx_s rxpkt[max_rx_pkt];
+    printf("INFO: rxpkt buffer size is set to %u\n", max_rx_pkt);
+    printf("INFO: Select channel mode %u\n", channel_mode);
+
+    /* Loop until user quits */
+    cnt_loop = 0;
+    while( (quit_sig != 1) && (exit_sig != 1) )
+    {
+        cnt_loop += 1;
+
+        if (com_type == LGW_COM_SPI) {
+            /* Board reset */
+            if (system("./reset_lgw.sh start") != 0) {
+                printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
+                exit(EXIT_FAILURE);
+            }
+        }
+
+        /* connect, configure and start the LoRa concentrator */
+        x = lgw_start();
+        if (x != 0) {
+            printf("ERROR: failed to start the gateway\n");
+            return EXIT_FAILURE;
+        }
+
+        /* Loop until we have enough packets with CRC OK */
+        printf("Waiting for packets...\n");
+        nb_pkt_crc_ok = 0;
+        while (((nb_pkt_crc_ok < nb_loop) || nb_loop == 0) && (quit_sig != 1) && (exit_sig != 1)) {
+            /* fetch N packets */
+            nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt);
+
+            if (nb_pkt == 0) {
+                wait_ms(10);
+            } else {
+                for (i = 0; i < nb_pkt; i++) {
+                    if (rxpkt[i].status == STAT_CRC_OK) {
+                        nb_pkt_crc_ok += 1;
+                    }
+                    printf("\n----- %s packet -----\n", (rxpkt[i].modulation == MOD_LORA) ? "LoRa" : "FSK");
+                    printf("  count_us: %u\n", rxpkt[i].count_us);
+                    printf("  size:     %u\n", rxpkt[i].size);
+                    printf("  chan:     %u\n", rxpkt[i].if_chain);
+                    printf("  status:   0x%02X\n", rxpkt[i].status);
+                    printf("  datr:     %u\n", rxpkt[i].datarate);
+                    printf("  codr:     %u\n", rxpkt[i].coderate);
+                    printf("  rf_chain  %u\n", rxpkt[i].rf_chain);
+                    printf("  freq_hz   %u\n", rxpkt[i].freq_hz);
+                    printf("  snr_avg:  %.1f\n", rxpkt[i].snr);
+                    printf("  rssi_chan:%.1f\n", rxpkt[i].rssic);
+                    printf("  rssi_sig :%.1f\n", rxpkt[i].rssis);
+                    printf("  crc:      0x%04X\n", rxpkt[i].crc);
+                    for (j = 0; j < rxpkt[i].size; j++) {
+                        printf("%02X ", rxpkt[i].payload[j]);
+                    }
+                    printf("\n");
+                }
+                printf("Received %d packets (total:%lu)\n", nb_pkt, nb_pkt_crc_ok);
+            }
+        }
+
+        printf( "\nNb valid packets received: %lu CRC OK (%lu)\n", nb_pkt_crc_ok, cnt_loop );
+
+        /* Stop the gateway */
+        x = lgw_stop();
+        if (x != 0) {
+            printf("ERROR: failed to stop the gateway\n");
+            return EXIT_FAILURE;
+        }
+
+        if (com_type == LGW_COM_SPI) {
+            /* Board reset */
+            if (system("./reset_lgw.sh stop") != 0) {
+                printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
+                exit(EXIT_FAILURE);
+            }
+        }
+    }
+
+    printf("=========== Test End ===========\n");
+
+    return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 615 - 0
sx1302/source/test_loragw_hal_tx.c

@@ -0,0 +1,615 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+  (C)2019 Semtech
+
+Description:
+    Minimum test program for HAL TX capability
+
+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>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+#include <signal.h>     /* sigaction */
+#include <getopt.h>     /* getopt_long */
+
+#include "loragw_hal.h"
+#include "loragw_reg.h"
+#include "loragw_aux.h"
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE MACROS ------------------------------------------------------- */
+
+#define RAND_RANGE(min, max) (rand() % (max + 1 - min) + min)
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE CONSTANTS ---------------------------------------------------- */
+
+#define COM_TYPE_DEFAULT LGW_COM_SPI
+#define COM_PATH_DEFAULT "/dev/spidev0.0"
+
+#define DEFAULT_CLK_SRC     0
+#define DEFAULT_FREQ_HZ     868500000U
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE 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 */
+
+/* -------------------------------------------------------------------------- */
+/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
+
+/* 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(" -u         Set COM type as USB (default is SPI)\n");
+    printf(" -d <path>  COM path to be used to connect the concentrator\n");
+    printf("            => default path: " COM_PATH_DEFAULT "\n");
+    printf(" -k <uint>  Concentrator clock source (Radio A or Radio B) [0..1]\n");
+    printf(" -c <uint>  RF chain to be used for TX (Radio A or Radio B) [0..1]\n");
+    printf(" -r <uint>  Radio type (1255, 1257, 1250)\n");
+    printf(" -f <float> Radio TX frequency in MHz\n");
+    printf(" -m <str>   modulation type ['CW', 'LORA', 'FSK']\n");
+    printf(" -o <int>   CW frequency offset from Radio TX frequency in kHz [-65..65]\n");
+    printf(" -s <uint>  LoRa datarate 0:random, [5..12]\n");
+    printf(" -b <uint>  LoRa bandwidth in khz 0:random, [125, 250, 500]\n");
+    printf(" -l <uint>  FSK/LoRa preamble length, [6..65535]\n");
+    printf(" -n <uint>  Number of packets to be sent\n");
+    printf(" -z <uint>  size of packets to be sent 0:random, [9..255]\n");
+    printf(" -t <uint>  TX mode timestamped with delay in ms. If delay is 0, TX mode GPS trigger\n");
+    printf(" -p <int>   RF power in dBm\n");
+    printf(" -i         Send LoRa packet using inverted modulation polarity\n");
+    printf(" -j         Set radio in single input mode (SX1250 only)\n");
+    printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
+    printf(" --fdev <uint>  FSK frequency deviation in kHz [1:250]\n");
+    printf(" --br   <float> FSK bitrate in kbps [0.5:250]\n");
+    printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
+    printf(" --pa   <uint> PA gain SX125x:[0..3], SX1250:[0,1]\n");
+    printf(" --dig  <uint> sx1302 digital gain for sx125x [0..3]\n");
+    printf(" --dac  <uint> sx125x DAC gain [0..3]\n");
+    printf(" --mix  <uint> sx125x MIX gain [5..15]\n");
+    printf(" --pwid <uint> sx1250 power index [0..22]\n");
+    printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
+    printf(" --nhdr        Send LoRa packet with implicit header\n");
+    printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
+    printf(" --loop        Number of loops for HAL start/stop (HAL unitary test)\n");
+    printf( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" );
+    printf(" --fdd         Enable Full-Duplex mode (CN490 reference design)\n");
+}
+
+/* handle signals */
+static void sig_handler(int sigio)
+{
+    if (sigio == SIGQUIT) {
+        quit_sig = 1;
+    }
+    else if((sigio == SIGINT) || (sigio == SIGTERM)) {
+        exit_sig = 1;
+    }
+}
+
+/* -------------------------------------------------------------------------- */
+/* --- MAIN FUNCTION -------------------------------------------------------- */
+
+int main(int argc, char **argv)
+{
+    int i, x;
+    uint32_t ft = DEFAULT_FREQ_HZ;
+    int8_t rf_power = 0;
+    uint8_t sf = 0;
+    uint16_t bw_khz = 0;
+    uint32_t nb_pkt = 1;
+    unsigned int nb_loop = 1, cnt_loop;
+    uint8_t size = 0;
+    char mod[64] = "LORA";
+    float br_kbps = 50;
+    uint8_t fdev_khz = 25;
+    int8_t freq_offset = 0;
+    double arg_d = 0.0;
+    unsigned int arg_u;
+    int arg_i;
+    char arg_s[64];
+    float xf = 0.0;
+    uint8_t clocksource = 0;
+    uint8_t rf_chain = 0;
+    lgw_radio_type_t radio_type = LGW_RADIO_TYPE_SX1250;
+    uint16_t preamble = 8;
+    bool invert_pol = false;
+    bool no_header = false;
+    bool single_input_mode = false;
+    bool full_duplex = false;
+
+    struct lgw_conf_board_s boardconf;
+    struct lgw_conf_rxrf_s rfconf;
+    struct lgw_pkt_tx_s pkt;
+    struct lgw_tx_gain_lut_s txlut; /* TX gain table */
+    uint8_t tx_status;
+    uint32_t count_us;
+    uint32_t trig_delay_us = 1000000;
+    bool trig_delay = false;
+
+    /* SPI interfaces */
+    const char com_path_default[] = COM_PATH_DEFAULT;
+    const char * com_path = com_path_default;
+    lgw_com_type_t com_type = COM_TYPE_DEFAULT;
+
+    static struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
+
+    /* Initialize TX gain LUT */
+    txlut.size = 0;
+    memset(txlut.lut, 0, sizeof txlut.lut);
+
+    /* Parameter parsing */
+    int option_index = 0;
+    static struct option long_options[] = {
+        {"fdev", required_argument, 0, 0},
+        {"br",   required_argument, 0, 0},
+        {"pa",   required_argument, 0, 0},
+        {"dac",  required_argument, 0, 0},
+        {"dig",  required_argument, 0, 0},
+        {"mix",  required_argument, 0, 0},
+        {"pwid", required_argument, 0, 0},
+        {"loop", required_argument, 0, 0},
+        {"nhdr", no_argument, 0, 0},
+        {"fdd",  no_argument, 0, 0},
+        {0, 0, 0, 0}
+    };
+
+    /* parse command line options */
+    while ((i = getopt_long (argc, argv, "hjif:s:b:n:z:p:k:r:c:l:t:m:o:ud:", long_options, &option_index)) != -1) {
+        switch (i) {
+            case 'h':
+                usage();
+                return -1;
+                break;
+            case 'u':
+                com_type = LGW_COM_USB;
+                break;
+            case 'd': /* <char> COM path */
+                if (optarg != NULL) {
+                    com_path = optarg;
+                }
+                break;
+            case 'i': /* Send packet using inverted modulation polarity */
+                invert_pol = true;
+                break;
+            case 'j': /* Set radio in single input mode */
+                single_input_mode = true;
+                break;
+            case 'r': /* <uint> Radio type */
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || ((arg_u != 1255) && (arg_u != 1257) && (arg_u != 1250))) {
+                    printf("ERROR: argument parsing of -r argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    switch (arg_u) {
+                        case 1255:
+                            radio_type = LGW_RADIO_TYPE_SX1255;
+                            break;
+                        case 1257:
+                            radio_type = LGW_RADIO_TYPE_SX1257;
+                            break;
+                        default: /* 1250 */
+                            radio_type = LGW_RADIO_TYPE_SX1250;
+                            break;
+                    }
+                }
+                break;
+            case 'l': /* <uint> LoRa/FSK preamble length */
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || (arg_u > 65535)) {
+                    printf("ERROR: argument parsing of -l argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    preamble = (uint16_t)arg_u;
+                }
+                break;
+            case 'm': /* <str> Modulation type */
+                i = sscanf(optarg, "%s", arg_s);
+                if ((i != 1) || ((strcmp(arg_s, "CW") != 0) && (strcmp(arg_s, "LORA") != 0) && (strcmp(arg_s, "FSK")))) {
+                    printf("ERROR: invalid modulation type\n");
+                    return EXIT_FAILURE;
+                } else {
+                    sprintf(mod, "%s", arg_s);
+                }
+                break;
+            case 'o': /* <int> CW frequency offset from Radio TX frequency */
+                i = sscanf(optarg, "%d", &arg_i);
+                if ((arg_i < -65) || (arg_i > 65)) {
+                    printf("ERROR: invalid frequency offset\n");
+                    return EXIT_FAILURE;
+                } else {
+                    freq_offset = (int32_t)arg_i;
+                }
+                break;
+            case 't': /* <uint> Trigger delay in ms */
+                i = sscanf(optarg, "%u", &arg_u);
+                if (i != 1) {
+                    printf("ERROR: argument parsing of -t argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    trig_delay = true;
+                    trig_delay_us = (uint32_t)(arg_u * 1E3);
+                }
+                break;
+            case 'k': /* <uint> Clock Source */
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || (arg_u > 1)) {
+                    printf("ERROR: argument parsing of -k argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    clocksource = (uint8_t)arg_u;
+                }
+                break;
+            case 'c': /* <uint> RF chain */
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || (arg_u > 1)) {
+                    printf("ERROR: argument parsing of -c argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    rf_chain = (uint8_t)arg_u;
+                }
+                break;
+            case 'f': /* <float> Radio TX frequency in MHz */
+                i = sscanf(optarg, "%lf", &arg_d);
+                if (i != 1) {
+                    printf("ERROR: argument parsing of -f argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    ft = (uint32_t)((arg_d*1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
+                }
+                break;
+            case 's': /* <uint> LoRa datarate */
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || (arg_u < 5) || (arg_u > 12)) {
+                    printf("ERROR: argument parsing of -s argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    sf = (uint8_t)arg_u;
+                }
+                break;
+            case 'b': /* <uint> LoRa bandwidth in khz */
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || ((arg_u != 125) && (arg_u != 250) && (arg_u != 500))) {
+                    printf("ERROR: argument parsing of -b argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    bw_khz = (uint16_t)arg_u;
+                }
+                break;
+            case 'n': /* <uint> Number of packets to be sent */
+                i = sscanf(optarg, "%u", &arg_u);
+                if (i != 1) {
+                    printf("ERROR: argument parsing of -n argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    nb_pkt = (uint32_t)arg_u;
+                }
+                break;
+            case 'p': /* <int> RF power */
+                i = sscanf(optarg, "%d", &arg_i);
+                if (i != 1) {
+                    printf("ERROR: argument parsing of -p argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    rf_power = (int8_t)arg_i;
+                    txlut.size = 1;
+                    txlut.lut[0].rf_power = rf_power;
+                }
+                break;
+            case 'z': /* <uint> packet size */
+                i = sscanf(optarg, "%u", &arg_u);
+                if ((i != 1) || (arg_u < 9) || (arg_u > 255)) {
+                    printf("ERROR: argument parsing of -z argument. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                } else {
+                    size = (uint8_t)arg_u;
+                }
+                break;
+            case 0:
+                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: invalid FSK frequency deviation\n");
+                        return EXIT_FAILURE;
+                    } else {
+                        fdev_khz = (uint8_t)arg_u;
+                    }
+                } else if (strcmp(long_options[option_index].name, "br") == 0) {
+                    i = sscanf(optarg, "%f", &xf);
+                    if ((i != 1) || (xf < 0.5) || (xf > 250)) {
+                        printf("ERROR: invalid FSK bitrate\n");
+                        return EXIT_FAILURE;
+                    } else {
+                        br_kbps = xf;
+                    }
+                } 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 {
+                        txlut.size = 1;
+                        txlut.lut[0].pa_gain = (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 {
+                        txlut.size = 1;
+                        txlut.lut[0].dac_gain = (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 {
+                        txlut.size = 1;
+                        txlut.lut[0].mix_gain = (uint8_t)arg_u;
+                    }
+                } else 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 {
+                        txlut.size = 1;
+                        txlut.lut[0].dig_gain = (uint8_t)arg_u;
+                    }
+                } else if (strcmp(long_options[option_index].name, "pwid") == 0) {
+                    i = sscanf(optarg, "%u", &arg_u);
+                    if ((i != 1) || (arg_u > 22)) {
+                        printf("ERROR: argument parsing of --pwid argument. Use -h to print help\n");
+                        return EXIT_FAILURE;
+                    } else {
+                        txlut.size = 1;
+                        txlut.lut[0].mix_gain = 5; /* TODO: rework this, should not be needed for sx1250 */
+                        txlut.lut[0].pwr_idx = (uint8_t)arg_u;
+                    }
+                } else if (strcmp(long_options[option_index].name, "loop") == 0) {
+                    printf("%p\n", optarg);
+                    i = sscanf(optarg, "%u", &arg_u);
+                    if (i != 1) {
+                        printf("ERROR: argument parsing of --loop argument. Use -h to print help\n");
+                        return EXIT_FAILURE;
+                    } else {
+                        nb_loop = arg_u;
+                    }
+                } else if (strcmp(long_options[option_index].name, "nhdr") == 0) {
+                    no_header = true;
+                } else if (strcmp(long_options[option_index].name, "fdd") == 0) {
+                    full_duplex = true;
+                } else {
+                    printf("ERROR: argument parsing options. Use -h to print help\n");
+                    return EXIT_FAILURE;
+                }
+                break;
+            default:
+                printf("ERROR: argument parsing\n");
+                usage();
+                return -1;
+        }
+    }
+
+    /* Summary of packet parameters */
+    if (strcmp(mod, "CW") == 0) {
+        printf("Sending %i CW on %u Hz (Freq. offset %d kHz) at %i dBm\n", nb_pkt, ft, freq_offset, rf_power);
+    }
+    else 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\n", nb_pkt, ft, fdev_khz, br_kbps, size, preamble, rf_power);
+    } else {
+        printf("Sending %i LoRa packets on %u Hz (BW %i kHz, SF %i, CR %i, %i bytes payload, %i symbols preamble, %s header, %s polarity) at %i dBm\n", nb_pkt, ft, bw_khz, sf, 1, size, preamble, (no_header == false) ? "explicit" : "implicit", (invert_pol == false) ? "non-inverted" : "inverted", rf_power);
+    }
+//处理中断推出
+    /* 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 );
+
+    /* Configure the gateway */
+    memset( &boardconf, 0, sizeof boardconf);
+    boardconf.lorawan_public = true;
+    boardconf.clksrc = clocksource;
+    boardconf.full_duplex = full_duplex;
+    boardconf.com_type = com_type;
+    strncpy(boardconf.com_path, com_path, sizeof boardconf.com_path);
+    boardconf.com_path[sizeof boardconf.com_path - 1] = '\0'; /* ensure string termination */
+    if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) {
+        printf("ERROR: failed to configure board\n");
+        return EXIT_FAILURE;
+    }
+
+    memset( &rfconf, 0, sizeof rfconf);
+    rfconf.enable = true; /* rf chain 0 needs to be enabled for calibration to work on sx1257 */
+    rfconf.freq_hz = ft;
+    rfconf.type = radio_type;
+    rfconf.tx_enable = true;
+    rfconf.single_input_mode = single_input_mode;
+    if (lgw_rxrf_setconf(0, &rfconf) != LGW_HAL_SUCCESS) {
+        printf("ERROR: failed to configure rxrf 0\n");
+        return EXIT_FAILURE;
+    }
+
+    memset( &rfconf, 0, sizeof rfconf);
+    rfconf.enable = (((rf_chain == 1) || (clocksource == 1)) ? true : false);
+    rfconf.freq_hz = ft;
+    rfconf.type = radio_type;
+    rfconf.tx_enable = false;
+    rfconf.single_input_mode = single_input_mode;
+    if (lgw_rxrf_setconf(1, &rfconf) != LGW_HAL_SUCCESS) {
+        printf("ERROR: failed to configure rxrf 1\n");
+        return EXIT_FAILURE;
+    }
+
+    if (txlut.size > 0) {
+        if (lgw_txgain_setconf(rf_chain, &txlut) != LGW_HAL_SUCCESS) {
+            printf("ERROR: failed to configure txgain lut\n");
+            return EXIT_FAILURE;
+        }
+    }
+
+    for (cnt_loop = 0; cnt_loop < nb_loop; cnt_loop++) {
+        if (com_type == LGW_COM_SPI) {
+        /* Board reset */
+            if (system("./reset_lgw.sh start") != 0) {
+                printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
+                exit(EXIT_FAILURE);
+            }
+        }
+
+        /* connect, configure and start the LoRa concentrator */
+        x = lgw_start();
+        if (x != 0) {
+            printf("ERROR: failed to start the gateway\n");
+            return EXIT_FAILURE;
+        }
+
+        /* Send packets */
+        memset(&pkt, 0, sizeof pkt);
+        pkt.rf_chain = rf_chain;
+        pkt.freq_hz = ft;
+        pkt.rf_power = rf_power;
+        if (trig_delay == false) {
+            pkt.tx_mode = IMMEDIATE;
+        } else {
+            if (trig_delay_us == 0) {
+                pkt.tx_mode = ON_GPS;
+            } else {
+                pkt.tx_mode = TIMESTAMPED;
+            }
+        }
+        if ( strcmp( mod, "CW" ) == 0 ) {
+            pkt.modulation = MOD_CW;
+            pkt.freq_offset = freq_offset;
+            pkt.f_dev = fdev_khz;
+        }
+        else if( strcmp( mod, "FSK" ) == 0 ) {
+            pkt.modulation = MOD_FSK;
+            pkt.no_crc = false;
+            pkt.datarate = br_kbps * 1e3;
+            pkt.f_dev = fdev_khz;
+        } else {
+            pkt.modulation = MOD_LORA;
+            pkt.coderate = CR_LORA_4_5;
+            pkt.no_crc = true;
+        }
+        pkt.invert_pol = invert_pol;
+        pkt.preamble = preamble;
+        pkt.no_header = no_header;
+        pkt.payload[0] = 0x40; /* Confirmed Data Up */
+        pkt.payload[1] = 0xAB;
+        pkt.payload[2] = 0xAB;
+        pkt.payload[3] = 0xAB;
+        pkt.payload[4] = 0xAB;
+        pkt.payload[5] = 0x00; /* FCTrl */
+        pkt.payload[6] = 0; /* FCnt */
+        pkt.payload[7] = 0; /* FCnt */
+        pkt.payload[8] = 0x02; /* FPort */
+        for (i = 9; i < 255; i++) {
+            pkt.payload[i] = i;
+        }
+
+        for (i = 0; i < (int)nb_pkt; i++) {
+            if (trig_delay == true) {
+                if (trig_delay_us > 0) {
+                    lgw_get_instcnt(&count_us);
+                    printf("count_us:%u\n", count_us);
+                    pkt.count_us = count_us + trig_delay_us;
+                    printf("programming TX for %u\n", pkt.count_us);
+                } else {
+                    printf("programming TX for next PPS (GPS)\n");
+                }
+            }
+
+            if( strcmp( mod, "LORA" ) == 0 ) {
+                pkt.datarate = (sf == 0) ? (uint8_t)RAND_RANGE(5, 12) : sf;
+            }
+
+            switch (bw_khz) {
+                case 125:
+                    pkt.bandwidth = BW_125KHZ;
+                    break;
+                case 250:
+                    pkt.bandwidth = BW_250KHZ;
+                    break;
+                case 500:
+                    pkt.bandwidth = BW_500KHZ;
+                    break;
+                default:
+                    pkt.bandwidth = (uint8_t)RAND_RANGE(BW_125KHZ, BW_500KHZ);
+                    break;
+            }
+
+            pkt.size = (size == 0) ? (uint8_t)RAND_RANGE(9, 255) : size;
+
+            pkt.payload[6] = (uint8_t)(i >> 0); /* FCnt */
+            pkt.payload[7] = (uint8_t)(i >> 8); /* FCnt */
+            x = lgw_send(&pkt);
+            if (x != 0) {
+                printf("ERROR: failed to send packet\n");
+                break;
+            }
+            /* wait for packet to finish sending */
+            do {
+                wait_ms(5);
+                lgw_status(pkt.rf_chain, TX_STATUS, &tx_status); /* get TX status */
+            } while ((tx_status != TX_FREE) && (quit_sig != 1) && (exit_sig != 1));
+
+            if ((quit_sig == 1) || (exit_sig == 1)) {
+                break;
+            }
+            printf("TX done\n");
+        }
+
+        printf( "\nNb packets sent: %u (%u)\n", i, cnt_loop + 1 );
+
+        /* Stop the gateway */
+        x = lgw_stop();
+        if (x != 0) {
+            printf("ERROR: failed to stop the gateway\n");
+        }
+
+        if (com_type == LGW_COM_SPI) {
+            /* Board reset */
+            if (system("./reset_lgw.sh stop") != 0) {
+                printf("ERROR: failed to reset SX1302, check your reset_lgw.sh script\n");
+                exit(EXIT_FAILURE);
+            }
+        }
+    }
+
+    printf("=========== Test End ===========\n");
+
+    return 0;
+}
+
+/* --- EOF ------------------------------------------------------------------ */

+ 145 - 0
sx1302/source/tinymt32.c

@@ -0,0 +1,145 @@
+/**
+ * @file tinymt32.c
+ *
+ * @brief Tiny Mersenne Twister only 127 bit internal state
+ *
+ * @author Mutsuo Saito (Hiroshima University)
+ * @author Makoto Matsumoto (The University of Tokyo)
+ *
+ * Copyright (C) 2011 Mutsuo Saito, Makoto Matsumoto,
+ * Hiroshima University and The University of Tokyo.
+ * All rights reserved.
+ *
+ * The 3-clause BSD License is applied to this software, see
+ * LICENSE.txt
+ */
+#include "tinymt32.h"
+#define MIN_LOOP 8
+#define PRE_LOOP 8
+
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t ini_func1(uint32_t x) {
+    return (x ^ (x >> 27)) * UINT32_C(1664525);
+}
+
+/**
+ * This function represents a function used in the initialization
+ * by init_by_array
+ * @param x 32-bit integer
+ * @return 32-bit integer
+ */
+static uint32_t ini_func2(uint32_t x) {
+    return (x ^ (x >> 27)) * UINT32_C(1566083941);
+}
+
+/**
+ * This function certificate the period of 2^127-1.
+ * @param random tinymt state vector.
+ */
+static void period_certification(tinymt32_t * random) {
+    if ((random->status[0] & TINYMT32_MASK) == 0 &&
+	random->status[1] == 0 &&
+	random->status[2] == 0 &&
+	random->status[3] == 0) {
+	random->status[0] = 'T';
+	random->status[1] = 'I';
+	random->status[2] = 'N';
+	random->status[3] = 'Y';
+    }
+}
+
+/**
+ * This function initializes the internal state array with a 32-bit
+ * unsigned integer seed.
+ * @param random tinymt state vector.
+ * @param seed a 32-bit unsigned integer used as a seed.
+ */
+void tinymt32_init(tinymt32_t * random, uint32_t seed) {
+    random->status[0] = seed;
+    random->status[1] = random->mat1;
+    random->status[2] = random->mat2;
+    random->status[3] = random->tmat;
+    for (int i = 1; i < MIN_LOOP; i++) {
+	random->status[i & 3] ^= i + UINT32_C(1812433253)
+	    * (random->status[(i - 1) & 3]
+	       ^ (random->status[(i - 1) & 3] >> 30));
+    }
+    period_certification(random);
+    for (int i = 0; i < PRE_LOOP; i++) {
+	tinymt32_next_state(random);
+    }
+}
+
+/**
+ * This function initializes the internal state array,
+ * with an array of 32-bit unsigned integers used as seeds
+ * @param random tinymt state vector.
+ * @param init_key the array of 32-bit integers, used as a seed.
+ * @param key_length the length of init_key.
+ */
+void tinymt32_init_by_array(tinymt32_t * random, uint32_t init_key[],
+			    int key_length) {
+    const int lag = 1;
+    const int mid = 1;
+    const int size = 4;
+    int i, j;
+    int count;
+    uint32_t r;
+    uint32_t * st = &random->status[0];
+
+    st[0] = 0;
+    st[1] = random->mat1;
+    st[2] = random->mat2;
+    st[3] = random->tmat;
+    if (key_length + 1 > MIN_LOOP) {
+	count = key_length + 1;
+    } else {
+	count = MIN_LOOP;
+    }
+    r = ini_func1(st[0] ^ st[mid % size]
+		  ^ st[(size - 1) % size]);
+    st[mid % size] += r;
+    r += key_length;
+    st[(mid + lag) % size] += r;
+    st[0] = r;
+    count--;
+    for (i = 1, j = 0; (j < count) && (j < key_length); j++) {
+	r = ini_func1(st[i % size]
+		      ^ st[(i + mid) % size]
+		      ^ st[(i + size - 1) % size]);
+	st[(i + mid) % size] += r;
+	r += init_key[j] + i;
+	st[(i + mid + lag) % size] += r;
+	st[i % size] = r;
+	i = (i + 1) % size;
+    }
+    for (; j < count; j++) {
+	r = ini_func1(st[i % size]
+		      ^ st[(i + mid) % size]
+		      ^ st[(i + size - 1) % size]);
+	st[(i + mid) % size] += r;
+	r += i;
+	st[(i + mid + lag) % size] += r;
+	st[i % size] = r;
+	i = (i + 1) % size;
+    }
+    for (j = 0; j < size; j++) {
+	r = ini_func2(st[i % size]
+		      + st[(i + mid) % size]
+		      + st[(i + size - 1) % size]);
+	st[(i + mid) % size] ^= r;
+	r -= i;
+	st[(i + mid + lag) % size] ^= r;
+	st[i % size] = r;
+	i = (i + 1) % size;
+    }
+    period_certification(random);
+    for (i = 0; i < PRE_LOOP; i++) {
+	tinymt32_next_state(random);
+    }
+}