~ruther/qmk_firmware

7b666245d6e6baea939e0088fbbf9104d8efaca1 — bbrfkr 4 years ago 23631de
[Keyboard] add molecule (#12601)

Co-authored-by: Ryan <fauxpark@gmail.com>
Co-authored-by: Drashna Jaelre <drashna@live.com>
A keyboards/molecule/adns.c => keyboards/molecule/adns.c +254 -0
@@ 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();
}

A keyboards/molecule/adns.h => keyboards/molecule/adns.h +36 -0
@@ 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);

A keyboards/molecule/adns9800_srom_A6.h => keyboards/molecule/adns9800_srom_A6.h +3081 -0
@@ 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,
0xb3,
0x6c,
0xb2,
0xeb,
0x17,
0x05,
0xa6,
0x0a,
0x8a,
0x7e,
0x83,
0x1c,
0xb6,
0x37,
0x09,
0xc6,
0x0b,
0x70,
0x3c,
0xb5,
0x93,
0x81,
0xd8,
0x93,
0xa0,
0x5f,
0x1e,
0x08,
0xe2,
0xc6,
0xe5,
0xc9,
0x72,
0xf1,
0xf1,
0xc1,
0xed,
0xd5,
0x58,
0x93,
0x83,
0xf8,
0x65,
0x67,
0x2e,
0x0d,
0xa9,
0xf1,
0x64,
0x12,
0xe6,
0x4c,
0xea,
0x15,
0x3f,
0x8c,
0x1a,
0xb6,
0xbf,
0xf6,
0xb9,
0x52,
0x35,
0x09,
0xb0,
0xe6,
0xf7,
0xcd,
0xf1,
0xa5,
0xaa,
0x81,
0xd1,
0x81,
0x6f,
0xb4,
0xa9,
0x66,
0x1f,
0xfc,
0x48,
0xc0,
0xb6,
0xd1,
0x8b,
0x06,
0x2f,
0xf6,
0xef,
0x1f,
0x0a,
0xe6,
0xce,
0x3a,
0x4a,
0x55,
0xbf,
0x6d,
0xf9,
0x4d,
0xd4,
0x08,
0x45,
0x4b,
0xc3,
0x66,
0x19,
0x92,
0x10,
0xe1,
0x17,
0x8e,
0x28,
0x91,
0x16,
0xbf,
0x3c,
0xee,
0xa3,
0xa6,
0x99,
0x92,
0x10,
0xe1,
0xf6,
0xcc,
0xac,
0xb8,
0x65,
0x0b,
0x43,
0x66,
0xf8,
0xe3,
0xe5,
0x3f,
0x24,
0x89,
0x47,
0x5d,
0x78,
0x43,
0xd0,
0x61,
0x17,
0xbd,
0x5b,
0x64,
0x54,
0x08,
0x45,
0x59,
0x93,
0xf6,
0x95,
0x8a,
0x41,
0x51,
0x62,
0x4b,
0x51,
0x02,
0x30,
0x73,
0xc7,
0x87,
0xc5,
0x4b,
0xa2,
0x97,
0x0f,
0xe8,
0x46,
0x5f,
0x7e,
0x2a,
0xe1,
0x30,
0x20,
0xb0,
0xfa,
0xe7,
0xce,
0x61,
0x42,
0x57,
0x6e,
0x21,
0xf3,
0x7a,
0xec,
0xe3,
0x25,
0xc7,
0x25,
0xf3,
0x67,
0xa7,
0x57,
0x40,
0x00,
0x02,
0xcf,
0x1c,
0x80,
0x77,
0x67,
0xbd,
0x70,
0xa1,
0x19,
0x92,
0x31,
0x75,
0x93,
0x27,
0x27,
0xb6,
0x82,
0xe4,
0xeb,
0x1d,
0x78,
0x48,
0xe7,
0xa5,
0x5e,
0x57,
0xef,
0x64,
0x28,
0x64,
0x1b,
0xf6,
0x11,
0xb2,
0x03,
0x9d,
0xb9,
0x18,
0x02,
0x27,
0xf7,
0xbe,
0x9d,
0x55,
0xfc,
0x00,
0xd2,
0xc7,
0xae,
0xad,
0x0b,
0xc5,
0xe9,
0x42,
0x41,
0x48,
0xd8,
0x32,
0xcf,
0xf6,
0x0f,
0xf5,
0xbc,
0x97,
0xc6,
0x99,
0x47,
0x76,
0xbd,
0x89,
0x06,
0x0f,
0x63,
0x0c,
0x51,
0xd4,
0x5e,
0xea,
0x48,
0xa8,
0xa2,
0x56,
0x1c,
0x79,
0x84,
0x86,
0x40,
0x88,
0x41,
0x76,
0x55,
0xfc,
0xc2,
0xd7,
0xfd,
0xc9,
0xc7,
0x80,
0x61,
0x35,
0xa7,
0x43,
0x20,
0xf7,
0xeb,
0x6c,
0x66,
0x13,
0xb0,
0xec,
0x02,
0x75,
0x3e,
0x4b,
0xaf,
0xb9,
0x5d,
0x40,
0xda,
0xd6,
0x6e,
0x2d,
0x39,
0x54,
0xc2,
0x95,
0x35,
0x54,
0x25,
0x72,
0xe1,
0x78,
0xb8,
0xeb,
0xc1,
0x16,
0x58,
0x0f,
0x9c,
0x9b,
0xb4,
0xea,
0x37,
0xec,
0x3b,
0x11,
0xba,
0xd5,
0x8a,
0xa9,
0xe3,
0x98,
0x00,
0x51,
0x1c,
0x14,
0xe0,
0x40,
0x96,
0xe5,
0xe9,
0xf2,
0x21,
0x22,
0xb1,
0x23,
0x60,
0x78,
0xd3,
0x17,
0xf8,
0x7a,
0xa5,
0xa8,
0xba,
0x20,
0xd3,
0x15,
0x1e,
0x32,
0xe4,
0x5e,
0x15,
0x48,
0xae,
0xa9,
0xe5,
0xb8,
0x33,
0xec,
0xe8,
0xa2,
0x42,
0xac,
0xbf,
0x10,
0x84,
0x53,
0x87,
0x19,
0xb4,
0x5f,
0x76,
0x4d,
0x01,
0x9d,
0x56,
0x74,
0xd9,
0x5c,
0x97,
0xe7,
0x88,
0xea,
0x3a,
0xbf,
0xdc,
0x4c,
0x33,
0x8a,
0x16,
0xb9,
0x5b,
0xfa,
0xd8,
0x42,
0xa7,
0xbb,
0x3c,
0x04,
0x27,
0x78,
0x49,
0x81,
0x2a,
0x5a,
0x7d,
0x7c,
0x23,
0xa8,
0xba,
0xf7,
0x9a,
0x9f,
0xd2,
0x66,
0x3e,
0x38,
0x3c,
0x75,
0xf9,
0xd1,
0x30,
0x26,
0x30,
0x6e,
0x5a,
0x6e,
0xdc,
0x6a,
0x69,
0x32,
0x50,
0x33,
0x47,
0x9e,
0xa4,
0xa8,
0x64,
0x66,
0xf0,
0x8a,
0xe4,
0xfd,
0x27,
0x6f,
0x51,
0x25,
0x8b,
0x43,
0x74,
0xc9,
0x8e,
0xbd,
0x88,
0x31,
0xbe,
0xec,
0x65,
0xd2,
0xcb,
0x8d,
0x5a,
0x13,
0x48,
0x16,
0x8c,
0x61,
0x0b,
0x11,
0xf6,
0xc6,
0x66,
0xae,
0xc3,
0xcc,
0x0c,
0xd2,
0xe1,
0x9f,
0x82,
0x41,
0x3f,
0x56,
0xf9,
0x73,
0xef,
0xdc,
0x30,
0x50,
0xcf,
0xb6,
0x7f,
0xbc,
0xd0,
0xb3,
0x10,
0xab,
0x24,
0xe4,
0xec,
0xad,
0x18,
0x8c,
0x39,
0x2d,
0x30,
0x4c,
0xc5,
0x40,
0x0d,
0xf6,
0xac,
0xd6,
0x18,
0x5d,
0x96,
0xbf,
0x5f,
0x71,
0x75,
0x96,
0x22,
0x97,
0x0f,
0x02,
0x94,
0x6e,
0xa6,
0xae,
0x6d,
0x8f,
0x1e,
0xca,
0x12,
0x9b,
0x2a,
0x1c,
0xce,
0xa9,
0xee,
0xfd,
0x12,
0x8e,
0xfc,
0xed,
0x09,
0x33,
0xba,
0xf4,
0x1a,
0x15,
0xf6,
0x9d,
0x87,
0x16,
0x43,
0x7c,
0x78,
0x57,
0xe1,
0x44,
0xc9,
0xeb,
0x1f,
0x58,
0x4d,
0xc1,
0x49,
0x11,
0x5c,
0xb2,
0x11,
0xa8,
0x55,
0x16,
0xf1,
0xc6,
0x50,
0xe9,
0x87,
0x89,
0xf6,
0xcf,
0xd8,
0x9c,
0x51,
0xa7,
0xbc,
0x5b,
0x31,
0x6d,
0x4d,
0x51,
0xd0,
0x4c,
0xbc,
0x0d,
0x58,
0x2d,
0x7b,
0x88,
0x7a,
0xf9,
0x8e,
0xd6,
0x40,
0x4d,
0xbb,
0xbe,
0xc4,
0xe5,
0x07,
0xfc,
0xd9,
0x7b,
0x6d,
0xa6,
0x42,
0x57,
0x8f,
0x02,
0x94,
0x4f,
0xe4,
0x2a,
0x65,
0xe2,
0x19,
0x5a,
0x50,
0xe1,
0x25,
0x65,
0x4a,
0x60,
0xc2,
0xcd,
0xa8,
0xec,
0x05,
0x2e,
0x87,
0x7b,
0x95,
0xb7,
0x4f,
0xa0,
0x0b,
0x1b,
0x4a,
0x7f,
0x92,
0xc8,
0x90,
0xee,
0x89,
0x1e,
0x10,
0xd2,
0x85,
0xe4,
0x9f,
0x63,
0xc8,
0x12,
0xbb,
0x4e,
0xb8,
0xcf,
0x0a,
0xec,
0x18,
0x4e,
0xe6,
0x7c,
0xb3,
0x33,
0x26,
0xc7,
0x1f,
0xd2,
0x04,
0x23,
0xea,
0x07,
0x0c,
0x5f,
0x90,
0xbd,
0xa7,
0x6a,
0x0f,
0x4a,
0xd6,
0x10,
0x01,
0x3c,
0x12,
0x29,
0x2e,
0x96,
0xc0,
0x4d,
0xbb,
0xbe,
0xe5,
0xa7,
0x83,
0xd5,
0x6a,
0x3c,
0xe3,
0x5b,
0xb8,
0xf2,
0x5c,
0x6d,
0x1f,
0xa6,
0xf3,
0x12,
0x24,
0xf6,
0xd6,
0x3b,
0x10,
0x14,
0x09,
0x07,
0x82,
0xe8,
0x30,
0x6a,
0x99,
0xdc,
0x95,
0x01,
0x9c,
0xd4,
0x68,
0x3b,
0xca,
0x98,
0x12,
0xab,
0x77,
0x25,
0x15,
0x7d,
0x10,
0x32,
0x45,
0x98,
0xcd,
0x7a,
0xdf,
0x71,
0x8a,
0x75,
0xc1,
0x1c,
0xd4,
0x68,
0x25,
0xeb,
0xbb,
0x54,
0x27,
0x6f,
0x2a,
0xf7,
0xb9,
0x98,
0x03,
0x27,
0xde,
0x24,
0xa8,
0xbb,
0x98,
0xc2,
0x84,
0xff,
0x9b,
0x51,
0xd8,
0x53,
0x50,
0xda,
0xf5,
0x88,
0xaa,
0x87,
0x2f,
0xae,
0xd6,
0xea,
0x6b,
0xde,
0xc8,
0xd7,
0xa7,
0x28,
0x65,
0x81,
0xe8,
0xb2,
0x3b,
0x1d,
0x4f,
0x75,
0x8f,
0x9f,
0x7a,
0x74,
0x8e,
0xc1,
0x5f,
0x9a,
0xa8,
0x9d,
0xfa,
0x03,
0xa3,
0x71,
0x9b,
0x37,
0x6d,
0xd5,
0x0b,
0xf5,
0xe1,
0xa1,
0x1b,
0x01,
0x6a,
0xc6,
0x67,
0xaa,
0xea,
0x2c,
0x9d,
0xa4,
0xd2,
0x6e,
0xfc,
0xde,
0x2e,
0x7f,
0x94,
0x69,
0xe5,
0x4a,
0xe0,
0x01,
0x48,
0x3c,
0x6b,
0xf7,
0x1e,
0xb6,
0x0b,
0x5f,
0xf9,
0x2e,
0x07,
0xc5,
0xe8,
0xae,
0x37,
0x1b,
0xbc,
0x3c,
0xd8,
0xd5,
0x0b,
0x91,
0x9e,
0x80,
0x24,
0xf5,
0x06,
0x0c,
0x0e,
0x98,
0x07,
0x96,
0x2d,
0x19,
0xdc,
0x58,
0x93,
0xcc,
0xfb,
0x4e,
0xeb,
0xbd,
0x0f,
0xf5,
0xaf,
0x01,
0xfa,
0xf1,
0x7c,
0x43,
0x8c,
0xb8,
0x56,
0x3e,
0xbe,
0x77,
0x4e,
0x2b,
0xf7,
0xbb,
0xb7,
0x45,
0x47,
0xcd,
0xcc,
0xa6,
0x4c,
0x72,
0x7b,
0x6a,
0x2a,
0x70,
0x13,
0x07,
0xfd,
0xb8,
0x9c,
0x98,
0x3a,
0xd8,
0x23,
0x67,
0x5b,
0x34,
0xd5,
0x14,
0x0c,
0xab,
0x77,
0x1f,
0xf8,
0x3d,
0x5a,
0x9f,
0x92,
0xb7,
0x2c,
0xad,
0x31,
0xde,
0x61,
0x07,
0xb3,
0x6b,
0xf7,
0x38,
0x15,
0x95,
0x46,
0x14,
0x48,
0x53,
0x69,
0x52,
0x66,
0x07,
0x6d,
0x83,
0x71,
0x8a,
0x67,
0x25,
0x20,
0x0f,
0xfe,
0xd7,
0x02,
0xd7,
0x6e,
0x2c,
0xd2,
0x1a,
0x0a,
0x5d,
0xfd,
0x0f,
0x74,
0xe3,
0xa4,
0x36,
0x07,
0x9a,
0xdf,
0xd4,
0x79,
0xbf,
0xef,
0x59,
0xc0,
0x44,
0x52,
0x87,
0x9a,
0x6e,
0x1d,
0x0e,
0xee,
0xde,
0x2e,
0x1a,
0xa9,
0x8f,
0x3a,
0xc9,
0xba,
0xec,
0x99,
0x78,
0x2d,
0x55,
0x6b,
0x14,
0xc2,
0x06,
0xd5,
0xfc,
0x93,
0x53,
0x4d,
0x11,
0x8c,
0xf8,
0xfa,
0x79,
0x7c,
0xa6,
0x64,
0xae,
0x61,
0xb8,
0x7b,
0x94,
0x56,
0xa6,
0x39,
0x78,
0x9a,
0xe5,
0xc7,
0xdf,
0x18,
0x63,
0x23,
0x9c,
0xfa,
0x66,
0xbb,
0xb7,
0x5a,
0x27,
0x4c,
0xd1,
0xa1,
0x83,
0x22,
0xb3,
0x52,
0x49,
0x35,
0xb0,
0x22,
0x83,
0x59,
0x12,
0x00,
0x16,
0x98,
0xdd,
0xad,
0xc2,
0x94,
0xf9,
0xd3,
0x7b,
0x64,
0x7f,
0x44,
0x3e,
0x3c,
0x8b,
0x9a,
0x83,
0x9c,
0x69,
0x6b,
0xe4,
0xdf,
0x9f,
0xed,
0x54,
0x1f,
0xe5,
0x5d,
0x7a,
0x05,
0x82,
0xb3,
0xdd,
0xef,
0xfc,
0x53,
0x96,
0xb0,
0x2c,
0x5a,
0xf8,
0xdf,
0x9c,
0x8b,
0x16,
0x4e,
0xdf,
0xda,
0x4d,
0x09,
0x09,
0x69,
0x50,
0x03,
0x65,
0xd8,
0x73,
0x70,
0xe8,
0x86,
0xbf,
0xbb,
0x35,
0xce,
0xb2,
0x46,
0xcb,
0x02,
0x00,
0x5b,
0xb4,
0xe2,
0xc6,
0x8f,
0x2f,
0x98,
0xaf,
0x87,
0x4b,
0x48,
0x45,
0xed,
0xcc,
0x1d,
0xe6,
0x58,
0xd6,
0xf2,
0x50,
0x25,
0x9f,
0x52,
0xc7,
0xcb,
0x8a,
0x17,
0x9d,
0x5b,
0xe5,
0xc8,
0xd7,
0x72,
0xb7,
0x52,
0xb2,
0xc4,
0x98,
0xe3,
0x7a,
0x17,
0x3e,
0xc6,
0x60,
0xa7,
0x97,
0xb0,
0xcf,
0x18,
0x81,
0x53,
0x84,
0x4c,
0xd5,
0x17,
0x32,
0x03,
0x13,
0x39,
0x51,
0x09,
0x10,
0xe3,
0x77,
0x49,
0x4f,
0x62,
0x01,
0xbf,
0x8c,
0x9a,
0xe0,
0x41,
0x9e,
0x89,
0x74,
0x36,
0xf9,
0x96,
0x86,
0x2e,
0x96,
0x1c,
0x4a,
0xb7,
0x2b,
0x4a,
0x97,
0xbc,
0x99,
0x40,
0xa3,
0xe0,
0x3d,
0xc8,
0xad,
0x2f,
0xdf,
0x4f,
0x2c,
0xc4,
0x69,
0x82,
0x9f,
0x9b,
0x81,
0x0c,
0x61,
0x5c,
0xa5,
0x9d,
0x8c,
0x89,
0xc0,
0x2c,
0xb4,
0x4a,
0x33,
0x4e,
0xeb,
0xa2,
0x56,
0x40,
0xc0,
0xc2,
0x46,
0xaf,
0x6a,
0xfc,
0x67,
0xd1,
0x80,
0x5e,
0xc5,
0x6d,
0x84,
0x43,
0x27,
0x3f,
0x55,
0x15,
0x96,
0x6a,
0xa0,
0xa5,
0xda,
0xb7,
0xff,
0xb7,
0x75,
0x6e,
0x4c,
0x49,
0x91,
0x9d,
0x22,
0xa3,
0x46,
0xea,
0xed,
0x9a,
0x00,
0xe2,
0x32,
0xc3,
0xd6,
0xa9,
0x71,
0x20,
0x55,
0xa3,
0x19,
0xed,
0xf8,
0x4f,
0xa7,
0x12,
0x9c,
0x66,
0x87,
0xaf,
0x4e,
0xb7,
0xf0,
0xdb,
0xbf,
0xef,
0xf0,
0xf6,
0xaf,
0xea,
0xda,
0x09,
0xfe,
0xde,
0x38,
0x5c,
0xa5,
0xa2,
0xdf,
0x99,
0x45,
0xa8,
0xe4,
0xe7,
0x92,
0xac,
0x67,
0xaa,
0x4f,
0xbf,
0x77,
0x3e,
0xa2,
0x40,
0x49,
0x22,
0x4a,
0x1e,
0x3b,
0xaa,
0x70,
0x7f,
0x95,
0xaf,
0x37,
0x4b,
0xfc,
0x99,
0xe2,
0xe0,
0xba,
0xd7,
0x34,
0xce,
0x55,
0x88,
0x5b,
0x84,
0x1b,
0x57,
0xc4,
0x80,
0x03,
0x53,
0xc9,
0x2f,
0x93,
0x04,
0x4d,
0xd5,
0x96,
0xe5,
0x70,
0xa6,
0x6e,
0x63,
0x5d,
0x9d,
0x6c,
0xdb,
0x02,
0x0a,
0xa9,
0xda,
0x8b,
0x53,
0xdc,
0xd9,
0x9a,
0xc5,
0x94,
0x2c,
0x91,
0x92,
0x2a,
0xde,
0xbb,
0x8b,
0x13,
0xb9,
0x19,
0x96,
0x64,
0xcc,
0xf2,
0x64,
0x39,
0xb7,
0x75,
0x49,
0xe9,
0x86,
0xc2,
0x86,
0x62,
0xd9,
0x24,
0xd3,
0x81,
0x35,
0x49,
0xfc,
0xa0,
0xa5,
0xa0,
0x93,
0x05,
0x64,
0xb4,
0x1a,
0x57,
0xce,
0x0c,
0x90,
0x02,
0x27,
0xc5,
0x7a,
0x2b,
0x5d,
0xae,
0x3e,
0xd5,
0xdd,
0x10,
0x7c,
0x14,
0xea,
0x3a,
0x08,
0xac,
0x72,
0x4e,
0x90,
0x3d,
0x3b,
0x7c,
0x86,
0x2e,
0xeb,
0xd4,
0x06,
0x70,
0xe6,
0xc7,
0xfb,
0x5f,
0xbd,
0x18,
0xf4,
0x11,
0xa4,
0x1a,
0x93,
0xc3,
0xbe,
0xd9,
0xfb,
0x26,
0x48,
0x2f,
0x37,
0x3c,
0xd0,
0x03,
0x47,
0x1a,
0xf7,
0x62,
0x19,
0x24,
0x5c,
0xf4,
0xa8,
0x92,
0x20,
0x7a,
0xf2,
0x9e,
0x2a,
0xc5,
0x95,
0xa2,
0xfb,
0xa4,
0xea,
0x85,
0xd8,
0x56,
0xb7,
0x70,
0xd1,
0x60,
0x30,
0xa5,
0x30,
0x82,
0x70,
0xdc,
0x7a,
0x65,
0x8a,
0x36,
0x3f,
0x5b,
0x0c,
0xae,
0x54,
0x7c,
0xd3,
0x57,
0x84,
0x7b,
0x3a,
0x65,
0x18,
0x81,
0xee,
0x05,
0x9b,
0x44,
0x4d,
0xb8,
0xda,
0xa2,
0xa1,
0xc9,
0x15,
0xd3,
0x73,
0x03,
0x0e,
0x43,
0xe9,
0x8e,
0x15,
0xf9,
0xbe,
0xc6,
0xc5,
0x8a,
0xe5,
0xc0,
0x1e,
0xc2,
0x37,
0x9e,
0x2a,
0x26,
0xa5,
0xa0,
0xbd,
0x24,
0x5f,
0xb9,
0xc1,
0xab,
0x34,
0x48,
0xb9,
0x5d,
0x98,
0xb4,
0x65,
0x18,
0xf3,
0x63,
0x19,
0x44,
0x1b,
0x11,
0x16,
0xff,
0xdc,
0xf1,
0x79,
0x08,
0x86,
0x0f,
0x52,
0x98,
0x73,
0xc4,
0x92,
0x90,
0x2b,
0x47,
0x09,
0xd0,
0x43,
0x6c,
0x2f,
0x20,
0xeb,
0xdc,
0xda,
0xc5,
0x08,
0x7b,
0x94,
0x42,
0x30,
0x6a,
0xc7,
0xda,
0x8c,
0xc3,
0x76,
0xa7,
0xa5,
0xcc,
0x62,
0x13,
0x00,
0x60,
0x31,
0x58,
0x44,
0x9b,
0xf5,
0x64,
0x14,
0xf5,
0x11,
0xc5,
0x54,
0x52,
0x83,
0xd4,
0x73,
0x01,
0x16,
0x0e,
0xb3,
0x7a,
0x29,
0x69,
0x35,
0x56,
0xd4,
0xee,
0x8a,
0x17,
0xa2,
0x99,
0x24,
0x9c,
0xd7,
0x8f,
0xdb,
0x55,
0xb5,
0x3e
};

