Skip to content
Snippets Groups Projects
Commit 0bb9878c authored by Per Lindgren's avatar Per Lindgren Committed by tommy
Browse files

SPI example updated

parent 6c5b6591
Branches
No related tags found
No related merge requests found
...@@ -3,12 +3,23 @@ ...@@ -3,12 +3,23 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
// use cortex_m::{iprintln, peripheral::DWT};
use embedded_hal::spi::MODE_3; use embedded_hal::spi::MODE_3;
// use cortex_m_semihosting::hprintln; use panic_rtt_target as _;
use panic_halt as _;
// use rtic::cyccnt::{Instant, U32Ext as _}; use rtic::cyccnt::{Instant, U32Ext as _};
use stm32f4xx_hal::{dwt::Dwt, gpio::Speed, prelude::*, rcc::Clocks, spi::Spi, stm32}; use stm32f4xx_hal::{
dwt::Dwt,
gpio::Speed,
gpio::{
gpiob::{PB10, PB4},
gpioc::{PC2, PC3},
Alternate, Output, PushPull,
},
prelude::*,
rcc::Clocks,
spi::Spi,
stm32,
};
use app::{ use app::{
pmw3389::{self, Register}, pmw3389::{self, Register},
...@@ -16,35 +27,41 @@ use app::{ ...@@ -16,35 +27,41 @@ use app::{
}; };
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprintln, rtt_init_print};
type PMW3389T = pmw3389::Pmw3389<
Spi<
stm32f4xx_hal::stm32::SPI2,
(
PB10<Alternate<stm32f4xx_hal::gpio::AF5>>,
PC2<Alternate<stm32f4xx_hal::gpio::AF5>>,
PC3<Alternate<stm32f4xx_hal::gpio::AF5>>,
),
>,
PB4<Output<PushPull>>,
>;
#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)] #[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
const APP: () = { const APP: () = {
struct Resources { struct Resources {
// late resources // late resources
GPIOA: stm32::GPIOA, pmw3389: PMW3389T,
} }
#[init(schedule = [toggle])] #[init(schedule = [poll])]
fn init(cx: init::Context) -> init::LateResources { fn init(cx: init::Context) -> init::LateResources {
rtt_init_print!(); rtt_init_print!();
rprintln!("init");
let mut core = cx.core; let mut core = cx.core;
let device = cx.device; let device = cx.device;
// Configure led: // Initialize (enable) the monotonic timer (CYCCNT)
// power on GPIOA, RM0368 6.3.11 core.DCB.enable_trace();
device.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); core.DWT.enable_cycle_counter();
// configure PA5 as output, RM0368 8.4.1
device.GPIOA.moder.modify(|_, w| w.moder5().bits(1));
// setup clocks // setup clocks
let rcc = device.RCC.constrain(); let rcc = device.RCC.constrain();
let clocks = rcc.cfgr.freeze(); let clocks = rcc.cfgr.freeze();
rprintln!("clocks:");
rprintln!("------------"); rprintln!("hclk {}", clocks.hclk().0);
rprintln!("pmw3389");
// Initialize (enable) the monotonic timer (CYCCNT)
core.DCB.enable_trace();
// Configure SPI // Configure SPI
// spi2 // spi2
...@@ -64,812 +81,74 @@ const APP: () = { ...@@ -64,812 +81,74 @@ const APP: () = {
let miso = gpioc.pc2.into_alternate_af5(); let miso = gpioc.pc2.into_alternate_af5();
let mosi = gpioc.pc3.into_alternate_af5(); let mosi = gpioc.pc3.into_alternate_af5();
let cs = gpiob.pb4.into_push_pull_output().set_speed(Speed::High); let cs = gpiob.pb4.into_push_pull_output().set_speed(Speed::High);
// let cs = gpiob.pb4.into_push_pull_output();
let spi = Spi::spi2( let spi = Spi::spi2(
device.SPI2, device.SPI2,
(sck, miso, mosi), (sck, miso, mosi),
MODE_3, MODE_3,
stm32f4xx_hal::time::KiloHertz(1000).into(), stm32f4xx_hal::time::KiloHertz(2000).into(),
clocks, clocks,
); );
let mut delay = DwtDelay::new(&mut core.DWT, clocks); let mut delay = DwtDelay::new(&mut core.DWT, clocks);
rprintln!("clocks:");
rprintln!("hclk {}", clocks.hclk().0);
// test the delay
let t1 = stm32::DWT::get_cycle_count();
delay.delay_us(1000);
let t2 = stm32::DWT::get_cycle_count();
rprintln!("1000us {}", t2.wrapping_sub(t1));
let t1 = stm32::DWT::get_cycle_count();
delay.delay_ms(1000);
let t2 = stm32::DWT::get_cycle_count();
rprintln!("1000ms {}", t2.wrapping_sub(t1));
let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap(); let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap();
let mut delay = DwtDelay::new(&mut core.DWT, clocks);
// loop {
// pmw3389.write_register(Register::Motion, 0x01).ok();
// let motion = pmw3389.read_register(Register::Motion).unwrap();
// let xl = pmw3389.read_register(Register::DeltaXL).unwrap();
// let xh = pmw3389.read_register(Register::DeltaXH).unwrap();
// let yl = pmw3389.read_register(Register::DeltaYL).unwrap();
// let yh = pmw3389.read_register(Register::DeltaYH).unwrap();
// let x = (xl as u16 + (xh as u16) << 8) as i16;
// let y = (yl as u16 + (yh as u16) << 8) as i16;
// let surface = motion & 0x08;
// let motion_detect = motion & 0x80;
// rprintln!(
// "motion {}, surface {}, (x, y) {:?}",
// motion_detect,
// surface,
// (x, y),
// );
// delay.delay_ms(200);
// }
// set in burst mode // set in burst mode
pmw3389.write_register(Register::MotionBurst, 0x00); pmw3389.write_register(Register::MotionBurst, 0x00);
loop {
pmw3389.read_status().unwrap();
delay.delay_ms(200);
}
let id = pmw3389.product_id().unwrap();
rprintln!("id {}", id);
let id = pmw3389
.read_register(pmw3389::Register::RevisionId)
.unwrap();
rprintln!("rev {}", id);
let id = pmw3389
.read_register(pmw3389::Register::ShutterLower)
.unwrap();
rprintln!("lower {}", id);
let id = pmw3389
.read_register(pmw3389::Register::ShutterUpper)
.unwrap();
rprintln!("upper {}", id);
let id = pmw3389.read_register(pmw3389::Register::SROMId).unwrap();
rprintln!("sromid {}", id);
let id = pmw3389
.read_register(pmw3389::Register::InverseProductID)
.unwrap();
rprintln!("-id {}", id);
let id = pmw3389
.read_register(pmw3389::Register::RippleControl)
.unwrap();
rprintln!("ripple_control {:x}", id);
// semantically, the monotonic timer is frozen at time "zero" during `init` // semantically, the monotonic timer is frozen at time "zero" during `init`
// NOTE do *not* call `Instant::now` in this context; it will return a nonsense value // NOTE do *not* call `Instant::now` in this context; it will return a nonsense value
// let now = cx.start; // the start time of the system let now = cx.start; // the start time of the system
// Schedule `toggle` to run 8e6 cycles (clock cycles) in the future cx.schedule.poll(now + 16_000.cycles()).unwrap();
// cx.schedule.toggle(now + 8_000_000.cycles()).unwrap();
// pass on late resources // pass on late resources
init::LateResources { init::LateResources { pmw3389 }
GPIOA: device.GPIOA,
}
} }
#[task(resources = [GPIOA], schedule = [toggle])] #[task(priority = 2, resources = [pmw3389], schedule = [poll], spawn = [trace])]
fn toggle(cx: toggle::Context) { fn poll(cx: poll::Context) {
static mut TOGGLE: bool = false; static mut COUNTER: u32 = 0;
rprintln!("toggle @ {:?}", Instant::now()); static mut POS_X: i64 = 0;
if *TOGGLE { *COUNTER += 1;
cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit()); if *COUNTER == 1000 / RATIO {
} else { cx.spawn.trace(*POS_X).unwrap();
cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit()); *COUNTER = 0;
} }
*TOGGLE = !*TOGGLE; let (x, _y) = cx.resources.pmw3389.read_status().unwrap();
*POS_X += x as i64;
// task should run each second N ms (16_000 cycles at 16MHz)
cx.schedule cx.schedule
.toggle(cx.scheduled + 8_000_000.cycles()) .poll(cx.scheduled + (RATIO * 16_000).cycles())
.unwrap(); .unwrap();
} }
#[task(priority = 1)]
fn trace(_cx: trace::Context, pos: i64) {
static mut OLD_POS: i64 = 0;
rprintln!(
"pos_x {:010}, diff {:010} @{:?}",
pos,
pos - *OLD_POS,
Instant::now()
);
*OLD_POS = pos;
}
#[idle]
fn idle(_cx: idle::Context) -> ! {
loop {
continue;
}
}
extern "C" { extern "C" {
fn EXTI0(); fn EXTI0();
fn EXTI1();
} }
}; };
// mod pmw3389 { const RATIO: u32 = 5;
// use super::DwtDelay;
// use cortex_m::{iprint, iprintln};
// use embedded_hal::blocking::spi::{Transfer, Write};
// use embedded_hal::digital::v2::OutputPin;
// use stm32f4xx_hal::{prelude::*, stm32};
// // use stm32f4xx_hal::{dwt::Dwt, gpio::Speed, prelude::*, rcc::Clocks, spi::Spi, stm32};
// #[allow(dead_code)]
// #[derive(Clone, Copy)]
// pub enum Register {
// ProductId = 0x00,
// RevisionId = 0x01,
// Motion = 0x02,
// DeltaXL = 0x03,
// DeltaXH = 0x04,
// DeltaYL = 0x05,
// DeltaYH = 0x06,
// SQUAL = 0x07,
// RawDataSum = 0x08,
// MaximumRawdata = 0x09,
// MinimumRawdata = 0x0A,
// ShutterLower = 0x0B,
// ShutterUpper = 0x0C,
// RippleControl = 0x0D,
// ResolutionL = 0x0E,
// ResolutionH = 0x0F,
// Config2 = 0x10,
// AngleTune = 0x11,
// FrameCapture = 0x12,
// SROMEnable = 0x13,
// RunDownshift = 0x14,
// Rest1RateLower = 0x15,
// Rest1RateUpper = 0x16,
// Rest1Downshift = 0x17,
// Rest2RateLower = 0x18,
// Rest2RateUpper = 0x19,
// Rest2Downshift = 0x1A,
// Rest3RateLower = 0x1B,
// Rest3RateUpper = 0x1C,
// Observation = 0x24,
// DataOutLower = 0x25,
// DataOutUpper = 0x26,
// RawDataDump = 0x29,
// SROMId = 0x2A,
// MinSQRun = 0x2B,
// RawDataThreshold = 0x2C,
// Control2 = 0x2D,
// Config5L = 0x2E,
// Config5H = 0x2F,
// PowerUpReset = 0x3A,
// Shutdown = 0x3B,
// InverseProductID = 0x3F,
// LiftCutoffTune3 = 0x41,
// AngleSnap = 0x42,
// LiftCutoffTune1 = 0x4A,
// MotionBurst = 0x50,
// LiftCutoffTune1Timeout = 0x58,
// LiftCutoffTune1MinLength = 0x5A,
// SROMLoadBurst = 0x62,
// LiftConfig = 0x63,
// RawDataBurst = 0x64,
// LiftCutoffTune2 = 0x65,
// LiftCutoffTune2Timeout = 0x71,
// LiftCutoffTune2MinLength = 0x72,
// PWMPeriodCnt = 0x73,
// PWMWidthCnt = 0x74,
// }
// impl Register {
// fn addr(self) -> u8 {
// self as u8
// }
// }
// pub struct Pmw3389<SPI, CS> {
// spi: SPI,
// cs: CS,
// delay: DwtDelay,
// }
// impl<SPI, CS, E> Pmw3389<SPI, CS>
// where
// SPI: Transfer<u8, Error = E> + Write<u8, Error = E>,
// CS: OutputPin,
// {
// fn com_begin(&mut self) {
// self.cs.set_low().ok();
// }
// fn com_end(&mut self) {
// self.cs.set_high().ok();
// }
// /// Creates a new driver from a SPI peripheral and a NCS pin
// pub fn new(spi: SPI, cs: CS, delay: DwtDelay, itm: &mut stm32::ITM) -> Result<Self, E> {
// let mut pmw3389 = Pmw3389 { spi, cs, delay };
// iprintln!(&mut itm.stim[0], "pmw3389 - new");
// // ensure SPI is reset
// pmw3389.com_end();
// pmw3389.delay.delay_us(40);
// pmw3389.com_begin();
// pmw3389.delay.delay_us(40);
// pmw3389.com_end();
// // read product id
// let id = pmw3389.product_id()?;
// iprintln!(&mut itm.stim[0], "product_id 0x{:x}", id);
// let srom_id = pmw3389.read_register(Register::SROMId)?;
// iprintln!(&mut itm.stim[0], "srom_id {}, 0x{:x}", srom_id, srom_id);
// iprintln!(&mut itm.stim[0], "reset");
// // shutdown
// // adns_write_reg(Shutdown, 0xb6); // Shutdown first
// // delay(300);
// // adns_com_begin(); // drop and raise ncs to reset spi port
// // delayMicroseconds(40);
// // adns_com_end();
// // delayMicroseconds(40);
// // pmw3389.write_register(Register::Shutdown, 0xb6)?;
// // pmw3389.delay.delay_ms(300);
// // pmw3389.com_begin();
// // pmw3389.delay.delay_us(40);
// // pmw3389.com_end();
// // pmw3389.delay.delay_us(40);
// // force reset
// pmw3389.write_register(Register::PowerUpReset, 0x5a)?;
// // wait for reboot
// pmw3389.delay.delay_ms(50);
// // read product id
// let id = pmw3389.product_id()?;
// iprintln!(&mut itm.stim[0], "product_id 0x{:x}", id);
// let srom_id = pmw3389.read_register(Register::SROMId)?;
// iprintln!(&mut itm.stim[0], "srom_id {}, 0x{:x}", srom_id, srom_id);
// // read registers 0x02 to 0x06 (and discard the data)
// pmw3389.read_register(Register::Motion)?;
// pmw3389.read_register(Register::DeltaXL)?;
// pmw3389.read_register(Register::DeltaXH)?;
// pmw3389.read_register(Register::DeltaYL)?;
// pmw3389.read_register(Register::DeltaYH)?;
// pmw3389.upload_firmware(itm)?;
// pmw3389.delay.delay_ms(1000);
// iprintln!(&mut itm.stim[0], "Optical Chip Initialized");
// // read product id
// let id = pmw3389.product_id()?;
// iprintln!(&mut itm.stim[0], "product_id 0x{:x}", id);
// let srom_id = pmw3389.read_register(Register::SROMId)?;
// iprintln!(&mut itm.stim[0], "srom_id {}, 0x{:x}", srom_id, srom_id);
// loop {
// pmw3389.write_register(Register::Motion, 0x01)?;
// let motion = pmw3389.read_register(Register::Motion)?;
// let xl = pmw3389.read_register(Register::DeltaXL)?;
// let xh = pmw3389.read_register(Register::DeltaXH)?;
// let yl = pmw3389.read_register(Register::DeltaYL)?;
// let yh = pmw3389.read_register(Register::DeltaYH)?;
// let x = (xl as u16 + (xh as u16) << 8) as i16;
// let y = (yl as u16 + (yh as u16) << 8) as i16;
// let surface = motion & 0x08;
// let motion_detect = motion & 0x80;
// iprintln!(
// &mut itm.stim[0],
// "motion {}, surface {}, (x, y) {:?}",
// motion_detect,
// surface,
// (x, y),
// );
// pmw3389.delay.delay_ms(200);
// }
// // self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
// // self.delay.delay_ms(35); // waits for tSRAD
// // loop {
// // pmw3389.read_status(itm)?;
// // pmw3389.delay.delay_ms(10);
// // }
// // Ok(pmw3389)
// }
// pub fn read_register(&mut self, reg: Register) -> Result<u8, E> {
// self.com_begin();
// let mut buffer = [reg.addr() & 0x7f];
// self.spi.transfer(&mut buffer)?;
// // tSRAD
// self.delay.delay_us(100);
// self.delay.delay_us(120);
// let mut buffer = [0];
// self.spi.transfer(&mut buffer)?;
// // tSCLK-NCS for read operation is 120ns
// self.delay.delay_us(1);
// self.com_end();
// // tSRW/tSRR (=20us) minus tSCLK-NCS
// self.delay.delay_us(19);
// self.delay.delay_us(120);
// Ok(buffer[0])
// }
// pub fn write_register(&mut self, reg: Register, byte: u8) -> Result<(), E> {
// self.com_begin();
// let mut buffer = [reg.addr() | 0x80];
// self.spi.transfer(&mut buffer)?;
// // send
// let mut buffer = [byte];
// self.spi.transfer(&mut buffer)?;
// // tSCLK-NCS for write operation
// self.delay.delay_us(20);
// self.com_end();
// // tSWW/tSWR (=120us) minus tSCLK-NCS.
// // Could be shortened, but is looks like a safe lower bound
// self.delay.delay_us(100);
// Ok(())
// }
// /// Reads the ProductId register; should return `0x47`
// pub fn product_id(&mut self) -> Result<u8, E> {
// self.read_register(Register::ProductId)
// }
// /// Read status
// pub fn read_status(&mut self, itm: &mut stm32::ITM) -> Result<(), E> {
// self.com_begin();
// self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
// self.delay.delay_us(35); // waits for tSRAD
// // read burst buffer
// let mut buf = [0u8; 12];
// self.spi.transfer(&mut buf)?;
// // tSCLK-NCS for read operation is 120ns
// self.delay.delay_us(120);
// self.com_end();
// iprint!(&mut itm.stim[0], "burst [");
// for j in buf.iter() {
// iprint!(&mut itm.stim[0], "0x{:02x}, ", j);
// }
// iprintln!(&mut itm.stim[0], "]");
// // SPI.endTransaction(); // Per:Not sure what it does
// // /*
// // BYTE[00] = Motion = if the 7th bit is 1, a motion is detected.
// // ==> 7 bit: MOT (1 when motion is detected)
// // ==> 3 bit: 0 when chip is on surface / 1 when off surface
// // ] = Observation
// // BYTE[02] = Delta_X_L = dx (LSB)
// // BYTE[03] = Delta_X_H = dx (MSB)
// // BYTE[04] = Delta_Y_L = dy (LSB)
// // BYTE[05] = Delta_Y_H = dy (MSB)
// // BYTE[06] = SQUAL = Surface Quality register, max 0x80
// // - Number of features on the surface = SQUAL * 8
// // BYTE[07] = Raw_Data_Sum = It reports the upper byte of an 18‐bit counter which sums all 1296 raw data in the current frame;
// // * Avg value = Raw_Data_Sum * 1024 / 1296
// // BYTE[08] = Maximum_Raw_Data = Max raw data value in current frame, max=127
// // BYTE[09] = Minimum_Raw_Data = Min raw data value in current frame, max=127
// // BYTE[10] = Shutter_Upper = Shutter LSB
// // BYTE[11] = Shutter_Lower = Shutter MSB, Shutter = shutter is adjusted to keep the average raw data values within normal operating ranges
// // */
// // int motion = (burstBuffer[0] & 0x80) > 0;
// let motion = buf[0] & 0x80;
// let surface = buf[0] & 0x08;
// // 0 if on surface / 1 if off surface
// let x = buf[2] as u16 + (buf[3] as u16) << 8;
// let y = buf[4] as u16 + (buf[5] as u16) << 8;
// let squal = buf[6];
// iprintln!(
// &mut itm.stim[0],
// "motion {}, surface {}, (x, y) {:?}, squal {}",
// motion,
// surface,
// (x, y),
// squal
// );
// Ok(())
// }
// // Upload the firmware
// pub fn upload_firmware(&mut self, itm: &mut stm32::ITM) -> Result<(), E> {
// let stim = &mut itm.stim[0];
// // send the firmware to the chip, cf p.18 of the datasheet
// // Serial.println("Uploading firmware...");
// iprintln!(stim, "Uploading firmware...");
// //Write 0 to Rest_En bit of Config2 register to disable Rest mode.
// // adns_write_reg(Config2, 0x20);
// // is this correct?
// self.write_register(Register::Config2, 0x00)?;
// // write 0x1d in SROM_enable reg for initializing
// // adns_write_reg(SROM_Enable, 0x1d);
// self.write_register(Register::SROMEnable, 0x1d)?;
// // wait for more than one frame period
// // delay(10);
// // assume that the frame rate is as low as 100fps...
// // even if it should never be that low
// self.delay.delay_ms(10);
// // write 0x18 to SROM_enable to start SROM download
// // adns_write_reg(SROM_Enable, 0x18);
// self.write_register(Register::SROMEnable, 0x18)?;
// iprintln!(stim, "Begin transfer...");
// // write the SROM file (=firmware data)
// // adns_com_begin();
// self.com_begin();
// // write burst destination address
// // SPI.transfer(SROM_Load_Burst | 0x80); // write burst destination address
// // delayMicroseconds(15);
// self.spi
// .transfer(&mut [Register::SROMLoadBurst.addr() | 0x80])?;
// self.delay.delay_us(15);
// // send all bytes of the firmware
// // unsigned char c;
// // for(int i = 0; i < firmware_length; i++){
// // c = (unsigned char)pgm_read_byte(firmware_data + i);
// // SPI.transfer(c);
// // delayMicroseconds(15);
// // }
// for i in FIRMWARE.iter() {
// let mut buff = [*i];
// // iprintln!(stim, "0x{:x}", buff[0]);
// self.spi.transfer(&mut buff)?;
// self.delay.delay_us(15); // 15
// }
// // // Per: added this, seems adequate
// self.delay.delay_us(105);
// self.com_end();
// //Read the SROM_ID register to verify the ID before any other register reads or writes.
// // adns_read_reg(SROM_ID);
// let srom_id = self.read_register(Register::SROMId)?;
// iprintln!(stim, "srom_id {}, 0x{:x}", srom_id, srom_id);
// // //Write 0x00 to Config2 register for wired mouse or 0x20 for wireless mouse design.
// // // adns_write_reg(Config2, 0x00);
// self.write_register(Register::Config2, 0x20)?;
// // // set initial CPI resolution
// // // adns_write_reg(Config1, 0x15);
// // self.write_register(Register::ResolutionL, 0x15)?;
// self.write_register(Register::ResolutionL, 0x5)?;
// // self.write_register(Register::ResolutionH, 0x15)?;
// self.write_register(Register::ResolutionH, 0x00)?;
// // adns_com_end(); // why the CS is already high
// self.com_end();
// Ok(())
// }
// }
// // const unsigned char firmware_data[] PROGMEM
// const FIRMWARE: [u8; 4094] = [
// 0x01, 0xe8, 0xba, 0x26, 0x0b, 0xb2, 0xbe, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0xa8, 0xb3,
// 0xe4, 0x2b, 0xb5, 0xe8, 0x53, 0x07, 0x6d, 0x3b, 0xd1, 0x20, 0xc2, 0x06, 0x6f, 0x3d, 0xd9,
// 0x11, 0xa0, 0xc2, 0xe7, 0x2d, 0xb9, 0xd1, 0x20, 0xa3, 0xa5, 0xc8, 0xf3, 0x64, 0x4a, 0xf7,
// 0x4d, 0x18, 0x93, 0xa4, 0xca, 0xf7, 0x6c, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xfe, 0x7e, 0x7e,
// 0x5f, 0x1d, 0x99, 0xb0, 0xc3, 0xe5, 0x29, 0xd3, 0x03, 0x65, 0x48, 0x12, 0x87, 0x6d, 0x58,
// 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xf2, 0x4f, 0xfd, 0x59, 0x11, 0x81, 0x61, 0x21, 0xc0, 0x02,
// 0x86, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x55, 0x28, 0xb3, 0xe4, 0x4a, 0x16,
// 0xab, 0xbf, 0xdd, 0x38, 0xf2, 0x66, 0x4e, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xc8,
// 0x12, 0xa6, 0xaf, 0xdc, 0x3a, 0xd1, 0x41, 0x60, 0x75, 0x58, 0x24, 0x92, 0xd4, 0x72, 0x6c,
// 0xe0, 0x2f, 0xfd, 0x23, 0x8d, 0x1c, 0x5b, 0xb2, 0x97, 0x36, 0x3d, 0x0b, 0xa2, 0x49, 0xb1,
// 0x58, 0xf2, 0x1f, 0xc0, 0xcb, 0xf8, 0x41, 0x4f, 0xcd, 0x1e, 0x6b, 0x39, 0xa7, 0x2b, 0xe9,
// 0x30, 0x16, 0x83, 0xd2, 0x0e, 0x47, 0x8f, 0xe3, 0xb1, 0xdf, 0xa2, 0x15, 0xdb, 0x5d, 0x30,
// 0xc5, 0x1a, 0xab, 0x31, 0x99, 0xf3, 0xfa, 0xb2, 0x86, 0x69, 0xad, 0x7a, 0xe8, 0xa7, 0x18,
// 0x6a, 0xcc, 0xc8, 0x65, 0x23, 0x87, 0xa8, 0x5f, 0xf5, 0x21, 0x59, 0x75, 0x09, 0x71, 0x45,
// 0x55, 0x25, 0x4b, 0xda, 0xa1, 0xc3, 0xf7, 0x41, 0xab, 0x59, 0xd9, 0x74, 0x12, 0x55, 0x5f,
// 0xbc, 0xaf, 0xd9, 0xfd, 0xb0, 0x1e, 0xa3, 0x0f, 0xff, 0xde, 0x11, 0x16, 0x6a, 0xae, 0x0e,
// 0xe1, 0x5d, 0x3c, 0x10, 0x43, 0x9a, 0xa1, 0x0b, 0x24, 0x8f, 0x0d, 0x7f, 0x0b, 0x5e, 0x4c,
// 0x42, 0xa4, 0x84, 0x2c, 0x40, 0xd0, 0x55, 0x39, 0xe6, 0x4b, 0xf8, 0x9b, 0x2f, 0xdc, 0x28,
// 0xff, 0xfa, 0xb5, 0x85, 0x19, 0xe5, 0x28, 0xa1, 0x77, 0xaa, 0x73, 0xf3, 0x03, 0xc7, 0x62,
// 0xa6, 0x91, 0x18, 0xc9, 0xb0, 0xcd, 0x05, 0xdc, 0xca, 0x81, 0x26, 0x1a, 0x47, 0x40, 0xda,
// 0x36, 0x7d, 0x6a, 0x53, 0xc8, 0x5a, 0x77, 0x5d, 0x19, 0xa4, 0x1b, 0x23, 0x83, 0xd0, 0xb2,
// 0xaa, 0x0e, 0xbf, 0x77, 0x4e, 0x3a, 0x3b, 0x59, 0x00, 0x31, 0x0d, 0x02, 0x1b, 0x88, 0x7a,
// 0xd4, 0xbd, 0x9d, 0xcc, 0x58, 0x04, 0x69, 0xf6, 0x3b, 0xca, 0x42, 0xe2, 0xfd, 0xc3, 0x3d,
// 0x39, 0xc5, 0xd0, 0x71, 0xe4, 0xc8, 0xb7, 0x3e, 0x3f, 0xc8, 0xe9, 0xca, 0xc9, 0x3f, 0x04,
// 0x4e, 0x1b, 0x79, 0xca, 0xa5, 0x61, 0xc2, 0xed, 0x1d, 0xa6, 0xda, 0x5a, 0xe9, 0x7f, 0x65,
// 0x8c, 0xbe, 0x12, 0x6e, 0xa4, 0x5b, 0x33, 0x2f, 0x84, 0x28, 0x9c, 0x1c, 0x88, 0x2d, 0xff,
// 0x07, 0xbf, 0xa6, 0xd7, 0x5a, 0x88, 0x86, 0xb0, 0x3f, 0xf6, 0x31, 0x5b, 0x11, 0x6d, 0xf5,
// 0x58, 0xeb, 0x58, 0x02, 0x9e, 0xb5, 0x9a, 0xb1, 0xff, 0x25, 0x9d, 0x8b, 0x4f, 0xb6, 0x0a,
// 0xf9, 0xea, 0x3e, 0x3f, 0x21, 0x09, 0x65, 0x21, 0x22, 0xfe, 0x3d, 0x4e, 0x11, 0x5b, 0x9e,
// 0x5a, 0x59, 0x8b, 0xdd, 0xd8, 0xce, 0xd6, 0xd9, 0x59, 0xd2, 0x1e, 0xfd, 0xef, 0x0d, 0x1b,
// 0xd9, 0x61, 0x7f, 0xd7, 0x2d, 0xad, 0x62, 0x09, 0xe5, 0x22, 0x63, 0xea, 0xc7, 0x31, 0xd9,
// 0xa1, 0x38, 0x80, 0x5c, 0xa7, 0x32, 0x82, 0xec, 0x1b, 0xa2, 0x49, 0x5a, 0x06, 0xd2, 0x7c,
// 0xc9, 0x96, 0x57, 0xbb, 0x17, 0x75, 0xfc, 0x7a, 0x8f, 0x0d, 0x77, 0xb5, 0x7a, 0x8e, 0x3e,
// 0xf4, 0xba, 0x2f, 0x69, 0x13, 0x26, 0xd6, 0xd9, 0x21, 0x60, 0x2f, 0x21, 0x3e, 0x87, 0xee,
// 0xfd, 0x87, 0x16, 0x0d, 0xc8, 0x08, 0x00, 0x25, 0x71, 0xac, 0x2c, 0x03, 0x2a, 0x37, 0x2d,
// 0xb3, 0x34, 0x09, 0x91, 0xe3, 0x06, 0x2c, 0x38, 0x37, 0x95, 0x3b, 0x17, 0x7a, 0xaf, 0xac,
// 0x99, 0x55, 0xab, 0x41, 0x39, 0x5f, 0x8e, 0xa6, 0x43, 0x80, 0x03, 0x88, 0x6f, 0x7d, 0xbd,
// 0x5a, 0xb4, 0x2b, 0x32, 0x23, 0x5a, 0xa9, 0x31, 0x32, 0x39, 0x4c, 0x5b, 0xf4, 0x6b, 0xaf,
// 0x66, 0x6f, 0x3c, 0x8e, 0x2d, 0x82, 0x97, 0x9f, 0x4a, 0x01, 0xdc, 0x99, 0x98, 0x00, 0xec,
// 0x38, 0x7a, 0x79, 0x70, 0xa6, 0x85, 0xd6, 0x21, 0x63, 0x0d, 0x45, 0x9a, 0x2e, 0x5e, 0xa7,
// 0xb1, 0xea, 0x66, 0x6a, 0xbc, 0x62, 0x2d, 0x7b, 0x7d, 0x85, 0xea, 0x95, 0x2f, 0xc0, 0xe8,
// 0x6f, 0x35, 0xa0, 0x3a, 0x02, 0x25, 0xbc, 0xb2, 0x5f, 0x5c, 0x43, 0x96, 0xcc, 0x26, 0xd2,
// 0x16, 0xb4, 0x96, 0x73, 0xd7, 0x13, 0xc7, 0xae, 0x53, 0x15, 0x31, 0x89, 0x68, 0x66, 0x6d,
// 0x2c, 0x92, 0x1f, 0xcc, 0x5b, 0xa7, 0x8f, 0x5d, 0xbb, 0xc9, 0xdb, 0xe8, 0x3b, 0x9d, 0x61,
// 0x74, 0x8b, 0x05, 0xa1, 0x58, 0x52, 0x68, 0xee, 0x3d, 0x39, 0x79, 0xa0, 0x9b, 0xdd, 0xe1,
// 0x55, 0xc9, 0x60, 0xeb, 0xad, 0xb8, 0x5b, 0xc2, 0x5a, 0xb5, 0x2c, 0x18, 0x55, 0xa9, 0x50,
// 0xc3, 0xf6, 0x72, 0x5f, 0xcc, 0xe2, 0xf4, 0x55, 0xb5, 0xd6, 0xb5, 0x4a, 0x99, 0xa5, 0x28,
// 0x74, 0x97, 0x18, 0xe8, 0xc0, 0x84, 0x89, 0x50, 0x03, 0x86, 0x4d, 0x1a, 0xb7, 0x09, 0x90,
// 0xa2, 0x01, 0x04, 0xbb, 0x73, 0x62, 0xcb, 0x97, 0x22, 0x70, 0x5d, 0x52, 0x41, 0x8e, 0xd9,
// 0x90, 0x15, 0xaa, 0xab, 0x0a, 0x31, 0x65, 0xb4, 0xda, 0xd0, 0xee, 0x24, 0xc9, 0x41, 0x91,
// 0x1e, 0xbc, 0x46, 0x70, 0x40, 0x9d, 0xda, 0x0e, 0x2a, 0xe4, 0xb2, 0x4c, 0x9f, 0xf2, 0xfc,
// 0xf3, 0x84, 0x17, 0x44, 0x1e, 0xd7, 0xca, 0x23, 0x1f, 0x3f, 0x5a, 0x22, 0x3d, 0xaf, 0x9b,
// 0x2d, 0xfc, 0x41, 0xad, 0x26, 0xb4, 0x45, 0x67, 0x0b, 0x80, 0x0e, 0xf9, 0x61, 0x37, 0xec,
// 0x3b, 0xf4, 0x4b, 0x14, 0xdf, 0x5a, 0x0c, 0x3a, 0x50, 0x0b, 0x14, 0x0c, 0x72, 0xae, 0xc6,
// 0xc5, 0xec, 0x35, 0x53, 0x2d, 0x59, 0xed, 0x91, 0x74, 0xe2, 0xc4, 0xc8, 0xf2, 0x25, 0x6b,
// 0x97, 0x6f, 0xc9, 0x76, 0xce, 0xa9, 0xb1, 0x99, 0x8f, 0x5a, 0x92, 0x3b, 0xc4, 0x8d, 0x54,
// 0x50, 0x40, 0x72, 0xd6, 0x90, 0x83, 0xfc, 0xe5, 0x49, 0x8b, 0x17, 0xf5, 0xfd, 0x6b, 0x8d,
// 0x32, 0x02, 0xe9, 0x0a, 0xfe, 0xbf, 0x00, 0x6b, 0xa3, 0xad, 0x5f, 0x09, 0x4b, 0x97, 0x2b,
// 0x00, 0x58, 0x65, 0x2e, 0x07, 0x49, 0x0a, 0x3b, 0x6b, 0x2e, 0x50, 0x6c, 0x1d, 0xac, 0xb7,
// 0x6a, 0x26, 0xd8, 0x13, 0xa4, 0xca, 0x16, 0xae, 0xab, 0x93, 0xb9, 0x1c, 0x1c, 0xb4, 0x47,
// 0x6a, 0x38, 0x36, 0x17, 0x27, 0xc9, 0x7f, 0xc7, 0x64, 0xcb, 0x89, 0x58, 0xc5, 0x61, 0xc2,
// 0xc6, 0xea, 0x15, 0x0b, 0x34, 0x0c, 0x5d, 0x61, 0x76, 0x6e, 0x2b, 0x62, 0x40, 0x92, 0xa3,
// 0x6c, 0xef, 0xf4, 0xe4, 0xc3, 0xa1, 0xa8, 0xf5, 0x94, 0x79, 0x0d, 0xd1, 0x3d, 0xcb, 0x3d,
// 0x40, 0xb6, 0xd0, 0xf0, 0x10, 0x54, 0xd8, 0x47, 0x25, 0x51, 0xc5, 0x41, 0x79, 0x00, 0xe5,
// 0xa0, 0x72, 0xde, 0xbb, 0x3b, 0x62, 0x17, 0xf6, 0xbc, 0x5d, 0x00, 0x76, 0x2e, 0xa7, 0x3b,
// 0xb6, 0xf1, 0x98, 0x72, 0x59, 0x2a, 0x73, 0xb0, 0x21, 0xd6, 0x49, 0xe0, 0xc0, 0xd5, 0xeb,
// 0x02, 0x7d, 0x4b, 0x41, 0x28, 0x70, 0x2d, 0xec, 0x2b, 0x71, 0x1f, 0x0b, 0xb9, 0x71, 0x63,
// 0x06, 0xe6, 0xbc, 0x60, 0xbb, 0xf4, 0x9a, 0x62, 0x43, 0x09, 0x18, 0x4e, 0x93, 0x06, 0x4d,
// 0x76, 0xfa, 0x7f, 0xbd, 0x02, 0xe4, 0x50, 0x91, 0x12, 0xe5, 0x86, 0xff, 0x64, 0x1e, 0xaf,
// 0x7e, 0xb3, 0xb2, 0xde, 0x89, 0xc1, 0xa2, 0x6f, 0x40, 0x7b, 0x41, 0x51, 0x63, 0xea, 0x25,
// 0xd1, 0x97, 0x57, 0x92, 0xa8, 0x45, 0xa1, 0xa5, 0x45, 0x21, 0x43, 0x7f, 0x83, 0x15, 0x29,
// 0xd0, 0x30, 0x53, 0x32, 0xb4, 0x5a, 0x17, 0x96, 0xbc, 0xc2, 0x68, 0xa9, 0xb7, 0xaf, 0xac,
// 0xdf, 0xf1, 0xe3, 0x89, 0xba, 0x24, 0x79, 0x54, 0xc6, 0x14, 0x07, 0x1c, 0x1e, 0x0d, 0x3a,
// 0x6b, 0xe5, 0x3d, 0x4e, 0x10, 0x60, 0x96, 0xec, 0x6c, 0xda, 0x47, 0xae, 0x03, 0x25, 0x39,
// 0x1d, 0x74, 0xc8, 0xac, 0x6a, 0xf2, 0x6b, 0x05, 0x2a, 0x9a, 0xe7, 0xe8, 0x92, 0xd6, 0xc2,
// 0x6d, 0xfa, 0xe8, 0xa7, 0x9d, 0x5f, 0x48, 0xc9, 0x75, 0xf1, 0x66, 0x6a, 0xdb, 0x5d, 0x9a,
// 0xcd, 0x27, 0xdd, 0xb9, 0x24, 0x04, 0x9c, 0x18, 0xc2, 0x6d, 0x0c, 0x91, 0x34, 0x48, 0x42,
// 0x6f, 0xe9, 0x59, 0x70, 0xc4, 0x7e, 0x81, 0x0e, 0x32, 0x0a, 0x93, 0x48, 0xb0, 0xc0, 0x15,
// 0x9e, 0x05, 0xac, 0x36, 0x16, 0xcb, 0x59, 0x65, 0xa0, 0x83, 0xdf, 0x3e, 0xda, 0xfb, 0x1d,
// 0x1a, 0xdb, 0x65, 0xec, 0x9a, 0xc6, 0xc3, 0x8e, 0x3c, 0x45, 0xfd, 0xc8, 0xf5, 0x1c, 0x6a,
// 0x67, 0x0d, 0x8f, 0x99, 0x7d, 0x30, 0x21, 0x8c, 0xea, 0x22, 0x87, 0x65, 0xc9, 0xb2, 0x4c,
// 0xe4, 0x1b, 0x46, 0xba, 0x54, 0xbd, 0x7c, 0xca, 0xd5, 0x8f, 0x5b, 0xa5, 0x01, 0x04, 0xd8,
// 0x0a, 0x16, 0xbf, 0xb9, 0x50, 0x2e, 0x37, 0x2f, 0x64, 0xf3, 0x70, 0x11, 0x02, 0x05, 0x31,
// 0x9b, 0xa0, 0xb2, 0x01, 0x5e, 0x4f, 0x19, 0xc9, 0xd4, 0xea, 0xa1, 0x79, 0x54, 0x53, 0xa7,
// 0xde, 0x2f, 0x49, 0xd3, 0xd1, 0x63, 0xb5, 0x03, 0x15, 0x4e, 0xbf, 0x04, 0xb3, 0x26, 0x8b,
// 0x20, 0xb2, 0x45, 0xcf, 0xcd, 0x5b, 0x82, 0x32, 0x88, 0x61, 0xa7, 0xa8, 0xb2, 0xa0, 0x72,
// 0x96, 0xc0, 0xdb, 0x2b, 0xe2, 0x5f, 0xba, 0xe3, 0xf5, 0x8a, 0xde, 0xf1, 0x18, 0x01, 0x16,
// 0x40, 0xd9, 0x86, 0x12, 0x09, 0x18, 0x1b, 0x05, 0x0c, 0xb1, 0xb5, 0x47, 0xe2, 0x43, 0xab,
// 0xfe, 0x92, 0x63, 0x7e, 0x95, 0x2b, 0xf0, 0xaf, 0xe1, 0xf1, 0xc3, 0x4a, 0xff, 0x2b, 0x09,
// 0xbb, 0x4a, 0x0e, 0x9a, 0xc4, 0xd8, 0x64, 0x7d, 0x83, 0xa0, 0x4f, 0x44, 0xdb, 0xc4, 0xa8,
// 0x58, 0xef, 0xfc, 0x9e, 0x77, 0xf9, 0xa6, 0x8f, 0x58, 0x8b, 0x12, 0xf4, 0xe9, 0x81, 0x12,
// 0x47, 0x51, 0x41, 0x83, 0xef, 0xf6, 0x73, 0xbc, 0x8e, 0x0f, 0x4c, 0x8f, 0x4e, 0x69, 0x90,
// 0x77, 0x29, 0x5d, 0x92, 0xb0, 0x6d, 0x06, 0x67, 0x29, 0x60, 0xbd, 0x4b, 0x17, 0xc8, 0x89,
// 0x69, 0x28, 0x29, 0xd6, 0x78, 0xcb, 0x11, 0x4c, 0xba, 0x8b, 0x68, 0xae, 0x7e, 0x9f, 0xef,
// 0x95, 0xda, 0xe2, 0x9e, 0x7f, 0xe9, 0x55, 0xe5, 0xe1, 0xe2, 0xb7, 0xe6, 0x5f, 0xbb, 0x2c,
// 0xa2, 0xe6, 0xee, 0xc7, 0x0a, 0x60, 0xa9, 0xd1, 0x80, 0xdf, 0x7f, 0xd6, 0x97, 0xab, 0x1d,
// 0x22, 0x25, 0xfc, 0x79, 0x23, 0xe0, 0xae, 0xc5, 0xef, 0x16, 0xa4, 0xa1, 0x0f, 0x92, 0xa9,
// 0xc7, 0xe3, 0x3a, 0x55, 0xdf, 0x62, 0x49, 0xd9, 0xf5, 0x84, 0x49, 0xc5, 0x90, 0x34, 0xd3,
// 0xe1, 0xac, 0x99, 0x21, 0xb1, 0x02, 0x76, 0x4a, 0xfa, 0xd4, 0xbb, 0xa4, 0x9c, 0xa2, 0xe2,
// 0xcb, 0x3d, 0x3b, 0x14, 0x75, 0x60, 0xd1, 0x02, 0xb4, 0xa3, 0xb4, 0x72, 0x06, 0xf9, 0x19,
// 0x9c, 0xe2, 0xe4, 0xa7, 0x0f, 0x25, 0x88, 0xc6, 0x86, 0xd6, 0x8c, 0x74, 0x4e, 0x6e, 0xfc,
// 0xa8, 0x48, 0x9e, 0xa7, 0x9d, 0x1a, 0x4b, 0x37, 0x09, 0xc8, 0xb0, 0x10, 0xbe, 0x6f, 0xfe,
// 0xa3, 0xc4, 0x7a, 0xb5, 0x3d, 0xe8, 0x30, 0xf1, 0x0d, 0xa0, 0xb2, 0x44, 0xfc, 0x9b, 0x8c,
// 0xf8, 0x61, 0xed, 0x81, 0xd1, 0x62, 0x11, 0xb4, 0xe1, 0xd5, 0x39, 0x52, 0x89, 0xd3, 0xa8,
// 0x49, 0x31, 0xdf, 0xb6, 0xf9, 0x91, 0xf4, 0x1c, 0x9d, 0x09, 0x95, 0x40, 0x56, 0xe7, 0xe3,
// 0xcd, 0x5c, 0x92, 0xc1, 0x1d, 0x6b, 0xe9, 0x78, 0x6f, 0x8e, 0x94, 0x42, 0x66, 0xa2, 0xaa,
// 0xd3, 0xc8, 0x2e, 0xe3, 0xf6, 0x07, 0x72, 0x0b, 0x6b, 0x1e, 0x7b, 0xb9, 0x7c, 0xe0, 0xa0,
// 0xbc, 0xd9, 0x25, 0xdf, 0x87, 0xa8, 0x5f, 0x9c, 0xcc, 0xf0, 0xdb, 0x42, 0x8e, 0x07, 0x31,
// 0x13, 0x01, 0x66, 0x32, 0xd1, 0xb8, 0xd6, 0xe3, 0x5e, 0x12, 0x76, 0x61, 0xd3, 0x38, 0x89,
// 0xe6, 0x17, 0x6f, 0xa5, 0xf2, 0x71, 0x0e, 0xa5, 0xe2, 0x88, 0x30, 0xbb, 0xbe, 0x8a, 0xea,
// 0xc7, 0x62, 0xc4, 0xcf, 0xb8, 0xcd, 0x33, 0x8d, 0x3d, 0x3e, 0xb5, 0x60, 0x3a, 0x03, 0x92,
// 0xe4, 0x6d, 0x1b, 0xe0, 0xb4, 0x84, 0x08, 0x55, 0x88, 0xa7, 0x3a, 0xb9, 0x3d, 0x43, 0xc3,
// 0xc0, 0xfa, 0x07, 0x6a, 0xca, 0x94, 0xad, 0x99, 0x55, 0xf1, 0xf1, 0xc0, 0x23, 0x87, 0x1d,
// 0x3d, 0x1c, 0xd1, 0x66, 0xa0, 0x57, 0x10, 0x52, 0xa2, 0x7f, 0xbe, 0xf9, 0x88, 0xb6, 0x02,
// 0xbf, 0x08, 0x23, 0xa9, 0x0c, 0x63, 0x17, 0x2a, 0xae, 0xf5, 0xf7, 0xb7, 0x21, 0x83, 0x92,
// 0x31, 0x23, 0x0d, 0x20, 0xc3, 0xc2, 0x05, 0x21, 0x62, 0x8e, 0x45, 0xe8, 0x14, 0xc1, 0xda,
// 0x75, 0xb8, 0xf8, 0x92, 0x01, 0xd0, 0x5d, 0x18, 0x9f, 0x99, 0x11, 0x19, 0xf5, 0x35, 0xe8,
// 0x7f, 0x20, 0x88, 0x8c, 0x05, 0x75, 0xf5, 0xd7, 0x40, 0x17, 0xbb, 0x1e, 0x36, 0x52, 0xd9,
// 0xa4, 0x9c, 0xc2, 0x9d, 0x42, 0x81, 0xd8, 0xc7, 0x8a, 0xe7, 0x4c, 0x81, 0xe0, 0xb7, 0x57,
// 0xed, 0x48, 0x8b, 0xf0, 0x97, 0x15, 0x61, 0xd9, 0x2c, 0x7c, 0x45, 0xaf, 0xc2, 0xcd, 0xfc,
// 0xaa, 0x13, 0xad, 0x59, 0xcc, 0xb2, 0xb2, 0x6e, 0xdd, 0x63, 0x9c, 0x32, 0x0f, 0xec, 0x83,
// 0xbe, 0x78, 0xac, 0x91, 0x44, 0x1a, 0x1f, 0xea, 0xfd, 0x5d, 0x8e, 0xb4, 0xc0, 0x84, 0xd4,
// 0xac, 0xb4, 0x87, 0x5f, 0xac, 0xef, 0xdf, 0xcd, 0x12, 0x56, 0xc8, 0xcd, 0xfe, 0xc5, 0xda,
// 0xd3, 0xc1, 0x69, 0xf3, 0x61, 0x05, 0xea, 0x25, 0xe2, 0x12, 0x05, 0x8f, 0x39, 0x08, 0x08,
// 0x7c, 0x37, 0xb6, 0x7e, 0x5b, 0xd8, 0xb1, 0x0e, 0xf2, 0xdb, 0x4b, 0xf1, 0xad, 0x90, 0x01,
// 0x57, 0xcd, 0xa0, 0xb4, 0x52, 0xe8, 0xf3, 0xd7, 0x8a, 0xbd, 0x4f, 0x9f, 0x21, 0x40, 0x72,
// 0xa4, 0xfc, 0x0b, 0x01, 0x2b, 0x2f, 0xb6, 0x4c, 0x95, 0x2d, 0x35, 0x33, 0x41, 0x6b, 0xa0,
// 0x93, 0xe7, 0x2c, 0xf2, 0xd3, 0x72, 0x8b, 0xf4, 0x4f, 0x15, 0x3c, 0xaf, 0xd6, 0x12, 0xde,
// 0x3f, 0x83, 0x3f, 0xff, 0xf8, 0x7f, 0xf6, 0xcc, 0xa6, 0x7f, 0xc9, 0x9a, 0x6e, 0x1f, 0xc1,
// 0x0c, 0xfb, 0xee, 0x9c, 0xe7, 0xaf, 0xc9, 0x26, 0x54, 0xef, 0xb0, 0x39, 0xef, 0xb2, 0xe9,
// 0x23, 0xc4, 0xef, 0xd1, 0xa1, 0xa4, 0x25, 0x24, 0x6f, 0x8d, 0x6a, 0xe5, 0x8a, 0x32, 0x3a,
// 0xaf, 0xfc, 0xda, 0xce, 0x18, 0x25, 0x42, 0x07, 0x4d, 0x45, 0x8b, 0xdf, 0x85, 0xcf, 0x55,
// 0xb2, 0x24, 0xfe, 0x9c, 0x69, 0x74, 0xa7, 0x6e, 0xa0, 0xce, 0xc0, 0x39, 0xf4, 0x86, 0xc6,
// 0x8d, 0xae, 0xb9, 0x48, 0x64, 0x13, 0x0b, 0x40, 0x81, 0xa2, 0xc9, 0xa8, 0x85, 0x51, 0xee,
// 0x9f, 0xcf, 0xa2, 0x8c, 0x19, 0x52, 0x48, 0xe2, 0xc1, 0xa8, 0x58, 0xb4, 0x10, 0x24, 0x06,
// 0x58, 0x51, 0xfc, 0xb9, 0x12, 0xec, 0xfd, 0x73, 0xb4, 0x6d, 0x84, 0xfa, 0x06, 0x8b, 0x05,
// 0x0b, 0x2d, 0xd6, 0xd6, 0x1f, 0x29, 0x82, 0x9f, 0x19, 0x12, 0x1e, 0xb2, 0x04, 0x8f, 0x7f,
// 0x4d, 0xbd, 0x30, 0x2e, 0xe3, 0xe0, 0x88, 0x29, 0xc5, 0x93, 0xd6, 0x6c, 0x1f, 0x29, 0x45,
// 0x91, 0xa7, 0x58, 0xcd, 0x05, 0x17, 0xd6, 0x6d, 0xb3, 0xca, 0x66, 0xcc, 0x3c, 0x4a, 0x74,
// 0xfd, 0x08, 0x10, 0xa6, 0x99, 0x92, 0x10, 0xd2, 0x85, 0xab, 0x6e, 0x1d, 0x0e, 0x8b, 0x26,
// 0x46, 0xd1, 0x6c, 0x84, 0xc0, 0x26, 0x43, 0x59, 0x68, 0xf0, 0x13, 0x1d, 0xfb, 0xe3, 0xd1,
// 0xd2, 0xb4, 0x71, 0x9e, 0xf2, 0x59, 0x6a, 0x33, 0x29, 0x79, 0xd2, 0xd7, 0x26, 0xf1, 0xae,
// 0x78, 0x9e, 0x1f, 0x0f, 0x3f, 0xe3, 0xe8, 0xd0, 0x27, 0x78, 0x77, 0xf6, 0xac, 0x9c, 0x56,
// 0x39, 0x73, 0x8a, 0x6b, 0x2f, 0x34, 0x78, 0xb1, 0x11, 0xdb, 0xa4, 0x5c, 0x80, 0x01, 0x71,
// 0x6a, 0xc2, 0xd1, 0x2e, 0x5e, 0x76, 0x28, 0x70, 0x93, 0xae, 0x3e, 0x78, 0xb0, 0x1f, 0x0f,
// 0xda, 0xbf, 0xfb, 0x8a, 0x67, 0x65, 0x4f, 0x91, 0xed, 0x49, 0x75, 0x78, 0x62, 0xa2, 0x93,
// 0xb5, 0x70, 0x7f, 0x4d, 0x08, 0x4e, 0x79, 0x61, 0xa8, 0x5f, 0x7f, 0xb4, 0x65, 0x9f, 0x91,
// 0x54, 0x3a, 0xe8, 0x50, 0x33, 0xd3, 0xd5, 0x8a, 0x7c, 0xf3, 0x9e, 0x8b, 0x77, 0x7b, 0xc6,
// 0xc6, 0x0c, 0x45, 0x95, 0x1f, 0xb0, 0xd0, 0x0b, 0x27, 0x4a, 0xfd, 0xc7, 0xf7, 0x0d, 0x5a,
// 0x43, 0xc9, 0x7d, 0x35, 0xb0, 0x7d, 0xc4, 0x9c, 0x57, 0x1e, 0x76, 0x0d, 0xf1, 0x95, 0x30,
// 0x71, 0xcc, 0xb3, 0x66, 0x3b, 0x63, 0xa8, 0x6c, 0xa3, 0x43, 0xa0, 0x24, 0xcc, 0xb7, 0x53,
// 0xfe, 0xfe, 0xbc, 0x6e, 0x60, 0x89, 0xaf, 0x16, 0x21, 0xc8, 0x91, 0x6a, 0x89, 0xce, 0x80,
// 0x2c, 0xf1, 0x59, 0xce, 0xc3, 0x60, 0x61, 0x3b, 0x0b, 0x19, 0xfe, 0x99, 0xac, 0x65, 0x90,
// 0x15, 0x12, 0x05, 0xac, 0x7e, 0xff, 0x98, 0x7b, 0x66, 0x64, 0x0e, 0x4b, 0x5b, 0xaa, 0x8d,
// 0x3b, 0xd2, 0x56, 0xcf, 0x99, 0x39, 0xee, 0x22, 0x81, 0xd0, 0x60, 0x06, 0x66, 0x20, 0x81,
// 0x48, 0x3c, 0x6f, 0x3a, 0x77, 0xba, 0xcb, 0x52, 0xac, 0x79, 0x56, 0xaf, 0xe9, 0x16, 0x17,
// 0x0a, 0xa3, 0x82, 0x08, 0xd5, 0x3c, 0x97, 0xcb, 0x09, 0xff, 0x7f, 0xf9, 0x4f, 0x60, 0x05,
// 0xb9, 0x53, 0x26, 0xaa, 0xb8, 0x50, 0xaa, 0x19, 0x25, 0xae, 0x5f, 0xea, 0x8a, 0xd0, 0x89,
// 0x12, 0x80, 0x43, 0x50, 0x24, 0x12, 0x21, 0x14, 0xcd, 0x77, 0xeb, 0x21, 0xcc, 0x5c, 0x09,
// 0x64, 0xf3, 0xc7, 0xcb, 0xc5, 0x4b, 0xc3, 0xe7, 0xed, 0xe7, 0x86, 0x2c, 0x1d, 0x8e, 0x19,
// 0x52, 0x9b, 0x2a, 0x0c, 0x18, 0x72, 0x0b, 0x1e, 0x1b, 0xb0, 0x0f, 0x42, 0x99, 0x04, 0xae,
// 0xd5, 0xb7, 0x89, 0x1a, 0xb9, 0x4f, 0xd6, 0xaf, 0xf3, 0xc9, 0x93, 0x6f, 0xb0, 0x60, 0x83,
// 0x6e, 0x6b, 0xd1, 0x5f, 0x3f, 0x1a, 0x83, 0x1e, 0x24, 0x00, 0x87, 0xb5, 0x3e, 0xdb, 0xf9,
// 0x4d, 0xa7, 0x16, 0x2e, 0x19, 0x5b, 0x8f, 0x1b, 0x0d, 0x47, 0x72, 0x42, 0xe9, 0x0a, 0x11,
// 0x08, 0x2d, 0x88, 0x1c, 0xbc, 0xc7, 0xb4, 0xbe, 0x29, 0x4d, 0x03, 0x5e, 0xec, 0xdf, 0xf3,
// 0x3d, 0x2f, 0xe8, 0x1d, 0x9a, 0xd2, 0xd1, 0xab, 0x41, 0x3d, 0x87, 0x11, 0x45, 0xb0, 0x0d,
// 0x46, 0xf5, 0xe8, 0x95, 0x62, 0x1c, 0x68, 0xf7, 0xa6, 0x5b, 0x39, 0x4e, 0xbf, 0x47, 0xba,
// 0x5d, 0x7f, 0xb7, 0x6a, 0xf4, 0xba, 0x1d, 0x69, 0xf6, 0xa4, 0xe7, 0xe4, 0x6b, 0x3b, 0x0d,
// 0x23, 0x16, 0x4a, 0xb2, 0x68, 0xf0, 0xb2, 0x0d, 0x09, 0x17, 0x6a, 0x63, 0x8c, 0x83, 0xd3,
// 0xbd, 0x05, 0xc9, 0xf6, 0xf0, 0xa1, 0x31, 0x0b, 0x2c, 0xac, 0x83, 0xac, 0x80, 0x34, 0x32,
// 0xb4, 0xec, 0xd0, 0xbc, 0x54, 0x82, 0x9a, 0xc8, 0xf6, 0xa0, 0x7d, 0xc6, 0x79, 0x73, 0xf4,
// 0x20, 0x99, 0xf3, 0xb4, 0x01, 0xde, 0x91, 0x27, 0xf2, 0xc0, 0xdc, 0x81, 0x00, 0x4e, 0x7e,
// 0x07, 0x99, 0xc8, 0x3a, 0x51, 0xbc, 0x38, 0xd6, 0x8a, 0xa2, 0xde, 0x3b, 0x6a, 0x8c, 0x1a,
// 0x7c, 0x81, 0x0f, 0x3a, 0x1f, 0xe4, 0x05, 0x7b, 0x20, 0x35, 0x6b, 0xa5, 0x6a, 0xa7, 0xe7,
// 0xbc, 0x9c, 0x20, 0xec, 0x00, 0x15, 0xe2, 0x51, 0xaf, 0x77, 0xeb, 0x29, 0x3c, 0x7d, 0x2e,
// 0x00, 0x5c, 0x81, 0x21, 0xfa, 0x35, 0x6f, 0x40, 0xef, 0xfb, 0xd1, 0x3f, 0xcc, 0x9d, 0x55,
// 0x53, 0xfb, 0x5a, 0xa5, 0x56, 0x89, 0x0b, 0x52, 0xeb, 0x57, 0x73, 0x4f, 0x1b, 0x67, 0x24,
// 0xcb, 0xb8, 0x6a, 0x10, 0x69, 0xd6, 0xfb, 0x52, 0x40, 0xff, 0x20, 0xa5, 0xf3, 0x72, 0xe1,
// 0x3d, 0xa4, 0x8c, 0x81, 0x66, 0x16, 0x0d, 0x5d, 0xad, 0xa8, 0x50, 0x25, 0x78, 0x31, 0x77,
// 0x0c, 0x57, 0xe4, 0xe9, 0x15, 0x2d, 0xdb, 0x07, 0x87, 0xc8, 0xb0, 0x43, 0xde, 0xfc, 0xfe,
// 0xa9, 0xeb, 0xf5, 0xb0, 0xd3, 0x7b, 0xe9, 0x1f, 0x6e, 0xca, 0xe4, 0x03, 0x95, 0xc5, 0xd1,
// 0x59, 0x72, 0x63, 0xf0, 0x86, 0x54, 0xe8, 0x16, 0x62, 0x0b, 0x35, 0x29, 0xc2, 0x68, 0xd0,
// 0xd6, 0x3e, 0x90, 0x60, 0x57, 0x1d, 0xc9, 0xed, 0x3f, 0xed, 0xb0, 0x2f, 0x7e, 0x97, 0x02,
// 0x51, 0xec, 0xee, 0x6f, 0x82, 0x74, 0x76, 0x7f, 0xfb, 0xd6, 0xc4, 0xc3, 0xdd, 0xe8, 0xb1,
// 0x60, 0xfc, 0xc6, 0xb9, 0x0d, 0x6a, 0x33, 0x78, 0xc6, 0xc1, 0xbf, 0x86, 0x2c, 0x50, 0xcc,
// 0x9a, 0x70, 0x8e, 0x7b, 0xec, 0xab, 0x95, 0xac, 0x53, 0xa0, 0x4b, 0x07, 0x88, 0xaf, 0x42,
// 0xed, 0x19, 0x8d, 0xf6, 0x32, 0x17, 0x48, 0x47, 0x1d, 0x41, 0x6f, 0xfe, 0x2e, 0xa7, 0x8f,
// 0x4b, 0xa0, 0x51, 0xf3, 0xbf, 0x02, 0x0a, 0x48, 0x58, 0xf7, 0xa1, 0x6d, 0xea, 0xa5, 0x13,
// 0x5a, 0x5b, 0xea, 0x0c, 0x9e, 0x52, 0x4f, 0x9e, 0xb9, 0x71, 0x7f, 0x23, 0x83, 0xda, 0x1b,
// 0x86, 0x9a, 0x41, 0x29, 0xda, 0x70, 0xe7, 0x64, 0xa1, 0x7b, 0xd5, 0x0a, 0x22, 0x0d, 0x5c,
// 0x40, 0xc4, 0x81, 0x07, 0x25, 0x35, 0x4a, 0x1c, 0x10, 0xdb, 0x45, 0x0a, 0xff, 0x36, 0xd4,
// 0xe0, 0xeb, 0x5f, 0x68, 0xd6, 0x67, 0xc6, 0xd0, 0x8b, 0x76, 0x1a, 0x7d, 0x59, 0x42, 0xa1,
// 0xcb, 0x96, 0x4d, 0x84, 0x09, 0x9a, 0x3d, 0xe0, 0x52, 0x85, 0x6e, 0x48, 0x90, 0x85, 0x2a,
// 0x63, 0xb2, 0x69, 0xd2, 0x00, 0x43, 0x31, 0x37, 0xb3, 0x52, 0xaf, 0x62, 0xfa, 0xc1, 0xe0,
// 0x03, 0xfb, 0x62, 0xaa, 0x88, 0xc9, 0xb2, 0x2c, 0xd5, 0xa8, 0xf5, 0xa5, 0x4c, 0x12, 0x59,
// 0x4e, 0x06, 0x5e, 0x9b, 0x15, 0x66, 0x11, 0xb2, 0x27, 0x92, 0xdc, 0x98, 0x59, 0xde, 0xdf,
// 0xfa, 0x9a, 0x32, 0x2e, 0xc0, 0x5d, 0x3c, 0x33, 0x41, 0x6d, 0xaf, 0xb2, 0x25, 0x23, 0x14,
// 0xa5, 0x7b, 0xc7, 0x9b, 0x68, 0xf3, 0xda, 0xeb, 0xe3, 0xa9, 0xe2, 0x6f, 0x0e, 0x1d, 0x1c,
// 0xba, 0x55, 0xb6, 0x34, 0x6a, 0x93, 0x1f, 0x1f, 0xb8, 0x34, 0xc8, 0x84, 0x08, 0xb1, 0x6b,
// 0x6a, 0x28, 0x74, 0x74, 0xe5, 0xeb, 0x75, 0xe9, 0x7c, 0xd8, 0xba, 0xd8, 0x42, 0xa5, 0xee,
// 0x1f, 0x80, 0xd9, 0x96, 0xb2, 0x2e, 0xe7, 0xbf, 0xba, 0xeb, 0xd1, 0x69, 0xbb, 0x8f, 0xfd,
// 0x5a, 0x63, 0x8f, 0x39, 0x7f, 0xdf, 0x1d, 0x37, 0xd2, 0x18, 0x35, 0x9d, 0xb6, 0xcc, 0xe4,
// 0x27, 0x81, 0x89, 0x38, 0x38, 0x68, 0x33, 0xe7, 0x78, 0xd8, 0x76, 0xf5, 0xee, 0xd0, 0x4a,
// 0x07, 0x69, 0x19, 0x7a, 0xad, 0x18, 0xb1, 0x94, 0x61, 0x45, 0x53, 0xa2, 0x48, 0xda, 0x96,
// 0x4a, 0xf9, 0xee, 0x94, 0x2a, 0x1f, 0x6e, 0x18, 0x3c, 0x92, 0x46, 0xd1, 0x1a, 0x28, 0x18,
// 0x32, 0x1f, 0x3a, 0x45, 0xbe, 0x04, 0x35, 0x92, 0xe5, 0xa3, 0xcb, 0xb5, 0x2e, 0x32, 0x43,
// 0xac, 0x65, 0x17, 0x89, 0x99, 0x15, 0x03, 0x9e, 0xb1, 0x23, 0x2f, 0xed, 0x76, 0x4d, 0xd8,
// 0xac, 0x21, 0x40, 0xc4, 0x99, 0x4e, 0x65, 0x71, 0x2c, 0xb3, 0x45, 0xab, 0xfb, 0xe7, 0x72,
// 0x39, 0x56, 0x30, 0x6d, 0xfb, 0x74, 0xeb, 0x99, 0xf3, 0xcd, 0x57, 0x5c, 0x78, 0x75, 0xe9,
// 0x8d, 0xc3, 0xa2, 0xfb, 0x5d, 0xe0, 0x90, 0xc5, 0x55, 0xad, 0x91, 0x53, 0x4e, 0x9e, 0xbd,
// 0x8c, 0x49, 0xa4, 0xa4, 0x69, 0x10, 0x0c, 0xc5, 0x76, 0xe9, 0x25, 0x86, 0x8d, 0x66, 0x23,
// 0xa8, 0xdb, 0x5c, 0xe8, 0xd9, 0x30, 0xe1, 0x15, 0x7b, 0xc0, 0x99, 0x0f, 0x03, 0xec, 0xaa,
// 0x12, 0xef, 0xce, 0xd4, 0xea, 0x55, 0x5c, 0x08, 0x86, 0xf4, 0xf4, 0xb0, 0x83, 0x42, 0x95,
// 0x37, 0xb6, 0x38, 0xe0, 0x2b, 0x54, 0x89, 0xbd, 0x4e, 0x20, 0x9d, 0x3f, 0xc3, 0x4b, 0xb7,
// 0xec, 0xfa, 0x5a, 0x14, 0x03, 0xcb, 0x64, 0xc8, 0x34, 0x4a, 0x4b, 0x6e, 0xf8, 0x6e, 0x56,
// 0xf6, 0xdd, 0x5f, 0xa1, 0x24, 0xe2, 0xd4, 0xd0, 0x82, 0x64, 0x1f, 0x8e, 0x9b, 0xfa, 0xb4,
// 0xcb, 0xdb, 0x0a, 0xe8, 0x15, 0xfc, 0x15, 0xab, 0x4b, 0x18, 0xbf, 0xd4, 0x42, 0x14, 0x48,
// 0x82, 0x85, 0xdd, 0xeb, 0x49, 0x1b, 0x0b, 0x0b, 0x05, 0xe9, 0xb4, 0xa1, 0x33, 0x0a, 0x5d,
// 0x0e, 0x6c, 0x4b, 0xc0, 0xd6, 0x6c, 0x7c, 0xfb, 0x69, 0x0b, 0x53, 0x19, 0xe4, 0xf3, 0x35,
// 0xfc, 0xbe, 0xa1, 0x34, 0x02, 0x09, 0x4f, 0x74, 0x86, 0x92, 0xcd, 0x5d, 0x1a, 0xc1, 0x27,
// 0x0c, 0xf2, 0xc5, 0xcf, 0xdd, 0x23, 0x93, 0x02, 0xbd, 0x41, 0x5e, 0x42, 0xf0, 0xa0, 0x9d,
// 0x0c, 0x72, 0xc8, 0xec, 0x32, 0x0a, 0x8a, 0xfd, 0x3d, 0x5a, 0x41, 0x27, 0x0c, 0x88, 0x59,
// 0xad, 0x94, 0x2e, 0xef, 0x5d, 0x8f, 0xc7, 0xdf, 0x66, 0xe4, 0xdd, 0x56, 0x6c, 0x7b, 0xca,
// 0x55, 0x81, 0xae, 0xae, 0x5c, 0x1b, 0x1a, 0xab, 0xae, 0x99, 0x8d, 0xcc, 0x42, 0x97, 0x59,
// 0xf4, 0x14, 0x3f, 0x75, 0xc6, 0xd1, 0x88, 0xba, 0xaa, 0x84, 0x4a, 0xd0, 0x34, 0x08, 0x3b,
// 0x7d, 0xdb, 0x15, 0x06, 0xb0, 0x5c, 0xbd, 0x40, 0xf5, 0xa8, 0xec, 0xae, 0x36, 0x40, 0xdd,
// 0x90, 0x1c, 0x3e, 0x0d, 0x7e, 0x73, 0xc7, 0xc2, 0xc5, 0x6a, 0xff, 0x52, 0x05, 0x7f, 0xbe,
// 0xd0, 0x92, 0xfd, 0xb3, 0x6f, 0xff, 0x5d, 0xb7, 0x97, 0x64, 0x73, 0x7b, 0xca, 0xd1, 0x98,
// 0x24, 0x6b, 0x0b, 0x01, 0x68, 0xdd, 0x27, 0x85, 0x85, 0xb5, 0x83, 0xc1, 0xe0, 0x50, 0x64,
// 0xc7, 0xaf, 0xf1, 0xc6, 0x4d, 0xb1, 0xef, 0xc9, 0xb4, 0x0a, 0x6d, 0x65, 0xf3, 0x47, 0xcc,
// 0xa3, 0x02, 0x21, 0x0c, 0xbe, 0x22, 0x29, 0x05, 0xcf, 0x5f, 0xe8, 0x94, 0x6c, 0xe5, 0xdc,
// 0xc4, 0xdf, 0xbe, 0x3e, 0xa8, 0xb4, 0x18, 0xb0, 0x99, 0xb8, 0x6f, 0xff, 0x5d, 0xb9, 0xfd,
// 0x3b, 0x5d, 0x16, 0xbf, 0x3e, 0xd8, 0xb3, 0xd8, 0x08, 0x34, 0xf6, 0x47, 0x35, 0x5b, 0x72,
// 0x1a, 0x33, 0xad, 0x52, 0x5d, 0xb8, 0xd0, 0x77, 0xc6, 0xab, 0xba, 0x55, 0x09, 0x5f, 0x02,
// 0xf8, 0xd4, 0x5f, 0x53, 0x06, 0x91, 0xcd, 0x74, 0x42, 0xae, 0x54, 0x91, 0x81, 0x62, 0x13,
// 0x6f, 0xd8, 0xa9, 0x77, 0xc3, 0x6c, 0xcb, 0xf1, 0x29, 0x5a, 0xcc, 0xda, 0x35, 0xbd, 0x52,
// 0x23, 0xbe, 0x59, 0xeb, 0x12, 0x6d, 0xb7, 0x53, 0xee, 0xfc, 0xb4, 0x1b, 0x13, 0x5e, 0xba,
// 0x16, 0x7c, 0xc5, 0xf3, 0xe3, 0x6d, 0x07, 0x78, 0xf5, 0x2b, 0x21, 0x05, 0x88, 0x4c, 0xc0,
// 0xa1, 0xe3, 0x36, 0x10, 0xf8, 0x1b, 0xd8, 0x17, 0xfb, 0x6a, 0x4e, 0xd8, 0xb3, 0x47, 0x2d,
// 0x99, 0xbd, 0xbb, 0x5d, 0x37, 0x7d, 0xba, 0xf1, 0xe1, 0x7c, 0xc0, 0xc5, 0x54, 0x62, 0x7f,
// 0xcf, 0x5a, 0x4a, 0x93, 0xcc, 0xf1, 0x1b, 0x34, 0xc8, 0xa6, 0x05, 0x4c, 0x55, 0x8b, 0x54,
// 0x84, 0xd5, 0x77, 0xeb, 0xc0, 0x6d, 0x3a, 0x29, 0xbd, 0x75, 0x61, 0x09, 0x9a, 0x2c, 0xbb,
// 0xf7, 0x18, 0x79, 0x34, 0x90, 0x24, 0xa5, 0x81, 0x70, 0x87, 0xc5, 0x02, 0x7c, 0xba, 0xd4,
// 0x5e, 0x14, 0x8e, 0xe4, 0xed, 0xa2, 0x61, 0x6a, 0xb9, 0x6e, 0xb5, 0x4a, 0xb9, 0x01, 0x46,
// 0xf4, 0xcf, 0xbc, 0x09, 0x2f, 0x27, 0x4b, 0xbd, 0x86, 0x7a, 0x10, 0xe1, 0xd4, 0xc8, 0xd9,
// 0x20, 0x8d, 0x8a, 0x63, 0x00, 0x63, 0x44, 0xeb, 0x54, 0x0b, 0x75, 0x49, 0x10, 0xa2, 0xa7,
// 0xad, 0xb9, 0xd1, 0x01, 0x80, 0x63, 0x25, 0xc8, 0x12, 0xa6, 0xce, 0x1e, 0xbe, 0xfe, 0x7e,
// 0x5f, 0x3c, 0xdb, 0x34, 0xea, 0x37, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x8c, 0x9a, 0xb6,
// 0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x1b, 0xb4, 0xea, 0x56,
// 0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xd6, 0x2e, 0xde, 0x1f, 0x9d,
// 0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x66, 0x4e, 0x1e, 0x9f, 0x9d, 0xb8, 0xf2, 0x47,
// 0x0c, 0x9a, 0xb6, 0xee, 0x3f, 0xfc, 0x7a, 0x57, 0x0d, 0x79, 0x70, 0x62, 0x27, 0xad, 0xb9,
// 0xd1, 0x01, 0x61, 0x40, 0x02, 0x67, 0x2d, 0xd8, 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xd7, 0x2c,
// 0xbb, 0xf4, 0x4b, 0xf5, 0x49, 0xf1, 0x60, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x01,
// 0x80, 0x63, 0x25, 0xa9, 0xb1, 0xe0, 0x42, 0xe7, 0x4c, 0x1a, 0x97, 0xac, 0xbb, 0xf4, 0x6a,
// 0x37, 0xcd, 0x18, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0xa8, 0xd2, 0x07, 0x6d, 0x58, 0x32,
// 0xe6, 0x4e, 0x1e, 0x9f, 0xbc, 0xfa, 0x57, 0x0d, 0x79, 0x51, 0x20, 0xc2, 0x06, 0x6f, 0x5c,
// 0x1b, 0x95, 0xa8, 0xb3, 0xc5, 0xe9, 0x31, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93,
// 0x85, 0x69, 0x31, 0xc1, 0xe1, 0x21, 0xc0, 0xe3, 0x44, 0x0a, 0x77, 0x6c, 0x5a, 0x17, 0x8d,
// 0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x17, 0xac, 0xbb, 0xf4, 0x4b, 0x14,
// 0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xb3, 0xc5, 0xe9, 0x31, 0xc1, 0x00, 0x82, 0x67, 0x4c,
// 0xfb, 0x55, 0x28, 0xd2, 0x26, 0xaf, 0xbd, 0xd9, 0x11, 0x81, 0x61, 0x21, 0xa1, 0xa1, 0xc0,
// 0x02, 0x86, 0x6f, 0x5c, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xdd,
// 0x19, 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x7c, 0x5b, 0x15, 0x89, 0x90, 0x83, 0x84, 0x6b, 0x54,
// 0x0b, 0x75, 0x68, 0x52, 0x07, 0x6d, 0x58, 0x32, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0xed, 0x58,
// 0x32, 0xe6, 0x4e, 0xff, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xdd, 0x38, 0xd3, 0x05, 0x88, 0x92,
// 0xa6, 0xaf, 0xdc, 0x1b, 0xb4, 0xcb, 0xf5, 0x68, 0x52, 0x07, 0x8c, 0x7b, 0x55, 0x09, 0x90,
// 0x83, 0x84, 0x6b, 0x54, 0x2a, 0xb7, 0xec, 0x3b, 0xd5, 0x09, 0x90, 0xa2, 0xc6, 0x0e, 0x7f,
// 0x7c, 0x7a, 0x57, 0x0d, 0x98, 0xb2, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0x0c, 0x7b, 0x74, 0x4b,
// 0x14, 0x8b, 0x94, 0xaa, 0xb7, 0xcd, 0x18, 0x93, 0xa4, 0xca, 0x16, 0xae, 0xbf, 0xdd, 0x19,
// 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x63, 0x44, 0xeb, 0x35, 0xc9,
// 0x10, 0x83, 0x65, 0x48, 0x12, 0xa6, 0xce, 0x1e, 0x9f, 0xbc, 0xdb, 0x15, 0x89, 0x71, 0x60,
// 0x23, 0xc4, 0xeb, 0x54, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xcf, 0x81, 0x10, 0xac, 0x74,
// ];
// }
...@@ -166,38 +166,6 @@ where ...@@ -166,38 +166,6 @@ where
let srom_id = pmw3389.read_register(Register::SROMId)?; let srom_id = pmw3389.read_register(Register::SROMId)?;
rprintln!("srom_id {}, 0x{:x}", srom_id, srom_id); rprintln!("srom_id {}, 0x{:x}", srom_id, srom_id);
// loop {
// pmw3389.write_register(Register::Motion, 0x01)?;
// let motion = pmw3389.read_register(Register::Motion)?;
// let xl = pmw3389.read_register(Register::DeltaXL)?;
// let xh = pmw3389.read_register(Register::DeltaXH)?;
// let yl = pmw3389.read_register(Register::DeltaYL)?;
// let yh = pmw3389.read_register(Register::DeltaYH)?;
// let x = (xl as u16 + (xh as u16) << 8) as i16;
// let y = (yl as u16 + (yh as u16) << 8) as i16;
// let surface = motion & 0x08;
// let motion_detect = motion & 0x80;
// rprintln!(
// "motion {}, surface {}, (x, y) {:?}",
// motion_detect,
// surface,
// (x, y),
// );
// pmw3389.delay.delay_ms(200);
// }
// self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
// self.delay.delay_ms(35); // waits for tSRAD
// loop {
// pmw3389.read_status(itm)?;
// pmw3389.delay.delay_ms(10);
// }
Ok(pmw3389) Ok(pmw3389)
} }
...@@ -208,8 +176,7 @@ where ...@@ -208,8 +176,7 @@ where
self.spi.transfer(&mut buffer)?; self.spi.transfer(&mut buffer)?;
// tSRAD // tSRAD
self.delay.delay_us(100); self.delay.delay_us(35);
self.delay.delay_us(120);
let mut buffer = [0]; let mut buffer = [0];
self.spi.transfer(&mut buffer)?; self.spi.transfer(&mut buffer)?;
...@@ -221,7 +188,6 @@ where ...@@ -221,7 +188,6 @@ where
// tSRW/tSRR (=20us) minus tSCLK-NCS // tSRW/tSRR (=20us) minus tSCLK-NCS
self.delay.delay_us(19); self.delay.delay_us(19);
self.delay.delay_us(120);
Ok(buffer[0]) Ok(buffer[0])
} }
...@@ -254,13 +220,10 @@ where ...@@ -254,13 +220,10 @@ where
} }
/// Read status /// Read status
pub fn read_status(&mut self) -> Result<(), E> { pub fn read_status(&mut self) -> Result<((i16, i16)), E> {
self.com_begin(); self.com_begin();
// self.write_register(Register::Motion, 0x01)?;
self.spi.transfer(&mut [Register::MotionBurst.addr()])?; self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
// self.write_register(Register::MotionBurst, 0x00);
self.delay.delay_us(35); // waits for tSRAD self.delay.delay_us(35); // waits for tSRAD
...@@ -269,16 +232,10 @@ where ...@@ -269,16 +232,10 @@ where
self.spi.transfer(&mut buf)?; self.spi.transfer(&mut buf)?;
// tSCLK-NCS for read operation is 120ns // tSCLK-NCS for read operation is 120ns
self.delay.delay_us(120); // self.delay.delay_us(120);
self.com_end(); self.com_end();
rprint!("burst [");
for j in buf.iter() {
rprint!("0x{:02x}, ", j);
}
rprintln!("]");
// SPI.endTransaction(); // Per:Not sure what it does // SPI.endTransaction(); // Per:Not sure what it does
// /* // /*
// BYTE[00] = Motion = if the 7th bit is 1, a motion is detected. // BYTE[00] = Motion = if the 7th bit is 1, a motion is detected.
...@@ -299,24 +256,16 @@ where ...@@ -299,24 +256,16 @@ where
// BYTE[11] = Shutter_Lower = Shutter MSB, Shutter = shutter is adjusted to keep the average raw data values within normal operating ranges // BYTE[11] = Shutter_Lower = Shutter MSB, Shutter = shutter is adjusted to keep the average raw data values within normal operating ranges
// */ // */
// int motion = (burstBuffer[0] & 0x80) > 0; // int motion = (burstBuffer[0] & 0x80) > 0;
let motion = buf[0] & 0x80; let _motion = buf[0] & 0x80;
let surface = buf[0] & 0x08; let _surface = buf[0] & 0x08;
// 0 if on surface / 1 if off surface // 0 if on surface / 1 if off surface
let x = buf[2] as u16 + (buf[3] as u16) << 8; let x: i16 = (((buf[3] as u16) << 8) | buf[2] as u16) as i16;
let y = buf[4] as u16 + (buf[5] as u16) << 8; let y: i16 = (((buf[5] as u16) << 8) | buf[4] as u16) as i16;
let squal = buf[6];
rprintln!( let _squal = buf[6];
"motion {}, surface {}, (x, y) {:?}, squal {}",
motion,
surface,
(x, y),
squal
);
Ok(()) Ok((x, y))
} }
// Upload the firmware // Upload the firmware
...@@ -369,9 +318,8 @@ where ...@@ -369,9 +318,8 @@ where
for i in Self::FIRMWARE.iter() { for i in Self::FIRMWARE.iter() {
let mut buff = [*i]; let mut buff = [*i];
// iprintln!(stim, "0x{:x}", buff[0]);
self.spi.transfer(&mut buff)?; self.spi.transfer(&mut buff)?;
self.delay.delay_us(15); // 15 self.delay.delay_us(15); // 15us delay between transfers
} }
// // Per: added this, seems adequate // // Per: added this, seems adequate
...@@ -387,18 +335,17 @@ where ...@@ -387,18 +335,17 @@ where
// //Write 0x00 to Config2 register for wired mouse or 0x20 for wireless mouse design. // //Write 0x00 to Config2 register for wired mouse or 0x20 for wireless mouse design.
// // adns_write_reg(Config2, 0x00); // // adns_write_reg(Config2, 0x00);
self.write_register(Register::Config2, 0x20)?; self.write_register(Register::Config2, 0x00)?;
// // set initial CPI resolution // // set initial CPI resolution
// // adns_write_reg(Config1, 0x15); // // adns_write_reg(Config1, 0x15);
// self.write_register(Register::ResolutionL, 0x15)?; let cpi: u16 = 16000;
self.write_register(Register::ResolutionL, 0x5)?; self.write_register(Register::ResolutionL, cpi as u8)?;
// self.write_register(Register::ResolutionH, 0x15)?; self.write_register(Register::ResolutionH, (cpi >> 8) as u8)?;
self.write_register(Register::ResolutionH, 0x00)?;
// adns_com_end(); // why the CS is already high // adns_com_end(); // why the CS is already high
self.com_end(); // self.com_end();
Ok(()) Ok(())
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment