Add files via upload

This commit is contained in:
rehius 2023-05-18 09:35:07 +00:00 committed by GitHub
parent bf58145e8e
commit c8f629a95f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 5133 additions and 0 deletions

45
CMakeLists.txt Normal file
View file

@ -0,0 +1,45 @@
# Generated Cmake Pico project file
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_BUILD_TYPE MinSizeRel)
# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)
project(usk C CXX ASM)
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Add executable. Default name is the project name, version 0.1
add_executable(usk main.c board_detect.c fuses.c pio_upload.c boot_detect.c config.c misc.c payload.c glitch.c)
target_compile_definitions(usk PRIVATE PICO_NO_BINARY_INFO)
pico_generate_pio_header(usk ${CMAKE_CURRENT_LIST_DIR}/ws2812.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}/generated)
pico_generate_pio_header(usk ${CMAKE_CURRENT_LIST_DIR}/emmc.pio OUTPUT_DIR ${CMAKE_CURRENT_LIST_DIR}/generated)
pico_set_program_name(usk "usk")
pico_set_program_version(usk "2.7")
pico_set_binary_type(usk no_flash)
pico_enable_stdio_uart(usk 0)
pico_enable_stdio_usb(usk 0)
# Add the standard library to the build
target_link_libraries(usk pico_stdlib)
# Add any user requested libraries
target_link_libraries(usk
hardware_pio
hardware_adc
hardware_flash
)
pico_add_extra_outputs(usk)

162
board_detect.c Normal file
View file

@ -0,0 +1,162 @@
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"
#include "pins.h"
#include "ws2812.pio.h"
#include "misc.h"
#include "board_detect.h"
extern int ws_pio_offset;
enum board_type {
BOARD_WS = 0,
BOARD_XO,
BOARD_IB,
BOARD_PI,
BOARD_SQ
};
enum board_type cur_board = BOARD_WS;
bool detect_by_pull_up(int frc_pin, int det_pin)
{
bool result = false;
if (frc_pin >= 0)
gpio_init(frc_pin);
gpio_init(det_pin);
if (frc_pin >= 0)
gpio_set_dir(frc_pin, true);
gpio_pull_up(det_pin);
sleep_us(15);
result = !gpio_get(det_pin);
gpio_deinit(det_pin);
if (frc_pin >= 0)
gpio_deinit(frc_pin);
gpio_disable_pulls(det_pin);
return result;
}
bool test_xiao()
{
return detect_by_pull_up(1, 2);
}
bool test_itsy()
{
return detect_by_pull_up(3, 2);
}
bool test_pico()
{
return detect_by_pull_up(-1, 22);
}
bool test_ws()
{
return detect_by_pull_up(-1, 25);
}
bool test_sqc()
{
return detect_by_pull_up(-1, 17);
}
void detect_board()
{
gpio_pull_down(PIN_GLI_WS);
gpio_pull_down(PIN_GLI_PICO);
gpio_pull_down(PIN_GLI_XIAO);
gpio_pull_down(PIN_GLI_ITSY);
gpio_disable_input_output(PIN_RST);
if (test_ws()) {
cur_board = BOARD_WS;
} else if (test_xiao()) {
cur_board = BOARD_XO;
} else if (test_itsy()) {
cur_board = BOARD_IB;
} else if (test_pico()) {
cur_board = BOARD_PI;
} else if (test_sqc()) {
cur_board = BOARD_SQ;
} else {
cur_board = BOARD_WS;
}
}
int led_pin()
{
switch(cur_board){
case BOARD_XO:
return PIN_LED_XIAO;
case BOARD_PI:
return PIN_LED_PICO;
case BOARD_IB:
return PIN_LED_ITSY;
default:
return PIN_LED_WS;
};
}
int pwr_pin()
{
switch(cur_board){
case BOARD_XO:
return PIN_LED_PWR_XIAO;
case BOARD_IB:
return PIN_LED_PWR_ITSY;
default:
return 31;
};
}
int scl_pin()
{
switch(cur_board){
case BOARD_XO:
return PIN_SCL_XIAO;
case BOARD_IB:
return PIN_SCL_ITSY;
case BOARD_PI:
return PIN_SCL_PICO;
case BOARD_SQ:
return PIN_SCL_SQC;
default:
return PIN_SCL_WS;
};
}
int sda_pin()
{
switch(cur_board){
case BOARD_XO:
return PIN_SDA_XIAO;
case BOARD_IB:
return PIN_SDA_ITSY;
case BOARD_PI:
return PIN_SDA_PICO;
case BOARD_SQ:
return PIN_SDA_SQC;
default:
return PIN_SDA_WS;
};
}
int gli_pin()
{
switch(cur_board){
case BOARD_XO:
return PIN_GLI_XIAO;
case BOARD_IB:
return PIN_GLI_ITSY;
case BOARD_PI:
return PIN_GLI_PICO;
default:
return PIN_GLI_WS;
};
}
bool is_pico()
{
return cur_board == BOARD_PI;
}

11
board_detect.h Normal file
View file

@ -0,0 +1,11 @@
#include "stdbool.h"
bool detect_by_pull_up(int frc_pin, int det_pin);
void detect_board();
int gli_pin();
int pwr_pin();
int led_pin();
bool is_pico();
int scl_pin();
int sda_pin();

70
boot_detect.c Normal file
View file

@ -0,0 +1,70 @@
#include "hardware/clocks.h"
#include "hardware/gpio.h"
#include "hardware/pio.h"
#include "pins.h"
#include "pico/stdlib.h"
#include "glitch.h"
#include "misc.h"
#include "fuses.h"
bool mariko = true;
bool board_detected = false;
bool wait_for_boot(int timeout_ms) {
absolute_time_t tio_full = make_timeout_time_ms(timeout_ms);
absolute_time_t tio_cmd1 = tio_full;
init_glitch_pio();
reset_cpu();
uint32_t word=0, last_word=0;
bool was_read_zero = false;
bool was_cmd1 = false;
int reset_attempts = 0;
while(!time_reached(tio_full)) {
if (time_reached(tio_cmd1))
{
if (reset_attempts > 4)
{
halt_with_error(0, 3);
}
reset_attempts++;
reset_cpu();
tio_cmd1 = tio_full;
}
if(!pio_sm_is_rx_fifo_empty(pio1, 0))
{
word = pio_sm_get(pio1, 0);
if (last_word == 0x41000000 && word == 0x00F9) // cmd1 request
{
tio_cmd1 = make_timeout_time_ms(20);
was_cmd1 = true;
}
else if (last_word == 0x00F9 && (word >> 24) == 0x3F) // cmd1 responce
{
tio_cmd1 = tio_full;
}
else if (last_word == 0x51000000 && word == 0x0055) //read block 0
{
tio_full = make_timeout_time_ms(100);
was_read_zero = true;
} else if (was_read_zero && last_word == 0x4D000200 && word == 0x00B1) // read status - erista only
{
mariko = false;
} else if (last_word == 0x51000000 && word == 0x0147) // read block 1, can finish now
{
deinit_glitch_pio();
return true;
}
last_word = word;
}
}
if (was_read_zero) {
halt_with_error(1, 3);
}
else if (was_cmd1) {
halt_with_error(2, 3);
} else {
halt_with_error(3, 3);
}
return false;
}

4
boot_detect.h Normal file
View file

@ -0,0 +1,4 @@
bool wait_for_boot(int timeout_ms);
// type of NS is detected in wait_for_boot
extern bool mariko;

133
config.c Normal file
View file

@ -0,0 +1,133 @@
#include "pico/stdlib.h"
#include "config.h"
#include "fuses.h"
#include <stdio.h>
#include <string.h>
typedef struct usk_cfg {
uint8_t cid[16];
uint8_t sign;
uint8_t version_hi;
uint8_t version_lo;
uint8_t lock;
uint16_t pcrc;
} usk_cfg;
#define VER_SIGN sizeof(usk_cfg)
uint16_t payload_crc();
#define typed_cfg ((const usk_cfg *)flash_cfg)
bool is_inited() {
return typed_cfg->sign == VER_SIGN
&& typed_cfg->version_hi == VER_HI
&& typed_cfg->version_lo == VER_LO
&& payload_crc() == typed_cfg->pcrc;
}
bool is_configured(uint8_t * cid) {
bool cid_ok = memcmp(typed_cfg->cid, cid, 16) == 0;
bool init_ok = is_inited();
return cid_ok && init_ok;
}
bool check_blank_config(int start, int size) {
for(int i = start; i < start + size; i+= 4) {
uint32_t val = *(volatile uint32_t*)(flash_cfg + i);
if (val != 0xFFFFFFFF)
return false;
}
return true;
}
void erase_config() {
for (int i = 0; i < CONFIG_SIZE; i += 0x1000) {
if (!check_blank_config(i, 0x1000)) {
flash_range_erase(CONFIG_START + i, 0x1000);
}
}
}
bool is_locked() {
return typed_cfg->lock != 0xFF;
}
void lock_config() {
if (is_locked())
return;
uint8_t buf[256];
usk_cfg * cfg = (usk_cfg *)buf;
memcpy(buf, flash_cfg, 256);
cfg->lock = 0;
flash_range_program(CONFIG_START, buf, 256);
}
extern int boot_slot;
void init_config(uint8_t * cid) {
erase_config();
uint8_t buf[256];
memset(buf, 0xFF, 256);
usk_cfg * cfg = (usk_cfg *)buf;
memcpy(cfg->cid, cid, 16);
cfg->sign = VER_SIGN;
cfg->version_hi = VER_HI;
cfg->version_lo = VER_LO;
cfg->pcrc = payload_crc();
flash_range_program(CONFIG_START, buf, 256);
}
void add_boot_record(int offset) {
if (is_locked()) {
return;
}
uint32_t buf[64];
memcpy(buf, flash_cfg + CONFIG_IDX(offset) * 256, 256);
for (int i = 0; i < 64; i++) {
if (buf[i] != 0) {
int tz = __builtin_ctz(buf[i]);
buf[i] &= ~(1 << tz);
flash_range_program(CONFIG_START + CONFIG_IDX(offset) * 256, (uint8_t*)buf, 256);
return;
}
}
lock_config();
}
int get_weigth(int offset) {
int weight = 0;
uint32_t * buf = (uint32_t*) (flash_cfg + CONFIG_IDX(offset) * 256);
for (int i = 0; i < 64; i++) {
if(buf[i] == 0)
weight += 32;
else {
weight += __builtin_ctz(buf[i]);
break;
}
}
return weight;
}
int find_best_record(int * max_weight) {
static int last_weight = -1;
static int last_offset = 0;
int best_offset = -1;
int best_weight = 0;
for (int i = OFFSET_MIN; i < OFFSET_MAX; i += OFFSET_DIV) {
int cur_weight = get_weigth(i);
if (cur_weight > best_weight) {
if (*max_weight == -1 || cur_weight < *max_weight
|| (cur_weight == *max_weight && *max_weight == last_weight &&
last_offset < i)) {
best_offset = i;
best_weight = cur_weight;
}
}
}
if (best_offset != -1) {
*max_weight = best_weight;
}
last_weight = best_weight;
last_offset = best_offset;
return best_offset;
}

24
config.h Normal file
View file

@ -0,0 +1,24 @@
#include "hardware/flash.h"
#define OFFSET_DIV 10
#define OFFSET_MIN 6200
#define OFFSET_MAX 6900
#define VER_HI 2
#define VER_LO 71
bool is_configured();
void init_config();
bool is_inited();
void erase_config();
void add_boot_record(int offset);
int find_best_record(int * max_weight);
bool fast_check();
int get_weigth(int offset);
#define CONFIG_START 0x8000 // change to 0x100000 when compiling in "default mode"
#define CONFIG_IDX(offset) (((offset - OFFSET_MIN) / OFFSET_DIV) + 1)
#define CONFIG_CNT CONFIG_IDX(OFFSET_MAX)
#define OFFSET_CNT (CONFIG_CNT-1)
#define CONFIG_SIZE (CONFIG_CNT * 256)
#define flash_cfg ((const uint8_t *) (XIP_BASE + CONFIG_START))

87
emmc.pio Normal file
View file

@ -0,0 +1,87 @@
.program sd_clk
.side_set 1
.wrap_target
; open-drain RST switcher to keep the CPU in reset state
set pindirs, 0 side 1 ; side-set push-pull eMMC clocker (2mA limit is set to prevent damage)
irq clear 0 side 0
set pindirs, 1 side 1
irq clear 0 side 0
.wrap
.program out_cmd_or_dat
.wrap_target
out x, 16
irq wait 0 [1] ; the next cmd will go on falling edge
send_loop:
out pindirs, 1 ; use open-drain just in case, to prevent 3.3v damage
jmp x-- send_loop
irq clear 1 ; unblock the reader
out NULL, 32 ; clear the osr
.wrap
.program in_cmd_or_dat
.wrap_target
out x, 32 ;get configuration
irq wait 1 ;wait for cmd to send
irq wait 0 ;sync with clock, next cmd will go at rising edge
data_wait:
jmp pin, data_wait [1] ; sync pin wait with rising edge
read_loop:
in pins, 1 ; here we always at the rising edge
jmp x-- read_loop
push
.wrap
.program glitch_sniff_cmd
.wrap_target
next_loop:
mov x, osr ; mmc command pre-loaded bits count (48 - 1 - 1)
wait_for_start_bit:
wait 0 pin, 31
wait 1 pin, 31
jmp pin wait_for_start_bit ; wait for cmd start bit on the rising edge
wait 0 pin, 31
; waits separated by only 1 instruction, should be able to catch 50 MHz
in NULL, 1
read_loop:
wait 1 pin, 31
in pins, 1 ; command sniffer
wait 0 pin, 31
jmp x-- read_loop
irq clear 2 ; 'some cmd has passed' trigger
mov x, isr ; save the last 16 bit of command
push ; send the rest 16 bits of data
jmp x != y, next_loop ; compare the glitch pattern (0x1351, read block + crc)
irq clear 0 ; 'glitch pattern' trigger
.wrap
.program glitch_dat_waiter
.wrap_target
mov x, y ; data length pre-loaded counter (512 + 16 - 1)
wait_for_start_bit:
wait 0 pin, 30
wait 1 pin, 30
jmp pin wait_for_start_bit ; wait for dat start bit of the rising edge
wait 0 pin, 30
skip_loop_dat:
wait 1 pin, 30
;in pins, 1 ; data sniffer (not needed anymore)
wait 0 pin, 30
jmp x-- skip_loop_dat ; skip the required data ticks
irq clear 1 ; 'data transfer done' trigger
.wrap
.program glitch_trigger
.side_set 1
.wrap_target
out x, 32 side 0 ; receive wait timing
out y, 32 side 0 ; receive pulse timing
irq wait 0 side 0 ; wait for read 13
irq wait 1 side 0 ; wait for data transfer
irq wait 2 side 0 ; wait for status request (should be NOPped for Mariko)
irq wait 2 side 0 ; wait for status reply (should be NOPped for Mariko)
wait_for_timing:
jmp x--, wait_for_timing side 0
glitch_en:
jmp y--, glitch_en side 1
.wrap

47
fuses.c Normal file
View file

@ -0,0 +1,47 @@
#include "fuses.h"
#include "stdint.h"
#include "string.h"
#include "hardware/watchdog.h"
// firmware info from the bootloader & flash
int boot_slot = 0;
int boot_try = 0;
// firmware update fuse count calculator
int count_fuses()
{
int weight = 0;
uint32_t * buf = (uint32_t*)fuses;
for (int i = 0; i < 64; i++) {
if(buf[i] == 0)
weight += 32;
else {
weight += __builtin_ctz(buf[i]);
break;
}
}
return weight;
}
// firmware update fuse burner
void burn_fuse()
{
uint32_t buf[64];
memcpy(buf, fuses, 256);
for (int i = 0; i < 64; i++) {
if (buf[i] != 0) {
int tz = __builtin_ctz(buf[i]);
buf[i] &= ~(1 << tz);
flash_range_program(FUSE_OFF, (uint8_t*)buf, 256);
return;
}
}
flash_range_erase(FUSE_OFF, 0x1000);
burn_fuse(); // burn one more because both 0 and 256*8 are even
}
void init_fuses()
{
boot_slot = watchdog_hw->scratch[1];
boot_try = watchdog_hw->scratch[0];
}

12
fuses.h Normal file
View file

@ -0,0 +1,12 @@
#include "hardware/flash.h"
// firmware info from the bootloader & flash
extern int boot_slot;
extern int boot_try;
int count_fuses();
void init_fuses();
void burn_fuse();
#define FUSE_OFF 0xF000
#define fuses ((const uint8_t *) (XIP_BASE + FUSE_OFF))

214
glitch.c Normal file
View file

@ -0,0 +1,214 @@
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "emmc.pio.h"
#include "pins.h"
#include "glitch.h"
#include <stdio.h>
#include "misc.h"
#include "board_detect.h"
#include "hardware/structs/rosc.h"
extern uint32_t gsniff_pio_offset;
extern uint32_t dsniff_pio_offset;
extern uint32_t gtrig_pio_offset;
void init_gsniff_pio() {
pio_sm_config c = glitch_sniff_cmd_program_get_default_config(gsniff_pio_offset);
sm_config_set_in_pins(&c, PIN_CMD);
sm_config_set_jmp_pin(&c, PIN_CMD);
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_out_shift(&c, false, false, 32);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
pio_sm_init(pio1, G_SNIFF_SM, gsniff_pio_offset, &c);
pio_sm_set_enabled(pio1, G_SNIFF_SM, true);
}
void init_dat0_pio() {
pio_sm_config c = glitch_dat_waiter_program_get_default_config(dsniff_pio_offset);
sm_config_set_in_pins(&c, PIN_DAT);
sm_config_set_jmp_pin(&c, PIN_DAT);
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_out_shift(&c, false, false, 32);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
pio_sm_init(pio1, G_DAT0_SM, dsniff_pio_offset, &c);
pio_sm_set_enabled(pio1, G_DAT0_SM, true);
}
extern bool mariko;
void init_trigger_pio() {
uint offset = gtrig_pio_offset;
pio_sm_config c = glitch_trigger_program_get_default_config(offset);
sm_config_set_sideset_pins (&c, gli_pin());
sm_config_set_out_shift(&c, false, true, 32);
pio_sm_set_consecutive_pindirs(pio1, G_TRIG_SM, gli_pin(), 1, true);
pio_sm_init(pio1, G_TRIG_SM, offset, &c);
pio_sm_set_enabled(pio1, G_TRIG_SM, true);
pio_gpio_init(pio1, gli_pin());
gpio_set_slew_rate(gli_pin(), GPIO_SLEW_RATE_FAST);
}
void init_glitch_pio() {
for (int i = PIN_CLK; i <= PIN_DAT; i++)
{
gpio_init(i);
gpio_enable_input_output(i);
gpio_pull_up(i);
}
gpio_init(gli_pin());
init_gsniff_pio();
init_dat0_pio();
init_trigger_pio();
}
void deinit_glitch_pio() {
pio_set_sm_mask_enabled(pio1, 0x3, false);
for (int i = PIN_CLK; i <= PIN_DAT; i++)
{
gpio_deinit(i);
gpio_disable_pulls(i);
gpio_disable_input_output(i);
}
gpio_deinit(gli_pin());
}
int do_glitch(int delay, int width, int total_ms, int after_ms) {
// at this point CPU must be reset
init_glitch_pio();
pio_sm_put_blocking(pio1, G_TRIG_SM, delay);
pio_sm_put_blocking(pio1, G_TRIG_SM, width);
bool glitch_started = false;
uint32_t last_word = 0;
uint32_t data_count = 0;
int result = GLITCH_RESULT_MISSING;
bool detected = false;
absolute_time_t detect_time = make_timeout_time_ms(20);
absolute_time_t full_time = make_timeout_time_ms(total_ms);
absolute_time_t tio_time = detect_time;
while (!time_reached(tio_time)) {
if (!pio_sm_is_rx_fifo_empty(pio1, G_DAT0_SM)) {
uint32_t temp = pio_sm_get(pio1, G_DAT0_SM);
}
if (!pio_sm_is_rx_fifo_empty(pio1, G_SNIFF_SM)) {
uint32_t cur_word = pio_sm_get(pio1, G_SNIFF_SM);
if (!detected && (cur_word >> 24) == 0x3F) {
tio_time = full_time;
detected = true;
}
if (glitch_started)
data_count += 1;
if (last_word == 0x51000000 && cur_word == 0x1351) {
if (!glitch_started)
tio_time = make_timeout_time_ms(after_ms);
glitch_started = true;
}
if (last_word == 0x51000000 && cur_word == 0x142F) {
result = GLITCH_RESULT_FAILURE;
break;
}
if (last_word == 0x40aa5458 && cur_word == 0xba3b) {
result = GLITCH_RESULT_SUCCESS;
break;
}
if (data_count == 10) {
tio_time = full_time;
}
last_word = cur_word;
}
}
deinit_glitch_pio();
if (result == GLITCH_RESULT_MISSING && glitch_started) {
result = GLITCH_RESULT_TIMEOUT;
}
return result;
}
int tries = 0;
// Blue pulsing implementation.
void inc_tries()
{
tries += 1;
if(tries & 1)
put_pixel(PIX_b);
else
put_pixel(PIX_blu);
}
// random() for glitch offset array generation
static uint32_t get_random_word() {
uint32_t byte;
int cycles = 32;
assert(rosc_hw->status & ROSC_STATUS_ENABLED_BITS);
for(int i=0; i < cycles; i++) {
byte = ((byte << 1) | rosc_hw->randombit);
busy_wait_at_least_cycles(100);
}
return byte;
}
int offsets_array[OFFSET_CNT];
void prepare_random_array()
{
for(int i = 0; i < OFFSET_CNT; i++)
offsets_array[i] = OFFSET_MIN + OFFSET_DIV*i;
for (int i = OFFSET_CNT - 1; i > 0; i--) {
size_t j = get_random_word() % (i+1);
int t = offsets_array[j];
offsets_array[j] = offsets_array[i];
offsets_array[i] = t;
}
}
bool glitch_try_offset(int offset, int * width, int edge_limit) {
int last_res = GLITCH_RESULT_SUCCESS;
int edges = 0;
int step = tries == 0 ? 32 : 8; // first ever edge search should be faster
int missing_count = 0;
inc_tries();
while (1) {
reset_cpu();
int gres = do_glitch(offset, *width, 300, 6);
if (gres == GLITCH_RESULT_MISSING)
missing_count +=1; // MMC has failed to initialize
else
missing_count = 0;
if (missing_count >= 5)
halt_with_error(4, 3); // something wrong with eMMC, cannot init properly
if (*width == 1) {
halt_with_error(5, 3);
}
if (*width >= 1000) { // no reaction to the glitch, hardware failure or bad mosfet wire
halt_with_error(6, 3);
}
if ((last_res == GLITCH_RESULT_TIMEOUT && gres == GLITCH_RESULT_FAILURE)
|| (gres == GLITCH_RESULT_TIMEOUT && last_res == GLITCH_RESULT_FAILURE)) {
if (step != 1)
step /= 2; // we have found the edge, now increase search presicion
else
edges += 1; // max precision, start walking around the edge
}
last_res = gres;
if (gres == GLITCH_RESULT_FAILURE) // not enough glitch, need more width
*width += step;
if (gres == GLITCH_RESULT_TIMEOUT) { // too much glitch, need less width
*width -= step;
if (*width <= 1)
*width = 1;
}
if (gres == GLITCH_RESULT_SUCCESS)
return true;
if (edges > edge_limit) // this offset did not work
return false;
}
}

14
glitch.h Normal file
View file

@ -0,0 +1,14 @@
#include "config.h"
#define GLITCH_RESULT_SUCCESS 0 // glitch worked and loaded
#define GLITCH_RESULT_MISSING 1 // trigger is missing
#define GLITCH_RESULT_FAILURE 2 // glitch did not work
#define GLITCH_RESULT_TIMEOUT 3 // glitch worked, but timed out
#define G_SNIFF_SM 0
#define G_TRIG_SM 1
#define G_DAT0_SM 2
int do_glitch(int delay, int width, int total_ms, int after_ms);
void init_glitch_pio();
void deinit_glitch_pio();
bool glitch_try_offset(int offset, int * width, int edge_limit);
void prepare_random_array();
extern int offsets_array[OFFSET_CNT];

173
main.c Normal file
View file