A keyboards/molecule/config.h => keyboards/molecule/config.h +159 -0
@@ 0,0 1,159 @@
/*
Copyright 2021 bbrfkr

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

#include "config_common.h"

/* USB Device descriptor parameter */
#define VENDOR_ID    0xFEED
#define PRODUCT_ID   0x0000
#define DEVICE_VER   0x0001
#define MANUFACTURER bbrfkr
#define PRODUCT      molecule

/* key matrix size */
#define MATRIX_ROWS 4
#define MATRIX_COLS 10

/*
 * Keyboard Matrix Assignments
 *
 * Change this to how you wired your keyboard
 * COLS: AVR pins used for columns, left to right
 * ROWS: AVR pins used for rows, top to bottom
 * DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
 *                  ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
 *
 */
#define MATRIX_ROW_PINS { F4, F5, F6, B6 }
#define MATRIX_COL_PINS { D3, D2, D1, D0, D4, C6, D7, E6, B4, B5 }
#define UNUSED_PINS

/* COL2ROW, ROW2COL */
#define DIODE_DIRECTION ROW2COL

/*
 * Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk, and define SOFT_SERIAL_PIN.
 */
// #define SOFT_SERIAL_PIN D2  // or D1, D2, D3, E6
// #define USE_SERIAL

//#define BACKLIGHT_PIN B7
//#define BACKLIGHT_LEVELS 3
//#define BACKLIGHT_BREATHING

