diff --git a/Documentation/components/drivers/character/wireless/lpwan/index.rst b/Documentation/components/drivers/character/wireless/lpwan/index.rst index eb370ccfc185f..eb1b8e60e8458 100644 --- a/Documentation/components/drivers/character/wireless/lpwan/index.rst +++ b/Documentation/components/drivers/character/wireless/lpwan/index.rst @@ -5,5 +5,7 @@ LPWAN .. toctree:: :maxdepth: 1 + lora_gw.rst sx126x.rst + sx127x.rst diff --git a/Documentation/components/drivers/character/wireless/lpwan/lora_gw.rst b/Documentation/components/drivers/character/wireless/lpwan/lora_gw.rst new file mode 100644 index 0000000000000..b0af563ed8b83 --- /dev/null +++ b/Documentation/components/drivers/character/wireless/lpwan/lora_gw.rst @@ -0,0 +1,128 @@ +.. _lora_gw: + +================================ +LoRa gateway (concentrator) API +================================ + +A LoRa gateway does not listen to one channel at a time as an end device +does: a concentrator demodulates several channels at once, on two radio +front-ends, and every packet arrives with its own frequency, spreading factor +and coding rate. The commands that configure a radio, ``WLIOC_SETRADIOFREQ`` +and the ``WLIOC_LORA_x`` family, therefore have nothing to act upon on such a +device, and what it needs instead is a channel plan, a way to be started and +stopped, and the counter its timestamps are taken from. + +This is the device independent interface those drivers implement, declared in +``nuttx/wireless/lpwan/lora_gw.h``. An application drives a gateway through it +and never names a chip. + +Character device +================ + +A driver of this class registers a character device, ``/dev/lora0`` by +convention, on which: + +* ``read`` returns whole multiples of ``struct lora_gw_rxpkt_s``, oldest + first, as many as fit in the buffer. It blocks until at least one packet is + available unless the file was opened with ``O_NONBLOCK``, and fails with + ``EINVAL`` if the buffer cannot hold one whole packet. + +* ``write`` takes exactly one ``struct lora_gw_txpkt_s``. The packet carries + its own frequency, power, modulation and, for a LoRaWAN downlink, + ``invert_pol``. It is sent immediately with ``LORA_GW_TX_IMMEDIATE`` or at a + concentrator timestamp with ``LORA_GW_TX_TIMESTAMPED``. + +Both structures follow the layout of the userspace HAL that Semtech publishes +for this family of chips, which is what gateway software is written against +on other systems, so that such an application ports by replacing its +``lgw_receive`` with ``read`` and its ``lgw_send`` with ``write``. Two things +deliberately differ: + +.. list-table:: + :header-rows: 1 + + * - Field + - Unit + * - ``rssi_dbm10``, ``snr_db10`` + - Tenths of a dBm or dB, as integers, so that no floating point is + needed in a driver + * - ``datarate`` + - The spreading factor as a plain number, 7 to 12, not a bit mask + * - ``bandwidth`` + - ``LORA_GW_BW_125K``, ``_250K`` or ``_500K`` + * - ``coderate`` + - ``enum wlioc_lora_cr_e``, shared with the end device drivers + * - ``status`` + - ``LORA_GW_STAT_CRC_OK``, ``_CRC_BAD`` or ``_NO_CRC`` + +A packet reported as ``LORA_GW_STAT_CRC_BAD`` must never be forwarded as if +it were valid: those are mostly correlator false triggers. + +IOCTL commands +============== + +See ``nuttx/wireless/ioctl.h`` : ``WLIOC_GW_x``. + +* ``WLIOC_GW_START`` resets the chip, loads the firmware of its internal + MCUs, calibrates it and starts receiving on the selected channel plan. + ``WLIOC_GW_STOP`` stops it and ``WLIOC_GW_RESET`` does both in sequence. + +* ``WLIOC_GW_SETREGION`` selects a channel plan by name, for example + ``"AU915"``, while the concentrator is stopped. ``WLIOC_GW_GETREGION`` + takes a ``struct lora_gw_regionreq_s``: an ``index`` of -1 describes the + active plan, and 0 upwards enumerates the supported ones until ``ENODEV``. + The description that comes back lists the centre frequency of each radio + and the frequency, radio and type of every channel. + +* ``WLIOC_GW_GETSTATUS`` fills a ``struct lora_gw_status_s`` with the state + of the concentrator and its counters, including the packets dropped + because their CRC failed. + +* ``WLIOC_GW_GETTRIGCNT`` reads the internal counter of the concentrator, in + microseconds. This is the time base a LoRaWAN network server schedules + downlinks against. + +Whether the units of the packet should instead follow the ones of the end +device commands, that is, bandwidth in Hz and levels scaled by a hundred as +in ``struct wlioc_rx_hdr_s``, is a question for the common LoRa API rather +than for one driver, and is left as it is until that API materialises. + +SX1301 driver +============= + +The Semtech SX1301 is the baseband processor of a LoRaWAN gateway: eight +multi-SF demodulators, one LoRa standard demodulator and one FSK +demodulator, driven by two SX125x radio front-ends that are reached through +an SPI bridge inside the SX1301 itself. It is the first implementation of the +interface above and is enabled with ``CONFIG_LPWAN_SX1301``. + +Options +------- + +* ``CONFIG_LPWAN_SX1301_SPIFREQ`` is the SPI clock, up to 10 MHz. + +* ``CONFIG_LPWAN_SX1301_DEFAULT_REGION`` is the channel plan selected when + the driver is registered: one of AU915, AU915-1, US915, US915-1, EU868, + AS923, KR920 or IN866. AU915 and US915 default to the second sub-band, + which is what The Things Network and the Brazilian deployments use. + +* ``CONFIG_LPWAN_SX1301_PRIVATE_NETWORK`` switches the frame synchronisation + word from the public LoRaWAN one to the private one. + +* ``CONFIG_LPWAN_SX1301_RXBADCRC`` and ``CONFIG_LPWAN_SX1301_RXNOCRC`` + deliver the packets that a gateway normally drops, which is useful when + bringing a shield up against an unknown transmitter. + +Board implementation +-------------------- + +The driver is registered with ``sx1301_register``, which takes the device +path, an SPI bus and a ``struct sx1301_lower_s``. That structure carries the +two things the chip needs from the board: a ``reset`` hook driving its reset +line, and an optional ``band_select`` hook for the shields whose front-end +filters are switched between 868 and 915 MHz by a pair of GPIOs. See +``nuttx/wireless/lpwan/sx1301.h``. + +A worked example, with the wiring of an LRWAN_GS_HF1 shield, the expected +boot output and a gateway forwarding to a public network, is in the +:ref:`Nucleo F746ZG ` page. diff --git a/Documentation/components/drivers/character/wireless/lpwan/sx127x.rst b/Documentation/components/drivers/character/wireless/lpwan/sx127x.rst new file mode 100644 index 0000000000000..7ec0f3a3df58b --- /dev/null +++ b/Documentation/components/drivers/character/wireless/lpwan/sx127x.rst @@ -0,0 +1,132 @@ +.. _sx127x: + +================= +SX127x LoRa radio +================= + +The SX127x family, which includes the SX1272 and the SX1276 found on most +modules and development boards, is a sub-GHz transceiver doing LoRa as well +as FSK and OOK. Unlike a concentrator it demodulates one channel at a time, +so frequency, spreading factor and bandwidth are settings of the radio and +not attributes of each packet. + +The driver is enabled with ``CONFIG_LPWAN_SX127X`` and registers a character +device, ``/dev/sx127x`` by convention. + +Userspace API +============= + +Reading and writing +------------------- + +``write`` transmits the given bytes with the parameters currently configured. +``read`` returns one received packet, blocking until one arrives; with +``CONFIG_LPWAN_SX127X_RXFIFO_LEN`` the driver keeps a small queue of them, so +a reader that falls behind loses the oldest rather than the newest. + +Each packet is preceded by a ``struct sx127x_read_hdr_s``, which carries the +payload length together with the received power and, in LoRa mode, the signal +to noise ratio of that packet. + +IOCTL commands +-------------- + +The basic radio parameters use the common commands of +``nuttx/wireless/ioctl.h``: ``WLIOC_SETRADIOFREQ`` and ``WLIOC_GETRADIOFREQ`` +for the frequency in Hz, ``WLIOC_SETTXPOWER`` and ``WLIOC_GETTXPOWER`` for +the output power in dBm. Both may be further limited by the board logic. + +The rest is in ``nuttx/wireless/lpwan/sx127x.h``: + +* ``SX127XIOC_MODULATIONSET`` and ``SX127XIOC_MODULATIONGET`` choose between + LoRa, FSK and OOK. + +* ``SX127XIOC_OPMODESET`` and ``SX127XIOC_OPMODEGET`` move the radio between + sleep, standby, transmit, receive and channel activity detection. + +* ``SX127XIOC_SYNCWORDSET`` and ``SX127XIOC_SYNCWORDGET`` change the sync + word, and ``SX127XIOC_PREAMBLESET`` and ``SX127XIOC_PREAMBLEGET`` the + preamble length. + +* ``SX127XIOC_RSSIGET`` reads the current RSSI, ``SX127XIOC_CHANSCAN`` scans + a channel and ``SX127XIOC_RANDOMGET`` returns a random number taken from + the noise of the receiver. + +Note that the spreading factor, the bandwidth and the coding rate have no +ioctl of their own yet: they come from the configuration below. + +Configuration +============= + +============================================ ================================== +Option Meaning +============================================ ================================== +``LPWAN_SX127X_RFFREQ_DEFAULT`` Frequency, in Hz, at registration +``LPWAN_SX127X_TXPOWER_DEFAULT`` Output power in dBm +``LPWAN_SX127X_MODULATION_DEFAULT`` 1 for FSK, 2 for OOK, 3 for LoRa +``LPWAN_SX127X_RXSUPPORT`` Build the receive path +``LPWAN_SX127X_TXSUPPORT`` Build the transmit path +``LPWAN_SX127X_LORA`` Build the LoRa modem +``LPWAN_SX127X_FSKOOK`` Build the FSK and OOK modem +``LPWAN_SX127X_LORA_SYNCWORD`` Sync word, see below +``LPWAN_SX127X_LORA_BW_DEFAULT`` Bandwidth, 7 selects 125 kHz +``LPWAN_SX127X_LORA_SF_DEFAULT`` Spreading factor, 6 to 12 +``LPWAN_SX127X_CRCON`` Append and check a CRC +``LPWAN_SX127X_RXFIFO_LEN`` Packets buffered by the driver +============================================ ================================== + +Talking to another radio +======================== + +Two settings decide whether two devices hear each other at all, and both are +silent failures when they disagree: + +* **Band.** The chip has separate low and high frequency front ends and the + modem has to be told which one is in use. The driver derives that from the + configured frequency, using the high band above 525 MHz. + +* **Sync word.** ``CONFIG_LPWAN_SX127X_LORA_SYNCWORD`` defaults to 0x12, the + private network value. A public LoRaWAN network uses 0x34, and a receiver + configured for the other value never even detects the frame. + +Beyond those, the spreading factor, the bandwidth and the coding rate have to +match on both sides. + +Two boards reach each other with the ``sx127x`` example of +``apps/examples/sx127x_demo``. Start the receiver first, since the example +gives up after the time given with ``-d``:: + + board A> sx127x -m 0 -f 917200000 -r -d 60 + board B> sx127x -m 0 -f 917200000 -t -p 0 -l 32 -d 30 + +The receiver prints the payload of every packet along with its signal to +noise ratio and its received power. Keep the boards a metre or so apart: at a +few centimetres a transmitter saturates the other receiver and the packets +arrive with a broken CRC. + +The same commands work against a gateway. A concentrator running the ``lora`` +command of ``apps/wireless/lora_pkt_fwd`` sends a packet with +``lora tx 917200000 7 hello``, which any board listening on that frequency +receives; and a board transmitting as above shows up on the gateway as an +ordinary uplink. See :ref:`lora_gw` for the gateway side. + +Board implementation +==================== + +The driver is registered with ``sx127x_register``, which takes an SPI bus and +a ``struct sx127x_lower_s``. That structure carries what the chip needs from +the board: attaching the DIO0 interrupt, which signals the end of a +transmission or a reception, a ``reset`` hook, and the optional +``opmode_change``, ``freq_select`` and ``pa_select`` hooks used by boards +whose antenna switch or power amplifier path depends on the operating mode, +the frequency or the requested power. See +``nuttx/wireless/lpwan/sx127x.h``. + +Boards +====== + +* :ref:`ST B-L072Z-LRWAN1 ` +* :ref:`Nucleo L073RZ ` +* :ref:`Nucleo F091RC ` +* :ref:`nRF52840-DK ` +* :ref:`Heltec WiFi LoRa 32 ` diff --git a/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst b/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst index 6375fad4b067c..43e93e1ab6afa 100644 --- a/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst +++ b/Documentation/platforms/arm/nrf52/boards/nrf52840-dk/index.rst @@ -1,3 +1,5 @@ +.. _nrf52840-dk: + =========== nRF52840-DK =========== diff --git a/Documentation/platforms/arm/stm32f0/boards/nucleo-f091rc/index.rst b/Documentation/platforms/arm/stm32f0/boards/nucleo-f091rc/index.rst index 8f5df38000915..a308569c09875 100644 --- a/Documentation/platforms/arm/stm32f0/boards/nucleo-f091rc/index.rst +++ b/Documentation/platforms/arm/stm32f0/boards/nucleo-f091rc/index.rst @@ -1,3 +1,5 @@ +.. _nucleo-f091rc: + ================= ST Nucleo F091RC ================= diff --git a/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/index.rst b/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/index.rst index f010732432a12..eedd91fa4d936 100644 --- a/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/index.rst +++ b/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/index.rst @@ -1,9 +1,14 @@ +.. _nucleo-f746zg: + ================ ST Nucleo F746ZG ================ .. tags:: chip:stm32, chip:stm32f7, chip:stm32f746 +.. figure:: nucleo-f746zg.jpg + :align: center + This page discusses issues unique to NuttX configurations for the STMicro Nucleo-144 board. See ST document STM32 Nucleo-144 boards (UM1974): @@ -313,6 +318,40 @@ and connect it as follows:: CD PC11 CN11-2 +LoRa Concentrator Shield +------------------------ + +The board supports a LoRa gateway shield of the LRWAN_GS_HF1 family, such as +the RisingHF RHF0M301, which carries a Semtech SX1301 baseband processor and +two SX1257 radio front ends. The shield is wired to SPI4 on the morpho +connector:: + + FUNCTION GPIO CONNECTOR + ------------ ---- --------- + SPI4_SCK PE12 CN11-49 + SPI4_MISO PE13 CN11-47 + SPI4_MOSI PE14 CN11-45 + SPI4_CS PE11 CN11-53 + SX1301_RESET PE15 active high + BAND_SET1 PD15 D9, front end filter select + BAND_SET2 PE9 D6, front end filter select + ------------ ---- --------- + +The chip select is driven as a plain output rather than by the hardware NSS, +as the concentrator needs it held low for a whole burst. The two band +selection lines drive the filter bank of the shield: 915 MHz uses SET1 low +and SET2 high, 868 MHz the other way around. + +With ``CONFIG_LPWAN_SX1301`` selected, the board registers the concentrator +at ``/dev/lora0``, behind the device independent gateway interface. That +interface, the configuration options of the driver and the channel plans it +supports are documented in :ref:`lora_gw`. + +The same shields usually carry a serial NOR flash on SPI5 (PF7 SCK, PF8 +MISO, PF9 MOSI, PF6 CS). The pins are defined in ``include/board.h`` and the +chip select is handled by the board, but no MTD driver is registered for it +yet. + Configurations ============== @@ -421,3 +460,68 @@ NOTES: CONFIG_HOST_LINUX=y : Builds under Linux CONFIG_ARM_TOOLCHAIN_GNU_EABI=y : ARM GNU for Linux + +lorawan_gw +---------- + +Turns the board into a LoRaWAN gateway: the SX1301 concentrator on SPI4 and +the Ethernet interface with DHCP and DNS. The console is the virtual COM port +on USART3. + +Selecting ``CONFIG_WIRELESS_LORA_PKT_FWD`` adds the Semtech UDP packet +forwarder of ``apps/wireless/lora_pkt_fwd``, which is what turns the +concentrator into a gateway and provides the ``lora`` command used below. + +.. figure:: nucleo-f746zg-lora-sx1301.png + :align: center + + The board with an LRWAN_GS_HF1 shield mounted on the morpho headers. + +Build and flash:: + + $ ./tools/configure.sh nucleo-f746zg:lorawan_gw + $ make + $ cp nuttx.bin /media//NODE_F746ZG/ + +The forwarder and the concentrator are driven by the ``lora`` command, which +mirrors the AT command set of the vendor gateway firmwares:: + + nsh> lora # list the subcommands + nsh> lora sys # identity, network and channel plan + nsh> lora ch # show the channel plan + nsh> lora ch EU868 # change region: AU915, AU915-1, US915, + # US915-1, EU868, AS923, KR920, IN866 + nsh> lora server [up] [down] # network server, name or address + nsh> lora start # start the concentrator and forward + nsh> lora status # counters of both sides + nsh> lora stop + nsh> lora tx 917200000 7 hello # transmit one packet, for bring-up + +The last one exists to bring a gateway up without a network server: it +sends a single packet with the polarity of an uplink, so any LoRa receiver +tuned to the same frequency, spreading factor and 125 kHz bandwidth sees +it. + +The default region is the second sub-band of AU915 (channels 8 to 15 plus the +500 kHz channel 65), which is what The Things Network and the Brazilian +deployments use; ``AU915-1`` selects the first sub-band instead. The default +server and the gateway identifier come from the configuration +(``CONFIG_LORA_PKT_FWD_SERVER`` and ``CONFIG_LORA_PKT_FWD_EUI``) and both can +be changed at runtime. + +A working session looks like this:: + + nsh> lora start + sx1301_reg_probe: SX1301 detected, version 0x67 + sx1301_setup_radio: Radio A: PLL locked at 917100000 Hz + sx1301_setup_radio: Radio B: PLL locked at 917900000 Hz + sx1301_calibrate: Calibration done, status 0xbf + sx1301_agc_start: AGC running, radio map 0xf0 + sx1301_start: Concentrator started, modems 0x0b + lora: forwarding to au1.cloud.thethings.network (up 1700, down 1700) + sx1301_receive: RX chain 0 SF10 915200000 Hz snr 14.0 dB size 23 status 0x10 + lora: forwarded 1 packet(s) + +Note that the sync word has to match the devices: the driver configures the +concentrator for a public LoRaWAN network, and +``CONFIG_LPWAN_SX1301_PRIVATE_NETWORK`` switches it to a private one. diff --git a/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/nucleo-f746zg-lora-sx1301.png b/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/nucleo-f746zg-lora-sx1301.png new file mode 100644 index 0000000000000..bab6c046629d2 Binary files /dev/null and b/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/nucleo-f746zg-lora-sx1301.png differ diff --git a/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/nucleo-f746zg.jpg b/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/nucleo-f746zg.jpg new file mode 100644 index 0000000000000..d2ecac936e28d Binary files /dev/null and b/Documentation/platforms/arm/stm32f7/boards/nucleo-f746zg/nucleo-f746zg.jpg differ diff --git a/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/b-l072z-lrwan1.jpg b/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/b-l072z-lrwan1.jpg new file mode 100644 index 0000000000000..b76958a3dd1d3 Binary files /dev/null and b/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/b-l072z-lrwan1.jpg differ diff --git a/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/index.rst b/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/index.rst index 0370a97552212..bb0b99d2170bf 100644 --- a/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/index.rst +++ b/Documentation/platforms/arm/stm32l0/boards/b-l072z-lrwan1/index.rst @@ -1,7 +1,238 @@ +.. _b-l072z-lrwan1: + ================= ST B-L072Z-LRWAN1 ================= .. tags:: chip:stm32, chip:stm32l0, chip:stm32l072 -The B-L072Z-LRWAN1 is a development board based on CMWX1ZZABZ-091 (STM32L072CZ and an SX1276 transceiver). +.. figure:: b-l072z-lrwan1.jpg + :align: center + +The B-L072Z-LRWAN1 is a LoRa and Sigfox discovery board built around the +Murata CMWX1ZZABZ-091 module, which packs an STM32L072CZ microcontroller and +a Semtech SX1276 sub-GHz transceiver into a single package. The board +carries an SMA connector with a whip antenna, an on-board ST-LINK/V2-1 and +Arduino Uno R3 compatible headers. + +Board information +================= + +The board features: + + - Murata CMWX1ZZABZ-091 module: STM32L072CZ (Cortex-M0+ up to 32 MHz, + 192 KiB flash, 20 KiB RAM) plus an SX1276 transceiver + - Programmable RF power, up to +14 dBm on the RFO path and +20 dBm on + PA_BOOST + - SMA and U.FL antenna connectors + - 32 MHz TCXO for the radio, powered from a GPIO + - On-board ST-LINK/V2-1 with mass storage programming and a virtual COM + port + - Arduino Uno R3 headers plus the ST morpho extension headers + - Four LEDs and one user button + - USB 2.0 full speed device connector + - Powered from USB, from an external supply or from a battery + +Board documentation: +https://www.st.com/en/evaluation-tools/b-l072z-lrwan1.html + +Clocking +======== + +NuttX runs the part from the internal 16 MHz RC oscillator through the PLL, +which gives a 32 MHz system clock. No external crystal is needed for the +microcontroller; the 32 MHz TCXO of the module belongs to the radio. + +Serial console +============== + +USART2 is wired to the virtual COM port of the on-board ST-LINK and is the +NuttX console in every configuration: + +=========== ===== +Signal Pin +=========== ===== +USART2_TX PA2 +USART2_RX PA3 +=========== ===== + +Settings are 115200 8N1. With the board plugged in, the port shows up as +``/dev/ttyACM0`` on Linux. + +LEDs +==== + +The board has four LEDs, all active high: + +===== ==== ======================== +LED Pin Colour +===== ==== ======================== +LED1 PA5 Green, also Arduino D13 +LED2 PB5 Green +LED3 PB6 Blue +LED4 PB7 Red +===== ==== ======================== + +If ``CONFIG_ARCH_LEDS`` is selected, LED1 is driven by the OS to show the +system state: + +========================== ========== +State LED1 +========================== ========== +Idle stack created ON +In an interrupt Flashing +Signal handler, assertion Flashing +The system has crashed Blinking +========================== ========== + +Otherwise the four LEDs are available to the application through +``/dev/userleds`` when ``CONFIG_USERLED`` is selected. + +Buttons +======= + +======== ==== =================================== +Button Pin Notes +======== ==== =================================== +B1 USER PB2 Pulled up, active low, EXTI capable +B2 RESET NRST Resets the microcontroller +======== ==== =================================== + +Radio +===== + +The SX1276 sits inside the module and is reached over SPI1. Besides the bus +and the interrupt lines, three GPIOs drive the antenna switch and one powers +the TCXO that clocks the radio: + +=============== ==== ============================================ +Signal Pin Notes +=============== ==== ============================================ +SPI1_NSS PA15 Chip select, driven as a GPIO +SPI1_SCK PB3 +SPI1_MISO PA6 +SPI1_MOSI PA7 +RESET PC0 Active low +DIO0 PB4 Transmit and receive done, EXTI capable +DIO1 PB1 +DIO2 PB0 +DIO3 PC13 +TCXO power PA12 Active high, needs about 5 ms to settle +RX enable PA1 Antenna switch towards RFI_HF +TX RFO enable PC2 Antenna switch towards RFO_HF, up to +14 dBm +TX BOOST enable PC1 Antenna switch towards PA_BOOST +=============== ==== ============================================ + +The board support code powers the TCXO before registering the driver and +picks the antenna switch position from the operating mode and the requested +power: the RFO path is used up to 14 dBm and PA_BOOST above that. This board +is wired for the high frequency band. + +The driver itself, its configuration options and what has to match between +two radios to make them hear each other are documented in :ref:`sx127x`. + +Other peripherals +================= + +========= ================================================ +Interface Pins +========= ================================================ +USART1 PA9 (TX), PA10 (RX), on the Arduino header +SPI2 PB12 (NSS), PB13 (SCK), PB14 (MISO), PB15 (MOSI) +I2C1 PB8 (SCL), PB9 (SDA) +ADC PA0, PA4 and the other Arduino analogue pins +========= ================================================ + +Flashing +======== + +The board can be programmed through its own ST-LINK or through an external +debug probe on the SWD header. + +With the ST-LINK, the simplest route is the mass storage device it exposes; +copying the raw binary to it programs the flash:: + + $ cp nuttx.bin /media//DIS_L072Z/ + +``openocd`` and ``st-flash`` work as well. + +With a SEGGER J-Link on the SWD pins, use a command script:: + + $ cat > flash.jlink << EOF + h + loadbin nuttx.bin, 0x08000000 + r + g + q + EOF + $ JLinkExe -device STM32L072CZ -if SWD -speed 4000 -autoconnect 1 \ + -nogui 1 -CommanderScript flash.jlink + +The virtual COM port of a stand-alone J-Link is not connected to USART2 of +this board, so the console still comes from the ST-LINK USB cable. + +Configurations +============== + +Each configuration is selected with:: + + $ ./tools/configure.sh b-l072z-lrwan1: + $ make + +nsh +--- + +The basic NuttShell configuration over USART2, with the ``hello`` example +built in. A good first check that the board boots. + +adc +--- + +NuttShell plus the ``adc`` example, reading the ADC with software triggered +conversions. + +nxlines_oled +------------ + +Runs the ``nxlines`` graphics example on an SSD1306 OLED display connected to +I2C1 (PB8 and PB9), in one bit per pixel mode. + +sx127x +------ + +NuttShell plus the ``sx127x`` example and the SX1276 driver registered at +``/dev/sx127x``. The example defaults to FSK at 930 MHz; everything can be +overridden from the command line:: + + nsh> sx127x -h + nsh> sx127x -m 0 -f 917200000 -t -p 14 -l 32 # transmit LoRa frames + nsh> sx127x -m 0 -f 917200000 -r # receive them + +lorawan_tx +---------- + +The same interactive setup, but with the radio defaults already matching a +public LoRaWAN network in the 915 MHz band: LoRa modulation, 917.2 MHz, +125 kHz bandwidth, spreading factor 7, CRC enabled and the 0x34 sync word. +Useful to feed a gateway under test:: + + nsh> sx127x -m 0 -f 917200000 -t -p 14 -l 32 -i 5 -d 60 + +lorawan_beacon +-------------- + +The same radio settings without a shell: the example itself is the entry +point and starts transmitting as soon as the board boots, which is what is +needed when the board is driven from a debug probe and no console is wired. +The command line of the example comes from ``CONFIG_INIT_ARGS``, and the +frequency, the payload size and the power from +``CONFIG_EXAMPLES_SX127X_RFFREQ``, ``_TXDATA`` and ``_TXPOWER``. + +Talking to another radio +======================== + +Two of these boards reach each other with the ``lorawan_tx`` configuration, +one receiving and the other transmitting, and the same commands work against +a LoRaWAN gateway. The recipes, and the settings that have to match on both +sides, are in :ref:`sx127x`. + diff --git a/Documentation/platforms/arm/stm32l0/boards/nucleo-l073rz/index.rst b/Documentation/platforms/arm/stm32l0/boards/nucleo-l073rz/index.rst index 6e41b3cba977a..3000df30ae2e8 100644 --- a/Documentation/platforms/arm/stm32l0/boards/nucleo-l073rz/index.rst +++ b/Documentation/platforms/arm/stm32l0/boards/nucleo-l073rz/index.rst @@ -1,3 +1,5 @@ +.. _nucleo-l073rz: + ================ ST Nucleo L073RZ ================ diff --git a/Documentation/platforms/xtensa/esp32/boards/heltec_wifi_lora32/index.rst b/Documentation/platforms/xtensa/esp32/boards/heltec_wifi_lora32/index.rst index b0d3501757fea..48d156ac73162 100644 --- a/Documentation/platforms/xtensa/esp32/boards/heltec_wifi_lora32/index.rst +++ b/Documentation/platforms/xtensa/esp32/boards/heltec_wifi_lora32/index.rst @@ -1,3 +1,5 @@ +.. _heltec_wifi_lora32: + ====================== Heltec WiFi LoRa 32 V2 ====================== diff --git a/arch/arm/src/stm32l0/stm32l0_rcc.c b/arch/arm/src/stm32l0/stm32l0_rcc.c index 79359bb30bf61..ad42b0fb997b4 100644 --- a/arch/arm/src/stm32l0/stm32l0_rcc.c +++ b/arch/arm/src/stm32l0/stm32l0_rcc.c @@ -319,11 +319,13 @@ static inline void rcc_enableapb2(void) regval = getreg32(STM32_RCC_APB2ENR); -#ifdef CONFIG_STM32_SYSCFG - /* SYSCFG clock */ + /* SYSCFG clock. This one is always enabled: the mapping of a pin to an + * EXTI line lives in SYSCFG_EXTICR, so without this clock the mapping + * silently stays at its reset value and any GPIO interrupt on a port + * other than port A never fires. + */ regval |= RCC_APB2ENR_SYSCFGEN; -#endif #ifdef CONFIG_STM32_TIM21 /* TIM21 Timer clock enable */ diff --git a/boards/arm/stm32f7/nucleo-f746zg/configs/lorawan_gw/defconfig b/boards/arm/stm32f7/nucleo-f746zg/configs/lorawan_gw/defconfig new file mode 100644 index 0000000000000..d3b4d844ff0cf --- /dev/null +++ b/boards/arm/stm32f7/nucleo-f746zg/configs/lorawan_gw/defconfig @@ -0,0 +1,85 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_ARCH_FPU is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-f746zg" +CONFIG_ARCH_BOARD_NUCLEO_F746ZG=y +CONFIG_ARCH_CHIP="stm32f7" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F746ZG=y +CONFIG_ARCH_CHIP_STM32F7=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y +CONFIG_ARMV7M_DTCM=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_BOARD_LOOPSPERMSEC=43103 +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_WIRELESS=y +CONFIG_DEBUG_WIRELESS_ERROR=y +CONFIG_DEBUG_WIRELESS_INFO=y +CONFIG_DEBUG_WIRELESS_WARN=y +CONFIG_DEFAULT_TASK_STACKSIZE=4096 +CONFIG_DRIVERS_LPWAN=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_ETH0_PHY_LAN8742A=y +CONFIG_FS_PROCFS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_LINE_MAX=64 +CONFIG_LPWAN_SX1301=y +CONFIG_MM_REGIONS=2 +CONFIG_NET=y +CONFIG_NETDB_DNSCLIENT=y +CONFIG_NETINIT_DHCPC=y +CONFIG_NETINIT_THREAD=y +CONFIG_NETUTILS_DHCPC=y +CONFIG_NET_BROADCAST=y +CONFIG_NET_ETH_PKTSIZE=1500 +CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_LOOPBACK=y +CONFIG_NET_STATISTICS=y +CONFIG_NET_TCP=y +CONFIG_NET_UDP=y +CONFIG_NET_UDP_CHECKSUMS=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_NUCLEO_F746ZG_CONSOLE_VIRTUAL=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=30 +CONFIG_START_MONTH=7 +CONFIG_START_YEAR=2026 +CONFIG_STM32_DTCMEXCLUDE=y +CONFIG_STM32_ETHMAC=y +CONFIG_STM32_PHYADDR=0 +CONFIG_STM32_PHYSR=31 +CONFIG_STM32_PHYSR_100FD=0x0018 +CONFIG_STM32_PHYSR_100HD=0x0008 +CONFIG_STM32_PHYSR_10FD=0x0014 +CONFIG_STM32_PHYSR_10HD=0x0004 +CONFIG_STM32_PHYSR_ALTCONFIG=y +CONFIG_STM32_PHYSR_ALTMODE=0x001c +CONFIG_STM32_SERIALBRK_BSDCOMPAT=y +CONFIG_STM32_SERIAL_DISABLE_REORDERING=y +CONFIG_STM32_SPI4=y +CONFIG_STM32_USART_BREAKS=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_PING=y +CONFIG_TASK_NAME_SIZE=24 +CONFIG_USART3_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32f7/nucleo-f746zg/include/board.h b/boards/arm/stm32f7/nucleo-f746zg/include/board.h index 3d83ffe2f9057..1503c4fdd586e 100644 --- a/boards/arm/stm32f7/nucleo-f746zg/include/board.h +++ b/boards/arm/stm32f7/nucleo-f746zg/include/board.h @@ -483,6 +483,49 @@ #define GPIO_SPI3_MOSI (GPIO_SPI3_MOSI_2|GPIO_SPEED_50MHz) #define GPIO_SPI3_SCK (GPIO_SPI3_SCK_1|GPIO_SPEED_50MHz) +/* SPI4 is wired to the LoRa concentrator of the LRWAN_GS_HF1 class of + * shields, on the Morpho connector: + * + * PE12 SPI4_SCK CN11-49 + * PE13 SPI4_MISO CN11-47 + * PE14 SPI4_MOSI CN11-45 + * PE11 SPI4_CS CN11-53, driven as a plain output + */ + +#define GPIO_SPI4_MISO (GPIO_SPI4_MISO_2|GPIO_SPEED_50MHz) +#define GPIO_SPI4_MOSI (GPIO_SPI4_MOSI_2|GPIO_SPEED_50MHz) +#define GPIO_SPI4_SCK (GPIO_SPI4_SCK_2|GPIO_SPEED_50MHz) + +#define GPIO_SPI4_CS0 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz| \ + GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN11) + +/* SPI5 is wired to the serial NOR flash of the same shields, on CN11: + * + * PF7 SPI5_SCK CN11-11 + * PF8 SPI5_MISO CN11-54 + * PF9 SPI5_MOSI CN11-56 + * PF6 SPI5_CS CN11-9, driven as a plain output + */ + +#define GPIO_SPI5_MISO (GPIO_SPI5_MISO_1|GPIO_SPEED_50MHz) +#define GPIO_SPI5_MOSI (GPIO_SPI5_MOSI_1|GPIO_SPEED_50MHz) +#define GPIO_SPI5_SCK (GPIO_SPI5_SCK_1|GPIO_SPEED_50MHz) + +#define GPIO_SPI5_CS0 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz| \ + GPIO_OUTPUT_SET|GPIO_PORTF|GPIO_PIN6) + +/* LoRa concentrator control lines of the shield. The reset line is active + * high, and the two band selection lines drive the front-end filter bank: + * 915 MHz needs SET1 low and SET2 high, 868 MHz the other way around. + */ + +#define GPIO_SX1301_RESET (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz| \ + GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN15) +#define GPIO_SX1301_BAND1 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz| \ + GPIO_OUTPUT_CLEAR|GPIO_PORTD|GPIO_PIN15) +#define GPIO_SX1301_BAND2 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz| \ + GPIO_OUTPUT_CLEAR|GPIO_PORTE|GPIO_PIN9) + /* I2C * * diff --git a/boards/arm/stm32f7/nucleo-f746zg/src/CMakeLists.txt b/boards/arm/stm32f7/nucleo-f746zg/src/CMakeLists.txt index 1c42f13728819..ffdd18a444b49 100644 --- a/boards/arm/stm32f7/nucleo-f746zg/src/CMakeLists.txt +++ b/boards/arm/stm32f7/nucleo-f746zg/src/CMakeLists.txt @@ -68,6 +68,10 @@ if(CONFIG_USBDEV_COMPOSITE) list(APPEND SRCS stm32_composite.c) endif() +if(CONFIG_LPWAN_SX1301) + list(APPEND SRCS stm32_sx1301.c) +endif() + target_sources(board PRIVATE ${SRCS}) set_property(GLOBAL PROPERTY LD_SCRIPT "${NUTTX_BOARD_DIR}/scripts/flash.ld") diff --git a/boards/arm/stm32f7/nucleo-f746zg/src/Make.defs b/boards/arm/stm32f7/nucleo-f746zg/src/Make.defs index 78a75d54df0c4..50abef59328a7 100644 --- a/boards/arm/stm32f7/nucleo-f746zg/src/Make.defs +++ b/boards/arm/stm32f7/nucleo-f746zg/src/Make.defs @@ -70,6 +70,10 @@ ifeq ($(CONFIG_USBDEV_COMPOSITE),y) CSRCS += stm32_composite.c endif +ifeq ($(CONFIG_LPWAN_SX1301),y) +CSRCS += stm32_sx1301.c +endif + DEPPATH += --dep-path board VPATH += :board CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board diff --git a/boards/arm/stm32f7/nucleo-f746zg/src/nucleo-f746zg.h b/boards/arm/stm32f7/nucleo-f746zg/src/nucleo-f746zg.h index 2a1c8d883b7c6..5b53859c28028 100644 --- a/boards/arm/stm32f7/nucleo-f746zg/src/nucleo-f746zg.h +++ b/boards/arm/stm32f7/nucleo-f746zg/src/nucleo-f746zg.h @@ -329,4 +329,17 @@ int stm32_gpio_initialize(void); #endif #endif /* __ASSEMBLY__ */ +/**************************************************************************** + * Name: stm32_sx1301_initialize + * + * Description: + * Initialise SPI4 and register the SX1301 LoRa concentrator driver at + * 'devpath'. + * + ****************************************************************************/ + +#ifdef CONFIG_LPWAN_SX1301 +int stm32_sx1301_initialize(FAR const char *devpath); +#endif + #endif /* __BOARDS_ARM_STM32F7_NUCLEO_F746ZG_SRC_NUCLEO_F746ZG_H */ diff --git a/boards/arm/stm32f7/nucleo-f746zg/src/stm32_bringup.c b/boards/arm/stm32f7/nucleo-f746zg/src/stm32_bringup.c index f7cc0a58d8154..15e119321c8ea 100644 --- a/boards/arm/stm32f7/nucleo-f746zg/src/stm32_bringup.c +++ b/boards/arm/stm32f7/nucleo-f746zg/src/stm32_bringup.c @@ -56,6 +56,10 @@ # include "stm32_spitest.h" #endif +#ifdef CONFIG_LPWAN_SX1301 +# include +#endif + #ifdef CONFIG_SYSTEMTICK_HOOK # include #endif @@ -290,6 +294,16 @@ int stm32_bringup(void) #endif UNUSED(ret); +#ifdef CONFIG_LPWAN_SX1301 + /* Register the LoRa concentrator of the gateway shield */ + + ret = stm32_sx1301_initialize("/dev/lora0"); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_sx1301_initialize failed: %d\n", ret); + } +#endif + return OK; } diff --git a/boards/arm/stm32f7/nucleo-f746zg/src/stm32_spi.c b/boards/arm/stm32f7/nucleo-f746zg/src/stm32_spi.c index 417e00c2ae1d3..299b49f39dc0a 100644 --- a/boards/arm/stm32f7/nucleo-f746zg/src/stm32_spi.c +++ b/boards/arm/stm32f7/nucleo-f746zg/src/stm32_spi.c @@ -131,6 +131,58 @@ static const uint32_t g_spi3gpio[] = }; #endif +#if defined(CONFIG_STM32_SPI4) +static const uint32_t g_spi4gpio[] = +{ +# if defined(GPIO_SPI4_CS0) + GPIO_SPI4_CS0, +# else + 0, +# endif +# if defined(GPIO_SPI4_CS1) + GPIO_SPI4_CS1, +# else + 0, +# endif +# if defined(GPIO_SPI4_CS2) + GPIO_SPI4_CS2, +# else + 0, +# endif +# if defined(GPIO_SPI4_CS3) + GPIO_SPI4_CS3 +# else + 0 +# endif +}; +#endif + +#if defined(CONFIG_STM32_SPI5) +static const uint32_t g_spi5gpio[] = +{ +# if defined(GPIO_SPI5_CS0) + GPIO_SPI5_CS0, +# else + 0, +# endif +# if defined(GPIO_SPI5_CS1) + GPIO_SPI5_CS1, +# else + 0, +# endif +# if defined(GPIO_SPI5_CS2) + GPIO_SPI5_CS2, +# else + 0, +# endif +# if defined(GPIO_SPI5_CS3) + GPIO_SPI5_CS3 +# else + 0 +# endif +}; +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -177,6 +229,26 @@ void weak_function stm32_spidev_initialize(void) } } #endif + +#if defined(CONFIG_STM32_SPI4) + for (int i = 0; i < nitems(g_spi4gpio); i++) + { + if (g_spi4gpio[i] != 0) + { + stm32_configgpio(g_spi4gpio[i]); + } + } +#endif + +#if defined(CONFIG_STM32_SPI5) + for (int i = 0; i < nitems(g_spi5gpio); i++) + { + if (g_spi5gpio[i] != 0) + { + stm32_configgpio(g_spi5gpio[i]); + } + } +#endif } /**************************************************************************** @@ -273,8 +345,17 @@ uint8_t stm32_spi3status(struct spi_dev_s *dev, uint32_t devid) void stm32_spi4select(struct spi_dev_s *dev, uint32_t devid, bool selected) { + uint32_t index = SPIDEVID_INDEX(devid); + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); + + /* The chip select of the LoRa concentrator is a plain output, active low */ + + if (index < nitems(g_spi4gpio) && g_spi4gpio[index] != 0) + { + stm32_gpiowrite(g_spi4gpio[index], !selected); + } } uint8_t stm32_spi4status(struct spi_dev_s *dev, uint32_t devid) @@ -287,8 +368,17 @@ uint8_t stm32_spi4status(struct spi_dev_s *dev, uint32_t devid) void stm32_spi5select(struct spi_dev_s *dev, uint32_t devid, bool selected) { + uint32_t index = SPIDEVID_INDEX(devid); + spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); + + /* The chip select of the serial NOR flash is a plain output, active low */ + + if (index < nitems(g_spi5gpio) && g_spi5gpio[index] != 0) + { + stm32_gpiowrite(g_spi5gpio[index], !selected); + } } uint8_t stm32_spi5status(struct spi_dev_s *dev, uint32_t devid) diff --git a/boards/arm/stm32f7/nucleo-f746zg/src/stm32_sx1301.c b/boards/arm/stm32f7/nucleo-f746zg/src/stm32_sx1301.c new file mode 100644 index 0000000000000..16e600cc6f764 --- /dev/null +++ b/boards/arm/stm32f7/nucleo-f746zg/src/stm32_sx1301.c @@ -0,0 +1,167 @@ +/**************************************************************************** + * boards/arm/stm32f7/nucleo-f746zg/src/stm32_sx1301.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Support for a LoRa concentrator shield of the LRWAN_GS_HF1 family (for + * instance the RisingHF RHF0M301, an SX1301 with two SX1257 front-ends) on + * SPI4 of the Morpho connector. See include/board.h for the pin map. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include + +#include "stm32_gpio.h" +#include "stm32_spi.h" +#include "nucleo-f746zg.h" + +#ifdef CONFIG_LPWAN_SX1301 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SX1301_SPI_BUS 4 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void stm32_sx1301_reset(FAR const struct sx1301_lower_s *lower, + bool assert); +static void stm32_sx1301_band(FAR const struct sx1301_lower_s *lower, + int band_mhz); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct sx1301_lower_s g_sx1301_lower = +{ + .reset = stm32_sx1301_reset, + .band_select = stm32_sx1301_band +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_sx1301_reset + * + * Description: + * Drive the reset line of the concentrator, which is active high. + * + ****************************************************************************/ + +static void stm32_sx1301_reset(FAR const struct sx1301_lower_s *lower, + bool assert) +{ + UNUSED(lower); + + stm32_gpiowrite(GPIO_SX1301_RESET, assert); +} + +/**************************************************************************** + * Name: stm32_sx1301_band + * + * Description: + * Select the band of the front-end filter bank of the shield. + * + ****************************************************************************/ + +static void stm32_sx1301_band(FAR const struct sx1301_lower_s *lower, + int band_mhz) +{ + UNUSED(lower); + + if (band_mhz >= 900) + { + stm32_gpiowrite(GPIO_SX1301_BAND1, false); + stm32_gpiowrite(GPIO_SX1301_BAND2, true); + } + else + { + stm32_gpiowrite(GPIO_SX1301_BAND1, true); + stm32_gpiowrite(GPIO_SX1301_BAND2, false); + } + + ninfo("Band set to %d MHz\n", band_mhz); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_sx1301_initialize + * + * Description: + * Initialise SPI4 and register the concentrator driver. + * + ****************************************************************************/ + +int stm32_sx1301_initialize(FAR const char *devpath) +{ + FAR struct spi_dev_s *spi; + int ret; + + /* Control lines first, so that the chip stays in reset until it is + * started. + */ + + stm32_configgpio(GPIO_SX1301_RESET); + stm32_configgpio(GPIO_SX1301_BAND1); + stm32_configgpio(GPIO_SX1301_BAND2); + + stm32_gpiowrite(GPIO_SX1301_RESET, true); + + spi = stm32_spibus_initialize(SX1301_SPI_BUS); + if (spi == NULL) + { + syslog(LOG_ERR, "ERROR: cannot initialise SPI port %d\n", + SX1301_SPI_BUS); + return -ENODEV; + } + + ret = sx1301_register(devpath, spi, &g_sx1301_lower); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: cannot register the concentrator: %d\n", ret); + return ret; + } + + syslog(LOG_INFO, "SX1301 concentrator at %s, SPI%d\n", devpath, + SX1301_SPI_BUS); + return OK; +} + +#endif /* CONFIG_LPWAN_SX1301 */ diff --git a/boards/arm/stm32l0/b-l072z-lrwan1/configs/lorawan_beacon/defconfig b/boards/arm/stm32l0/b-l072z-lrwan1/configs/lorawan_beacon/defconfig new file mode 100644 index 0000000000000..01c5b0231e2a5 --- /dev/null +++ b/boards/arm/stm32l0/b-l072z-lrwan1/configs/lorawan_beacon/defconfig @@ -0,0 +1,72 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_ARGCAT is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="b-l072z-lrwan1" +CONFIG_ARCH_BOARD_B_L072Z_LRWAN1=y +CONFIG_ARCH_CHIP="stm32l0" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32L072CZ=y +CONFIG_ARCH_CHIP_STM32L072XX=y +CONFIG_ARCH_CHIP_STM32L0=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=2796 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_WIRELESS=y +CONFIG_DEBUG_WIRELESS_ERROR=y +CONFIG_DEBUG_WIRELESS_INFO=y +CONFIG_DEBUG_WIRELESS_WARN=y +CONFIG_DISABLE_ENVIRON=y +CONFIG_DISABLE_MOUNTPOINT=y +CONFIG_DISABLE_MQUEUE=y +CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DISABLE_PSEUDOFS_OPERATIONS=y +CONFIG_DRIVERS_LPWAN=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_SX127X=y +CONFIG_EXAMPLES_SX127X_RFFREQ=917200000 +CONFIG_EXAMPLES_SX127X_TXDATA=32 +CONFIG_EXAMPLES_SX127X_TXPOWER=17 +CONFIG_INIT_ARGS="\"-m\", \"0\", \"-t\", \"-d\", \"0\"" +CONFIG_INIT_ENTRYPOINT="sx127x_main" +CONFIG_INIT_STACKSIZE=1536 +CONFIG_INTELHEX_BINARY=y +CONFIG_LINE_MAX=64 +CONFIG_LPWAN_SX127X=y +CONFIG_LPWAN_SX127X_LORA_BW_DEFAULT=7 +CONFIG_LPWAN_SX127X_LORA_SYNCWORD=0x34 +CONFIG_LPWAN_SX127X_RFFREQ_DEFAULT=917200000 +CONFIG_LPWAN_SX127X_RXSUPPORT=y +CONFIG_LPWAN_SX127X_TXSUPPORT=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=64 +CONFIG_NSH_MAXARGUMENTS=12 +CONFIG_NSH_READLINE=y +CONFIG_NUNGET_CHARS=0 +CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=1536 +CONFIG_PTHREAD_MUTEX_UNSAFE=y +CONFIG_PTHREAD_STACK_DEFAULT=1536 +CONFIG_RAM_SIZE=20480 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=19 +CONFIG_START_MONTH=5 +CONFIG_START_YEAR=2013 +CONFIG_STDIO_DISABLE_BUFFERING=y +CONFIG_STM32_PWR=y +CONFIG_STM32_SPI1=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32l0/b-l072z-lrwan1/configs/lorawan_tx/defconfig b/boards/arm/stm32l0/b-l072z-lrwan1/configs/lorawan_tx/defconfig new file mode 100644 index 0000000000000..e6cedc1f76dbe --- /dev/null +++ b/boards/arm/stm32l0/b-l072z-lrwan1/configs/lorawan_tx/defconfig @@ -0,0 +1,64 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_ARGCAT is not set +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="b-l072z-lrwan1" +CONFIG_ARCH_BOARD_B_L072Z_LRWAN1=y +CONFIG_ARCH_CHIP="stm32l0" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32L072CZ=y +CONFIG_ARCH_CHIP_STM32L072XX=y +CONFIG_ARCH_CHIP_STM32L0=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=2796 +CONFIG_BUILTIN=y +CONFIG_DISABLE_ENVIRON=y +CONFIG_DISABLE_MOUNTPOINT=y +CONFIG_DISABLE_MQUEUE=y +CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DISABLE_PSEUDOFS_OPERATIONS=y +CONFIG_DRIVERS_LPWAN=y +CONFIG_DRIVERS_WIRELESS=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_SX127X=y +CONFIG_EXAMPLES_SX127X_RFFREQ=917200000 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=1536 +CONFIG_INTELHEX_BINARY=y +CONFIG_LINE_MAX=64 +CONFIG_LPWAN_SX127X=y +CONFIG_LPWAN_SX127X_LORA_BW_DEFAULT=7 +CONFIG_LPWAN_SX127X_LORA_SYNCWORD=0x34 +CONFIG_LPWAN_SX127X_RFFREQ_DEFAULT=917200000 +CONFIG_LPWAN_SX127X_RXSUPPORT=y +CONFIG_LPWAN_SX127X_TXSUPPORT=y +CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=64 +CONFIG_NSH_MAXARGUMENTS=12 +CONFIG_NSH_READLINE=y +CONFIG_NUNGET_CHARS=0 +CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=1536 +CONFIG_PTHREAD_MUTEX_UNSAFE=y +CONFIG_PTHREAD_STACK_DEFAULT=1536 +CONFIG_RAM_SIZE=20480 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_START_DAY=19 +CONFIG_START_MONTH=5 +CONFIG_START_YEAR=2013 +CONFIG_STDIO_DISABLE_BUFFERING=y +CONFIG_STM32_PWR=y +CONFIG_STM32_SPI1=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/boards/arm/stm32l0/b-l072z-lrwan1/src/b-l072z-lrwan1.h b/boards/arm/stm32l0/b-l072z-lrwan1/src/b-l072z-lrwan1.h index dfbc614c32214..3ee53c2c26105 100644 --- a/boards/arm/stm32l0/b-l072z-lrwan1/src/b-l072z-lrwan1.h +++ b/boards/arm/stm32l0/b-l072z-lrwan1/src/b-l072z-lrwan1.h @@ -65,21 +65,20 @@ /* Button definitions *******************************************************/ -/* The Nucleo L073RZ supports two buttons; only one button is controllable - * by software: +/* The board has two buttons, only one of which is controllable by software: * - * B1 USER: user button connected to the I/O PC13 of the STM32L073RZT6. - * B2 RESET: push button connected to NRST is used to RESET the - * STM32L073RZT6. + * B1 USER: user button connected to PB2, pulled up, active low. + * B2 RESET: push button connected to NRST. * - * NOTE that EXTI interrupts are configured. + * NOTE that EXTI interrupts are configured. PC13 is not a button here: on + * this board it carries DIO3 of the radio. */ #define MIN_IRQBUTTON BUTTON_USER #define MAX_IRQBUTTON BUTTON_USER #define NUM_IRQBUTTONS 1 -#define GPIO_BTN_USER (GPIO_INPUT|GPIO_FLOAT|GPIO_EXTI|GPIO_PORTC|GPIO_PIN13) +#define GPIO_BTN_USER (GPIO_INPUT|GPIO_PULLUP|GPIO_EXTI|GPIO_PORTB|GPIO_PIN2) /* SX1276 * RESET - PC0 (active low) @@ -103,6 +102,13 @@ #define GPIO_SX127X_CRF2 (GPIO_SPEED_HIGH | GPIO_PORTC | GPIO_PIN2) #define GPIO_SX127X_CRF3 (GPIO_SPEED_HIGH | GPIO_PORTC | GPIO_PIN1) +/* The 32 MHz TCXO of the module is powered from PA12. The radio has no + * clock at all until this is driven high. + */ + +#define GPIO_SX127X_TCXO (GPIO_OUTPUT | GPIO_SPEED_HIGH | \ + GPIO_OUTPUT_SET | GPIO_PORTA | GPIO_PIN12) + /* Oled configuration */ #define OLED_I2C_PORT 1 diff --git a/boards/arm/stm32l0/b-l072z-lrwan1/src/stm32_sx127x.c b/boards/arm/stm32l0/b-l072z-lrwan1/src/stm32_sx127x.c index e6ffc4681397d..b2b1dce81da30 100644 --- a/boards/arm/stm32l0/b-l072z-lrwan1/src/stm32_sx127x.c +++ b/boards/arm/stm32l0/b-l072z-lrwan1/src/stm32_sx127x.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -249,6 +250,12 @@ int stm32_lpwaninitialize(void) wlinfo("Register the sx127x module\n"); + /* Power the TCXO that clocks the radio, and give it time to settle */ + + stm32_configgpio(GPIO_SX127X_TCXO); + stm32_gpiowrite(GPIO_SX127X_TCXO, true); + up_mdelay(10); + /* Setup DIO0 */ stm32_configgpio(GPIO_SX127X_DIO0); diff --git a/drivers/wireless/lpwan/Kconfig b/drivers/wireless/lpwan/Kconfig index 0b3a9fc4379e5..1b3590528713d 100644 --- a/drivers/wireless/lpwan/Kconfig +++ b/drivers/wireless/lpwan/Kconfig @@ -5,6 +5,15 @@ if DRIVERS_LPWAN +config LPWAN_LORA_GW + bool + default n + ---help--- + Selected by the driver of a LoRa gateway, that is, of a concentrator + registering the character device described by + include/nuttx/wireless/lpwan/lora_gw.h. An application driving a + gateway depends on this symbol rather than on one particular chip. + config LPWAN_RN2XX3 bool "Microchip RN2xx3 driver support" default n @@ -30,4 +39,17 @@ config LPWAN_SX127X source "drivers/wireless/lpwan/sx127x/Kconfig" +config LPWAN_SX1301 + bool "SX1301 LoRa concentrator (gateway) support" + default n + select SPI + select LPWAN_LORA_GW + ---help--- + This option adds driver support for the Semtech SX1301 LoRa + concentrator, the baseband processor of a LoRaWAN gateway, together + with its two SX125x radio front-ends. Registers a character device + delivering received packets and accepting downlinks. + +source "drivers/wireless/lpwan/sx1301/Kconfig" + endif # DRIVERS_LPWAN diff --git a/drivers/wireless/lpwan/Make.defs b/drivers/wireless/lpwan/Make.defs index a6998793e5c8e..fe58d5b0e0776 100644 --- a/drivers/wireless/lpwan/Make.defs +++ b/drivers/wireless/lpwan/Make.defs @@ -27,5 +27,6 @@ ifeq ($(CONFIG_DRIVERS_LPWAN),y) include wireless/lpwan/sx127x/Make.defs include wireless/lpwan/sx126x/Make.defs include wireless/lpwan/rn2xx3/Make.defs +include wireless/lpwan/sx1301/Make.defs endif # CONFIG_DRIVERS_LPWAN diff --git a/drivers/wireless/lpwan/sx127x/Kconfig b/drivers/wireless/lpwan/sx127x/Kconfig index 2af745e6d427e..51fe87af31412 100644 --- a/drivers/wireless/lpwan/sx127x/Kconfig +++ b/drivers/wireless/lpwan/sx127x/Kconfig @@ -79,6 +79,29 @@ config LPWAN_SX127X_LORA_IMPHEADER range 0 1 default 0 +config LPWAN_SX127X_LORA_SYNCWORD + hex "SX127X LORA sync word" + default 0x12 + ---help--- + Sync word written to the modem: 0x12 for a private network, 0x34 + for the public LoRaWAN network. A gateway configured for the + public network does not even detect a frame sent with the private + sync word, so this has to match the other end. + +config LPWAN_SX127X_LORA_BW_DEFAULT + int "SX127X LORA default bandwidth" + default 0 + range 0 9 + ---help--- + Bandwidth used until it is changed: 0 = 7.8 kHz, 1 = 10.4 kHz, + 2 = 15.6 kHz, 3 = 20.8 kHz, 4 = 31.2 kHz, 5 = 41.4 kHz, + 6 = 62.5 kHz, 7 = 125 kHz, 9 = 250 kHz. LoRaWAN uses 125 kHz. + +config LPWAN_SX127X_LORA_SF_DEFAULT + int "SX127X LORA default spreading factor" + default 7 + range 6 12 + endif # LPWAN_SX127X_LORA config LPWAN_SX127X_FSKOOK diff --git a/drivers/wireless/lpwan/sx127x/sx127x.c b/drivers/wireless/lpwan/sx127x/sx127x.c index 8b3f334a60e95..6aba75ddd81a3 100644 --- a/drivers/wireless/lpwan/sx127x/sx127x.c +++ b/drivers/wireless/lpwan/sx127x/sx127x.c @@ -130,11 +130,11 @@ /* Default LORA bandwidth */ -#define SX127X_LRM_BW_DEFAULT LORA_BANDWIDTH_7P8KHZ +#define SX127X_LRM_BW_DEFAULT CONFIG_LPWAN_SX127X_LORA_BW_DEFAULT /* Default SF for LORA */ -#define SX127X_LRM_SF_DEFAULT (7) +#define SX127X_LRM_SF_DEFAULT CONFIG_LPWAN_SX127X_LORA_SF_DEFAULT /* FSK/OOK RX/TX FIFO size (two separate FIFOs) */ @@ -1286,7 +1286,12 @@ static int sx127x_poll(FAR struct file *filep, FAR struct pollfd *fds, * ****************************************************************************/ +/* The stall watchdog is only wired into the FSK and OOK receive path, so a + * configuration with LoRa alone must not compile it. + */ + #if defined(CONFIG_LPWAN_SX127X_RXSUPPORT) && \ + defined(CONFIG_LPWAN_SX127X_FSKOOK) && \ CONFIG_LPWAN_SX127X_RX_TIMEOUT > 0 static void sx127x_rx_watchdog(FAR void *arg) { @@ -1321,7 +1326,7 @@ static void sx127x_rx_watchdog(FAR void *arg) sx127x_rx_watchdog, dev, MSEC2TICK(dev->rx_timeout)); } -#endif /* CONFIG_LPWAN_SX127X_RXSUPPORT && CONFIG_LPWAN_SX127X_RX_TIMEOUT > 0 */ +#endif /* RXSUPPORT && FSKOOK && RX_TIMEOUT > 0 */ /**************************************************************************** * Name: sx127x_lora_isr0_process @@ -3875,6 +3880,22 @@ static int sx127x_frequency_set(FAR struct sx127x_dev_s *dev, uint32_t freq) sx127x_writeregbyte(dev, SX127X_CMN_FRFLSB, SX127X_CMN_FRF_LSB(frf)); + /* Tell the modem which of the two front ends the frequency belongs to. + * The chip comes up in low frequency mode, and a board wired for the high + * band (868 or 915 MHz) then neither transmits nor receives anything. + */ + + if (freq > SX127X_HFBAND_THR) + { + sx127x_modregbyte(dev, SX127X_CMN_OPMODE, 0, + SX127X_CMN_OPMODE_LFMODEON); + } + else + { + sx127x_modregbyte(dev, SX127X_CMN_OPMODE, + SX127X_CMN_OPMODE_LFMODEON, 0); + } + /* Unlock SPI */ sx127x_unlock(dev->spi); diff --git a/drivers/wireless/lpwan/sx127x/sx127x.h b/drivers/wireless/lpwan/sx127x/sx127x.h index 7e2fb3d2ba6c4..ecde2a5001016 100644 --- a/drivers/wireless/lpwan/sx127x/sx127x.h +++ b/drivers/wireless/lpwan/sx127x/sx127x.h @@ -181,7 +181,8 @@ /* FSK/OOK/LORA: RF carrier frequency */ #define SX127X_CMN_FRF_MAX (0xffffff) -#define SX127X_FRF_FROM_FREQ(freq) (freq/SX127X_FSTEP) +#define SX127X_FRF_FROM_FREQ(freq) \ + ((uint32_t)(((uint64_t)(freq) << SX127X_FSTEP_SHIFT) / SX127X_FXOSC)) #define SX127X_CMN_FRF_MSB(frf) ((frf >> 16) & 0xff) #define SX127X_CMN_FRF_MID(frf) ((frf >> 8) & 0xff) #define SX127X_CMN_FRF_LSB(frf) ((frf >> 0) & 0xff) @@ -337,7 +338,8 @@ #define SX127X_FOM_FDEV_MSB_MASK (0x3f) #define SX127X_FOM_FDEV_MAX (0x3fff) -#define SX127X_FDEV_FROM_FREQ(freq) (freq/SX127X_FSTEP) +#define SX127X_FDEV_FROM_FREQ(freq) \ + ((uint32_t)(((uint64_t)(freq) << SX127X_FSTEP_SHIFT) / SX127X_FXOSC)) #define SX127X_FOM_FDEV_MSB(v) ((v >> 8) & 0xff) #define SX127X_FOM_FDEV_LSB(v) ((v >> 0) & 0xff) @@ -790,7 +792,7 @@ /* LORA: LORA Sync Word */ -#define SX127X_LRM_SYNCWORD_DEFAULT (0x12) +#define SX127X_LRM_SYNCWORD_DEFAULT CONFIG_LPWAN_SX127X_LORA_SYNCWORD #define SX127X_LRM_SYNCWORD_LORAWAN (0x34) /* Lora data rate: @@ -810,9 +812,14 @@ #define SX127X_FXOSC (32000000) -/* FSTEP is FXOSC/(2**19) =~ 61 Hz */ +/* One step of the frequency synthesiser is FXOSC/(2**19), about 61.035 Hz. + * It is not an integer, so the conversions below multiply first and divide + * afterwards instead of dividing by a truncated step: rounding it down to + * 61 Hz places a 915 MHz channel more than 500 kHz away from the requested + * frequency, well outside the bandwidth of the channel. + */ -#define SX127X_FSTEP (SX127X_FXOSC/(2<<18)) +#define SX127X_FSTEP_SHIFT (19) /**************************************************************************** * Public Data Types diff --git a/drivers/wireless/lpwan/sx1301/CMakeLists.txt b/drivers/wireless/lpwan/sx1301/CMakeLists.txt new file mode 100644 index 0000000000000..961afdd3a8522 --- /dev/null +++ b/drivers/wireless/lpwan/sx1301/CMakeLists.txt @@ -0,0 +1,26 @@ +# ############################################################################## +# drivers/wireless/lpwan/sx1301/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## +if(CONFIG_LPWAN_SX1301) + target_sources(drivers PRIVATE sx1301.c sx1301_reg.c sx1301_region.c + sx1301_fw.c) + target_include_directories(drivers PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +endif() diff --git a/drivers/wireless/lpwan/sx1301/Kconfig b/drivers/wireless/lpwan/sx1301/Kconfig new file mode 100644 index 0000000000000..95ab698f07e1a --- /dev/null +++ b/drivers/wireless/lpwan/sx1301/Kconfig @@ -0,0 +1,57 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if LPWAN_SX1301 + +config LPWAN_SX1301_SPIFREQ + int "SX1301 SPI frequency" + default 8000000 + ---help--- + SPI clock frequency used to talk to the concentrator. The SX1301 + accepts up to 10 MHz. + +config LPWAN_SX1301_DEFAULT_REGION + string "Default channel plan" + default "AU915" + ---help--- + Channel plan selected when the driver is registered. One of AU915, + AU915-1, US915, US915-1, EU868, AS923, KR920 or IN866, and it can be + changed at runtime with WLIOC_GW_SETREGION. + + AU915 and US915 default to the second sub-band (channels 8 to 15 plus + the 500 kHz channel 65), which is what The Things Network and the + Brazilian deployments use. The "-1" variants select the first + sub-band (channels 0 to 7 plus channel 64). + +config LPWAN_SX1301_PRIVATE_NETWORK + bool "Private network sync word" + default n + ---help--- + Use the sync word of a private LoRa network (frame synchronisation + peaks at 1 and 2, matching 0x12 on an SX127x) instead of the public + LoRaWAN one (peaks at 3 and 4, matching 0x34). A gateway that does + not match the end devices never detects a frame. + +config LPWAN_SX1301_RXBADCRC + bool "Report packets with a bad CRC" + default n + ---help--- + By default a packet whose CRC failed is counted and dropped, since + most of them are correlator false triggers and a gateway must not + forward them to the network server. Enable this to have them + returned by read() with status LORA_GW_STAT_CRC_BAD, which is useful + when debugging the receive chain. + +config LPWAN_SX1301_RXNOCRC + bool "Report packets received without CRC" + default n + ---help--- + A LoRaWAN uplink always carries a CRC, so a packet arriving without + one is either a correlator false trigger or the downlink of another + gateway nearby. Both are counted and dropped by default, as the + reference packet forwarder does. Enable this to have them returned + by read() with status LORA_GW_STAT_NO_CRC. + +endif # LPWAN_SX1301 diff --git a/drivers/wireless/lpwan/sx1301/Make.defs b/drivers/wireless/lpwan/sx1301/Make.defs new file mode 100644 index 0000000000000..4b39ed204a9e6 --- /dev/null +++ b/drivers/wireless/lpwan/sx1301/Make.defs @@ -0,0 +1,35 @@ +############################################################################ +# drivers/wireless/lpwan/sx1301/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +# Include SX1301 concentrator driver into the build + +ifeq ($(CONFIG_LPWAN_SX1301),y) + +CSRCS += sx1301.c sx1301_reg.c sx1301_region.c sx1301_fw.c + +# Include SX1301 build support + +DEPPATH += --dep-path wireless$(DELIM)lpwan$(DELIM)sx1301 +VPATH += :wireless$(DELIM)lpwan$(DELIM)sx1301 +CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)drivers$(DELIM)wireless$(DELIM)lpwan$(DELIM)sx1301 + +endif # CONFIG_LPWAN_SX1301 diff --git a/drivers/wireless/lpwan/sx1301/sx1301.c b/drivers/wireless/lpwan/sx1301/sx1301.c new file mode 100644 index 0000000000000..b6cb39461feb9 --- /dev/null +++ b/drivers/wireless/lpwan/sx1301/sx1301.c @@ -0,0 +1,1772 @@ +/**************************************************************************** + * drivers/wireless/lpwan/sx1301/sx1301.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Character driver for the Semtech SX1301 LoRa concentrator. + * + * The chip has no register level documentation in the public datasheet: the + * start-up sequence below follows the Semtech reference HAL (lora_gateway, + * libloragw) step by step, including the parts that look redundant. The + * order matters and several of the writes have been verified on hardware: + * + * - the modems must be enabled *before* the MCU firmwares are loaded; + * - the calibration firmware has to run for about 2.3 s in the AGC MCU + * before the production firmware is loaded; + * - register 0x6a is written with the PROM multiplexers explicitly set, + * never with a read-modify-write, and the MCUs are released with 0x0c + * (not 0x00) so that they keep access to their program memory; + * - TX_SWAP_IQ (bit 7 of page 1 register 0x2a) must be set or downlinks + * silently fail. + * + * Interface: + * + * read() returns whole multiples of struct lora_gw_rxpkt_s, blocking + * until at least one packet is available unless O_NONBLOCK is set. + * write() takes exactly one struct lora_gw_txpkt_s. + * ioctl() see include/nuttx/wireless/lpwan/lora_gw.h + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sx1301_fw.h" +#include "sx1301_priv.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Multi-SF correlator mask: bit 0 is SF6 ... bit 6 is SF12, so 0x7e enables + * SF7 to SF12. Without this the demodulators never detect a preamble. + */ + +#define SX1301_CORR_SF7_SF12 0x7e + +/* Frame synchronisation words, as peak positions. The chip powers up for a + * private network (1 and 2); the public LoRaWAN network uses 3 and 4, which + * is what the 0x34 sync word of an end device maps to. Getting this wrong + * costs nothing visible: the demodulators simply never detect a frame. + */ + +#define SX1301_SYNCH_PRIVATE (1 | (2 << 4)) +#define SX1301_SYNCH_PUBLIC (3 | (4 << 4)) + +#ifdef CONFIG_LPWAN_SX1301_PRIVATE_NETWORK +# define SX1301_SYNCH_WORD SX1301_SYNCH_PRIVATE +#else +# define SX1301_SYNCH_WORD SX1301_SYNCH_PUBLIC +#endif + +/* Bits of the modem enable register (0x10) */ + +#define SX1301_EN_MBWSSF (1 << 0) +#define SX1301_EN_CONCENTRATOR (1 << 1) +#define SX1301_EN_FSK (1 << 2) +#define SX1301_EN_GLOBAL (1 << 3) + +/* Bits of the MCU control register (0x6a) */ + +#define SX1301_MCU_RST_ARB (1 << 0) +#define SX1301_MCU_RST_AGC (1 << 1) +#define SX1301_MCU_MUX_ARB (1 << 2) +#define SX1301_MCU_MUX_AGC (1 << 3) + +/* AGC MCU command channel. Commands are written to RADIO_SELECT, each one + * preceded by CMD_WAIT, and the progress is read back from AGC_STATUS. + */ + +#define SX1301_AGC_CMD_WAIT 16 +#define SX1301_AGC_STATUS_READY 0x10 +#define SX1301_AGC_STATUS_DONE 0x40 +#define SX1301_CAL_STATUS_OK 0x81 + +/* Number of entries of the transmit gain look-up table. With a full table + * the AGC advances on its own and must not receive CMD_ABORT. + */ + +#define SX1301_TX_LUT_SIZE 16 + +/* Default transmit start delay, in microseconds, and the correction applied + * for a 125 kHz channel (1.5 us in the reference HAL). + */ + +#define SX1301_TX_START_DELAY 1497 +#define SX1301_TX_START_DLY_125 1495 + +/* Payload plus metadata of one packet in the receive FIFO */ + +#define SX1301_RXBUF_SIZE (LORA_GW_MAX_PAYLOAD + \ + SX1301_RX_METADATA_NB) + +/* The five byte FIFO header read from register 0x0b */ + +#define SX1301_FIFO_HDR_SIZE 5 + +/* Reduced spreading factor mode, needed by the timestamp correction */ + +#define SX1301_PPM_ON(bw, sf) \ + ((((bw) == LORA_GW_BW_125K) && ((sf) == 11 || (sf) == 12)) || \ + (((bw) == LORA_GW_BW_250K) && ((sf) == 12))) + +/* The bridge that reaches the SX125x radios needs time to shift the byte in + * and out after the chip select pulse. The reference HAL gets this for free + * from the cost of a Linux spidev transaction; here the register writes are + * fast enough that the read back register has to be given a moment, or it + * always reads as zero. + */ + +#define SX1301_BRIDGE_DELAY_US 20 + +/* Interval used to poll the receive FIFO of a blocking read(). The SX1301 + * has no usable interrupt line on the reference shields. + */ + +#define SX1301_RXPOLL_USEC 10000 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int sx1301_open(FAR struct file *filep); +static int sx1301_close(FAR struct file *filep); +static ssize_t sx1301_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t sx1301_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static int sx1301_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_sx1301_fops = +{ + sx1301_open, /* open */ + sx1301_close, /* close */ + sx1301_read, /* read */ + sx1301_write, /* write */ + NULL, /* seek */ + sx1301_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + NULL /* poll */ +}; + +/* Transmit gain look-up table of the RisingHF RHF0M301 reference design. + * Each entry is mix_gain + 16 * dac_gain + 64 * pa_gain, and g_sx1301_tx_pwr + * gives the antenna power each entry is calibrated for. + */ + +static const uint8_t g_sx1301_tx_lut[SX1301_TX_LUT_SIZE] = +{ + 8 + (16 * 3) + (64 * 0), /* -6 dBm */ + 10 + (16 * 3) + (64 * 0), /* -3 dBm */ + 12 + (16 * 3) + (64 * 0), /* 0 dBm */ + 8 + (16 * 3) + (64 * 1), /* 3 dBm */ + 10 + (16 * 3) + (64 * 1), /* 6 dBm */ + 12 + (16 * 3) + (64 * 1), /* 10 dBm */ + 13 + (16 * 3) + (64 * 1), /* 11 dBm */ + 9 + (16 * 3) + (64 * 2), /* 12 dBm */ + 15 + (16 * 3) + (64 * 1), /* 13 dBm */ + 10 + (16 * 3) + (64 * 2), /* 14 dBm */ + 11 + (16 * 3) + (64 * 2), /* 16 dBm */ + 9 + (16 * 3) + (64 * 3), /* 20 dBm */ + 10 + (16 * 3) + (64 * 3), /* 24 dBm */ + 11 + (16 * 3) + (64 * 3), /* 25 dBm */ + 12 + (16 * 3) + (64 * 3), /* 26 dBm */ + 14 + (16 * 3) + (64 * 3) /* 27 dBm */ +}; + +static const int8_t g_sx1301_tx_pwr[SX1301_TX_LUT_SIZE] = +{ + -6, -3, 0, 3, 6, 10, 11, 12, 13, 14, 16, 20, 24, 25, 26, 27 +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sx1301_msleep + ****************************************************************************/ + +static void sx1301_msleep(unsigned int msec) +{ + nxsig_usleep(msec * 1000); +} + +/**************************************************************************** + * Name: sx1301_radio_write + * + * Description: + * Write an SX125x radio register through the SPI bridge of the SX1301. + * The radios are not on the host SPI bus: the concentrator drives them + * from page 2 registers, one byte at a time, with an explicit chip select + * pulse. + * + ****************************************************************************/ + +static void sx1301_radio_write(FAR struct sx1301_dev_s *priv, uint8_t radio, + uint8_t addr, uint8_t value) +{ + uint8_t areg; + uint8_t dreg; + uint8_t csreg; + + if (radio == 0) + { + areg = SX1301_REG_RADIO_A_ADDR; + dreg = SX1301_REG_RADIO_A_DATA; + csreg = SX1301_REG_RADIO_A_CS; + } + else + { + areg = SX1301_REG_RADIO_B_ADDR; + dreg = SX1301_REG_RADIO_B_DATA; + csreg = SX1301_REG_RADIO_B_CS; + } + + sx1301_reg_write(priv, SX1301_PAGE_2, csreg, 0); + sx1301_reg_write(priv, SX1301_PAGE_2, areg, 0x80 | (addr & 0x7f)); + sx1301_reg_write(priv, SX1301_PAGE_2, dreg, value); + sx1301_reg_write(priv, SX1301_PAGE_2, csreg, 1); + up_udelay(SX1301_BRIDGE_DELAY_US); + sx1301_reg_write(priv, SX1301_PAGE_2, csreg, 0); + up_udelay(SX1301_BRIDGE_DELAY_US); +} + +/**************************************************************************** + * Name: sx1301_radio_read + ****************************************************************************/ + +static void sx1301_radio_read(FAR struct sx1301_dev_s *priv, uint8_t radio, + uint8_t addr, FAR uint8_t *value) +{ + uint8_t areg; + uint8_t dreg; + uint8_t csreg; + uint8_t rbreg; + + if (radio == 0) + { + areg = SX1301_REG_RADIO_A_ADDR; + dreg = SX1301_REG_RADIO_A_DATA; + csreg = SX1301_REG_RADIO_A_CS; + rbreg = SX1301_REG_RADIO_A_RB; + } + else + { + areg = SX1301_REG_RADIO_B_ADDR; + dreg = SX1301_REG_RADIO_B_DATA; + csreg = SX1301_REG_RADIO_B_CS; + rbreg = SX1301_REG_RADIO_B_RB; + } + + sx1301_reg_write(priv, SX1301_PAGE_2, csreg, 0); + sx1301_reg_write(priv, SX1301_PAGE_2, areg, addr & 0x7f); + sx1301_reg_write(priv, SX1301_PAGE_2, dreg, 0); + sx1301_reg_write(priv, SX1301_PAGE_2, csreg, 1); + up_udelay(SX1301_BRIDGE_DELAY_US); + sx1301_reg_write(priv, SX1301_PAGE_2, csreg, 0); + up_udelay(SX1301_BRIDGE_DELAY_US); + sx1301_reg_read(priv, SX1301_PAGE_2, rbreg, value); +} + +/**************************************************************************** + * Name: sx1301_setup_radio + * + * Description: + * Bring up one SX125x front-end: analogue configuration, PLL frequency and + * oscillator, then wait for the PLL to lock. Radio B has been seen to + * need a couple of milliseconds more than radio A, hence the retries. + * + ****************************************************************************/ + +static int sx1301_setup_radio(FAR struct sx1301_dev_s *priv, uint8_t radio) +{ + uint32_t freqreg; + uint8_t version = 0; + uint8_t status = 0; + uint8_t clkout; + int i; + + clkout = (radio == 0) ? 1 : 0; + + sx1301_radio_read(priv, radio, 0x07, &version); + wlinfo("Radio %c: SX125x version 0x%02x\n", radio == 0 ? 'A' : 'B', + version); + + /* Analogue configuration, values of the reference HAL setup_sx125x() */ + + sx1301_radio_write(priv, radio, 0x10, 0x03); /* TX DAC clock select */ + sx1301_radio_write(priv, radio, 0x13, clkout); + sx1301_radio_write(priv, radio, 0x10, 0x67); /* Full TX analogue chain */ + sx1301_radio_write(priv, radio, 0x08, 46); /* TX mix and DAC gain */ + sx1301_radio_write(priv, radio, 0x0a, 32); /* TX bandwidth */ + sx1301_radio_write(priv, radio, 0x0b, 5); /* TX DAC bandwidth */ + sx1301_radio_write(priv, radio, 0x0c, 57); /* LNA and baseband gain */ + sx1301_radio_write(priv, radio, 0x0d, 248); /* RX ADC trim and bandwidth */ + sx1301_radio_write(priv, radio, 0x0e, 0); /* RX PLL bandwidth */ + sx1301_radio_write(priv, radio, 0x26, 45); /* Crystal oscillator */ + + /* Fractional-N divider setting for a 32 MHz reference: + * freqreg = freq_hz * 2^19 / 32000000, computed without floating point. + */ + + freqreg = (uint32_t)(((uint64_t)priv->rf[radio].freq_hz << 19) / 32000000); + + sx1301_radio_write(priv, radio, 0x01, (freqreg >> 16) & 0xff); + sx1301_radio_write(priv, radio, 0x02, (freqreg >> 8) & 0xff); + sx1301_radio_write(priv, radio, 0x03, freqreg & 0xff); + + if (priv->rf[radio].tx_enable) + { + sx1301_radio_write(priv, radio, 0x04, (freqreg >> 16) & 0xff); + sx1301_radio_write(priv, radio, 0x05, (freqreg >> 8) & 0xff); + sx1301_radio_write(priv, radio, 0x06, freqreg & 0xff); + } + + sx1301_radio_write(priv, radio, 0x00, 1); /* Crystal on */ + sx1301_msleep(10); + sx1301_radio_write(priv, radio, 0x00, 3); /* Crystal plus RX PLL on */ + sx1301_msleep(10); + + for (i = 0; i < 5; i++) + { + sx1301_radio_read(priv, radio, 0x11, &status); + if ((status & 0x02) != 0) + { + wlinfo("Radio %c: PLL locked at %" PRIu32 " Hz\n", + radio == 0 ? 'A' : 'B', priv->rf[radio].freq_hz); + return OK; + } + + sx1301_msleep(1); + } + + wlwarn("WARNING: radio %c PLL lock not confirmed, status 0x%02x\n", + radio == 0 ? 'A' : 'B', status); + return OK; +} + +/**************************************************************************** + * Name: sx1301_hwreset + ****************************************************************************/ + +static void sx1301_hwreset(FAR struct sx1301_dev_s *priv) +{ + DEBUGASSERT(priv->lower != NULL && priv->lower->reset != NULL); + + priv->lower->reset(priv->lower, false); + sx1301_msleep(100); + priv->lower->reset(priv->lower, true); + sx1301_msleep(100); + priv->lower->reset(priv->lower, false); + sx1301_msleep(500); + + priv->page = 0; + wlinfo("Concentrator reset\n"); +} + +/**************************************************************************** + * Name: sx1301_loadfw + * + * Description: + * Copy one firmware image into the program memory of an internal MCU. + * + * Register 0x6a holds one reset bit and one multiplexer bit per MCU. The + * multiplexer must be zero for the MCU being loaded (host owns its memory) + * and one for the other, and only one may be in host mode at a time; the + * register is therefore written whole rather than bit by bit. + * + ****************************************************************************/ + +static int sx1301_loadfw(FAR struct sx1301_dev_s *priv, uint8_t mcu, + FAR const uint8_t *fw) +{ + uint8_t ctrl; + uint8_t readback = 0; + uint8_t dummy = 0; + uint8_t verify[4]; + size_t off; + size_t len; + int ret; + + ctrl = SX1301_MCU_RST_ARB | SX1301_MCU_RST_AGC; + ctrl |= (mcu == 0) ? SX1301_MCU_MUX_AGC : SX1301_MCU_MUX_ARB; + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_MCU_CTRL, ctrl); + sx1301_reg_read(priv, SX1301_PAGE_0, SX1301_REG_MCU_CTRL, &readback); + if (readback != ctrl) + { + wlwarn("WARNING: MCU%d control wrote 0x%02x read 0x%02x\n", + mcu, ctrl, readback); + } + + /* Let the multiplexer settle before touching the program memory */ + + sx1301_msleep(1); + + sx1301_reg_write(priv, SX1301_PAGE_ANY, SX1301_REG_PROM_ADDR, 0); + + for (off = 0; off < SX1301_MCU_FW_SIZE; off += len) + { + len = SX1301_MCU_FW_SIZE - off; + if (len > 1024) + { + len = 1024; + } + + ret = sx1301_reg_wrburst(priv, SX1301_PAGE_ANY, SX1301_REG_PROM_DATA, + fw + off, len); + if (ret < 0) + { + wlerr("ERROR: MCU%d firmware write failed at %zu: %d\n", + mcu, off, ret); + return ret; + } + } + + /* The first read after a write returns stale data on this interface, so + * rewind, throw one byte away and only then compare. + */ + + sx1301_reg_read(priv, SX1301_PAGE_ANY, SX1301_REG_PROM_DATA, &dummy); + sx1301_reg_write(priv, SX1301_PAGE_ANY, SX1301_REG_PROM_ADDR, 0); + sx1301_reg_read(priv, SX1301_PAGE_ANY, SX1301_REG_PROM_DATA, &dummy); + sx1301_reg_rdburst(priv, SX1301_PAGE_ANY, SX1301_REG_PROM_DATA, + verify, sizeof(verify)); + + if (memcmp(fw, verify, sizeof(verify)) != 0) + { + wlerr("ERROR: MCU%d program memory verify failed: " + "wrote %02x %02x %02x %02x read %02x %02x %02x %02x\n", + mcu, fw[0], fw[1], fw[2], fw[3], + verify[0], verify[1], verify[2], verify[3]); + return -EIO; + } + + /* Hand the program memory back to the MCU */ + + ctrl |= (mcu == 0) ? SX1301_MCU_MUX_ARB : SX1301_MCU_MUX_AGC; + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_MCU_CTRL, ctrl); + + wlinfo("MCU%d firmware loaded (%d bytes)\n", mcu, SX1301_MCU_FW_SIZE); + return OK; +} + +/**************************************************************************** + * Name: sx1301_mcu_fwversion + * + * Description: + * Read the version byte an MCU firmware publishes at address 0x20 of its + * RAM, through the debug port on page 2. + * + ****************************************************************************/ + +static uint8_t sx1301_mcu_fwversion(FAR struct sx1301_dev_s *priv, + uint8_t mcu) +{ + uint8_t version = 0; + uint8_t addrreg; + uint8_t datareg; + + addrreg = (mcu == 0) ? SX1301_REG_DBG_ARB_ADDR : SX1301_REG_DBG_AGC_ADDR; + datareg = (mcu == 0) ? SX1301_REG_DBG_ARB_DATA : SX1301_REG_DBG_AGC_DATA; + + sx1301_reg_write(priv, SX1301_PAGE_2, addrreg, 0x20); + sx1301_reg_read(priv, SX1301_PAGE_2, datareg, &version); + + return version; +} + +/**************************************************************************** + * Name: sx1301_calibrate + * + * Description: + * Run the calibration firmware in the AGC MCU. Without this the AGC never + * initialises and the receive chain stays deaf. + * + ****************************************************************************/ + +static int sx1301_calibrate(FAR struct sx1301_dev_s *priv) +{ + uint8_t cmd; + uint8_t status = 0; + uint8_t version; + int ret; + + /* Build the calibration command: bit 0 and 1 request the RX IQ mismatch + * calibration of radio A and B, bit 2 and 3 the TX DC offset calibration, + * bit 4 selects a DAC gain of 3 and bit 5 stays clear for the SX1257. + */ + + cmd = 0; + if (priv->rf[0].enable) + { + cmd |= 0x01; + if (priv->rf[0].tx_enable) + { + cmd |= 0x04; + } + } + + if (priv->rf[1].enable) + { + cmd |= 0x02; + if (priv->rf[1].tx_enable) + { + cmd |= 0x08; + } + } + + cmd |= 0x10; + + wlinfo("Calibration starting, command 0x%02x\n", cmd); + + ret = sx1301_loadfw(priv, 1, g_sx1301_cal_fw); + if (ret < 0) + { + return ret; + } + + /* Give the radios back to the AGC, pass the command and release the AGC */ + + sx1301_reg_setbit(priv, SX1301_PAGE_0, SX1301_REG_FORCE_CTRL, 1, false); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RADIO_SELECT, cmd); + sx1301_reg_setbit(priv, SX1301_PAGE_0, SX1301_REG_MCU_CTRL, 1, false); + + /* The version byte only changes once the MCU has restarted and rewritten + * it, so right after the release it may still show the previous firmware. + * Report it, do not treat it as a failure. + */ + + version = sx1301_mcu_fwversion(priv, 1); + wlinfo("Calibration firmware version %d (expected %d)\n", + version, SX1301_FW_VERSION_CAL); + + /* Release the host control so that the MCU can drive the chip. Both + * registers are page independent and must be written raw, since the page + * register itself is used as part of the sequence. + */ + + sx1301_reg_write(priv, SX1301_PAGE_ANY, SX1301_REG_PAGE, 3); + sx1301_reg_write(priv, SX1301_PAGE_ANY, SX1301_REG_EMERGENCY, 0); + + sx1301_msleep(2300); + + sx1301_reg_write(priv, SX1301_PAGE_ANY, SX1301_REG_EMERGENCY, 1); + sx1301_reg_write(priv, SX1301_PAGE_ANY, SX1301_REG_PAGE, 0); + + sx1301_reg_read(priv, SX1301_PAGE_0, SX1301_REG_AGC_STATUS, &status); + if ((status & SX1301_CAL_STATUS_OK) == SX1301_CAL_STATUS_OK) + { + wlinfo("Calibration done, status 0x%02x\n", status); + } + else + { + wlwarn("WARNING: calibration incomplete, status 0x%02x\n", status); + } + + return OK; +} + +/**************************************************************************** + * Name: sx1301_agc_command + * + * Description: + * Send one byte to the AGC MCU command channel and return the status the + * MCU reports afterwards. + * + ****************************************************************************/ + +static uint8_t sx1301_agc_command(FAR struct sx1301_dev_s *priv, + uint8_t value) +{ + uint8_t status = 0; + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RADIO_SELECT, + SX1301_AGC_CMD_WAIT); + sx1301_msleep(1); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RADIO_SELECT, value); + sx1301_msleep(1); + sx1301_reg_read(priv, SX1301_PAGE_0, SX1301_REG_AGC_STATUS, &status); + + return status; +} + +/**************************************************************************** + * Name: sx1301_agc_start + * + * Description: + * Hand the transmit gain table and the channel mapping to the AGC MCU. + * The sequence is: sixteen gain table entries, the transmit frequency + * range selector, the channel selection option and finally the radio + * mapping. The MCU reports 0x40 once it is running. + * + ****************************************************************************/ + +static void sx1301_agc_start(FAR struct sx1301_dev_s *priv) +{ + uint8_t status; + uint8_t txfreq; + int i; + + for (i = 0; i < SX1301_TX_LUT_SIZE; i++) + { + status = sx1301_agc_command(priv, g_sx1301_tx_lut[i]); + wlinfo("AGC gain table entry %d = %d, status 0x%02x\n", + i, g_sx1301_tx_lut[i], status); + } + + /* Transmit frequency range: 3 above 768 MHz, 2 below, as in the reference + * HAL. A full gain table makes the AGC advance on its own, so no abort + * command is sent here. + */ + + txfreq = (priv->rf[0].freq_hz > 768000000) ? 3 : 2; + + status = sx1301_agc_command(priv, txfreq); + wlinfo("AGC transmit range %d, status 0x%02x\n", txfreq, status); + + status = sx1301_agc_command(priv, 0); + wlinfo("AGC channel option, status 0x%02x\n", status); + + status = sx1301_agc_command(priv, priv->radio_select); + if (status == SX1301_AGC_STATUS_DONE) + { + wlinfo("AGC running, radio map 0x%02x\n", priv->radio_select); + } + else + { + wlwarn("WARNING: AGC status 0x%02x, expected 0x%02x\n", + status, SX1301_AGC_STATUS_DONE); + } +} + +/**************************************************************************** + * Name: sx1301_start + * + * Description: + * Full start-up sequence. Must be called with the device locked. + * + ****************************************************************************/ + +static int sx1301_start(FAR struct sx1301_dev_s *priv) +{ + uint8_t modem_en; + uint8_t status = 0; + uint8_t version; + uint32_t drift; + int ret; + int i; + + if (priv->started) + { + return -EALREADY; + } + + /* Hardware reset and band selection of the front-end filters */ + + sx1301_hwreset(priv); + + if (priv->lower->band_select != NULL) + { + priv->lower->band_select(priv->lower, + priv->rf[0].freq_hz > 900000000 ? 915 : 868); + } + + ret = sx1301_reg_probe(priv); + if (ret < 0) + { + return ret; + } + + /* Soft reset, then gate every clock while the radios are configured */ + + sx1301_reg_setbit(priv, SX1301_PAGE_ANY, SX1301_REG_PAGE, 7, true); + sx1301_msleep(10); + + sx1301_reg_setbit(priv, SX1301_PAGE_0, SX1301_REG_GLOBAL_EN, 3, false); + sx1301_reg_setbit(priv, SX1301_PAGE_0, SX1301_REG_CLK_CTRL, 0, false); + + /* Power the radios up and only then pulse their reset line. Enabling + * them is what starts the 32 MHz crystal of the front-end, and it needs + * half a second to stabilise: talking to the radios earlier gets zeros + * back from the bridge. + */ + + sx1301_reg_write(priv, SX1301_PAGE_2, SX1301_REG_RADIO_CFG, 0x03); + sx1301_msleep(500); + sx1301_reg_write(priv, SX1301_PAGE_2, SX1301_REG_RADIO_CFG, 0x07); + sx1301_msleep(5); + sx1301_reg_write(priv, SX1301_PAGE_2, SX1301_REG_RADIO_CFG, 0x03); + sx1301_msleep(5); + + for (i = 0; i < LORA_GW_RF_CHAIN_NB; i++) + { + if (priv->rf[i].enable) + { + ret = sx1301_setup_radio(priv, i); + if (ret < 0) + { + return ret; + } + } + } + + /* Clocks back on */ + + sx1301_reg_setbit(priv, SX1301_PAGE_0, SX1301_REG_GLOBAL_EN, 3, true); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_CLK_CTRL, 0x03); + + /* Drive the five concentrator GPIOs as outputs and let the AGC use them + * for the antenna switch. Without this the switch stays in receive and + * nothing leaves the antenna during a downlink. + */ + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_GPIO_MODE, 31); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_GPIO_SELECT, 2); + + /* Fixed tuning constants of the reference HAL */ + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RSSI_BB_DFLT, 23); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RSSI_DEC_DFLT, 66); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RSSI_CHAN_DFT, 85); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RSSI_BB_ALPHA, 6); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RSSI_DEC_ALPH, 7); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RSSI_CHN_ALPH, 7); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_GAIN_OFFSET, + 7 | (6 << 4)); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_CORR_TUNE, + 4 | (7 << 4)); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_PPM_OFFSET, 0x60); + + drift = 4096000000ul / (priv->rf[0].freq_hz >> 1); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_FREQ_DRIFT, + drift > 63 ? 63 : (uint8_t)drift); + + drift = 4096000000ul / (priv->rf[0].freq_hz >> 3); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_MBWSSF_DRIFT, + drift > 63 ? 63 : (uint8_t)drift); + + /* Transmitter constants. TX_SWAP_IQ is mandatory for LoRaWAN downlinks, + * the frame synchronisation words are the public network ones. + */ + + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_GAIN, 0x80); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_FRAME_SYNC, + SX1301_SYNCH_WORD); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_START_DLY, + SX1301_TX_START_DELAY & 0xff); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_START_DLY + 1, + (SX1301_TX_START_DELAY >> 8) & 0xff); + + /* Frame synchronisation of the receive path: the multi-SF demodulators and + * the LoRa standard one. Both come up configured for a private network. + */ + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_FRAME_SYNCH, + SX1301_SYNCH_WORD); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_MBWSSF_SYNCH, + SX1301_SYNCH_WORD); + + /* Intermediate frequencies and radio mapping of the eight multi-SF + * demodulators + */ + + priv->radio_select = 0; + for (i = 0; i < LORA_GW_MULTI_NB; i++) + { + if (priv->ifc[i].enable && priv->ifc[i].rf_chain == 1) + { + priv->radio_select |= 1 << i; + } + } + + for (i = 0; i < LORA_GW_MULTI_NB; i++) + { + int32_t ifreg = 0; + + if (priv->ifc[i].enable) + { + ifreg = SX1301_IF_HZ_TO_REG(priv->ifc[i].freq_hz); + } + + sx1301_reg_write13s(priv, SX1301_PAGE_0, + SX1301_REG_IF_FREQ_BASE + (i * 2), ifreg); + } + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RADIO_SELECT, + priv->radio_select); + + /* Correlators. This is what actually turns a channel on. */ + + for (i = 0; i < LORA_GW_MULTI_NB; i++) + { + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_CORR_EN_BASE + i, + priv->ifc[i].enable ? SX1301_CORR_SF7_SF12 : 0); + } + + /* LoRa standard demodulator */ + + if (priv->std.enable) + { + uint8_t bwsel = 0; + + if (priv->std.bandwidth == LORA_GW_BW_250K) + { + bwsel = 1; + } + else if (priv->std.bandwidth == LORA_GW_BW_500K) + { + bwsel = 2; + } + + sx1301_reg_write13s(priv, SX1301_PAGE_0, SX1301_REG_IF_FREQ_8, + SX1301_IF_HZ_TO_REG(priv->std.freq_hz)); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_MBWSSF_BW_SEL, + bwsel | ((priv->std.rf_chain & 1) << 2)); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_MBWSSF_SF, + priv->std.datarate); + } + + /* The modems have to be enabled before the firmwares are loaded */ + + modem_en = SX1301_EN_GLOBAL | SX1301_EN_CONCENTRATOR; + if (priv->std.enable) + { + modem_en |= SX1301_EN_MBWSSF; + } + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_GLOBAL_EN, modem_en); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_CLK_CTRL, 0x03); + + /* Calibration pass, then the production firmwares */ + + ret = sx1301_calibrate(priv); + if (ret < 0) + { + return ret; + } + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_MCU_CTRL, + SX1301_MCU_RST_ARB | SX1301_MCU_RST_AGC); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_FORCE_CTRL, 0x0e); + + ret = sx1301_loadfw(priv, 0, g_sx1301_arb_fw); + if (ret < 0) + { + return ret; + } + + ret = sx1301_loadfw(priv, 1, g_sx1301_agc_fw); + if (ret < 0) + { + return ret; + } + + version = sx1301_mcu_fwversion(priv, 0); + wlinfo("Arbiter firmware version %d (expected %d)\n", + version, SX1301_FW_VERSION_ARB); + + /* Release the host control and let both MCUs run. The multiplexer bits + * must stay set or the MCUs lose access to their program memory. + */ + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_FORCE_CTRL, 0); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RADIO_SELECT, 0); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_MCU_CTRL, + SX1301_MCU_MUX_ARB | SX1301_MCU_MUX_AGC); + + sx1301_msleep(10); + + for (i = 0; i < 100; i++) + { + sx1301_reg_read(priv, SX1301_PAGE_0, SX1301_REG_AGC_STATUS, &status); + if (status == SX1301_AGC_STATUS_READY) + { + break; + } + + sx1301_msleep(10); + } + + if (status != SX1301_AGC_STATUS_READY) + { + wlerr("ERROR: AGC did not become ready, status 0x%02x\n", status); + return -EIO; + } + + sx1301_agc_start(priv); + + /* Re-assert the modem enables, the MCU initialisation may clear them */ + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_GLOBAL_EN, modem_en); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_CLK_CTRL, 0x03); + + memset(&priv->status, 0, sizeof(priv->status)); + priv->started = true; + priv->status.started = true; + + wlinfo("Concentrator started, modems 0x%02x\n", modem_en); + return OK; +} + +/**************************************************************************** + * Name: sx1301_stop + ****************************************************************************/ + +static int sx1301_stop(FAR struct sx1301_dev_s *priv) +{ + if (!priv->started) + { + return OK; + } + + sx1301_reg_setbit(priv, SX1301_PAGE_0, SX1301_REG_GLOBAL_EN, 3, false); + + if (priv->lower->reset != NULL) + { + priv->lower->reset(priv->lower, true); + } + + priv->started = false; + priv->connected = false; + priv->status.started = false; + + wlinfo("Concentrator stopped\n"); + return OK; +} + +/**************************************************************************** + * Name: sx1301_tscorrection + * + * Description: + * Delay, in microseconds, between the end of a packet on the air and the + * moment the concentrator latches its timestamp. The network server + * derives the downlink window from the value we report, so the correction + * of the reference HAL has to be applied or every downlink is late. + * + ****************************************************************************/ + +static uint32_t sx1301_tscorrection(uint8_t bandwidth, uint8_t sf, + uint8_t cr, uint16_t size, bool crc_en, + bool stdchan) +{ + uint32_t delay_x; + uint32_t delay_y; + uint32_t delay_z; + uint32_t bw_pow; + uint32_t ppm; + int32_t payload; + + if (sf < 6 || sf > 12) + { + return 0; + } + + ppm = SX1301_PPM_ON(bandwidth, sf) ? 1 : 0; + + if (stdchan) + { + switch (bandwidth) + { + case LORA_GW_BW_125K: + delay_x = 64; + bw_pow = 1; + break; + + case LORA_GW_BW_250K: + delay_x = 32; + bw_pow = 2; + break; + + case LORA_GW_BW_500K: + delay_x = 16; + bw_pow = 4; + break; + + default: + return 0; + } + } + else + { + delay_x = 114; + bw_pow = 1; + } + + payload = 2 * (size + (crc_en ? 2 : 0)); + + if ((payload - (sf - 7)) <= 0) + { + /* The payload fits entirely in the first eight symbols */ + + delay_y = (((1 << (sf - 1)) * (sf + 1)) + (3 * (1 << (sf - 4)))) / + bw_pow; + delay_z = 32 * (payload + 5) / bw_pow; + } + else + { + delay_y = (((1 << (sf - 1)) * (sf + 1)) + + ((4 - ppm) * (1 << (sf - 4)))) / bw_pow; + delay_z = (16 + 4 * cr) * + (((payload - sf + 6) % (sf - 2 * ppm)) + 1) / bw_pow; + } + + return delay_x + delay_y + delay_z; +} + +/**************************************************************************** + * Name: sx1301_receive + * + * Description: + * Drain the receive FIFO into the caller buffer. Must be called with the + * device locked. + * + * Returned Value: + * Number of packets stored in pkts, or a negated errno value. + * + ****************************************************************************/ + +static int sx1301_receive(FAR struct sx1301_dev_s *priv, + FAR struct lora_gw_rxpkt_s *pkts, int maxpkt) +{ + FAR struct lora_gw_rxpkt_s *pkt; + FAR uint8_t *meta; + uint8_t buffer[SX1301_RXBUF_SIZE]; + uint8_t hdr[SX1301_FIFO_HDR_SIZE]; + uint8_t status; + uint8_t sf; + uint8_t cr; + uint16_t size; + size_t total; + bool crc_en; + bool stdchan; + int npkt = 0; + int ret; + + while (npkt < maxpkt) + { + /* Reading the packet count also latches the data buffer pointer, so + * the five header bytes must be fetched in one burst. + */ + + ret = sx1301_reg_rdburst(priv, SX1301_PAGE_0, + SX1301_REG_RX_NUM_STORED, hdr, sizeof(hdr)); + if (ret < 0) + { + priv->status.rx_err++; + return npkt > 0 ? npkt : ret; + } + + if (hdr[0] == 0) + { + break; + } + + status = hdr[3]; + size = hdr[4]; + total = size + SX1301_RX_METADATA_NB; + + if (total > sizeof(buffer)) + { + total = sizeof(buffer); + } + + ret = sx1301_reg_rdburst(priv, SX1301_PAGE_0, SX1301_REG_RX_BUF_DATA, + buffer, total); + if (ret < 0) + { + priv->status.rx_err++; + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RX_NUM_STORED, 0); + continue; + } + + /* Pop the packet before anything else can touch the FIFO pointer */ + + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_RX_NUM_STORED, 0); + + meta = &buffer[size]; + pkt = &pkts[npkt]; + + memset(pkt, 0, sizeof(*pkt)); + + /* The three low bits of the FIFO status tell CRC pass from CRC fail + * from no CRC at all. Anything else is a demodulator hiccup. + */ + + switch (status & 0x07) + { + case 5: + pkt->status = LORA_GW_STAT_CRC_OK; + crc_en = true; + break; + + case 7: + pkt->status = LORA_GW_STAT_CRC_BAD; + crc_en = true; + priv->status.rx_bad++; + break; + + case 1: + pkt->status = LORA_GW_STAT_NO_CRC; + crc_en = false; + priv->status.rx_nocrc++; + break; + + default: + pkt->status = LORA_GW_STAT_UNDEFINED; + crc_en = false; + priv->status.rx_err++; + break; + } + +#ifndef CONFIG_LPWAN_SX1301_RXBADCRC + /* A gateway has nothing to do with a corrupted packet, and forwarding + * it as if it were valid pollutes the network server with correlator + * false triggers. Drop it unless the debug option asks for it. + */ + + if (pkt->status == LORA_GW_STAT_CRC_BAD || + pkt->status == LORA_GW_STAT_UNDEFINED) + { + continue; + } +#endif + +#ifndef CONFIG_LPWAN_SX1301_RXNOCRC + /* Same for a packet that carried no CRC at all: a LoRaWAN uplink + * always has one, so what shows up here is either a false trigger of + * the correlator or the downlink of another gateway. The reference + * packet forwarder does not forward those either. + */ + + if (pkt->status == LORA_GW_STAT_NO_CRC) + { + continue; + } +#endif + + pkt->if_chain = meta[0]; + pkt->modulation = LORA_GW_MOD_LORA; + pkt->size = size; + + sf = (meta[1] >> 4) & 0x0f; + cr = (meta[1] >> 1) & 0x07; + + if (sf < 6 || sf > 12) + { + sf = 7; + } + + if (cr < 1 || cr > 4) + { + cr = WLIOC_LORA_CR_4_5; + } + + pkt->coderate = cr; + + /* Frequency, bandwidth and, for the standard channel, the spreading + * factor all come from the channel plan rather than the metadata. + */ + + stdchan = (pkt->if_chain == LORA_GW_MULTI_NB); + + if (stdchan && priv->std.enable) + { + pkt->rf_chain = priv->std.rf_chain; + pkt->bandwidth = priv->std.bandwidth; + pkt->datarate = priv->std.datarate; + pkt->freq_hz = priv->rf[priv->std.rf_chain].freq_hz + + priv->std.freq_hz; + } + else if (pkt->if_chain < LORA_GW_MULTI_NB) + { + pkt->rf_chain = priv->ifc[pkt->if_chain].rf_chain; + pkt->bandwidth = LORA_GW_BW_125K; + pkt->datarate = sf; + pkt->freq_hz = priv->rf[pkt->rf_chain].freq_hz + + priv->ifc[pkt->if_chain].freq_hz; + } + else + { + /* IF9 is the FSK demodulator, which this driver does not use */ + + wlwarn("WARNING: packet from unexpected chain %d\n", + pkt->if_chain); + priv->status.rx_err++; + continue; + } + + pkt->rssi_dbm10 = (int16_t)(meta[5] * 10) + + priv->rf[pkt->rf_chain].rssi_offset_dbm10; + pkt->snr_db10 = ((int16_t)((int8_t)meta[2]) * 10) / 4; + + pkt->count_us = (uint32_t)meta[6] | + ((uint32_t)meta[7] << 8) | + ((uint32_t)meta[8] << 16) | + ((uint32_t)meta[9] << 24); + + pkt->count_us -= sx1301_tscorrection(pkt->bandwidth, pkt->datarate, + pkt->coderate, size, crc_en, + stdchan); + + memcpy(pkt->payload, buffer, size); + + if (pkt->status == LORA_GW_STAT_CRC_OK) + { + priv->status.rx_ok++; + } + + wlinfo("RX chain %d SF%d %" PRIu32 " Hz rssi %d.%d dBm snr %d.%d dB " + "size %d status 0x%02x\n", + pkt->if_chain, pkt->datarate, pkt->freq_hz, + pkt->rssi_dbm10 / 10, abs(pkt->rssi_dbm10 % 10), + pkt->snr_db10 / 10, abs(pkt->snr_db10 % 10), + pkt->size, pkt->status); + + npkt++; + } + + return npkt; +} + +/**************************************************************************** + * Name: sx1301_send + * + * Description: + * Queue one packet for transmission. Must be called with the device + * locked. The transmission itself happens asynchronously, either right + * away or at the requested concentrator timestamp, so this does not wait + * for completion. + * + ****************************************************************************/ + +static int sx1301_send(FAR struct sx1301_dev_s *priv, + FAR const struct lora_gw_txpkt_s *pkt) +{ + uint8_t buffer[SX1301_RX_METADATA_NB + LORA_GW_MAX_PAYLOAD]; + uint32_t part_int; + uint32_t part_frac; + uint32_t timestamp; + uint16_t start_delay; + uint16_t preamble; + uint8_t powidx; + uint8_t status = 0; + int i; + + if (pkt->size > LORA_GW_MAX_PAYLOAD || + pkt->rf_chain >= LORA_GW_RF_CHAIN_NB) + { + return -EINVAL; + } + + if (!priv->rf[pkt->rf_chain].tx_enable) + { + wlerr("ERROR: radio %d cannot transmit\n", pkt->rf_chain); + return -EPERM; + } + + memset(buffer, 0, SX1301_RX_METADATA_NB); + + /* Radio frequency, as an integer part in units of 4 MHz plus a fraction */ + + part_int = pkt->freq_hz / 4000000; + part_frac = ((pkt->freq_hz % 4000000) << 8) / 15625; + + buffer[0] = part_int & 0xff; + if (pkt->bandwidth == LORA_GW_BW_500K) + { + buffer[0] |= 0x80; + } + + buffer[1] = (part_frac >> 8) & 0xff; + buffer[2] = part_frac & 0xff; + + /* The transmit chain starts start_delay microseconds before the packet + * appears on the air, so the requested time is moved back by that much. + */ + + start_delay = (pkt->bandwidth == LORA_GW_BW_125K) ? + SX1301_TX_START_DLY_125 : SX1301_TX_START_DELAY; + + timestamp = pkt->count_us - start_delay; + buffer[3] = (timestamp >> 24) & 0xff; + buffer[4] = (timestamp >> 16) & 0xff; + buffer[5] = (timestamp >> 8) & 0xff; + buffer[6] = timestamp & 0xff; + + /* Radio chain, modulation and index in the transmit gain table. Pick the + * first table entry that reaches the requested power. + */ + + powidx = SX1301_TX_LUT_SIZE - 1; + for (i = 0; i < SX1301_TX_LUT_SIZE; i++) + { + if (pkt->rf_power <= g_sx1301_tx_pwr[i]) + { + powidx = i; + break; + } + } + + buffer[7] = ((pkt->rf_chain & 0x01) << 5) | (powidx & 0x0f); + buffer[8] = 0; + + buffer[9] = pkt->no_crc ? 0 : 0x80; + buffer[9] |= (pkt->coderate & 0x07) << 4; + buffer[9] |= pkt->datarate & 0x0f; + + buffer[10] = pkt->size; + + buffer[11] = 0; + if (pkt->invert_pol) + { + buffer[11] |= 0x10; + } + + if (SX1301_PPM_ON(pkt->bandwidth, pkt->datarate)) + { + buffer[11] |= 0x08; + } + + if (pkt->no_header) + { + buffer[11] |= 0x04; + } + + if (pkt->bandwidth == LORA_GW_BW_250K) + { + buffer[11] |= 0x01; + } + else if (pkt->bandwidth == LORA_GW_BW_500K) + { + buffer[11] |= 0x02; + } + + preamble = (pkt->preamble != 0) ? pkt->preamble : 8; + buffer[12] = (preamble >> 8) & 0xff; + buffer[13] = preamble & 0xff; + + memcpy(&buffer[SX1301_RX_METADATA_NB], pkt->payload, pkt->size); + + /* No transmit IQ calibration values are kept, and the digital gain stays + * at zero while TX_SWAP_IQ has to be preserved. + */ + + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_OFFSET_I, 0); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_OFFSET_Q, 0); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_GAIN, 0x80); + + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_START_DLY, + start_delay & 0xff); + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_START_DLY + 1, + (start_delay >> 8) & 0xff); + + /* Abort anything pending, load the buffer and trigger */ + + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_TRIG, 0); + sx1301_reg_write(priv, SX1301_PAGE_0, SX1301_REG_TX_BUF_ADDR, 0); + sx1301_reg_wrburst(priv, SX1301_PAGE_0, SX1301_REG_TX_BUF_DATA, buffer, + SX1301_RX_METADATA_NB + pkt->size); + + sx1301_reg_write(priv, SX1301_PAGE_1, SX1301_REG_TX_TRIG, + pkt->tx_mode == LORA_GW_TX_IMMEDIATE ? 0x01 : 0x02); + + sx1301_reg_read(priv, SX1301_PAGE_1, SX1301_REG_TX_STATUS, &status); + + priv->status.tx_ok++; + + wlinfo("TX %s %" PRIu32 " Hz SF%d %d bytes, gain %d, status 0x%02x\n", + pkt->tx_mode == LORA_GW_TX_IMMEDIATE ? "now" : "scheduled", + pkt->freq_hz, pkt->datarate, pkt->size, powidx, status); + + return OK; +} + +/**************************************************************************** + * Name: sx1301_open + ****************************************************************************/ + +static int sx1301_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct sx1301_dev_s *priv = inode->i_private; + int ret; + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + priv->crefs++; + nxmutex_unlock(&priv->lock); + + return OK; +} + +/**************************************************************************** + * Name: sx1301_close + ****************************************************************************/ + +static int sx1301_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct sx1301_dev_s *priv = inode->i_private; + int ret; + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + if (priv->crefs > 0) + { + priv->crefs--; + } + + nxmutex_unlock(&priv->lock); + return OK; +} + +/**************************************************************************** + * Name: sx1301_read + ****************************************************************************/ + +static ssize_t sx1301_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct sx1301_dev_s *priv = inode->i_private; + FAR struct lora_gw_rxpkt_s *pkts; + int maxpkt; + int npkt; + int ret; + + maxpkt = buflen / sizeof(struct lora_gw_rxpkt_s); + if (maxpkt < 1) + { + return -EINVAL; + } + + pkts = (FAR struct lora_gw_rxpkt_s *)buffer; + + for (; ; ) + { + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + if (!priv->started) + { + nxmutex_unlock(&priv->lock); + return -ENXIO; + } + + npkt = sx1301_receive(priv, pkts, maxpkt); + nxmutex_unlock(&priv->lock); + + if (npkt < 0) + { + return npkt; + } + + if (npkt > 0) + { + return npkt * sizeof(struct lora_gw_rxpkt_s); + } + + if ((filep->f_oflags & O_NONBLOCK) != 0) + { + return -EAGAIN; + } + + /* There is no interrupt line on the reference shields, so a blocking + * reader polls the FIFO. + */ + + ret = nxsig_usleep(SX1301_RXPOLL_USEC); + if (ret < 0) + { + return ret; + } + } +} + +/**************************************************************************** + * Name: sx1301_write + ****************************************************************************/ + +static ssize_t sx1301_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct sx1301_dev_s *priv = inode->i_private; + FAR const struct lora_gw_txpkt_s *pkt; + int ret; + + if (buflen != sizeof(struct lora_gw_txpkt_s)) + { + return -EINVAL; + } + + pkt = (FAR const struct lora_gw_txpkt_s *)buffer; + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + if (!priv->started) + { + nxmutex_unlock(&priv->lock); + return -ENXIO; + } + + ret = sx1301_send(priv, pkt); + if (ret < 0) + { + priv->status.tx_err++; + } + + nxmutex_unlock(&priv->lock); + + return ret < 0 ? ret : (ssize_t)buflen; +} + +/**************************************************************************** + * Name: sx1301_ioctl + ****************************************************************************/ + +static int sx1301_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct sx1301_dev_s *priv = inode->i_private; + int ret; + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + switch (cmd) + { + case WLIOC_GW_START: + { + ret = sx1301_start(priv); + } + break; + + case WLIOC_GW_STOP: + { + ret = sx1301_stop(priv); + } + break; + + case WLIOC_GW_RESET: + { + sx1301_stop(priv); + ret = sx1301_start(priv); + } + break; + + case WLIOC_GW_SETREGION: + { + FAR const char *name = (FAR const char *)((uintptr_t)arg); + + if (name == NULL) + { + ret = -EINVAL; + } + else + { + ret = sx1301_region_byname(name); + if (ret >= 0) + { + ret = sx1301_region_apply(priv, ret); + } + } + } + break; + + case WLIOC_GW_GETREGION: + { + FAR struct lora_gw_regionreq_s *req = + (FAR struct lora_gw_regionreq_s *)((uintptr_t)arg); + + if (req == NULL) + { + ret = -EINVAL; + } + else + { + ret = sx1301_region_getinfo(req->index < 0 ? priv->region : + req->index, &req->info); + } + } + break; + + case WLIOC_GW_GETSTATUS: + { + FAR struct lora_gw_status_s *status = + (FAR struct lora_gw_status_s *)((uintptr_t)arg); + + if (status == NULL) + { + ret = -EINVAL; + } + else + { + memcpy(status, &priv->status, sizeof(*status)); + ret = OK; + } + } + break; + + case WLIOC_GW_GETTRIGCNT: + { + FAR uint32_t *count = (FAR uint32_t *)((uintptr_t)arg); + uint8_t buffer[4]; + + if (count == NULL) + { + ret = -EINVAL; + } + else if (!priv->started) + { + ret = -ENXIO; + } + else + { + ret = sx1301_reg_rdburst(priv, SX1301_PAGE_0, + SX1301_REG_TIMESTAMP, buffer, + sizeof(buffer)); + if (ret >= 0) + { + *count = (uint32_t)buffer[0] | + ((uint32_t)buffer[1] << 8) | + ((uint32_t)buffer[2] << 16) | + ((uint32_t)buffer[3] << 24); + } + } + } + break; + + default: + { + ret = -ENOTTY; + } + break; + } + + nxmutex_unlock(&priv->lock); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sx1301_register + ****************************************************************************/ + +int sx1301_register(FAR const char *devpath, FAR struct spi_dev_s *spi, + FAR const struct sx1301_lower_s *lower) +{ + FAR struct sx1301_dev_s *priv; + int region; + int ret; + + DEBUGASSERT(devpath != NULL && spi != NULL && lower != NULL); + DEBUGASSERT(lower->reset != NULL); + + priv = kmm_zalloc(sizeof(struct sx1301_dev_s)); + if (priv == NULL) + { + return -ENOMEM; + } + + priv->spi = spi; + priv->lower = lower; + + nxmutex_init(&priv->lock); + + /* Select the compiled in default region */ + + region = sx1301_region_byname(CONFIG_LPWAN_SX1301_DEFAULT_REGION); + if (region < 0) + { + wlwarn("WARNING: unknown default region '%s', using the first one\n", + CONFIG_LPWAN_SX1301_DEFAULT_REGION); + region = 0; + } + + ret = sx1301_region_apply(priv, region); + if (ret < 0) + { + goto errout; + } + + /* Hold the chip in reset until it is started */ + + lower->reset(lower, true); + + ret = register_driver(devpath, &g_sx1301_fops, 0666, priv); + if (ret < 0) + { + wlerr("ERROR: failed to register %s: %d\n", devpath, ret); + goto errout; + } + + wlinfo("SX1301 registered at %s\n", devpath); + return OK; + +errout: + nxmutex_destroy(&priv->lock); + kmm_free(priv); + return ret; +} diff --git a/drivers/wireless/lpwan/sx1301/sx1301_fw.c b/drivers/wireless/lpwan/sx1301/sx1301_fw.c new file mode 100644 index 0000000000000..ca6a96ae4150c --- /dev/null +++ b/drivers/wireless/lpwan/sx1301/sx1301_fw.c @@ -0,0 +1,2126 @@ +/**************************************************************************** + * drivers/wireless/lpwan/sx1301/sx1301_fw.c + * + * SPDX-License-Identifier: BSD-3-Clause + * SPDX-FileCopyrightText: 2013 Semtech-Cycleo + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. 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. + * 3. 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 THE COPYRIGHT HOLDER OR + * CONTRIBUTORS 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. + * + ****************************************************************************/ + +/* Firmware images of the two internal 8 KiB MCUs of the SX1301, taken + * verbatim from the Semtech reference HAL (lora_gateway, libloragw): + * + * agc - automatic gain control, version 4 + * arb - arbiter, version 1 + * cal - calibration, version 2. Loaded into the AGC MCU before the + * production firmware, runs for about 2.3 s and then is replaced. + * + * They are const so that they live in flash rather than in RAM. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "sx1301_fw.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* AGC firmware */ + +const uint8_t g_sx1301_agc_fw[SX1301_MCU_FW_SIZE] = +{ + 0x8a, 0x51, 0x11, 0x28, 0xff, 0xbf, 0xff, 0xbf, 0x80, 0x40, 0x03, 0x4e, + 0x83, 0x52, 0x03, 0x53, 0xac, 0x00, 0x04, 0x88, 0xad, 0x40, 0x0a, 0xc8, + 0xae, 0x40, 0x01, 0x88, 0xaf, 0x80, 0x8a, 0x51, 0x13, 0x68, 0x8a, 0x51, + 0x59, 0x2d, 0x8b, 0xdc, 0x1a, 0x68, 0xa0, 0xe0, 0x8a, 0x51, 0x27, 0x60, + 0x40, 0xf0, 0x9b, 0x40, 0x10, 0xf0, 0x8b, 0x00, 0x2f, 0x88, 0x81, 0x80, + 0x2e, 0x48, 0x8a, 0xc0, 0x2d, 0x48, 0x84, 0x80, 0x2c, 0x8e, 0x83, 0xc0, + 0x80, 0x0e, 0x00, 0xce, 0x09, 0x80, 0x95, 0x41, 0x96, 0x41, 0x97, 0x81, + 0x98, 0x01, 0x99, 0x41, 0x9a, 0x41, 0x9b, 0x81, 0x9c, 0x41, 0x9e, 0x81, + 0x19, 0x54, 0x19, 0x95, 0x18, 0x56, 0x8b, 0x41, 0xd4, 0x41, 0x02, 0xf0, + 0x54, 0x02, 0x03, 0x18, 0x59, 0xa8, 0x54, 0x08, 0x51, 0x3e, 0x84, 0x80, + 0x83, 0x93, 0x80, 0x81, 0x54, 0x08, 0x5d, 0xbe, 0x84, 0x80, 0x07, 0x70, + 0x80, 0x40, 0x54, 0x08, 0x72, 0x60, 0x8a, 0x51, 0x54, 0x08, 0x5d, 0xbe, + 0x84, 0x80, 0x00, 0xce, 0xf0, 0x39, 0x96, 0x00, 0x54, 0x9c, 0x52, 0x68, + 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x55, 0xa8, 0x83, 0x52, 0x03, 0x53, + 0x18, 0xd0, 0x18, 0x55, 0x18, 0x11, 0xd4, 0x8a, 0x35, 0xa8, 0xd3, 0x81, + 0x08, 0xf0, 0x53, 0x42, 0x03, 0x18, 0x6f, 0x28, 0x53, 0x48, 0x55, 0x7e, + 0x84, 0x80, 0x04, 0xf0, 0x83, 0x93, 0x80, 0x40, 0x53, 0x48, 0x55, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0x96, 0x00, 0x53, 0x48, 0x95, 0x00, 0x98, 0x54, + 0x98, 0x10, 0xd3, 0xca, 0x5a, 0xa8, 0x10, 0xf0, 0x9b, 0x40, 0x08, 0x40, + 0xab, 0x40, 0x51, 0x3e, 0x84, 0x80, 0x00, 0x48, 0xaa, 0x00, 0x23, 0x3e, + 0x84, 0x80, 0x8a, 0x51, 0x1d, 0xe5, 0x8a, 0x51, 0xa7, 0x40, 0x05, 0x30, + 0x03, 0xd0, 0xa7, 0x0d, 0xff, 0x7e, 0x03, 0x9d, 0x7e, 0x28, 0x2a, 0x08, + 0x2d, 0x7e, 0x84, 0x80, 0x8a, 0x51, 0x1d, 0xe5, 0x8a, 0x51, 0xa8, 0xc0, + 0x28, 0x47, 0x27, 0x44, 0x01, 0x38, 0xa9, 0x00, 0x2b, 0x48, 0x22, 0xfe, + 0x84, 0x80, 0x29, 0x08, 0x80, 0x40, 0x2b, 0x48, 0x22, 0xfe, 0x84, 0x80, + 0x00, 0x48, 0x83, 0x96, 0xa0, 0x80, 0x83, 0x52, 0x2b, 0x48, 0x83, 0x96, + 0xa1, 0xc0, 0x0c, 0x30, 0xd3, 0xe1, 0x08, 0x40, 0x18, 0x12, 0x80, 0xf0, + 0x9b, 0x40, 0x10, 0xf0, 0x9e, 0x40, 0x13, 0x1f, 0xab, 0xe8, 0x83, 0x52, + 0x03, 0x53, 0x18, 0x14, 0xae, 0xe8, 0x83, 0x52, 0x03, 0x53, 0x18, 0xd0, + 0x92, 0x1f, 0xb4, 0xa8, 0x83, 0x96, 0x03, 0x53, 0xa4, 0x54, 0xb7, 0x28, + 0x83, 0x96, 0x03, 0x53, 0xa4, 0x10, 0x83, 0x52, 0x12, 0xdf, 0xbe, 0x28, + 0x83, 0x96, 0x03, 0x53, 0x24, 0x14, 0xc1, 0x68, 0x83, 0x96, 0x03, 0x53, + 0x24, 0xd0, 0x83, 0x52, 0x5f, 0xc8, 0xa7, 0x40, 0x06, 0x30, 0x03, 0xd0, + 0xa7, 0x0d, 0xff, 0x7e, 0x03, 0x9d, 0xc5, 0xa8, 0x12, 0xc8, 0x3f, 0xb9, + 0x27, 0x44, 0xa5, 0x00, 0x83, 0x96, 0x24, 0x5c, 0xd3, 0xe8, 0x83, 0x52, + 0x9e, 0x15, 0x83, 0x52, 0x13, 0x08, 0x0f, 0x39, 0x3f, 0xfe, 0x84, 0x80, + 0x83, 0x93, 0x00, 0x48, 0xa1, 0xc0, 0x21, 0xc8, 0xa9, 0x00, 0x3f, 0x30, + 0xa9, 0x85, 0x29, 0x08, 0x83, 0x96, 0xa0, 0x80, 0x00, 0xb0, 0x83, 0x52, + 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa1, 0xc0, 0x08, 0xf0, 0xd3, 0xe1, + 0x8a, 0x51, 0x21, 0xdf, 0xf1, 0xe8, 0x83, 0x52, 0x03, 0x53, 0x19, 0x96, + 0xf4, 0xe8, 0x83, 0x52, 0x03, 0x53, 0x19, 0x52, 0xa1, 0x1f, 0xfa, 0x28, + 0x83, 0x52, 0x03, 0x53, 0x99, 0xd6, 0xfd, 0x68, 0x83, 0x52, 0x03, 0x53, + 0x99, 0x92, 0x83, 0x96, 0xa4, 0x9c, 0x0d, 0xa9, 0x6c, 0xb0, 0xa0, 0x80, + 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa1, 0xc0, + 0x0a, 0x30, 0xd3, 0xe1, 0x8a, 0x51, 0x04, 0xf0, 0x19, 0xa9, 0x60, 0x30, + 0xa0, 0x80, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, + 0xa1, 0xc0, 0x0a, 0x30, 0xd3, 0xe1, 0x8a, 0x51, 0x05, 0x30, 0x83, 0x96, + 0xa0, 0x80, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, + 0xa1, 0xc0, 0x0b, 0x70, 0xd3, 0xe1, 0x8a, 0x51, 0x25, 0x08, 0x83, 0x96, + 0xa0, 0x80, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, + 0xa1, 0xc0, 0x04, 0xf0, 0xd3, 0xe1, 0x8a, 0x51, 0x11, 0xc8, 0x83, 0x96, + 0xa0, 0x80, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, + 0xa1, 0xc0, 0x05, 0x30, 0xd3, 0xe1, 0x8a, 0x51, 0x10, 0x88, 0x83, 0x96, + 0xa0, 0x80, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, + 0xa1, 0xc0, 0x06, 0x30, 0xd3, 0xe1, 0x8a, 0x51, 0x83, 0x96, 0x00, 0xb0, + 0xa0, 0xc1, 0xa0, 0x0a, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, + 0xa1, 0xc0, 0x00, 0xb0, 0xd3, 0xe1, 0x8a, 0x51, 0x35, 0xb0, 0xa7, 0x40, + 0xa7, 0x0b, 0x56, 0xe9, 0x05, 0x30, 0x83, 0x96, 0x03, 0x53, 0xa0, 0x80, + 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa1, 0xc0, + 0x00, 0xb0, 0xd3, 0xe1, 0x8a, 0x51, 0x03, 0x30, 0xa8, 0xc0, 0x7d, 0x30, + 0xa7, 0x40, 0xa7, 0x0b, 0x69, 0xe9, 0xa8, 0x8b, 0x69, 0xe9, 0x83, 0x52, + 0x03, 0x53, 0x13, 0x1f, 0x73, 0x29, 0x19, 0x51, 0x74, 0xe9, 0x19, 0x10, + 0x05, 0x30, 0xa7, 0x40, 0xa7, 0x0b, 0x76, 0x29, 0x83, 0x52, 0x03, 0x53, + 0x13, 0x1f, 0x7e, 0x69, 0x99, 0xd5, 0x7f, 0xa9, 0x99, 0x94, 0x15, 0x70, + 0xa8, 0xc0, 0xc6, 0xb0, 0xa7, 0x40, 0xa7, 0x0b, 0x83, 0xa9, 0xa8, 0x8b, + 0x83, 0xa9, 0x00, 0x00, 0x0d, 0x70, 0x83, 0x96, 0x03, 0x53, 0xa0, 0x80, + 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa1, 0xc0, + 0x00, 0xb0, 0xd3, 0xe1, 0x8a, 0x51, 0x93, 0x1b, 0x95, 0xe9, 0x99, 0x92, + 0x19, 0x52, 0x83, 0x96, 0x00, 0xb0, 0xa0, 0xc1, 0xa0, 0x0a, 0x83, 0x52, + 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa1, 0xc0, 0x00, 0xb0, 0xd3, 0xe1, + 0x8a, 0x51, 0x13, 0x1f, 0xa9, 0xe9, 0x99, 0x91, 0xaa, 0xe9, 0x99, 0x50, + 0xe4, 0xb0, 0xa7, 0x40, 0xad, 0x29, 0xae, 0x29, 0xa7, 0x0b, 0xac, 0xe9, + 0xb1, 0xe9, 0x00, 0x00, 0x83, 0x52, 0x03, 0x53, 0x13, 0x1f, 0xb8, 0xe9, + 0x19, 0x95, 0xb9, 0x29, 0x19, 0x54, 0x03, 0x30, 0x83, 0x96, 0xa0, 0x80, + 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa1, 0xc0, + 0x00, 0xb0, 0xd3, 0xe1, 0x8a, 0x51, 0x05, 0x30, 0xa8, 0xc0, 0x26, 0x70, + 0xa7, 0x40, 0xa7, 0x0b, 0xc9, 0xe9, 0xa8, 0x8b, 0xc9, 0xe9, 0x00, 0x00, + 0x83, 0x52, 0x03, 0x53, 0x18, 0x56, 0x9e, 0x81, 0x08, 0x40, 0x83, 0x52, + 0xa6, 0x00, 0x83, 0x96, 0x21, 0xc8, 0x03, 0x59, 0xe0, 0xa9, 0x20, 0x88, + 0x83, 0x52, 0x88, 0x80, 0x26, 0x08, 0x80, 0x38, 0x86, 0xc0, 0x08, 0x40, + 0x20, 0x88, 0x83, 0x52, 0x88, 0x80, 0x26, 0x08, 0x80, 0x38, 0x85, 0xc0, + 0x08, 0x40, 0x95, 0x41, 0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, + 0x9a, 0x41, 0x9b, 0x81, 0x9c, 0x41, 0x9e, 0x81, 0x19, 0x54, 0x19, 0x95, + 0x18, 0x56, 0x8b, 0x41, 0xd4, 0x41, 0x02, 0xf0, 0x54, 0x02, 0x03, 0x18, + 0x19, 0xaa, 0x54, 0x08, 0x51, 0x3e, 0x84, 0x80, 0x83, 0x93, 0x80, 0x81, + 0x54, 0x08, 0x5d, 0xbe, 0x84, 0x80, 0x07, 0x70, 0x80, 0x40, 0x54, 0x08, + 0x32, 0x62, 0x8a, 0x51, 0x54, 0x08, 0x5d, 0xbe, 0x84, 0x80, 0x00, 0xce, + 0xf0, 0x39, 0x96, 0x00, 0x54, 0x9c, 0x12, 0x6a, 0x83, 0x52, 0x03, 0x53, + 0x18, 0x14, 0x15, 0xaa, 0x83, 0x52, 0x03, 0x53, 0x18, 0xd0, 0x18, 0x55, + 0x18, 0x11, 0xd4, 0x8a, 0xf5, 0x69, 0xd3, 0x81, 0x08, 0xf0, 0x53, 0x42, + 0x03, 0x18, 0x2f, 0x2a, 0x53, 0x48, 0x55, 0x7e, 0x84, 0x80, 0x04, 0xf0, + 0x83, 0x93, 0x80, 0x40, 0x53, 0x48, 0x55, 0x7e, 0x84, 0x80, 0x00, 0x48, + 0x96, 0x00, 0x53, 0x48, 0x95, 0x00, 0x98, 0x54, 0x98, 0x10, 0xd3, 0xca, + 0x1a, 0xaa, 0x10, 0xf0, 0x9b, 0x40, 0x08, 0x40, 0xb5, 0x40, 0x51, 0x3e, + 0x84, 0x80, 0x00, 0x48, 0xb4, 0x00, 0x23, 0x3e, 0x84, 0x80, 0x8a, 0x51, + 0x1d, 0xe5, 0x8a, 0x51, 0xb1, 0x00, 0x05, 0x30, 0x03, 0xd0, 0xb1, 0xcd, + 0xff, 0x7e, 0x03, 0x9d, 0x3e, 0x2a, 0x34, 0x08, 0x2d, 0x7e, 0x84, 0x80, + 0x8a, 0x51, 0x1d, 0xe5, 0x8a, 0x51, 0xb2, 0x00, 0x32, 0x87, 0x31, 0x04, + 0x01, 0x38, 0xb3, 0x40, 0x35, 0x48, 0x22, 0xfe, 0x84, 0x80, 0x33, 0x48, + 0x80, 0x40, 0x35, 0x48, 0x22, 0xfe, 0x84, 0x80, 0x00, 0x48, 0x83, 0x96, + 0xa2, 0xc0, 0x83, 0x52, 0x35, 0x48, 0x83, 0x96, 0xa3, 0x00, 0x0c, 0x30, + 0x92, 0xeb, 0x18, 0x12, 0x80, 0xf0, 0x9b, 0x40, 0x10, 0xf0, 0x9e, 0x40, + 0x13, 0x1f, 0x6a, 0xea, 0x83, 0x52, 0x03, 0x53, 0x18, 0x14, 0x6d, 0x2a, + 0x83, 0x52, 0x03, 0x53, 0x18, 0xd0, 0x92, 0x1f, 0x73, 0x2a, 0x83, 0x96, + 0x03, 0x53, 0xa4, 0x54, 0x76, 0x2a, 0x83, 0x96, 0x03, 0x53, 0xa4, 0x10, + 0x83, 0x52, 0x12, 0xdf, 0x7d, 0x6a, 0x83, 0x96, 0x03, 0x53, 0x24, 0x14, + 0x80, 0x2a, 0x83, 0x96, 0x03, 0x53, 0x24, 0xd0, 0x83, 0x52, 0x5f, 0xc8, + 0xb1, 0x00, 0x06, 0x30, 0x03, 0xd0, 0xb1, 0xcd, 0xff, 0x7e, 0x03, 0x9d, + 0x84, 0x6a, 0x12, 0xc8, 0x3f, 0xb9, 0x31, 0x04, 0xa5, 0x00, 0x83, 0x96, + 0x24, 0x5c, 0x92, 0xaa, 0x83, 0x52, 0x9e, 0x15, 0x83, 0x52, 0x13, 0x08, + 0x0f, 0x39, 0x3f, 0xfe, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xa1, 0xc0, + 0x21, 0xc8, 0xb3, 0x40, 0x3f, 0x30, 0xb3, 0xc5, 0x33, 0x48, 0x83, 0x96, + 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, + 0xa3, 0x00, 0x08, 0xf0, 0x92, 0xa3, 0x8a, 0x51, 0x21, 0xdf, 0xb0, 0xaa, + 0x83, 0x52, 0x03, 0x53, 0x19, 0x96, 0xb3, 0x2a, 0x83, 0x52, 0x03, 0x53, + 0x19, 0x52, 0xa1, 0x1f, 0xb9, 0x2a, 0x83, 0x52, 0x03, 0x53, 0x99, 0xd6, + 0xbc, 0x2a, 0x83, 0x52, 0x03, 0x53, 0x99, 0x92, 0x83, 0x96, 0xa4, 0x9c, + 0xcc, 0xea, 0x6c, 0xb0, 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, + 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x0a, 0x30, 0x92, 0xa3, 0x8a, 0x51, + 0x04, 0xf0, 0xd8, 0xea, 0x60, 0x30, 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, + 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x0a, 0x30, 0x92, 0xa3, + 0x8a, 0x51, 0x05, 0x30, 0x83, 0x96, 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, + 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x0b, 0x70, 0x92, 0xa3, + 0x8a, 0x51, 0x25, 0x08, 0x83, 0x96, 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, + 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x04, 0xf0, 0x92, 0xa3, + 0x8a, 0x51, 0x11, 0xc8, 0x83, 0x96, 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, + 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x05, 0x30, 0x92, 0xa3, + 0x8a, 0x51, 0x10, 0x88, 0x83, 0x96, 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, + 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x06, 0x30, 0x92, 0xa3, + 0x8a, 0x51, 0x83, 0x96, 0x00, 0xb0, 0xa2, 0x01, 0xa2, 0x4a, 0x83, 0x52, + 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x00, 0xb0, 0x92, 0xa3, + 0x8a, 0x51, 0x35, 0xb0, 0xb1, 0x00, 0xb1, 0xcb, 0x15, 0xeb, 0x05, 0x30, + 0x83, 0x96, 0x03, 0x53, 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, + 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x00, 0xb0, 0x92, 0xa3, 0x8a, 0x51, + 0x03, 0x30, 0xb2, 0x00, 0x7d, 0x30, 0xb1, 0x00, 0xb1, 0xcb, 0x28, 0xab, + 0xb2, 0xcb, 0x28, 0xab, 0x83, 0x52, 0x03, 0x53, 0x13, 0x1f, 0x32, 0xeb, + 0x19, 0x51, 0x33, 0x2b, 0x19, 0x10, 0x05, 0x30, 0xb1, 0x00, 0xb1, 0xcb, + 0x35, 0x2b, 0x83, 0x52, 0x03, 0x53, 0x13, 0x1f, 0x3d, 0x6b, 0x99, 0xd5, + 0x3e, 0x6b, 0x99, 0x94, 0x15, 0x70, 0xb2, 0x00, 0xc6, 0xb0, 0xb1, 0x00, + 0xb1, 0xcb, 0x42, 0xab, 0xb2, 0xcb, 0x42, 0xab, 0x00, 0x00, 0x0d, 0x70, + 0x83, 0x96, 0x03, 0x53, 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, + 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x00, 0xb0, 0x92, 0xa3, 0x8a, 0x51, + 0x93, 0x1b, 0x54, 0xeb, 0x99, 0x92, 0x19, 0x52, 0x83, 0x96, 0x00, 0xb0, + 0xa2, 0x01, 0xa2, 0x4a, 0x83, 0x52, 0x13, 0xdb, 0x01, 0xf0, 0x83, 0x96, + 0xa3, 0x00, 0x00, 0xb0, 0x92, 0xa3, 0x8a, 0x51, 0x13, 0x1f, 0x68, 0xeb, + 0x99, 0x91, 0x69, 0x2b, 0x99, 0x50, 0xe4, 0xb0, 0xb1, 0x00, 0x6c, 0x2b, + 0x6d, 0x6b, 0xb1, 0xcb, 0x6b, 0x6b, 0x70, 0xeb, 0x00, 0x00, 0x83, 0x52, + 0x03, 0x53, 0x13, 0x1f, 0x77, 0xab, 0x19, 0x95, 0x78, 0x2b, 0x19, 0x54, + 0x03, 0x30, 0x83, 0x96, 0xa2, 0xc0, 0x00, 0xb0, 0x83, 0x52, 0x13, 0xdb, + 0x01, 0xf0, 0x83, 0x96, 0xa3, 0x00, 0x00, 0xb0, 0x92, 0xa3, 0x8a, 0x51, + 0x05, 0x30, 0xb2, 0x00, 0x26, 0x70, 0xb1, 0x00, 0xb1, 0xcb, 0x88, 0xab, + 0xb2, 0xcb, 0x88, 0xab, 0x00, 0x00, 0x83, 0x52, 0x03, 0x53, 0x18, 0x56, + 0x9e, 0x81, 0x08, 0x40, 0x83, 0x52, 0xb0, 0xc0, 0x83, 0x96, 0x23, 0x08, + 0x03, 0x59, 0x9f, 0xab, 0x22, 0xc8, 0x83, 0x52, 0x88, 0x80, 0x30, 0xc8, + 0x80, 0x38, 0x86, 0xc0, 0x08, 0x40, 0x22, 0xc8, 0x83, 0x52, 0x88, 0x80, + 0x30, 0xc8, 0x80, 0x38, 0x85, 0xc0, 0x08, 0x40, 0x11, 0x30, 0xbe, 0x80, + 0x04, 0xf0, 0xa0, 0x80, 0x8a, 0x51, 0xe7, 0x21, 0x8a, 0x51, 0xbd, 0xc1, + 0x10, 0xf0, 0x3d, 0x82, 0x03, 0x18, 0xdd, 0xab, 0x3e, 0x88, 0x10, 0x7a, + 0x03, 0x59, 0xbb, 0xab, 0x8a, 0x51, 0x8a, 0xa5, 0x8a, 0x51, 0xbe, 0x80, + 0xb2, 0x2b, 0x3d, 0x88, 0x20, 0x38, 0x9b, 0x40, 0x3e, 0x88, 0x10, 0x7a, + 0x03, 0x9d, 0xc7, 0x6b, 0x8a, 0x51, 0x8a, 0xa5, 0x8a, 0x51, 0xbe, 0x80, + 0xbe, 0xab, 0x3e, 0x88, 0x11, 0xba, 0x03, 0x9d, 0xce, 0x6b, 0x30, 0x30, + 0x9b, 0x40, 0xdd, 0xab, 0x3d, 0x88, 0x3f, 0xfe, 0x84, 0x80, 0x3e, 0x88, + 0x83, 0x93, 0x80, 0x40, 0x3d, 0x88, 0x30, 0x78, 0x9b, 0x40, 0xbd, 0x0a, + 0xae, 0x6b, 0x8a, 0x51, 0x8a, 0xa5, 0x8a, 0x51, 0xbe, 0x80, 0x3e, 0x88, + 0x10, 0x7a, 0x03, 0x9d, 0xd9, 0x6b, 0x20, 0xf0, 0x9b, 0x40, 0x3e, 0x88, + 0x10, 0x7a, 0x03, 0x9d, 0xec, 0x6b, 0x8a, 0x51, 0x8a, 0xa5, 0x8a, 0x51, + 0xbe, 0x80, 0xe3, 0x6b, 0x3e, 0x88, 0xdf, 0xc0, 0x5f, 0xc8, 0x30, 0x78, + 0x9b, 0x40, 0x3e, 0x88, 0x10, 0x7a, 0x03, 0x59, 0xfa, 0xab, 0x8a, 0x51, + 0x8a, 0xa5, 0x8a, 0x51, 0xbe, 0x80, 0xf1, 0x6b, 0x20, 0xf0, 0x9b, 0x40, + 0x3e, 0x88, 0x10, 0x7a, 0x03, 0x9d, 0x05, 0x6c, 0x8a, 0x51, 0x8a, 0xa5, + 0x8a, 0x51, 0xbe, 0x80, 0xfc, 0xab, 0x3e, 0x88, 0xbc, 0x40, 0x30, 0x78, + 0x9b, 0x40, 0x3e, 0x88, 0x10, 0x7a, 0x03, 0x59, 0x12, 0x6c, 0x8a, 0x51, + 0x8a, 0xa5, 0x8a, 0x51, 0xbe, 0x80, 0x09, 0x6c, 0x40, 0xf0, 0x9b, 0x40, + 0x93, 0x5f, 0x1b, 0xec, 0x8a, 0x51, 0x5f, 0x22, 0x8a, 0x51, 0x40, 0xf0, + 0x9b, 0x40, 0xd3, 0x81, 0x08, 0xf0, 0x53, 0x42, 0x03, 0x18, 0x53, 0xec, + 0x53, 0x48, 0x95, 0x00, 0x85, 0x70, 0x0d, 0x02, 0x03, 0x5c, 0x33, 0xec, + 0x53, 0x48, 0x55, 0x7e, 0x84, 0x80, 0x0e, 0x70, 0x83, 0x93, 0x00, 0x42, + 0x03, 0x18, 0x33, 0xec, 0x53, 0x48, 0x55, 0x7e, 0x84, 0x80, 0x00, 0x8a, + 0x44, 0x6c, 0x34, 0x70, 0x0d, 0x02, 0x03, 0x18, 0x51, 0xac, 0x53, 0x48, + 0x55, 0x7e, 0x84, 0x80, 0x05, 0x30, 0x83, 0x93, 0x00, 0x42, 0x03, 0x5c, + 0x51, 0xac, 0x53, 0x48, 0x55, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xff, 0x7e, + 0xb6, 0x40, 0x53, 0x48, 0x55, 0x7e, 0x84, 0x80, 0x36, 0x48, 0x80, 0x40, + 0x53, 0x48, 0x55, 0x7e, 0x84, 0x80, 0x00, 0x48, 0x96, 0x00, 0x98, 0x54, + 0x98, 0x10, 0xd3, 0xca, 0x1c, 0xac, 0xd4, 0x41, 0x02, 0xf0, 0x54, 0x02, + 0x03, 0x18, 0xc7, 0x2c, 0x54, 0x9c, 0x5e, 0x2c, 0x83, 0x52, 0x03, 0x53, + 0x18, 0x14, 0x61, 0xac, 0x83, 0x52, 0x03, 0x53, 0x18, 0xd0, 0x54, 0x08, + 0x51, 0x3e, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x03, 0x9d, 0x6a, 0xec, + 0x64, 0x70, 0x6b, 0x2c, 0x73, 0xf0, 0xb7, 0x80, 0x0e, 0x08, 0x37, 0x82, + 0x03, 0x18, 0x7c, 0x2c, 0x54, 0x08, 0x5d, 0xbe, 0x84, 0x80, 0x0b, 0x70, + 0x00, 0x42, 0x03, 0x18, 0x7c, 0x2c, 0x54, 0x08, 0x5d, 0xbe, 0x84, 0x80, + 0x00, 0x8a, 0x8c, 0xac, 0x2d, 0xb0, 0x0e, 0x02, 0x03, 0x18, 0x9a, 0xec, + 0x54, 0x08, 0x5d, 0xbe, 0x84, 0x80, 0x08, 0xf0, 0x00, 0x42, 0x03, 0x5c, + 0x9a, 0xec, 0x54, 0x08, 0x5d, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xff, 0x7e, + 0xb6, 0x40, 0x54, 0x08, 0x5d, 0xbe, 0x84, 0x80, 0x36, 0x48, 0x80, 0x40, + 0x54, 0x08, 0x5d, 0xbe, 0x84, 0x80, 0x00, 0xce, 0xf0, 0x39, 0x96, 0x00, + 0x18, 0x55, 0x18, 0x11, 0x24, 0x30, 0x0f, 0x42, 0x03, 0x5c, 0xaa, 0xec, + 0x54, 0x08, 0x51, 0x3e, 0x84, 0x80, 0x09, 0x30, 0x00, 0x42, 0x03, 0x18, + 0xaa, 0xec, 0x54, 0x08, 0x51, 0x3e, 0x84, 0x80, 0x00, 0x8a, 0xb9, 0x2c, + 0x10, 0xf0, 0x0f, 0x42, 0x03, 0x18, 0xc5, 0xec, 0x54, 0x08, 0x51, 0x3e, + 0x84, 0x80, 0x80, 0x88, 0x03, 0x59, 0xc5, 0xec, 0x54, 0x08, 0x51, 0x3e, + 0x84, 0x80, 0x00, 0x48, 0xff, 0x7e, 0xb6, 0x40, 0x54, 0x08, 0x51, 0x3e, + 0x84, 0x80, 0x36, 0x48, 0x80, 0x40, 0x54, 0x08, 0x8a, 0x51, 0x32, 0x62, + 0x8a, 0x51, 0x98, 0x95, 0x98, 0x51, 0xd4, 0x8a, 0x54, 0xac, 0x51, 0x08, + 0x19, 0x3e, 0x84, 0x80, 0x8a, 0x51, 0x1d, 0xe5, 0x8a, 0x51, 0xba, 0x40, + 0x06, 0x30, 0xe0, 0xc0, 0x5d, 0x88, 0xf9, 0xfe, 0x8a, 0x51, 0x99, 0xe5, + 0x8a, 0x51, 0xbb, 0x80, 0x3a, 0xc7, 0x97, 0x40, 0x52, 0x08, 0x19, 0x3e, + 0x84, 0x80, 0x8a, 0x51, 0x1d, 0xe5, 0x8a, 0x51, 0xba, 0x40, 0x06, 0x30, + 0xe0, 0xc0, 0x5e, 0x88, 0xf9, 0xfe, 0x8a, 0x51, 0x99, 0xe5, 0x8a, 0x51, + 0xbb, 0x80, 0x3a, 0xc7, 0x9c, 0x00, 0x3c, 0x48, 0x95, 0x00, 0x0d, 0x08, + 0xb6, 0x40, 0x03, 0xd0, 0xb6, 0xcc, 0x03, 0xd0, 0xb6, 0xcc, 0x03, 0xd0, + 0xb6, 0xcc, 0x36, 0x48, 0x01, 0xbe, 0x84, 0x80, 0x8a, 0x51, 0x1d, 0xe5, + 0x8a, 0x51, 0xb9, 0x40, 0x06, 0x30, 0xe0, 0xc0, 0x3c, 0x48, 0x55, 0x7e, + 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xfc, 0xfe, 0x8a, 0x51, 0x99, 0xe5, + 0x8a, 0x51, 0xb8, 0x00, 0x01, 0xf0, 0xb6, 0x40, 0x3c, 0x8a, 0x0c, 0xad, + 0x03, 0xd0, 0xb6, 0x0d, 0xff, 0x7e, 0x03, 0x9d, 0x0a, 0xad, 0x36, 0x48, + 0x14, 0x05, 0x03, 0x59, 0x16, 0xed, 0x38, 0x08, 0x1c, 0x87, 0x18, 0xad, + 0x38, 0x08, 0x17, 0xc7, 0xb6, 0x40, 0x39, 0x48, 0x36, 0xc7, 0x9a, 0x00, + 0x14, 0x6c, 0x05, 0x30, 0x8a, 0xc0, 0x04, 0x88, 0x84, 0x0a, 0x82, 0x47, + 0x00, 0xf4, 0x00, 0xf4, 0x00, 0xf4, 0x00, 0xf4, 0x00, 0xf4, 0x00, 0xf4, + 0x02, 0x34, 0x04, 0x34, 0x05, 0x74, 0x06, 0x74, 0x07, 0xb4, 0x08, 0x34, + 0x09, 0x74, 0x0a, 0x74, 0x0a, 0x74, 0x0b, 0xb4, 0x0b, 0xb4, 0x0c, 0x74, + 0x0d, 0xb4, 0x0d, 0xb4, 0x0e, 0xb4, 0x0e, 0xb4, 0x0e, 0xb4, 0x0f, 0xf4, + 0x0f, 0xf4, 0x00, 0xf4, 0x06, 0x74, 0x0c, 0x74, 0x12, 0x74, 0x18, 0x74, + 0x1e, 0xf4, 0x24, 0x74, 0x2a, 0xb4, 0x30, 0x74, 0x36, 0xf4, 0x01, 0x34, + 0x01, 0x34, 0x01, 0x34, 0x02, 0x34, 0x03, 0x74, 0x04, 0x34, 0x05, 0x74, + 0x05, 0x74, 0x06, 0x74, 0x06, 0x74, 0x0f, 0xf4, 0x0c, 0x74, 0x09, 0x74, + 0x09, 0x74, 0x09, 0x74, 0x0c, 0x74, 0x0f, 0xf4, 0x0c, 0x74, 0x0f, 0xf4, + 0x0c, 0x74, 0x83, 0x93, 0x51, 0x70, 0x84, 0x80, 0x60, 0x30, 0x8a, 0x51, + 0xa7, 0x25, 0x8a, 0x51, 0x83, 0x96, 0xa4, 0x01, 0x83, 0x52, 0x38, 0x70, + 0xbf, 0xc0, 0x3a, 0xb0, 0xc0, 0x80, 0x3c, 0xb0, 0xc1, 0xc0, 0x78, 0xb0, + 0xc2, 0xc0, 0x7a, 0xf0, 0xc3, 0x00, 0x7c, 0xf0, 0xc4, 0xc0, 0x7d, 0x30, + 0xc5, 0x00, 0x7f, 0x70, 0xc6, 0x00, 0xb9, 0xf0, 0xc7, 0x40, 0xba, 0xf0, + 0xc8, 0xc0, 0xbb, 0x30, 0xc9, 0x00, 0xfa, 0x30, 0xca, 0x00, 0xfb, 0x70, + 0xcb, 0x40, 0xfc, 0x30, 0xcc, 0x00, 0xfd, 0x70, 0xcd, 0x40, 0xff, 0xb0, + 0xce, 0x40, 0x00, 0xb0, 0xcf, 0x80, 0x01, 0xf0, 0xd0, 0xc0, 0x83, 0x01, + 0x8a, 0x51, 0xa6, 0x2b, 0x50, 0xc8, 0xb1, 0x00, 0x4f, 0x88, 0xb0, 0xc0, + 0x31, 0x08, 0x30, 0x06, 0x03, 0x59, 0x97, 0x6d, 0x14, 0xc8, 0xb0, 0xc0, + 0x14, 0xc8, 0xb1, 0x00, 0x8e, 0x2d, 0x31, 0x08, 0x08, 0x40, 0xb1, 0x00, + 0xb0, 0x01, 0x60, 0xc8, 0x31, 0x58, 0xb0, 0x87, 0x03, 0xd0, 0xe0, 0x8d, + 0x03, 0xd0, 0xb1, 0x8c, 0xb1, 0x48, 0x03, 0x9d, 0x9b, 0x6d, 0x30, 0xc8, + 0x08, 0x40, 0x64, 0xc0, 0x80, 0x81, 0x84, 0x0a, 0x04, 0xc6, 0x03, 0x59, + 0x00, 0xf4, 0x04, 0xc6, 0xa8, 0xed, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, +}; + +/* arbiter firmware */ + +const uint8_t g_sx1301_arb_fw[SX1301_MCU_FW_SIZE] = +{ + 0x8a, 0x51, 0xae, 0x6e, 0x00, 0xb0, 0x8a, 0xc0, 0x04, 0x88, 0x84, 0x0a, + 0x82, 0x47, 0x00, 0xf4, 0x07, 0xb4, 0x06, 0x74, 0x05, 0x74, 0x04, 0x34, + 0x03, 0x74, 0x02, 0x34, 0x01, 0x34, 0x00, 0xf4, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0x64, 0xc0, 0x80, 0x81, + 0x84, 0x0a, 0x04, 0xc6, 0x03, 0x59, 0x00, 0xf4, 0x04, 0xc6, 0xa7, 0x6e, + 0xd9, 0x81, 0x83, 0x93, 0x22, 0x30, 0x84, 0x80, 0x59, 0xb0, 0x8a, 0x51, + 0xa6, 0xe6, 0x83, 0x01, 0x8a, 0x51, 0xb8, 0x2e, 0x01, 0xf0, 0xa0, 0x80, + 0x8a, 0x51, 0x01, 0x67, 0x8a, 0x51, 0x0d, 0x58, 0xd4, 0x2e, 0xd3, 0x81, + 0x59, 0x94, 0x53, 0x48, 0x8a, 0x51, 0xdb, 0x66, 0x8a, 0x51, 0x83, 0x52, + 0x03, 0x53, 0xd9, 0x1c, 0xcc, 0x2e, 0x8a, 0x51, 0x85, 0xe7, 0x8a, 0x51, + 0x0d, 0x58, 0xbd, 0xae, 0x08, 0xf0, 0xd3, 0xca, 0x53, 0x42, 0x03, 0x18, + 0xbd, 0xae, 0xc0, 0xae, 0x59, 0xdc, 0xbd, 0xae, 0x8a, 0x51, 0x32, 0xe7, + 0x8a, 0x51, 0x59, 0x50, 0xbd, 0xae, 0xdb, 0x80, 0xd9, 0x90, 0x5b, 0x88, + 0x96, 0x00, 0x15, 0x70, 0xda, 0x40, 0xda, 0x0b, 0xe1, 0x2e, 0x83, 0x52, + 0x03, 0x53, 0x8d, 0xdc, 0x08, 0x40, 0xd9, 0xd4, 0x15, 0x54, 0x15, 0x70, + 0xda, 0x40, 0xda, 0x0b, 0xeb, 0xae, 0x83, 0x52, 0x03, 0x53, 0x0d, 0xdd, + 0xed, 0xae, 0x10, 0x88, 0xd4, 0x00, 0x11, 0xc8, 0xd5, 0x40, 0x0f, 0x48, + 0xd7, 0x80, 0x0e, 0x08, 0xd2, 0x00, 0x12, 0xc8, 0xd6, 0x40, 0x15, 0x10, + 0x15, 0x70, 0xda, 0x40, 0xda, 0x0b, 0xfe, 0xee, 0x08, 0x40, 0x95, 0x41, + 0x96, 0x41, 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9a, 0x41, 0x9b, 0x81, + 0x9c, 0x41, 0x9e, 0x81, 0xd8, 0x41, 0x08, 0xf0, 0x58, 0x02, 0x03, 0x18, + 0x29, 0x2f, 0x58, 0x08, 0x32, 0x3e, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08, + 0x3a, 0x7e, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08, 0x4a, 0x3e, 0x84, 0x80, + 0x80, 0x81, 0x58, 0x08, 0x22, 0xfe, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08, + 0x42, 0xfe, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08, 0x2a, 0x3e, 0x84, 0x80, + 0x80, 0x81, 0xd8, 0x8a, 0x0b, 0x2f, 0xd4, 0x41, 0xd5, 0x81, 0xd7, 0xc1, + 0xd2, 0x41, 0xd6, 0x81, 0x59, 0x50, 0xd9, 0x90, 0xa1, 0x01, 0x08, 0x40, + 0xd8, 0x41, 0x08, 0xf0, 0x58, 0x02, 0x03, 0x18, 0x08, 0x40, 0x58, 0x08, + 0x2a, 0x3e, 0x84, 0x80, 0x83, 0x93, 0x00, 0xcb, 0x83, 0x2f, 0x58, 0x08, + 0x2a, 0x3e, 0x84, 0x80, 0x80, 0x81, 0x58, 0x08, 0x42, 0xfe, 0x84, 0x80, + 0x00, 0x48, 0x97, 0x40, 0x58, 0x08, 0x22, 0xfe, 0x84, 0x80, 0x00, 0x48, + 0x98, 0xc0, 0x58, 0x08, 0x32, 0x3e, 0x84, 0x80, 0x00, 0x48, 0x99, 0x00, + 0x58, 0x08, 0x3a, 0x7e, 0x84, 0x80, 0x00, 0x48, 0x9a, 0x00, 0x58, 0x08, + 0x01, 0xbe, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x9b, 0x40, + 0x58, 0x08, 0x4a, 0x3e, 0x84, 0x80, 0x00, 0x48, 0x9c, 0x00, 0x95, 0x94, + 0x15, 0x70, 0xda, 0x40, 0xda, 0x0b, 0x64, 0x2f, 0x83, 0x52, 0x03, 0x53, + 0x95, 0x50, 0x15, 0x70, 0xda, 0x40, 0xda, 0x0b, 0x6b, 0xaf, 0x01, 0xf0, + 0x83, 0x52, 0x03, 0x53, 0xda, 0x40, 0x58, 0x08, 0x01, 0xbe, 0x84, 0x80, + 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x01, 0xbe, 0x7b, 0xef, 0x03, 0xd0, + 0xda, 0x0d, 0xff, 0x7e, 0x03, 0x9d, 0x79, 0xaf, 0x5a, 0x48, 0x13, 0x45, + 0x03, 0x59, 0x6d, 0xaf, 0xa1, 0x4a, 0xd8, 0x8a, 0x33, 0x6f, 0x59, 0x91, + 0xd8, 0x41, 0x08, 0xf0, 0x58, 0x02, 0x03, 0x18, 0xbd, 0xef, 0x0a, 0x30, + 0x57, 0x82, 0x03, 0x18, 0x91, 0x2f, 0x59, 0xd5, 0xb9, 0xaf, 0x01, 0xf0, + 0xda, 0x40, 0x58, 0x08, 0x01, 0xbe, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, + 0x8a, 0x51, 0x01, 0xbe, 0x9d, 0xaf, 0x03, 0xd0, 0xda, 0x0d, 0xff, 0x7e, + 0x03, 0x9d, 0x9b, 0xaf, 0x5a, 0x48, 0x13, 0x45, 0x03, 0x9d, 0xaa, 0x6f, + 0x58, 0x08, 0x2a, 0x3e, 0x84, 0x80, 0x83, 0x93, 0x00, 0xcb, 0xb9, 0xaf, + 0x58, 0x08, 0x42, 0xfe, 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0x56, 0x86, + 0x03, 0x9d, 0xb9, 0xaf, 0x58, 0x08, 0x22, 0xfe, 0x84, 0x80, 0x00, 0x48, + 0x52, 0x46, 0x03, 0x59, 0x8f, 0xaf, 0x59, 0xd9, 0xbd, 0xef, 0xd8, 0x8a, + 0x87, 0x6f, 0x59, 0xd9, 0x08, 0x40, 0xd8, 0x41, 0x08, 0xf0, 0x58, 0x02, + 0x03, 0x18, 0x08, 0x40, 0x01, 0xf0, 0xda, 0x40, 0x58, 0x08, 0x01, 0xbe, + 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x01, 0xbe, 0xd0, 0x2f, + 0x03, 0xd0, 0xda, 0x0d, 0xff, 0x7e, 0x03, 0x9d, 0xce, 0xaf, 0x5a, 0x48, + 0x13, 0x45, 0x03, 0x9d, 0xfe, 0x2f, 0x58, 0x08, 0x2a, 0x3e, 0x84, 0x80, + 0x83, 0x93, 0x00, 0x48, 0x03, 0x9d, 0xfe, 0x2f, 0x58, 0x08, 0x32, 0x3e, + 0x84, 0x80, 0x54, 0x08, 0x80, 0x40, 0x58, 0x08, 0x3a, 0x7e, 0x84, 0x80, + 0x55, 0x48, 0x80, 0x40, 0x58, 0x08, 0x4a, 0x3e, 0x84, 0x80, 0x57, 0x88, + 0x80, 0x40, 0x58, 0x08, 0x22, 0xfe, 0x84, 0x80, 0x52, 0x08, 0x80, 0x40, + 0x58, 0x08, 0x42, 0xfe, 0x84, 0x80, 0x56, 0x48, 0x80, 0x40, 0x58, 0x08, + 0x2a, 0x3e, 0x84, 0x80, 0x01, 0xf0, 0x80, 0x40, 0x59, 0xd5, 0x08, 0x40, + 0xd8, 0x8a, 0xc0, 0xef, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, +}; + +/* calibration firmware */ + +const uint8_t g_sx1301_cal_fw[SX1301_MCU_FW_SIZE] = +{ + 0x8a, 0x51, 0x6f, 0x28, 0x00, 0xb0, 0x8a, 0xc0, 0x04, 0x88, 0x84, 0x0a, + 0x82, 0x47, 0x00, 0xf4, 0x18, 0x74, 0x1c, 0xb4, 0x1e, 0xf4, 0x20, 0x34, + 0x22, 0x74, 0x23, 0xb4, 0x24, 0x74, 0x25, 0xb4, 0x26, 0xb4, 0x27, 0xf4, + 0x28, 0x74, 0x28, 0x74, 0x29, 0xb4, 0x2a, 0xb4, 0x2a, 0xb4, 0x2b, 0xf4, + 0x2b, 0xf4, 0x2c, 0xb4, 0x2c, 0xb4, 0x2d, 0xf4, 0x2d, 0xf4, 0x2d, 0xf4, + 0x2e, 0xf4, 0x2e, 0xf4, 0x2e, 0xf4, 0x2f, 0x34, 0x2f, 0x34, 0x2f, 0x34, + 0x30, 0x74, 0x30, 0x74, 0x00, 0xf4, 0x00, 0xf4, 0x06, 0x74, 0x0a, 0x74, + 0x0c, 0x74, 0x0e, 0xb4, 0x10, 0x34, 0x11, 0x74, 0x12, 0x74, 0x13, 0xb4, + 0x14, 0x74, 0x15, 0xb4, 0x16, 0xb4, 0x16, 0xb4, 0x17, 0xf4, 0x18, 0x74, + 0x0f, 0xf4, 0x0c, 0x74, 0x09, 0x74, 0x09, 0x74, 0x09, 0x74, 0x0c, 0x74, + 0x0f, 0xf4, 0x0c, 0x74, 0x0f, 0xf4, 0x0c, 0x74, 0x01, 0x34, 0x01, 0x34, + 0x01, 0x34, 0x02, 0x34, 0x03, 0x74, 0x04, 0x34, 0x05, 0x74, 0x05, 0x74, + 0x06, 0x74, 0x06, 0x74, 0x02, 0x34, 0x02, 0x34, 0x03, 0x74, 0x04, 0x34, + 0x05, 0x74, 0x06, 0x74, 0x07, 0xb4, 0x40, 0x34, 0x20, 0x34, 0x10, 0x34, + 0x08, 0x34, 0x04, 0x34, 0x02, 0x34, 0x01, 0x34, 0x06, 0x74, 0x06, 0x74, + 0x07, 0xb4, 0x07, 0xb4, 0x07, 0xb4, 0x10, 0x34, 0x08, 0x34, 0x04, 0x34, + 0x02, 0x34, 0x01, 0x34, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0x64, 0xc0, 0x80, 0x81, 0x84, 0x0a, 0x04, 0xc6, 0x03, 0x59, + 0x00, 0xf4, 0x04, 0xc6, 0x68, 0x68, 0xe6, 0x81, 0xe7, 0xc1, 0x83, 0x93, + 0x55, 0xb0, 0x84, 0x80, 0x66, 0xb0, 0x8a, 0x51, 0x67, 0xa0, 0x8a, 0x51, + 0xda, 0xf0, 0x84, 0x80, 0xee, 0x30, 0x8a, 0x51, 0x67, 0xa0, 0x8a, 0x51, + 0x83, 0xd7, 0xa0, 0x30, 0x84, 0x80, 0xae, 0xf0, 0x8a, 0x51, 0x67, 0xa0, + 0x83, 0x96, 0x01, 0xf0, 0xee, 0x80, 0x83, 0x52, 0x01, 0xf0, 0xe8, 0x00, + 0x07, 0x70, 0xe9, 0x40, 0x06, 0x30, 0xea, 0x40, 0x0f, 0xb0, 0xeb, 0x80, + 0x01, 0xf0, 0xec, 0x40, 0x05, 0x30, 0xed, 0x80, 0x02, 0xf0, 0xee, 0x80, + 0x0e, 0x70, 0xef, 0xc0, 0x83, 0x01, 0x8a, 0x51, 0x4c, 0xac, 0xa3, 0x41, + 0x23, 0x08, 0xea, 0xbe, 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, 0x00, 0xb0, + 0x22, 0x21, 0x8a, 0x51, 0x83, 0x93, 0x80, 0x40, 0x23, 0x08, 0xe0, 0x3e, + 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, 0x01, 0xf0, 0x22, 0x21, 0x8a, 0x51, + 0x80, 0x40, 0x23, 0x08, 0xde, 0xfe, 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, + 0x02, 0xf0, 0x22, 0x21, 0x8a, 0x51, 0x80, 0x40, 0x23, 0x08, 0xda, 0xbe, + 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, 0x03, 0x30, 0x22, 0x21, 0x8a, 0x51, + 0x80, 0x40, 0x23, 0x08, 0xe8, 0x7e, 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, + 0x04, 0xf0, 0x22, 0x21, 0x8a, 0x51, 0x80, 0x40, 0x23, 0x08, 0xe6, 0xbe, + 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, 0x05, 0x30, 0x22, 0x21, 0x8a, 0x51, + 0x80, 0x40, 0x23, 0x08, 0xe4, 0x7e, 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, + 0x06, 0x30, 0x22, 0x21, 0x8a, 0x51, 0x80, 0x40, 0x23, 0x08, 0xac, 0x7e, + 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, 0x08, 0xf0, 0x22, 0x21, 0x8a, 0x51, + 0x83, 0xd7, 0x80, 0x40, 0x23, 0x08, 0xa8, 0x3e, 0x84, 0x80, 0x23, 0x08, + 0xa1, 0xc0, 0x0a, 0x30, 0x22, 0x21, 0x8a, 0x51, 0x80, 0x40, 0x23, 0x08, + 0xaa, 0x7e, 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, 0x0b, 0x70, 0x22, 0x21, + 0x8a, 0x51, 0x80, 0x40, 0x23, 0x08, 0xa2, 0x3e, 0x84, 0x80, 0x23, 0x08, + 0xa1, 0xc0, 0x0c, 0x30, 0x22, 0x21, 0x8a, 0x51, 0x80, 0x40, 0x23, 0x08, + 0xa4, 0x3e, 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, 0x0d, 0x70, 0x22, 0x21, + 0x8a, 0x51, 0x80, 0x40, 0x23, 0x08, 0xa6, 0x7e, 0x84, 0x80, 0x23, 0x08, + 0xa1, 0xc0, 0x0e, 0x70, 0x22, 0x21, 0x8a, 0x51, 0x80, 0x40, 0x23, 0x08, + 0xa0, 0xfe, 0x84, 0x80, 0x23, 0x08, 0xa1, 0xc0, 0x10, 0xf0, 0x22, 0x21, + 0x8a, 0x51, 0x80, 0x40, 0x02, 0xf0, 0xa3, 0x8a, 0x23, 0x02, 0x03, 0x18, + 0x08, 0x40, 0x9c, 0xa8, 0xa2, 0xc0, 0x21, 0xc8, 0x03, 0x59, 0x2b, 0xe9, + 0x22, 0xc8, 0x86, 0xc0, 0x22, 0xc8, 0x86, 0xc0, 0x2f, 0x29, 0x22, 0xc8, + 0x85, 0xc0, 0x22, 0xc8, 0x85, 0xc0, 0x08, 0x88, 0x08, 0x40, 0xb4, 0x00, + 0x34, 0x8e, 0xf0, 0x39, 0x0c, 0x78, 0xb8, 0x00, 0xbb, 0xc1, 0x38, 0x08, + 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x54, 0x70, 0xa7, 0x23, 0x8a, 0x51, + 0x38, 0x08, 0x02, 0xbe, 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x54, 0x70, + 0xa7, 0x23, 0x8a, 0x51, 0x02, 0xf0, 0xa1, 0xc0, 0x54, 0x70, 0x30, 0x24, + 0x8a, 0x51, 0xe5, 0x40, 0xe5, 0x9f, 0x46, 0xa9, 0x02, 0xf0, 0xa1, 0xc0, + 0x57, 0xf0, 0x30, 0x24, 0x8a, 0x51, 0xb5, 0x40, 0x02, 0xf0, 0xa1, 0xc0, + 0x58, 0x70, 0x30, 0x24, 0x8a, 0x51, 0xb6, 0x40, 0x3b, 0x88, 0x25, 0x3e, + 0x84, 0x80, 0x35, 0x48, 0x44, 0x24, 0x8a, 0x51, 0xa4, 0xc0, 0x36, 0x48, + 0x44, 0x24, 0x8a, 0x51, 0x24, 0x47, 0x83, 0x93, 0x80, 0x40, 0x0f, 0xb0, + 0xbb, 0x0a, 0x3b, 0x82, 0x03, 0x5c, 0x37, 0x29, 0xba, 0x81, 0x25, 0x08, + 0xb9, 0x40, 0xb7, 0xc1, 0xbb, 0xc1, 0x3b, 0x88, 0x25, 0x3e, 0x84, 0x80, + 0x39, 0x48, 0x00, 0x42, 0x03, 0x18, 0x7f, 0xa9, 0x3b, 0x88, 0x25, 0x3e, + 0x84, 0x80, 0x00, 0x48, 0xb9, 0x40, 0x3b, 0x88, 0xb7, 0x80, 0x0f, 0xb0, + 0xbb, 0x0a, 0x3b, 0x82, 0x03, 0x5c, 0x71, 0xe9, 0x37, 0x88, 0x25, 0x3e, + 0x84, 0x80, 0xff, 0xb0, 0x80, 0x40, 0x08, 0xf0, 0xba, 0xca, 0x3a, 0x42, + 0x03, 0x5c, 0x6d, 0x29, 0x39, 0x48, 0x08, 0x40, 0xb2, 0x00, 0xc9, 0x41, + 0xca, 0x41, 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x53, 0xb0, 0xa7, 0x23, + 0xc7, 0x81, 0x49, 0x08, 0xb3, 0x40, 0x4a, 0x08, 0xbc, 0x40, 0x47, 0x48, + 0x4a, 0x3e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x49, 0x87, + 0xb4, 0x00, 0x47, 0x48, 0x4a, 0x3e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, + 0x8a, 0x51, 0x4a, 0x87, 0xbd, 0x80, 0x47, 0x48, 0x4a, 0x3e, 0x84, 0x80, + 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x49, 0x87, 0xb5, 0x40, 0x47, 0x48, + 0x4a, 0x3e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x4a, 0x02, + 0xbe, 0x80, 0x47, 0x48, 0x4a, 0x3e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, + 0x8a, 0x51, 0x49, 0x02, 0xb6, 0x40, 0x47, 0x48, 0x4a, 0x3e, 0x84, 0x80, + 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x4a, 0x87, 0xbf, 0xc0, 0x47, 0x48, + 0x4a, 0x3e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x49, 0x02, + 0xb7, 0x80, 0x47, 0x48, 0x4a, 0x3e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, + 0x8a, 0x51, 0x4a, 0x02, 0xc0, 0x80, 0xc8, 0x01, 0x48, 0xc8, 0x33, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x27, 0xb0, 0xa2, 0x01, 0xa2, 0x4a, + 0xa7, 0x23, 0x8a, 0x51, 0x48, 0xc8, 0x3c, 0x7e, 0x84, 0x80, 0x00, 0x48, + 0xa1, 0xc0, 0x28, 0x30, 0xa2, 0x01, 0xa2, 0x4a, 0xa7, 0x23, 0x47, 0x48, + 0x43, 0x3e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0xd2, 0xe3, + 0x8a, 0x51, 0xc6, 0x00, 0x48, 0xc8, 0x03, 0x59, 0x01, 0x2a, 0x45, 0x08, + 0x46, 0x02, 0x03, 0x18, 0x0d, 0xaa, 0x46, 0x08, 0xc5, 0x00, 0x48, 0xc8, + 0x33, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xc9, 0x00, 0x48, 0xc8, 0x3c, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0xca, 0x00, 0x05, 0x30, 0xc8, 0x4a, 0x48, 0xc2, + 0x03, 0x5c, 0xde, 0x69, 0x07, 0x70, 0xc7, 0xca, 0x47, 0x42, 0x49, 0x08, + 0xb3, 0x40, 0x4a, 0x08, 0xbc, 0x40, 0x03, 0x5c, 0x9d, 0x29, 0x49, 0x4a, + 0xb4, 0x00, 0x4a, 0x4a, 0xbd, 0x80, 0x49, 0x4a, 0xb5, 0x40, 0x4a, 0x43, + 0xbe, 0x80, 0x49, 0x43, 0xb6, 0x40, 0x4a, 0x4a, 0xbf, 0xc0, 0x49, 0x43, + 0xb7, 0x80, 0x4a, 0x43, 0xc0, 0x80, 0x49, 0x08, 0xb8, 0x00, 0x4a, 0x4a, + 0xc1, 0xc0, 0x49, 0x08, 0xb9, 0x40, 0x4a, 0x43, 0xc2, 0xc0, 0x49, 0x4a, + 0xba, 0x40, 0x4a, 0x08, 0xc3, 0x00, 0x49, 0x43, 0xbb, 0x80, 0x4a, 0x08, + 0xc4, 0xc0, 0xc8, 0x01, 0x48, 0xc8, 0x33, 0x7e, 0x84, 0x80, 0x00, 0x48, + 0xa1, 0xc0, 0x27, 0xb0, 0xa2, 0x01, 0xa2, 0x4a, 0xa7, 0x23, 0x8a, 0x51, + 0x48, 0xc8, 0x3c, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x28, 0x30, + 0xa2, 0x01, 0xa2, 0x4a, 0xa7, 0x23, 0x8a, 0x51, 0x07, 0x70, 0xd2, 0xe3, + 0x8a, 0x51, 0xc6, 0x00, 0x48, 0xc8, 0x03, 0x59, 0x5b, 0x2a, 0x45, 0x08, + 0x46, 0x02, 0x03, 0x18, 0x67, 0x2a, 0x46, 0x08, 0xc5, 0x00, 0x48, 0xc8, + 0x33, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xc9, 0x00, 0x48, 0xc8, 0x3c, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0xca, 0x00, 0x09, 0x30, 0xc8, 0x4a, 0x48, 0xc2, + 0x03, 0x5c, 0x3c, 0xea, 0x49, 0x08, 0xa1, 0xc0, 0x27, 0xb0, 0xa2, 0x01, + 0xa2, 0x4a, 0xa7, 0x23, 0x8a, 0x51, 0x4a, 0x08, 0xa1, 0xc0, 0x28, 0x30, + 0xa2, 0x01, 0xa2, 0x4a, 0xa7, 0x6b, 0xb3, 0x40, 0xcb, 0x81, 0xcc, 0x41, + 0x33, 0xcb, 0x82, 0x6a, 0x74, 0xb0, 0xc7, 0x40, 0x75, 0xf0, 0x85, 0xaa, + 0x72, 0xb0, 0xc7, 0x40, 0x73, 0xf0, 0xc8, 0xc0, 0x33, 0x48, 0xa1, 0xc0, + 0x02, 0xf0, 0xa2, 0xc0, 0x53, 0xb0, 0xa7, 0x23, 0xca, 0x41, 0x4b, 0x48, + 0xb5, 0x40, 0x4c, 0x08, 0xbe, 0x80, 0x4a, 0x08, 0x56, 0x7e, 0x84, 0x80, + 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x4b, 0xc7, 0xb6, 0x40, 0x4a, 0x08, + 0x56, 0x7e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x4c, 0x87, + 0xbf, 0xc0, 0x4a, 0x08, 0x56, 0x7e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, + 0x8a, 0x51, 0x4b, 0xc7, 0xb7, 0x80, 0x4a, 0x08, 0x56, 0x7e, 0x84, 0x80, + 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x4c, 0x02, 0xc0, 0x80, 0x4a, 0x08, + 0x56, 0x7e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x4b, 0x42, + 0xb8, 0x00, 0x4a, 0x08, 0x56, 0x7e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, + 0x8a, 0x51, 0x4c, 0x87, 0xc1, 0xc0, 0x4a, 0x08, 0x56, 0x7e, 0x84, 0x80, + 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x4b, 0x42, 0xb9, 0x40, 0x4a, 0x08, + 0x56, 0x7e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0x4c, 0x02, + 0xc2, 0xc0, 0xcd, 0x81, 0x1f, 0xf0, 0xa1, 0xc0, 0xe0, 0x70, 0xa2, 0xc0, + 0x4d, 0x48, 0x35, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xbb, 0x63, 0x8a, 0x51, + 0xb2, 0x00, 0x4d, 0x48, 0x35, 0x7e, 0x84, 0x80, 0x32, 0x08, 0x80, 0x40, + 0x1f, 0xf0, 0xa1, 0xc0, 0xe0, 0x70, 0xa2, 0xc0, 0x4d, 0x48, 0x3e, 0xbe, + 0x84, 0x80, 0x00, 0x48, 0xbb, 0x63, 0x8a, 0x51, 0xb2, 0x00, 0x4d, 0x48, + 0x3e, 0xbe, 0x84, 0x80, 0x32, 0x08, 0x80, 0x40, 0x4d, 0x48, 0x35, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0xa2, 0x01, 0x47, 0x48, 0xa7, 0x23, + 0x8a, 0x51, 0x4d, 0x48, 0x3e, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, + 0xa2, 0x01, 0x48, 0xc8, 0xa7, 0x23, 0x4a, 0x08, 0x51, 0x3e, 0x84, 0x80, + 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x51, 0xd2, 0xe3, 0x8a, 0x51, 0xc9, 0x00, + 0x4d, 0x48, 0x03, 0x59, 0x13, 0xeb, 0x34, 0x08, 0x49, 0x02, 0x03, 0x18, + 0x1f, 0x6b, 0x49, 0x08, 0xb4, 0x00, 0x4d, 0x48, 0x35, 0x7e, 0x84, 0x80, + 0x00, 0x48, 0xcb, 0x40, 0x4d, 0x48, 0x3e, 0xbe, 0x84, 0x80, 0x00, 0x48, + 0xcc, 0x00, 0x05, 0x30, 0xcd, 0xca, 0x4d, 0x42, 0x03, 0x5c, 0xd2, 0xea, + 0x05, 0x30, 0xca, 0x8a, 0x4a, 0x02, 0x4b, 0x48, 0xb5, 0x40, 0x4c, 0x08, + 0xbe, 0x80, 0x03, 0x5c, 0x91, 0xaa, 0x4b, 0x8a, 0xb6, 0x40, 0x4c, 0x4a, + 0xbf, 0xc0, 0x4b, 0x8a, 0xb7, 0x80, 0x4c, 0x43, 0xc0, 0x80, 0x4b, 0x83, + 0xb8, 0x00, 0x4c, 0x4a, 0xc1, 0xc0, 0x4b, 0x83, 0xb9, 0x40, 0x4c, 0x43, + 0xc2, 0xc0, 0x4b, 0x48, 0xba, 0x40, 0x4c, 0x4a, 0xc3, 0x00, 0x4b, 0x48, + 0xbb, 0x80, 0x4c, 0x43, 0xc4, 0xc0, 0x4b, 0x8a, 0xbc, 0x40, 0x4c, 0x08, + 0xc5, 0x00, 0x4b, 0x83, 0xbd, 0x80, 0x4c, 0x08, 0xc6, 0x00, 0xcd, 0x81, + 0x1f, 0xf0, 0xa1, 0xc0, 0xe0, 0x70, 0xa2, 0xc0, 0x4d, 0x48, 0x35, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0xbb, 0x63, 0x8a, 0x51, 0xb2, 0x00, 0x4d, 0x48, + 0x35, 0x7e, 0x84, 0x80, 0x32, 0x08, 0x80, 0x40, 0x1f, 0xf0, 0xa1, 0xc0, + 0xe0, 0x70, 0xa2, 0xc0, 0x4d, 0x48, 0x3e, 0xbe, 0x84, 0x80, 0x00, 0x48, + 0xbb, 0x63, 0x8a, 0x51, 0xb2, 0x00, 0x4d, 0x48, 0x3e, 0xbe, 0x84, 0x80, + 0x32, 0x08, 0x80, 0x40, 0x4d, 0x48, 0x35, 0x7e, 0x84, 0x80, 0x00, 0x48, + 0xa1, 0xc0, 0xa2, 0x01, 0x47, 0x48, 0xa7, 0x23, 0x8a, 0x51, 0x4d, 0x48, + 0x3e, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0xa2, 0x01, 0x48, 0xc8, + 0xa7, 0x23, 0x8a, 0x51, 0x07, 0x70, 0xd2, 0xe3, 0x8a, 0x51, 0xc9, 0x00, + 0x4d, 0x48, 0x03, 0x59, 0x8b, 0x2b, 0x34, 0x08, 0x49, 0x02, 0x03, 0x18, + 0x97, 0x6b, 0x49, 0x08, 0xb4, 0x00, 0x4d, 0x48, 0x35, 0x7e, 0x84, 0x80, + 0x00, 0x48, 0xcb, 0x40, 0x4d, 0x48, 0x3e, 0xbe, 0x84, 0x80, 0x00, 0x48, + 0xcc, 0x00, 0x09, 0x30, 0xcd, 0xca, 0x4d, 0x42, 0x03, 0x5c, 0x4e, 0x2b, + 0x4b, 0x48, 0xa1, 0xc0, 0xa2, 0x01, 0x47, 0x48, 0xa7, 0x23, 0x8a, 0x51, + 0x4c, 0x08, 0xa1, 0xc0, 0xa2, 0x01, 0x48, 0xc8, 0xa7, 0x6b, 0xa3, 0x00, + 0x22, 0x0a, 0x03, 0x59, 0xb5, 0x6b, 0x22, 0xc8, 0x63, 0x86, 0x03, 0x59, + 0xb5, 0x6b, 0x22, 0xc8, 0x88, 0x80, 0x80, 0xf0, 0x8c, 0xc0, 0x22, 0xc8, + 0xe3, 0x40, 0x21, 0xc8, 0x88, 0x80, 0x23, 0x08, 0x80, 0x38, 0x8c, 0xc0, + 0x08, 0x40, 0xa4, 0xc0, 0x21, 0xc8, 0x80, 0x7a, 0xa3, 0x00, 0x24, 0xc8, + 0x80, 0x7a, 0xa3, 0x42, 0x03, 0x18, 0xc6, 0x2b, 0x21, 0xc8, 0x08, 0x40, + 0x24, 0xc8, 0x80, 0x7a, 0xa3, 0x00, 0x22, 0xc8, 0x80, 0x7a, 0xa3, 0x42, + 0x03, 0x18, 0xd0, 0xeb, 0x22, 0xc8, 0x08, 0x40, 0x24, 0xc8, 0x08, 0x40, + 0xaa, 0x00, 0x2a, 0x8e, 0xf0, 0x39, 0x0c, 0x78, 0xae, 0x40, 0xb1, 0x41, + 0x2e, 0x48, 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x54, 0x70, 0xa7, 0x23, + 0x8a, 0x51, 0x2e, 0x48, 0x02, 0xbe, 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, + 0x54, 0x70, 0xa7, 0x23, 0x8a, 0x51, 0x02, 0xf0, 0xa1, 0xc0, 0x54, 0x70, + 0x30, 0x24, 0x8a, 0x51, 0xe5, 0x40, 0xe5, 0x9f, 0xe7, 0xab, 0x02, 0xf0, + 0xa1, 0xc0, 0x57, 0xf0, 0x30, 0x24, 0x8a, 0x51, 0xab, 0x40, 0x02, 0xf0, + 0xa1, 0xc0, 0x58, 0x70, 0x30, 0x24, 0x8a, 0x51, 0xac, 0x00, 0x31, 0x08, + 0x25, 0x3e, 0x84, 0x80, 0x2b, 0x48, 0x44, 0x24, 0x8a, 0x51, 0xa4, 0xc0, + 0x2c, 0x08, 0x44, 0x24, 0x8a, 0x51, 0x24, 0x47, 0x80, 0x40, 0x05, 0x30, + 0xb1, 0x8a, 0x31, 0x02, 0x03, 0x5c, 0xd8, 0x2b, 0xb0, 0x01, 0x25, 0x08, + 0xaf, 0x80, 0xad, 0x81, 0xb1, 0x41, 0x31, 0x08, 0x25, 0x3e, 0x84, 0x80, + 0x2f, 0x88, 0x00, 0x42, 0x03, 0x18, 0x1f, 0x2c, 0x31, 0x08, 0x25, 0x3e, + 0x84, 0x80, 0x00, 0x48, 0xaf, 0x80, 0x31, 0x08, 0xad, 0x40, 0x05, 0x30, + 0xb1, 0x8a, 0x31, 0x02, 0x03, 0x5c, 0x11, 0x6c, 0x2d, 0x48, 0x25, 0x3e, + 0x84, 0x80, 0xff, 0xb0, 0x80, 0x40, 0x03, 0x30, 0xb0, 0x4a, 0x30, 0xc2, + 0x03, 0x5c, 0x0d, 0xac, 0x2f, 0x88, 0x08, 0x40, 0xa2, 0xc0, 0x21, 0x0a, + 0x03, 0x59, 0x3e, 0x2c, 0x21, 0xc8, 0x63, 0x86, 0x03, 0x59, 0x3e, 0x2c, + 0x21, 0xc8, 0x88, 0x80, 0x80, 0xf0, 0x8c, 0xc0, 0x21, 0xc8, 0xe3, 0x40, + 0x22, 0xc8, 0x8c, 0xc0, 0x22, 0xc8, 0x8c, 0xc0, 0x08, 0x88, 0x08, 0x40, + 0xa1, 0xc0, 0xa1, 0x1f, 0x4a, 0xac, 0x21, 0x03, 0xff, 0x3a, 0x08, 0x40, + 0x21, 0xc8, 0x08, 0x40, 0x02, 0xf0, 0xa0, 0x80, 0x95, 0x41, 0x96, 0x41, + 0x97, 0x81, 0x98, 0x01, 0x99, 0x41, 0x9a, 0x41, 0x9b, 0x81, 0x9c, 0x41, + 0x10, 0xf0, 0x9e, 0x40, 0x8b, 0x41, 0x83, 0x96, 0xd0, 0x01, 0xd1, 0x41, + 0x83, 0x52, 0xd4, 0x41, 0x54, 0x08, 0xa0, 0xfe, 0x84, 0x80, 0x80, 0x81, + 0x54, 0x08, 0xa8, 0x3e, 0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xb0, 0x3e, + 0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xb8, 0x7e, 0x84, 0x80, 0x80, 0x81, + 0x54, 0x08, 0xc0, 0xfe, 0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xc8, 0x3e, + 0x84, 0x80, 0x80, 0x81, 0x54, 0x08, 0xd2, 0x7e, 0x84, 0x80, 0x08, 0xf0, + 0x80, 0x81, 0xd4, 0x8a, 0x54, 0x02, 0x03, 0x5c, 0x5e, 0x2c, 0x00, 0xb0, + 0xa1, 0x01, 0xa1, 0x43, 0x8a, 0x51, 0x30, 0x24, 0x8a, 0x51, 0x03, 0xba, + 0x03, 0x9d, 0x7f, 0xac, 0x03, 0x30, 0xe3, 0x40, 0xc8, 0x70, 0xa1, 0xc0, + 0x02, 0xf0, 0xa2, 0xc0, 0x56, 0xb0, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, + 0x02, 0xf0, 0xa1, 0xc0, 0x56, 0xb0, 0x8a, 0x51, 0x30, 0x24, 0x8a, 0x51, + 0xe5, 0x40, 0xc8, 0xfa, 0x03, 0x59, 0x1b, 0x94, 0xc9, 0xb0, 0xa1, 0xc0, + 0x04, 0xf0, 0xa2, 0x01, 0x8a, 0x95, 0xf0, 0x27, 0x8a, 0x51, 0x04, 0xf0, + 0xa1, 0x01, 0x8a, 0x51, 0x22, 0x21, 0x8a, 0x51, 0xe5, 0x40, 0xc9, 0x3a, + 0x03, 0x59, 0x9b, 0xd4, 0xca, 0xb0, 0xa1, 0xc0, 0x04, 0xf0, 0xa2, 0x01, + 0xa2, 0x4a, 0x8a, 0x95, 0xf0, 0x27, 0x8a, 0x51, 0x04, 0xf0, 0xa1, 0x01, + 0xa1, 0x4a, 0x8a, 0x51, 0x22, 0x21, 0x8a, 0x51, 0xe5, 0x40, 0xca, 0x3a, + 0x03, 0x59, 0x1b, 0xd5, 0x14, 0xc8, 0xce, 0x40, 0x06, 0x30, 0x03, 0xd0, + 0xce, 0xcc, 0xff, 0x7e, 0x03, 0x9d, 0xc1, 0xac, 0x4e, 0x48, 0xd1, 0x00, + 0x14, 0x5c, 0xce, 0x2c, 0x83, 0x52, 0x03, 0x53, 0x66, 0xd6, 0xd1, 0xec, + 0x83, 0x52, 0x03, 0x53, 0x66, 0x92, 0x94, 0x9c, 0xd7, 0x6c, 0x83, 0x52, + 0x03, 0x53, 0xe6, 0x16, 0xda, 0x2c, 0x83, 0x52, 0x03, 0x53, 0xe6, 0xd2, + 0x14, 0x9d, 0xe0, 0xac, 0x83, 0x52, 0x03, 0x53, 0xe6, 0x57, 0xe3, 0x2c, + 0x83, 0x52, 0x03, 0x53, 0xe6, 0x13, 0x94, 0xdd, 0xe9, 0x2c, 0x83, 0x52, + 0x03, 0x53, 0x67, 0xd4, 0xec, 0x2c, 0x83, 0x52, 0x03, 0x53, 0x67, 0x90, + 0x14, 0x9e, 0xf2, 0x2c, 0x83, 0x52, 0x03, 0x53, 0x66, 0x94, 0xf5, 0x6c, + 0x83, 0x52, 0x03, 0x53, 0x66, 0x50, 0x94, 0xde, 0xfb, 0xac, 0x83, 0x52, + 0x03, 0x53, 0x66, 0x17, 0xfe, 0xac, 0x83, 0x52, 0x03, 0x53, 0x66, 0xd3, + 0xd1, 0x48, 0x03, 0x9d, 0x05, 0xad, 0x83, 0x52, 0x03, 0x53, 0xe6, 0x15, + 0x08, 0x6d, 0x83, 0x52, 0x03, 0x53, 0xe6, 0xd1, 0x51, 0x8b, 0x0e, 0xed, + 0x83, 0x52, 0x03, 0x53, 0xe6, 0xd4, 0x11, 0xad, 0x83, 0x52, 0x03, 0x53, + 0xe6, 0x90, 0x51, 0x08, 0x02, 0x7a, 0x03, 0x9d, 0x19, 0xed, 0x83, 0x52, + 0x03, 0x53, 0x66, 0xd5, 0x1c, 0xed, 0x83, 0x52, 0x03, 0x53, 0x66, 0x91, + 0x8a, 0x51, 0x9b, 0xa0, 0x8a, 0x51, 0xd4, 0x41, 0x54, 0x08, 0xe0, 0x3e, + 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xce, 0x40, 0x54, 0x08, 0xe2, 0x7e, + 0x84, 0x80, 0x4e, 0x48, 0x80, 0x40, 0x54, 0x08, 0xde, 0xfe, 0x84, 0x80, + 0x00, 0x48, 0xce, 0x40, 0x54, 0x08, 0x55, 0x7e, 0x84, 0x80, 0x4e, 0x48, + 0x80, 0x40, 0x54, 0x08, 0xda, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xce, 0x40, + 0x54, 0x08, 0xdc, 0xbe, 0x84, 0x80, 0x4e, 0x48, 0x80, 0x40, 0x54, 0x08, + 0xe8, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xce, 0x40, 0x54, 0x08, 0x5b, 0xbe, + 0x84, 0x80, 0x4e, 0x48, 0x80, 0x40, 0x54, 0x08, 0xe6, 0xbe, 0x84, 0x80, + 0x00, 0x48, 0xce, 0x40, 0x54, 0x08, 0x59, 0x7e, 0x84, 0x80, 0x4e, 0x48, + 0x80, 0x40, 0x54, 0x08, 0xe4, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xce, 0x40, + 0x54, 0x08, 0x57, 0xbe, 0x84, 0x80, 0x4e, 0x48, 0x80, 0x40, 0x02, 0xf0, + 0xd4, 0x8a, 0x54, 0x02, 0x03, 0x5c, 0x20, 0x6d, 0x69, 0xb0, 0xa1, 0x01, + 0xa2, 0x01, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x19, 0x10, 0x19, 0x51, + 0x99, 0x50, 0x99, 0x91, 0x21, 0x30, 0xa1, 0x01, 0xa1, 0x4a, 0xa2, 0x01, + 0xa2, 0x4a, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x21, 0x30, 0xa1, 0x01, + 0xa2, 0x01, 0xa2, 0x4a, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x07, 0x70, + 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x30, 0x30, 0x8a, 0x51, 0xa7, 0x23, + 0x8a, 0x51, 0xe6, 0xd8, 0xe8, 0x41, 0x27, 0xb0, 0xa1, 0x01, 0xa2, 0x01, + 0xa2, 0x4a, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x28, 0x30, 0xa1, 0x01, + 0xa2, 0x01, 0xa2, 0x4a, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x66, 0x1e, + 0x3e, 0x6e, 0xe6, 0x5d, 0x66, 0xd9, 0x9a, 0x2d, 0xe6, 0x1c, 0xbd, 0xad, + 0x18, 0x14, 0xe6, 0x1c, 0xb2, 0x2d, 0x03, 0x30, 0xa1, 0xc0, 0x02, 0xf0, + 0xa2, 0xc0, 0x2c, 0x70, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x99, 0xd5, + 0x29, 0x70, 0xd0, 0xc0, 0x96, 0xb0, 0xcf, 0x80, 0xa6, 0xb0, 0xce, 0x40, + 0xce, 0x0b, 0xac, 0x2d, 0xcf, 0x4b, 0xac, 0x2d, 0xd0, 0x8b, 0xac, 0x2d, + 0x03, 0x30, 0x83, 0x52, 0x03, 0x53, 0xee, 0x80, 0x0f, 0xb0, 0xef, 0xc0, + 0x00, 0xb0, 0x8a, 0x95, 0x02, 0x26, 0x8a, 0x51, 0xc7, 0x6d, 0x18, 0xd0, + 0x02, 0xf0, 0xee, 0x80, 0x0e, 0x70, 0xef, 0xc0, 0x01, 0xf0, 0xaa, 0x41, + 0x8a, 0x95, 0x75, 0x25, 0x8a, 0x51, 0x6c, 0x48, 0x83, 0x96, 0xd2, 0x00, + 0x83, 0x52, 0x6b, 0x88, 0x83, 0x96, 0xd3, 0x40, 0x83, 0x52, 0x64, 0x08, + 0x83, 0x96, 0xd4, 0x00, 0x83, 0x52, 0x02, 0xf0, 0xa1, 0x01, 0xa2, 0xc0, + 0x53, 0xb0, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x14, 0x30, 0xa1, 0xc0, + 0x02, 0xf0, 0xa2, 0xc0, 0x56, 0xb0, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, + 0x02, 0xf0, 0x8a, 0x51, 0x31, 0x61, 0x8a, 0x51, 0xd2, 0x00, 0xec, 0xf0, + 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x56, 0xb0, 0x8a, 0x51, 0xa7, 0x23, + 0x8a, 0x51, 0x00, 0xb0, 0x8a, 0x51, 0x79, 0xe2, 0x8a, 0x51, 0x07, 0x70, + 0x8a, 0x51, 0x31, 0x61, 0x8a, 0x51, 0xd3, 0x40, 0x02, 0xf0, 0xa1, 0x01, + 0xa2, 0xc0, 0x2f, 0xf0, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x24, 0x30, + 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x2f, 0xf0, 0x8a, 0x51, 0xa7, 0x23, + 0x8a, 0x51, 0x2a, 0x70, 0xcf, 0x80, 0x8d, 0xb0, 0xce, 0x40, 0xce, 0x0b, + 0x0b, 0xee, 0xcf, 0x4b, 0x0b, 0xee, 0x10, 0x6e, 0x83, 0x52, 0x02, 0xf0, + 0x03, 0x53, 0xa1, 0x01, 0xa2, 0xc0, 0x2f, 0xf0, 0x8a, 0x51, 0xa7, 0x23, + 0x8a, 0x51, 0xe6, 0x5d, 0x66, 0xd9, 0x1e, 0x2e, 0xe6, 0x1c, 0x25, 0xee, + 0x99, 0x91, 0x03, 0x30, 0xa1, 0xc0, 0x00, 0xb0, 0xa2, 0x01, 0xa2, 0x4a, + 0x29, 0xee, 0x03, 0x30, 0xa1, 0xc0, 0x00, 0xb0, 0xa2, 0x01, 0x8a, 0x95, + 0xf0, 0x27, 0x8a, 0x51, 0x52, 0x08, 0x8a, 0x95, 0xeb, 0x24, 0x8a, 0x51, + 0xce, 0x40, 0x53, 0x48, 0x8a, 0x95, 0xeb, 0x24, 0x8a, 0x51, 0x4e, 0x42, + 0x1e, 0x7e, 0x83, 0x96, 0xd0, 0xc0, 0x32, 0x70, 0x50, 0xc2, 0x83, 0x52, + 0x03, 0x18, 0x9b, 0x15, 0x83, 0x52, 0xe6, 0x5e, 0xee, 0xae, 0xe6, 0x5d, + 0x66, 0xd9, 0x46, 0xee, 0xe6, 0x1c, 0x69, 0x2e, 0x18, 0xd0, 0xe6, 0x1c, + 0x5e, 0x6e, 0x03, 0x30, 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x2c, 0x70, + 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x99, 0x94, 0x29, 0x70, 0xd0, 0xc0, + 0x96, 0xb0, 0xcf, 0x80, 0xa6, 0xb0, 0xce, 0x40, 0xce, 0x0b, 0x58, 0xee, + 0xcf, 0x4b, 0x58, 0xee, 0xd0, 0x8b, 0x58, 0xee, 0x03, 0x30, 0x83, 0x52, + 0x03, 0x53, 0xee, 0x80, 0x0f, 0xb0, 0xef, 0xc0, 0x01, 0xf0, 0x8a, 0x95, + 0x02, 0x26, 0x8a, 0x51, 0x74, 0x2e, 0x18, 0x14, 0x02, 0xf0, 0xee, 0x80, + 0x0e, 0x70, 0xef, 0xc0, 0x01, 0xf0, 0xaa, 0x41, 0xaa, 0x8a, 0x8a, 0x95, + 0x75, 0x25, 0x8a, 0x51, 0x6c, 0x48, 0x83, 0x96, 0xd2, 0x00, 0x83, 0x52, + 0x6b, 0x88, 0x83, 0x96, 0xd3, 0x40, 0x83, 0x52, 0x64, 0x08, 0x83, 0x96, + 0xd4, 0x00, 0x83, 0x52, 0x02, 0xf0, 0xa1, 0x01, 0xa1, 0x4a, 0xa2, 0xc0, + 0x53, 0xb0, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x14, 0x30, 0xa1, 0xc0, + 0x02, 0xf0, 0xa2, 0xc0, 0x56, 0xb0, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, + 0x02, 0xf0, 0x8a, 0x51, 0x31, 0x61, 0x8a, 0x51, 0xd2, 0x00, 0xec, 0xf0, + 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x56, 0xb0, 0x8a, 0x51, 0xa7, 0x23, + 0x8a, 0x51, 0x01, 0xf0, 0x8a, 0x51, 0x79, 0xe2, 0x8a, 0x51, 0x07, 0x70, + 0x8a, 0x51, 0x31, 0x61, 0x8a, 0x51, 0xd3, 0x40, 0x02, 0xf0, 0xa1, 0x01, + 0xa2, 0xc0, 0x2f, 0xf0, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x25, 0x70, + 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x2f, 0xf0, 0x8a, 0x51, 0xa7, 0x23, + 0x8a, 0x51, 0x2a, 0x70, 0xcf, 0x80, 0x8d, 0xb0, 0xce, 0x40, 0xce, 0x0b, + 0xb9, 0x6e, 0xcf, 0x4b, 0xb9, 0x6e, 0xbe, 0xae, 0x83, 0x52, 0x02, 0xf0, + 0x03, 0x53, 0xa1, 0x01, 0xa2, 0xc0, 0x2f, 0xf0, 0x8a, 0x51, 0xa7, 0x23, + 0x8a, 0x51, 0xe6, 0x5d, 0x66, 0xd9, 0xcc, 0x2e, 0xe6, 0x1c, 0xd4, 0x2e, + 0xe6, 0x1c, 0xcf, 0xae, 0x99, 0x50, 0x03, 0x30, 0xa1, 0xc0, 0x00, 0xb0, + 0xa2, 0x01, 0xd9, 0x6e, 0x03, 0x30, 0xa1, 0xc0, 0x00, 0xb0, 0xa2, 0x01, + 0xa2, 0x4a, 0x8a, 0x95, 0xf0, 0x27, 0x8a, 0x51, 0x52, 0x08, 0x8a, 0x95, + 0xeb, 0x24, 0x8a, 0x51, 0xce, 0x40, 0x53, 0x48, 0x8a, 0x95, 0xeb, 0x24, + 0x8a, 0x51, 0x4e, 0x42, 0x1e, 0x7e, 0x83, 0x96, 0xd1, 0x00, 0x32, 0x70, + 0x51, 0x02, 0x83, 0x52, 0x03, 0x18, 0x1b, 0xd6, 0x83, 0x52, 0x66, 0xdc, + 0xf3, 0xae, 0x03, 0x30, 0xf4, 0x6e, 0x02, 0xf0, 0xee, 0x80, 0x01, 0xf0, + 0xe1, 0x00, 0x14, 0x30, 0xa1, 0xc0, 0x02, 0xf0, 0xa2, 0xc0, 0x56, 0xb0, + 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0xe6, 0x9f, 0x72, 0x6f, 0x18, 0xd0, + 0x02, 0xf0, 0xa1, 0x01, 0xa2, 0xc0, 0x53, 0xb0, 0x8a, 0x51, 0xa7, 0x23, + 0x8a, 0x51, 0x9b, 0x16, 0xd4, 0x41, 0x27, 0xb0, 0xa1, 0x01, 0xa2, 0x01, + 0xa2, 0x4a, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x28, 0x30, 0xa1, 0x01, + 0xa2, 0x01, 0xa2, 0x4a, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x54, 0x08, + 0x08, 0xbe, 0xef, 0xc0, 0x00, 0xb0, 0xaa, 0x41, 0xd4, 0x48, 0x03, 0x59, + 0x01, 0xf0, 0x8a, 0x95, 0x75, 0x25, 0x8a, 0x51, 0x54, 0x08, 0xd2, 0x7e, + 0x84, 0x80, 0x6b, 0x0e, 0xf0, 0x39, 0x64, 0x04, 0x83, 0x93, 0x80, 0x40, + 0x03, 0x30, 0x8a, 0x51, 0x31, 0x61, 0x8a, 0x51, 0xd2, 0x00, 0x00, 0xb0, + 0x8a, 0x51, 0x90, 0x21, 0x8a, 0x51, 0x07, 0x70, 0x8a, 0x51, 0x31, 0x61, + 0x8a, 0x51, 0xd3, 0x40, 0x52, 0x08, 0x8a, 0x95, 0xeb, 0x24, 0x8a, 0x51, + 0xce, 0x40, 0x53, 0x48, 0x8a, 0x95, 0xeb, 0x24, 0x8a, 0x51, 0x4e, 0x42, + 0x18, 0xfe, 0xcf, 0x80, 0x54, 0x08, 0xc0, 0xfe, 0x84, 0x80, 0x4f, 0x88, + 0x80, 0x40, 0x54, 0x08, 0xa0, 0xfe, 0x84, 0x80, 0x27, 0xb0, 0xa1, 0x01, + 0xa1, 0x4a, 0x8a, 0x51, 0x30, 0x24, 0x8a, 0x51, 0x80, 0x40, 0x54, 0x08, + 0xa8, 0x3e, 0x84, 0x80, 0x28, 0x30, 0xa1, 0x01, 0xa1, 0x4a, 0x8a, 0x51, + 0x30, 0x24, 0x8a, 0x51, 0x80, 0x40, 0x54, 0x08, 0xc0, 0xfe, 0x84, 0x80, + 0x14, 0x30, 0x00, 0x42, 0x03, 0x5c, 0x9b, 0xd2, 0x08, 0xf0, 0xd4, 0x8a, + 0x54, 0x02, 0x03, 0x5c, 0x0b, 0x2f, 0x03, 0x30, 0xa1, 0xc0, 0x00, 0xb0, + 0xa2, 0x01, 0x8a, 0x95, 0xf0, 0x27, 0x8a, 0x51, 0x67, 0x1c, 0xe8, 0x6f, + 0x18, 0x14, 0x02, 0xf0, 0xa1, 0x01, 0xa1, 0x4a, 0xa2, 0xc0, 0x53, 0xb0, + 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, 0x1b, 0x17, 0xd4, 0x41, 0x27, 0xb0, + 0xa1, 0x01, 0xa2, 0x01, 0xa2, 0x4a, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, + 0x28, 0x30, 0xa1, 0x01, 0xa2, 0x01, 0xa2, 0x4a, 0x8a, 0x51, 0xa7, 0x23, + 0x8a, 0x51, 0x54, 0x08, 0x08, 0xbe, 0xef, 0xc0, 0x00, 0xb0, 0xaa, 0x41, + 0xaa, 0x8a, 0xd4, 0x48, 0x03, 0x59, 0x01, 0xf0, 0x8a, 0x95, 0x75, 0x25, + 0x8a, 0x51, 0x54, 0x08, 0xd2, 0x7e, 0x84, 0x80, 0x6b, 0x0e, 0xf0, 0x39, + 0x64, 0x04, 0x83, 0x93, 0x80, 0x40, 0x03, 0x30, 0x8a, 0x51, 0x31, 0x61, + 0x8a, 0x51, 0xd2, 0x00, 0x01, 0xf0, 0x8a, 0x51, 0x90, 0x21, 0x8a, 0x51, + 0x07, 0x70, 0x8a, 0x51, 0x31, 0x61, 0x8a, 0x51, 0xd3, 0x40, 0x52, 0x08, + 0x8a, 0x95, 0xeb, 0x24, 0x8a, 0x51, 0xce, 0x40, 0x53, 0x48, 0x8a, 0x95, + 0xeb, 0x24, 0x8a, 0x51, 0x4e, 0x42, 0x18, 0xfe, 0xcf, 0x80, 0x54, 0x08, + 0xc8, 0x3e, 0x84, 0x80, 0x4f, 0x88, 0x80, 0x40, 0x54, 0x08, 0xb0, 0x3e, + 0x84, 0x80, 0x27, 0xb0, 0xa1, 0x01, 0xa1, 0x4a, 0x8a, 0x51, 0x30, 0x24, + 0x8a, 0x51, 0x80, 0x40, 0x54, 0x08, 0xb8, 0x7e, 0x84, 0x80, 0x28, 0x30, + 0xa1, 0x01, 0xa1, 0x4a, 0x8a, 0x51, 0x30, 0x24, 0x8a, 0x51, 0x80, 0x40, + 0x54, 0x08, 0xc8, 0x3e, 0x84, 0x80, 0x14, 0x30, 0x00, 0x42, 0x03, 0x5c, + 0x1b, 0xd3, 0x08, 0xf0, 0xd4, 0x8a, 0x54, 0x02, 0x03, 0x5c, 0x7f, 0x2f, + 0x03, 0x30, 0xa1, 0xc0, 0x00, 0xb0, 0xa2, 0x01, 0xa2, 0x4a, 0x8a, 0x95, + 0xf0, 0x27, 0x8a, 0x51, 0x18, 0x56, 0x18, 0x12, 0x8a, 0x95, 0x5b, 0x67, + 0x8a, 0x51, 0xe4, 0xb0, 0xce, 0x40, 0xf0, 0x6f, 0xf1, 0xaf, 0xce, 0x0b, + 0xef, 0x2f, 0xf4, 0xaf, 0x00, 0x00, 0x0e, 0x70, 0x83, 0x52, 0x03, 0x53, + 0xa1, 0xc0, 0x69, 0xb0, 0xa2, 0x01, 0x8a, 0x51, 0xa7, 0x23, 0x8a, 0x51, + 0x9b, 0x57, 0xff, 0x6f, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, 0xff, 0xbf, + 0xff, 0xbf, 0xa2, 0xc0, 0x10, 0xf0, 0x22, 0xc2, 0x22, 0xc8, 0x03, 0x18, + 0xf6, 0x6c, 0x1f, 0xbe, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x08, 0x40, + 0xa1, 0xc0, 0x03, 0xd0, 0xa1, 0x4c, 0x03, 0xd0, 0xa1, 0x4c, 0x03, 0xd0, + 0xa1, 0x4c, 0x21, 0xc8, 0x01, 0xbe, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, + 0x08, 0x40, 0xa8, 0xc0, 0x28, 0x5c, 0x0a, 0xad, 0x83, 0x52, 0x03, 0x53, + 0x18, 0x14, 0x0d, 0xed, 0x83, 0x52, 0x03, 0x53, 0x18, 0xd0, 0x07, 0x70, + 0xe4, 0x00, 0x64, 0x8e, 0xf0, 0x39, 0x96, 0x00, 0x18, 0x55, 0x18, 0x11, + 0xa9, 0x41, 0x28, 0xc8, 0xa4, 0xc0, 0x00, 0xb0, 0x56, 0xe5, 0x8a, 0x95, + 0x98, 0x95, 0x98, 0x51, 0xa7, 0x81, 0x74, 0xb0, 0x0e, 0x02, 0x03, 0x5c, + 0x27, 0x2d, 0x0b, 0x70, 0x64, 0x02, 0x03, 0x18, 0x27, 0x2d, 0xe4, 0x8a, + 0x31, 0xed, 0x2d, 0xb0, 0x0e, 0x02, 0x03, 0x18, 0x36, 0x2d, 0x08, 0xf0, + 0x64, 0x02, 0x03, 0x5c, 0x36, 0x2d, 0xff, 0xb0, 0xe4, 0xc7, 0x64, 0x8e, + 0xf0, 0x39, 0x96, 0x00, 0x18, 0x55, 0x18, 0x11, 0x24, 0x30, 0x0f, 0x42, + 0x03, 0x5c, 0x40, 0x6d, 0x09, 0x30, 0x29, 0x02, 0x03, 0x18, 0x40, 0x6d, + 0xa9, 0x8a, 0x49, 0xed, 0x10, 0xf0, 0x0f, 0x42, 0x03, 0x18, 0x50, 0xad, + 0x29, 0x08, 0x03, 0x59, 0x50, 0xad, 0xff, 0xb0, 0xa9, 0xc7, 0x28, 0xc8, + 0xa4, 0xc0, 0x29, 0x08, 0x56, 0xe5, 0x8a, 0x95, 0x98, 0x95, 0x98, 0x51, + 0x14, 0x30, 0xa7, 0xca, 0x27, 0x42, 0x03, 0x18, 0x08, 0x40, 0x1d, 0x2d, + 0xa6, 0x00, 0x39, 0x7e, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, 0x8a, 0x95, + 0xec, 0x40, 0x26, 0x08, 0x2f, 0xbe, 0x84, 0x80, 0x8a, 0x51, 0x02, 0xa0, + 0x8a, 0x95, 0xeb, 0x80, 0x6c, 0x48, 0xa5, 0x00, 0x05, 0x30, 0x03, 0xd0, + 0xa5, 0xcd, 0xff, 0x7e, 0x03, 0xd0, 0x03, 0x9d, 0x68, 0xed, 0x6b, 0x0d, + 0x25, 0x04, 0x68, 0x04, 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, 0x0c, 0x30, + 0xf0, 0x6f, 0xad, 0x40, 0x01, 0xf0, 0x83, 0x96, 0xed, 0x80, 0x83, 0x52, + 0x2a, 0x08, 0xaa, 0xe6, 0x8a, 0x95, 0x2d, 0x48, 0x03, 0x59, 0xfe, 0xed, + 0x2a, 0x08, 0xe2, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xab, 0x40, 0x2a, 0x08, + 0x5b, 0xbe, 0x84, 0x80, 0x2b, 0x48, 0x80, 0x40, 0x66, 0x5f, 0x92, 0xed, + 0x2a, 0x08, 0x55, 0x7e, 0x84, 0x80, 0x00, 0x48, 0x28, 0xfe, 0x97, 0x6d, + 0x2a, 0x08, 0x55, 0x7e, 0x84, 0x80, 0x00, 0x48, 0x14, 0xfe, 0xab, 0x40, + 0x2a, 0x08, 0x59, 0x7e, 0x84, 0x80, 0x2b, 0x48, 0x80, 0x40, 0x2a, 0x08, + 0x55, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xab, 0x40, 0x2a, 0x08, 0x59, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0xac, 0x00, 0x2b, 0x48, 0x2c, 0x02, 0x2a, 0x08, + 0x03, 0x18, 0xb6, 0x6d, 0x5b, 0xbe, 0x84, 0x80, 0x00, 0x8a, 0xab, 0x40, + 0x2a, 0x08, 0x5b, 0xbe, 0x84, 0x80, 0x2b, 0x48, 0x80, 0x40, 0x2a, 0x08, + 0xdc, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xab, 0x40, 0x2a, 0x08, 0x57, 0xbe, + 0x84, 0x80, 0x2b, 0x48, 0x80, 0x40, 0x2a, 0x08, 0x5b, 0xbe, 0x84, 0x80, + 0x00, 0x48, 0xa1, 0xc0, 0x2a, 0x08, 0xa2, 0xc0, 0x04, 0xf0, 0xf0, 0x27, + 0x8a, 0x95, 0x2a, 0x08, 0x59, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, + 0x2a, 0x08, 0xa2, 0xc0, 0x05, 0x30, 0xf0, 0x27, 0x8a, 0x95, 0x2a, 0x08, + 0x57, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x2a, 0x08, 0xa2, 0xc0, + 0x06, 0x30, 0xf0, 0x27, 0x8a, 0x95, 0xa1, 0x01, 0xa1, 0x4a, 0x2a, 0x08, + 0xa2, 0xc0, 0x00, 0xb0, 0xf0, 0x27, 0x8a, 0x95, 0xe4, 0xb0, 0xab, 0x40, + 0xe7, 0xad, 0xe8, 0x2d, 0xab, 0x0b, 0xe6, 0x6d, 0xeb, 0xad, 0x00, 0x00, + 0x0f, 0xb0, 0x83, 0x52, 0x03, 0x53, 0xa1, 0xc0, 0x2a, 0x08, 0xa2, 0xc0, + 0x00, 0xb0, 0xf0, 0x27, 0x8a, 0x95, 0xd0, 0x70, 0xac, 0x00, 0xc9, 0xb0, + 0xab, 0x40, 0xab, 0x0b, 0xf9, 0xad, 0xac, 0xcb, 0xf9, 0xad, 0xfe, 0xed, + 0x83, 0x52, 0x03, 0x53, 0x2a, 0x08, 0x03, 0xad, 0xac, 0x00, 0x2c, 0x08, + 0x03, 0x59, 0x0a, 0xae, 0xad, 0x81, 0xad, 0xca, 0xae, 0x81, 0x0d, 0xee, + 0xad, 0x81, 0xae, 0x81, 0xae, 0xca, 0x83, 0x96, 0xed, 0xc1, 0x0e, 0x70, + 0x83, 0x52, 0xef, 0xc0, 0x02, 0xf0, 0xee, 0x80, 0x2d, 0x48, 0xaa, 0xe6, + 0x8a, 0x95, 0x2e, 0x48, 0xaa, 0xe6, 0x8a, 0x95, 0x2d, 0x48, 0xe2, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0xaa, 0x00, 0x2e, 0x48, 0x5b, 0xbe, 0x84, 0x80, + 0x2a, 0x08, 0x80, 0x40, 0x66, 0x5f, 0x2c, 0xee, 0x2d, 0x48, 0x55, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0x28, 0xfe, 0x31, 0xee, 0x2d, 0x48, 0x55, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0x14, 0xfe, 0xaa, 0x00, 0x2e, 0x48, 0x59, 0x7e, + 0x84, 0x80, 0x2a, 0x08, 0x80, 0x40, 0x2d, 0x48, 0x55, 0x7e, 0x84, 0x80, + 0x00, 0x48, 0xaa, 0x00, 0x2e, 0x48, 0x59, 0x7e, 0x84, 0x80, 0x00, 0x48, + 0xab, 0x40, 0x2a, 0x08, 0x2b, 0x42, 0x03, 0x18, 0x4f, 0x6e, 0x2e, 0x48, + 0x5b, 0xbe, 0x84, 0x80, 0x00, 0x8a, 0xaa, 0x00, 0x2e, 0x48, 0x5b, 0xbe, + 0x84, 0x80, 0x2a, 0x08, 0x80, 0x40, 0x2d, 0x48, 0xdc, 0xbe, 0x84, 0x80, + 0x00, 0x48, 0xaa, 0x00, 0x2e, 0x48, 0x57, 0xbe, 0x84, 0x80, 0x2a, 0x08, + 0x80, 0x40, 0x2e, 0x48, 0x5b, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, + 0x2e, 0x48, 0xa2, 0xc0, 0x04, 0xf0, 0xf0, 0x27, 0x8a, 0x95, 0x2e, 0x48, + 0x59, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x2e, 0x48, 0xa2, 0xc0, + 0x05, 0x30, 0xf0, 0x27, 0x8a, 0x95, 0x2e, 0x48, 0x57, 0xbe, 0x84, 0x80, + 0x00, 0x48, 0xa1, 0xc0, 0x2e, 0x48, 0xa2, 0xc0, 0x06, 0x30, 0xf0, 0x27, + 0x8a, 0x95, 0xa1, 0x01, 0xa1, 0x4a, 0x2d, 0x48, 0xa2, 0xc0, 0x00, 0xb0, + 0xf0, 0x27, 0x8a, 0x95, 0xa1, 0x01, 0xa1, 0x4a, 0x2e, 0x48, 0xa2, 0xc0, + 0x00, 0xb0, 0xf0, 0x27, 0x8a, 0x95, 0xe4, 0xb0, 0xaa, 0x00, 0x88, 0xae, + 0x89, 0xee, 0xaa, 0xcb, 0x87, 0x2e, 0x8c, 0xee, 0x00, 0x00, 0x03, 0x30, + 0x83, 0x52, 0x03, 0x53, 0xa1, 0xc0, 0x2d, 0x48, 0xa2, 0xc0, 0x00, 0xb0, + 0xf0, 0x27, 0x8a, 0x95, 0x0d, 0x70, 0xa1, 0xc0, 0x2e, 0x48, 0xa2, 0xc0, + 0x00, 0xb0, 0xf0, 0x27, 0x8a, 0x95, 0xd0, 0x70, 0xab, 0x40, 0xc9, 0xb0, + 0xaa, 0x00, 0xaa, 0xcb, 0xa1, 0xee, 0xab, 0x0b, 0xa1, 0xee, 0xa6, 0x2e, + 0x83, 0x52, 0x03, 0x53, 0x2d, 0x48, 0x03, 0xad, 0xa6, 0x00, 0xe2, 0x7e, + 0x84, 0x80, 0x83, 0x93, 0x00, 0x48, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, + 0x01, 0xf0, 0xf0, 0x27, 0x8a, 0x95, 0x26, 0x08, 0x55, 0x7e, 0x84, 0x80, + 0x00, 0x48, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, 0x02, 0xf0, 0xf0, 0x27, + 0x8a, 0x95, 0x26, 0x08, 0xdc, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, + 0x26, 0x08, 0xa2, 0xc0, 0x03, 0x30, 0xf0, 0x27, 0x8a, 0x95, 0x26, 0x08, + 0x5b, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, + 0x04, 0xf0, 0xf0, 0x27, 0x8a, 0x95, 0x26, 0x08, 0x59, 0x7e, 0x84, 0x80, + 0x00, 0x48, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, 0x05, 0x30, 0xf0, 0x27, + 0x8a, 0x95, 0x26, 0x08, 0x57, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, + 0x26, 0x08, 0xa2, 0xc0, 0x06, 0x30, 0xf0, 0x27, 0x8a, 0x95, 0x6e, 0x0e, + 0xf0, 0x39, 0x6f, 0xc4, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, 0x08, 0xf0, + 0xf0, 0x27, 0x8a, 0x95, 0x62, 0x08, 0xa4, 0xc0, 0x04, 0xf0, 0x03, 0xd0, + 0xa4, 0x8d, 0xff, 0x7e, 0x03, 0xd0, 0x03, 0x9d, 0xf4, 0x6e, 0x24, 0x4d, + 0x60, 0xc4, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, 0x0a, 0x30, 0xf0, 0x27, + 0x8a, 0x95, 0x6d, 0x88, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, 0x0b, 0x70, + 0xf0, 0x27, 0x8a, 0x95, 0x6c, 0x48, 0xa4, 0xc0, 0x05, 0x30, 0x03, 0xd0, + 0xa4, 0x8d, 0xff, 0x7e, 0x03, 0xd0, 0x03, 0x9d, 0x0c, 0xef, 0x6b, 0x0d, + 0x24, 0xc4, 0x68, 0x04, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, 0x0c, 0x30, + 0xf0, 0x27, 0x8a, 0x95, 0x69, 0x48, 0xa4, 0xc0, 0x05, 0x30, 0x03, 0xd0, + 0xa4, 0x8d, 0xff, 0x7e, 0x03, 0x9d, 0x1d, 0x6f, 0x6a, 0x48, 0xa5, 0x00, + 0x01, 0xf0, 0x03, 0xd0, 0xa5, 0xcd, 0xff, 0x7e, 0x03, 0xd0, 0x03, 0x9d, + 0x26, 0x2f, 0x25, 0x8d, 0x24, 0xc4, 0x5e, 0x84, 0xa1, 0xc0, 0x26, 0x08, + 0xa2, 0xc0, 0x0d, 0x70, 0xf0, 0x27, 0x8a, 0x95, 0x03, 0xd0, 0x5f, 0x4d, + 0x5d, 0x84, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, 0x0e, 0x70, 0xf0, 0x27, + 0x8a, 0x95, 0x83, 0x96, 0x6c, 0x48, 0x83, 0x52, 0xa4, 0xc0, 0x03, 0xd0, + 0xa4, 0x8d, 0x03, 0xd0, 0xa4, 0x8d, 0x03, 0xd0, 0xa4, 0x8d, 0x83, 0x96, + 0x6d, 0x88, 0x83, 0x52, 0xa5, 0x00, 0x03, 0xd0, 0xa5, 0xcd, 0x03, 0xd0, + 0xa5, 0xcd, 0x83, 0x96, 0x03, 0xd0, 0x6e, 0x0d, 0x83, 0x52, 0x25, 0x04, + 0x24, 0xc4, 0x61, 0x04, 0xa1, 0xc0, 0x26, 0x08, 0xa2, 0xc0, 0x10, 0xf0, + 0xf0, 0x6f, 0xa4, 0x01, 0x24, 0xc8, 0xea, 0xbe, 0x84, 0x80, 0x83, 0x93, + 0x00, 0x48, 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, 0x00, 0xb0, 0xf0, 0x27, + 0x8a, 0x95, 0x24, 0xc8, 0xe0, 0x3e, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, + 0x24, 0xc8, 0xa2, 0xc0, 0x01, 0xf0, 0xf0, 0x27, 0x8a, 0x95, 0x24, 0xc8, + 0xde, 0xfe, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, + 0x02, 0xf0, 0xf0, 0x27, 0x8a, 0x95, 0x24, 0xc8, 0xda, 0xbe, 0x84, 0x80, + 0x00, 0x48, 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, 0x03, 0x30, 0xf0, 0x27, + 0x8a, 0x95, 0x24, 0xc8, 0xe8, 0x7e, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, + 0x24, 0xc8, 0xa2, 0xc0, 0x04, 0xf0, 0xf0, 0x27, 0x8a, 0x95, 0x24, 0xc8, + 0xe6, 0xbe, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, + 0x05, 0x30, 0xf0, 0x27, 0x8a, 0x95, 0x24, 0xc8, 0xe4, 0x7e, 0x84, 0x80, + 0x00, 0x48, 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, 0x06, 0x30, 0xf0, 0x27, + 0x8a, 0x95, 0x24, 0xc8, 0xac, 0x7e, 0x84, 0x80, 0x83, 0xd7, 0x00, 0x48, + 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, 0x08, 0xf0, 0xf0, 0x27, 0x8a, 0x95, + 0x24, 0xc8, 0xa8, 0x3e, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x24, 0xc8, + 0xa2, 0xc0, 0x0a, 0x30, 0xf0, 0x27, 0x8a, 0x95, 0x24, 0xc8, 0xaa, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, 0x0b, 0x70, + 0xf0, 0x27, 0x8a, 0x95, 0x24, 0xc8, 0xa2, 0x3e, 0x84, 0x80, 0x00, 0x48, + 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, 0x0c, 0x30, 0xf0, 0x27, 0x8a, 0x95, + 0x24, 0xc8, 0xa4, 0x3e, 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x24, 0xc8, + 0xa2, 0xc0, 0x0d, 0x70, 0xf0, 0x27, 0x8a, 0x95, 0x24, 0xc8, 0xa6, 0x7e, + 0x84, 0x80, 0x00, 0x48, 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, 0x0e, 0x70, + 0xf0, 0x27, 0x8a, 0x95, 0x24, 0xc8, 0xa0, 0xfe, 0x84, 0x80, 0x00, 0x48, + 0xa1, 0xc0, 0x24, 0xc8, 0xa2, 0xc0, 0x10, 0xf0, 0xf0, 0x27, 0x8a, 0x95, + 0x02, 0xf0, 0xa4, 0x4a, 0x24, 0xc2, 0x03, 0x18, 0x08, 0x40, 0x5c, 0x6f, + 0xa3, 0x00, 0x22, 0xc8, 0x03, 0x59, 0xfa, 0xef, 0x21, 0xc8, 0x88, 0x80, + 0x23, 0x08, 0x80, 0x38, 0x86, 0xc0, 0x08, 0x40, 0x21, 0xc8, 0x88, 0x80, + 0x23, 0x08, 0x80, 0x38, 0x85, 0xc0, 0x08, 0x40, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ diff --git a/drivers/wireless/lpwan/sx1301/sx1301_fw.h b/drivers/wireless/lpwan/sx1301/sx1301_fw.h new file mode 100644 index 0000000000000..510ed15583589 --- /dev/null +++ b/drivers/wireless/lpwan/sx1301/sx1301_fw.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * drivers/wireless/lpwan/sx1301/sx1301_fw.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_LPWAN_SX1301_SX1301_FW_H +#define __DRIVERS_WIRELESS_LPWAN_SX1301_SX1301_FW_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Both internal MCUs have an 8 KiB program memory */ + +#define SX1301_MCU_FW_SIZE 8192 + +/* Firmware versions, as read back from the MCU RAM at address 0x20 */ + +#define SX1301_FW_VERSION_AGC 4 +#define SX1301_FW_VERSION_ARB 1 +#define SX1301_FW_VERSION_CAL 2 + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern const uint8_t g_sx1301_agc_fw[SX1301_MCU_FW_SIZE]; +extern const uint8_t g_sx1301_arb_fw[SX1301_MCU_FW_SIZE]; +extern const uint8_t g_sx1301_cal_fw[SX1301_MCU_FW_SIZE]; + +#endif /* __DRIVERS_WIRELESS_LPWAN_SX1301_SX1301_FW_H */ diff --git a/drivers/wireless/lpwan/sx1301/sx1301_priv.h b/drivers/wireless/lpwan/sx1301/sx1301_priv.h new file mode 100644 index 0000000000000..88fffcf75047f --- /dev/null +++ b/drivers/wireless/lpwan/sx1301/sx1301_priv.h @@ -0,0 +1,243 @@ +/**************************************************************************** + * drivers/wireless/lpwan/sx1301/sx1301_priv.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_LPWAN_SX1301_SX1301_PRIV_H +#define __DRIVERS_WIRELESS_LPWAN_SX1301_SX1301_PRIV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register pages. The page is selected by the low bits of address 0x00 and + * a few registers (the FIFO and PROM ports) are page independent; those are + * accessed with SX1301_PAGE_ANY, which does not switch the page at all. + */ + +#define SX1301_PAGE_0 0 +#define SX1301_PAGE_1 1 +#define SX1301_PAGE_2 2 +#define SX1301_PAGE_3 3 +#define SX1301_PAGE_ANY 0xff + +/* SPI protocol of the SX1301: two byte transactions, MSB of the first byte + * selects a write. There is no FPGA/mux on this class of shield, so the + * radios are reached through the internal bridge on page 2 instead. + */ + +#define SX1301_SPI_WRITE_FLAG 0x80 +#define SX1301_SPI_ADDR_MASK 0x7f + +/* Register map -- page independent */ + +#define SX1301_REG_PAGE 0x00 /* Bits 1:0 page, bit 7 soft reset */ +#define SX1301_REG_VERSION 0x01 +#define SX1301_REG_RX_BUF_ADDR 0x02 /* 16 bit read pointer (0x02..0x03) */ +#define SX1301_REG_RX_BUF_DATA 0x04 /* Auto incrementing data port */ +#define SX1301_REG_TX_BUF_ADDR 0x05 +#define SX1301_REG_TX_BUF_DATA 0x06 /* Write port; reads give the counter */ +#define SX1301_REG_TIMESTAMP 0x06 /* 32 bit concentrator counter (RO) */ +#define SX1301_REG_PROM_ADDR 0x09 +#define SX1301_REG_PROM_DATA 0x0a +#define SX1301_REG_RX_NUM_STORED 0x0b /* Packets pending; write 0 to pop */ +#define SX1301_REG_RX_ADDR_PTR 0x0c /* 16 bit (0x0c..0x0d), RO */ +#define SX1301_REG_RX_STATUS 0x0e /* CRC status of the pending packet */ +#define SX1301_REG_RX_PLD_SIZE 0x0f +#define SX1301_REG_GLOBAL_EN 0x10 /* b0 MBWSSF, b1 CONC, b2 FSK, b3 EN */ +#define SX1301_REG_CLK_CTRL 0x11 /* b0 CLK32M, b1 CLKHS */ +#define SX1301_REG_AGC_STATUS 0x20 +#define SX1301_REG_CHIP_ID 0x7e +#define SX1301_REG_EMERGENCY 0x7f /* b0 force host control */ + +/* Register map -- page 0 */ + +#define SX1301_REG_GPIO_SELECT 0x1c +#define SX1301_REG_GPIO_MODE 0x1d +#define SX1301_REG_RADIO_SELECT 0x23 +#define SX1301_REG_IF_FREQ_BASE 0x24 /* IF0..IF7, two bytes each */ +#define SX1301_REG_IF_FREQ_8 0x34 +#define SX1301_REG_IF_FREQ_9 0x36 +#define SX1301_REG_CORR_EN_BASE 0x41 /* CORR0..CORR7 detect enable */ +#define SX1301_REG_CORR_TUNE 0x4e /* b3:0 same peak, b6:4 mac gain */ +#define SX1301_REG_FRAME_SYNCH 0x5f /* b3:0 peak1, b7:4 peak2 */ +#define SX1301_REG_FREQ_DRIFT 0x5d +#define SX1301_REG_PPM_OFFSET 0x64 +#define SX1301_REG_GAIN_OFFSET 0x68 /* b3:0 dec, b7:4 chan */ +#define SX1301_REG_FORCE_CTRL 0x69 /* b1 radio, b2 front end, b3 filter */ +#define SX1301_REG_MCU_CTRL 0x6a /* b0/b1 reset, b2/b3 PROM mux */ +#define SX1301_REG_RSSI_BB_DFLT 0x6c +#define SX1301_REG_RSSI_DEC_DFLT 0x6d +#define SX1301_REG_RSSI_CHAN_DFT 0x6e +#define SX1301_REG_RSSI_BB_ALPHA 0x6f +#define SX1301_REG_RSSI_DEC_ALPH 0x70 +#define SX1301_REG_RSSI_CHN_ALPH 0x71 + +/* Register map -- page 1 (transmitter and LoRa standard demodulator) */ + +#define SX1301_REG_TX_TRIG 0x21 /* b0 immediate, b1 timestamped */ +#define SX1301_REG_TX_START_DLY 0x22 /* 16 bit (0x22..0x23) */ +#define SX1301_REG_TX_FRAME_SYNC 0x24 +#define SX1301_REG_TX_OFFSET_I 0x27 +#define SX1301_REG_TX_OFFSET_Q 0x28 +#define SX1301_REG_TX_GAIN 0x2a /* b1:0 digital gain, b7 swap IQ */ +#define SX1301_REG_MBWSSF_SYNCH 0x2e /* b3:0 peak1, b7:4 peak2 */ +#define SX1301_REG_MBWSSF_DRIFT 0x35 +#define SX1301_REG_MBWSSF_BW_SEL 0x3a /* b1:0 bandwidth, b2 radio select */ +#define SX1301_REG_MBWSSF_PPM 0x3b +#define SX1301_REG_MBWSSF_SF 0x3c +#define SX1301_REG_TX_STATUS 0x3e + +/* Register map -- page 2 (radio bridge and MCU RAM debug ports) */ + +#define SX1301_REG_RADIO_A_DATA 0x21 +#define SX1301_REG_RADIO_A_RB 0x22 +#define SX1301_REG_RADIO_A_ADDR 0x23 +#define SX1301_REG_RADIO_A_CS 0x25 +#define SX1301_REG_RADIO_B_DATA 0x26 +#define SX1301_REG_RADIO_B_RB 0x27 +#define SX1301_REG_RADIO_B_ADDR 0x28 +#define SX1301_REG_RADIO_B_CS 0x2a +#define SX1301_REG_RADIO_CFG 0x2b /* b0 A enable, b1 B enable, b2 reset */ +#define SX1301_REG_DBG_ARB_DATA 0x40 +#define SX1301_REG_DBG_AGC_DATA 0x41 +#define SX1301_REG_DBG_ARB_ADDR 0x50 +#define SX1301_REG_DBG_AGC_ADDR 0x51 + +/* Expected identification values */ + +#define SX1301_CHIP_VERSION 0x67 +#define SX1301_CHIP_ID_VALUE 0x01 + +/* Sixteen bytes of metadata follow the payload in the RX data buffer */ + +#define SX1301_RX_METADATA_NB 16 + +/* Largest burst that can be issued with a zero filled MOSI buffer. Big + * enough for a full payload plus its metadata. + */ + +#define SX1301_ZEROBUF_SIZE (LORA_GW_MAX_PAYLOAD + SX1301_RX_METADATA_NB) + +/* Convert an intermediate frequency in Hz into the 13 bit signed register + * value: value = (if_hz << 5) / 15625. + */ + +#define SX1301_IF_HZ_TO_REG(f) ((int32_t)(((int64_t)(f) << 5) / 15625)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Radio front-end configuration, derived from the active region */ + +struct sx1301_rfconf_s +{ + bool enable; + bool tx_enable; + uint32_t freq_hz; + int16_t rssi_offset_dbm10; /* RSSI offset in 0.1 dBm units */ +}; + +/* Multi-SF demodulator configuration (IF0..IF7) */ + +struct sx1301_ifconf_s +{ + bool enable; + uint8_t rf_chain; + int32_t freq_hz; /* Offset from the radio centre frequency */ +}; + +/* LoRa standard demodulator configuration (IF8) */ + +struct sx1301_stdconf_s +{ + bool enable; + uint8_t rf_chain; + uint8_t bandwidth; + uint8_t datarate; + int32_t freq_hz; +}; + +/* Driver state */ + +struct sx1301_dev_s +{ + FAR struct spi_dev_s *spi; + FAR const struct sx1301_lower_s *lower; + + mutex_t lock; /* Exclusive access to the chip and state */ + uint8_t page; /* Currently selected register page */ + uint8_t crefs; /* Number of open references */ + bool connected; /* SPI probed and chip identified */ + bool started; /* Concentrator running */ + int region; /* Active region index */ + uint8_t radio_select; /* Radio mapping bitmask of IF0..IF7 */ + + struct lora_gw_status_s status; + struct sx1301_rfconf_s rf[LORA_GW_RF_CHAIN_NB]; + struct sx1301_ifconf_s ifc[LORA_GW_MULTI_NB]; + struct sx1301_stdconf_s std; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Register access, sx1301_reg.c ********************************************/ + +int sx1301_reg_probe(FAR struct sx1301_dev_s *priv); +int sx1301_reg_write(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, uint8_t value); +int sx1301_reg_read(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, FAR uint8_t *value); +int sx1301_reg_wrburst(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, FAR const uint8_t *buffer, + size_t buflen); +int sx1301_reg_rdburst(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, FAR uint8_t *buffer, size_t buflen); +int sx1301_reg_setbit(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, uint8_t bit, bool value); +int sx1301_reg_write13s(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, int32_t value); + +/* Region handling, sx1301_region.c *****************************************/ + +int sx1301_region_count(void); +int sx1301_region_byname(FAR const char *name); +int sx1301_region_getinfo(int region, + FAR struct lora_gw_regioninfo_s *info); +int sx1301_region_apply(FAR struct sx1301_dev_s *priv, int region); + +#endif /* __DRIVERS_WIRELESS_LPWAN_SX1301_SX1301_PRIV_H */ diff --git a/drivers/wireless/lpwan/sx1301/sx1301_reg.c b/drivers/wireless/lpwan/sx1301/sx1301_reg.c new file mode 100644 index 0000000000000..163b16bcc9d27 --- /dev/null +++ b/drivers/wireless/lpwan/sx1301/sx1301_reg.c @@ -0,0 +1,392 @@ +/**************************************************************************** + * drivers/wireless/lpwan/sx1301/sx1301_reg.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Page aware register access for the SX1301. + * + * The SX1301 uses a plain two byte SPI protocol: + * + * write: [0x80 | addr] [data] + * read: [0x00 | addr] [dummy] -> data comes back in the second byte + * + * Bursts keep the same one byte header and let the chip auto increment the + * address internally, which is how the 8 KiB MCU firmware images and the RX + * FIFO are moved. The chip select must stay asserted for the whole burst, + * hence the explicit SPI_SELECT() around each transaction instead of one + * SPI_SNDBLOCK() per buffer. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "sx1301_priv.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* MOSI filler used during burst reads. The reference HAL clocks out zeros + * (the Linux spidev driver sends zeros for a NULL tx buffer), while + * SPI_EXCHANGE() with a NULL tx buffer sends 0xff on most NuttX ports. The + * SX1301 ignores MOSI during the data phase of a read, but keeping the same + * pattern as the reference removes one variable when debugging silence on + * the bus. + */ + +static const uint8_t g_sx1301_zerobuf[SX1301_ZEROBUF_SIZE]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sx1301_lock + * + * Description: + * Take the SPI bus and configure it for the SX1301. + * + ****************************************************************************/ + +static void sx1301_lock(FAR struct sx1301_dev_s *priv) +{ + SPI_LOCK(priv->spi, true); + SPI_SETMODE(priv->spi, SPIDEV_MODE0); + SPI_SETBITS(priv->spi, 8); + SPI_SETFREQUENCY(priv->spi, CONFIG_LPWAN_SX1301_SPIFREQ); +} + +/**************************************************************************** + * Name: sx1301_unlock + ****************************************************************************/ + +static void sx1301_unlock(FAR struct sx1301_dev_s *priv) +{ + SPI_LOCK(priv->spi, false); +} + +/**************************************************************************** + * Name: sx1301_rawwrite + * + * Description: + * Single register write without any page handling. The bus must already + * be locked. + * + ****************************************************************************/ + +static void sx1301_rawwrite(FAR struct sx1301_dev_s *priv, uint8_t addr, + uint8_t value) +{ + uint8_t txbuf[2]; + + txbuf[0] = SX1301_SPI_WRITE_FLAG | (addr & SX1301_SPI_ADDR_MASK); + txbuf[1] = value; + + SPI_SELECT(priv->spi, SPIDEV_LPWAN(0), true); + SPI_SNDBLOCK(priv->spi, txbuf, 2); + SPI_SELECT(priv->spi, SPIDEV_LPWAN(0), false); +} + +/**************************************************************************** + * Name: sx1301_rawread + * + * Description: + * Single register read without any page handling. The bus must already + * be locked. + * + ****************************************************************************/ + +static void sx1301_rawread(FAR struct sx1301_dev_s *priv, uint8_t addr, + FAR uint8_t *value) +{ + uint8_t txbuf[2]; + uint8_t rxbuf[2]; + + txbuf[0] = addr & SX1301_SPI_ADDR_MASK; + txbuf[1] = 0; + + SPI_SELECT(priv->spi, SPIDEV_LPWAN(0), true); + SPI_EXCHANGE(priv->spi, txbuf, rxbuf, 2); + SPI_SELECT(priv->spi, SPIDEV_LPWAN(0), false); + + *value = rxbuf[1]; +} + +/**************************************************************************** + * Name: sx1301_setpage + * + * Description: + * Select a register page, if it is not the current one. The bus must + * already be locked. SX1301_PAGE_ANY leaves the page untouched, for the + * registers that are page independent. + * + ****************************************************************************/ + +static void sx1301_setpage(FAR struct sx1301_dev_s *priv, uint8_t page) +{ + if (page == SX1301_PAGE_ANY || page == priv->page) + { + return; + } + + sx1301_rawwrite(priv, SX1301_REG_PAGE, page & 0x03); + priv->page = page; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sx1301_reg_write + ****************************************************************************/ + +int sx1301_reg_write(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, uint8_t value) +{ + sx1301_lock(priv); + sx1301_setpage(priv, page); + sx1301_rawwrite(priv, addr, value); + sx1301_unlock(priv); + + /* Writing the page register by hand invalidates the cached page */ + + if (addr == SX1301_REG_PAGE) + { + priv->page = value & 0x03; + } + + return OK; +} + +/**************************************************************************** + * Name: sx1301_reg_read + ****************************************************************************/ + +int sx1301_reg_read(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, FAR uint8_t *value) +{ + if (value == NULL) + { + return -EINVAL; + } + + sx1301_lock(priv); + sx1301_setpage(priv, page); + sx1301_rawread(priv, addr, value); + sx1301_unlock(priv); + + return OK; +} + +/**************************************************************************** + * Name: sx1301_reg_wrburst + * + * Description: + * Burst write. The address byte is followed by the whole buffer with the + * chip select held low; the SX1301 increments its internal pointer. + * + ****************************************************************************/ + +int sx1301_reg_wrburst(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, FAR const uint8_t *buffer, + size_t buflen) +{ + uint8_t hdr; + + if (buffer == NULL || buflen == 0) + { + return -EINVAL; + } + + hdr = SX1301_SPI_WRITE_FLAG | (addr & SX1301_SPI_ADDR_MASK); + + sx1301_lock(priv); + sx1301_setpage(priv, page); + + SPI_SELECT(priv->spi, SPIDEV_LPWAN(0), true); + SPI_SNDBLOCK(priv->spi, &hdr, 1); + SPI_SNDBLOCK(priv->spi, buffer, buflen); + SPI_SELECT(priv->spi, SPIDEV_LPWAN(0), false); + + sx1301_unlock(priv); + return OK; +} + +/**************************************************************************** + * Name: sx1301_reg_rdburst + * + * Description: + * Burst read. The first byte clocked back during the address phase is + * discarded, the rest is the payload. + * + ****************************************************************************/ + +int sx1301_reg_rdburst(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, FAR uint8_t *buffer, size_t buflen) +{ + uint8_t hdr; + size_t chunk; + size_t off; + + if (buffer == NULL || buflen == 0) + { + return -EINVAL; + } + + hdr = addr & SX1301_SPI_ADDR_MASK; + + sx1301_lock(priv); + sx1301_setpage(priv, page); + + SPI_SELECT(priv->spi, SPIDEV_LPWAN(0), true); + SPI_SNDBLOCK(priv->spi, &hdr, 1); + + /* Clock out zeros while reading, in chunks of the filler buffer */ + + for (off = 0; off < buflen; off += chunk) + { + chunk = buflen - off; + if (chunk > SX1301_ZEROBUF_SIZE) + { + chunk = SX1301_ZEROBUF_SIZE; + } + + SPI_EXCHANGE(priv->spi, g_sx1301_zerobuf, buffer + off, chunk); + } + + SPI_SELECT(priv->spi, SPIDEV_LPWAN(0), false); + + sx1301_unlock(priv); + return OK; +} + +/**************************************************************************** + * Name: sx1301_reg_setbit + * + * Description: + * Read modify write of a single bit. + * + ****************************************************************************/ + +int sx1301_reg_setbit(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, uint8_t bit, bool value) +{ + uint8_t regval; + int ret; + + ret = sx1301_reg_read(priv, page, addr, ®val); + if (ret < 0) + { + return ret; + } + + if (value) + { + regval |= 1 << bit; + } + else + { + regval &= ~(1 << bit); + } + + return sx1301_reg_write(priv, page, addr, regval); +} + +/**************************************************************************** + * Name: sx1301_reg_write13s + * + * Description: + * Write a 13 bit signed value spanning two consecutive registers, which is + * how the intermediate frequency of every demodulator is programmed. + * + ****************************************************************************/ + +int sx1301_reg_write13s(FAR struct sx1301_dev_s *priv, uint8_t page, + uint8_t addr, int32_t value) +{ + uint16_t raw = value & 0x1fff; + int ret; + + ret = sx1301_reg_write(priv, page, addr, raw & 0xff); + if (ret < 0) + { + return ret; + } + + return sx1301_reg_write(priv, page, addr + 1, (raw >> 8) & 0x1f); +} + +/**************************************************************************** + * Name: sx1301_reg_probe + * + * Description: + * Identify the chip on the bus. Some shields come back with an + * unexpected version right after reset but still report the correct chip + * identifier, so both are checked. + * + * Returned Value: + * OK if an SX1301 answered, -ENODEV otherwise. + * + ****************************************************************************/ + +int sx1301_reg_probe(FAR struct sx1301_dev_s *priv) +{ + uint8_t version; + uint8_t chipid; + + priv->page = 0; + + sx1301_reg_read(priv, SX1301_PAGE_ANY, SX1301_REG_VERSION, &version); + if (version == SX1301_CHIP_VERSION) + { + wlinfo("SX1301 detected, version 0x%02x\n", version); + } + else + { + sx1301_reg_read(priv, SX1301_PAGE_ANY, SX1301_REG_CHIP_ID, &chipid); + if (chipid != SX1301_CHIP_ID_VALUE) + { + wlerr("ERROR: no SX1301 found, version 0x%02x chipid 0x%02x\n", + version, chipid); + return -ENODEV; + } + + wlwarn("WARNING: SX1301 version 0x%02x, chipid 0x%02x, going on\n", + version, chipid); + } + + /* Make sure we start from page 0 */ + + sx1301_reg_write(priv, SX1301_PAGE_ANY, SX1301_REG_PAGE, 0); + priv->page = 0; + priv->connected = true; + + return OK; +} diff --git a/drivers/wireless/lpwan/sx1301/sx1301_region.c b/drivers/wireless/lpwan/sx1301/sx1301_region.c new file mode 100644 index 0000000000000..54d690c72da18 --- /dev/null +++ b/drivers/wireless/lpwan/sx1301/sx1301_region.c @@ -0,0 +1,386 @@ +/**************************************************************************** + * drivers/wireless/lpwan/sx1301/sx1301_region.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Channel plans of the supported regions. + * + * Each plan lists the absolute frequency of the eight multi-SF channels and + * of the LoRa standard channel, plus the centre frequency of the two radios. + * The intermediate frequency of every demodulator is the difference between + * the two, and must stay inside about +/-460 kHz for a 125 kHz channel, + * which is what sx1301_region_apply() checks. + * + * The AU915 and US915 bands are split in eight sub-bands of eight 125 kHz + * channels. Networks pick one: The Things Network and the Brazilian + * deployments use the second sub-band (channels 8 to 15 plus the 500 kHz + * channel 65), so that is the default here. The first sub-band (channels 0 + * to 7 plus channel 64) is available as "AU915-1" and "US915-1". + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "sx1301_priv.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Front-end RSSI offset, in 0.1 dBm units, for the SX125x radios of the + * reference designs. + */ + +#define SX1301_RSSI_OFFSET_DBM10 (-1660) + +/* Largest usable intermediate frequency of a 125 kHz channel */ + +#define SX1301_IF_LIMIT_HZ 460000 + +#define MULTI(f, rf) \ + { \ + .freq_hz = (f), .rf_chain = (rf), \ + .type = LORA_GW_CHAN_MULTI_SF, \ + .bandwidth = LORA_GW_BW_125K, .datarate = 0, \ + .enable = true \ + } + +#define STD(f, rf, bw, sf) \ + { \ + .freq_hz = (f), .rf_chain = (rf), \ + .type = LORA_GW_CHAN_STD, \ + .bandwidth = (bw), .datarate = (sf), \ + .enable = true \ + } + +#define CHAN_OFF(t) \ + { \ + .freq_hz = 0, .rf_chain = 0, .type = (t), \ + .bandwidth = LORA_GW_BW_UNDEFINED, .datarate = 0, \ + .enable = false \ + } + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct lora_gw_regioninfo_s g_sx1301_regions[] = +{ + { + .name = "AU915", + .desc = "AU915 sub-band 2, ch 8-15+65 (BR/AU, TTN)", + .radio_freq = + { + 917100000, 917900000 + }, + .channels = + { + MULTI(916800000, 0), MULTI(917000000, 0), + MULTI(917200000, 0), MULTI(917400000, 0), + MULTI(917600000, 1), MULTI(917800000, 1), + MULTI(918000000, 1), MULTI(918200000, 1), + STD(917500000, 0, LORA_GW_BW_500K, 8), + CHAN_OFF(LORA_GW_CHAN_FSK) + } + }, + { + .name = "AU915-1", + .desc = "AU915 sub-band 1, ch 0-7+64", + .radio_freq = + { + 915500000, 916300000 + }, + .channels = + { + MULTI(915200000, 0), MULTI(915400000, 0), + MULTI(915600000, 0), MULTI(915800000, 0), + MULTI(916000000, 1), MULTI(916200000, 1), + MULTI(916400000, 1), MULTI(916600000, 1), + STD(915900000, 0, LORA_GW_BW_500K, 8), + CHAN_OFF(LORA_GW_CHAN_FSK) + } + }, + { + .name = "US915", + .desc = "US915 sub-band 2, ch 8-15+65 (TTN)", + .radio_freq = + { + 904200000, 905000000 + }, + .channels = + { + MULTI(903900000, 0), MULTI(904100000, 0), + MULTI(904300000, 0), MULTI(904500000, 0), + MULTI(904700000, 1), MULTI(904900000, 1), + MULTI(905100000, 1), MULTI(905300000, 1), + STD(904600000, 0, LORA_GW_BW_500K, 8), + CHAN_OFF(LORA_GW_CHAN_FSK) + } + }, + { + .name = "US915-1", + .desc = "US915 sub-band 1, ch 0-7+64", + .radio_freq = + { + 903500000, 904300000 + }, + .channels = + { + MULTI(903200000, 0), MULTI(903400000, 0), + MULTI(903600000, 0), MULTI(903800000, 0), + MULTI(904000000, 1), MULTI(904200000, 1), + MULTI(904400000, 1), MULTI(904600000, 1), + STD(903900000, 0, LORA_GW_BW_500K, 8), + CHAN_OFF(LORA_GW_CHAN_FSK) + } + }, + { + .name = "EU868", + .desc = "EU863-870, 8 channels + 868.3 BW250", + .radio_freq = + { + 867500000, 868500000 + }, + .channels = + { + MULTI(867100000, 0), MULTI(867300000, 0), + MULTI(867500000, 0), MULTI(867700000, 0), + MULTI(867900000, 0), MULTI(868100000, 1), + MULTI(868300000, 1), MULTI(868500000, 1), + STD(868300000, 1, LORA_GW_BW_250K, 7), + CHAN_OFF(LORA_GW_CHAN_FSK) + } + }, + { + .name = "AS923", + .desc = "AS923-1, 922.2-923.6 MHz", + .radio_freq = + { + 922500000, 923300000 + }, + .channels = + { + MULTI(922200000, 0), MULTI(922400000, 0), + MULTI(922600000, 0), MULTI(922800000, 0), + MULTI(923000000, 1), MULTI(923200000, 1), + MULTI(923400000, 1), MULTI(923600000, 1), + STD(923200000, 1, LORA_GW_BW_250K, 7), + CHAN_OFF(LORA_GW_CHAN_FSK) + } + }, + { + .name = "KR920", + .desc = "KR920-923, 7 channels", + .radio_freq = + { + 922400000, 923100000 + }, + .channels = + { + MULTI(922100000, 0), MULTI(922300000, 0), + MULTI(922500000, 0), MULTI(922700000, 0), + MULTI(922900000, 1), MULTI(923100000, 1), + MULTI(923300000, 1), CHAN_OFF(LORA_GW_CHAN_MULTI_SF), + CHAN_OFF(LORA_GW_CHAN_STD), + CHAN_OFF(LORA_GW_CHAN_FSK) + } + }, + { + .name = "IN866", + .desc = "IN865-867, 3 mandatory + 3 extra channels", + .radio_freq = + { + 865520000, 866300000 + }, + .channels = + { + MULTI(865062500, 0), MULTI(865402500, 0), + MULTI(865985000, 0), MULTI(866100000, 1), + MULTI(866300000, 1), MULTI(866500000, 1), + CHAN_OFF(LORA_GW_CHAN_MULTI_SF), + CHAN_OFF(LORA_GW_CHAN_MULTI_SF), + CHAN_OFF(LORA_GW_CHAN_STD), + CHAN_OFF(LORA_GW_CHAN_FSK) + } + } +}; + +#define SX1301_NREGIONS (sizeof(g_sx1301_regions) / \ + sizeof(g_sx1301_regions[0])) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sx1301_region_count + ****************************************************************************/ + +int sx1301_region_count(void) +{ + return SX1301_NREGIONS; +} + +/**************************************************************************** + * Name: sx1301_region_byname + * + * Description: + * Look up a region by name, case insensitively. + * + * Returned Value: + * The region index, or -ENOENT if there is no such region. + * + ****************************************************************************/ + +int sx1301_region_byname(FAR const char *name) +{ + unsigned int i; + + if (name == NULL) + { + return -EINVAL; + } + + for (i = 0; i < SX1301_NREGIONS; i++) + { + if (strcasecmp(name, g_sx1301_regions[i].name) == 0) + { + return i; + } + } + + return -ENOENT; +} + +/**************************************************************************** + * Name: sx1301_region_getinfo + ****************************************************************************/ + +int sx1301_region_getinfo(int region, + FAR struct lora_gw_regioninfo_s *info) +{ + if (info == NULL) + { + return -EINVAL; + } + + if (region < 0 || region >= sx1301_region_count()) + { + return -ENODEV; + } + + memcpy(info, &g_sx1301_regions[region], sizeof(*info)); + return OK; +} + +/**************************************************************************** + * Name: sx1301_region_apply + * + * Description: + * Translate a channel plan into the radio and demodulator configuration + * used by sx1301_start(). Only radio A is enabled for transmission, as + * on the reference designs where radio B has no PA path. + * + ****************************************************************************/ + +int sx1301_region_apply(FAR struct sx1301_dev_s *priv, int region) +{ + FAR const struct lora_gw_regioninfo_s *ri; + FAR const struct lora_gw_chaninfo_s *ch; + uint32_t centre; + int32_t iffreq; + int i; + + if (region < 0 || region >= sx1301_region_count()) + { + return -ENODEV; + } + + ri = &g_sx1301_regions[region]; + + /* Radios. Both receive, only radio A transmits. */ + + for (i = 0; i < LORA_GW_RF_CHAIN_NB; i++) + { + priv->rf[i].enable = true; + priv->rf[i].tx_enable = (i == 0); + priv->rf[i].freq_hz = ri->radio_freq[i]; + priv->rf[i].rssi_offset_dbm10 = SX1301_RSSI_OFFSET_DBM10; + } + + /* Multi-SF demodulators */ + + for (i = 0; i < LORA_GW_MULTI_NB; i++) + { + ch = &ri->channels[i]; + centre = ri->radio_freq[ch->rf_chain]; + + memset(&priv->ifc[i], 0, sizeof(priv->ifc[i])); + + if (!ch->enable) + { + continue; + } + + iffreq = (int32_t)ch->freq_hz - (int32_t)centre; + if (iffreq > SX1301_IF_LIMIT_HZ || iffreq < -SX1301_IF_LIMIT_HZ) + { + wlerr("ERROR: %s channel %d at %" PRIu32 " Hz is %" PRId32 + " Hz away from radio %d\n", + ri->name, i, ch->freq_hz, iffreq, ch->rf_chain); + return -ERANGE; + } + + priv->ifc[i].enable = true; + priv->ifc[i].rf_chain = ch->rf_chain; + priv->ifc[i].freq_hz = iffreq; + } + + /* LoRa standard demodulator (IF8) */ + + ch = &ri->channels[LORA_GW_MULTI_NB]; + memset(&priv->std, 0, sizeof(priv->std)); + + if (ch->enable) + { + centre = ri->radio_freq[ch->rf_chain]; + iffreq = (int32_t)ch->freq_hz - (int32_t)centre; + + priv->std.enable = true; + priv->std.rf_chain = ch->rf_chain; + priv->std.freq_hz = iffreq; + priv->std.bandwidth = ch->bandwidth; + priv->std.datarate = ch->datarate; + } + + priv->region = region; + + wlinfo("Region %s selected (%s)\n", ri->name, ri->desc); + return OK; +} diff --git a/include/nuttx/wireless/ioctl.h b/include/nuttx/wireless/ioctl.h index f67c2e18b8e2a..b9c15cba9062e 100644 --- a/include/nuttx/wireless/ioctl.h +++ b/include/nuttx/wireless/ioctl.h @@ -182,6 +182,46 @@ #define _WLIOC_OOK_COMMANDS 2 /* ! Must be corrected after changes to commands. * ! Equal to the amount of commands above. */ +/**************************************************************************** + * LoRa gateway common IOCTL commands + ****************************************************************************/ + +/* A LoRa gateway receives on several channels at once, so the frequency, the + * spreading factor and the coding rate belong to each packet rather than + * being settings of one radio: the commands above have nothing to act upon. + * What such a concentrator needs is a channel plan, a way to be started and + * stopped, and the counter its timestamps are taken from. The types these + * commands take are in include/nuttx/wireless/lpwan/lora_gw.h. + */ + +/* Offsets. Must follow WLIOC_OOK */ + +#define _WLIOC_GW_OFFS _WLIOC_OOK_OFFS+_WLIOC_OOK_COMMANDS +#define _WLIOC_GW(x) _WLCIOC(_WLIOC_GW_OFFS+x) + +/* Commands */ + +#define WLIOC_GW_START _WLIOC_GW(0) /* arg: none. Load the firmware, */ + /* calibrate and start receiving */ +#define WLIOC_GW_STOP _WLIOC_GW(1) /* arg: none */ +#define WLIOC_GW_RESET _WLIOC_GW(2) /* arg: none. Stop then start */ + +#define WLIOC_GW_SETREGION _WLIOC_GW(3) /* arg: Pointer to a NUL */ + /* terminated channel plan name */ +#define WLIOC_GW_GETREGION _WLIOC_GW(4) /* arg: Pointer to */ + /* struct lora_gw_regionreq_s */ + +#define WLIOC_GW_GETSTATUS _WLIOC_GW(5) /* arg: Pointer to */ + /* struct lora_gw_status_s */ + +#define WLIOC_GW_GETTRIGCNT _WLIOC_GW(6) /* arg: Pointer to uint32_t, */ + /* concentrator counter in us */ + +/* Number of commands */ + +#define _WLIOC_GW_COMMANDS 7 /* ! Must be corrected after changes to cmds. + * ! Equal to the amount of commands above. */ + /**************************************************************************** * Device-specific IOCTL commands ****************************************************************************/ @@ -191,9 +231,9 @@ * LoRa API. These commands are currently only used by the RN2XX3 driver. */ -/* Offsets. Must follow WLIOC_OOK */ +/* Offsets. Must follow WLIOC_GW */ -#define _WLIOC_RN2XX3_OFFS _WLIOC_OOK_OFFS+_WLIOC_OOK_COMMANDS +#define _WLIOC_RN2XX3_OFFS _WLIOC_GW_OFFS+_WLIOC_GW_COMMANDS #define _WLIOC_RN2XX3(x) _WLCIOC(_WLIOC_RN2XX3_OFFS+x) /* Commands */ diff --git a/include/nuttx/wireless/lpwan/lora_gw.h b/include/nuttx/wireless/lpwan/lora_gw.h new file mode 100644 index 0000000000000..ab6e1b779021f --- /dev/null +++ b/include/nuttx/wireless/lpwan/lora_gw.h @@ -0,0 +1,195 @@ +/**************************************************************************** + * include/nuttx/wireless/lpwan/lora_gw.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_WIRELESS_LPWAN_LORA_GW_H +#define __INCLUDE_NUTTX_WIRELESS_LPWAN_LORA_GW_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Device independent interface of a LoRa gateway, that is, of a concentrator + * demodulating several channels at once instead of one channel at a time as + * an end device does. A driver of this class registers a character device + * where read() returns whole struct lora_gw_rxpkt_s records, write() takes + * one struct lora_gw_txpkt_s, and the channel plan and the state of the chip + * are reached with the WLIOC_GW_* commands of nuttx/wireless/ioctl.h. + * + * The layout below follows the userspace HAL that Semtech publishes for this + * family of chips, which is what gateway software is written against on + * other systems, so that such an application ports by replacing its + * lgw_receive() with read() and its lgw_send() with write(). Two things + * deliberately differ: the signal levels are integers scaled by ten instead + * of floats, and the spreading factor is the plain number, not a bit mask. + * + * Whether the units should instead follow the ones of the end device + * commands of nuttx/wireless/ioctl.h, that is, bandwidth in Hz and levels + * scaled by a hundred, is a question for the common LoRa API rather than for + * one driver, and is left as it is until that API materialises. + */ + +#define LORA_GW_MULTI_NB 8 /* Multi-SF IF chains (IF0..IF7) */ +#define LORA_GW_IF_CHAIN_NB 10 /* 8 multi-SF + LoRa standard + FSK */ +#define LORA_GW_RF_CHAIN_NB 2 /* Radio A and radio B */ +#define LORA_GW_MAX_PAYLOAD 256 /* Maximum PHY payload */ +#define LORA_GW_REGION_NAMELEN 12 +#define LORA_GW_REGION_DESCLEN 48 + +/* Bandwidth codes */ + +#define LORA_GW_BW_UNDEFINED 0x00 +#define LORA_GW_BW_125K 0x04 +#define LORA_GW_BW_250K 0x05 +#define LORA_GW_BW_500K 0x06 + +/* Modulation codes */ + +#define LORA_GW_MOD_LORA 0x10 +#define LORA_GW_MOD_FSK 0x20 + +/* Packet status. A concentrator distinguishes a packet whose CRC was + * checked and passed from one that failed and from one that carried no CRC + * at all. A gateway must never forward LORA_GW_STAT_CRC_BAD as if it were + * valid: those are mostly correlator false triggers. + */ + +#define LORA_GW_STAT_UNDEFINED 0x00 +#define LORA_GW_STAT_NO_CRC 0x01 +#define LORA_GW_STAT_CRC_OK 0x10 +#define LORA_GW_STAT_CRC_BAD 0x11 + +/* TX modes */ + +#define LORA_GW_TX_IMMEDIATE 0 +#define LORA_GW_TX_TIMESTAMPED 1 + +/* Channel types reported by WLIOC_GW_GETREGION */ + +#define LORA_GW_CHAN_OFF 0 +#define LORA_GW_CHAN_MULTI_SF 1 /* One of IF0..IF7, SF7..SF12 */ +#define LORA_GW_CHAN_STD 2 /* IF8, single SF/BW (LoRa standard) */ +#define LORA_GW_CHAN_FSK 3 /* IF9 */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* A packet received by the concentrator. read() returns whole multiples of + * this structure, newest last. + * + * RSSI and SNR are scaled integers (tenths of a dBm/dB) so that no floating + * point is needed in the driver. + */ + +struct lora_gw_rxpkt_s +{ + uint32_t freq_hz; /* Absolute frequency of the receiving channel */ + uint32_t count_us; /* Concentrator timestamp, corrected as per the + * reference HAL */ + int16_t rssi_dbm10; /* RSSI in 0.1 dBm units */ + int16_t snr_db10; /* Signal to noise ratio in 0.1 dB units */ + uint16_t size; /* Payload size in bytes */ + uint8_t if_chain; /* Demodulator index 0..9 */ + uint8_t rf_chain; /* Radio 0 (A) or 1 (B) */ + uint8_t status; /* One of LORA_GW_STAT_* */ + uint8_t modulation; /* LORA_GW_MOD_* */ + uint8_t bandwidth; /* LORA_GW_BW_* */ + uint8_t datarate; /* Spreading factor, 7..12 */ + uint8_t coderate; /* enum wlioc_lora_cr_e */ + uint8_t payload[LORA_GW_MAX_PAYLOAD]; +}; + +/* A packet to transmit. write() takes exactly one of these. */ + +struct lora_gw_txpkt_s +{ + uint32_t freq_hz; + uint32_t count_us; /* On-air time for LORA_GW_TX_TIMESTAMPED */ + uint16_t size; + uint16_t preamble; /* 0 selects the LoRaWAN default of 8 symbols */ + uint8_t tx_mode; /* LORA_GW_TX_IMMEDIATE or _TIMESTAMPED */ + int8_t rf_power; /* Requested antenna power in dBm */ + uint8_t rf_chain; + uint8_t modulation; + uint8_t bandwidth; + uint8_t datarate; + uint8_t coderate; /* enum wlioc_lora_cr_e */ + bool invert_pol; /* True for LoRaWAN downlinks */ + bool no_crc; + bool no_header; + uint8_t payload[LORA_GW_MAX_PAYLOAD]; +}; + +/* Concentrator counters and state */ + +struct lora_gw_status_s +{ + bool started; + uint32_t rx_ok; /* Packets with a valid CRC */ + uint32_t rx_bad; /* Packets dropped because the CRC failed */ + uint32_t rx_nocrc; /* Packets received without CRC */ + uint32_t rx_err; /* FIFO read errors */ + uint32_t tx_ok; + uint32_t tx_err; +}; + +/* One entry of the channel plan of a region */ + +struct lora_gw_chaninfo_s +{ + uint32_t freq_hz; + uint8_t rf_chain; + uint8_t type; /* LORA_GW_CHAN_* */ + uint8_t bandwidth; /* LORA_GW_BW_* */ + uint8_t datarate; /* SF for LORA_GW_CHAN_STD, 0 for multi-SF */ + bool enable; +}; + +/* A complete region description */ + +struct lora_gw_regioninfo_s +{ + char name[LORA_GW_REGION_NAMELEN]; + char desc[LORA_GW_REGION_DESCLEN]; + uint32_t radio_freq[LORA_GW_RF_CHAIN_NB]; + struct lora_gw_chaninfo_s channels[LORA_GW_IF_CHAIN_NB]; +}; + +/* Argument of WLIOC_GW_GETREGION */ + +struct lora_gw_regionreq_s +{ + int index; /* -1: active region, else 0..n */ + struct lora_gw_regioninfo_s info; /* Returned description */ +}; + +#endif /* __INCLUDE_NUTTX_WIRELESS_LPWAN_LORA_GW_H */ diff --git a/include/nuttx/wireless/lpwan/sx1301.h b/include/nuttx/wireless/lpwan/sx1301.h new file mode 100644 index 0000000000000..e1fc304de5e45 --- /dev/null +++ b/include/nuttx/wireless/lpwan/sx1301.h @@ -0,0 +1,108 @@ +/**************************************************************************** + * include/nuttx/wireless/lpwan/sx1301.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_WIRELESS_LPWAN_SX1301_H +#define __INCLUDE_NUTTX_WIRELESS_LPWAN_SX1301_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The SX1301 is a LoRa concentrator (gateway baseband processor) with 8 + * multi-SF demodulators, one LoRa standard demodulator (IF8) and one FSK + * demodulator (IF9), driven by two SX125x radio front-ends accessed + * indirectly through the SX1301 internal SPI bridge. + * + * Only the board glue is here: everything an application deals with is the + * gateway interface of nuttx/wireless/lpwan/lora_gw.h. + */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Board specific hooks. The SX1301 needs a reset line and, on the + * LRWAN_GS_HF1 class of shields, a pair of GPIOs selecting the RF band of + * the front-end filters. + */ + +struct sx1301_lower_s +{ + /* Drive the reset line. 'assert' true holds the chip in reset. */ + + CODE void (*reset)(FAR const struct sx1301_lower_s *lower, bool assert); + + /* Select the RF band of the shield, in MHz (868 or 915). May be NULL on + * boards with a single band. + */ + + CODE void (*band_select)(FAR const struct sx1301_lower_s *lower, + int band_mhz); +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: sx1301_register + * + * Description: + * Register the SX1301 concentrator character driver. + * + * Input Parameters: + * devpath - The full path to the driver to register, e.g. "/dev/lora0" + * spi - An instance of the SPI interface wired to the SX1301 + * lower - Board specific reset and band selection hooks + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int sx1301_register(FAR const char *devpath, FAR struct spi_dev_s *spi, + FAR const struct sx1301_lower_s *lower); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_WIRELESS_LPWAN_SX1301_H */