diff options
Diffstat (limited to 'keyboards/molecule')
-rw-r--r-- | keyboards/molecule/adns.c | 254 | ||||
-rw-r--r-- | keyboards/molecule/adns.h | 36 | ||||
-rw-r--r-- | keyboards/molecule/adns9800_srom_A6.h | 3081 | ||||
-rwxr-xr-x | keyboards/molecule/config.h | 159 | ||||
-rwxr-xr-x | keyboards/molecule/info.json | 215 | ||||
-rwxr-xr-x | keyboards/molecule/keymaps/default/keymap.c | 39 | ||||
-rwxr-xr-x | keyboards/molecule/keymaps/default/readme.md | 1 | ||||
-rwxr-xr-x | keyboards/molecule/molecule.c | 17 | ||||
-rwxr-xr-x | keyboards/molecule/molecule.h | 40 | ||||
-rwxr-xr-x | keyboards/molecule/readme.md | 21 | ||||
-rwxr-xr-x | keyboards/molecule/rules.mk | 27 |
11 files changed, 3890 insertions, 0 deletions
diff --git a/keyboards/molecule/adns.c b/keyboards/molecule/adns.c new file mode 100644 index 0000000000..be40cf7ea7 --- /dev/null +++ b/keyboards/molecule/adns.c @@ -0,0 +1,254 @@ +/* Copyright 2020 Richard Sutherland <rich@brickbots.com> + * + * 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 2 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 <http://www.gnu.org/licenses/>. + */ +#include "spi_master.h" +#include "adns.h" +#include "debug.h" +#include "quantum.h" +#include "pointing_device.h" +#include "adns9800_srom_A6.h" + +// registers +#define REG_Product_ID 0x00 +#define REG_Revision_ID 0x01 +#define REG_Motion 0x02 +#define REG_Delta_X_L 0x03 +#define REG_Delta_X_H 0x04 +#define REG_Delta_Y_L 0x05 +#define REG_Delta_Y_H 0x06 +#define REG_SQUAL 0x07 +#define REG_Pixel_Sum 0x08 +#define REG_Maximum_Pixel 0x09 +#define REG_Minimum_Pixel 0x0a +#define REG_Shutter_Lower 0x0b +#define REG_Shutter_Upper 0x0c +#define REG_Frame_Period_Lower 0x0d +#define REG_Frame_Period_Upper 0x0e +#define REG_Configuration_I 0x0f +#define REG_Configuration_II 0x10 +#define REG_Frame_Capture 0x12 +#define REG_SROM_Enable 0x13 +#define REG_Run_Downshift 0x14 +#define REG_Rest1_Rate 0x15 +#define REG_Rest1_Downshift 0x16 +#define REG_Rest2_Rate 0x17 +#define REG_Rest2_Downshift 0x18 +#define REG_Rest3_Rate 0x19 +#define REG_Frame_Period_Max_Bound_Lower 0x1a +#define REG_Frame_Period_Max_Bound_Upper 0x1b +#define REG_Frame_Period_Min_Bound_Lower 0x1c +#define REG_Frame_Period_Min_Bound_Upper 0x1d +#define REG_Shutter_Max_Bound_Lower 0x1e +#define REG_Shutter_Max_Bound_Upper 0x1f +#define REG_LASER_CTRL0 0x20 +#define REG_Observation 0x24 +#define REG_Data_Out_Lower 0x25 +#define REG_Data_Out_Upper 0x26 +#define REG_SROM_ID 0x2a +#define REG_Lift_Detection_Thr 0x2e +#define REG_Configuration_V 0x2f +#define REG_Configuration_IV 0x39 +#define REG_Power_Up_Reset 0x3a +#define REG_Shutdown 0x3b +#define REG_Inverse_Product_ID 0x3f +#define REG_Motion_Burst 0x50 +#define REG_SROM_Load_Burst 0x62 +#define REG_Pixel_Burst 0x64 + +// pins +#define NCS F7 + +extern const uint16_t firmware_length; +extern const uint8_t firmware_data[]; + +enum motion_burst_propertr{ + motion = 0, + observation, + delta_x_l, + delta_x_h, + delta_y_l, + delta_y_h, + squal, + pixel_sum, + maximum_pixel, + minimum_pixel, + shutter_upper, + shutter_lower, + frame_period_upper, + frame_period_lower, + end_data +}; + +void adns_begin(void){ + spi_start(NCS, false, 3, 8); +} + +void adns_end(void){ + spi_stop(); +} + +void adns_write(uint8_t reg_addr, uint8_t data){ + + adns_begin(); + //send address of the register, with MSBit = 1 to indicate it's a write + spi_write(reg_addr | 0x80 ); + spi_write(data); + + // tSCLK-NCS for write operation + wait_us(20); + + + // tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound + wait_us(100); + adns_end(); +} + +uint8_t adns_read(uint8_t reg_addr){ + + + adns_begin(); + // send adress of the register, with MSBit = 0 to indicate it's a read + spi_write(reg_addr & 0x7f ); + uint8_t data = spi_read(); + + // tSCLK-NCS for read operation is 120ns + wait_us(1); + + + // tSRW/tSRR (=20us) minus tSCLK-NCS + wait_us(19); + + adns_end(); + return data; +} + +void pointing_device_init(void) { + dprint("STARTING INTI\n"); + + spi_init(); + // reset serial port + adns_begin(); + adns_end(); + + // reboot + adns_write(REG_Power_Up_Reset, 0x5a); + wait_ms(50); + // read registers and discard + adns_read(REG_Motion); + adns_read(REG_Delta_X_L); + adns_read(REG_Delta_X_H); + adns_read(REG_Delta_Y_L); + adns_read(REG_Delta_Y_H); + + // upload firmware + + // set the configuration_IV register in 3k firmware mode + // bit 1 = 1 for 3k mode, other bits are reserved + adns_write(REG_Configuration_IV, 0x02); + + // write 0x1d in SROM_enable reg for initializing + adns_write(REG_SROM_Enable, 0x1d); + + // wait for more than one frame period + // assume that the frame rate is as low as 100fps... even if it should never be that low + wait_ms(10); + + // write 0x18 to SROM_enable to start SROM download + adns_write(REG_SROM_Enable, 0x18); + + // write the SROM file (=firmware data) + + // write burst destination adress + adns_begin(); + spi_write(REG_SROM_Load_Burst | 0x80); + wait_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_write(c); + wait_us(15); + } + + adns_end(); + wait_ms(10); + + // enable laser(bit 0 = 0b), in normal mode (bits 3,2,1 = 000b) + // reading the actual value of the register is important because the real + // default value is different from what is said in the datasheet, and if you + // change the reserved bytes (like by writing 0x00...) it would not work. + uint8_t laser_ctrl0 = adns_read(REG_LASER_CTRL0); + adns_write(REG_LASER_CTRL0, laser_ctrl0 & 0xf0); + + wait_ms(1); + + // set the configuration_I register to set the CPI + // 0x01 = 50, minimum + // 0x44 = 3400, default + // 0x8e = 7100 + // 0xA4 = 8200, maximum + adns_write(REG_Configuration_I, 0x10); + + wait_ms(100); + dprint("INIT ENDED\n"); +} + +int16_t convertDeltaToInt(uint8_t high, uint8_t low){ + + // join bytes into twos compliment + //int16_t twos_comp = (high << 8) | low; + //return twos_comp; + return (high << 8) | low; +} + +motion_delta_t readSensor(void) { + adns_begin(); + + // read from Motion_Burst to enable burt mode + spi_write(REG_Motion_Burst & 0x7f); + + // Wait one frame per docs, thanks u/kbjunky + wait_us(100); + uint8_t burst_data[pixel_sum]; + + for (int i = 0; i < pixel_sum; ++i) { + burst_data[i] = spi_read(); + } + + uint16_t delta_x = convertDeltaToInt(burst_data[delta_x_h], burst_data[delta_x_l]); + uint16_t delta_y = convertDeltaToInt(burst_data[delta_y_h], burst_data[delta_y_l]); + // Only consider the MSB for motion as this byte has other status bits + uint8_t motion_ind = burst_data[motion] & 0b10000000; + adns_end(); + + motion_delta_t delta = {delta_x, delta_y, motion_ind}; + return delta; +} + +void pointing_device_task(void) { + motion_delta_t delta = readSensor(); + + report_mouse_t report = pointing_device_get_report(); + + if(delta.motion_ind) { + // clamp deltas from -127 to 127 + report.x = delta.delta_x < -127 ? -127 : delta.delta_x > 127 ? 127 : delta.delta_x; + report.x = -report.x; + report.y = delta.delta_y < -127 ? -127 : delta.delta_y > 127 ? 127 : delta.delta_y; + } + + pointing_device_set_report(report); + pointing_device_send(); +} diff --git a/keyboards/molecule/adns.h b/keyboards/molecule/adns.h new file mode 100644 index 0000000000..d684d3cbcb --- /dev/null +++ b/keyboards/molecule/adns.h @@ -0,0 +1,36 @@ +/* Copyright 2020 Richard Sutherland <rich@brickbots.com> + * + * 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 2 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 <http://www.gnu.org/licenses/>. + */ +#pragma once + +void adns_begin(void); + +void adns_end(void); + +void adns_write(uint8_t reg_addr, uint8_t data); + +uint8_t adns_read(uint8_t reg_addr); + + +int16_t convertDeltaToInt(uint8_t high, uint8_t low); + +struct _motion_delta { + int16_t delta_x; + int16_t delta_y; + int8_t motion_ind; +}; +typedef struct _motion_delta motion_delta_t; + +motion_delta_t readSensor(void); diff --git a/keyboards/molecule/adns9800_srom_A6.h b/keyboards/molecule/adns9800_srom_A6.h new file mode 100644 index 0000000000..fddf30589d --- /dev/null +++ b/keyboards/molecule/adns9800_srom_A6.h @@ -0,0 +1,3081 @@ +// ADNS-9800 Firmware bytecode is Copyright Avago Technologies. +// Originally formatted for Arduino use by MrJohnK - https://github.com/mrjohnk + +#pragma once + +#include "progmem.h" + +const uint16_t firmware_length = 3070; + +const uint8_t firmware_data[] PROGMEM = { + 0x03, +0xa6, +0x68, +0x1e, +0x7d, +0x10, +0x7e, +0x7e, +0x5f, +0x1c, +0xb8, +0xf2, +0x47, +0x0c, +0x7b, +0x74, +0x4b, +0x14, +0x8b, +0x75, +0x66, +0x51, +0x0b, +0x8c, +0x76, +0x74, +0x4b, +0x14, +0xaa, +0xd6, +0x0f, +0x9c, +0xba, +0xf6, +0x6e, +0x3f, +0xdd, +0x38, +0xd5, +0x02, +0x80, +0x9b, +0x82, +0x6d, +0x58, +0x13, +0xa4, +0xab, +0xb5, +0xc9, +0x10, +0xa2, +0xc6, +0x0a, +0x7f, +0x5d, +0x19, +0x91, +0xa0, +0xa3, +0xce, +0xeb, +0x3e, +0xc9, +0xf1, +0x60, +0x42, +0xe7, +0x4c, +0xfb, +0x74, +0x6a, +0x56, +0x2e, +0xbf, +0xdd, +0x38, +0xd3, +0x05, +0x88, +0x92, +0xa6, +0xce, +0xff, +0x5d, +0x38, +0xd1, +0xcf, +0xef, +0x58, +0xcb, +0x65, +0x48, +0xf0, +0x35, +0x85, +0xa9, +0xb2, +0x8f, +0x5e, +0xf3, +0x80, +0x94, +0x97, +0x7e, +0x75, +0x97, +0x87, +0x73, +0x13, +0xb0, +0x8a, +0x69, +0xd4, +0x0a, +0xde, +0xc1, +0x79, +0x59, +0x36, +0xdb, +0x9d, +0xd6, +0xb8, +0x15, +0x6f, +0xce, +0x3c, +0x72, +0x32, +0x45, +0x88, +0xdf, +0x6c, +0xa5, +0x6d, +0xe8, +0x76, +0x96, +0x14, +0x74, +0x20, +0xdc, +0xf4, +0xfa, +0x37, +0x6a, +0x27, +0x32, +0xe3, +0x29, +0xbf, +0xc4, +0xc7, +0x06, +0x9d, +0x58, +0xe7, +0x87, +0x7c, +0x2e, +0x9f, +0x6e, +0x49, +0x07, +0x5d, +0x23, +0x64, +0x54, +0x83, +0x6e, +0xcb, +0xb7, +0x77, +0xf7, +0x2b, +0x6e, +0x0f, +0x2e, +0x66, +0x12, +0x60, +0x55, +0x65, +0xfc, +0x43, +0xb3, +0x58, +0x73, +0x5b, +0xe8, +0x67, +0x04, +0x43, +0x02, +0xde, +0xb3, +0x89, +0xa0, +0x6d, +0x3a, +0x27, +0x79, +0x64, +0x5b, +0x0c, +0x16, +0x9e, +0x66, +0xb1, +0x8b, +0x87, +0x0c, +0x5d, +0xf2, +0xb6, +0x3d, +0x71, +0xdf, +0x42, +0x03, +0x8a, +0x06, +0x8d, +0xef, +0x1d, +0xa8, +0x96, +0x5c, +0xed, +0x31, +0x61, +0x5c, +0xa1, +0x34, +0xf6, +0x8c, +0x08, +0x60, +0x33, +0x07, +0x00, +0x3e, +0x79, +0x95, +0x1b, +0x43, +0x7f, +0xfe, +0xb6, +0xa6, +0xd4, +0x9d, +0x76, +0x72, +0xbf, +0xad, +0xc0, +0x15, +0xe8, +0x37, +0x31, +0xa3, +0x72, +0x63, +0x52, +0x1d, +0x1c, +0x5d, +0x51, +0x1b, +0xe1, +0xa9, +0xed, +0x60, +0x32, +0x3e, +0xa9, +0x50, +0x28, +0x53, +0x06, +0x59, +0xe2, +0xfc, +0xe7, +0x02, +0x64, +0x39, +0x21, +0x56, +0x4a, +0xa5, +0x40, +0x80, +0x81, +0xd5, +0x5a, +0x60, +0x7b, +0x68, +0x84, +0xf1, +0xe0, +0xb1, +0xb6, +0x5b, +0xdf, +0xa8, +0x1d, +0x6d, +0x65, +0x20, +0xc0, +0xa2, +0xb9, +0xd9, +0xbb, +0x00, +0xa6, +0xdb, +0x8b, +0x01, +0x53, +0x91, +0xfe, +0xc4, +0x51, +0x85, +0xb0, +0x96, +0x7f, +0xfd, +0x51, +0xdd, +0x14, +0x03, +0x67, +0x2e, +0x75, +0x1c, +0x76, +0xd3, +0x6e, +0xdd, +0x99, +0x55, +0x76, +0xe5, +0xab, +0x23, +0xfc, +0x4a, +0xd5, +0xc6, +0xe8, +0x2e, +0xca, +0x8a, +0xb3, +0xf6, +0x8c, +0x6c, +0xb0, +0xe9, +0xf2, +0xe7, +0x9e, +0x69, +0x41, +0xed, +0xf1, +0x6d, +0xd2, +0x86, +0xd8, +0x7e, +0xcb, +0x5d, +0x47, +0x6c, +0x85, +0x6a, +0x23, +0xed, +0x20, +0x40, +0x93, +0xb4, +0x20, +0xc7, +0xa5, +0xc9, +0xaf, +0x03, +0x15, +0xac, +0x19, +0xe5, +0x2a, +0x36, +0xdf, +0x6d, +0xc5, +0x8c, +0x80, +0x07, +0xce, +0x92, +0x0c, +0xd8, +0x06, +0x62, +0x0f, +0xdd, +0x48, +0x46, +0x1a, +0x53, +0xc7, +0x8a, +0x8c, +0x5d, +0x5d, +0xb4, +0xa1, +0x02, +0xd3, +0xa9, +0xb8, +0xf3, +0x94, +0x8f, +0x3f, +0xe5, +0x54, +0xd4, +0x11, +0x65, +0xb2, +0x5e, +0x09, +0x0b, +0x81, +0xe3, +0x75, +0xa7, +0x89, +0x81, +0x39, +0x6c, +0x46, +0xf6, +0x06, +0x9f, +0x27, +0x3b, +0xb6, +0x2d, +0x5f, +0x1d, +0x4b, +0xd4, +0x7b, +0x1d, +0x61, +0x74, +0x89, +0xe4, +0xe3, +0xbd, +0x98, +0x1b, +0xc4, +0x51, +0x3b, +0xa4, +0xfa, +0xe0, +0x92, +0xf7, +0xbe, +0xf2, +0x4d, +0xbb, +0xff, +0xad, +0x4f, +0x6d, +0x68, +0xc2, +0x79, +0x40, +0xaa, +0x9b, +0x8f, +0x0c, +0x32, +0x4b, +0x5f, +0x3e, +0xab, +0x59, +0x98, +0xb3, +0xf5, +0x1d, +0xac, +0x5e, +0xbc, +0x78, +0xd3, +0x01, +0x6c, +0x64, +0x15, +0x2f, +0xd8, +0x71, +0xa6, +0x2d, +0x45, +0xe1, +0x22, +0x42, +0xe4, +0x4e, +0x04, +0x3c, +0x7d, +0xf4, +0x40, +0x21, +0xb4, +0x67, +0x05, +0xa8, +0xe2, +0xf3, +0x72, +0x87, +0x4c, +0x7d, +0xd9, +0x1b, +0x65, +0x97, +0xf3, +0xc2, +0xe3, +0xe4, +0xc8, +0xd2, +0xde, +0xf6, +0xef, +0xdc, +0xbb, +0x44, +0x08, +0x5e, +0xe2, +0x45, +0x27, +0x01, +0xb0, +0xf6, +0x43, +0xe7, +0x3a, +0xf6, +0xdc, +0x9d, +0xed, +0xf3, +0xc5, +0x0c, +0xb8, +0x9c, +0x98, +0x3a, +0xd8, +0x36, +0xee, +0x96, +0x72, +0x67, +0xe7, +0x81, +0x91, +0xd5, +0x05, +0x0a, +0xe0, +0x82, +0xd5, +0x8f, +0xe8, +0xf9, +0xb0, +0xc9, +0xcf, +0x93, +0xe7, +0x04, +0xc5, +0xbc, +0x2b, +0x43, +0x56, +0x7e, +0xe8, +0x67, +0x7c, +0xe5, +0xfb, +0x49, +0xad, +0x5e, +0x9f, +0x25, +0x13, +0xde, +0x6e, +0x6e, +0xe9, +0xf1, +0xec, +0x87, +0x0b, +0x59, +0x81, +0x76, +0x84, +0x76, +0xb3, +0x24, +0xaf, +0x30, +0xfd, +0x27, +0x8b, +0xab, +0xd8, +0x00, +0x8b, +0x9b, +0x0c, +0xd2, +0xb2, +0x4e, +0x5e, +0x9d, +0x1d, +0x96, +0x01, +0x00, +0x67, +0xc1, +0x5f, +0x02, +0x20, +0xfd, +0x45, +0x6a, +0x01, +0x60, +0x58, +0x45, +0xca, +0x47, +0x21, +0x90, +0x5a, +0xc4, +0x43, +0x26, +0x1a, +0xd7, +0xa5, +0x4a, +0xb2, +0x5d, +0x2b, +0x35, +0x49, +0xfb, +0xa5, +0x17, +0x92, +0x21, +0x1e, +0x93, +0x96, +0x67, +0xa2, +0x7e, +0x36, +0x7a, +0xde, +0x5f, +0xbe, +0x7a, +0x58, +0x9d, +0xf8, +0x78, +0xa3, +0xfa, +0xc8, +0xd5, +0x17, +0xf0, +0x21, +0x97, +0x8c, +0x80, +0xb5, +0x4b, +0x3b, +0xbd, +0xbb, +0x41, +0x21, +0xa8, +0x50, +0x67, +0xf7, +0xe7, +0x19, +0x80, +0x10, +0x8e, +0xce, +0x04, +0x18, +0x3f, +0x51, +0x6b, +0x77, +0xd8, +0x9e, +0x16, +0xaf, +0xec, +0xef, +0x48, +0x16, +0x4d, +0x9e, +0x85, +0x38, +0x18, +0x3e, +0xd4, +0x28, +0x87, +0x60, +0x2a, +0xf6, +0x7f, +0x09, +0x86, +0x6f, +0x9c, +0x3c, +0x3a, +0xff, +0xab, +0xd0, +0x61, +0xa2, +0x97, +0x0d, +0x71, +0x94, +0x7e, +0xfd, +0xb9, +0x80, +0x02, +0x89, +0x6a, +0xb3, +0x84, +0x6c, +0x2a, +0x77, +0x62, +0xbe, +0x0b, +0xf4, +0xaf, +0xac, +0x7b, +0x7c, +0x8e, +0xca, +0x01, +0xba, +0x71, +0x78, +0x94, +0xfd, +0xb5, +0x39, +0xa4, +0x4d, +0x2f, +0x78, +0xcf, +0xca, +0x92, +0x0c, +0x1a, +0x99, +0x48, +0x4c, +0x11, +0x96, +0xb5, +0x4e, +0x41, +0x28, +0xe4, +0xa6, +0xfe, +0x4b, +0x72, +0x91, +0xe7, +0xd4, +0xdd, +0x9f, +0x12, +0xe6, +0x29, +0x38, +0xce, +0x45, +0xae, +0x02, +0xb8, +0x24, +0xae, +0xbd, +0xe9, +0x66, +0x08, +0x62, +0xa2, +0x2c, +0x2b, +0x00, +0xe2, +0x23, +0xd9, +0xc4, +0x48, +0xe4, +0xd3, +0xac, +0xbb, +0x34, +0xc7, +0xf0, +0xe3, +0x4f, +0xb9, +0x30, +0xea, +0xa2, +0x12, +0xf1, +0x30, +0x2c, +0x36, +0xde, +0x48, +0xf2, +0xb0, +0x4c, +0x43, +0x3f, +0x2e, +0x58, +0xe4, +0x20, +0xe3, +0x58, +0xcd, +0x31, +0x22, +0xf0, +0xa2, +0x2a, +0xe6, +0x19, +0x90, +0x55, +0x86, +0xf6, +0x55, +0x79, +0xd1, +0xd7, +0x46, +0x2f, +0xc0, +0xdc, +0x99, +0xe8, +0xf3, +0x6a, +0xdf, +0x7f, +0xeb, +0x24, +0x4a, +0x1e, +0x5a, +0x75, +0xde, +0x2f, +0x5c, +0x19, +0x61, +0x03, +0x53, +0x54, +0x6a, +0x3b, +0x18, +0x70, +0xb6, +0x4f, +0xf1, +0x9c, +0x0a, +0x59, +0x9d, +0x19, +0x92, +0x65, +0x8c, +0x83, +0x14, +0x2d, +0x44, +0x8a, +0x75, +0xa9, +0xf5, +0x90, +0xd2, +0x66, +0x4e, +0xfa, +0x69, +0x0f, +0x5b, +0x0b, +0x98, +0x65, +0xc8, +0x11, +0x42, +0x59, +0x7f, +0xdd, +0x1b, +0x75, +0x17, +0x31, +0x4c, +0x75, +0x58, +0xeb, +0x58, +0x63, +0x7d, +0xf2, +0xa6, +0xc2, +0x6e, +0xb7, +0x3f, +0x3e, +0x5e, +0x47, +0xad, +0xb7, +0x04, +0xe8, +0x05, +0xf8, +0xb2, +0xcf, +0x19, +0xf3, +0xd2, +0x85, +0xfe, +0x3e, +0x3e, +0xb1, +0x62, +0x08, +0x2c, +0x10, +0x07, +0x0d, +0x73, +0x90, +0x17, +0xfa, +0x9b, +0x56, +0x02, +0x75, +0xf9, +0x51, +0xe0, +0xe9, +0x1a, +0x7b, +0x9f, +0xb3, +0xf3, +0x98, +0xb8, +0x1c, +0x9c, +0xe1, +0xd5, +0x35, +0xae, +0xc8, +0x60, +0x48, +0x11, +0x09, +0x94, +0x6b, +0xd0, +0x8b, +0x15, +0xbc, +0x05, +0x68, +0xd3, +0x54, +0x8a, +0x51, +0x39, +0x5c, +0x42, +0x76, +0xce, +0xd8, +0xad, +0x89, +0x30, +0xc9, +0x05, +0x1c, +0xcc, +0x94, +0x3f, +0x0f, +0x90, +0x6f, +0x72, +0x2d, +0x85, +0x64, +0x9a, +0xb9, +0x23, +0xf9, +0x0b, +0xc3, +0x7c, +0x39, +0x0f, +0x97, +0x07, +0x97, +0xda, +0x58, +0x48, +0x33, +0x05, +0x23, +0xb8, +0x82, +0xe8, +0xd3, +0x53, +0x89, +0xaf, +0x33, +0x80, +0x22, +0x84, +0x0c, +0x95, +0x5c, +0x67, +0xb8, +0x77, +0x0c, +0x5c, +0xa2, +0x5f, +0x3d, +0x58, +0x0f, +0x27, +0xf3, +0x2f, +0xae, +0x48, +0xbd, +0x0b, +0x6f, +0x54, +0xfb, +0x67, +0x4c, +0xea, +0x32, +0x27, +0xf1, +0xfa, +0xe2, +0xb0, +0xec, +0x0b, +0x15, +0xb4, +0x70, +0xf6, +0x5c, +0xdd, +0x71, +0x60, +0xc3, +0xc1, +0xa8, +0x32, +0x65, +0xac, +0x7a, +0x77, +0x41, +0xe5, +0xa9, +0x6b, +0x11, +0x81, +0xfa, +0x34, +0x8d, +0xfb, +0xc1, +0x80, +0x6e, +0xc4, +0x60, +0x30, +0x07, +0xd4, +0x8b, +0x67, +0xbd, +0xaa, +0x8c, +0x9c, +0x64, +0xac, +0xdb, +0x0b, +0x24, +0x8b, +0x63, +0x6f, +0xe6, +0xbc, +0xe7, +0x33, +0xa4, +0x4a, +0x4c, +0xa7, +0x9f, +0x43, +0x53, +0xd2, +0xbb, +0x8f, +0x43, +0xc7, +0x3d, +0x78, +0x68, +0x3f, +0xa5, +0x3d, +0xca, +0x69, +0x84, +0xa6, +0x97, +0x2d, +0xc0, +0x7d, +0x31, +0x34, +0x55, +0x1d, +0x07, +0xb1, +0x5f, +0x40, +0x5c, +0x93, +0xb0, +0xbc, +0x7c, +0xb0, +0xbc, +0xe7, +0x12, +0xee, +0x6b, +0x2b, +0xd3, +0x4d, +0x67, +0x70, +0x3a, +0x9a, +0xf2, +0x3c, +0x7c, +0x81, +0xfa, +0xd7, +0xd9, +0x90, +0x91, +0x81, +0xb8, +0xb1, +0xf3, +0x48, +0x6a, +0x26, +0x4f, +0x0c, +0xce, +0xb0, +0x9e, +0xfd, +0x4a, +0x3a, +0xaf, +0xac, +0x5b, +0x3f, +0xbf, +0x44, +0x5a, +0xa3, +0x19, +0x1e, +0x4b, +0xe7, +0x36, +0x6a, +0xd7, +0x20, +0xae, +0xd7, +0x7d, +0x3b, +0xe7, +0xff, +0x3a, +0x86, +0x2e, +0xd0, +0x4a, +0x3e, +0xaf, +0x9f, +0x8e, +0x01, +0xbf, +0xf8, +0x4f, +0xc1, +0xe8, +0x6f, +0x74, +0xe1, +0x45, +0xd3, +0xf7, +0x04, +0x6a, +0x4b, +0x9d, +0xec, +0x33, +0x27, +0x76, +0xd7, +0xc5, +0xe1, +0xb0, +0x3b, +0x0e, +0x23, +0xec, +0xf0, +0x86, +0xd2, +0x1a, +0xbf, +0x3d, +0x04, +0x62, |