/* underglow LED */
// #define RGB_DI_PIN D3
// #ifdef RGBLIGHT_ENABLE
// #   define RGBLED_NUM 10
// #   define RGBLED_SPLIT { 5, 5 }
// #   define RGBLIGHT_ANIMATIONS
// #endif

//#define RGB_DI_PIN E2
//#ifdef RGB_DI_PIN
//#    define RGBLED_NUM 16
//#    define RGBLIGHT_HUE_STEP 8
//#    define RGBLIGHT_SAT_STEP 8
//#    define RGBLIGHT_VAL_STEP 8
//#    define RGBLIGHT_LIMIT_VAL 255 /* The maximum brightness level */
//#    define RGBLIGHT_SLEEP  /* If defined, the RGB lighting will be switched off when the host goes to sleep */
/*== all animations enable ==*/
//#    define RGBLIGHT_ANIMATIONS
/*== or choose animations ==*/
//#    define RGBLIGHT_EFFECT_BREATHING
//#    define RGBLIGHT_EFFECT_RAINBOW_MOOD
//#    define RGBLIGHT_EFFECT_RAINBOW_SWIRL
//#    define RGBLIGHT_EFFECT_SNAKE
//#    define RGBLIGHT_EFFECT_KNIGHT
//#    define RGBLIGHT_EFFECT_CHRISTMAS
//#    define RGBLIGHT_EFFECT_STATIC_GRADIENT
//#    define RGBLIGHT_EFFECT_RGB_TEST
//#    define RGBLIGHT_EFFECT_ALTERNATING
/*== customize breathing effect ==*/
/*==== (DEFAULT) use fixed table instead of exp() and sin() ====*/
//#    define RGBLIGHT_BREATHE_TABLE_SIZE 256      // 256(default) or 128 or 64
/*==== use exp() and sin() ====*/
//#    define RGBLIGHT_EFFECT_BREATHE_CENTER 1.85  // 1 to 2.7
//#    define RGBLIGHT_EFFECT_BREATHE_MAX    255   // 0 to 255
//#endif


