diff --git a/libraries/AP_OpticalFlow/AP_OpticalFlow_Pixart.cpp b/libraries/AP_OpticalFlow/AP_OpticalFlow_Pixart.cpp new file mode 100644 index 0000000000..9cee004a59 --- /dev/null +++ b/libraries/AP_OpticalFlow/AP_OpticalFlow_Pixart.cpp @@ -0,0 +1,276 @@ +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +/* + driver for Pixart PMW3900DH optical flow sensor + + + NOTE: This sensor does not use traditional SPI register access. The + timing for register reads and writes is critical + */ + +#include +#include +#include +#include "OpticalFlow.h" +#include "AP_OpticalFlow_Pixart_SROM.h" +#include + +extern const AP_HAL::HAL& hal; + +#define PIXART_REG_PRODUCT_ID 0x00 +#define PIXART_REG_REVISION_ID 0x01 +#define PIXART_REG_MOTION 0x02 +#define PIXART_REG_DELTA_X_L 0x03 +#define PIXART_REG_DELTA_X_H 0x04 +#define PIXART_REG_DELTA_Y_L 0x05 +#define PIXART_REG_DELTA_Y_H 0x06 +#define PIXART_REG_SQUAL 0x07 +#define PIXART_REG_RAWDATA_SUM 0x08 +#define PIXART_REG_RAWDATA_MAX 0x09 +#define PIXART_REG_RAWDATA_MIN 0x0A +#define PIXART_REG_SHUTTER_LOW 0x0B +#define PIXART_REG_SHUTTER_HI 0x0C +#define PIXART_REG_CONFIG1 0x0F +#define PIXART_REG_CONFIG2 0x10 +#define PIXART_REG_FRAME_CAP 0x12 +#define PIXART_REG_SROM_EN 0x13 +#define PIXART_REG_RUN_DS 0x14 +#define PIXART_REG_REST1_RATE 0x15 +#define PIXART_REG_REST1_DS 0x16 +#define PIXART_REG_REST2_RATE 0x17 +#define PIXART_REG_REST2_DS 0x18 +#define PIXART_REG_REST3_RATE 0x19 +#define PIXART_REG_OBS 0x24 +#define PIXART_REG_DOUT_L 0x25 +#define PIXART_REG_DOUT_H 0x26 +#define PIXART_REG_RAW_GRAB 0x29 +#define PIXART_REG_SROM_ID 0x2A +#define PIXART_REG_POWER_RST 0x3A +#define PIXART_REG_SHUTDOWN 0x3B +#define PIXART_REG_INV_PROD_ID 0x3F +#define PIXART_REG_MOT_BURST 0x50 +#define PIXART_REG_SROM_BURST 0x62 +#define PIXART_REG_RAW_BURST 0x64 + +// writing to registers needs this flag +#define PIXART_WRITE_FLAG 0x80 + +// timings in microseconds +#define PIXART_Tsrad 150 + +// correct result for SROM CRC +#define PIXART_SROM_CRC_RESULT 0xBEEF + +// constructor +AP_OpticalFlow_Pixart::AP_OpticalFlow_Pixart(OpticalFlow &_frontend) : +OpticalFlow_backend(_frontend) +{ + _dev = std::move(hal.spi->get_device("external0m3")); +} + + +// detect the device +AP_OpticalFlow_Pixart *AP_OpticalFlow_Pixart::detect(OpticalFlow &_frontend) +{ + AP_OpticalFlow_Pixart *sensor = new AP_OpticalFlow_Pixart(_frontend); + if (!sensor) { + return nullptr; + } + if (!sensor->setup_sensor()) { + delete sensor; + return nullptr; + } + return sensor; +} + +// setup the device +bool AP_OpticalFlow_Pixart::setup_sensor(void) +{ + if (!_dev->get_semaphore()->take(0)) { + AP_HAL::panic("Unable to get bus semaphore"); + } + + uint8_t id; + uint16_t crc; + + // power-up sequence + reg_write(PIXART_REG_POWER_RST, 0x5A); + hal.scheduler->delay(50); + + // check product ID + if (reg_read(PIXART_REG_PRODUCT_ID) != 0x3F || + reg_read(PIXART_REG_INV_PROD_ID) != 0xC0) { + goto failed; + } + + srom_download(); + + id = reg_read(PIXART_REG_SROM_ID); + if (id != srom_id) { + printf("Pixart: bad SROM ID: 0x%02x\n", id); + goto failed; + } + + reg_write(PIXART_REG_SROM_EN, 0x15); + hal.scheduler->delay(10); + + crc = reg_read16u(PIXART_REG_DOUT_L); + if (crc != 0xBEEF) { + printf("Pixart: bad SROM CRC: 0x%04x\n", crc); + goto failed; + } + + load_configuration(); + + hal.scheduler->delay(50); + + printf("Pixart ready: prod:0x%02x rev:0x%02x iprod:0x%02x shi:0x%02x cfg1:0x%02x cfg2:0x%02x\n", + (unsigned)reg_read(PIXART_REG_PRODUCT_ID), + (unsigned)reg_read(PIXART_REG_REVISION_ID), + (unsigned)reg_read(PIXART_REG_INV_PROD_ID), + (unsigned)reg_read(PIXART_REG_SHUTTER_HI), + (unsigned)reg_read(PIXART_REG_CONFIG1), + (unsigned)reg_read(PIXART_REG_CONFIG2)); + + _dev->get_semaphore()->give(); + + _dev->register_periodic_callback(2000, FUNCTOR_BIND_MEMBER(&AP_OpticalFlow_Pixart::timer, bool)); + return true; + +failed: + _dev->get_semaphore()->give(); + return false; +} + +// update - read latest values from sensor and fill in x,y and totals. +void AP_OpticalFlow_Pixart::update(void) +{ +} + +// write an 8 bit register +void AP_OpticalFlow_Pixart::reg_write(uint8_t reg, uint8_t value) +{ + _dev->write_register(reg | PIXART_WRITE_FLAG, value); + hal.scheduler->delay_microseconds(120); +} + +// read from an 8 bit register +uint8_t AP_OpticalFlow_Pixart::reg_read(uint8_t reg) +{ + uint8_t v = 0; + _dev->set_chip_select(true); + _dev->transfer(®, 1, nullptr, 0); + hal.scheduler->delay_microseconds(PIXART_Tsrad); + _dev->transfer(nullptr, 0, &v, 1); + _dev->set_chip_select(false); + hal.scheduler->delay_microseconds(120); + return v; +} + +// read from a 16 bit unsigned register +uint16_t AP_OpticalFlow_Pixart::reg_read16u(uint8_t reg) +{ + uint16_t low = reg_read(reg); + uint16_t high = reg_read(reg+1); + return low | (high<<8); +} + +// read from a 16 bit signed register +int16_t AP_OpticalFlow_Pixart::reg_read16s(uint8_t reg) +{ + return (int16_t)reg_read16u(reg); +} + + +void AP_OpticalFlow_Pixart::srom_download(void) +{ + reg_write(0x39, 0x02); + hal.scheduler->delay(1); + reg_write(PIXART_REG_SROM_EN, 0x1D); + hal.scheduler->delay(10); + reg_write(PIXART_REG_SROM_EN, 0x18); + + if (!_dev->set_chip_select(true)) { + printf("Failed to force CS\n"); + } + hal.scheduler->delay_microseconds(1); + uint8_t reg = PIXART_REG_SROM_BURST | PIXART_WRITE_FLAG; + _dev->transfer(®, 1, nullptr, 0); + + for (uint16_t i = 0; i < ARRAY_SIZE(srom_data); i++) { + hal.scheduler->delay_microseconds(15); + _dev->transfer(&srom_data[i], 1, nullptr, 0); + } + + hal.scheduler->delay_microseconds(125); + if (!_dev->set_chip_select(false)) { + printf("Failed to force CS off\n"); + } + hal.scheduler->delay_microseconds(160); +} + +void AP_OpticalFlow_Pixart::load_configuration(void) +{ + for (uint16_t i = 0; i < ARRAY_SIZE(init_data); i++) { + reg_write(init_data[i].reg, init_data[i].value); + } +} + + +void AP_OpticalFlow_Pixart::motion_burst(void) +{ + uint8_t *b = (uint8_t *)&burst; + + burst.delta_x = 0; + burst.delta_y = 0; + + _dev->set_chip_select(true); + uint8_t reg = PIXART_REG_MOT_BURST; + + _dev->transfer(®, 1, nullptr, 0); + hal.scheduler->delay_microseconds(150); + + for (uint8_t i=0; itransfer(nullptr, 0, &b[i], 1); + if (i == 0 && (burst.motion & 0x80) == 0) { + // no motion, save some bus bandwidth + _dev->set_chip_select(false); + return; + } + } + _dev->set_chip_select(false); +} + +bool AP_OpticalFlow_Pixart::timer(void) +{ + if (AP_HAL::micros() - last_burst_us < 500) { + return true; + } + motion_burst(); + last_burst_us = AP_HAL::micros(); + + sum_x += burst.delta_x; + sum_y += burst.delta_y; + + uint32_t now = AP_HAL::millis(); + if (now - last_print_ms >= 100 && (sum_x != 0 || sum_y != 0)) { + last_print_ms = now; + printf("Motion: %d %d obs:0x%02x squal:%u rds:%u maxr:%u minr:%u sup:%u slow:%u\n", + (int)sum_x, (int)sum_y, (unsigned)burst.squal, (unsigned)burst.rawdata_sum, (unsigned)burst.max_raw, + (unsigned)burst.max_raw, (unsigned)burst.min_raw, (unsigned)burst.shutter_upper, (unsigned)burst.shutter_lower); + sum_x = sum_y = 0; + } + return true; +} diff --git a/libraries/AP_OpticalFlow/AP_OpticalFlow_Pixart.h b/libraries/AP_OpticalFlow/AP_OpticalFlow_Pixart.h new file mode 100644 index 0000000000..c443137088 --- /dev/null +++ b/libraries/AP_OpticalFlow/AP_OpticalFlow_Pixart.h @@ -0,0 +1,64 @@ +#pragma once + +#include "OpticalFlow.h" +#include + +class AP_OpticalFlow_Pixart : public OpticalFlow_backend +{ +public: + /// constructor + AP_OpticalFlow_Pixart(OpticalFlow &_frontend); + + // init - initialise the sensor + void init() override {} + + // update - read latest values from sensor and fill in x,y and totals. + void update(void) override; + + // detect if the sensor is available + static AP_OpticalFlow_Pixart *detect(OpticalFlow &_frontend); + +private: + AP_HAL::OwnPtr _dev; + + struct RegData { + uint8_t reg; + uint8_t value; + }; + + struct PACKED MotionBurst { + uint8_t motion; + uint8_t observation; + int16_t delta_x; + int16_t delta_y; + uint8_t squal; + uint8_t rawdata_sum; + uint8_t max_raw; + uint8_t min_raw; + uint8_t shutter_upper; + uint8_t shutter_lower; + } burst; + + static const uint8_t srom_data[]; + static const uint8_t srom_id; + static const RegData init_data[]; + + // setup sensor + bool setup_sensor(void); + + void reg_write(uint8_t reg, uint8_t value); + uint8_t reg_read(uint8_t reg); + int16_t reg_read16s(uint8_t reg); + uint16_t reg_read16u(uint8_t reg); + + void srom_download(void); + void load_configuration(void); + + bool timer(void); + void motion_burst(void); + + int32_t sum_x; + int32_t sum_y; + uint32_t last_print_ms; + uint32_t last_burst_us; +}; diff --git a/libraries/AP_OpticalFlow/AP_OpticalFlow_Pixart_SROM.h b/libraries/AP_OpticalFlow/AP_OpticalFlow_Pixart_SROM.h new file mode 100644 index 0000000000..335b6dfb66 --- /dev/null +++ b/libraries/AP_OpticalFlow/AP_OpticalFlow_Pixart_SROM.h @@ -0,0 +1,280 @@ +/* + SROM for Pixart flow, converted from data supplied by Pixart (thanks to Fish for conversion) + */ + +const uint8_t AP_OpticalFlow_Pixart::srom_id = 0xED; + +const uint8_t AP_OpticalFlow_Pixart::srom_data[] = +{ + 0x03, 0xed, 0xb5, 0x32, 0x26, 0xfc, 0x1e, 0xbe, 0xd8, 0x1d, 0xb8, 0xd3, 0x05, 0x88, 0x73, 0x45, + 0x08, 0x92, 0xa6, 0xce, 0x1e, 0xba, 0xfe, 0x71, 0x5f, 0x1d, 0xb8, 0xf2, 0x66, 0x2f, 0xdc, 0x1b, + 0x95, 0xa8, 0xb3, 0xe4, 0x2b, 0xb5, 0xe8, 0x52, 0x26, 0xce, 0xff, 0x5d, 0x38, 0xf2, 0x66, 0x4e, + 0xff, 0x5d, 0x38, 0xd3, 0x05, 0x6f, 0x31, 0xe0, 0x42, 0x06, 0x8e, 0x7f, 0x7c, 0x5b, 0x34, 0xcb, + 0xf5, 0x68, 0x52, 0x26, 0xce, 0xff, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xdd, 0x19, 0xb3, 0xc3, 0x06, + 0x8a, 0x96, 0x8f, 0x9c, 0x9b, 0x95, 0x81, 0x90, 0x83, 0x84, 0x6a, 0x54, 0x0b, 0x75, 0x49, 0x10, + 0x83, 0x60, 0x41, 0x18, 0x8c, 0x61, 0x34, 0xfe, 0x68, 0xe6, 0xa1, 0x61, 0x44, 0x81, 0x7d, 0xc3, + 0xc7, 0xcf, 0x96, 0x11, 0x65, 0x14, 0x2d, 0xa7, 0xe1, 0x91, 0xe6, 0xfa, 0x99, 0x04, 0x65, 0x1d, + 0x57, 0x98, 0x7c, 0xce, 0x9a, 0xe2, 0x41, 0xd5, 0x0e, 0x3b, 0x51, 0xed, 0x0f, 0x55, 0x45, 0xc0, + 0xbc, 0x32, 0x00, 0xcb, 0x3e, 0x84, 0xba, 0x7a, 0x59, 0x84, 0x04, 0x5f, 0xf2, 0xf3, 0x8b, 0x20, + 0x2d, 0x6c, 0xb5, 0x88, 0x9c, 0x4c, 0x4c, 0x70, 0x45, 0x13, 0x8a, 0x9a, 0x93, 0x64, 0x2b, 0xf5, + 0xa8, 0x7d, 0x63, 0x78, 0xcc, 0xd0, 0xa6, 0x6e, 0x54, 0xff, 0xc9, 0x67, 0x40, 0xe0, 0x4c, 0xdd, + 0x48, 0x58, 0xff, 0xb6, 0x80, 0x95, 0xb5, 0xc3, 0x2b, 0x19, 0x2b, 0x8c, 0x19, 0x66, 0x1a, 0xc6, + 0xac, 0x2e, 0x4a, 0x9f, 0xcc, 0x1e, 0xe6, 0xed, 0x36, 0x2d, 0x63, 0xb4, 0x9b, 0xb9, 0xbf, 0xd9, + 0x22, 0xde, 0xaf, 0xcc, 0xde, 0x02, 0xa3, 0xf7, 0x9a, 0xa5, 0x27, 0x64, 0x19, 0x82, 0x16, 0xdc, + 0xf5, 0x21, 0x93, 0x54, 0xdf, 0x4e, 0x4d, 0x99, 0xac, 0x89, 0x55, 0x3b, 0xb1, 0x73, 0x56, 0x7e, + 0xed, 0x28, 0x46, 0x5d, 0xc6, 0xe7, 0x1f, 0x7f, 0x4c, 0x68, 0x4d, 0x71, 0xf3, 0xa4, 0x5f, 0x41, + 0x9b, 0xe9, 0x23, 0xed, 0x1b, 0xa5, 0xc4, 0x6c, 0x35, 0xb2, 0xfa, 0x82, 0x1e, 0x28, 0xab, 0xf1, + 0x53, 0xb7, 0x4f, 0xf1, 0x00, 0x77, 0xe4, 0x3a, 0x34, 0xe7, 0x4f, 0xfe, 0xbb, 0x84, 0x08, 0x79, + 0x3d, 0x39, 0x90, 0xd2, 0x85, 0x83, 0x0b, 0x76, 0x8a, 0xc7, 0x8e, 0x96, 0xc6, 0x88, 0xbe, 0xfa, + 0x2e, 0x5c, 0x28, 0x2b, 0xa4, 0x69, 0x59, 0xff, 0x07, 0x5f, 0x68, 0x85, 0xd0, 0xe6, 0x1c, 0x88, + 0x2f, 0xe5, 0x10, 0xe0, 0x55, 0x1b, 0xc4, 0xaa, 0x91, 0x2d, 0x69, 0xd2, 0x13, 0x91, 0xb1, 0x40, + 0x25, 0x87, 0xbd, 0x5b, 0x00, 0x75, 0x6c, 0x86, 0x09, 0xb8, 0x78, 0x70, 0xc1, 0x13, 0x1b, 0x5d, + 0xca, 0x47, 0x8e, 0x6f, 0x25, 0x25, 0x53, 0x54, 0x8a, 0x5f, 0x8c, 0x6f, 0x0a, 0xd8, 0xa7, 0xad, + 0xac, 0xc8, 0x73, 0x59, 0xc0, 0x5a, 0x75, 0x95, 0xe8, 0xe6, 0x9b, 0xa8, 0xc0, 0x7a, 0x68, 0x15, + 0xf6, 0x2e, 0x1e, 0xff, 0x57, 0xf9, 0xe4, 0xfc, 0xf4, 0xff, 0x8f, 0xb1, 0xc5, 0xf6, 0x22, 0xf6, + 0xba, 0xb2, 0xd5, 0x88, 0x7e, 0x8f, 0x93, 0x56, 0x32, 0x7c, 0x2d, 0xa0, 0xc1, 0x3f, 0x96, 0x24, + 0xf0, 0x75, 0xe7, 0x17, 0x8d, 0x98, 0x19, 0x8c, 0x0b, 0xfa, 0xd4, 0x98, 0x3e, 0x2f, 0x59, 0xf5, + 0x03, 0x23, 0x4b, 0xa0, 0xbe, 0xca, 0x3b, 0xcd, 0x39, 0xf1, 0x75, 0x4d, 0x2b, 0x17, 0x58, 0x2b, + 0x55, 0x15, 0x53, 0x1b, 0x1e, 0xed, 0xce, 0xb2, 0x32, 0x5d, 0x30, 0x12, 0x37, 0xe7, 0xad, 0x59, + 0x2c, 0x61, 0x35, 0x3f, 0x13, 0xd4, 0x8a, 0x4a, 0x8c, 0x0e, 0xec, 0xfd, 0xbf, 0xc1, 0xa0, 0x87, + 0x24, 0x2a, 0x95, 0xf2, 0x5b, 0x14, 0xa6, 0xca, 0x96, 0x36, 0x07, 0x5e, 0x49, 0x3a, 0x54, 0x0f, + 0x4e, 0xcd, 0xb8, 0xf8, 0xa7, 0xb9, 0xf9, 0xd4, 0x83, 0x64, 0x7e, 0x70, 0xea, 0xa6, 0x1b, 0x3a, + 0xcb, 0xb1, 0xee, 0xdf, 0x53, 0x69, 0x13, 0x33, 0x94, 0xeb, 0x08, 0x39, 0x61, 0xe0, 0x68, 0x17, + 0x58, 0xe9, 0x91, 0xb0, 0x40, 0x3b, 0x38, 0x08, 0x46, 0x0a, 0xaf, 0x7e, 0xb4, 0xc4, 0x7a, 0xb4, + 0xcc, 0x09, 0xe0, 0xe1, 0x46, 0x7a, 0x8c, 0x4e, 0xaf, 0x1b, 0x04, 0x7b, 0x64, 0x10, 0x83, 0xa1, + 0xf3, 0xf5, 0x49, 0x9b, 0x77, 0xcd, 0xff, 0xb0, 0x4b, 0x86, 0x0c, 0x89, 0x4a, 0x13, 0x22, 0x0a, + 0x1e, 0x2c, 0x78, 0xa7, 0x9e, 0x0f, 0x7a, 0x2c, 0x78, 0x85, 0xcc, 0xcb, 0xf7, 0x78, 0x41, 0x26, + 0x5f, 0x9d, 0x22, 0x19, 0x71, 0xcf, 0x9a, 0x59, 0x4b, 0xe4, 0x7a, 0x5f, 0x61, 0xc2, 0xf7, 0xc1, + 0xd4, 0x62, 0x91, 0x7b, 0x5d, 0xc5, 0x05, 0xe1, 0x40, 0x35, 0xa0, 0x24, 0x73, 0x4d, 0xf3, 0x37, + 0xa1, 0xba, 0xd8, 0xa9, 0x0c, 0x21, 0xb6, 0xb7, 0xa9, 0xfe, 0x57, 0xf6, 0xbd, 0xcc, 0xa2, 0x42, + 0x65, 0x0f, 0xc4, 0xb1, 0x03, 0xd0, 0xfb, 0xd3, 0xa2, 0xd8, 0x7b, 0x2e, 0x4c, 0x0f, 0x05, 0x2b, + 0x5a, 0x01, 0xf8, 0x28, 0x30, 0x17, 0x75, 0xc3, 0x9a, 0xb8, 0xba, 0x4d, 0xea, 0x83, 0x3c, 0x20, + 0x7c, 0x5d, 0x60, 0xf9, 0xd3, 0x91, 0x79, 0x8a, 0x78, 0xd1, 0x24, 0x4a, 0xec, 0x29, 0x64, 0xe5, + 0xb3, 0xb9, 0xd9, 0x6b, 0xc1, 0x5c, 0x77, 0x03, 0x27, 0xac, 0x50, 0xff, 0xa2, 0x97, 0xee, 0x3a, + 0x14, 0xb3, 0x46, 0xad, 0xeb, 0xb5, 0x6c, 0x01, 0x15, 0x34, 0xc6, 0x40, 0x80, 0x6d, 0xcc, 0xa6, + 0x31, 0x71, 0xa2, 0xc5, 0xe6, 0x97, 0x8e, 0x3d, 0x0b, 0x54, 0x89, 0x50, 0xdf, 0xa5, 0x10, 0xe7, + 0xf1, 0xa6, 0x44, 0xd6, 0x1e, 0x34, 0x1c, 0x8d, 0xcf, 0xfb, 0xc5, 0xeb, 0x93, 0x11, 0x7f, 0x51, + 0x4d, 0x05, 0x5b, 0xc7, 0xb9, 0x50, 0x1f, 0x47, 0x52, 0xe8, 0xf3, 0x80, 0x3d, 0xcf, 0x31, 0x81, + 0xb3, 0xb5, 0x48, 0xce, 0x84, 0xd4, 0xe4, 0xea, 0x70, 0x3c, 0xce, 0x14, 0x5a, 0x21, 0xca, 0xd7, + 0x4b, 0xdc, 0x2a, 0x11, 0x10, 0x72, 0x57, 0x36, 0xdf, 0x39, 0xc3, 0xf6, 0xce, 0x0c, 0xca, 0x3a, + 0xaf, 0x9f, 0xaf, 0xf4, 0x3b, 0x65, 0xc9, 0xe1, 0x14, 0xf3, 0xf6, 0xcc, 0x28, 0xfb, 0x27, 0x9d, + 0xf9, 0x7b, 0x16, 0x46, 0x3c, 0x6f, 0xa0, 0x6c, 0xce, 0xcc, 0x60, 0xc6, 0x8f, 0x71, 0x0c, 0xb2, + 0xb7, 0xaf, 0x0f, 0x18, 0xbb, 0x65, 0xe8, 0x5c, 0x73, 0x4c, 0x8b, 0xd7, 0x1e, 0xbd, 0x3d, 0xfc, + 0x66, 0xb2, 0x2f, 0x00, 0x8b, 0x5f, 0xd8, 0xf3, 0xc1, 0x68, 0xb2, 0x1a, 0x7f, 0x28, 0xbb, 0x37, + 0x96, 0x97, 0x45, 0xe1, 0xd1, 0x18, 0xc8, 0xaf, 0xd5, 0xa3, 0x20, 0x7f, 0xc0, 0x6a, 0xb6, 0x12, + 0x2f, 0x29, 0xb9, 0x39, 0xdc, 0x18, 0x3a, 0xd8, 0xd7, 0x30, 0x4a, 0xca, 0xaf, 0xb1, 0x18, 0x36, + 0x1b, 0xf5, 0x51, 0xb2, 0x97, 0xed, 0x3b, 0x21, 0x7b, 0x87, 0xfb, 0xa9, 0x7d, 0x3c, 0xe8, 0x9f, + 0x11, 0xd5, 0x48, 0xf1, 0x1b, 0x2b, 0x5b, 0xff, 0x3b, 0x79, 0xe6, 0x0f, 0x7f, 0x07, 0x53, 0x8a, + 0x9d, 0x2a, 0x05, 0xfd, 0xfc, 0x46, 0x0a, 0x44, 0xd9, 0x90, 0x86, 0x61, 0x58, 0x66, 0x1f, 0xfd, + 0x5d, 0xd5, 0x31, 0xb6, 0xee, 0x81, 0xdf, 0x9a, 0x89, 0x8c, 0x19, 0xc6, 0xcf, 0x27, 0x9a, 0x1a, + 0x16, 0x8b, 0x6c, 0x19, 0x19, 0x9e, 0x6e, 0x1f, 0xb8, 0xa4, 0x34, 0x6a, 0x53, 0x9f, 0x1c, 0xbf, + 0x37, 0xf2, 0x17, 0x67, 0xb5, 0x88, 0x77, 0x1b, 0x2b, 0x35, 0xcc, 0x61, 0xc1, 0xe5, 0xa0, 0xfd, + 0xe8, 0xb8, 0xf9, 0x72, 0xa4, 0xb6, 0xce, 0x00, 0x32, 0xe7, 0xdc, 0x5d, 0x63, 0xb6, 0xf3, 0xb9, + 0xf1, 0xb2, 0x05, 0xb2, 0x54, 0xd7, 0x92, 0xc6, 0xfb, 0x9b, 0xce, 0xcd, 0xea, 0xf6, 0x0e, 0x88, + 0xb9, 0xab, 0x07, 0x5e, 0x7d, 0x18, 0x6a, 0x61, 0xfa, 0xc4, 0xdb, 0xb2, 0xa6, 0x4e, 0x44, 0xbb, + 0xbf, 0xe3, 0xf0, 0x14, 0x56, 0x55, 0xb6, 0x28, 0x0e, 0xcc, 0xe6, 0x9b, 0x42, 0xfa, 0x0c, 0x46, + 0xe2, 0x24, 0xaa, 0xcd, 0xc5, 0xd2, 0xd1, 0xbd, 0x98, 0x51, 0x5a, 0xaa, 0x5b, 0x96, 0xef, 0x66, + 0x7d, 0xbc, 0x6c, 0xa6, 0xcf, 0xbf, 0xa7, 0x31, 0x2d, 0xba, 0xd6, 0x54, 0xd8, 0x15, 0x5f, 0xa1, + 0xa0, 0xe1, 0x3a, 0x0b, 0x99, 0x12, 0x67, 0xb3, 0x86, 0x4c, 0x80, 0x7c, 0x79, 0xa4, 0x4b, 0xc3, + 0x88, 0xad, 0xf3, 0x38, 0x75, 0x90, 0x60, 0xc9, 0xa3, 0xb9, 0x57, 0x46, 0x3c, 0xd7, 0xa4, 0x2e, + 0xc0, 0x85, 0x95, 0xe0, 0x45, 0x02, 0x61, 0xa8, 0x31, 0xb2, 0x40, 0x9b, 0x07, 0x0d, 0x51, 0xb1, + 0x31, 0x62, 0x2b, 0xd4, 0x89, 0x96, 0x4b, 0xf3, 0x0c, 0x0a, 0x70, 0xf3, 0x55, 0x38, 0x89, 0x71, + 0x24, 0xf9, 0x16, 0x09, 0x38, 0x94, 0x6c, 0xbb, 0x57, 0x0a, 0x01, 0x69, 0xa2, 0x87, 0x87, 0x9f, + 0xe4, 0xe9, 0x36, 0x1c, 0xbf, 0x5b, 0x89, 0x3a, 0xc3, 0xa2, 0xce, 0x9f, 0xbb, 0x58, 0xb6, 0x68, + 0xaa, 0xee, 0xa8, 0xb5, 0x10, 0x61, 0xd8, 0x4c, 0xfd, 0xe4, 0xcb, 0xa7, 0xea, 0xf0, 0x5d, 0x37, + 0x4c, 0xdd, 0x9b, 0xbb, 0x65, 0xca, 0xe3, 0xb1, 0x75, 0x58, 0x73, 0x6e, 0x6b, 0xd5, 0x31, 0x70, + 0x32, 0x46, 0x0c, 0x6e, 0xc4, 0xf9, 0x07, 0x70, 0x2e, 0xfb, 0x47, 0xe0, 0xce, 0x8a, 0xd7, 0x2e, + 0xc4, 0xd5, 0x86, 0x63, 0x2c, 0xb6, 0x19, 0xb1, 0xc3, 0x7f, 0x82, 0x16, 0x0e, 0xa4, 0x70, 0x4c, + 0xa1, 0x32, 0xb2, 0x83, 0xb8, 0xd7, 0x3e, 0x0c, 0x1b, 0x90, 0x4d, 0x00, 0xf7, 0x1c, 0xfb, 0x51, + 0xec, 0xa2, 0x90, 0xc3, 0x3a, 0xa9, 0x76, 0x70, 0xbe, 0xbd, 0xaf, 0x1d, 0xc3, 0x33, 0x48, 0xb2, + 0xe2, 0xdf, 0x7f, 0xd5, 0x06, 0x5e, 0x5e, 0x3a, 0xa0, 0x1d, 0x19, 0xb5, 0x53, 0x65, 0x4d, 0xf2, + 0x78, 0x1c, 0x1a, 0x8d, 0x20, 0xec, 0xab, 0xb4, 0xee, 0x29, 0x2e, 0x5e, 0x1a, 0x0d, 0x38, 0xf6, + 0x86, 0xd0, 0x4c, 0xba, 0xca, 0x81, 0xae, 0xae, 0x5f, 0x01, 0x3b, 0x60, 0x24, 0x05, 0x4a, 0xc2, + 0xa6, 0x99, 0x3c, 0xe4, 0x40, 0xbf, 0x7b, 0x8c, 0x58, 0xb9, 0xa2, 0xda, 0x91, 0xeb, 0x47, 0x61, + 0x29, 0x55, 0x57, 0x8a, 0x6a, 0xff, 0x5a, 0xdd, 0xbe, 0x37, 0xee, 0x4c, 0x9d, 0x00, 0xf1, 0xc2, + 0xde, 0x63, 0xc2, 0x6e, 0xce, 0xd9, 0x80, 0x73, 0x74, 0xf0, 0x62, 0x63, 0x16, 0x29, 0xb7, 0x44, + 0xac, 0xfd, 0xf8, 0xd0, 0xc9, 0xdb, 0xdd, 0xeb, 0x34, 0xc0, 0x11, 0xf8, 0xd0, 0xc9, 0x3e, 0x1a, + 0x11, 0x3c, 0x50, 0x17, 0x6b, 0x3d, 0x39, 0xf9, 0xc0, 0xf2, 0x05, 0x0f, 0x48, 0xb2, 0xe0, 0x0d, + 0x3d, 0x5f, 0xc4, 0xec, 0x50, 0x85, 0x70, 0xa1, 0x58, 0x4c, 0xfd, 0xc5, 0x89, 0x23, 0xc3, 0xc3, + 0x5a, 0x58, 0x73, 0x43, 0xc4, 0x45, 0x78, 0xb0, 0xf7, 0xba, 0x63, 0x55, 0x6c, 0x5a, 0xe2, 0xc7, + 0xca, 0xd9, 0x95, 0x0f, 0x64, 0xaf, 0x73, 0xe2, 0xdf, 0xde, 0xe6, 0x11, 0x87, 0xf1, 0xc0, 0xb1, + 0xe7, 0xea, 0x69, 0x3e, 0x3f, 0xfa, 0xf6, 0x61, 0x40, 0x33, 0x25, 0x8f, 0x20, 0xb2, 0x45, 0x1c, + 0x6e, 0x0f, 0x1e, 0x8a, 0x40, 0x97, 0xfd, 0xdd, 0x8e, 0x8f, 0x1d, 0x53, 0x23, 0x8a, 0xe3, 0xc8, + 0x48, 0xc0, 0xa1, 0xeb, 0xad, 0xa2, 0x96, 0x2e, 0x17, 0x2e, 0x5d, 0xdd, 0x58, 0xb3, 0x06, 0xfd, + 0xab, 0x85, 0x17, 0x2c, 0xa8, 0xa0, 0x73, 0x20, 0x90, 0x11, 0x04, 0x1d, 0x3d, 0xa1, 0x73, 0x87, + 0x89, 0xa3, 0x56, 0x66, 0x3b, 0xe0, 0xf1, 0xa3, 0x5e, 0x4f, 0x99, 0x78, 0xb7, 0xd9, 0x88, 0xa9, + 0x63, 0x3d, 0x1e, 0xe3, 0x89, 0xfc, 0x3e, 0xec, 0xdd, 0xfb, 0x62, 0x92, 0xad, 0x6c, 0x41, 0xc2, + 0x23, 0xf1, 0x88, 0x27, 0x64, 0x71, 0xb1, 0xbe, 0xf9, 0x4c, 0xd7, 0x21, 0xe5, 0x1a, 0x50, 0xe1, + 0x16, 0x99, 0xbf, 0x6b, 0x4b, 0xd6, 0x0b, 0x82, 0xaa, 0x61, 0x5d, 0x84, 0xb0, 0xde, 0x77, 0x1b, + 0x4a, 0x96, 0x8b, 0x79, 0xed, 0xf2, 0x91, 0xd1, 0x69, 0x6e, 0xfd, 0x7d, 0x9e, 0x8b, 0x6e, 0xfc, + 0xfd, 0x6c, 0x80, 0x30, 0x41, 0x01, 0x6e, 0x8a, 0x4b, 0xd7, 0xf6, 0xc4, 0xee, 0x9f, 0x94, 0xbc, + 0xe9, 0xa4, 0x3c, 0x13, 0xb4, 0xe9, 0x92, 0x51, 0x90, 0x09, 0x19, 0x33, 0x8e, 0x58, 0x6d, 0x7b, + 0xc4, 0x0e, 0x4c, 0xdc, 0x1b, 0xfb, 0xe4, 0x2a, 0xda, 0x45, 0xeb, 0x37, 0x2c, 0xb8, 0xf3, 0xb3, + 0x47, 0x0f, 0x97, 0x99, 0x4a, 0xb4, 0x4c, 0x4e, 0xc4, 0x99, 0xf2, 0x68, 0xa2, 0x12, 0x5a, 0x08, + 0xa4, 0x25, 0x7c, 0xfa, 0xa4, 0xbd, 0x4d, 0xa3, 0xcd, 0x4c, 0x83, 0x5d, 0x7d, 0xbb, 0x31, 0x5e, + 0x28, 0x05, 0x94, 0xaa, 0xd6, 0x0f, 0x9c, 0xba, 0xd7, 0x0d, 0x9c, 0x81, 0x42, 0xc5, 0x56, 0x5d, + 0x05, 0x5b, 0xa7, 0xc1, 0xff, 0xad, 0x88, 0x45, 0x84, 0x4c, 0x6e, 0x84, 0x0c, 0xa1, 0x40, 0x06, + 0x5c, 0x22, 0x25, 0xbe, 0xac, 0x88, 0xb7, 0xfe, 0xae, 0xb0, 0x89, 0x44, 0xde, 0x7f, 0x59, 0xbb, + 0x60, 0x6b, 0xc8, 0x3d, 0x1c, 0xc6, 0xc5, 0x35, 0x48, 0x4d, 0x76, 0x6e, 0x80, 0x99, 0xcc, 0x60, + 0xdb, 0x0b, 0xa6, 0xbf, 0x90, 0x72, 0xe7, 0x48, 0xfa, 0xf2, 0xef, 0x0d, 0x7a, 0x4c, 0x2f, 0xdb, + 0xb2, 0xb4, 0x79, 0xd0, 0x3e, 0x85, 0x6d, 0xda, 0xd2, 0x17, 0x3f, 0x3f, 0xc6, 0x57, 0x45, 0xef, + 0x17, 0x7f, 0x33, 0x78, 0xd1, 0x11, 0x2d, 0x3d, 0x84, 0x64, 0xd7, 0x8f, 0x5c, 0x9d, 0xf1, 0xa2, + 0xf3, 0xa5, 0x9f, 0x51, 0x1f, 0xd2, 0x85, 0x9d, 0x7e, 0xc0, 0x49, 0xcd, 0xa4, 0x68, 0xd8, 0x2d, + 0x78, 0x97, 0x21, 0xbd, 0x46, 0xca, 0xb7, 0x30, 0x6c, 0xcf, 0xcf, 0x24, 0x2f, 0x08, 0x13, 0x8c, + 0x2a, 0x26, 0x6d, 0x81, 0x0b, 0x15, 0xbf, 0x70, 0x5d, 0x37, 0x4f, 0x08, 0x77, 0xd2, 0x8c, 0x66, + 0xf2, 0xa4, 0xcd, 0x1b, 0x35, 0x2c, 0x57, 0x30, 0x3d, 0x3c, 0x7a, 0xaa, 0x18, 0x06, 0x7c, 0x63, + 0xa1, 0x81, 0xbd, 0x00, 0x46, 0xbb, 0xf6, 0x3e, 0x3c, 0xd4, 0xf9, 0xf5, 0x80, 0xe0, 0x87, 0x63, + 0x19, 0xae, 0x59, 0xf2, 0xcf, 0xbf, 0xf5, 0x96, 0x4e, 0xbf, 0x3b, 0xec, 0x96, 0xf3, 0x68, 0x4e, + 0x30, 0x41, 0x0f, 0x6e, 0xfa, 0x9e, 0xcc, 0xe1, 0xd1, 0x7d, 0x66, 0xe8, 0xa9, 0x0b, 0x37, 0xda, + 0xf4, 0x74, 0x55, 0x88, 0x1e, 0x81, 0x09, 0x83, 0xd5, 0x69, 0x76, 0xc2, 0x58, 0x1f, 0x6f, 0x41, + 0x68, 0xb5, 0xbb, 0x1c, 0xed, 0xb2, 0x2f, 0xdc, 0xaa, 0x76, 0x69, 0xf3, 0x6b, 0x24, 0x4b, 0x33, + 0x6b, 0x6b, 0x79, 0x42, 0x3a, 0x9e, 0x19, 0xe3, 0xac, 0x8d, 0x72, 0xce, 0xff, 0xec, 0xfa, 0x51, + 0x81, 0xae, 0xae, 0x5d, 0xcc, 0x79, 0x04, 0xe3, 0x5f, 0xeb, 0xa4, 0xef, 0xaf, 0x6a, 0xf4, 0xbd, + 0xbe, 0x3b, 0x63, 0xf9, 0xb4, 0xc6, 0xd9, 0xbc, 0x11, 0x07, 0x2e, 0x4b, 0x80, 0xea, 0xc7, 0xef, + 0x79, 0x72, 0x87, 0x1d, 0x5c, 0x79, 0xa5, 0x5c, 0x92, 0xf7, 0xae, 0xb8, 0x72, 0x95, 0x9f, 0x28, + 0x79, 0x64, 0xa4, 0x3e, 0x03, 0x66, 0x58, 0x92, 0xb8, 0xdb, 0xbf, 0x08, 0xb6, 0x1a, 0x68, 0xc7, + 0xfe, 0x4b, 0x0a, 0xcd, 0x62, 0xc2, 0x34, 0x8a, 0x66, 0x0f, 0xd4, 0xeb, 0xe1, 0x08, 0x71, 0x23, + 0x8e, 0xea, 0xb1, 0x68, 0x39, 0xb3, 0x45, 0xeb, 0x8d, 0x7d, 0x42, 0xb7, 0x3a, 0xb2, 0xd5, 0x5b, + 0x81, 0xf5, 0x65, 0x01, 0x4b, 0x36, 0xcb, 0xc6, 0x7d, 0x73, 0x74, 0x67, 0x2c, 0x17, 0x04, 0x5c, + 0xd3, 0x20, 0xd1, 0xba, 0x91, 0xe5, 0xd7, 0x09, 0x42, 0x81, 0x70, 0x93, 0x4f, 0x78, 0xa6, 0xbd, + 0x14, 0x02, 0x3c, 0x1b, 0x70, 0x70, 0x04, 0x1b, 0xd1, 0xa8, 0x31, 0x23, 0x70, 0x41, 0x74, 0x03, + 0x84, 0x5e, 0xa3, 0xfb, 0x64, 0x5a, 0xa0, 0x16, 0x9e, 0x27, 0x92, 0x9b, 0x4c, 0x72, 0xa7, 0x0a, + 0x7f, 0x03, 0x9b, 0x7c, 0xfb, 0x90, 0x6c, 0x25, 0xb3, 0x63, 0x5e, 0x40, 0x32, 0x3a, 0x21, 0xfd, + 0x32, 0xb0, 0x4b, 0x86, 0x26, 0x3f, 0x53, 0x96, 0x3e, 0xec, 0x34, 0x90, 0xb1, 0x71, 0xc5, 0x3d, + 0x73, 0x0b, 0x37, 0xe3, 0xa6, 0x9f, 0x1f, 0x8a, 0x54, 0x7f, 0x15, 0xbc, 0xe3, 0x12, 0xcb, 0x45, + 0xab, 0xa1, 0x04, 0xbb, 0x35, 0xef, 0xe0, 0x32, 0x24, 0xdf, 0x1b, 0xe4, 0xea, 0x10, 0x1c, 0x19, + 0xe4, 0x89, 0xf0, 0x72, 0x56, 0x73, 0x01, 0xbb, 0x33, 0x54, 0xad, 0x85, 0x45, 0x64, 0x6f, 0x6f, + 0x90, 0xf6, 0xd1, 0x77, 0x02, 0x5f, 0x60, 0x9d, 0x83, 0x81, 0xfa, 0xce, 0x08, 0xe8, 0x26, 0xcc, + 0x21, 0x64, 0x3c, 0x1c, 0xe7, 0xa0, 0x8f, 0xb9, 0xc3, 0x13, 0xf4, 0xa5, 0xac, 0xcb, 0xad, 0x65, + 0x54, 0x33, 0xed, 0xc9, 0xea, 0xa1, 0xa3, 0x07, 0xea, 0x77, 0xbe, 0x3e, 0x8e, 0xb7, 0x14, 0xbf, + 0x1f, 0xc8, 0x5a, 0x8f, 0xdd, 0x70, 0x12, 0x3d, 0x82, 0x16, 0xff, 0xea, 0x86, 0xbe, 0x2c, 0x30, + 0xa3, 0x89, 0x53, 0x75, 0xf0, 0xfe, 0x43, 0xfc, 0x12, 0x67, 0x9d, 0x35, 0x0b, 0x6f, 0x3f, 0x3f, + 0x71, 0x4b, 0x5d, 0xc0, 0xb6, 0x2c, 0x52, 0xa7, 0x6f, 0x19, 0x0b, 0xcb, 0xf9, 0x87, 0xe7, 0xce, + 0x9b, 0x5b, 0xf6, 0xb9, 0x5b, 0x4f, 0xcd, 0xbd, 0x4f, 0x31, 0xc2, 0xc5, 0x85, 0x53, 0x3f, 0x99, + 0xd9, 0xc8, 0x26, 0xed, 0x2c, 0x73, 0xdd, 0xa9, 0x55, 0x71, 0xfb, 0xf4, 0x1e, 0x9c, 0xde, 0xa4, + 0xb1, 0x26, 0x44, 0x68, 0x17, 0x43, 0x0c, 0x0c, 0xb4, 0x20, 0xa4, 0x0c, 0x02, 0x97, 0x75, 0x24, + 0xdb, 0xec, 0x54, 0x7b, 0xa5, 0xd4, 0x11, 0x64, 0xc8, 0xff, 0x56, 0x0d, 0xec, 0x36, 0xa7, 0x0d, + 0xa8, 0x67, 0x4c, 0xd7, 0xba, 0xd8, 0x09, 0x15, 0x2a, 0xbb, 0xde, 0x1d, 0xed, 0x34, 0xc2, 0x26, + 0xfe, 0x2a, 0xd4, 0x02, 0x73, 0xf8, 0x30, 0x15, 0xe5, 0xc1, 0x40, 0x87, 0x83, 0xd8, 0xa5, 0x05, + 0x5e, 0x75, 0xca, 0xc1, 0x46, 0x1b, 0xd8, 0x31, 0x32, 0x11, 0x5b, 0x80, 0x70, 0x75, 0xb5, 0x1e, + 0x76, 0xbd, 0x0f, 0xd3, 0x15, 0x3e, 0xcb, 0x05, 0x16, 0x08, 0xf0, 0x94, 0x05, 0xbd, 0x42, 0xb1, + 0x2c, 0xcf, 0x60, 0xd2, 0xe3, 0x58, 0x2b, 0x9d, 0x79, 0x9b, 0x45, 0xe3, 0x30, 0xf7, 0x42, 0x80, + 0x68, 0x18, 0xb2, 0xc4, 0x09, 0xad, 0x53, 0x87, 0x9c, 0x65, 0xa4, 0xd7, 0x37, 0x1a, 0xd7, 0xa1, + 0x77, 0x25, 0x54, 0x64, 0x85, 0xc5, 0xb8, 0x26, 0xeb, 0x06, 0x69, 0x43, 0x7c, 0x6b, 0x25, 0xbf, + 0xbe, 0x56, 0x4a, 0xe5, 0x1a, 0x02, 0x36, 0xfa, 0x18, 0xba, 0xff, 0x2e, 0x56, 0x19, 0xf1, 0x69, + 0xe0, 0x53, 0xc0, 0xd8, 0xf7, 0xc6, 0x78, 0x1b, 0x76, 0x4e, 0x55, 0x6e, 0x37, 0xbb, 0xa7, 0xe5, + 0x0a, 0xf5, 0x79, 0x79, 0x11, 0x2f, 0x85, 0x9b, 0x9c, 0xdb, 0x91, 0xbd, 0xf6, 0x45, 0xd9, 0x02, + 0x04, 0x64, 0x4d, 0xf1, 0xb3, 0x65, 0xe0, 0xd2, 0x34, 0xf9, 0xea, 0x8a, 0xee, 0x9c, 0x25, 0x9c, + 0x05, 0xd7, 0x39, 0x7a, 0x54, 0xdc, 0x94, 0x77, 0xc0, 0xd4, 0x67, 0x61, 0x6b, 0xb1, 0x8a, 0x64, + 0x64, 0x01, 0x07, 0x0e, 0x28, 0x7c, 0x1f, 0x01, 0x37, 0x40, 0x0a, 0xc4, 0x88, 0x26, 0xdc, 0xeb, + 0x80, 0x23, 0x99, 0xca, 0x3e, 0x0b, 0x68, 0xbb, 0xe8, 0x0b, 0x77, 0xf3, 0x11, 0x1f, 0x23, 0x91, + 0x7d, 0x85, 0xc0, 0x2b, 0xc5, 0x9c, 0x14, 0x5c, 0x25, 0x83, 0xbb, 0x0e, 0x29, 0xfa, 0x0f, 0x85, + 0x5f, 0xc8, 0xb9, 0x07, 0x53, 0xf2, 0x60, 0xcb, 0xc3, 0xb2, 0x25, 0xa6, 0x35, 0x88, 0xfc, 0x55, + 0xaf, 0xc6, 0x68, 0x19, 0xa4, 0x30, 0x65, 0xb2, 0xb5, 0x7b, 0xae, 0x7d, 0x1b, 0x4f, 0xca, 0x21, + 0x1f, 0x46, 0xfb, 0x42, 0x6e, 0xfd, 0xd9, 0xc6, 0x81, 0x61, 0x75, 0xbe, 0x52, 0x0d, 0x3f, 0x58, + 0xa8, 0x71, 0x6c, 0xce, 0x1d, 0x0f, 0x1e, 0xb3, 0x33, 0xf0, 0x7e, 0xb5, 0xbe, 0x05, 0x7a, 0x2a, + 0xa8, 0x71, 0xb4, 0x2f, 0x9f, 0x1b, 0x30, 0xe1, 0x27, 0x29, 0xf2, 0xac, 0x19, 0x1e, 0x05, 0xe8, + 0xbc, 0xd5, 0x89, 0xf3, 0x9f, 0x4b, 0x23, 0x3a, 0x2d, 0x0c, 0xac, 0x93, 0xc7, 0xad, 0xee, 0xd1, + 0x44, 0x77, 0xba, 0x3b, 0xd8, 0x7a, 0xd2, 0x9d, 0xfa, 0x5d, 0xa0, 0xa0, 0x54, 0x68, 0x38, 0x08, + 0xc6, 0xd2, 0xed, 0x0e, 0x65, 0x3a, 0xcb, 0x6a, 0xf5, 0xbc, 0x5e, 0x3d, 0x7e, 0xdb, 0x16, 0x28, + 0x37, 0xef, 0x88, 0x31, 0xd3, 0x0d, 0xcc, 0x03, 0x40, 0xa3, 0x42, 0x2b, 0x5c, 0xa8, 0x50, 0x11, + 0x99, 0xc0, 0xa1, 0xa8, 0x9d, 0x38, 0x07, 0x44, 0xef, 0xd7, 0xda, 0x14, 0x0f, 0xcf, 0x0e, 0x6e, + 0xfc, 0x0a, 0xa6, 0xd2, 0x34, 0xa9, 0x82, 0x96, 0x1e, 0xc0, 0xe6, 0xa4, 0x5e, 0x6a, 0x5e, 0xfc, + 0xae, 0x5f, 0x03, 0xcc, 0xd1, 0xf5, 0xcb, 0xae, 0x85, 0xcf, 0x47, 0x5d, 0x4a, 0x4f, 0x40, 0x22, + 0xf3, 0xa6, 0xd8, 0x16, 0x09, 0x19, 0xe2, 0x84, 0xa3, 0x50, 0x75, 0x14, 0x0e, 0x01, 0x57, 0x01, + 0xc1, 0xef, 0xd0, 0x60, 0x35, 0x49, 0x13, 0x67, 0xe5, 0xbd, 0xd3, 0xb0, 0x41, 0x72, 0x8d, 0xac, + 0x8b, 0x16, 0xb8, 0x32, 0xf2, 0xc0, 0x79, 0x52, 0x4c, 0x84, 0x29, 0xa2, 0x0c, 0x0e, 0x37, 0x1b, + 0xad, 0x3d, 0x0d, 0x1a, 0xa6, 0x02, 0xd2, 0x5e, 0x9b, 0xd1, 0x20, 0xa3, 0xc4, 0xeb, 0x54, 0x2a, + 0xb7, 0xcd, 0xf9, 0x70, 0x62, 0x46, 0xef, 0x5c, 0x3a, 0xd7, 0x2c, 0xda, 0x17, 0x8d, 0x79, 0x51, + 0x20, 0xc2, 0xe7, 0x4c, 0x1a, 0x97, 0xac, 0xda, 0x17, 0x8d, 0x98, 0x93, 0xa4, 0xca, 0x16, 0x8f, + 0x9c, 0xba, 0xf6, 0x4f, 0x1c, 0xba, 0xd7, 0x2c, 0xda, 0x36, 0xee, 0x3f, 0xdd, 0x19, 0x91, 0xa0, + 0xa3, 0xa5, 0xc8, 0x12, 0x87, 0x8c, 0x9a, 0xb6, 0xcf, 0xfd, 0x78, 0x53, 0x24, 0xca, 0x16, 0xae, + 0xbf, 0xfc, 0x5b, 0x34, 0xcb, 0xf5, 0x68, 0x33, 0xc5, 0xe9, 0x50, 0x22, 0xc6, 0x0e, 0x7f, 0x5d, + 0x38, 0xf2, 0x66, 0x2f, 0xbd, 0xd9, 0x11, 0xa0, 0xa3, 0xa5, 0xa9, 0xb1, 0xe0, 0x23, 0xa5, 0xa9, + 0xb1, 0xc1, 0xe1, 0x21, 0xa1, 0xc0, 0x02, 0x67, 0x2d, 0xb9, 0xd1, 0x20, 0xc2, 0x06, 0x6f, 0x3d, + 0xd9, 0x30, 0xc3, 0x04, 0x6b, 0x35, 0xc9, 0xf1, 0x60, 0x23, 0xc4, 0xeb, 0x35, 0xc9, 0x10, 0xa2, + 0xa7, 0xcc, 0xfb, 0x55, 0x28, 0xd2, 0x26, 0xaf, 0xbd, 0xf8, 0x72, 0x47, 0xed, 0x39, 0xd1, 0x20, + 0xa3, 0xc4, 0xeb, 0x35, 0xe8, 0x52, 0x26, 0xaf, 0xdc, 0x3a, 0xf6, 0x4f, 0xfd, 0x59, 0x30, 0xe2, + 0x46, 0x0e, 0x7f, 0x5d, 0x19, 0x91, 0x81, 0x61, 0x21, 0xc0, 0xe3, 0x25, 0xa9, 0xb1, 0xe0, 0x42, + 0x06, 0x6f, 0x3d, 0xf8, 0x72, 0x47, 0x0c, 0x7b, 0x74, 0x4b, 0x14, 0x8b, 0x75, 0x49, 0x10, 0x83, + 0x84, 0x6b, 0x54, 0x0b, 0x94, 0x8b, 0x94, 0xaa, 0xb7, 0xec, 0xa2, 0xc7, 0x77, 0xd9, +}; + + +/* + initialisation data (register config) + */ +const AP_OpticalFlow_Pixart::RegData AP_OpticalFlow_Pixart::init_data[] = +{ + { 0x30, 0x44 }, + + { 0x31, 0xe9 }, + { 0x32, 0x82 }, + { 0x33, 0xdf }, + + { 0x31, 0xea }, + { 0x32, 0x82 }, + { 0x33, 0xff }, + + { 0x31, 0xeb }, + { 0x32, 0x82 }, + { 0x33, 0xdf }, + + { 0x31, 0xec }, + { 0x32, 0x82 }, + { 0x33, 0xff }, + + { 0x31, 0xed }, + { 0x32, 0x82 }, + { 0x33, 0xdf }, + + { 0x31, 0xee }, + { 0x32, 0x82 }, + { 0x33, 0xff }, + + + { 0x31, 0xdd }, + { 0x32, 0x82 }, + { 0x33, 0xfe }, + + { 0x31, 0xde }, + { 0x32, 0x82 }, + { 0x33, 0x0b }, + + { 0x31, 0xdf }, + { 0x32, 0x82 }, + { 0x33, 0xfe }, + + { 0x31, 0xe0 }, + { 0x32, 0x82 }, + { 0x33, 0x0b }, + + { 0x31, 0xe1 }, + { 0x32, 0x82 }, + { 0x33, 0xfe }, + + { 0x31, 0xe2 }, + { 0x32, 0x82 }, + { 0x33, 0x0b }, + + { 0x47, 0x00 }, + { 0x10, 0x08 }, + + { 0x0f, 0x28 }, + { 0x2b, 0x08 }, + { 0x2c, 0x10 }, + { 0x2e, 0x1f }, + + { 0x49, 0x40 }, + { 0x4a, 0x60 }, + { 0x4b, 0x3F }, + + { 0x10, 0x08 }, + { 0x30, 0x00 }, + + { 0x45, 0x8b }, + { 0x46, 0x02 }, + { 0x53, 0x07 }, + { 0x52, 0x10 }, +}; + diff --git a/libraries/AP_OpticalFlow/OpticalFlow.cpp b/libraries/AP_OpticalFlow/OpticalFlow.cpp index 22d6f18e85..2e6a6969e7 100644 --- a/libraries/AP_OpticalFlow/OpticalFlow.cpp +++ b/libraries/AP_OpticalFlow/OpticalFlow.cpp @@ -1,3 +1,4 @@ +#include #include "OpticalFlow.h" #include "AP_OpticalFlow_Onboard.h" @@ -74,7 +75,13 @@ void OpticalFlow::init(void) { if (!backend) { #if CONFIG_HAL_BOARD == HAL_BOARD_PX4 || CONFIG_HAL_BOARD == HAL_BOARD_VRBRAIN - backend = new AP_OpticalFlow_PX4(*this); + if (AP_BoardConfig::get_board_type() == AP_BoardConfig::PX4_BOARD_PIXHAWK) { + // possibly have pixhart on external SPI + backend = AP_OpticalFlow_Pixart::detect(*this); + } + if (backend == nullptr) { + backend = new AP_OpticalFlow_PX4(*this); + } #elif CONFIG_HAL_BOARD == HAL_BOARD_SITL backend = new AP_OpticalFlow_HIL(*this); #elif CONFIG_HAL_BOARD_SUBTYPE == HAL_BOARD_SUBTYPE_LINUX_BEBOP ||\ diff --git a/libraries/AP_OpticalFlow/OpticalFlow.h b/libraries/AP_OpticalFlow/OpticalFlow.h index 793c6c4505..7d7a8928a9 100644 --- a/libraries/AP_OpticalFlow/OpticalFlow.h +++ b/libraries/AP_OpticalFlow/OpticalFlow.h @@ -103,3 +103,4 @@ private: #include "AP_OpticalFlow_HIL.h" #include "AP_OpticalFlow_PX4.h" #include "AP_OpticalFlow_Linux.h" +#include "AP_OpticalFlow_Pixart.h" diff --git a/libraries/AP_OpticalFlow/OpticalFlow_backend.cpp b/libraries/AP_OpticalFlow/OpticalFlow_backend.cpp index 2341cf7f4f..2c867d80f1 100644 --- a/libraries/AP_OpticalFlow/OpticalFlow_backend.cpp +++ b/libraries/AP_OpticalFlow/OpticalFlow_backend.cpp @@ -23,6 +23,13 @@ OpticalFlow_backend::OpticalFlow_backend(OpticalFlow &_frontend) : _sem = hal.util->new_semaphore(); } +OpticalFlow_backend::~OpticalFlow_backend(void) +{ + if (_sem) { + delete _sem; + } +} + // update the frontend void OpticalFlow_backend::_update_frontend(const struct OpticalFlow::OpticalFlow_state &state) { diff --git a/libraries/AP_OpticalFlow/OpticalFlow_backend.h b/libraries/AP_OpticalFlow/OpticalFlow_backend.h index e0e4226f11..a562af97da 100644 --- a/libraries/AP_OpticalFlow/OpticalFlow_backend.h +++ b/libraries/AP_OpticalFlow/OpticalFlow_backend.h @@ -27,7 +27,8 @@ class OpticalFlow_backend public: // constructor OpticalFlow_backend(OpticalFlow &_frontend); - + virtual ~OpticalFlow_backend(void); + // init - initialise sensor virtual void init() = 0;