@ -0,0 +1,173 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/pio.h"
#include "hardware/clocks.h"
#include "hardware/vreg.h"
#include "hardware/xosc.h"
#include "hardware/watchdog.h"
#include "boot_detect.h"
#include "board_detect.h"
#include "config.h"
#include "misc.h"
#include "glitch.h"
#include "fuses.h"
#include "pio_upload.h"
#include "pins.h"
bool write_payload();
// overclock to 200 MHz, pretty stable & enough for the glitch
void init_system() {
vreg_set_voltage(VREG_VOLTAGE_1_30);
set_sys_clock_khz(200000, true);
}
// filled within "fast check" on eMMC init
extern uint8_t cid_buf[17];
void rewrite_payload()
{
put_pixel(PIX_whi);
write_payload();
put_pixel(PIX_blu);
// used to automatically rewrite payload when eMMC/console changes
init_config(cid_buf + 1);
}
bool safe_test_voltage(int pin, float target, float range)
{
gpio_enable_input_output(pin);
adc_gpio_init(pin);
adc_select_input(pin - 26);
uint16_t result = adc_read();
gpio_disable_input_output(pin);
float voltage = result * 3.3f / (1 << 12);
return voltage >= (target - range) && voltage <= (target + range);
}
// test all ADC pins
void self_test()
{
absolute_time_t tio_time = make_timeout_time_ms(2500);
adc_init();
bool rst_ok = false, cmd_ok = false, d0_ok = false, clk_ok = false;
while (!time_reached(tio_time)) {
if (!rst_ok)
rst_ok |= safe_test_voltage(PIN_RST, 1.8f, 0.2f);
if (!cmd_ok)
cmd_ok |= safe_test_voltage(PIN_CMD, 1.8f, 0.2f);
if (!d0_ok)
d0_ok |= safe_test_voltage(PIN_DAT, 1.8f, 0.2f);
if (!clk_ok)
clk_ok |= safe_test_voltage(PIN_CLK, 1.1f, 0.9f);
if (rst_ok && cmd_ok && d0_ok && clk_ok)
break;
}
if(!rst_ok)
{
halt_with_error(0, 2);
}
if(!cmd_ok)
{
halt_with_error(1, 2);
}
if(!d0_ok)
{
halt_with_error(2, 2);
}
if(!clk_ok)
{
halt_with_error(3, 2);
}
}
extern bool was_self_reset;
int main()
{
// stop watchdog
*(uint32_t*)(0x40058000 + 0x3000) = (1 << 30);
// init reset, mosfet and LED
detect_board();
// clocks & voltage
init_system();
// fuses counter
init_fuses();
// LED & glitch & emmc PIO
upload_pio();
// check if this is the very first start
if (watchdog_caused_reboot() && boot_try == 0)
{
halt_with_error(1, 1);
}
// is chip reset required
bool force_button = detect_by_pull_up(1, 0);
// start LED
put_pixel(PIX_blu);
// test pins
self_test();
// wait till the CPU has proper power & started reading the eMMC
wait_for_boot(2500);
// ensure the BCT has not been overwritten by system update
bool force_check = fast_check();
was_self_reset = force_button || !is_configured(cid_buf + 1);
// perform payload rewrite if required
if (!force_check || was_self_reset) {
rewrite_payload();
}
// setup the glitch trigger for Mariko
if (mariko) {
pio1->instr_mem[gtrig_pio_offset + 4] = pio_encode_nop();
pio1->instr_mem[gtrig_pio_offset + 5] = pio_encode_nop();
}
// start from some default width
int width = 150;
bool glitched = false;
int offset = 0;
for (int full_try = 0; full_try < 2; full_try++) {
// try saved records
for (int y = 0; (y < 2) && !glitched; y++) {
int max_weight = -1;
while (1) {
offset = find_best_record(&max_weight);
if (offset == -1)
break;
// try glitch
glitched = glitch_try_offset(offset, &width, 3);
if (glitched)
break;
}
}
if (!glitched) {
for(int z = 0; (z < 2) && !glitched; z++) {
prepare_random_array();
for(int y = 0; y < OFFSET_CNT; y++)
{
offset = offsets_array[y];
glitched = glitch_try_offset(offset, &width, 4);
if (glitched)
break;
}
}
}
if (glitched) {
if ((count_fuses() & 1) != boot_slot)
{
// finish update / rollback
burn_fuse();
}
add_boot_record(offset);
halt_with_error(0, 0);
}
if (full_try == 0) {
rewrite_payload();
}
}
// attempts limit
halt_with_error(7, 3);
}

589
mariko_bct.h Normal file
View file

@ -0,0 +1,589 @@
const uint8_t mariko_bct_sign[] = {
0x03, 0xA2, 0x6C, 0xA5, 0x5A, 0x73, 0x47, 0xC7, 0x78, 0xD7, 0x40, 0x62, 0x2D, 0xA5, 0x38, 0xC0,
0x89, 0x00, 0xC5, 0x65, 0xA2, 0x75, 0x25, 0xE8, 0xC6, 0xD3, 0x46, 0xE9, 0xC4, 0x41, 0xFE, 0x7B,
0x47, 0xD4, 0xC1, 0x49, 0x70, 0x57, 0x22, 0xFD, 0x32, 0x4F, 0x09, 0x8A, 0x87, 0xEC, 0x40, 0x5D,
0xC2, 0x24, 0xDC, 0x45, 0x4A, 0xBA, 0x4A, 0x2F, 0x27, 0x02, 0xD9, 0x34, 0xB0, 0x1D, 0xE2, 0xA3,
0xAE, 0x9C, 0xB8, 0xC4, 0x47, 0x26, 0xCC, 0x29, 0xDB, 0x11, 0xA5, 0xE6, 0x98, 0xE8, 0xE5, 0x7B,
0xB2, 0x4B, 0x63, 0xFC, 0x53, 0x8C, 0xD2, 0x71, 0x95, 0xA7, 0x81, 0x9D, 0xE7, 0x20, 0x94, 0x67,
0xF3, 0x53, 0x78, 0xB4, 0x0D, 0xBD, 0xBD, 0xAF, 0xEC, 0xD7, 0xB2, 0xC3, 0xE9, 0x7E, 0xD6, 0xC8,
0xB9, 0xD1, 0x72, 0x74, 0x0E, 0x4F, 0x8C, 0x24, 0x4E, 0xB7, 0x4A, 0xB1, 0x4A, 0x16, 0x89, 0x59,
0x56, 0x7F, 0x27, 0x12, 0xFB, 0x7C, 0x67, 0xD3, 0x04, 0x6E, 0x34, 0xCC, 0x8D, 0x73, 0x47, 0x02,
0xA7, 0x57, 0x64, 0xC7, 0x2C, 0x8A, 0x88, 0xDA, 0xBC, 0x5A, 0xE4, 0x46, 0x1A, 0x34, 0xD5, 0xE7,
0x83, 0x74, 0xFF, 0x6D, 0x67, 0xC7, 0x72, 0x81, 0x63, 0x4A, 0x25, 0x7A, 0xB6, 0xEE, 0xFF, 0x30,
0x98, 0xBF, 0xCE, 0x38, 0xD7, 0x4B, 0xA6, 0xFE, 0x94, 0xF7, 0x89, 0xE6, 0x2A, 0x1F, 0xE9, 0x8E,
0xB4, 0xF8, 0xA4, 0xA9, 0x4A, 0xE9, 0x14, 0x59, 0x07, 0xAD, 0xD6, 0x50, 0x4D, 0xBB, 0x36, 0xB7,
0xD1, 0x65, 0x32, 0x32, 0x37, 0x74, 0x8E, 0xF3, 0x0A, 0xCC, 0x9E, 0x00, 0xAE, 0x3A, 0x82, 0xEA,
0xCB, 0x10, 0x65, 0xFC, 0x96, 0xBE, 0x67, 0xC3, 0x76, 0x42, 0xE6, 0x1A, 0xA5, 0x5B, 0x1B, 0x8E,
0x8F, 0xA6, 0x71, 0x0A, 0xA7, 0xE8, 0x0C, 0xA8, 0xE1, 0x9B, 0x8B, 0x2E, 0xEB, 0x82, 0x20, 0x6A
};
const uint8_t mariko_bct_data[] = {
0x17, 0x8B, 0x59, 0x4B, 0xB4, 0x11, 0xFE, 0x24, 0x07, 0x3E, 0xA9, 0xF0, 0xF4, 0xC8, 0x4E, 0xB0,
0x95, 0x40, 0x03, 0x21, 0x05, 0x48, 0x60, 0xC4, 0xDF, 0xAE, 0x56, 0x32, 0xF6, 0x5E, 0x27, 0xE1,
0x2B, 0x25, 0x25, 0xE8, 0x19, 0xC6, 0xBB, 0xC9, 0xA4, 0x28, 0x21, 0x2E, 0x62, 0x98, 0x5E, 0x20,
0x0D, 0x3D, 0x61, 0x99, 0x84, 0x90, 0xC4, 0x73, 0x8B, 0xC9, 0x83, 0x78, 0xBF, 0x8E, 0x9C, 0x92,
0xD9, 0xB2, 0x33, 0x33, 0x9F, 0x28, 0x4D, 0xF7, 0x43, 0xC5, 0x5D, 0x2A, 0x1F, 0x26, 0xA3, 0x41,
0xB1, 0x72, 0xEB, 0x28, 0x64, 0x07, 0xA4, 0x2A, 0x89, 0x70, 0xEE, 0x86, 0x43, 0xC5, 0x9C, 0x19,
0xEA, 0xDC, 0x6C, 0x90, 0xF2, 0x13, 0xDD, 0xBE, 0x06, 0xF4, 0xB5, 0x11, 0xD4, 0x33, 0x79, 0x45,
0x5E, 0x63, 0xD4, 0x89, 0x0A, 0x46, 0x8C, 0xF8, 0x12, 0x59, 0x16, 0xC1, 0xBB, 0xA0, 0xE7, 0x79,
0x11, 0xD4, 0x03, 0x26, 0xFD, 0x3A, 0xB0, 0xB4, 0x5F, 0x8E, 0x05, 0x0A, 0x1E, 0x9D, 0xAB, 0x31,
0x31, 0xF2, 0x96, 0x37, 0x77, 0xAE, 0x56, 0xF3, 0x36, 0x17, 0xF3, 0x94, 0xF8, 0x90, 0x48, 0xD3,
0xD1, 0x93, 0x2A, 0x4B, 0x2E, 0x90, 0x85, 0xCD, 0x04, 0xA3, 0x34, 0x7E, 0xC9, 0xEA, 0xB2, 0x84,
0x58, 0x4C, 0xB7, 0xCD, 0xC8, 0xA6, 0x31, 0x84, 0xAB, 0xCD, 0x86, 0x71, 0xE3, 0x07, 0x0E, 0xAC,
0x27, 0x94, 0x19, 0x3E, 0xE7, 0xB4, 0x61, 0x31, 0xA1, 0xF5, 0x87, 0xDF, 0x8B, 0xC0, 0xD0, 0x8C,
0x2E, 0x7F, 0x92, 0x82, 0x9B, 0x78, 0x84, 0x31, 0x8F, 0x77, 0x03, 0xF1, 0x70, 0xB1, 0xA6, 0xEB,
0xAF, 0x11, 0x5E, 0xC1, 0x33, 0x85, 0x44, 0xD7, 0x96, 0x3D, 0x33, 0x8D, 0x07, 0x6B, 0x58, 0x6B,
0x66, 0x9D, 0x9C, 0x50, 0xEF, 0x45, 0x0F, 0x6F, 0xA7, 0x96, 0x71, 0x75, 0xCA, 0x41, 0x76, 0x6A,
0x80, 0x67, 0xE8, 0x29, 0xC5, 0x50, 0x77, 0x2D, 0x2A, 0x8D, 0x38, 0x36, 0xFF, 0x04, 0x6A, 0x6C,
0xDA, 0x22, 0x51, 0x4C, 0x6C, 0xB6, 0x1D, 0xD3, 0xA5, 0x15, 0x41, 0x43, 0x3B, 0x04, 0xE5, 0xD9,
0x11, 0xBA, 0x46, 0xA9, 0x7F, 0x54, 0xFC, 0xD1, 0xFB, 0x88, 0x1F, 0x0C, 0xA1, 0x74, 0x21, 0x8A,
0x83, 0x7E, 0xC1, 0x1C, 0xDB, 0x77, 0xC6, 0x6A, 0xFF, 0x21, 0xC2, 0x9A, 0x46, 0xEE, 0xEA, 0x9D,
0x92, 0xD1, 0x04, 0x7A, 0x98, 0xD8, 0xB8, 0xA2, 0x22, 0xF5, 0xAA, 0xAE, 0x52, 0xD4, 0x66, 0x14,
0x61, 0x18, 0x1C, 0x56, 0xCB, 0xA9, 0xA4, 0x84, 0x19, 0x08, 0xAE, 0xF1, 0x7E, 0x66, 0x4C, 0xA4,
0xF6, 0xDE, 0xC4, 0x4B, 0x9D, 0xA1, 0x78, 0xFB, 0xE8, 0xA5, 0x9D, 0xFF, 0x20, 0xBB, 0x76, 0xAC,
0xC8, 0x96, 0x31, 0x0F, 0x14, 0xE4, 0x51, 0x88, 0x08, 0xDC, 0x73, 0x6E, 0x43, 0x5A, 0x25, 0x14,
0x49, 0x03, 0xA2, 0x44, 0x78, 0x37, 0xD8, 0xB6, 0x99, 0x31, 0xE1, 0xC8, 0x79, 0x9C, 0x4A, 0x5B,
0x01, 0x68, 0x10, 0xC0, 0x77, 0x77, 0x1C, 0xA0, 0x3C, 0x92, 0xEC, 0xA7, 0x4D, 0x8C, 0xA3, 0x35,
0xDE, 0xBA, 0xEE, 0xC0, 0xC1, 0x40, 0xE6, 0xB7, 0xF0, 0x63, 0x31, 0x6F, 0x22, 0x6B, 0x96, 0x3E,
0xB1, 0xF1, 0xA2, 0x74, 0x26, 0xB7, 0x59, 0x9B, 0x5F, 0x77, 0x12, 0x42, 0x3E, 0x7D, 0xD1, 0x17,
0x69, 0x65, 0x89, 0x3C, 0xDE, 0xCA, 0x6F, 0x07, 0xC2, 0x04, 0xF5, 0x57, 0xD7, 0x85, 0xDF, 0xB8,
0x61, 0xC1, 0x02, 0x7E, 0xC1, 0x12, 0x07, 0x1E, 0xA9, 0x36, 0x8D, 0x65, 0x76, 0x46, 0x1E, 0x18,
0x78, 0x9C, 0x93, 0x2B, 0x66, 0xB8, 0x6C, 0x3C, 0x50, 0x5C, 0x33, 0xE7, 0x0D, 0x7E, 0xA0, 0xFD,
0xF9, 0x84, 0xE5, 0x96, 0x48, 0xF8, 0xCF, 0x45, 0x1D, 0x43, 0x7A, 0x78, 0xFB, 0xD4, 0x86, 0x1E,
0x55, 0x3F, 0xB3, 0xC8, 0xE8, 0x8E, 0xE1, 0xD9, 0xF5, 0x57, 0x74, 0x70, 0xEB, 0x7F, 0xBC, 0xE5,
0xC6, 0x63, 0x8A, 0x04, 0xDF, 0x9D, 0xD6, 0x2F, 0x95, 0xDC, 0xC6, 0x94, 0x89, 0x9B, 0xFE, 0x85,
0x71, 0x31, 0x4A, 0x1A, 0x79, 0xFA, 0x48, 0x8E, 0xF1, 0x78, 0x34, 0x02, 0x7A, 0xA0, 0xEB, 0xD0,
0x1E, 0xBF, 0xA3, 0x86, 0x3D, 0xDD, 0x38, 0x5C, 0x8B, 0xC3, 0x13, 0x39, 0xF7, 0x63, 0x88, 0x48,
0xC3, 0x0D, 0x63, 0x62, 0x7D, 0xE0, 0x16, 0x51, 0x12, 0xA0, 0x67, 0x9B, 0xA7, 0x49, 0xAB, 0xDC,
0x76, 0x44, 0xA3, 0xC3, 0xEC, 0x37, 0x87, 0xA0, 0x3F, 0xA3, 0x48, 0x5F, 0xE2, 0x97, 0x60, 0x3A,
0x5F, 0xDA, 0x71, 0xF6, 0x3F, 0x72, 0xEA, 0x6A, 0x61, 0xF1, 0xB9, 0x04, 0x6F, 0xA9, 0x93, 0xA9,
0x11, 0xA2, 0x06, 0x5B, 0x8D, 0xA1, 0x4F, 0x1B, 0x01, 0x05, 0xB5, 0xD7, 0x93, 0x53, 0x31, 0x7D,
0xEC, 0xE6, 0x38, 0x18, 0x2C, 0x8A, 0x1D, 0x51, 0x9F, 0x33, 0x32, 0xD3, 0x19, 0x3E, 0xE1, 0x44,
0x6F, 0x8D, 0x9F, 0x53, 0x43, 0xF4, 0x39, 0x44, 0xFE, 0x10, 0xF1, 0x9B, 0xC8, 0xA9, 0x86, 0x26,
0xCC, 0xF2, 0x59, 0x8E, 0x86, 0x54, 0xAF, 0xA4, 0xCC, 0x91, 0x87, 0x7B, 0x64, 0xCE, 0x8B, 0x54,
0x0C, 0xC6, 0x90, 0x5F, 0x64, 0x04, 0x3C, 0xE2, 0x1A, 0xB0, 0x48, 0xE3, 0x3A, 0x75, 0x00, 0x2E,
0xC8, 0x7D, 0x9D, 0x85, 0x59, 0x2B, 0x19, 0x4D, 0x3A, 0x5E, 0x8A, 0x6C, 0x27, 0x2C, 0x4E, 0xF1,
0x35, 0x5B, 0x58, 0x1B, 0x38, 0x7F, 0x29, 0xE3, 0xCD, 0x1D, 0x8B, 0x31, 0x1C, 0x14, 0x0E, 0xBA,
0x17, 0xEE, 0x3C, 0x3B, 0x54, 0xBE, 0x4B, 0x01, 0x11, 0xD6, 0xCA, 0x03, 0xA4, 0xAC, 0x9D, 0xD9,
0xA2, 0x09, 0x06, 0x06, 0x65, 0xBC, 0x89, 0xFD, 0x03, 0xC5, 0x87, 0xE5, 0xDB, 0x67, 0x5B, 0x58,
0x35, 0x77, 0xFD, 0x52, 0x4F, 0xC7, 0xCF, 0xA9, 0x35, 0x4C, 0x72, 0x77, 0x9B, 0x50, 0x03, 0x9D,
0xC5, 0x9E, 0xA2, 0x95, 0x52, 0xB5, 0xC0, 0xB6, 0x54, 0x86, 0x41, 0xD0, 0xC2, 0xE1, 0x58, 0xF9,
0xA7, 0x1B, 0xDE, 0xE0, 0x4D, 0x8E, 0x3C, 0xA7, 0x8F, 0x09, 0x1A, 0xCE, 0x04, 0xE7, 0x02, 0xBA,
0x5E, 0x2A, 0x9A, 0x87, 0xEF, 0xDE, 0x9B, 0xD1, 0x4E, 0x9F, 0x41, 0x4E, 0x45, 0xBA, 0xA5, 0x85,
0x8E, 0xE6, 0x20, 0x79, 0xF9, 0x93, 0x68, 0x24, 0x3A, 0x71, 0xFB, 0x26, 0x3F, 0x59, 0x85, 0xAA,
0xAD, 0xEA, 0x6F, 0x81, 0xFA, 0x8C, 0x0A, 0x33, 0x81, 0x29, 0xF1, 0xF8, 0x1B, 0xBA, 0x38, 0xC6,
0x33, 0x07, 0xD1, 0x1A, 0x60, 0x3F, 0x0A, 0x35, 0x7F, 0x3C, 0x69, 0x35, 0xAF, 0x7C, 0x7F, 0x4A,
0xFD, 0x2D, 0xF8, 0x05, 0x14, 0xFD, 0x0C, 0xC3, 0xB6, 0x4B, 0x9C, 0x3B, 0xC2, 0xA2, 0x63, 0x00,
0x80, 0xF0, 0x7F, 0xFC, 0x94, 0x0A, 0x92, 0x08, 0xB0, 0x68, 0x4C, 0x39, 0x69, 0x95, 0x8F, 0xD6,
0xAA, 0x05, 0x9B, 0x99, 0xDE, 0x37, 0xC3, 0x49, 0xD9, 0xA5, 0xED, 0xA4, 0x0A, 0x69, 0xDA, 0xE0,
0x6D, 0x14, 0x10, 0x6C, 0x72, 0xBD, 0x7C, 0xE3, 0x0F, 0x2D, 0xE3, 0x0C, 0x25, 0x82, 0xFB, 0xED,
0x80, 0x58, 0x24, 0x48, 0xCE, 0xA1, 0x40, 0x4C, 0x0C, 0x31, 0x61, 0xAE, 0xCD, 0x39, 0xFE, 0x95,
0xE3, 0x64, 0x9B, 0x34, 0xC0, 0x1B, 0xB0, 0xFB, 0xF3, 0xAC, 0x71, 0x8B, 0xCF, 0x77, 0x67, 0x7A,
0x9A, 0xA8, 0x3F, 0x25, 0x2B, 0xC9, 0x91, 0x31, 0x54, 0x8C, 0x98, 0xB4, 0xE3, 0x58, 0xB7, 0x32,
0xDD, 0xC6, 0x19, 0xA0, 0x26, 0xBA, 0x6E, 0xC0, 0x7C, 0x74, 0x4C, 0x84, 0x5D, 0x41, 0x64, 0xCA,
0xAA, 0xCD, 0xAA, 0xA0, 0xAF, 0x4D, 0xF2, 0xAB, 0xC6, 0x6F, 0x6D, 0xFE, 0x7D, 0x3D, 0xDC, 0x69,
0xE9, 0x05, 0x88, 0xEF, 0xC9, 0xB6, 0x9C, 0x5D, 0x99, 0xEE, 0xD4, 0x90, 0xBF, 0xF4, 0x4A, 0x40,
0x1D, 0xB9, 0xF7, 0x9C, 0x55, 0x68, 0x7C, 0x9C, 0x68, 0x78, 0xF6, 0xAF, 0xB9, 0x96, 0xF3, 0x4A,
0x2C, 0x33, 0x0D, 0x02, 0x56, 0x5F, 0x9E, 0x67, 0x58, 0x33, 0xE9, 0x40, 0x21, 0xE7, 0x18, 0xEB,
0xA5, 0xD9, 0x8D, 0x31, 0x67, 0xEB, 0x4C, 0x8D, 0x5E, 0x40, 0x93, 0xFE, 0x10, 0x6F, 0x5F, 0x39,
0x6F, 0x99, 0xB6, 0x4D, 0x73, 0xFB, 0xB1, 0xF8, 0x95, 0x9E, 0x47, 0x3F, 0x83, 0x9C, 0x84, 0x5C,
0x34, 0x0F, 0x91, 0x11, 0x6B, 0x83, 0x0B, 0x1B, 0xAA, 0x69, 0x46, 0xF3, 0x4E, 0xDA, 0xC3, 0xAF,
0x92, 0xB9, 0x89, 0xB9, 0x40, 0x03, 0x27, 0x5F, 0x5C, 0x77, 0x9E, 0xEB, 0x67, 0xA6, 0x7F, 0xC2,
0x20, 0xFB, 0xC3, 0xD4, 0x2E, 0xEC, 0xD6, 0x53, 0xCD, 0x3F, 0xC8, 0x5C, 0xD8, 0x2D, 0x40, 0x42,
0xF4, 0x60, 0x92, 0xBF, 0x15, 0x3B, 0x18, 0x75, 0x56, 0x02, 0xE6, 0x8E, 0x14, 0xA3, 0x4F, 0x04,
0x98, 0x04, 0x61, 0x52, 0x30, 0x16, 0x95, 0x09, 0x4F, 0x86, 0xFE, 0xE9, 0x79, 0xEB, 0x70, 0xB6,
0x59, 0x2B, 0x9A, 0xF6, 0x5B, 0xFA, 0xF7, 0xE2, 0x0B, 0xD8, 0x6C, 0x54, 0x1B, 0x16, 0xAB, 0x06,
0x5C, 0x70, 0xA1, 0x84, 0x88, 0x5A, 0xE5, 0xBA, 0xE6, 0x41, 0xF9, 0xF4, 0x7B, 0xE3, 0x34, 0xB9,
0x12, 0xEC, 0xA3, 0x05, 0xF2, 0x99, 0x98, 0x00, 0x43, 0x1A, 0x52, 0xA3, 0xF6, 0xCC, 0x45, 0x90,
0x3E, 0x42, 0xBA, 0xE3, 0x75, 0xFF, 0xC9, 0x5E, 0x3F, 0xAA, 0xA1, 0xAF, 0xEA, 0x5E, 0x82, 0x35,
0x82, 0xD4, 0x47, 0x81, 0x79, 0xC7, 0x3B, 0x63, 0x45, 0xD4, 0xFD, 0x25, 0xAB, 0x32, 0x9E, 0xED,
0x98, 0x14, 0x01, 0x75, 0xAD, 0x1C, 0xD8, 0xE4, 0x24, 0x4C, 0x34, 0x58, 0x6A, 0xAA, 0x35, 0xB1,
0xAA, 0xF1, 0xDD, 0x7E, 0x44, 0x45, 0x8A, 0xA4, 0x15, 0x60, 0xC1, 0x28, 0x37, 0x8F, 0xC2, 0xAE,
0xD8, 0x80, 0xCB, 0xB4, 0x9E, 0x92, 0xD2, 0xCB, 0x15, 0x59, 0x3B, 0x8D, 0x8E, 0x23, 0x72, 0xBE,
0x39, 0x7B, 0x60, 0x7B, 0x7D, 0xCA, 0x59, 0x08, 0x9A, 0x90, 0x61, 0x78, 0xF0, 0xF1, 0x12, 0x4E,
0x35, 0xC9, 0x56, 0x42, 0x6C, 0x58, 0xC4, 0xA1, 0xB9, 0x61, 0x27, 0x12, 0xF4, 0x83, 0x8E, 0x27,
0x29, 0x0F, 0xE3, 0xA8, 0x2C, 0xEE, 0xD9, 0xFD, 0x8F, 0x0A, 0x34, 0xB1, 0x67, 0x0E, 0x90, 0x9A,
0xC2, 0xEE, 0xBB, 0xFC, 0x49, 0x12, 0xBB, 0x0C, 0x62, 0xD1, 0x31, 0x32, 0x26, 0xAA, 0xCC, 0x56,
0x3D, 0x20, 0x0F, 0xD9, 0x7D, 0xBC, 0x42, 0x1E, 0x86, 0x99, 0xEC, 0xAE, 0x97, 0x43, 0x78, 0x3C,
0xDF, 0xD2, 0x6C, 0xBA, 0x8F, 0x9E, 0x95, 0x9E, 0x7F, 0x26, 0xEC, 0x56, 0x04, 0xF2, 0x57, 0x26,
0xE1, 0xD8, 0x1F, 0x09, 0x8A, 0xC1, 0xBD, 0xE5, 0xE6, 0x6A, 0xE7, 0x2F, 0x40, 0xD2, 0xA2, 0x60,
0x66, 0x19, 0x01, 0xB9, 0x9E, 0x49, 0x6A, 0x50, 0x9B, 0x6D, 0x82, 0x31, 0x72, 0x42, 0x8D, 0xF2,
0xCD, 0x0B, 0xC5, 0x1E, 0x4E, 0xF8, 0x62, 0xBE, 0xF0, 0x4C, 0x30, 0x48, 0x01, 0x74, 0x01, 0xC2,
0x24, 0x78, 0xFC, 0x0F, 0xDB, 0xED, 0xA5, 0xFA, 0x1A, 0x56, 0x3E, 0x67, 0x8B, 0x66, 0x8E, 0xD6,
0x11, 0x54, 0xCD, 0x8B, 0xD0, 0xF8, 0x2A, 0x55, 0xB7, 0xC2, 0x09, 0x3E, 0x45, 0xF6, 0x9A, 0xC4,
0xE5, 0x40, 0x26, 0x81, 0xB3, 0x62, 0x8F, 0xEC, 0x1D, 0xF4, 0x08, 0x0B, 0x6A, 0xB4, 0x2F, 0x3A,
0xE5, 0xDF, 0x19, 0x67, 0x02, 0xF1, 0xF6, 0xE9, 0x17, 0x92, 0xDB, 0xA7, 0xB7, 0x10, 0x00, 0xBF,
0x22, 0x5C, 0x5A, 0xA0, 0x00, 0xD5, 0x44, 0xA1, 0xD6, 0xCD, 0x24, 0xDA, 0xB6, 0x22, 0xD0, 0xA3,
0xA2, 0xFD, 0xDF, 0x40, 0x24, 0xA0, 0xF3, 0xC0, 0xEB, 0xEE, 0xE0, 0x93, 0xD5, 0x04, 0x0C, 0x08,
0x34, 0x79, 0xBC, 0x2B, 0x4B, 0xB5, 0xF4, 0xCD, 0x41, 0xBA, 0x8E, 0xFA, 0x8C, 0xAC, 0xF6, 0x50,
0x0C, 0x75, 0xC0, 0x2B, 0x46, 0xA3, 0x0B, 0x8B, 0x2A, 0x6D, 0xE6, 0x5F, 0xF5, 0x39, 0x90, 0x9D,
0x0C, 0x9F, 0x9B, 0x66, 0x21, 0xA3, 0x01, 0xD1, 0xCE, 0x0A, 0x32, 0xA4, 0x3F, 0x47, 0x61, 0x1E,
0x33, 0xFD, 0x20, 0x7C, 0x38, 0x6B, 0x34, 0x11, 0xBA, 0xCC, 0x3F, 0x83, 0xEC, 0x73, 0x28, 0x78,
0x96, 0x99, 0x19, 0x40, 0xAE, 0xB4, 0x1C, 0xE8, 0xD2, 0x7E, 0xED, 0x3A, 0xE2, 0x23, 0x06, 0xB9,
0xBA, 0x0D, 0x95, 0x89, 0xEF, 0xDE, 0x97, 0xCD, 0x63, 0xC6, 0x55, 0xC0, 0x34, 0x21, 0x26, 0xD0,
0xEC, 0xE7, 0x96, 0xBC, 0x3D, 0x4D, 0x50, 0x63, 0x8A, 0xAE, 0xD3, 0x16, 0x0E, 0x12, 0x46, 0xC1,
0x62, 0x49, 0xF2, 0x4D, 0x3E, 0x6F, 0x93, 0x02, 0xB5, 0x1B, 0x9F, 0x71, 0x79, 0xEC, 0x2B, 0x99,
0xDD, 0xCB, 0x7E, 0x10, 0xA1, 0x8F, 0xDC, 0x44, 0xBC, 0x4E, 0x90, 0x19, 0xEA, 0x23, 0x78, 0x79,
0x96, 0x1C, 0xE7, 0xBF, 0x15, 0xBC, 0x32, 0x63, 0x8B, 0xE3, 0xD2, 0x23, 0xEB, 0xD9, 0x67, 0x4E,
0xB3, 0x53, 0x93, 0x5E, 0x8D, 0xA7, 0xEE, 0xC3, 0x75, 0x28, 0x07, 0xB4, 0x35, 0x12, 0x06, 0xB6,
0x70, 0x42, 0x2C, 0xAC, 0x67, 0xD2, 0x6D, 0xAE, 0x49, 0x35, 0xD8, 0x31, 0xB6, 0x36, 0xD5, 0x23,
0x64, 0x6B, 0x09, 0xC4, 0x3C, 0x16, 0x8A, 0xA0, 0x13, 0x9D, 0x01, 0x6B, 0x3D, 0x65, 0xCC, 0xE0,
0x77, 0x07, 0xDE, 0xBA, 0xAB, 0x70, 0x52, 0x8B, 0x6F, 0xCD, 0x06, 0x0B, 0xF3, 0x65, 0x30, 0x52,
0x17, 0x9D, 0x31, 0xC9, 0x56, 0xFE, 0x05, 0x05, 0x78, 0xAA, 0x18, 0xDA, 0xFD, 0x77, 0x12, 0xA5,
0x18, 0x57, 0x24, 0xB6, 0x57, 0xFC, 0xEC, 0x21, 0xBE, 0x48, 0xA9, 0x33, 0xA0, 0x10, 0xBF, 0x38,
0xC6, 0xA2, 0x8E, 0xFB, 0x0D, 0x03, 0x03, 0xFC, 0xC1, 0xF5, 0x11, 0x46, 0xF1, 0x77, 0xC4, 0x91,
0x92, 0x61, 0x30, 0x56, 0xB1, 0xFA, 0x38, 0x0E, 0x7A, 0x16, 0x1D, 0xFC, 0x9C, 0x5D, 0x07, 0xD0,
0x68, 0xA1, 0xC8, 0x2F, 0x3D, 0x8E, 0x6D, 0x47, 0x98, 0x21, 0x0C, 0xD5, 0xB1, 0xF1, 0xC5, 0x3F,
0xFE, 0x51, 0x0E, 0x70, 0xB7, 0x6C, 0x95, 0xDE, 0x1F, 0x73, 0x8C, 0x27, 0x11, 0x34, 0x21, 0x47,
0x00, 0x5B, 0xC7, 0xD2, 0xE9, 0x35, 0x50, 0xF5, 0x7B, 0xD6, 0xB2, 0x38, 0x89, 0x48, 0x6A, 0x9B,
0x76, 0x6D, 0x7D, 0x92, 0x31, 0xE6, 0xCE, 0x97, 0xE5, 0xA3, 0xAA, 0xA7, 0xE0, 0x77, 0x2E, 0x29,
0xB2, 0xB8, 0x6F, 0x1C, 0x74, 0x6F, 0x04, 0xC7, 0x70, 0x92, 0x7E, 0x31, 0xB6, 0xBE, 0x75, 0xA0,
0x2D, 0x8C, 0xC9, 0x1C, 0x36, 0x30, 0xE8, 0xAB, 0xEB, 0x39, 0x51, 0x5C, 0x58, 0x80, 0x3B, 0x9F,
0xB4, 0x0F, 0x45, 0x9A, 0xE9, 0xE5, 0x61, 0xB1, 0x6B, 0x4D, 0x61, 0x9C, 0xA8, 0x2A, 0x0A, 0x97,
0xE5, 0x2E, 0x76, 0x9B, 0x2F, 0xFE, 0x0D, 0x83, 0x8A, 0xFA, 0x9A, 0x48, 0x60, 0x60, 0x48, 0x35,
0x3E, 0x86, 0x51, 0x06, 0xC4, 0x81, 0xC9, 0x9C, 0x5D, 0xE2, 0x18, 0xAE, 0x29, 0xE9, 0x06, 0x75,
0x16, 0x7B, 0x1D, 0x21, 0x23, 0xDF, 0xDE, 0xD1, 0x77, 0xBC, 0x34, 0x9A, 0xFE, 0xB6, 0x7B, 0x9D,
0x37, 0x61, 0x1D, 0x8B, 0x4C, 0x53, 0xD9, 0xCA, 0xFA, 0x72, 0xB4, 0x9D, 0x7C, 0x0C, 0x56, 0xBF,
0x5B, 0x96, 0xE7, 0x56, 0xDE, 0x2F, 0x60, 0xB2, 0x54, 0x23, 0x7B, 0xAC, 0x2B, 0xC3, 0xF3, 0x28,
0x86, 0xB5, 0xD6, 0x0E, 0x90, 0x35, 0x80, 0xF0, 0xFC, 0x07, 0x93, 0x67, 0xDB, 0x70, 0xAC, 0xBA,
0xE3, 0xD7, 0xD8, 0x3B, 0x2A, 0xAF, 0x27, 0xBC, 0x51, 0x57, 0xCC, 0xE9, 0x10, 0x55, 0x66, 0x27,
0x47, 0x7E, 0xB3, 0x82, 0x6B, 0x70, 0x26, 0x40, 0x0D, 0x43, 0x33, 0x8E, 0xCA, 0x91, 0x2F, 0x39,
0x41, 0x93, 0x98, 0x5E, 0x96, 0x81, 0xEB, 0x5E, 0xBE, 0xB0, 0x5B, 0x5A, 0xE7, 0xA1, 0x7F, 0xFD,
0x68, 0x62, 0xF9, 0x63, 0x31, 0x59, 0xB5, 0xEC, 0x65, 0x65, 0xE7, 0x57, 0x13, 0x4B, 0x35, 0xD5,
0x18, 0x21, 0x1D, 0x71, 0xBA, 0x63, 0xE6, 0x4B, 0xA6, 0xF8, 0xD2, 0x02, 0xBD, 0x00, 0x2A, 0xAC,
0xD0, 0xA9, 0x27, 0x92, 0x66, 0xAC, 0xAE, 0xEA, 0x96, 0xB9, 0x87, 0x73, 0xF8, 0x69, 0xE7, 0x56,
0x7C, 0xCF, 0xB2, 0x1C, 0x39, 0x0C, 0xC5, 0xAD, 0x81, 0x9A, 0xAF, 0x01, 0x83, 0xD7, 0x6D, 0x8E,
0x5C, 0x22, 0xBB, 0xAC, 0xD3, 0x62, 0x11, 0xB8, 0x29, 0x57, 0x9D, 0x8A, 0x09, 0xE3, 0x34, 0xB5,
0x0F, 0x49, 0x2F, 0x8C, 0x97, 0x6D, 0xE7, 0x63, 0x0C, 0x97, 0x63, 0xD7, 0xF1, 0x6B, 0xF6, 0x98,
0xE1, 0x1D, 0x5A, 0x20, 0xEA, 0xA1, 0xF3, 0x1D, 0x65, 0x6B, 0x2D, 0xF2, 0x0D, 0xE7, 0x99, 0xB5,
0xD6, 0xE9, 0xCC, 0xD1, 0x2D, 0x74, 0xA5, 0x2B, 0x2B, 0xDC, 0x60, 0x1C, 0x92, 0x90, 0xC3, 0xB2,
0x02, 0x6B, 0x2A, 0xE7, 0xC3, 0x70, 0x72, 0x5D, 0xD9, 0x29, 0xE1, 0xE0, 0x32, 0xB5, 0xE2, 0x52,
0xF5, 0xF9, 0x35, 0x4E, 0xFF, 0x57, 0x8B, 0xBA, 0x47, 0x83, 0xCE, 0x43, 0x37, 0xD7, 0x85, 0x72,
0x4A, 0xA0, 0xDD, 0xA5, 0x1B, 0xC3, 0xBA, 0x57, 0xE3, 0x6A, 0x09, 0x53, 0xAC, 0x3C, 0xC6, 0x4F,
0xE0, 0x56, 0x5F, 0x52, 0x83, 0x45, 0x0D, 0xF7, 0x9B, 0x92, 0x2E, 0x57, 0xBE, 0xA1, 0x8F, 0x2B,
0x90, 0x59, 0x79, 0x08, 0xD8, 0xE0, 0x9C, 0x01, 0x6D, 0xF3, 0xCC, 0x0A, 0x7C, 0xFA, 0xF5, 0x26,
0xAD, 0xF9, 0x45, 0xEC, 0xDA, 0x77, 0x31, 0xDC, 0x89, 0x3D, 0x73, 0x77, 0xC1, 0xFE, 0xEC, 0x06,
0x84, 0x26, 0xF1, 0xCB, 0xAC, 0xD9, 0x05, 0x1B, 0x51, 0x7A, 0x40, 0x21, 0x82, 0x1F, 0xEC, 0x6C,
0xF8, 0x87, 0xA7, 0x6C, 0x7F, 0xB2, 0x2C, 0xD6, 0x35, 0x9E, 0x36, 0xAA, 0xEB, 0x10, 0x92, 0xEB,
0x30, 0x77, 0x73, 0x10, 0x45, 0x8D, 0x66, 0x6C, 0xD0, 0x4B, 0x51, 0xBA, 0x01, 0x06, 0xC8, 0x50,
0x80, 0xC5, 0x8A, 0x16, 0xC7, 0x97, 0xCC, 0x8E, 0x5A, 0x98, 0x26, 0x24, 0x6F, 0xE9, 0xEA, 0x0F,
0x53, 0x27, 0x04, 0x3B, 0x62, 0x61, 0xD8, 0x67, 0x1F, 0x70, 0x51, 0xED, 0x31, 0x8C, 0xE0, 0x59,
0xB6, 0xAE, 0x4C, 0x60, 0xE2, 0xFB, 0xF9, 0x78, 0xA0, 0x1A, 0xDB, 0x14, 0x1F, 0x8A, 0x7C, 0xDE,
0x39, 0x74, 0x72, 0x3B, 0xAE, 0x76, 0xE5, 0x82, 0x50, 0xA9, 0xCE, 0xD0, 0x8E, 0x2F, 0x5F, 0x04,
0x9E, 0x16, 0x06, 0x0D, 0xE6, 0xB7, 0x3E, 0x2A, 0x95, 0x3C, 0x06, 0xC9, 0xBE, 0x3D, 0x1B, 0x68,
0x62, 0x9E, 0x73, 0x7E, 0x3A, 0xD4, 0x9F, 0xBC, 0x51, 0xAC, 0xC1, 0xE1, 0x84, 0x08, 0x5D, 0xD8,
0x59, 0x07, 0xEB, 0x1E, 0x6C, 0xB1, 0xFC, 0x42, 0x23, 0x47, 0xF7, 0xF5, 0xBB, 0x19, 0x04, 0x6E,
0xCC, 0x29, 0x3E, 0xC6, 0xB3, 0x1C, 0xA1, 0xAE, 0xA3, 0xCB, 0x5E, 0xC5, 0x11, 0x17, 0xAC, 0xC0,
0x43, 0x30, 0xA2, 0x03, 0xC0, 0xCF, 0x33, 0x80, 0x0E, 0xA9, 0xC1, 0xAC, 0x5F, 0xF9, 0x12, 0x7D,
0x24, 0xD4, 0x6E, 0x39, 0x3A, 0xF9, 0xFF, 0x64, 0x7C, 0x5D, 0x7D, 0xFB, 0xED, 0xDF, 0x1A, 0x6B,
0x81, 0x36, 0x7F, 0x1D, 0x34, 0xD3, 0xEB, 0x01, 0xF0, 0xAE, 0xFD, 0xC7, 0xC5, 0x19, 0x72, 0xBA,
0x4D, 0x4F, 0x38, 0xB6, 0x17, 0x2E, 0x87, 0x97, 0x89, 0x79, 0x03, 0x4C, 0x4A, 0x35, 0x13, 0x43,
0xF5, 0xF4, 0xB2, 0xE1, 0x5C, 0x01, 0x60, 0xC7, 0xC8, 0x8B, 0x27, 0x21, 0x73, 0xBD, 0xB9, 0x1F,
0xF4, 0x83, 0x2F, 0xC6, 0x67, 0x1A, 0x51, 0x3F, 0xEA, 0x31, 0xC9, 0x27, 0x69, 0xF6, 0x17, 0x6F,
0xE6, 0xED, 0x3A, 0xB1, 0x55, 0x6D, 0xD8, 0x7E, 0xA0, 0x19, 0x2A, 0x86, 0x4A, 0x08, 0x04, 0x64,
0x97, 0x80, 0xFF, 0xFE, 0x80, 0x00, 0xB2, 0x29, 0x6C, 0x6C, 0xE2, 0xAA, 0xD2, 0xD0, 0x69, 0x0D,
0xA8, 0x0E, 0x77, 0xD9, 0xEE, 0x13, 0xE7, 0x47, 0xD2, 0xC3, 0x1F, 0x3D, 0x52, 0x9D, 0x38, 0x3E,
0x93, 0x06, 0x82, 0x51, 0x09, 0x85, 0x92, 0x29, 0x33, 0x93, 0xAF, 0x86, 0x94, 0x30, 0x05, 0x89,
0x2D, 0x12, 0x57, 0xC1, 0x20, 0x34, 0xC5, 0x55, 0x1C, 0x12, 0x0D, 0x14, 0x15, 0x75, 0x92, 0x7D,
0x4B, 0x95, 0x2E, 0x62, 0x68, 0x90, 0x90, 0xDA, 0x74, 0x97, 0x3D, 0x22, 0x97, 0xCA, 0x22, 0xF6,
0xA6, 0xC0, 0xF5, 0xFE, 0x45, 0xAF, 0x15, 0x75, 0x26, 0x86, 0x02, 0x11, 0x39, 0xEC, 0x3B, 0x38,
0xD7, 0x65, 0x51, 0x95, 0xA3, 0x24, 0x0C, 0x89, 0xB1, 0xD6, 0x46, 0x84, 0xA1, 0x7B, 0x78, 0xD8,
0xDD, 0x4C, 0x7F, 0x34, 0xE5, 0xAF, 0xE6, 0x4D, 0xE5, 0xF0, 0x05, 0xEA, 0x32, 0xCC, 0xB8, 0x1A,
0x82, 0x91, 0x93, 0xF6, 0x4B, 0xAF, 0x6D, 0xAE, 0xF1, 0xE4, 0x16, 0x87, 0x3F, 0xA8, 0xDE, 0xE2,
0xD6, 0xCA, 0xE8, 0x83, 0xD6, 0xCA, 0x9F, 0xC2, 0xC5, 0xEE, 0xE5, 0x68, 0x29, 0xF5, 0xB0, 0x55,
0x15, 0x21, 0xF0, 0xE0, 0x26, 0x0C, 0x3B, 0xA3, 0x59, 0x77, 0x6F, 0xB2, 0x89, 0xC4, 0x74, 0xAA,
0xF1, 0x2F, 0x5C, 0x68, 0x23, 0x41, 0x54, 0x0D, 0x4A, 0x38, 0x5D, 0x87, 0x3F, 0x46, 0x9D, 0x53,
0xFD, 0x83, 0x55, 0x9D, 0xA3, 0x0D, 0xB4, 0xA4, 0x19, 0xA0, 0x8F, 0x20, 0x17, 0x7C, 0xC3, 0x59,
0xE7, 0xE2, 0x5D, 0x2A, 0xD7, 0xCC, 0x88, 0x29, 0xB9, 0x38, 0x13, 0xCC, 0xD1, 0x7E, 0xCE, 0x94,
0x43, 0xB2, 0x2C, 0x6A, 0xB0, 0x5D, 0xDC, 0xFE, 0x12, 0x28, 0x15, 0x51, 0x0C, 0xD2, 0xA5, 0xB2,
0xF9, 0x87, 0x8E, 0x91, 0xD9, 0xA5, 0x3C, 0xD6, 0x43, 0xD6, 0xB2, 0x98, 0x95, 0x49, 0xDB, 0x41,
0x1F, 0xEE, 0x79, 0x28, 0x26, 0x19, 0xFF, 0x51, 0xC8, 0x11, 0xCA, 0x82, 0x05, 0x61, 0xF7, 0x64,
0xF6, 0x24, 0x18, 0x42, 0xCA, 0x82, 0xE0, 0xA9, 0xDE, 0x58, 0xAF, 0xFC, 0x7A, 0x5E, 0x84, 0xEE,
0xC9, 0xB6, 0xEC, 0x11, 0x55, 0xDF, 0xC1, 0x6F, 0x6C, 0x17, 0xD5, 0xE4, 0xA8, 0xF1, 0xCD, 0xE0,
0x84, 0xB4, 0x25, 0x58, 0xAD, 0xD3, 0xF7, 0x5E, 0xB3, 0x36, 0xCE, 0xE0, 0xFA, 0x7D, 0xEF, 0x03,
0x62, 0x46, 0x8A, 0xA0, 0x7D, 0xBD, 0xA1, 0xA7, 0xF2, 0x0D, 0xEF, 0xC2, 0x55, 0xA2, 0xB4, 0x2E,
0x12, 0x7F, 0xE2, 0x62, 0x7E, 0x1A, 0x95, 0x47, 0x7C, 0x49, 0x45, 0x46, 0x88, 0xE7, 0x6A, 0xC7,
0x7C, 0x1E, 0x87, 0x0E, 0x9E, 0x55, 0x6E, 0x58, 0x31, 0xA8, 0x33, 0xA2, 0xC6, 0x1C, 0x29, 0x28,
0xB0, 0xE4, 0x3E, 0x80, 0x22, 0xB1, 0x74, 0x4F, 0x83, 0xC7, 0x7D, 0x89, 0x4C, 0xED, 0x1A, 0x37,
0x66, 0xCB, 0x92, 0xAA, 0xBC, 0x36, 0x0E, 0x2E, 0xAE, 0x81, 0x1F, 0x49, 0x8D, 0xC7, 0xC1, 0x0E,
0x18, 0xA2, 0x64, 0xE9, 0x18, 0x05, 0xE0, 0x71, 0xF6, 0x94, 0x8A, 0x41, 0x86, 0x12, 0xE3, 0xDB,
0x71, 0xDB, 0x70, 0xBA, 0xB5, 0x91, 0xF0, 0xED, 0xAA, 0x82, 0xFC, 0x99, 0x51, 0x8A, 0x49, 0xCF,
0x36, 0xA9, 0x58, 0x8A, 0xCC, 0xB4, 0xE7, 0x5D, 0x9E, 0xB9, 0xFE, 0xEB, 0xE1, 0xC7, 0x08, 0x3B,
0xB0, 0xDB, 0x7D, 0x2C, 0x03, 0x6F, 0x21, 0x1E, 0x5A, 0x12, 0x56, 0x9F, 0x97, 0xC5, 0x43, 0x1B,
0xBC, 0xEB, 0x26, 0x0C, 0xFC, 0xEA, 0xA4, 0xAA, 0x91, 0x0C, 0xF7, 0xB7, 0xDC, 0x30, 0x5E, 0x65,
0x0D, 0xCB, 0x37, 0xB9, 0x07, 0xD0, 0x4F, 0x70, 0x07, 0x15, 0x29, 0x6F, 0x1B, 0xF7, 0x7F, 0x8A,
0xD3, 0xBE, 0x20, 0x81, 0x94, 0xF2, 0xF2, 0x2D, 0xA2, 0x44, 0x9C, 0x02, 0xCE, 0xAF, 0x95, 0xA5,
0xB7, 0x60, 0x6A, 0x66, 0x8F, 0x99, 0x14, 0x14, 0x3C, 0xC3, 0x21, 0xA5, 0x57, 0x50, 0x7B, 0xDD,
0x09, 0x02, 0x4F, 0xFE, 0x42, 0x71, 0xD7, 0xC5, 0x1E, 0xFD, 0x70, 0x64, 0x7E, 0xB9, 0x65, 0xB4,
0xB1, 0xA9, 0xC6, 0x7E, 0x3B, 0xA8, 0x33, 0x9A, 0x57, 0x82, 0x05, 0x7B, 0x67, 0xF2, 0x6C, 0xCF,
0xBC, 0x7D, 0x4D, 0x46, 0x9E, 0x4A, 0x40, 0xA5, 0xF2, 0x69, 0x7C, 0x01, 0x87, 0xAA, 0xBC, 0xA9,
0xEC, 0xAA, 0x99, 0xB8, 0xD6, 0xDF, 0xFF, 0xEF, 0xAF, 0x24, 0x08, 0x41, 0xDE, 0x2A, 0x25, 0xBA,
0x5A, 0x0D, 0x11, 0x10, 0xAA, 0xA0, 0x60, 0x0C, 0xFF, 0x2A, 0xBE, 0x8E, 0x2A, 0x27, 0x1F, 0x67,
0xD1, 0x69, 0x72, 0x68, 0xD8, 0x87, 0xC9, 0xAF, 0xD7, 0x52, 0x52, 0x9F, 0xCE, 0x86, 0x09, 0xDF,
0xD0, 0x0C, 0x3A, 0x6A, 0x0F, 0x98, 0x83, 0x92, 0x0C, 0x46, 0x54, 0x85, 0x8E, 0x49, 0x21, 0x40,
0x0F, 0x4C, 0x61, 0xCF, 0x6D, 0x78, 0xDD, 0x32, 0xC9, 0x1E, 0x89, 0x23, 0xE5, 0x63, 0x80, 0xF2,
0xAD, 0x82, 0x17, 0x09, 0x78, 0x95, 0xDC, 0x67, 0x72, 0x77, 0x9B, 0x41, 0x59, 0x8F, 0xF3, 0xF0,
0x93, 0x00, 0x7C, 0x53, 0x86, 0x3E, 0x7C, 0xF7, 0xC3, 0xE1, 0xEC, 0xC4, 0xF4, 0x81, 0x2B, 0x43,
0x3F, 0x9A, 0xA6, 0xBA, 0xFD, 0xD7, 0xEA, 0xF9, 0xE5, 0x10, 0x29, 0xDE, 0x6A, 0x5A, 0x13, 0xFE,
0xC0, 0x89, 0x1B, 0xBB, 0x70, 0xEF, 0x59, 0xBB, 0xB1, 0xFB, 0xCA, 0x4D, 0x8B, 0x84, 0x55, 0xED,
0x53, 0x63, 0x39, 0xBF, 0xF1, 0x81, 0x4B, 0x43, 0xCA, 0x3F, 0x7F, 0xA3, 0xB6, 0xCE, 0xD1, 0xC7,
0xF7, 0xC7, 0x70, 0xA0, 0xD2, 0x27, 0xB9, 0xA1, 0xA2, 0x86, 0x1C, 0xBB, 0xC3, 0xCB, 0x39, 0x12,
0x7C, 0xE7, 0x54, 0xC7, 0x77, 0x85, 0x42, 0x87, 0xFB, 0x0C, 0xCA, 0x29, 0x5F, 0x01, 0xCB, 0xFE,
0x9C, 0xD2, 0x7B, 0xD1, 0x61, 0xB5, 0x8E, 0x0E, 0x79, 0x54, 0xFE, 0x9A, 0xC2, 0xDB, 0xF5, 0x4D,
0x94, 0x46, 0x92, 0x28, 0x97, 0x0F, 0x6E, 0x28, 0xDE, 0x4C, 0xBF, 0xDF, 0x77, 0xC8, 0xF1, 0x4B,
0xDF, 0x71, 0x98, 0xEF, 0xE8, 0x17, 0xD6, 0xCD, 0xEC, 0xBF, 0x37, 0x26, 0xCB, 0x10, 0x87, 0x7E,
0x97, 0x9A, 0xAE, 0xAB, 0x82, 0x42, 0xE5, 0x82, 0xA3, 0x89, 0xDB, 0x30, 0x63, 0x30, 0x5E, 0x0E,
0xD7, 0xA6, 0x3F, 0x6A, 0xF7, 0x61, 0xBE, 0x81, 0x0F, 0x43, 0xBA, 0x10, 0x32, 0x40, 0xFB, 0xCE,
0xA1, 0xA9, 0xBD, 0x2B, 0x20, 0xB5, 0x65, 0xF8, 0xB6, 0x82, 0x55, 0x1D, 0x22, 0x6F, 0x3F, 0xF2,
0x70, 0x41, 0xB6, 0xC9, 0x48, 0xD4, 0x94, 0x8F, 0x7D, 0x29, 0x20, 0x06, 0xDB, 0x87, 0xD2, 0xB9,
0xCD, 0x92, 0x57, 0xEE, 0x11, 0xE4, 0x62, 0x25, 0x17, 0x1A, 0xE8, 0x47, 0x2C, 0x4E, 0xCE, 0x02,
0xBF, 0x6C, 0x90, 0xE2, 0x1A, 0x88, 0x7B, 0xEE, 0xD9, 0x53, 0xB9, 0x9C, 0x4A, 0x65, 0x6B, 0xE0,
0x71, 0x7E, 0x45, 0xCD, 0xC4, 0xAB, 0x66, 0xF6, 0xB7, 0x7D, 0x63, 0x88, 0x06, 0xE9, 0x25, 0x8D,
0xFE, 0x2C, 0x3C, 0x2C, 0x6E, 0x13, 0xA5, 0x09, 0x17, 0xEE, 0x0E, 0x1A, 0xFA, 0xF9, 0xAF, 0xD6,
0x34, 0xCA, 0x75, 0x85, 0xA4, 0xD0, 0x93, 0x5F, 0x77, 0x5B, 0x83, 0x9E, 0xDE, 0x9B, 0x13, 0x01,
0xD2, 0x42, 0xF3, 0x8F, 0x3A, 0xE0, 0x39, 0xDB, 0x0F, 0x37, 0x27, 0x42, 0x08, 0x42, 0xE3, 0x26,
0xE4, 0xCD, 0x63, 0xD1, 0x3F, 0x62, 0x1C, 0xE5, 0xF2, 0x29, 0x1C, 0x75, 0xE6, 0x84, 0x96, 0x48,
0x6E, 0x59, 0x84, 0x2F, 0xE3, 0x98, 0xED, 0x2E, 0x8F, 0x79, 0x23, 0xD8, 0x44, 0x1E, 0x27, 0x08,
0xC1, 0x86, 0x7A, 0xD8, 0xAD, 0x8D, 0x07, 0x0C, 0x65, 0xB7, 0xAB, 0x93, 0x91, 0x9F, 0x3F, 0xB7,
0xE0, 0x82, 0x67, 0xD4, 0x69, 0x39, 0xA8, 0xAA, 0x1E, 0x4D, 0x3B, 0xF1, 0x06, 0x6E, 0x01, 0x47,
0x66, 0xB1, 0xFC, 0x5A, 0x89, 0x63, 0x42, 0xD6, 0xE2, 0x85, 0xE1, 0x76, 0x78, 0x4B, 0x4B, 0x5D,
0xEA, 0xD5, 0x45, 0x9E, 0x0F, 0xAA, 0x8D, 0x96, 0x1A, 0xCD, 0xE6, 0xE6, 0xCE, 0x99, 0x68, 0x01,
0xF7, 0x78, 0x28, 0x0A, 0x3A, 0x4C, 0xB2, 0x0D, 0x34, 0x79, 0x9B, 0xBD, 0xBB, 0x55, 0xF7, 0x41,
0x11, 0x71, 0xE1, 0x15, 0xFA, 0xE2, 0x1E, 0x74, 0xCB, 0xCF, 0xF7, 0x7A, 0x93, 0x1E, 0x2A, 0xB5,
0x12, 0x1F, 0x43, 0x2B, 0x8E, 0x71, 0x99, 0x44, 0xA6, 0x68, 0xF7, 0x73, 0x05, 0xE6, 0xF5, 0x66,
0x64, 0x33, 0x67, 0xCA, 0x51, 0x2F, 0xF3, 0xC2, 0xAB, 0xFB, 0x33, 0x92, 0xB1, 0x21, 0x4C, 0x74,
0x61, 0xB8, 0x72, 0x0A, 0x34, 0x23, 0xCB, 0x9F, 0xA9, 0xE5, 0xB3, 0x2F, 0x07, 0xF9, 0x88, 0x3A,
0xB8, 0x4C, 0xE6, 0x23, 0x7E, 0x98, 0x7B, 0x84, 0xC9, 0xC8, 0x62, 0xA5, 0x4B, 0x57, 0x2A, 0x78,
0xEF, 0x43, 0x0E, 0x7E, 0x42, 0xF1, 0x51, 0xDD, 0xF3, 0xF2, 0xC9, 0xC5, 0x95, 0x42, 0xEC, 0x62,
0x0C, 0x2C, 0x56, 0x0B, 0x20, 0x57, 0xBE, 0x4E, 0x2E, 0xE2, 0xE7, 0x99, 0x68, 0xCA, 0xF0, 0xCA,
0xB4, 0xCF, 0x8F, 0x6C, 0x1F, 0xFA, 0x0D, 0x97, 0xFE, 0x10, 0x9A, 0x43, 0x1A, 0xE0, 0xA0, 0x1A,
0x32, 0x48, 0xC8, 0xF4, 0x68, 0x3E, 0x7E, 0xF9, 0x82, 0x7C, 0xED, 0x76, 0x21, 0x97, 0x3D, 0x56,
0x5A, 0x78, 0x2B, 0xF6, 0x66, 0x6B, 0xC2, 0x7E, 0xE8, 0xAC, 0x0D, 0x44, 0xF2, 0xEE, 0x32, 0x77,
0xBD, 0x8E, 0x9B, 0x7C, 0x4F, 0xCC, 0xD1, 0x3F, 0xF7, 0x9B, 0x13, 0x7D, 0x07, 0xAC, 0xBC, 0x2C,
0xDD, 0xB9, 0xD6, 0x38, 0x1F, 0x2A, 0xC7, 0xE2, 0x08, 0x79, 0x49, 0xA3, 0x6A, 0x90, 0x8F, 0x8F,
0xA2, 0xB5, 0x5C, 0xF7, 0x14, 0x88, 0x88, 0x2F, 0x19, 0x52, 0x91, 0xEF, 0xEE, 0x6C, 0x37, 0x1F,
0x2C, 0x95, 0xCC, 0xBA, 0xEC, 0xB2, 0xD2, 0xE8, 0x2A, 0x50, 0xB4, 0x64, 0x5A, 0xD1, 0xD1, 0xD0,
0xE3, 0x28, 0x1A, 0xF8, 0x94, 0x88, 0x92, 0xB6, 0x17, 0xAF, 0x8B, 0xD3, 0x6B, 0xED, 0xAB, 0x06,
0xD8, 0x0C, 0xA0, 0x7E, 0xBA, 0x4A, 0xAD, 0x78, 0xC4, 0xC4, 0xA7, 0x82, 0x5E, 0xB2, 0xA4, 0x47,
0x85, 0x04, 0x5F, 0xE8, 0x87, 0xF8, 0x1B, 0x4B, 0xBF, 0x17, 0x4A, 0x9A, 0x76, 0xC5, 0x89, 0x47,
0x1C, 0x03, 0x2F, 0x17, 0xEA, 0xB1, 0x22, 0x7F, 0x9D, 0xDA, 0xCE, 0x4C, 0x04, 0x36, 0x46, 0xFF,
0xA3, 0x12, 0x2C, 0x55, 0x7D, 0x10, 0x1A, 0x9A, 0x71, 0x68, 0x52, 0xFA, 0x3D, 0x87, 0x7A, 0xEA,
0x18, 0xAC, 0x53, 0xA1, 0x24, 0x36, 0x69, 0x64, 0x71, 0x45, 0xCD, 0x93, 0x0D, 0xBB, 0x3E, 0xE1,
0x8F, 0xBD, 0xD8, 0x0A, 0xC5, 0x05, 0x69, 0xE6, 0x3C, 0x8F, 0x13, 0x0A, 0x94, 0x7B, 0x2D, 0x64,
0xE1, 0xC2, 0x31, 0x96, 0x89, 0xF6, 0x8F, 0xB4, 0x2C, 0xD2, 0xA3, 0x70, 0xE6, 0xD1, 0x40, 0x59,
0xE5, 0xAE, 0x01, 0x27, 0x16, 0x8E, 0x34, 0xCF, 0x42, 0x64, 0x46, 0xB4, 0x3A, 0xC2, 0x80, 0xFB,
0x97, 0x0A, 0x63, 0xCB, 0xCD, 0xB0, 0x70, 0x5B, 0xE1, 0x38, 0xEB, 0x74, 0x69, 0xD0, 0x86, 0xF4,
0xF3, 0xBC, 0xEC, 0x92, 0x92, 0x59, 0x0F, 0x56, 0xAF, 0x8D, 0x9B, 0x7C, 0x78, 0xB1, 0xB5, 0xE5,
0x5B, 0xC8, 0x7F, 0x51, 0x33, 0xB0, 0x6E, 0xCD, 0x75, 0x55, 0x49, 0x64, 0xB6, 0x31, 0x9A, 0xEA,
0x17, 0xFF, 0x9F, 0x1D, 0x7D, 0xB7, 0xA7, 0x16, 0x48, 0x49, 0xFB, 0x2E, 0x55, 0xB4, 0x2E, 0x1C,
0x57, 0x2B, 0x69, 0xEE, 0x87, 0xD1, 0x4B, 0x28, 0x00, 0xDA, 0xB9, 0xDA, 0x01, 0xF9, 0xFB, 0x5A,
0x81, 0x1A, 0x11, 0xEE, 0xB1, 0x36, 0x90, 0xD0, 0x8E, 0xC5, 0xF2, 0x9C, 0xCF, 0xA2, 0xC5, 0xA5,
0x70, 0xC8, 0x20, 0x51, 0x6D, 0xBE, 0x5D, 0x76, 0xE0, 0xE7, 0x6F, 0x48, 0x91, 0x04, 0x2C, 0xA9,
0xAB, 0x4C, 0xB3, 0xA0, 0xD4, 0xF2, 0x03, 0x99, 0x8A, 0xA7, 0x4F, 0x87, 0x98, 0xEE, 0x2C, 0x92,
0x28, 0x07, 0x14, 0xA4, 0x96, 0xE5, 0x9F, 0xDF, 0x08, 0x33, 0x23, 0xC2, 0xEC, 0xFB, 0xA3, 0x6C,
0x36, 0x3D, 0x94, 0x8F, 0x4E, 0x80, 0x3D, 0x03, 0x41, 0x59, 0xC0, 0x5B, 0xE8, 0x27, 0x8D, 0x9F,
0xE4, 0xBA, 0x3F, 0x15, 0x11, 0x0B, 0x9D, 0x9E, 0x11, 0xE8, 0xDE, 0x2D, 0x9C, 0xD8, 0xF3, 0x73,
0x68, 0x38, 0xE5, 0x49, 0x8E, 0x58, 0x71, 0xF6, 0x25, 0x29, 0x86, 0x93, 0xD8, 0x2A, 0xC9, 0xE6,
0x9C, 0x2E, 0xFC, 0xD1, 0x0E, 0xEF, 0x3F, 0x74, 0x81, 0x24, 0x84, 0x24, 0xA9, 0x11, 0xCA, 0x8C,
0xBE, 0x14, 0x65, 0xCD, 0xF5, 0xAA, 0xFB, 0x8B, 0x77, 0x7A, 0x80, 0xA8, 0x99, 0x68, 0x60, 0x8E,
0xA6, 0x58, 0x0B, 0x1A, 0x1E, 0xBC, 0xD8, 0xCC, 0xCC, 0xD0, 0x91, 0x4C, 0x43, 0xFC, 0xE9, 0x44,
0xD4, 0x33, 0xC3, 0x50, 0x63, 0xDC, 0x72, 0xCE, 0x9B, 0x69, 0x2D, 0x87, 0xA3, 0xBE, 0x4C, 0xFF,
0x10, 0x6A, 0xC8, 0x68, 0xBC, 0x8E, 0x58, 0x5C, 0x2D, 0x08, 0xA3, 0x61, 0xD1, 0x23, 0x17, 0x14,
0xAD, 0x24, 0x6C, 0x36, 0xDB, 0x4E, 0xCF, 0xF3, 0x59, 0x05, 0xDA, 0x24, 0xA1, 0x90, 0x7F, 0x29,
0xC2, 0xC7, 0xD5, 0x6B, 0x1A, 0x35, 0xA2, 0xA7, 0xB1, 0x27, 0x0C, 0x3F, 0xC5, 0x1D, 0x12, 0x11,
0xE7, 0xAE, 0x79, 0xB4, 0xEE, 0xD1, 0x5B, 0xF9, 0xB1, 0xEC, 0xB8, 0x3C, 0x00, 0x43, 0x83, 0x63,
0xF6, 0xA5, 0x98, 0x4A, 0xF9, 0xF3, 0x32, 0xC9, 0xAB, 0xD2, 0xFF, 0x9E, 0xE3, 0xE4, 0x89, 0x22,
0x61, 0x5B, 0xAE, 0xEA, 0x95, 0x50, 0xC5, 0x7D, 0x8C, 0x6D, 0x48, 0xFB, 0xBE, 0x50, 0xF9, 0x85,
0xAD, 0xEB, 0x06, 0xA5, 0xCE, 0x0E, 0x71, 0x7F, 0x3A, 0xB7, 0xCC, 0x06, 0x2B, 0x9E, 0x90, 0x60,
0xAD, 0xA2, 0x6C, 0x74, 0x92, 0xF6, 0x9C, 0xC6, 0x38, 0x1A, 0xD3, 0x45, 0x4E, 0xC2, 0x5D, 0x3F,
0x42, 0x7B, 0x77, 0xA7, 0x63, 0x69, 0x2C, 0x9F, 0x85, 0xFF, 0x56, 0x1E, 0x0E, 0x9F, 0xB0, 0xDA,
0x5A, 0x1A, 0x95, 0x5A, 0x11, 0x0C, 0xC1, 0x82, 0x54, 0xF9, 0x8A, 0xE2, 0x8E, 0x11, 0x94, 0x9F,
0x2F, 0x62, 0x35, 0x2A, 0x3D, 0x7F, 0x38, 0x40, 0xA4, 0xED, 0x97, 0x95, 0x93, 0xC2, 0x98, 0xB0,
0xEA, 0xA7, 0x80, 0x34, 0xBC, 0x6B, 0xD6, 0xC2, 0xC3, 0xF3, 0xB7, 0x87, 0xF6, 0x3F, 0x3E, 0xDA,
0xD8, 0x9E, 0x1D, 0x10, 0x8C, 0x5C, 0xAC, 0xE5, 0xCA, 0x72, 0x6D, 0x92, 0xF5, 0xEC, 0x84, 0x31,
0x12, 0x28, 0x3D, 0xA8, 0x30, 0xFE, 0x41, 0xD0, 0x20, 0x2B, 0xE9, 0xE9, 0x34, 0xE2, 0xBA, 0x8D,
0xDB, 0xAA, 0x1E, 0x7E, 0x38, 0x7D, 0x32, 0x27, 0xB3, 0x83, 0x97, 0x9A, 0x1C, 0x6F, 0x45, 0xDC,
0x74, 0x20, 0xBE, 0x8F, 0x7D, 0xC0, 0xDA, 0x78, 0x06, 0xBC, 0x2F, 0xF9, 0x44, 0x4B, 0xDA, 0xA2,
0xAE, 0x09, 0x2C, 0x8E, 0xD2, 0xD4, 0x8E, 0xC4, 0x05, 0x26, 0xAB, 0xBB, 0xD9, 0x99, 0x7E, 0x48,
0x6A, 0xB5, 0x97, 0x2A, 0x5A, 0xA1, 0xAF, 0x92, 0x03, 0xEF, 0x05, 0xC0, 0x7A, 0x07, 0x46, 0x12,
0x0F, 0x8D, 0xCA, 0x62, 0x78, 0x69, 0x98, 0x00, 0x08, 0x2E, 0xF3, 0x55, 0xAA, 0x56, 0xEA, 0xEC,
0xC6, 0xB6, 0x55, 0x60, 0x27, 0x35, 0x9A, 0x6F, 0xE2, 0xE1, 0x49, 0x6C, 0x83, 0x5B, 0x0F, 0x08,
0x1E, 0x1A, 0x1E, 0x94, 0x81, 0xFB, 0xB5, 0x26, 0xD5, 0x09, 0x9C, 0xD7, 0xC4, 0xA2, 0x38, 0x47,
0x2E, 0x87, 0xEB, 0xE7, 0xB0, 0x36, 0x7D, 0xFD, 0xE4, 0x95, 0x4A, 0xAD, 0xD5, 0xE2, 0x39, 0xCB,
0xEB, 0x49, 0x2B, 0xBF, 0xB6, 0x5C, 0x84, 0x07, 0x8E, 0x12, 0x70, 0x7F, 0xBE, 0xFB, 0xDD, 0x9B,
0x28, 0x18, 0x10, 0x6C, 0x12, 0x2F, 0x10, 0x9D, 0xB7, 0x39, 0x2B, 0x01, 0x54, 0xAC, 0x60, 0x4E,
0xF7, 0x4D, 0x2F, 0x82, 0x0F, 0xBC, 0x20, 0xD9, 0xB7, 0x67, 0xBF, 0x41, 0x44, 0x27, 0xA1, 0xBC,
0xA5, 0x81, 0x7C, 0x58, 0xC6, 0x9F, 0x79, 0x1F, 0x25, 0x6F, 0x46, 0x65, 0x29, 0xA6, 0x18, 0x0C,
0xD6, 0xB5, 0x5F, 0x74, 0x47, 0xD0, 0x44, 0xD2, 0x97, 0x8B, 0x3C, 0x34, 0x96, 0xED, 0x57, 0x97,
0xE8, 0xD8, 0x4B, 0xE9, 0x42, 0x09, 0xBE, 0xE2, 0xB2, 0x6C, 0x5A, 0xE9, 0xEA, 0x8A, 0xB2, 0x14,
0x71, 0x7A, 0xC8, 0x6C, 0xE2, 0xAD, 0xEF, 0x04, 0x3D, 0x1A, 0x42, 0x16, 0xD8, 0x55, 0xE7, 0xA2,
0xDE, 0xDB, 0xA5, 0x4A, 0x96, 0xCD, 0xE0, 0x6F, 0x64, 0x23, 0x5C, 0xCB, 0x3C, 0x6D, 0x80, 0x62,
0xB7, 0xA4, 0x14, 0x2D, 0x10, 0x41, 0xF1, 0x93, 0x09, 0xAF, 0xCF, 0x1A, 0x79, 0x28, 0xB9, 0x76,
0x0E, 0xAD, 0x3C, 0xE9, 0x5D, 0x0A, 0x2D, 0x8C, 0xA6, 0x18, 0xEA, 0xD1, 0xF3, 0x7B, 0x7D, 0x12,
0x87, 0x34, 0x40, 0xCB, 0x56, 0xCB, 0xA1, 0x24, 0xF0, 0x09, 0x65, 0x39, 0x4F, 0x6D, 0x41, 0x50,
0xD5, 0x41, 0x0E, 0x1B, 0x5E, 0x93, 0x39, 0xDF, 0x92, 0x86, 0x11, 0x7D, 0xD1, 0x30, 0x27, 0xFE,
0xA9, 0x42, 0xA4, 0x07, 0xCA, 0x9D, 0x6E, 0xDD, 0x75, 0xBA, 0x49, 0xA5, 0x04, 0xFC, 0xF4, 0xFC,
0x35, 0x22, 0x46, 0xC7, 0x50, 0x03, 0x28, 0xD0, 0xBE, 0x69, 0xCF, 0xD1, 0xD7, 0xE1, 0x17, 0xC1,
0xE7, 0xC1, 0xFE, 0x24, 0xAB, 0x0C, 0x74, 0x6E, 0x43, 0x58, 0x8A, 0xD0, 0x05, 0xB2, 0x65, 0xE1,
0xA3, 0xFE, 0x45, 0x59, 0xBC, 0x39, 0xA5, 0x92, 0xB6, 0x82, 0x09, 0x1F, 0xB2, 0x6A, 0x22, 0x1C,
0xEC, 0x9C, 0x86, 0x3D, 0xA0, 0xEB, 0x51, 0x4F, 0x3D, 0x62, 0xD2, 0x50, 0x14, 0xD9, 0xF5, 0x3D,
0xFD, 0x2B, 0x82, 0x3E, 0x4F, 0x9D, 0x3C, 0xCD, 0xF3, 0x33, 0x81, 0xC7, 0xD0, 0xF5, 0x9C, 0xFF,
0x68, 0x46, 0x07, 0x9C, 0xB3, 0x38, 0x3C, 0xC8, 0x91, 0xB4, 0xFA, 0x9A, 0xD0, 0xDA, 0xD5, 0x2F,
0x4C, 0x25, 0xED, 0xDE, 0xF0, 0xFD, 0xDD, 0x2D, 0x5D, 0xB7, 0x44, 0xA3, 0x98, 0x92, 0xAA, 0xA9,
0x01, 0xDA, 0x1F, 0x96, 0xF7, 0xE7, 0x9F, 0x85, 0x7A, 0xB8, 0xF2, 0x97, 0xB2, 0x5B, 0xE3, 0x27,
0x75, 0x4E, 0x18, 0xF9, 0xF7, 0x69, 0x90, 0xEC, 0x30, 0xE9, 0x4C, 0xB6, 0x8A, 0x1F, 0x81, 0xF8,
0xE3, 0x52, 0x93, 0xF3, 0xC1, 0x78, 0x15, 0x32, 0x5D, 0x9F, 0xD3, 0x22, 0x3D, 0x02, 0x7C, 0x68,
0x68, 0xAB, 0x1C, 0x3F, 0x8C, 0xF7, 0x38, 0x2B, 0x0C, 0x47, 0xF9, 0x04, 0xAF, 0xA3, 0xD5, 0xA1,
0x16, 0xA8, 0xC5, 0x27, 0xD5, 0x10, 0x28, 0x94, 0x8F, 0x37, 0x55, 0x4C, 0x43, 0x50, 0x37, 0x5E,
0xD3, 0xF8, 0xF3, 0xD8, 0xB0, 0x67, 0x07, 0x66, 0x7F, 0x20, 0x59, 0x0A, 0xD6, 0xD0, 0x65, 0x82,
0x1D, 0xB1, 0xF6, 0xA4, 0x16, 0x2E, 0x51, 0x07, 0xC9, 0x9D, 0xFD, 0xCD, 0xDD, 0x67, 0xA1, 0x74,
0x37, 0x4C, 0x39, 0x97, 0x84, 0x5F, 0x62, 0x85, 0xFD, 0x7C, 0xBE, 0xDA, 0x50, 0x1F, 0xF5, 0x01,
0xC8, 0xA0, 0xE5, 0x90, 0xD4, 0xB0, 0x77, 0x41, 0xAD, 0x90, 0x17, 0xBC, 0x8B, 0x3C, 0x1E, 0x3E,
0x51, 0x43, 0xDF, 0x61, 0x1D, 0xA2, 0x81, 0x34, 0x10, 0x35, 0x6F, 0xAE, 0xF8, 0x92, 0x6E, 0xA0,
0x3E, 0xB5, 0x58, 0xBB, 0x4F, 0x35, 0x51, 0xE0, 0x94, 0x3E, 0x29, 0x3E, 0xFD, 0xC8, 0x59, 0xAF,
0x3F, 0x66, 0x88, 0xEE, 0x7F, 0x31, 0x36, 0xA4, 0x4C, 0x7C, 0x3C, 0x9C, 0x02, 0x55, 0x97, 0xAB,
0xDD, 0xB7, 0xDD, 0x49, 0x0C, 0xFF, 0xF8, 0xB7, 0x81, 0x5F, 0x10, 0xED, 0xA2, 0x4A, 0x47, 0xE1,
0x80, 0xD4, 0x04, 0x05, 0x46, 0xCA, 0x87, 0xA3, 0x80, 0x29, 0xF3, 0x7D, 0xBF, 0xF9, 0x0D, 0xA1,
0xC4, 0xF6, 0xCF, 0x6A, 0x5C, 0x7C, 0x5A, 0x78, 0xCE, 0x52, 0x70, 0x4D, 0xE1, 0x73, 0x56, 0xED,
0xB5, 0x29, 0x5D, 0x92, 0xCF, 0xBC, 0x02, 0xBF, 0x04, 0xBA, 0x35, 0x33, 0x48, 0xA8, 0xCA, 0xD6,
0xCD, 0xC6, 0x5F, 0xD8, 0x20, 0xD9, 0x78, 0x17, 0x7C, 0x3F, 0x45, 0x33, 0x25, 0xC0, 0x38, 0x18,
0x7D, 0x43, 0xA7, 0xF8, 0x7A, 0x4B, 0x19, 0x9B, 0xFF, 0x8F, 0x18, 0x0F, 0xC3, 0xB7, 0x60, 0xA0,
0x21, 0x7E, 0xC7, 0x91, 0xAD, 0x3D, 0xAA, 0x44, 0x64, 0x7A, 0x33, 0x4B, 0x2F, 0x4F, 0x76, 0x85,
0x2D, 0xFE, 0xA7, 0x36, 0x04, 0x08, 0x4E, 0x3B, 0x83, 0x33, 0x1B, 0x25, 0xFD, 0xED, 0x69, 0x17,
0x66, 0x0A, 0x4D, 0x21, 0x11, 0x42, 0xC6, 0xC7, 0xD9, 0x7E, 0xC0, 0x66, 0x1A, 0xD5, 0xF5, 0xA3,
0x97, 0x6C, 0xEE, 0x63, 0xBA, 0xC5, 0x2C, 0xF0, 0x36, 0x8B, 0xE3, 0xC2, 0x23, 0x7A, 0x75, 0x7C,
0x60, 0x78, 0x22, 0x8B, 0x26, 0xBA, 0x08, 0x3A, 0x9D, 0x92, 0x23, 0x14, 0xFA, 0xB0, 0x86, 0x75,
0x8E, 0x31, 0x39, 0xD2, 0x54, 0xA6, 0xE5, 0xC3, 0x73, 0xA7, 0xA4, 0x23, 0x29, 0x98, 0xE5, 0x1C,
0xF9, 0x6C, 0x24, 0xAA, 0x2A, 0x25, 0x39, 0xC3, 0xF0, 0x7C, 0xD2, 0x42, 0xFD, 0x56, 0xC0, 0x2B,
0x4F, 0xBD, 0x1C, 0x99, 0x18, 0xF8, 0x4C, 0x50, 0xCF, 0x7F, 0x5D, 0xF2, 0x14, 0x90, 0x86, 0x09,
0xBE, 0x03, 0x75, 0x17, 0x35, 0xA4, 0x52, 0x89, 0x6B, 0x24, 0x7E, 0x73, 0xA8, 0xCB, 0x7C, 0x05,
0x0E, 0x73, 0x8C, 0x72, 0xCD, 0x58, 0x5C, 0xBB, 0x7A, 0xF4, 0xBC, 0x4F, 0x27, 0xE7, 0xA5, 0xF1,
0x7E, 0x83, 0xED, 0x45, 0x9E, 0x34, 0x75, 0x1C, 0x15, 0x06, 0xDA, 0x6F, 0x8E, 0x26, 0x02, 0x2F,
0x9B, 0x03, 0x03, 0x74, 0x10, 0x47, 0x33, 0x90, 0x23, 0x1D, 0xFE, 0x2F, 0x7B, 0x48, 0x59, 0xEE,
0xF2, 0xA4, 0xA3, 0x7C, 0x60, 0xA6, 0x80, 0xDE, 0x82, 0x74, 0x53, 0xA9, 0x0A, 0xEB, 0x4E, 0x63,
0x93, 0x16, 0xAC, 0x23, 0x37, 0x01, 0x61, 0x4A, 0xBE, 0x84, 0x5F, 0xCB, 0x08, 0x29, 0x77, 0x60,
0xF5, 0xD9, 0x60, 0xE9, 0x75, 0x15, 0x20, 0xD6, 0xA5, 0x12, 0x90, 0xDB, 0x1E, 0x74, 0x9D, 0x91,
0xCD, 0xD7, 0x6D, 0xAC, 0x75, 0xC5, 0xA3, 0xB9, 0xBE, 0xCF, 0xCE, 0xA7, 0xB2, 0x78, 0x58, 0xBB,
0x5D, 0x19, 0x0D, 0x59, 0xF2, 0x4B, 0x0B, 0x40, 0x60, 0xA8, 0x34, 0x2F, 0x08, 0xE7, 0xE4, 0xBB,
0x77, 0x4A, 0xB1, 0xC7, 0x2F, 0x31, 0x4C, 0x93, 0xE4, 0x59, 0xCE, 0x9D, 0x2F, 0x22, 0xC3, 0xC0,
0x1B, 0xE3, 0x77, 0xFD, 0xA5, 0xB9, 0x9C, 0x32, 0x26, 0x81, 0x88, 0xAF, 0x18, 0xCC, 0xE5, 0x26,
0x01, 0xE5, 0x5E, 0x25, 0xB3, 0x17, 0x19, 0x86, 0xAD, 0xAE, 0xF4, 0x13, 0x00, 0x1B, 0xA8, 0xA5,
0xE0, 0x14, 0xC6, 0x54, 0x4B, 0x99, 0x3D, 0x68, 0xF0, 0xF3, 0xBA, 0x31, 0xF8, 0x74, 0x6D, 0xED,
0xB0, 0xA7, 0x5E, 0xCD, 0x62, 0xFD, 0x38, 0x05, 0xAE, 0x26, 0xAC, 0x86, 0xE2, 0x20, 0x8A, 0xA4,
0xC0, 0x3A, 0x0B, 0x57, 0x24, 0x62, 0x1A, 0x73, 0x7C, 0xFE, 0x42, 0x24, 0x94, 0x08, 0x56, 0x06,
0xEE, 0x1E, 0xE2, 0xF2, 0x81, 0xCA, 0xB3, 0x72, 0xD4, 0x26, 0x79, 0xFD, 0xAA, 0x71, 0x70, 0x57,
0x77, 0xC2, 0x28, 0xB9, 0xA0, 0x8F, 0x0C, 0xB7, 0x08, 0xAE, 0xD6, 0xB9, 0x80, 0x7D, 0xEC, 0x74,
0x2A, 0xE7, 0x59, 0x08, 0x27, 0x43, 0x18, 0xDF, 0x78, 0xEB, 0xF6, 0xC9, 0xE2, 0xF1, 0x70, 0x77,
0xC7, 0x3E, 0x7E, 0x1D, 0x5F, 0xED, 0x49, 0x0F, 0xF4, 0xBE, 0x76, 0x81, 0xC9, 0x91, 0xDC, 0x9E,
0xF5, 0xEC, 0x2A, 0x14, 0xF7, 0xE5, 0x25, 0xD7, 0x61, 0x43, 0x62, 0x87, 0x4D, 0x5E, 0x30, 0xE7,
0x1E, 0xF4, 0xFA, 0x78, 0x90, 0xDD, 0xD6, 0x99, 0x34, 0xF5, 0x2D, 0xE3, 0x77, 0x5A, 0x15, 0xB4,
0x2B, 0xAC, 0xA8, 0x8E, 0xA0, 0x68, 0x89, 0xA3, 0xD2, 0x3A, 0xE1, 0xB6, 0x3A, 0x1F, 0xD3, 0x7D,
0x6F, 0xBF, 0x47, 0xC4, 0x9A, 0x15, 0x66, 0x5B, 0xE6, 0x89, 0xBC, 0x37, 0xAE, 0xB9, 0xE2, 0xDD,
0x23, 0xAF, 0xCF, 0x92, 0xB6, 0x50, 0x4E, 0x0D, 0xDE, 0x2C, 0x3C, 0x84, 0x36, 0x08, 0x96, 0xC3,
0x91, 0x02, 0x97, 0x8F, 0xE9, 0x62, 0x74, 0x2C, 0x0C, 0xE1, 0xA4, 0x0C, 0x85, 0xD7, 0x7E, 0xB0,
0xD9, 0x2D, 0x0B, 0x14, 0x53, 0x70, 0xC8, 0xC5, 0x1A, 0x92, 0x73, 0x5F, 0xD2, 0x76, 0x81, 0x5F,
0x77, 0xAC, 0xEE, 0x7D, 0x1F, 0xFD, 0x1C, 0xFD, 0xE4, 0xEC, 0xBF, 0xBA, 0x2E, 0xDC, 0x8D, 0x5B,
0xDE, 0x6F, 0xE0, 0xC7, 0xA3, 0x37, 0x51, 0xC5, 0xE9, 0x44, 0x16, 0x77, 0xDB, 0x48, 0x43, 0x9B,
0xFD, 0x4D, 0x82, 0x25, 0xF3, 0xE4, 0x4D, 0xC6, 0x76, 0xF5, 0x34, 0xBA, 0x2A, 0xA3, 0x58, 0x42,
0x99, 0x78, 0x2E, 0xAC, 0xB3, 0x04, 0x04, 0x2C, 0x91, 0xF4, 0xC3, 0x8A, 0xC9, 0xE7, 0x66, 0xF8,
0x6D, 0xAE, 0xF5, 0x28, 0x99, 0xD9, 0x44, 0xB8, 0xFC, 0x29, 0x82, 0x3A, 0x82, 0x02, 0xEC, 0x2A,
0x4F, 0x08, 0xF9, 0x9C, 0xE7, 0xDB, 0x64, 0xE9, 0x2B, 0x14, 0x50, 0xA2, 0xB2, 0x3A, 0x74, 0x1A,
0x62, 0x51, 0xC6, 0xC1, 0x60, 0x88, 0x4E, 0x09, 0xB3, 0x44, 0x1E, 0x47, 0x31, 0x2C, 0x0B, 0x9D,
0xAF, 0x3F, 0x5B, 0x6F, 0x70, 0x45, 0x5D, 0xBC, 0xDA, 0x6E, 0x7A, 0x3C, 0x07, 0x3D, 0x2E, 0x93,
0x35, 0xF8, 0x4D, 0x42, 0x43, 0x14, 0x0B, 0x68, 0xF8, 0xE7, 0xD9, 0x5A, 0x78, 0x8E, 0x2C, 0xF4,
0x36, 0xB5, 0x07, 0x8A, 0xD2, 0x21, 0x3A, 0x29, 0xB6, 0x7B, 0x12, 0xD2, 0x22, 0x4A, 0xC7, 0x5B,
0xCC, 0x66, 0x04, 0xE8, 0x8B, 0xB2, 0x5E, 0xB2, 0x59, 0x39, 0x39, 0x6D, 0x21, 0x16, 0x24, 0x10,
0x04, 0xC3, 0xC7, 0xA2, 0x50, 0x37, 0x8D, 0xAF, 0x2C, 0x87, 0xF3, 0x36, 0x85, 0xC4, 0x42, 0x3F,
0x44, 0xFB, 0x7B, 0xB9, 0x8D, 0xF1, 0x58, 0x5C, 0xCD, 0xA4, 0x88, 0x5C, 0xF1, 0x53, 0x45, 0xF5,
0x63, 0xF9, 0x63, 0x72, 0x39, 0x8B, 0x62, 0xBC, 0xF6, 0xB3, 0xF3, 0x9E, 0xD7, 0xC3, 0x96, 0x3A,
0xF6, 0x6B, 0x09, 0xB8, 0x08, 0x6A, 0x00, 0x52, 0xAC, 0x73, 0x91, 0x38, 0x72, 0x5D, 0xE4, 0x1A,
0x1F, 0xE7, 0x81, 0xED, 0x9C, 0xB2, 0xFD, 0x72, 0xDE, 0xE2, 0x18, 0x25, 0x70, 0xE8, 0x2E, 0x56,
0x5C, 0xED, 0xFD, 0x21, 0x43, 0x99, 0x20, 0x3D, 0x82, 0x20, 0x4F, 0xDF, 0x4C, 0xCF, 0x37, 0xC5,
0xB1, 0x48, 0x2D, 0x26, 0x92, 0xE5, 0x2B, 0xB5, 0xC8, 0xBB, 0xC4, 0x31, 0x4E, 0x5B, 0x29, 0x42,
0xF8, 0xFF, 0x93, 0x19, 0x4B, 0xBE, 0x87, 0x46, 0xC0, 0x04, 0xE0, 0x11, 0xA2, 0xB6, 0x63, 0x5D,
0xF3, 0x29, 0xFC, 0xC3, 0xF9, 0x3A, 0xBF, 0xDD, 0xA4, 0xBA, 0x8D, 0x35, 0x65, 0x90, 0xE6, 0x61,
0x9C, 0xB1, 0xBF, 0x50, 0x03, 0xF8, 0x24, 0xA4, 0xC5, 0x95, 0xC5, 0x84, 0x8D, 0x33, 0x31, 0xC0,
0x3B, 0x92, 0x01, 0x8C, 0xA5, 0xA2, 0xD8, 0xB6, 0xCB, 0xC5, 0xE6, 0x83, 0x30, 0x6D, 0xA0, 0xCC,
0x18, 0x4E, 0x11, 0xE6, 0x20, 0x66, 0xC3, 0x45, 0x85, 0x9A, 0x19, 0x36, 0x10, 0x20, 0x86, 0xB3,
0x7D, 0x73, 0xAA, 0x1D, 0xE6, 0x2D, 0x5B, 0xE0, 0xC1, 0xA1, 0x10, 0xDC, 0xBC, 0x86, 0xCE, 0x35,
0x13, 0xEA, 0x8F, 0x66, 0x5E, 0x53, 0x42, 0x10, 0x28, 0xB3, 0x5D, 0x62, 0xC6, 0xC1, 0x76, 0x99,
0x82, 0xAA, 0x1D, 0xEF, 0x9C, 0x96, 0xD7, 0x6F, 0x15, 0x40, 0x11, 0x8D, 0xC4, 0x14, 0x88, 0x99,
0x26, 0x53, 0x0D, 0x8B, 0xA9, 0xAF, 0xCE, 0x1B, 0x28, 0x18, 0x6E, 0x0F, 0x12, 0x24, 0x34, 0xC0,
0x82, 0x48, 0x7C, 0xD2, 0xE8, 0xD6, 0xCE, 0xB7, 0xDC, 0xD5, 0x37, 0xD5, 0x93, 0x12, 0x02, 0x40,
0xEA, 0xE8, 0x3B, 0x22, 0x1A, 0x54, 0x6B, 0x62, 0x59, 0xDB, 0x3A, 0x8C, 0xA8, 0xFC, 0x70, 0x94,
0xC7, 0x75, 0x14, 0x0E, 0xF5, 0x54, 0x16, 0x17, 0x85, 0xC5, 0x7E, 0x65, 0x71, 0xFF, 0x1E, 0x3D,
0x90, 0x7B, 0xCD, 0xE3, 0xD8, 0x37, 0x2C, 0x69, 0xD2, 0xAF, 0xF4, 0xA0, 0x4A, 0x33, 0x9E, 0x58,
0x26, 0x01, 0x7F, 0xFD, 0xE6, 0x47, 0x68, 0x27, 0x6B, 0xC4, 0xC3, 0xB8, 0x9D, 0x49, 0x2B, 0x6B,
0x42, 0xE4, 0x08, 0xB4, 0xA4, 0xB5, 0x8F, 0xB6, 0xCB, 0x4C, 0x61, 0x6C, 0x78, 0x57, 0xC1, 0x52,
0xA3, 0x07, 0xEE, 0xAC, 0xB8, 0xB6, 0xBB, 0x62, 0xEB, 0x4B, 0xC7, 0x9B, 0xE5, 0xA7, 0x3F, 0x7E,
0x3E, 0x5C, 0x42, 0x4E, 0x74, 0x14, 0x7B, 0x44, 0x01, 0x27, 0x53, 0x02, 0x5D, 0x35, 0x72, 0x1A,
0xFC, 0x70, 0xBD, 0xFE, 0xCB, 0x8B, 0x29, 0x9E, 0x6D, 0x1A, 0x44, 0x3E, 0x84, 0xFF, 0xFA, 0xE5,
0x1B, 0xB7, 0x35, 0xDF, 0xE6, 0x28, 0x92, 0xD3, 0xEC, 0xD0, 0xEF, 0x38, 0x4F, 0x57, 0xD7, 0xDD,
0x01, 0xE9, 0xBE, 0x7D, 0x51, 0x95, 0xA8, 0xB6, 0x58, 0xD6, 0x88, 0xD8, 0x34, 0x25, 0x7B, 0xF6,
0x5C, 0xD6, 0xB2, 0x70, 0x2B, 0x86, 0x29, 0xD1, 0x3E, 0x9D, 0x5E, 0xC3, 0xD1, 0x4C, 0xDC, 0xAF,
0x88, 0x58, 0x72, 0x22, 0x06, 0x1A, 0x9A, 0xA2, 0x1F, 0x7B, 0x59, 0x2C, 0x3B, 0x52, 0x8F, 0x76,
0xB2, 0x89, 0x8D, 0xDD, 0x39, 0xDD, 0xC9, 0x35, 0x0C, 0x8F, 0x6C, 0xA6, 0x6B, 0xC5, 0xCB, 0xC3,
0xBA, 0xE5, 0x7F, 0x54, 0xA3, 0xC3, 0x00, 0x26, 0x0E, 0xAB, 0x17, 0xAA, 0x45, 0x33, 0x6F, 0x1D,
0x8A, 0x48, 0x0D, 0xAA, 0xA4, 0x5B, 0x73, 0xAE, 0x7C, 0x67, 0x40, 0xB2, 0x65, 0x7C, 0x4B, 0xC3,
0x0E, 0x3B, 0xD2, 0x29, 0x52, 0xFB, 0x2D, 0x35, 0x9D, 0x9D, 0x9B, 0xD3, 0xA4, 0x92, 0x04, 0x62,
0x1C, 0x54, 0x96, 0xA3, 0x9A, 0x2A, 0xFE, 0x46, 0x38, 0x2E, 0x51, 0x56, 0x95, 0x5E, 0x2B, 0xBF,
0x27, 0xF4, 0x2F, 0x79, 0x25, 0x2D, 0xA3, 0xC7, 0x34, 0xEF, 0xA6, 0xD3, 0x52, 0x19, 0x46, 0xCA,
0x4D, 0xCE, 0xF0, 0xA6, 0x76, 0xFD, 0x6A, 0x3D, 0x31, 0x77, 0x61, 0xAC, 0x1F, 0xEC, 0x9A, 0x0F,
0x4D, 0xEA, 0x7B, 0xD5, 0x99, 0xE9, 0xD5, 0x95, 0x5D, 0xEF, 0x81, 0x6C, 0x62, 0x92, 0xA4, 0x81,
0x97, 0x95, 0x43, 0x16, 0xFA, 0xC0, 0xF8, 0x30, 0x3A, 0xA3, 0xCC, 0x32, 0x31, 0x2B, 0xA1, 0x87,
0x40, 0x40, 0xDA, 0x4D, 0x97, 0x53, 0x27, 0xB9, 0x90, 0xDA, 0xD5, 0xCD, 0xA4, 0xB7, 0x59, 0x27,
0x34, 0xAD, 0xC4, 0x9B, 0x25, 0x9C, 0xB6, 0xB3, 0x41, 0x56, 0xC3, 0x90, 0xD7, 0xC7, 0xB1, 0x24,
0x40, 0x82, 0x59, 0x29, 0x1C, 0x1B, 0x4B, 0xE4, 0x99, 0xEC, 0x67, 0xA2, 0x51, 0x80, 0x31, 0x4C,
0x18, 0x1E, 0x7B, 0x5C, 0x2E, 0xF0, 0xAF, 0x90, 0xB1, 0x0B, 0x22, 0x81, 0xE6, 0x0F, 0x57, 0x20,
0xFC, 0x81, 0xC2, 0x09, 0x78, 0xBD, 0x84, 0xE7, 0xE0, 0xC1, 0x03, 0x47, 0xFD, 0x4C, 0xAB, 0x86,
0x87, 0x1D, 0x21, 0x3E, 0x75, 0x41, 0xDF, 0x64, 0xD3, 0x51, 0xEA, 0x13, 0xEC, 0x05, 0x83, 0x40,
0x4D, 0xD7, 0xEC, 0x91, 0x8C, 0x35, 0x6A, 0xC2, 0xC8, 0x47, 0xDB, 0x50, 0x5A, 0x98, 0xA2, 0x45,
0xE8, 0x3A, 0x6E, 0x33, 0x67, 0x01, 0x88, 0x23, 0xDF, 0xD6, 0x86, 0x54, 0x4E, 0x76, 0x9E, 0xF0,
0x24, 0x5A, 0xD2, 0xBD, 0x00, 0x81, 0xCB, 0x87, 0xC5, 0xA0, 0x29, 0x4B, 0xEF, 0x1E, 0xB8, 0x88,
0x7E, 0xC2, 0xE3, 0x3F, 0x68, 0x38, 0xBA, 0x31, 0x3F, 0x51, 0x05, 0x3B, 0xA5, 0x24, 0x1F, 0x26,
0x45, 0xE5, 0xBF, 0xB4, 0x2F, 0x27, 0x39, 0x7F, 0x1F, 0x1B, 0x17, 0x0A, 0xEA, 0x87, 0x30, 0xA3,
0x75, 0x5B, 0x70, 0xF0, 0x94, 0xC6, 0xCB, 0x96, 0xB2, 0x20, 0x62, 0x2A, 0x90, 0xBE, 0x8F, 0xB9,
0x21, 0xD9, 0x7D, 0x01, 0x8F, 0x75, 0x21, 0x05, 0x06, 0x3D, 0xBC, 0xD6, 0xE1, 0xEB, 0x3A, 0x24,
0x4C, 0x53, 0x72, 0x6D, 0x6C, 0xF0, 0xDA, 0xAD, 0xE7, 0x18, 0x01, 0x93, 0x21, 0x30, 0x19, 0xB1,
0x2E, 0xDB, 0x39, 0x1C, 0xC7, 0xDA, 0x99, 0xA7, 0xA0, 0x09, 0x14, 0x48, 0xDC, 0xDD, 0x00, 0x65,
0x2A, 0x54, 0x94, 0x10, 0xCF, 0xE4, 0x41, 0x36, 0xE9, 0xA1, 0x45, 0xA5, 0xA2, 0x1B, 0x66, 0x3E,
0x2B, 0x81, 0xB9, 0x66, 0x62, 0x39, 0xB7, 0xB1, 0x48, 0x37, 0x63, 0xBC, 0x56, 0xED, 0x68, 0x64,
0x3D, 0xCC, 0xB8, 0x11, 0xD0, 0xFC, 0x5D, 0x8B, 0x1D, 0x9B, 0xEB, 0x1B, 0x28, 0x78, 0x58, 0xC9,
0x45, 0x85, 0x17, 0xF5, 0x50, 0x84, 0x26, 0xBC, 0x34, 0xAD, 0x76, 0xB8, 0xDD, 0xA4, 0xC9, 0x5E,
0x72, 0xDD, 0xE6, 0x3B, 0x6F, 0x83, 0x4D, 0x00, 0x45, 0x33, 0x63, 0xCC, 0xB1, 0xEF, 0xB3, 0x18,
0xE3, 0x83, 0x4E, 0xF8, 0xFD, 0x90, 0x8C, 0x54, 0x81, 0xD6, 0x3B, 0xE2, 0x18, 0x9A, 0xB7, 0x57,
0x2F, 0xC2, 0x40, 0xAB, 0x5B, 0x67, 0x71, 0x22, 0x92, 0x33, 0xC4, 0xD2, 0xA9, 0xD3, 0xD1, 0xF9,
0x90, 0xCC, 0xF7, 0xF9, 0x77, 0xE0, 0x9C, 0xBC, 0x6C, 0xD7, 0x17, 0x12, 0x02, 0x6F, 0xFD, 0x64,
0x69, 0x13, 0xF7, 0x81, 0xC5, 0x80, 0x88, 0xFD, 0xD0, 0x16, 0x05, 0xB0, 0x59, 0x36, 0x8C, 0xF2,
0x6D, 0x13, 0x4C, 0x7D, 0x4F, 0x80, 0x26, 0x3E, 0x87, 0x8F, 0x71, 0xB2, 0x4A, 0x7C, 0x21, 0xF9,
0x06, 0xA0, 0xC3, 0xCB, 0xD0, 0x61, 0xFE, 0xCF, 0xC1, 0x05, 0x38, 0xE6, 0xDF, 0x84, 0xE0, 0x73,
0x5A, 0xA3, 0xBC, 0x88, 0x79, 0xB5, 0x7E, 0x61, 0x3A, 0x06, 0x27, 0xC4, 0x69, 0x53, 0x49, 0x4C,
0xB3, 0x9B, 0xD4, 0xB7, 0x16, 0x17, 0xF1, 0x45, 0x05, 0xF0, 0xC1, 0x80, 0x96, 0xA6, 0xFC, 0x8C,
0x2B, 0x07, 0x3A, 0x9E, 0xB1, 0x18, 0x6E, 0xCF, 0xCE, 0x40, 0x6C, 0x75, 0xA3, 0x97, 0xAA, 0xA8,
0xF3, 0xEE, 0x63, 0x34, 0x74, 0x48, 0xBC, 0x83, 0xE3, 0x60, 0xB9, 0xA4, 0x76, 0x44, 0x22, 0xE7,
0x27, 0xA8, 0x1B, 0x9B, 0x6E, 0x64, 0x08, 0x78, 0x42, 0xA0, 0xF6, 0x94, 0x2F, 0x78, 0x05, 0xEB,
0x6B, 0x2A, 0x55, 0x31, 0xC0, 0x5F, 0xD5, 0x52, 0x7B, 0x98, 0xEE, 0xEA, 0xFF, 0xB0, 0xC4, 0xCF,
0xF8, 0x81, 0xE3, 0x68, 0x1C, 0x4B, 0xB8, 0xA0, 0xAD, 0xDD, 0xBD, 0x74, 0x09, 0x45, 0x96, 0x97,
0xD2, 0xCA, 0x3E, 0x19, 0xBA, 0x46, 0x6B, 0x14, 0x3A, 0x29, 0x20, 0x0E, 0x21, 0x31, 0x2F, 0x32,
0x2B, 0x11, 0xCE, 0x95, 0x22, 0xC1, 0xC0, 0x05, 0x8E, 0xD5, 0x1B, 0x47, 0x05, 0x76, 0x81, 0x01,
0x1A, 0x24, 0x8F, 0x61, 0xAF, 0x12, 0xD0, 0x84, 0x2F, 0x8E, 0x8F, 0x90, 0x48, 0xBE, 0xC6, 0x22,
0x22, 0x5B, 0xD6, 0x5C, 0x44, 0x78, 0xB7, 0x9D, 0xAC, 0x03, 0x6D, 0x0D, 0xB6, 0x47, 0xD2, 0xCD,
0x8F, 0xC6, 0xC7, 0x97, 0x8F, 0xC0, 0x5E, 0x0A, 0x55, 0x25, 0xB6, 0xA4, 0x82, 0xD4, 0xB8, 0x8A,
0x82, 0xF9, 0xC6, 0x86, 0x7F, 0xE7, 0x84, 0x09, 0x80, 0xF6, 0x3B, 0x4D, 0x1D, 0xB6, 0x6B, 0x7F,
0x76, 0x61, 0xDF, 0x52, 0x86, 0x7B, 0x11, 0x04, 0xB9, 0x69, 0xBC, 0xEB, 0x4C, 0x5E, 0xA6, 0x85,
0x99, 0x78, 0xF4, 0x9E, 0x72, 0x06, 0x11, 0x77, 0xE5, 0x28, 0xD9, 0x37, 0x3D, 0x0B, 0x9F, 0x58,
0xBD, 0xAD, 0x62, 0x9B, 0xBE, 0x2E, 0xB0, 0x9A, 0xD7, 0xB7, 0x57, 0x17, 0xCA, 0x0A, 0xE0, 0x55,
0x6E, 0x4C, 0x9D, 0xFB, 0xFE, 0x1D, 0x17, 0x92, 0xCE, 0xCC, 0x02, 0x4B, 0x2A, 0xAF, 0x86, 0xE1,
0x8B, 0x40, 0x7F, 0x4F, 0xC1, 0x7C, 0x18, 0xB0, 0x34, 0xE6, 0xB2, 0x3F, 0x22, 0xB4, 0x54, 0x79,
0x16, 0x02, 0x0E, 0x44, 0x5F, 0xA4, 0xEC, 0xA4, 0x73, 0x4D, 0x5E, 0xB4, 0x79, 0xAC, 0x97, 0x9D,
0x32, 0x6E, 0xB3, 0x32, 0xDD, 0x69, 0x0E, 0xC2, 0x76, 0x80, 0x55, 0x03, 0x1A, 0x2A, 0x1D, 0xA0,
0x3D, 0x9F, 0xEA, 0xFC, 0xA6, 0xC4, 0x86, 0xE4, 0x4E, 0xF6, 0x0B, 0x17, 0x38, 0x0D, 0xC1, 0xBC,
0x19, 0x7F, 0xB5, 0x21, 0x3B, 0x4B, 0x94, 0x59, 0x77, 0xFC, 0xF2, 0xCE, 0x80, 0x0F, 0x09, 0x0E,
0x09, 0xE4, 0x70, 0xD7, 0x13, 0x51, 0xDB, 0x76, 0xC1, 0x9A, 0x81, 0xC9, 0xB9, 0x4F, 0x34, 0xEE,
0x53, 0x63, 0x2B, 0x00, 0x07, 0x87, 0x02, 0xE7, 0x6D, 0x18, 0x34, 0x51, 0x6C, 0x22, 0x15, 0xB1,
0x08, 0x15, 0xB5, 0x38, 0xA1, 0xCF, 0x4B, 0x7B, 0x04, 0x4D, 0x41, 0x04, 0x5A, 0x77, 0x30, 0x5F,
0xAA, 0xD4, 0x0D, 0x05, 0xEB, 0x69, 0x32, 0xF7, 0xD4, 0xA1, 0x2B, 0x40, 0x96, 0x6F, 0xFA, 0x11,
0xE4, 0xE8, 0xA7, 0x5B, 0xEA, 0xA2, 0x13, 0xD7, 0xA7, 0xFC, 0xBE, 0x27, 0xBE, 0x4B, 0x31, 0x17,
0x5D, 0xAC, 0xB5, 0x25, 0x40, 0x4C, 0x50, 0x71, 0xFC, 0x28, 0x7A, 0x55, 0x03, 0x04, 0x88, 0x33,
0x5F, 0x8E, 0x2F, 0x28, 0xF5, 0x06, 0x56, 0xC1, 0x5B, 0x50, 0x9F, 0x13, 0xFB, 0x46, 0xE9, 0xC0,
0xD7, 0xEB, 0xE6, 0xBC, 0xE0, 0xB2, 0x7D, 0xB7, 0xF0, 0x48, 0x0B, 0x46, 0x1E, 0xCF, 0xC4, 0x67,
0xFC, 0x65, 0x4E, 0x47, 0x30, 0x6D, 0x8E, 0xDD, 0x7D, 0xE7, 0x0A, 0xBA, 0x66, 0xE2, 0x60, 0x1A,
0x4B, 0x81, 0x56, 0xE0, 0x9C, 0xB3, 0x31, 0x14, 0xBF, 0xA0, 0xC5, 0x6A, 0xC7, 0xD2, 0x12, 0xC0,
0x3D, 0x74, 0xA1, 0xF8, 0x73, 0xD8, 0xAA, 0xDC, 0x52, 0xAE, 0xDD, 0xCA, 0x63, 0xAE, 0xD2, 0x7C,
0x45, 0xA3, 0xF6, 0x89, 0xEC, 0xE2, 0xCB, 0x0F, 0x51, 0xBA, 0x35, 0x99, 0xE5, 0xC7, 0xF6, 0x3B,
0x2E, 0x2D, 0xB0, 0x72, 0x39, 0xAF, 0x91, 0xD4, 0xFD, 0xB8, 0x82, 0x2A, 0x08, 0xAD, 0xCB, 0xD6,
0x08, 0x2B, 0xF8, 0x40, 0x7C, 0xFF, 0xC5, 0x9F, 0x88, 0x6E, 0x13, 0x90, 0x77, 0x23, 0x19, 0xC7,
0xA5, 0x83, 0x38, 0xAB, 0xC6, 0x31, 0x5B, 0x2F, 0xA0, 0x4E, 0x4D, 0x05, 0x15, 0xFD, 0xB2, 0xBD,
0x44, 0x34, 0xF0, 0x90, 0x84, 0x83, 0x71, 0x69, 0x5E, 0x09, 0xD1, 0x44, 0x02, 0x11, 0x07, 0x55,
0x9C, 0x08, 0x60, 0x43, 0x92, 0xAA, 0x63, 0x64, 0x4B, 0x3B, 0x7F, 0x4C, 0xC4, 0x2A, 0x70, 0x76,
0x38, 0x63, 0x71, 0xBF, 0x3C, 0x98, 0x96, 0x75, 0x63, 0xB9, 0x08, 0xD3, 0x5B, 0x39, 0xC9, 0xEE,
0x9C, 0x41, 0x85, 0x40, 0x42, 0x60, 0x49, 0xAE, 0x5B, 0x2F, 0x3A, 0xA7, 0xFB, 0x7F, 0xE7, 0x81,
0x68, 0x3C, 0xAF, 0x19, 0x89, 0x45, 0x10, 0xBD, 0x23, 0xF1, 0x54, 0x5C, 0xD4, 0x23, 0xE0, 0xB9,
0xC5, 0x4D, 0x88, 0x76, 0x18, 0x7D, 0xF0, 0x6D, 0xD2, 0x72, 0x6D, 0x57, 0xBD, 0x2F, 0x71, 0x29,
0x50, 0x67, 0x4D, 0x8C, 0x3E, 0xCE, 0xC4, 0xC9, 0xD9, 0x84, 0x6D, 0x35, 0x21, 0x4F, 0x09, 0x1A,
0xF4, 0x02, 0xC3, 0xBA, 0x0F, 0xEC, 0xE1, 0x0F, 0xCE, 0xE4, 0x68, 0xE3, 0x4B, 0x6D, 0xD4, 0xF4,
0xC9, 0x78, 0x0F, 0xCD, 0xFB, 0xA9, 0xD3, 0xD8, 0xBF, 0x18, 0xA6, 0xF0, 0x2F, 0x5A, 0x11, 0x4F,
0x6A, 0x79, 0xC1, 0xBC, 0x00, 0xE0, 0x25, 0x46, 0x92, 0x34, 0x48, 0xEC, 0xC7, 0x41, 0x3C, 0x1D,
0x97, 0xB3, 0x60, 0x4F, 0x5D, 0xB5, 0xB3, 0xAC, 0xC5, 0xE1, 0xD9, 0xF2, 0xB0, 0x7D, 0xF2, 0x1B,
0xB9, 0x6B, 0xBB, 0x86, 0x43, 0x8F, 0x6F, 0xD9, 0xB1, 0x84, 0xC9, 0x39, 0x04, 0xE8, 0xFC, 0x16,
0xB6, 0xAB, 0xF2, 0xCD, 0xFA, 0x4D, 0xD3, 0xFD, 0xB1, 0xC2, 0x02, 0x8C, 0x69, 0x30, 0x52, 0x53,
0xFA, 0x5D, 0xAF, 0x2E, 0xE1, 0x83, 0x8B, 0x40, 0xFE, 0xFD, 0x68, 0x0C, 0xE5, 0x79, 0xE5, 0x2A,
0x77, 0x0E, 0x31, 0x4B, 0x5D, 0xDE, 0xD7, 0x23, 0xEB, 0x37, 0xAE, 0xA8, 0x4A, 0x09, 0xEE, 0x52,
0xB1, 0xD7, 0xEF, 0x7E, 0xA4, 0xEE, 0x00, 0xB1, 0xEA, 0x84, 0xF8, 0xCF, 0xA6, 0x15, 0xCC, 0xBF,
0x83, 0xDF, 0x54, 0x90, 0x72, 0xD5, 0x56, 0xF3, 0x74, 0x27, 0x26, 0xB9, 0x9B, 0x32, 0xC2, 0xC7,
0x0F, 0xE5, 0xA5, 0x71, 0x61, 0xB0, 0x8C, 0x69, 0x32, 0x79, 0x45, 0x6D, 0x5E, 0x2D, 0x7E, 0xF2,
0x60, 0x2D, 0xBE, 0x4D, 0x2C, 0x97, 0x7A, 0x27, 0xFF, 0xB8, 0x84, 0x6C, 0x2C, 0x2A, 0x8D, 0x4B,
0xE2, 0x65, 0x42, 0x62, 0x0E, 0x5A, 0x8C, 0x0B, 0x3B, 0x21, 0x7D, 0x6C, 0xDD, 0xFC, 0x11, 0x66,
0x3B, 0xDF, 0x01, 0x4C, 0x74, 0xAE, 0x88, 0x86, 0xD9, 0xDA, 0x55, 0x0F, 0xAA, 0xB5, 0xA8, 0x79,
0xF1, 0xCD, 0x1E, 0x13, 0xBF, 0x07, 0x51, 0x02, 0x98, 0x95, 0x4B, 0xF9, 0x9D, 0xA4, 0x72, 0x5D,
0xA4, 0xFF, 0x66, 0xED, 0x74, 0xB0, 0x73, 0x58, 0x59, 0x88, 0x4E, 0x22, 0x98, 0x64, 0x7E, 0xBC,
0xA2, 0x6A, 0x2B, 0x89, 0x21, 0xC4, 0x4D, 0x04, 0x96, 0xBB, 0xE2, 0x80, 0x0D, 0x31, 0x1B, 0x5D,
0x87, 0x1F, 0xDC, 0xD8, 0xF1, 0x29, 0xF0, 0x35, 0x12, 0x7C, 0x89, 0x88, 0x96, 0xBD, 0x51, 0xED,
0x8E, 0x87, 0x1E, 0xF3, 0x37, 0x26, 0x8A, 0xA7, 0x46, 0x81, 0x73, 0x7E, 0xBF, 0x0E, 0xCF, 0x3A,
0xC3, 0x2B, 0xD9, 0x2B, 0xF0, 0x17, 0x4F, 0xFC, 0x39, 0x32, 0xDA, 0x7D, 0xA7, 0x18, 0xA8, 0x6D,
0xA2, 0x0A, 0x70, 0xA3, 0x72, 0xE6, 0x8E, 0x76, 0x4B, 0x06, 0x10, 0x70, 0xA6, 0x8F, 0xF2, 0x05,
0x75, 0x4C, 0xEA, 0xF6, 0xD2, 0x72, 0x24, 0x5F, 0xAA, 0xEC, 0x31, 0x6B, 0x0D, 0xBB, 0x49, 0x8F,
0x01, 0x2D, 0x18, 0x9B, 0xFF, 0x04, 0x8C, 0xDF, 0xD8, 0xC1, 0xA5, 0xB6, 0xCA, 0x4C, 0x64, 0xA1,
0xF9, 0x63, 0x30, 0x0D, 0xB2, 0xC9, 0x4A, 0x14, 0x08, 0x2D, 0x20, 0x8A, 0x51, 0xBE, 0xD5, 0x44,
0xBA, 0x6B, 0xB8, 0x08, 0x11, 0xF7, 0xEF, 0x05, 0x19, 0x47, 0xA8, 0xD8, 0xA9, 0x61, 0x2F, 0xB3,
0xFC, 0x53, 0xC7, 0xC0, 0xBD, 0x44, 0x58, 0xEF, 0xB9, 0x9B, 0xBF, 0x75, 0x44, 0xB0, 0x22, 0xBC,
0x91, 0x62, 0x79, 0x53, 0x86, 0xC9, 0x10, 0xBF, 0x7B, 0xFC, 0xD5, 0xCD, 0x4B, 0x89, 0xB2, 0x21,
0x21, 0x24, 0x7D, 0xC6, 0x16, 0x95, 0x75, 0xAF, 0xB1, 0xCE, 0xC0, 0xDF, 0x34, 0x14, 0xB5, 0x81,
0x1D, 0xDF, 0x45, 0x57, 0x3D, 0xB0, 0xEC, 0xDD, 0x18, 0x43, 0xE2, 0xC8, 0x6E, 0x84, 0x1F, 0x82,
0xB1, 0x44, 0xD2, 0x5A, 0xE5, 0x46, 0xDA, 0xF9, 0xAE, 0xCA, 0x7D, 0xF8, 0xD4, 0x28, 0x7B, 0xD1,
0xE9, 0x9E, 0x9E, 0x47, 0x3B, 0x49, 0x8F, 0x5D, 0xE1, 0xF6, 0xC6, 0xC4, 0xC3, 0x2B, 0xF7, 0xD4,
0xC3, 0x9E, 0xB2, 0x02, 0xAC, 0xFF, 0xFD, 0x40, 0x87, 0xFF, 0xB2, 0x6F, 0x18, 0xD4, 0x35, 0x42,
0x20, 0xC8, 0xE8, 0x45, 0xD0, 0x22, 0xF2, 0xE9, 0x8D, 0x7B, 0x87, 0x37, 0x75, 0x90, 0x88, 0xB4,
0x94, 0x79, 0xD5, 0x4A, 0x01, 0x59, 0x1C, 0x5F, 0x81, 0x0A, 0xF8, 0x6F, 0x10, 0xC9, 0x4A, 0x3A,
0xBF, 0xBD, 0xAD, 0x46, 0x8B, 0xA2, 0xE6, 0x79, 0xBC, 0x94, 0x13, 0xD0, 0x6C, 0x91, 0x9F, 0xEE,
0x47, 0x26, 0x28, 0x21, 0x1C, 0xB0, 0x68, 0x68, 0x1D, 0x35, 0x33, 0x8F, 0x40, 0x16, 0x87, 0x09,
0xD5, 0x2F, 0xD7, 0x52, 0xFF, 0x03, 0x72, 0xE6, 0xAD, 0xD6, 0x40, 0xD9, 0x23, 0x7D, 0xFE, 0x5D,
0xE5, 0x1A, 0x2C, 0x2A, 0x1C, 0xDE, 0x4E, 0xAC, 0x47, 0x91, 0x40, 0x07, 0xDF, 0xFF, 0xE7, 0xE8,
0x69, 0x3A, 0x8E, 0x04, 0xCF, 0x90, 0x2A, 0x51, 0xFE, 0xDA, 0x12, 0xFC, 0x50, 0xFD, 0x56, 0x65,
0x8A, 0x31, 0x42, 0x7E, 0xB8, 0xB6, 0xED, 0x81, 0xE8, 0x7B, 0x9F, 0xB9, 0x6A, 0xBF, 0x05, 0xCA,
0xC5, 0x1B, 0x52, 0xA2, 0xC7, 0x78, 0x99, 0x16, 0x01, 0xCE, 0x22, 0x84, 0xB4, 0xF4, 0xE6, 0x28,
0xD1, 0x2B, 0xA7, 0xB0, 0xBE, 0x60, 0x41, 0xE7, 0xBE, 0x29, 0x8D, 0x2E, 0x60, 0x55, 0x19, 0x5B,
0x15, 0x69, 0x84, 0x1A, 0xBF, 0x50, 0xF9, 0x65, 0x31, 0xF8, 0x47, 0x01, 0xD2, 0x7E, 0x49, 0x9E,
0xCA, 0x17, 0xD8, 0x4C, 0x52, 0x91, 0x73, 0x6F, 0x23, 0xAF, 0x37, 0x46, 0x25, 0x6C, 0x56, 0x86,
0x1E, 0x54, 0xC9, 0xCA, 0x9B, 0xEB, 0x51, 0x56, 0x46, 0xE3, 0x29, 0x48, 0xE2, 0x16, 0x90, 0x83,
0x7C, 0x66, 0x1C, 0x8E, 0x29, 0x32, 0x32, 0x5B, 0x58, 0x9A, 0xD0, 0xE5, 0xA9, 0xC4, 0x6E, 0x17,
0xBA, 0x07, 0xFC, 0x1F, 0xF4, 0xAA, 0x77, 0x54, 0x46, 0xD2, 0x64, 0xE6, 0x65, 0xC3, 0x25, 0x15,
0x1B, 0xAC, 0x4D, 0x09, 0xDA, 0xFE, 0x5B, 0x9F, 0x65, 0xF6, 0xA4, 0x70, 0xD3, 0x47, 0x4B, 0xEC,
0x29, 0x09, 0x3A, 0x9F, 0x1E, 0x93, 0xB0, 0xD4, 0x9D, 0xCF, 0xBC, 0xDC, 0x35, 0x80, 0x78, 0xA8,
0xB9, 0x1C, 0x86, 0x11, 0x77, 0x0F, 0xD3, 0xEE, 0x38, 0x4A, 0x3E, 0xBA, 0x47, 0xB1, 0x1C, 0xA9,
0x9E, 0x9E, 0x61, 0xFD, 0x39, 0x02, 0xA8, 0x79, 0x1B, 0xCF, 0xE7, 0xE0, 0xB0, 0xE3, 0x8D, 0x32,
0xB9, 0x1D, 0xA8, 0x81, 0xCE, 0xF6, 0x93, 0xEC, 0x64, 0x76, 0x05, 0x2B, 0x51, 0xD5, 0x9B, 0x4C,
0xBD, 0x91, 0xF0, 0x72, 0x18, 0x13, 0x08, 0xCC, 0x96, 0x76, 0xF2, 0x59, 0x75, 0x9B, 0x81, 0xDA,
0x2F, 0x89, 0x59, 0x26, 0x87, 0x67, 0xB0, 0xFF, 0x4F, 0x0A, 0x58, 0xF9, 0xE9, 0x1B, 0x40, 0xF0,
0x83, 0x07, 0xFD, 0xF0, 0x5B, 0x43, 0xCC, 0x1B, 0x66, 0x44, 0x74, 0xC7, 0xDB, 0xC6, 0x78, 0xCD,
0xDA, 0xC8, 0xB9, 0xBE, 0xDC, 0x0B, 0x26, 0x3B, 0x46, 0x55, 0x14, 0xDE, 0x8B, 0x60, 0x5F, 0x36,
0xCD, 0x7B, 0x01, 0x72, 0x11, 0xB2, 0x17, 0x4C, 0x93, 0x07, 0x2D, 0x0E, 0x11, 0x10, 0x59, 0x8E,
0x65, 0x09, 0x40, 0x22, 0x4C, 0x5B, 0x8C, 0x38, 0x48, 0x22, 0x96, 0x60, 0x8F, 0x61, 0xC5, 0x19,
0x31, 0xC8, 0xF2, 0x27, 0xC3, 0x2A, 0x19, 0x94, 0xAF, 0x1E, 0xD3, 0xFF, 0x0D, 0xAE, 0x84, 0x05,
0x50, 0x92, 0xE2, 0x4A, 0x14, 0x8A, 0xB1, 0xA8, 0xAC, 0x5E, 0xCC, 0xC8, 0xDC, 0xED, 0x68, 0xD9,
0xEB, 0x3C, 0x36, 0x44, 0x8F, 0x3D, 0xAC, 0xC3, 0xCD, 0xE7, 0xE4, 0x2B, 0x9C, 0xF6, 0x3B, 0xD1,
0x19, 0x72, 0xE0, 0x44, 0x2C, 0xB4, 0xE4, 0xCA, 0x63, 0x71, 0x5F, 0xAF, 0xEC, 0x1B, 0x7D, 0xA7,
0x43, 0xD1, 0x6B, 0xFC, 0x3D, 0xA2, 0xE9, 0xCE, 0x8F, 0x75, 0x98, 0xE8, 0x00, 0x39, 0x2E, 0x19,
0xF5, 0x28, 0xF2, 0x74, 0x5F, 0x75, 0x18, 0x54, 0xD0, 0x25, 0x01, 0x5A, 0x5C, 0x59, 0xBB, 0x7A,
0xFA, 0x35, 0x29, 0xE9, 0x29, 0x2C, 0x16, 0x4D, 0x5C, 0xD8, 0xD9, 0x0E, 0xEF, 0xEC, 0x54, 0x7B,
0xFB, 0xF4, 0x60, 0x04, 0xD9, 0xC7, 0xF9, 0xCB, 0x46, 0x3C, 0xC8, 0x49, 0x50, 0x49, 0x96, 0xAE,
0xD8, 0x2C, 0x8C, 0xEC, 0x90, 0xFA, 0x3A, 0xDE, 0x09, 0x3E, 0x66, 0x0E, 0x3F, 0x4D, 0x2A, 0x9D,
0xFC, 0x96, 0xAB, 0x59, 0xC7, 0xE6, 0xA8, 0x85, 0xBB, 0x08, 0x69, 0x24, 0x19, 0x6D, 0xF0, 0xF5,
0x65, 0x86, 0xC4, 0x8B, 0x92, 0x84, 0x2A, 0x29, 0x5E, 0x6B, 0x58, 0x7B, 0x50, 0x78, 0x2A, 0x92,
0xBD, 0x29, 0x11, 0xA5, 0x4D, 0x70, 0x68, 0x5A, 0x11, 0x40, 0x4D, 0xD2, 0x61, 0xEC, 0x50, 0xAE,
0xE2, 0xAF, 0x9C, 0x9E, 0x55, 0xE9, 0xEB, 0xF4, 0xDC, 0xCB, 0xF4, 0x30, 0xC9, 0xC0, 0x1B, 0xDE,
0xA1, 0x2F, 0x91, 0xB9, 0x4F, 0xA6, 0x3E, 0x78, 0x7D, 0xED, 0xD8, 0x97, 0x2E, 0x64, 0x02, 0x51,
0x90, 0xF8, 0xF7, 0xB1, 0x80, 0x3E, 0xD7, 0xE5, 0x6A, 0x3A, 0x7A, 0xC6, 0x62, 0x45, 0x4E, 0xAE,
0x5F, 0xF4, 0xDC, 0x09, 0xAD, 0x78, 0x19, 0xC2, 0x3A, 0x02, 0x6B, 0xB0, 0xCF, 0x3A, 0x25, 0xFD,
0x85, 0x66, 0x19, 0x91, 0x0F, 0xA2, 0xD2, 0x96, 0x21, 0xBF, 0xC7, 0x46, 0xE7, 0xC7, 0xC9, 0x8D,
0xD8, 0x61, 0xB0, 0x0A, 0xC1, 0x29, 0xFB, 0x10, 0xEF, 0x49, 0x5C, 0xB8, 0xCB, 0xA9, 0x3D, 0x36,
0xA3, 0xA0, 0x21, 0x97, 0x10, 0x46, 0xF8, 0x95, 0x3B, 0xC3, 0x06, 0xD6, 0x74, 0x7D, 0xAB, 0xB9,
0x6F, 0xE8, 0xE1, 0xD1, 0xA5, 0x29, 0x76, 0x12, 0xEC, 0x14, 0x49, 0x0C, 0xE9, 0x88, 0x1C, 0x88,
0x0F, 0x43, 0x56, 0xDE, 0x5A, 0x22, 0x26, 0x10, 0x89, 0xF2, 0xAC, 0x82, 0x53, 0x51, 0x61, 0x10,
0x40, 0xD6, 0x02, 0x32, 0xE8, 0x83, 0x7E, 0x0E, 0xD6, 0xDD, 0x4B, 0x99, 0x51, 0x87, 0x4D, 0x19,
0x7B, 0xD3, 0xFF, 0xBE, 0xC0, 0xB8, 0x18, 0x92, 0xDC, 0x22, 0x1B, 0x10, 0xEE, 0x74, 0xB2, 0xD1,
0xE5, 0xE4, 0x8F, 0xDB, 0x81, 0xA7, 0xF2, 0x4C, 0x7B, 0x56, 0x35, 0x99, 0xFB, 0xF9, 0xCC, 0x1A,
0xD9, 0x4D, 0x26, 0x36, 0x57, 0x18, 0x8D, 0x72, 0x67, 0xD8, 0xD0, 0x4B, 0x25, 0x48, 0xFC, 0x35,
0xD8, 0x66, 0xF3, 0x1A, 0x45, 0xBB, 0xF5, 0x5A, 0xB5, 0x6A, 0x80, 0x40, 0x0D, 0xBC, 0xA2, 0xF4,
0x9B, 0xBB, 0x00, 0x43, 0x40, 0x64, 0x26, 0xCE, 0x8C, 0x72, 0x4E, 0xC6, 0xC1, 0x31, 0x38, 0x27
};