/* OLED */
#define OLED_TIMEOUT 0

/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
#define DEBOUNCE 5

/* define if matrix has ghost (lacks anti-ghosting diodes) */
//#define MATRIX_HAS_GHOST

/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
#define LOCKING_SUPPORT_ENABLE
/* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE

/* If defined, GRAVE_ESC will always act as ESC when CTRL is held.
 * This is useful for the Windows task manager shortcut (ctrl+shift+esc).
 */
//#define GRAVE_ESC_CTRL_OVERRIDE

/*
 * Force NKRO
 *
 * Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved
 * state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the
 * makefile for this to work.)
 *
 * If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N)
 * until the next keyboard reset.
 *
 * NKRO may prevent your keystrokes from being detected in the BIOS, but it is
 * fully operational during normal computer usage.
 *
 * For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N)
 * or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by
 * bootmagic, NKRO mode will always be enabled until it is toggled again during a
 * power-up.
 *
 */
//#define FORCE_NKRO

/*
 * Feature disable options
 *  These options are also useful to firmware size reduction.
 */

/* disable debug print */
//#define NO_DEBUG

/* disable print */
//#define NO_PRINT

/* disable action features */
//#define NO_ACTION_LAYER
//#define NO_ACTION_TAPPING
//#define NO_ACTION_ONESHOT