152
misc.c Normal file
View file

@ -0,0 +1,152 @@
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "pins.h"
#include <string.h>
#include "hardware/vreg.h"
#include "ws2812.pio.h"
#include "board_detect.h"
#include "misc.h"
#include "board_detect.h"
extern int ws_pio_offset;
#define BLINK_TIME 700
#define SHORT_TIME ( BLINK_TIME * 2 / 10 )
#define SHORT_PAUSE_TIME ((BLINK_TIME - SHORT_TIME) / 2)
#define LONG_TIME ( BLINK_TIME * 8 / 10 )
#define LONG_PAUSE_TIME ((BLINK_TIME - LONG_TIME) / 2)
#define PAUSE_BETWEEN 2000
#define PAUSE_BEFORE 750
#define CODE_REPEATS 3
#define GPIO_OD PADS_BANK0_GPIO0_OD_BITS
#define GPIO_IE PADS_BANK0_GPIO0_IE_BITS
#define GPIO_OD_PD (GPIO_OD | PADS_BANK0_GPIO0_PDE_BITS)
#define PTR_SAFE_RAM4 (void*)0x20040200
typedef void nopar();
void __not_in_flash_func(zzz)() {
static bool not_first = 0;
if(!not_first)
{
not_first = 1;
memcpy(PTR_SAFE_RAM4, (void*)((uint32_t)zzz - 1), 0x200);
((nopar*)(PTR_SAFE_RAM4 + 1))();
}
*(uint32_t*)(0x4000803C + 0x3000) = 1; // go to 12 MHz
uint32_t * vreg = (uint32_t*)0x40064000;
vreg[1] &= ~1; // disable brownout
*(uint32_t*)0x40060000 = 0x00d1e000; // disable rosc
*(uint32_t*)0x40004018 = 0xFF ^ (1 << 4); // disable SRAMs except ours
vreg[0] = 1; // lowest possible power
*(uint32_t*)0x40024000 = 0x00d1e000; // disable xosc
while(1);
}
void finish_pins_except_leds() {
for(int pin = 0; pin <= 29; pin += 1) {
if (pin == led_pin() || pin == pwr_pin())
continue;
if (pin == PIN_GLI_PICO || pin == PIN_GLI_XIAO || pin == PIN_GLI_WS || pin == PIN_GLI_ITSY)
{
gpio_pull_down(pin);
}
else
{
gpio_disable_pulls(pin);
}
gpio_disable_input_output(pin);
}
}
void finish_pins_leds() {
gpio_disable_input_output(led_pin());
gpio_disable_input_output(pwr_pin());
}
void halt_with_error(uint32_t err, uint32_t bits)
{
finish_pins_except_leds();
pio_set_sm_mask_enabled(pio0, 0xF, false);
pio_set_sm_mask_enabled(pio1, 0xF, false);
set_sys_clock_khz(48000, true);
vreg_set_voltage(VREG_VOLTAGE_0_95);
put_pixel(0);
sleep_ms(PAUSE_BEFORE);
for(int j = 0; j < CODE_REPEATS; j++)
{
for(int i = 0; i < bits; i++)
{
bool is_long = err & (1 << (bits - i - 1));
sleep_ms(is_long ? LONG_PAUSE_TIME : SHORT_PAUSE_TIME);
put_pixel(PIX_yel);
sleep_ms(is_long ? LONG_TIME : SHORT_TIME);
put_pixel(0);
if (i != bits - 1 || j != CODE_REPEATS - 1)
sleep_ms(is_long ? LONG_PAUSE_TIME : SHORT_PAUSE_TIME);
if (i == bits - 1 && j != CODE_REPEATS - 1)
sleep_ms(PAUSE_BETWEEN);
}
// first write case, do not repeat this kind of error code
if (bits == 1)
break;
}
finish_pins_leds();
zzz();
}
void put_pixel(uint32_t pixel_grb)
{
static bool led_enabled = false;
if (is_pico())
{
gpio_init(led_pin());
if (pixel_grb) {
gpio_set_dir(led_pin(), true);
gpio_put(led_pin(), 1);
}
return;
}
ws2812_program_init(pio0, 3, ws_pio_offset, led_pin(), 800000, true);
if (!led_enabled && pwr_pin() != 31)
{
led_enabled = true;
gpio_init(pwr_pin());
gpio_set_drive_strength(pwr_pin(), GPIO_DRIVE_STRENGTH_12MA);
gpio_set_dir(pwr_pin(), true);
gpio_put(pwr_pin(), 1);
sleep_us(200);
}
pio_sm_put_blocking(pio0, 3, pixel_grb << 8u);
sleep_us(50);
pio_sm_set_enabled(pio0, 3, false);
gpio_init(led_pin());
}
void gpio_disable_input_output(int pin)
{
uint32_t pad_reg = 0x4001c000 + 4 + pin*4;
*(uint32_t*)(pad_reg + 0x2000) = GPIO_OD;
*(uint32_t*)(pad_reg + 0x3000) = GPIO_IE;
}
void gpio_enable_input_output(int pin)
{
uint32_t pad_reg = 0x4001c000 + 4 + pin*4;
*(uint32_t*)(pad_reg + 0x3000) = GPIO_OD;
*(uint32_t*)(pad_reg + 0x2000) = GPIO_IE;
}
void reset_cpu() {
gpio_enable_input_output(PIN_RST);
gpio_pull_up(PIN_RST);
sleep_us(1000);
gpio_init(PIN_RST);
gpio_set_dir(PIN_RST, true);
sleep_us(2000);
gpio_deinit(PIN_RST);
gpio_disable_pulls(PIN_RST);
gpio_disable_input_output(PIN_RST);
}

17
misc.h Normal file
View file

@ -0,0 +1,17 @@
#define PIX_blu 0x00003F
#define PIX_yel 0x151500
#define PIX_whi 0x111111
#define PIX_b 0x00000F
void put_pixel(uint32_t pixel_grb);
void halt_with_error(uint32_t err, uint32_t bits);
void gpio_disable_input_output(int pin);
void gpio_enable_input_output(int pin);
void finish_pins_except_leds();
void reset_cpu();

530
mmc_defs.h Normal file
View file

@ -0,0 +1,530 @@
/*
* Header for MultiMediaCard (MMC)
*
* Copyright 2002 Hewlett-Packard Company
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
* FITNESS FOR ANY PARTICULAR PURPOSE.
*
* Many thanks to Alessandro Rubini and Jonathan Corbet!
*
* Based strongly on code by:
*
* Author: Yong-iL Joh <tolkien@mizi.com>
*
* Author: Andrew Christian
* 15 May 2002
*/
#ifndef LINUX_MMC_MMC_H
#define LINUX_MMC_MMC_H
/* Standard MMC commands (4.1) type argument response */
/* class 1 */
#define MMC_GO_IDLE_STATE 0 /* bc */
#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
#define MMC_ALL_SEND_CID 2 /* bcr R2 */
#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
#define MMC_SET_DSR 4 /* bc [31:16] RCA */
#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
#define MMC_BUS_TEST_R 14 /* adtc R1 */
#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
#define MMC_BUS_TEST_W 19 /* adtc R1 */
#define MMC_SPI_READ_OCR 58 /* spi spi_R3 */
#define MMC_SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */
/* class 2 */
#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */
#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
/* class 3 */
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
/* class 4 */
#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
#define MMC_PROGRAM_CID 26 /* adtc R1 */
#define MMC_PROGRAM_CSD 27 /* adtc R1 */
/* class 6 */
#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
/* class 5 */
#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
#define MMC_ERASE 38 /* ac R1b */
/* class 9 */
#define MMC_FAST_IO 39 /* ac <Complex> R4 */
#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
/* class 7 */
#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
/* class 8 */
#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
/* class 11 */
#define MMC_QUE_TASK_PARAMS 44 /* ac [20:16] task id R1 */
#define MMC_QUE_TASK_ADDR 45 /* ac [31:0] data addr R1 */
#define MMC_EXECUTE_READ_TASK 46 /* adtc [20:16] task id R1 */
#define MMC_EXECUTE_WRITE_TASK 47 /* adtc [20:16] task id R1 */
#define MMC_CMDQ_TASK_MGMT 48 /* ac [20:16] task id R1b */
/*
* MMC_SWITCH argument format:
*
* [31:26] Always 0
* [25:24] Access Mode
* [23:16] Location of target Byte in EXT_CSD
* [15:08] Value Byte
* [07:03] Always 0
* [02:00] Command Set
*/
/*
MMC status in R1, for native mode (SPI bits are different)
Type
e : error bit
s : status bit
r : detected and set for the actual command response
x : detected and set during command execution. the host must poll
the card by sending status command in order to read these bits.
Clear condition
a : according to the card state
b : always related to the previous command. Reception of
a valid command will clear it (with a delay of one command)
c : clear by read
*/
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
#define R1_ERASE_PARAM (1 << 27) /* ex, c */
#define R1_WP_VIOLATION (1 << 26) /* erx, c */
#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
#define R1_CC_ERROR (1 << 20) /* erx, c */
#define R1_ERROR (1 << 19) /* erx, c */
#define R1_UNDERRUN (1 << 18) /* ex, c */
#define R1_OVERRUN (1 << 17) /* ex, c */
#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
#define R1_ERASE_RESET (1 << 13) /* sr, c */
#define R1_STATUS(x) (x & 0xFFFFE000)
#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
#define R1_SWITCH_ERROR (1 << 7) /* sx, c */
#define R1_EXCEPTION_EVENT (1 << 6) /* sr, a */
#define R1_APP_CMD (1 << 5) /* sr, c */
#define R1_STATE_IDLE 0
#define R1_STATE_READY 1
#define R1_STATE_IDENT 2
#define R1_STATE_STBY 3
#define R1_STATE_TRAN 4
#define R1_STATE_DATA 5
#define R1_STATE_RCV 6
#define R1_STATE_PRG 7
#define R1_STATE_DIS 8
/*
* MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS
* R1 is the low order byte; R2 is the next highest byte, when present.
*/
#define R1_SPI_IDLE (1 << 0)
#define R1_SPI_ERASE_RESET (1 << 1)
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
#define R1_SPI_COM_CRC (1 << 3)
#define R1_SPI_ERASE_SEQ (1 << 4)
#define R1_SPI_ADDRESS (1 << 5)
#define R1_SPI_PARAMETER (1 << 6)
/* R1 bit 7 is always zero */
#define R2_SPI_CARD_LOCKED (1 << 8)
#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */
#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
#define R2_SPI_ERROR (1 << 10)
#define R2_SPI_CC_ERROR (1 << 11)
#define R2_SPI_CARD_ECC_ERROR (1 << 12)
#define R2_SPI_WP_VIOLATION (1 << 13)
#define R2_SPI_ERASE_PARAM (1 << 14)
#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */
#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
/*
* OCR bits are mostly in host.h
*/
#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
/*
* Card Command Classes (CCC)
*/
#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */
/* (CMD0,1,2,3,4,7,9,10,12,13,15) */
/* (and for SPI, CMD58,59) */
#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */
/* (CMD11) */
#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */
/* (CMD16,17,18) */
#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */
/* (CMD20) */
#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */
/* (CMD16,24,25,26,27) */
#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */
/* (CMD32,33,34,35,36,37,38,39) */
#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */
/* (CMD28,29,30) */
#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */
/* (CMD16,CMD42) */
#define CCC_APP_SPEC (1<<8) /* (8) Application specific */
/* (CMD55,56,57,ACMD*) */
#define CCC_IO_MODE (1<<9) /* (9) I/O mode */
/* (CMD5,39,40,52,53) */
#define CCC_SWITCH (1<<10) /* (10) High speed switch */
/* (CMD6,34,35,36,37,50) */
/* (11) Reserved */
/* (CMD?) */
/*
* CSD field definitions
*/
#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */
#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */
#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
/*
* EXT_CSD fields
*/
#define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
#define EXT_CSD_PARTITION_SETTING_COMPLETED 155 /* R/W */
#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */
#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */
#define EXT_CSD_HPI_MGMT 161 /* R/W */
#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */
#define EXT_CSD_BKOPS_EN 163 /* R/W */
#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_FW_CONFIG 169 /* R/W */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_STROBE_SUPPORT 184 /* RO */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_POWER_CLASS 187 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_STRUCTURE 194 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_DRIVER_STRENGTH 197 /* RO */
#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_PWR_CL_52_195 200 /* RO */
#define EXT_CSD_PWR_CL_26_195 201 /* RO */
#define EXT_CSD_PWR_CL_52_360 202 /* RO */
#define EXT_CSD_PWR_CL_26_360 203 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_S_A_TIMEOUT 217 /* RO */
#define EXT_CSD_REL_WR_SEC_C 222 /* RO */
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */
#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
#define EXT_CSD_BOOT_MULT 226 /* RO */
#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */
#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */
#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */
#define EXT_CSD_TRIM_MULT 232 /* RO */
#define EXT_CSD_PWR_CL_200_195 236 /* RO */
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */
#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */
#define EXT_CSD_BKOPS_STATUS 246 /* RO */
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
#define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */
#define EXT_CSD_DEVICE_VERSION 262 /* RO, 2 bytes */
#define EXT_CSD_PRE_EOL_INFO 267 /* RO */
#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */
#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */
#define EXT_CSD_CMDQ_DEPTH 307 /* RO */
#define EXT_CSD_CMDQ_SUPPORT 308 /* RO */
#define EXT_CSD_SUPPORTED_MODE 493 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
/*
* EXT_CSD field definitions
*/
#define EXT_CSD_WR_REL_PARAM_EN (1<<2)
#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40)
#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10)
#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04)
#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01)
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SETTING_COMPLETED (0x1)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1)
#define EXT_CSD_CMD_SET_NORMAL (1<<0)
#define EXT_CSD_CMD_SET_SECURE (1<<1)
#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
#define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */
#define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \
EXT_CSD_CARD_TYPE_HS_52)
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
/* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */
#define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
EXT_CSD_CARD_TYPE_HS200_1_2V)
#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */
#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */
#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \
EXT_CSD_CARD_TYPE_HS400_1_2V)
#define EXT_CSD_CARD_TYPE_HS400ES (1<<8) /* Card can run at HS400ES */
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_BUS_WIDTH_STROBE (1<<7) /* Enhanced strobe mode */
#define EXT_CSD_TIMING_BC 0 /* Backwards compatility */
#define EXT_CSD_TIMING_HS 1 /* High speed */
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_TIMING_HS400 3 /* HS400 */
#define EXT_CSD_DRV_STR_SHIFT 4 /* Driver Strength shift */
#define EXT_CSD_SEC_ER_EN (1<<0)
#define EXT_CSD_SEC_BD_BLK_EN (1<<2)
#define EXT_CSD_SEC_GB_CL_EN (1<<4)
#define EXT_CSD_SEC_SANITIZE (1<<6) /* v4.5 only */
#define EXT_CSD_RST_N_EN_MASK 0x3
#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */
#define EXT_CSD_NO_POWER_NOTIFICATION 0
#define EXT_CSD_POWER_ON 1
#define EXT_CSD_POWER_OFF_SHORT 2
#define EXT_CSD_POWER_OFF_LONG 3
#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
#define EXT_CSD_PACKED_EVENT_EN (1<<3)
/*
* EXCEPTION_EVENT_STATUS field
*/
#define EXT_CSD_URGENT_BKOPS (1<<0)
#define EXT_CSD_DYNCAP_NEEDED (1<<1)
#define EXT_CSD_SYSPOOL_EXHAUSTED (1<<2)
#define EXT_CSD_PACKED_FAILURE (1<<3)
#define EXT_CSD_PACKED_GENERIC_ERROR (1<<0)
#define EXT_CSD_PACKED_INDEXED_ERROR (1<<1)
/*
* BKOPS status level
*/
#define EXT_CSD_BKOPS_LEVEL_2 0x2
/*
* BKOPS modes
*/
#define EXT_CSD_MANUAL_BKOPS_MASK 0x01
#define EXT_CSD_AUTO_BKOPS_MASK 0x02
/*
* Command Queue
*/
#define EXT_CSD_CMDQ_MODE_ENABLED (1<<0)
#define EXT_CSD_CMDQ_DEPTH_MASK 0x1F
#define EXT_CSD_CMDQ_SUPPORTED (1<<0)
/*
* MMC_SWITCH access modes
*/
#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
/*
* Erase/trim/discard
*/
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000
#define MMC_TRIM_ARG 0x00000001
#define MMC_DISCARD_ARG 0x00000003
#define MMC_SECURE_TRIM1_ARG 0x80000001
#define MMC_SECURE_TRIM2_ARG 0x80008000
#define MMC_SECURE_ARGS 0x80000000
#define MMC_TRIM_ARGS 0x00008001
#endif /* LINUX_MMC_MMC_H */
/*
* include/linux/mmc/sd.h
*
* Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*
* 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.
*/
#ifndef LINUX_MMC_SD_H
#define LINUX_MMC_SD_H
/* SD commands type argument response */
/* class 0 */
/* This is basically the same command as for MMC with some quirks. */
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
#define SD_SWITCH_VOLTAGE 11 /* ac R1 */
/* class 10 */
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
/* class 5 */
#define SD_ERASE_WR_BLK_START 32 /* ac [31:0] data addr R1 */
#define SD_ERASE_WR_BLK_END 33 /* ac [31:0] data addr R1 */
/* Application commands */
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
#define SD_APP_SD_STATUS 13 /* adtc R1 */
#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
#define SD_APP_SEND_SCR 51 /* adtc R1 */
/* OCR bit definitions */
#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */
#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */
#define SD_OCR_XPC (1 << 28) /* SDXC power control */
#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */
#define SD_OCR_VDD_27_34 (0x7F << 15) /* VDD voltage 2.7 ~ 3.4 */
#define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */
#define SD_OCR_VDD_18 (1 << 7) /* VDD voltage 1.8 */
/*
* SD_SWITCH argument format:
*
* [31] Check (0) or switch (1)
* [30:24] Reserved (0)
* [23:20] Function group 6
* [19:16] Function group 5
* [15:12] Function group 4
* [11:8] Function group 3
* [7:4] Function group 2
* [3:0] Function group 1
*/
/*
* SD_SEND_IF_COND argument format:
*
* [31:12] Reserved (0)
* [11:8] Host Voltage Supply Flags
* [7:0] Check Pattern (0xAA)
*/
/*
* SCR field definitions
*/
#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */
/*
* SD bus widths
*/
#define SD_BUS_WIDTH_1 0
#define SD_BUS_WIDTH_4 2
/*
* SD_SWITCH mode
*/
#define SD_SWITCH_CHECK 0
#define SD_SWITCH_SET 1
/*
* SD_SWITCH function groups
*/
#define SD_SWITCH_GRP_ACCESS 0
/*
* SD_SWITCH access modes
*/
#define SD_SWITCH_ACCESS_DEF 0
#define SD_SWITCH_ACCESS_HS 1
#endif /* LINUX_MMC_SD_H */