/* disable these deprecated features by default */
#define NO_ACTION_MACRO
#define NO_ACTION_FUNCTION

/* Bootmagic Lite key configuration */
//#define BOOTMAGIC_LITE_ROW 0
//#define BOOTMAGIC_LITE_COLUMN 0

A keyboards/molecule/info.json => keyboards/molecule/info.json +215 -0
@@ 0,0 1,215 @@
{
    "keyboard_name": "molecule",
    "url": "https://github.com/bbrfkr/keyboards/tree/master/molecule",
    "maintainer": "bbrfkr",
    "width": 14.75, 
    "height": 5, 
    "layouts": {
        "LAYOUT": {
            "layout": [
                {
                   "label":"E",
                   "x":2,
                   "y":0
                },
                {
                   "label":"I",
                   "x":11.75,
                   "y":0
                },
                {
                   "label":"W",
                   "x":1,
                   "y":0.25
                },
                {
                   "label":"O",
                   "x":12.75,
                   "y":0.25
                },
                {
                   "label":"R",
                   "x":3,
                   "y":0.5
                },
                {
                   "label":"U",
                   "x":10.75,
                   "y":0.5
                },
                {
                   "label":"T",
                   "x":4,
                   "y":0.75
                },
                {
                   "label":"Y",
                   "x":9.75,
                   "y":0.75
                },
                {
                   "label":"Q",
                   "x":0,
                   "y":1
                },
                {
                   "label":"D",
                   "x":2,
                   "y":1
                },
                {
                   "label":"K",
                   "x":11.75,
                   "y":1
                },
                {
                   "label":"P",
                   "x":13.75,
                   "y":1
                },
                {
                   "label":"S",
                   "x":1,
                   "y":1.25
                },
                {
                   "label":"L",
                   "x":12.75,
                   "y":1.25
                },
                {
                   "label":"F",
                   "x":3,
                   "y":1.5
                },
                {
                   "label":"J",
                   "x":10.75,
                   "y":1.5
                },
                {
                   "label":"G",
                   "x":4,
                   "y":1.75
                },
                {
                   "label":"H",
                   "x":9.75,
                   "y":1.75
                },
                {
                   "label":"A",
                   "x":0,
                   "y":2
                },
                {
                   "label":"C",
                   "x":2,
                   "y":2
                },
                {
                   "label":",",
                   "x":11.75,
                   "y":2
                },
                {
                   "label":";",
                   "x":13.75,
                   "y":2
                },
                {
                   "label":"X",
                   "x":1,
                   "y":2.25
                },
                {
                   "label":".",
                   "x":12.75,
                   "y":2.25
                },
                {
                   "label":"V",
                   "x":3,
                   "y":2.5
                },
                {
                   "label":"M",
                   "x":10.75,
                   "y":2.5
                },
                {
                   "label":"B",
                   "x":4,
                   "y":2.75
                },
                {
                   "label":"N",
                   "x":9.75,
                   "y":2.75
                },
                {
                   "label":"Z",
                   "x":0,
                   "y":3
                },
                {
                   "label":"Shift",
                   "x":2,
                   "y":3
                },
                {
                   "label":"Alt",
                   "x":5.25,
                   "y":3
                },
                {
                   "label":"Super",
                   "x":8.5,
                   "y":3
                },
                {
                   "label":"Shift",
                   "x":11.75,
                   "y":3
                },
                {
                   "label":"/",
                   "x":13.75,
                   "y":3
                },
                {
                   "label":"Ctrl",
                   "x":1,
                   "y":3.25
                },
                {
                   "label":"Space",
                   "x":6.25,
                   "y":3.25,
                   "h":1.5
                },
                {
                   "label":"Enter",
                   "x":7.5,
                   "y":3.25,
                   "h":1.5
                },
                {
                   "label":"Ctrl",
                   "x":12.75,
                   "y":3.25
                },
                {
                   "label":"Lower",
                   "x":5.25,
                   "y":4
                },
                {
                   "label":"Raise",
                   "x":8.5,
                   "y":4
                }
            ]
        }
    }
}
\ No newline at end of file

A keyboards/molecule/keymaps/default/keymap.c => keyboards/molecule/keymaps/default/keymap.c +39 -0
@@ 0,0 1,39 @@
/* Copyright 2021 bbrfkr
 *
 * 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 QMK_KEYBOARD_H

// Defines names for use in layer keycodes and the keymap
enum layer_names {
    _QWERTY_BASE,
	_EUCALYN_BASE,
    _LOWER,
    _RAISE,
    _FN,
};

// Defines the keycodes used by our macros in process_record_user
enum custom_keycodes {
    QMKBEST = SAFE_RANGE,
    QMKURL
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
        [_QWERTY_BASE] = LAYOUT(KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_LCTL, KC_LSFT, MO(2), KC_LALT, KC_SPC, KC_ENT, KC_RGUI, MO(3), KC_RSFT, KC_RCTL),
        [_EUCALYN_BASE] = LAYOUT(KC_Q, KC_W, KC_COMM, KC_DOT, KC_SCLN, KC_M, KC_R, KC_D, KC_Y, KC_P, KC_A, KC_O, KC_E, KC_I, KC_U, KC_G, KC_T, KC_K, KC_S, KC_N, KC_Z, KC_X, KC_C, KC_V, KC_F, KC_B, KC_H, KC_J, KC_L, KC_SLSH, KC_LCTL, KC_LSFT, MO(2), KC_LALT, KC_SPC, KC_ENT, KC_RGUI, MO(3), KC_RSFT, KC_RCTL),
        [_LOWER] = LAYOUT(KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_F2, KC_F3, KC_WH_U, KC_F4, KC_F5, KC_F6, KC_F7, KC_UP, KC_F8, KC_F9, KC_F1, KC_MS_BTN2, KC_WH_D, KC_MS_BTN1, KC_F11, KC_F12, KC_LEFT, KC_DOWN, KC_RGHT, KC_F10, KC_LCTL, KC_LSFT, KC_TRNS, KC_LALT, KC_SPC, KC_ENT, KC_RGUI, MO(4),  KC_RSFT, KC_RCTL),
        [_RAISE] = LAYOUT(KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_ESC, KC_DEL, KC_BSPC, KC_GRV, KC_BSLS, KC_MINS, KC_EQL, KC_QUOT, KC_LCBR, KC_RCBR, KC_CAPS, KC_TAB, KC_PSCR, KC_TILD, KC_PIPE, KC_UNDS, KC_PLUS, KC_DQUO, KC_LBRC, KC_RBRC, KC_LCTL, KC_LSFT, MO(4), KC_LALT, KC_SPC, KC_ENT, KC_RGUI, KC_TRNS, KC_RSFT, KC_RCTL),
		[_FN] = LAYOUT(KC_VOLU, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_BRIU, KC_VOLD, KC_NO, KC_NO, KC_NO, DF(0), DF(1), KC_NO, KC_NO, KC_NO, KC_BRID, KC_MUTE, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_LCTL, KC_LSFT, KC_TRNS, KC_LALT, KC_SPC, KC_ENT, KC_RGUI, KC_TRNS, KC_RSFT, KC_RCTL)
};

A keyboards/molecule/keymaps/default/readme.md => keyboards/molecule/keymaps/default/readme.md +1 -0
@@ 0,0 1,1 @@
# The default keymap for molecule

A keyboards/molecule/molecule.c => keyboards/molecule/molecule.c +17 -0
@@ 0,0 1,17 @@
/* Copyright 2021 bbrfkr
 *
 * 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 "molecule.h"

A keyboards/molecule/molecule.h => keyboards/molecule/molecule.h +40 -0
@@ 0,0 1,40 @@
/* Copyright 2021 bbrfkr
 *
 * 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

#include "quantum.h"

/* This is a shortcut to help you visually see your layout.
 *
 * The first section contains all of the arguments representing the physical
 * layout of the board and position of the keys.
 *
 * The second converts the arguments into a two-dimensional array which
 * represents the switch matrix.
 */