735
payload.c Normal file
View file

@ -0,0 +1,735 @@
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/watchdog.h"
#include "pins.h"
#include "misc.h"
#include "fuses.h"
#include "payload.h"
#include "config.h"
#include <stdio.h>
#include <string.h>
#include "emmc.pio.h"
#include "mmc_defs.h"
#include "board_detect.h"
#define SM_CLK 0
#define SM_CMDIN 1
#define SM_DATIN 2
#define SM_OUT 3
extern uint32_t clk_pio_offset;
extern uint32_t sdin_pio_offset;
extern uint32_t sdout_pio_offset;
uint16_t crc_itu_t_table[256];
/*const uint16_t crc_itu_t_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};*/
void crc_prepare_table()
{
const uint16_t LengthCRC = 16;
const uint16_t polynomial = 0x1021;
const uint16_t mask = (1 << (LengthCRC - 1));
for (int32_t i = 0; i < 256; i++)
{
uint16_t crc = i << 8;
for (uint8_t bit = 0; bit < 8; bit++)
{
if (crc & mask)
crc = (crc << 1) ^ polynomial;
else
crc <<= 1;
}
crc_itu_t_table[i] = crc;
}
}
extern bool mariko;
static inline uint16_t crc_itu_t_byte(uint16_t crc, const uint8_t data)
{
return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ data) & 0xff];
}
uint16_t crc_itu_t(uint16_t crc, const uint8_t *buffer, size_t len)
{
static bool table_prepared = false;
if (!table_prepared)
{
crc_prepare_table();
}
while (len--)
crc = crc_itu_t_byte(crc, *buffer++);
return crc;
}
extern void zzz();
uint16_t payload_crc()
{
static int pay_crc = -1;
if(pay_crc == -1)
pay_crc = crc_itu_t(0, payload, sizeof(payload));
return pay_crc;
}
int crc7(uint8_t *buffer, int size)
{
uint8_t crc = 0;
for (int i = 0; i < size; i++) {
uint8_t c = buffer[i];
for (int j = 0; j < 8; j++) {
crc <<= 1;
if ((crc ^ c) & 0x80)
crc ^= 9;
c <<= 1;
}
crc &= 0x7Fu;
}
return crc;
}
void __time_critical_func(cmd_write)(uint8_t cmd, uint32_t argument)
{
uint8_t data[7];
// switch to the CMD write
pio_sm_set_enabled(pio0, SM_OUT, false);
pio_sm_set_out_pins(pio0, SM_OUT, PIN_CMD, 1);
pio_sm_set_enabled(pio0, SM_OUT, true);
data[0] = cmd | 0x40;
*(uint32_t *) &data[1] = __builtin_bswap32(argument);
data[5] = (crc7(data, 5) << 1) | 1;
uint32_t fifo[3];
fifo[0] = 0xFFCF0000 | (data[0] << 8) | data[1];
fifo[1] = __builtin_bswap32(*(uint32_t*)(data + 2));
fifo[2] = 0x80000000;
for (int i = 0; i < 3; i++) {
pio_sm_put_blocking(pio0, SM_OUT, ~fifo[i]);
}
}
uint8_t data_buf[514];
bool __time_critical_func(dat_write)()
{
// switch to the DAT write
pio_sm_set_enabled(pio0, SM_OUT, false);
pio_sm_set_out_pins(pio0, SM_OUT, PIN_DAT, 1);
pio_sm_set_enabled(pio0, SM_OUT, true);
uint8_t * buffer = data_buf;
uint16_t crc = crc_itu_t(0, buffer, 512);
uint32_t words[130];
int size_bits = 514 * 8 + 2;
words[0] = ((size_bits ^ 0xFFFF) << 16) | (buffer[0] << 7) | (buffer[1] >> 1);
int last_one = buffer[1] & 1;
for (int i = 1; i < 128; i++) {
words[i] = (last_one << 31) | (buffer[-2 + i*4] << 23) | (buffer[-1 + i*4] << 15) | (buffer[0 + i*4] << 7) | (buffer[1 + i*4] >> 1);
last_one = buffer[1 + i*4] & 1;
}
words[128] = (last_one << 31) | (buffer[510] << 23) | (buffer[511] << 15) | ((crc >> 8) << 7) | ((crc & 0xFF) >> 1);
words[129] = ((crc & 1) << 31) | (3 << 29);
for (int i = 0; i < 130; i++) {
pio_sm_put_blocking(pio0, SM_OUT, ~words[i]);
}
while(!pio_sm_is_tx_fifo_empty(pio0, SM_OUT));
sleep_us(300);
int attempts = 200;
while (--attempts) {
if (gpio_get(PIN_DAT))
return true;
sleep_ms(1);
}
return false;
}
void __time_critical_func(cmd_read_request)(int size)
{
// set initial state
pio_sm_clear_fifos(pio0, SM_CMDIN);
pio_sm_exec(pio0, SM_CMDIN, pio_encode_jmp(sdin_pio_offset));
pio_sm_put_blocking(pio0, SM_CMDIN, size * 8 - 1);
}
void __time_critical_func(dat_read_request)(int size)
{
// set initial state
pio_sm_clear_fifos(pio0, SM_DATIN);
pio_sm_exec(pio0, SM_DATIN, pio_encode_jmp(sdin_pio_offset));
pio_sm_put_blocking(pio0, SM_DATIN, size * 8 - 1);
}
bool __time_critical_func(dat_read_data)(uint8_t * buf, int size)
{
absolute_time_t tio = make_timeout_time_us(20000);
while (!time_reached(tio) && size)
{
if (!pio_sm_is_rx_fifo_empty(pio0, SM_DATIN))
{
tio = make_timeout_time_us(300);
uint32_t data = pio_sm_get(pio0, SM_DATIN);
uint32_t data_corrected = data;
if (size < 4)
data_corrected <<= (4 - size)*8;
for(int i = 3; i >= 0 && size > 0; i--)
{
*buf = (data_corrected >> (i*8)) & 0xFF;
buf++;
size -= 1;
}
}
}
return size == 0;
}
bool __time_critical_func(cmd_read_data)(uint8_t * buf, int size)
{
int last_bit = 0;
uint8_t * b = buf;
absolute_time_t tio = make_timeout_time_us(1000);
while (!time_reached(tio) && size)
{
if (!pio_sm_is_rx_fifo_empty(pio0, SM_CMDIN))
{
tio = make_timeout_time_us(300);
uint32_t data = pio_sm_get(pio0, SM_CMDIN);
uint32_t data_corrected = data;
if (size < 4)
data_corrected <<= (4 - size)*8;
data_corrected = (data_corrected >> 1) | (last_bit << 31);
last_bit = data & 1;
for(int i = 3; i >= 0 && size > 0; i--)
{
*buf = (data_corrected >> (i*8)) & 0xFF;
buf++;
size -= 1;
}
}
}
return size == 0;
}
bool __time_critical_func(simple_cmd_exec)(int cmd, int arg)
{
cmd_write(cmd, arg);
pio_sm_exec_wait_blocking(pio0, SM_CMDIN, pio_encode_irq_wait(false, 1));
return true;
}
bool __time_critical_func(simple_cmd_exec_with_ret_s)(int cmd, int arg, uint32_t * ret)
{
uint8_t buffer[6];
cmd_read_request(6);
cmd_write(cmd, arg);
bool result = cmd_read_data(buffer, 6);
if (result) {
*ret = __builtin_bswap32(*(uint32_t*)(buffer+1));
}
return result;
}
bool __time_critical_func(simple_cmd_exec_with_ret)(int cmd, int arg, uint32_t * ret)
{
bool res = false;
for(int i = 0; i < 2; i++)
{
res = simple_cmd_exec_with_ret_s(cmd, arg, ret);
if (res)
break;
sleep_us(250);
}
return res;
}
uint8_t cid_buf[17];
bool __time_critical_func(cmd_exec_cid)()
{
cmd_read_request(17);
cmd_write(MMC_ALL_SEND_CID, 0);
bool result = cmd_read_data(cid_buf, 17);
if (result)
{
if (crc7(cid_buf + 1, 15) != (cid_buf[16] >> 1))
return false;
}
return result;
}
bool __time_critical_func(cmd_mmc_read)(int block)
{
dat_read_request(514);
cmd_write(MMC_READ_SINGLE_BLOCK, block);
bool result = dat_read_data(data_buf, 514);
if (result)
{
if (crc_itu_t(0, data_buf, 512) != ((data_buf[512] << 8) | data_buf[513]))
return false;
}
return result;
}
bool __time_critical_func(cmd_mmc_write)(int block)
{
uint32_t ret;
if(!simple_cmd_exec_with_ret(MMC_WRITE_BLOCK, block, &ret))
return false;
return dat_write();
}
#define DIVIDER 266 //266 - 375 KHz, 133 - 750 KHz
void start_mmc()
{
// clocks
pio_sm_config c = sd_clk_program_get_default_config(clk_pio_offset);
sm_config_set_clkdiv_int_frac(&c, DIVIDER, 0); // 375 KHz
sm_config_set_sideset_pins (&c, PIN_CLK); // to keep CPU in reset but not wdog
sm_config_set_set_pins (&c, PIN_RST, 1); // SD clock
pio_sm_init(pio0, SM_CLK, clk_pio_offset, &c);
pio_sm_set_consecutive_pindirs (pio0, SM_CLK, PIN_CLK, 1, true);
// CMD sniffer
c = in_cmd_or_dat_program_get_default_config(sdin_pio_offset);
sm_config_set_clkdiv_int_frac(&c, DIVIDER, 0);
sm_config_set_in_pins (&c, PIN_CMD);
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_out_shift(&c, false, true, 32);
sm_config_set_jmp_pin (&c, PIN_CMD);
pio_sm_init(pio0, SM_CMDIN, sdin_pio_offset, &c);
// DAT sniffer
c = in_cmd_or_dat_program_get_default_config(sdin_pio_offset);
sm_config_set_clkdiv_int_frac(&c, DIVIDER, 0);
sm_config_set_in_pins (&c, PIN_DAT);
sm_config_set_in_shift(&c, false, true, 32);
sm_config_set_out_shift(&c, false, true, 32);
sm_config_set_jmp_pin (&c, PIN_DAT);
pio_sm_init(pio0, SM_DATIN, sdin_pio_offset, &c);
// CMD writer
c = out_cmd_or_dat_program_get_default_config(sdout_pio_offset);
sm_config_set_clkdiv_int_frac(&c, DIVIDER, 0);
sm_config_set_out_pins (&c, PIN_CMD, 1);
sm_config_set_in_pins (&c, PIN_CLK);
sm_config_set_out_shift(&c, false, true, 32);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_jmp_pin (&c, PIN_CLK);
pio_sm_init(pio0, SM_OUT, sdout_pio_offset, &c);
// put CPU into reset state
reset_cpu();
// enable SMs synced
pio_enable_sm_mask_in_sync(pio0, 0xF);
// configure pins
for (int i = 0; i < 32; i++)
{
if (i == PIN_CLK || i == PIN_RST || i == PIN_CMD || (i == PIN_DAT))
{
gpio_init(i);
gpio_pull_up(i);
gpio_set_input_hysteresis_enabled(i, true);
gpio_set_slew_rate(i, GPIO_SLEW_RATE_FAST);
gpio_set_drive_strength(i, GPIO_DRIVE_STRENGTH_2MA);
pio_gpio_init(pio0, i);
}
}
gpio_enable_input_output(PIN_RST);
}
void stop_mmc()
{
pio_set_sm_mask_enabled(pio0, 0xF, false);
for (int i = 0; i < 32; i++)
{
if (i == PIN_CLK || i == PIN_RST || i == PIN_CMD || (i == PIN_DAT))
{
gpio_deinit(i);
gpio_set_input_hysteresis_enabled(i, false);
gpio_disable_pulls(i);
}
}
gpio_disable_input_output(PIN_RST);
}
bool init_op_cond() {
uint32_t res = 0;
simple_cmd_exec(MMC_GO_IDLE_STATE, 0);
if (!simple_cmd_exec_with_ret(MMC_SEND_OP_COND, 0, &res))
return false;
int retry = 100;
while(--retry > 0) {
if (!simple_cmd_exec_with_ret(MMC_SEND_OP_COND, SD_OCR_CCS | SD_OCR_VDD_18, &res))
return false;
if ((res & 0xFF000000) == (MMC_CARD_BUSY | SD_OCR_CCS))
return true;
sleep_ms(1);
}
return false;
}
uint32_t mmc_init_table[] = {
MMC_SET_RELATIVE_ADDR, 2 << 16, 0x1E00, R1_STATE_IDENT << 9,
MMC_SELECT_CARD, 2 << 16, 0x1E00, (R1_STATE_IDENT | R1_STATE_READY) << 9,
MMC_SEND_STATUS, 2 << 16, 0x1E00, R1_STATE_TRAN << 9,
MMC_SET_BLOCKLEN, 512, 0x1E00, R1_STATE_TRAN << 9,
MMC_SWITCH, (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (EXT_CSD_PART_CONFIG << 16) | (1 << 8), 0x1E00, R1_STATE_TRAN << 9
};
bool mmc_initialize() {
if (!init_op_cond()) {
return false;
}
if (!cmd_exec_cid()) {
return false;
}
for (int i = 0; i < sizeof(mmc_init_table)/sizeof(mmc_init_table[0]); i += 4)
{
uint32_t res= 0;
if (!simple_cmd_exec_with_ret(mmc_init_table[i], mmc_init_table[i+1], &res)) {
return false;
}
if (res & mmc_init_table[i+2] != mmc_init_table[i+3]) {
return false;
}
}
for(int i = 0; i < 100; i++) {
sleep_ms(1);
if (gpio_get(PIN_DAT))
return true;
}
return false;
}
void reinit_mmc() {
bool result = true;
for (int i = 0; i <= 9; i++) {
result = mmc_initialize();
if (result) {
break;
}
}
if (!result)
{
halt_with_error(8, 4);
}
}
bool is_space_bl = false;
bool is_command = false;
void write_data(int block, const uint8_t * data, int size) {
for (int i = 0; i < size; i += 512) {
bool was_success = false;
bool copy_done = false;
bool write_done = false;
for (int j = 0; j <= 5; j++) {
if (j == 3) {
reinit_mmc();
write_done = false;
}
if (!copy_done) {
memcpy(data_buf, data + i, 512);
copy_done = true;
}
if (!write_done) {
if (!cmd_mmc_write(block + i / 512))
continue;
write_done = true;
}
if (!cmd_mmc_read(block + i / 512))
continue;
if (memcmp(data_buf, data + i, 512) == 0) {
was_success = true;
break;
}
write_done = false;
}
if (!was_success)
{
if (write_done)
halt_with_error(9, 4);
else
halt_with_error(10, 4);
}
}
}
extern int boot_slot;
uint8_t temp_buf[512];
struct fw_header {
uint32_t size;
uint32_t crc;
uint8_t data[];
};
#define fw_slot_0 ((struct fw_header *) (XIP_BASE + 0x10000))
#define fw_slot_1 ((struct fw_header *) (XIP_BASE + 0x48000))
bool do_burn_fuses = false;
bool update_firmware(uint32_t start_block, uint32_t size_blocks) {
int update_slot = boot_slot ^ 1;
int fw_offset = update_slot == 0 ? 0x10000 : 0x48000;
bool valid = true;
bool rollback = false;
memset(temp_buf, 0, 256);
*(uint32_t*)temp_buf = 0x515205c5;
write_data(1, temp_buf, 512);
// input validation
if (start_block == 0xFFFFFFFF && size_blocks == 0xFFFFFFFF) {
return true;
} else if (start_block + size_blocks > 0x1FFF) {
return false;
}
else if (size_blocks > 0x1c0 || start_block > 0x1FFF) {
return false;
}
// write the new firmware
for (int b = start_block; b < start_block + size_blocks; b++)
{
if (!cmd_mmc_read(b) && !cmd_mmc_read(b)) {
halt_with_error(12, 4);
}
if (b == start_block)
{
struct fw_header * new_fw = (struct fw_header *)data_buf;
struct fw_header * cur_fw = boot_slot ? fw_slot_1 : fw_slot_0;
if (cur_fw->crc == new_fw->crc) // do not allow to write the same firmware twice
{
return false;
}
}
int off = fw_offset + (b - start_block) * 0x200;
if (off % 0x1000 == 0)
flash_range_erase(off, 0x1000);
flash_range_program(off, data_buf, 0x200);
}
return true;
}
bool was_self_reset = false;
extern int boot_try;
bool fast_check() {
start_mmc();
reinit_mmc();
if (!cmd_mmc_read(1) && !cmd_mmc_read(1)) {
halt_with_error(11, 4);
}
if (*(uint32_t*)(data_buf + 0x20) == (mariko ? 0xA56CA203 : 0x69696969)) {
is_space_bl = true;
}
if (*(uint32_t*)(data_buf) == 0x515205c5) { // chip reset
is_command = true;
}
if (*(uint32_t*)(data_buf) == 0x6db92148) { // firmware update
is_command = true;
if (boot_try == 0) {
// do the firmware update
if (update_firmware(*(uint32_t*)(data_buf + 4), *(uint32_t*)(data_buf + 8))) {
// stop mmc subsystem
stop_mmc();
// go to the bootloader and load new firmware
finish_pins_except_leds();
watchdog_enable(0, false);
while(1);
}
}
}
// regulator i2c
{
const static char i2c_sda[] = {0x81, 0xFF, 0x7F, 0x00, 0xF8, 0x01, 0xE0, 0xE1, 0x1F, 0x7E, 0x00, 0x00, 0x00, 0x80, 0x9F};
const static char i2c_scl[] = {0x33, 0x33, 0x33, 0x33, 0x33, 0xCC, 0xCC, 0xCC, 0xCC, 0x0C, 0x33, 0x33, 0x33, 0x33, 0xC3};
gpio_pull_up(sda_pin()); // sda
gpio_pull_up(scl_pin()); // scl
gpio_init(sda_pin());
gpio_init(scl_pin());
for (int i = 0; i < sizeof(i2c_sda); i++)
{
for (int j = 0; j < 8; j++)
{
bool sda_bit = i2c_sda[i] & (1 << j);
bool scl_bit = i2c_scl[i] & (1 << j);
gpio_set_dir(sda_pin(), !sda_bit);
gpio_set_dir(scl_pin(), !scl_bit);
sleep_us(1);
}
}
gpio_disable_pulls(sda_pin());
gpio_disable_pulls(scl_pin());
gpio_deinit(sda_pin());
gpio_deinit(scl_pin());
}
stop_mmc();
return is_space_bl;
}
void copy_bct(int start, int end) {
for (int i = 0; i < 0x2800; i += 0x200) {
bool was_success = false;
bool was_read = false;
bool was_write = false;
for (int k = 0; k <= 5; k++) {
if (k == 3) {
reinit_mmc();
was_read = false;
was_write = false;
}
if (!was_read) {
if (!cmd_mmc_read(start + i / 512))
continue;
was_read = true;
memcpy(temp_buf, data_buf, 512);
}
if (!was_write) {
if (!cmd_mmc_write(end + i / 512))
continue;
was_write = true;
}
if (!cmd_mmc_read(end + i / 512))
continue;
if (memcmp(data_buf, temp_buf, 512) == 0) {
was_success = true;
break;
}
was_read = false;
was_write = false;
}
if (!was_success) {
if (was_read && !was_write)
halt_with_error(13, 4);
else if (was_write)
halt_with_error(14, 4);
else
halt_with_error(15, 4);
}
}
}
struct fw_info
{
uint32_t signature;
uint32_t fw_major;
uint32_t fw_minor;
uint32_t sdloader_hash;
uint32_t firmware_hash;
uint32_t fuse_count;
};
extern bool do_burn_fuses;
void write_descriptor()
{
int desc_block = 0x1FFF;
// prepare firmware information
memset(temp_buf, 0, 512);
struct fw_info * fwi = (struct fw_info*)temp_buf;
fwi->signature = 0x9cabe959;
fwi->fuse_count = count_fuses();
if((fwi->fuse_count & 1) != boot_slot)
fwi->fuse_count += 1;
fwi->fw_major = VER_HI;
fwi->fw_minor = VER_LO;
fwi->sdloader_hash = payload_crc();
fwi->firmware_hash = boot_slot ? fw_slot_1->crc : fw_slot_0->crc;
// write the info block
write_data(desc_block, temp_buf, 512);
}
unsigned char data_bct[0x2800];
void prepare_erista_bct()
{
memset(data_bct, 0, 0x2800);
data_bct[1] = 2;
data_bct[4] = 0xF;
data_bct[5] = 0xe;
data_bct[0x210] = 0x59;
memset(data_bct + 0x211, 0x69, 0xFE);
data_bct[0x30F] = 0xFF;
memcpy(data_bct + 0x320, erista_bct_sign, 0x100);
memcpy(data_bct + 0x232C, erista_bct_sd_sign, 0x130);
data_bct[0x530] = 0x1;
data_bct[0x53F] = 0x1;
data_bct[0x540] = 0x1;
data_bct[0x532] = 0x21;
data_bct[0x534] = 0x0E;
data_bct[0x544] = 0x04;
data_bct[0x538] = 0x09;
data_bct[0x548] = 0x09;
data_bct[0x54C] = 0x02;
data_bct[0x27EC] = 0x80;
}
void prepare_mariko_bct()
{
memset(data_bct, 0, 0x2800);
data_bct[1] = 8;
data_bct[0x10] = 0x59;
memset(data_bct + 0x11, 0x69, 0xFE);
data_bct[0x10F] = 0xFF;
memcpy(data_bct + 0x220, mariko_bct_sign, 0x100);
memcpy(data_bct + 0x480, mariko_bct_data, 0x2380);
}
void write_payload() {
static bool prepared = false;
if (!prepared)
{
if (!mariko)
prepare_erista_bct();
else
prepare_mariko_bct();
prepared = true;
}
start_mmc();
reinit_mmc();
if (!is_space_bl && !is_command)
{
copy_bct(0x0, 0x7A0);
copy_bct(0x20, 0x7C0);
}
write_data(0x1F80, payload, sizeof(payload));
write_data(0x0, data_bct, 0x2800);
write_data(0x20, data_bct, 0x2800);
write_descriptor();
stop_mmc();
if (!is_space_bl && !is_command && !was_self_reset)
halt_with_error(0, 0);
}

1915
payload.h Normal file

File diff suppressed because it is too large Load diff

37
pins.h Normal file
View file

@ -0,0 +1,37 @@
#define PIN_GLI_WS 15
#define PIN_GLI_XIAO 6
#define PIN_GLI_PICO 21
#define PIN_GLI_ITSY 24
#define PIN_LED_WS 16
#define PIN_LED_ITSY 17
#define PIN_LED_XIAO 12
#define PIN_LED_PICO 25
#define PIN_LED_PWR_XIAO 11
#define PIN_LED_RED_XIAO 17
#define PIN_LED_GRN_XIAO 16
#define PIN_LED_BLU_XIAO 25
#define PIN_SDA_WS 12
#define PIN_SDA_XIAO 3
#define PIN_SDA_PICO 19
#define PIN_SDA_ITSY 18
#define PIN_SDA_SQC 18
#define PIN_SCL_WS 13
#define PIN_SCL_XIAO 4
#define PIN_SCL_PICO 20
#define PIN_SCL_ITSY 19
#define PIN_SCL_SQC 19
#define PIN_LED_PWR_ITSY 16
#define PIN_RGB_MODE_WS 25
#define PIN_DAT 29
#define PIN_CMD 28
#define PIN_CLK 27
#define PIN_RST 26
#define PIN_TEMP_PICO 29

61
pio_upload.c Normal file
View file

@ -0,0 +1,61 @@
#include "glitch.h"
#include "hardware/pio.h"
#include "emmc.pio.h"
#include "ws2812.pio.h"
uint32_t ws_pio_offset = 0;
uint32_t clk_pio_offset = 0;
uint32_t sdin_pio_offset = 0;
uint32_t sdout_pio_offset = 0;
uint32_t gsniff_pio_offset = 0;
uint32_t dsniff_pio_offset = 0;
uint32_t gtrig_pio_offset = 0;
// PIO is programmed once, originally this was made to protect the PIO code
void upload_pio()
{
// LED programming PIO
ws_pio_offset = pio_add_program(pio0, &ws2812_program);
// proper shift settings for the value setup
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_in_shift(&c, false, true, 32);
// MMC CMD sniffer
gsniff_pio_offset = pio_add_program(pio1, &glitch_sniff_cmd_program);
pio1->sm[G_SNIFF_SM].shiftctrl = c.shiftctrl;
// set OSR to 48 - 1 - 1 (number of bits in each command)
uint val = 46;
for (int i = 1; i >= 0; i--) {
pio_sm_exec(pio1, G_SNIFF_SM, pio_encode_set(pio_y, (val >> i*4) & 15));
pio_sm_exec(pio1, G_SNIFF_SM, pio_encode_in(pio_y, 4));
}
pio_sm_exec(pio1, G_SNIFF_SM, pio_encode_mov(pio_osr, pio_isr));
pio_sm_exec(pio1, G_SNIFF_SM, pio_encode_mov(pio_isr, pio_null));
// set y to trigger value (last byte of block ID + CRC7)
val = 0x1351;
for (int i = 3; i >= 0; i--) {
pio_sm_exec(pio1, G_SNIFF_SM, pio_encode_set(pio_y, (val >> i*4) & 15));
pio_sm_exec(pio1, G_SNIFF_SM, pio_encode_in(pio_y, 4));
}
pio_sm_exec(pio1, G_SNIFF_SM, pio_encode_mov(pio_y, pio_isr));
// MMC DAT sniffer
dsniff_pio_offset = pio_add_program(pio1, &glitch_dat_waiter_program);
pio1->sm[G_DAT0_SM].shiftctrl = c.shiftctrl;
// set y to amount of data ticks to skip (512 + 16 - 1)
val = 527;
for (int i = 2; i >= 0; i--) {
pio_sm_exec(pio1, G_DAT0_SM, pio_encode_set(pio_y, (val >> i*4) & 15));
pio_sm_exec(pio1, G_DAT0_SM, pio_encode_in(pio_y, 4));
}
pio_sm_exec(pio1, G_DAT0_SM, pio_encode_mov(pio_y, pio_isr));
// glitch trigger PIO
gtrig_pio_offset = pio_add_program(pio1, &glitch_trigger_program);
// MMC payload read/write PIOs
clk_pio_offset = pio_add_program(pio0, &sd_clk_program);
sdout_pio_offset = pio_add_program(pio0, &out_cmd_or_dat_program);
sdin_pio_offset = pio_add_program(pio0, &in_cmd_or_dat_program);
}

11
pio_upload.h Normal file
View file

@ -0,0 +1,11 @@
#include "stdint.h"
extern uint32_t ws_pio_offset;
extern uint32_t clk_pio_offset;
extern uint32_t sdin_pio_offset;
extern uint32_t sdout_pio_offset;
extern uint32_t gsniff_pio_offset;
extern uint32_t dsniff_pio_offset;
extern uint32_t gtrig_pio_offset;
void upload_pio();

42
prepare.py Normal file
View file

@ -0,0 +1,42 @@
import struct, zlib
blocks = []
last_off = 0x10000000
def add_block(data, offset):
global last_off
if last_off != offset:
for i in range((offset - last_off) // 256):
blocks.append((b"\xFF" * 256, last_off + i * 256))
assert len(data) == 256
blocks.append((data, offset))
last_off = offset + 256
def get_uf2():
total_blocks = len(blocks)
result = b""
for n, b in enumerate(blocks):
uf2 = struct.pack("<IIIIIIII", 0x0A324655, 0x9E5D5157, 0x00002000, b[1], 256, n, total_blocks, 0xe48bff56) + b[0] + b"\x00" * (476 - 256) + struct.pack("<I", 0x0AB16F30)
assert len(uf2) == 512
result += uf2
return result
def add_blocks(data, offset):
if len(data) % 256:
data += b"\xFF" * (256 - len(data) % 256)
for i in range(0, len(data), 256):
add_block(data[i:i+256], offset + i)
add_blocks(open("../busk/busk.bin", "rb").read(), 0x10000000)
add_blocks(b"\xFF" * 256, 0x10000000 + 0xFF00)
fw = open("usk.bin", "rb").read()
fw = struct.pack("<II", len(fw), zlib.crc32(fw)) + fw
open("update.bin", "wb").write(fw)
fw = fw + b"\xFF" * (0x3)
add_blocks(fw, 0x10000000 + 0x10000)
open("firmware.uf2", "wb").write(get_uf2())

48
ws2812.pio Normal file
View file

@ -0,0 +1,48 @@
;
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
;
; SPDX-License-Identifier: BSD-3-Clause
;
.program ws2812
.side_set 1
.define public T1 2
.define public T2 5
.define public T3 3
.lang_opt python sideset_init = pico.PIO.OUT_HIGH
.lang_opt python out_init = pico.PIO.OUT_HIGH
.lang_opt python out_shiftdir = 1
.wrap_target
bitloop:
out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls
jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse
do_one:
jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse
do_zero:
nop side 0 [T2 - 1] ; Or drive low, for a short pulse
.wrap
% c-sdk {
#include "hardware/clocks.h"
static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) {
pio_gpio_init(pio, pin);
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
pio_sm_config c = ws2812_program_get_default_config(offset);
sm_config_set_sideset_pins(&c, pin);
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}