#define LAYOUT( \
  L00, L01, L02, L03, L04,      R00, R01, R02, R03, R04, \
  L10, L11, L12, L13, L14,      R10, R11, R12, R13, R14, \
  L20, L21, L22, L23, L24,      R20, R21, R22, R23, R24, \
  L30, L31, L32, L33, L34,      R30, R31, R32, R33, R34  \
  ) \
  { \
    { L00, L01, L02, L03, L04, R00, R01, R02, R03, R04 }, \
    { L10, L11, L12, L13, L14, R10, R11, R12, R13, R14 }, \
    { L20, L21, L22, L23, L24, R20, R21, R22, R23, R24 }, \
    { L30, L31, L32, L33, L34, R30, R31, R32, R33, R34 }, \
  }

A keyboards/molecule/readme.md => keyboards/molecule/readme.md +21 -0
@@ 0,0 1,21 @@
# molecule

[![molecule](https://imgur.com/uYCeS4Y)](https://i.imgur.com/uYCeS4Yh.jpg)

A 40 keys keyboard with trackball.

* Keyboard Maintainer: [bbrfkr](https://github.com/bbrfkr) [@bbrfkr](https://twitter.com/bbrfkr)
* Hardware Supported: molecule PCB, Pro Micro
* Hardware Availability: https://bbrfkr.booth.pm/

Make example for this keyboard (after setting up your build environment):

    make molecule:default

Flashing example for this keyboard:

    make molecule:default:flash

See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).

This keyboard project includes [aball](https://github.com/brickbots/aball) project source code partially. 

A keyboards/molecule/rules.mk => keyboards/molecule/rules.mk +27 -0
@@ 0,0 1,27 @@
# MCU name
MCU = atmega32u4

# Bootloader selection
BOOTLOADER = atmel-dfu

# Build Options
#   change yes to no to disable
#
BOOTMAGIC_ENABLE = lite     # Virtual DIP switch configuration
MOUSEKEY_ENABLE = yes       # Mouse keys
EXTRAKEY_ENABLE = yes       # Audio control and System control
CONSOLE_ENABLE = no         # Console for debug
COMMAND_ENABLE = no         # Commands for debug and configuration
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
SLEEP_LED_ENABLE = no       # Breathing sleep LED during USB suspend
# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
NKRO_ENABLE = no            # USB Nkey Rollover
BACKLIGHT_ENABLE = no       # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no     # Enable keyboard RGB underglow
BLUETOOTH_ENABLE = no       # Enable Bluetooth
AUDIO_ENABLE = no           # Audio output

# Add trackball support
POINTING_DEVICE_ENABLE = yes
SRC += adns.c
QUANTUM_LIB_SRC += spi_master.c