working hax 👀
This commit is contained in:
parent
565d13b7d4
commit
829c665e23
|
@ -19,9 +19,12 @@ void cli_tool78_glitch_dump(void);
|
|||
void cli_tool78_glitch_paramsearch(void);
|
||||
void cli_tool78_glitch_ocd_dump(void);
|
||||
|
||||
#define DUMP_OFFSET 0xef000
|
||||
#define DUMP_OFFSET 0/*0xef000*/
|
||||
#define DUMP_SIZE 4096
|
||||
|
||||
// test with decoupling caps: length in 20..500(..1500) -> ok
|
||||
// testing on ocd lock: length: 5..35
|
||||
|
||||
/*
|
||||
hw inited
|
||||
baudrate result=0xc1
|
||||
|
@ -36,17 +39,18 @@ result: 0x06. sig:
|
|||
secget: 0x06
|
||||
sec: flg=fe bot=03 fsws=0000 fswe=003f
|
||||
*/
|
||||
//void trl78_uart1_set_exclusive(bool ex);
|
||||
|
||||
static uint8_t databuf[DUMP_SIZE];
|
||||
|
||||
static void glitch_init_core1_stuff(void) {
|
||||
static void glitch_init_core1_stuff(bool exttrig) {
|
||||
// REGC = 2.11V / 0.47..1 uF // WUFM: REGC = 1.80V // BUT: OCD mode: always 2.1!
|
||||
static const struct glitch_params gparam = (struct glitch_params){
|
||||
static struct glitch_params gparam = (struct glitch_params){
|
||||
.offset_min_us = 10,
|
||||
.offset_max_us = 35433/100,
|
||||
.offset_max_us = 35433,
|
||||
// with REGC & 10uF Vcc:
|
||||
.length_min_us = 30000,//*4,
|
||||
.length_max_us = 60000,//*8,
|
||||
.length_min_us = -1,//10,//-1,//20,
|
||||
.length_max_us = 100,//*8,
|
||||
// with REGC:
|
||||
/*.length_min_us = 4000,
|
||||
.length_max_us = 6300,*/
|
||||
|
@ -60,13 +64,14 @@ static void glitch_init_core1_stuff(void) {
|
|||
// * REGC@VDD, short pulses: 0V
|
||||
// * with REGC, 10uF@VDD, long pulses: 0..3mV (strict upper limit)
|
||||
// * 100uF@VDD: too much, even w/o REGC
|
||||
.trigger_in_pin = TRIGGER_IN_PIN,
|
||||
.trigger_in_pin = -2,
|
||||
.glitch_out_pin = GLITCH_OUT_PIN,
|
||||
.trigger_in_polarity = glitch_positive,
|
||||
.glitch_out_polarity = glitch_positive,
|
||||
.impl = glitch_impl_core1,
|
||||
.offset_cur = 0, .length_cur = 0
|
||||
};
|
||||
gparam.trigger_in_pin = exttrig ? TRIGGER_IN_PIN : (-1);
|
||||
glitch_ready(&gparam);
|
||||
}
|
||||
static void glitch_init_pwm_stuff(void) {
|
||||
|
@ -178,7 +183,7 @@ deinit_bad:
|
|||
}
|
||||
|
||||
void cli_tool78_glitch_paramsearch(void) {
|
||||
glitch_init_core1_stuff();
|
||||
glitch_init_core1_stuff(true);
|
||||
|
||||
uint8_t passwd[10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
uint16_t ver;
|
||||
|
@ -193,11 +198,22 @@ restart:
|
|||
|
||||
ver=0;
|
||||
st = tool78_init_ocd(&tool78_hw_rl78_uart1, &ver, passwd);
|
||||
if (st == 0xc3) {
|
||||
printf("aa\n");
|
||||
st = 0;
|
||||
rr = tool78_hw_rl78_uart1.recv(1, (uint8_t*)&st, 120*1000);
|
||||
printf("rr=%d\n", rr);
|
||||
if (rr != 1) {
|
||||
printf("aaaa\n");
|
||||
goto do_reset_stuff;
|
||||
}
|
||||
}
|
||||
//printf("result: 0x%02x ver=%04x\n", st, ver);
|
||||
if (st != 0xf2 && st != 0xf0) {
|
||||
printf("init: %d\n", st);
|
||||
printf("init: 0x%02x\n", st);
|
||||
goto deinit_bad;
|
||||
}
|
||||
if (first) printf("result: 0x%02x ver=%04x\n", st, ver);
|
||||
|
||||
// can't write too much at 0xf07e0 as 0xf0800 and up contains OCD state,
|
||||
// overwrite this and suddenly the OCD system resets itself
|
||||
|
@ -268,7 +284,7 @@ restart:
|
|||
// timeout or something
|
||||
printf("X");
|
||||
tool78_hw_rl78_uart1.deinit();
|
||||
goto restart;
|
||||
goto do_reset_stuff;
|
||||
} else {
|
||||
int firstbad = -1, lastbad = -1;
|
||||
for (int i = 0; i < rr; ++i) {
|
||||
|
@ -290,30 +306,51 @@ restart:
|
|||
deinit_bad:
|
||||
tool78_hw_rl78_uart1.deinit();
|
||||
return;
|
||||
|
||||
do_reset_stuff:
|
||||
tool78_hw_rl78_uart1.deinit();
|
||||
|
||||
// glitch for way too long to power cycle
|
||||
sio_hw->gpio_set = 1u << GLITCH_OUT_PIN;
|
||||
busy_wait_ms(16);
|
||||
sio_hw->gpio_clr = 1u << GLITCH_OUT_PIN;
|
||||
|
||||
goto restart;
|
||||
}
|
||||
|
||||
void cli_tool78_glitch_ocd_dump(void) {
|
||||
glitch_init_core1_stuff();
|
||||
glitch_init_core1_stuff(false);
|
||||
|
||||
//gpio_set_function(2, GPIO_FUNC_SIO);
|
||||
//gpio_set_dir(2, GPIO_OUT);
|
||||
//gpio_put(2, false);
|
||||
|
||||
//gpio_set_function(3, GPIO_FUNC_SIO);
|
||||
//gpio_set_dir(3, GPIO_OUT);
|
||||
//gpio_put(3, false);
|
||||
|
||||
uint8_t passwd[10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
uint16_t ver;
|
||||
int st, rr;
|
||||
int st, rr/*, r0, r1, r2*/;
|
||||
static uint8_t checkbuf[256];
|
||||
bool first = true;
|
||||
|
||||
restart:
|
||||
//trl78_uart1_set_exclusive(true);
|
||||
//tool78_hw_rl78_uart1.rx_set_stop_bit(false);
|
||||
//gpio_put(2, false);
|
||||
/*glitch_disarm();
|
||||
busy_wait_ms(40);*/
|
||||
|
||||
ver=0;
|
||||
st = tool78_init_ocd(&tool78_hw_rl78_uart1, &ver, passwd);
|
||||
if (st == 0xc3) {
|
||||
printf("aa\n");
|
||||
//printf("aa\n");
|
||||
st = 0;
|
||||
rr = tool78_hw_rl78_uart1.recv(1, (uint8_t*)&st, 120*1000);
|
||||
printf("rr=%d\n", rr);
|
||||
//printf("rr=%d\n", rr);
|
||||
if (rr != 1) {
|
||||
printf("aaaa\n");
|
||||
//printf("aaaa\n");
|
||||
goto do_reset_stuff;
|
||||
}
|
||||
}
|
||||
|
@ -341,18 +378,21 @@ restart:
|
|||
if (first) printf("all set, let's go\n");
|
||||
first = false;
|
||||
|
||||
//tool78_hw_rl78_uart1.rx_set_stop_bit(false);
|
||||
glitch_arm();
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
glitch_trigger_sw_core1();
|
||||
rr = tool78_hw_rl78_uart1.recv(1, checkbuf, 12*1000);
|
||||
if (rr != 1) {
|
||||
busy_wait_ms(1); // leave time to recharge
|
||||
printf(".");
|
||||
//printf(".");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("checkbuf: %d", checkbuf[0]);
|
||||
printf("\n!!!\n");
|
||||
/*printf("checkbuf: %d", checkbuf[0]);
|
||||
printf("\n!!!\n");*/
|
||||
tool78_hw_rl78_uart1.flags |= tool78_hw_flag_done_reset;
|
||||
|
||||
glitch_disarm();
|
||||
goto success;
|
||||
}
|
||||
|
@ -369,18 +409,39 @@ do_reset_stuff:
|
|||
|
||||
goto restart;
|
||||
|
||||
success:
|
||||
success:;
|
||||
//gpio_put(2, true);
|
||||
//busy_wait_ms(5);
|
||||
// (02): read from above (checkbuf) code
|
||||
// 03 06 18 00 df 03
|
||||
// ^-- baud rate set response
|
||||
// 00
|
||||
// ^-- OCD entry response
|
||||
rr = tool78_hw_rl78_uart1.recv(7, &databuf[0], 10000);
|
||||
if (rr != 7) {
|
||||
printf("rr=%d, wut?\n", rr);
|
||||
goto do_reset_stuff;
|
||||
}
|
||||
|
||||
busy_wait_us_32(500);
|
||||
|
||||
ver = 0;
|
||||
st = tool78_ocd_version(&tool78_hw_rl78_uart1, &ver);
|
||||
if (st) {
|
||||
printf("OCD: get version failed: %d\n", st);
|
||||
goto do_reset_stuff;
|
||||
}
|
||||
printf("got ver! %04x\n", ver);
|
||||
|
||||
printf("len: %lu\n", *(volatile uint32_t*)&glitch_param_cur.length_cur);
|
||||
goto do_reset_stuff;
|
||||
|
||||
st = tool78_ocd_connect(&tool78_hw_rl78_uart1, passwd);
|
||||
if (st != 0xf0 && st != 0xf2) {
|
||||
printf("OCD: connect failed: %d\n", st);
|
||||
goto deinit_bad;
|
||||
}
|
||||
printf("connect! 0x%02x\n", st);
|
||||
|
||||
// can't write too much at 0xf07e0 as 0xf0800 and up contains OCD state,
|
||||
// overwrite this and suddenly the OCD system resets itself
|
||||
|
@ -406,9 +467,10 @@ success:
|
|||
goto deinit_bad;
|
||||
}
|
||||
|
||||
for (size_t iii = 0; iii < DUMP_SIZE; ++iii) {
|
||||
for (size_t iii = 0; iii < DUMP_SIZE + DUMP_OFFSET; ++iii) {
|
||||
// wait for completion
|
||||
rr = tool78_hw_rl78_uart1.recv(1, &databuf[iii], 120*1000*1000);
|
||||
size_t off = (iii < DUMP_OFFSET) ? 0 : (iii - DUMP_OFFSET);
|
||||
rr = tool78_hw_rl78_uart1.recv(1, &databuf[off], 120*1000*1000);
|
||||
if (rr != 1) {
|
||||
printf("exec code: no response :/ (%d)\n", rr);
|
||||
goto deinit_bad;
|
||||
|
|
201
src/cli/rl78.c
201
src/cli/rl78.c
|
@ -9,23 +9,11 @@ void cli_tool78_testtest(void);
|
|||
void cli_tool78_prototest(void);
|
||||
void cli_tool78_ocdtest(void);
|
||||
|
||||
/*static uint16_t DATA_text[0x24] = {
|
||||
0xc232,0x43c2,0x0000,0x4031,0x02fe,0x40f2,0x00ff,0x002a,0x40b2,0x5a10,0x0120,
|
||||
0x43d2,0x0000,0xd232,0xd032,0x0018,0x3ffd,0xc3d2,0x0002,0xd3d2,0x0000,0xe3d2,
|
||||
0x0029,0x4130,0x1300,0x1300,0x1300,0x1300,0x1300,0x1300,0x12b0,0xf822,0x1300,
|
||||
0x1300,0x1300,0x3fdc
|
||||
};
|
||||
static uint16_t DATA_vectors[0x10] = {
|
||||
0xf830,0xf830,0xf832,0xf834,0xf836,0xf830,0xf830,0xf830,
|
||||
0xf838,0xf83a,0xf83c,0xf842,0xf830,0xf830,0xf844,0xf846
|
||||
};
|
||||
|
||||
// 2k/8k flash, 256b RAM
|
||||
static uint16_t dumpmem_ram[256>>1];
|
||||
static uint16_t dumpmem_flash[8192>>1];*/
|
||||
static uint8_t DATA_main_dbgpad[1024];
|
||||
static uint8_t DATA_main_nodbg [1024];
|
||||
|
||||
static uint8_t shellcode_test[] = {
|
||||
0x51, 0x61, // mov a, #97
|
||||
0x51, 0x61, // mov a, #'a'
|
||||
0xfc, 0xa1, 0xff, 0x0e, // call !!effa1
|
||||
|
||||
0xd7, // ret
|
||||
|
@ -88,6 +76,8 @@ sec: flg=fe bot=03 fsws=0000 fswe=000f
|
|||
blank check: 0x06
|
||||
*/
|
||||
|
||||
uint8_t* datatoflash = true ? DATA_main_nodbg : DATA_main_dbgpad;
|
||||
|
||||
// NOTE: RL78 ONLY
|
||||
struct tool78_security sec;
|
||||
memset(&sec, 0, sizeof sec);
|
||||
|
@ -95,15 +85,20 @@ blank check: 0x06
|
|||
printf("secget: 0x%02x\n", st);
|
||||
printf("sec: flg=%02x bot=%02x fsws=%04x fswe=%04x\n", sec.flg, sec.bot, sec.fsws, sec.fswe);
|
||||
|
||||
//st = tool78_do_security_release(&tool78_hw_rl78_uart1);
|
||||
/*//st = tool78_do_security_release(&tool78_hw_rl78_uart1);
|
||||
//printf("sec rel: 0x%02x\n", st);
|
||||
/*st = tool78_do_block_blank_check(hw, 0, 0x3ff, false);
|
||||
printf("blank check: 0x%02x\n", st);*/
|
||||
/*st = tool78_do_programming(hw, 0, 0x000ff, DATA_test_rom);
|
||||
printf("programming: 0x%02x\n", st);*/
|
||||
// one block = 0x400 = 1k
|
||||
st = tool78_do_block_erase(hw, 0, -1);
|
||||
printf("block erase 0: 0x%02x\n", st);
|
||||
st = tool78_do_block_blank_check(hw, 0, 0x3ff, false);
|
||||
printf("blank check: 0x%02x\n", st);
|
||||
st = tool78_do_programming(hw, 0, 0x003ff, datatoflash);
|
||||
printf("programming: 0x%02x\n", st);
|
||||
|
||||
/*st = tool78_do_verify(hw, 0, 0x0ff, DATA_test_rom);
|
||||
st = tool78_do_verify(hw, 0, 0x3ff, datatoflash);
|
||||
printf("verify: 0x%02x\n", st);*/
|
||||
|
||||
tool78_hw_rl78_uart1.deinit();
|
||||
}
|
||||
|
||||
void cli_tool78_ocdtest(void) {
|
||||
|
@ -162,3 +157,167 @@ deinit_bad:
|
|||
return;
|
||||
}
|
||||
|
||||
static uint8_t DATA_main_dbgpad[1024] = {
|
||||
0xda, 0x00, 0x00, 0x00, 0x43, 0x01, 0x4f, 0x01, 0x5b, 0x01, 0x67, 0x01, 0x73,
|
||||
0x01, 0x7f, 0x01, 0x8b, 0x01, 0x97, 0x01, 0xa3, 0x01, 0xaf, 0x01, 0xbb, 0x01,
|
||||
0xc7, 0x01, 0xd3, 0x01, 0xff, 0xff, 0xdf, 0x01, 0xff, 0xff, 0xeb, 0x01, 0xf7,
|
||||
0x01, 0x03, 0x02, 0x0f, 0x02, 0x1b, 0x02, 0x27, 0x02, 0x33, 0x02, 0x3f, 0x02,
|
||||
0x4b, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x57, 0x02, 0x63, 0x02, 0x6f,
|
||||
0x02, 0x7b, 0x02, 0x87, 0x02, 0x93, 0x02, 0x9f, 0x02, 0xab, 0x02, 0xb7, 0x02,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x02, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x1a, 0xe0,
|
||||
0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xcb, 0xf8, 0xe0,
|
||||
0xfe, 0x41, 0x00, 0x61, 0xcf, 0x34, 0xd4, 0x03, 0x36, 0x80, 0xf9, 0x61, 0xdf,
|
||||
0x36, 0x80, 0xf9, 0x30, 0x80, 0xf9, 0x27, 0x31, 0x1e, 0x44, 0x00, 0x00, 0xdd,
|
||||
0x0e, 0xb1, 0x61, 0xcf, 0x11, 0xa9, 0xbb, 0xa5, 0xa5, 0xa7, 0xa7, 0x61, 0xdf,
|
||||
0xef, 0xed, 0x61, 0xcf, 0x36, 0x00, 0xf9, 0x30, 0x00, 0x00, 0x61, 0xdf, 0x30,
|
||||
0x00, 0xf9, 0x27, 0x31, 0x1e, 0x44, 0x00, 0x00, 0xdd, 0x0a, 0xb1, 0x61, 0xcf,
|
||||
0xbb, 0xa7, 0xa7, 0x61, 0xdf, 0xef, 0xf1, 0x61, 0xcf, 0xfc, 0x38, 0x01, 0x00,
|
||||
0x00, 0x30, 0x00, 0x00, 0xc1, 0xc1, 0xc1, 0xfc, 0xcf, 0x02, 0x00, 0xef, 0xfe,
|
||||
0x71, 0x7b, 0xfa, 0xfc, 0xa6, 0x03, 0x00, 0x71, 0x7a, 0xfa, 0xd7, 0x61, 0xcf,
|
||||
0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1,
|
||||
0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3,
|
||||
0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5,
|
||||
0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7,
|
||||
0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6,
|
||||
0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4,
|
||||
0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2,
|
||||
0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0,
|
||||
0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61,
|
||||
0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc,
|
||||
0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61,
|
||||
0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf,
|
||||
0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1,
|
||||
0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3,
|
||||
0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5,
|
||||
0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7,
|
||||
0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6,
|
||||
0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4,
|
||||
0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2,
|
||||
0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0,
|
||||
0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61,
|
||||
0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc,
|
||||
0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61,
|
||||
0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf,
|
||||
0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1,
|
||||
0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3,
|
||||
0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5,
|
||||
0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7,
|
||||
0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6,
|
||||
0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4,
|
||||
0xc2, 0xc0, 0x61, 0xfc, 0xf5, 0x22, 0xff, 0xf5, 0x62, 0x00, 0xf5, 0x77, 0x00,
|
||||
0xf5, 0x79, 0x00, 0xf5, 0x75, 0x00, 0xf5, 0x7c, 0x00, 0xf5, 0x02, 0xff, 0xc9,
|
||||
0xf2, 0x02, 0xff, 0xc9, 0xf0, 0x00, 0x40, 0x00, 0xb6, 0xf0, 0xad, 0xf0, 0x44,
|
||||
0x00, 0x00, 0x61, 0xe8, 0xec, 0xec, 0x02, 0x00, 0xad, 0xf2, 0x16, 0x8b, 0x7c,
|
||||
0xfe, 0x9b, 0xc9, 0xf0, 0x00, 0x40, 0xec, 0xec, 0x02, 0x00, 0x20, 0x02, 0xcf,
|
||||
0xa0, 0xff, 0x14, 0xc9, 0xf0, 0xa1, 0xff, 0xad, 0xf0, 0x16, 0x71, 0xf2, 0x71,
|
||||
0x48, 0xa4, 0xff, 0x71, 0xe3, 0xf6, 0xb8, 0x00, 0x44, 0xa0, 0x00, 0x61, 0xf3,
|
||||
0xec, 0x39, 0x03, 0x00, 0x00, 0xa8, 0x00, 0xa1, 0xb8, 0x00, 0x44, 0xa0, 0x00,
|
||||
0x61, 0xe3, 0xec, 0x2a, 0x03, 0x00, 0xf5, 0xf3, 0x00, 0x71, 0x68, 0xa4, 0xff,
|
||||
0x71, 0x08, 0xa1, 0xff, 0x10, 0x02, 0xd7, 0xf5, 0x00, 0xff, 0xcf, 0x01, 0xff,
|
||||
0x07, 0xf5, 0x02, 0xff, 0xf5, 0x03, 0xff, 0xf5, 0x04, 0xff, 0xf5, 0x05, 0xff,
|
||||
0xf5, 0x06, 0xff, 0xf5, 0x07, 0xff, 0xf5, 0x0c, 0xff, 0xf5, 0x0d, 0xff, 0xf5,
|
||||
0x0e, 0xff, 0x51, 0x03, 0x9f, 0x30, 0x00, 0x51, 0xf3, 0x9f, 0x60, 0x00, 0x51,
|
||||
0xfe, 0x9f, 0x6c, 0x00, 0x51, 0x7f, 0x9f, 0x6e, 0x00, 0xe5, 0x76, 0x00, 0xcf,
|
||||
0x20, 0xff, 0x83, 0xf5, 0x21, 0xff, 0xf5, 0x22, 0xff, 0xcf, 0x23, 0xff, 0xfc,
|
||||
0xcf, 0x24, 0xff, 0xf1, 0xcf, 0x25, 0xff, 0xc0, 0xcf, 0x26, 0xff, 0xf0, 0xf5,
|
||||
0x27, 0xff, 0xcf, 0x2c, 0xff, 0xfe, 0xcf, 0x2e, 0xff, 0x3c, 0xd7, 0xf5, 0x77,
|
||||
0x00, 0xfc, 0x47, 0x03, 0x00, 0xfc, 0x09, 0x03, 0x00, 0xf5, 0xf0, 0x02, 0xf5,
|
||||
0x78, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
static uint8_t DATA_main_nodbg[1024] = {
|
||||
0xda, 0x00, 0x00, 0x00, 0x43, 0x01, 0x4f, 0x01, 0x5b, 0x01, 0x67, 0x01, 0x73,
|
||||
0x01, 0x7f, 0x01, 0x8b, 0x01, 0x97, 0x01, 0xa3, 0x01, 0xaf, 0x01, 0xbb, 0x01,
|
||||
0xc7, 0x01, 0xd3, 0x01, 0xff, 0xff, 0xdf, 0x01, 0xff, 0xff, 0xeb, 0x01, 0xf7,
|
||||
0x01, 0x03, 0x02, 0x0f, 0x02, 0x1b, 0x02, 0x27, 0x02, 0x33, 0x02, 0x3f, 0x02,
|
||||
0x4b, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x57, 0x02, 0x63, 0x02, 0x6f,
|
||||
0x02, 0x7b, 0x02, 0x87, 0x02, 0x93, 0x02, 0x9f, 0x02, 0xab, 0x02, 0xb7, 0x02,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x02, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x1a, 0xe0,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0xcb, 0xf8, 0xe0,
|
||||
0xfe, 0x41, 0x00, 0x61, 0xcf, 0x34, 0xd4, 0x03, 0x36, 0x80, 0xf9, 0x61, 0xdf,
|
||||
0x36, 0x80, 0xf9, 0x30, 0x80, 0xf9, 0x27, 0x31, 0x1e, 0x44, 0x00, 0x00, 0xdd,
|
||||
0x0e, 0xb1, 0x61, 0xcf, 0x11, 0xa9, 0xbb, 0xa5, 0xa5, 0xa7, 0xa7, 0x61, 0xdf,
|
||||
0xef, 0xed, 0x61, 0xcf, 0x36, 0x00, 0xf9, 0x30, 0x00, 0x00, 0x61, 0xdf, 0x30,
|
||||
0x00, 0xf9, 0x27, 0x31, 0x1e, 0x44, 0x00, 0x00, 0xdd, 0x0a, 0xb1, 0x61, 0xcf,
|
||||
0xbb, 0xa7, 0xa7, 0x61, 0xdf, 0xef, 0xf1, 0x61, 0xcf, 0xfc, 0x38, 0x01, 0x00,
|
||||
0x00, 0x30, 0x00, 0x00, 0xc1, 0xc1, 0xc1, 0xfc, 0xcf, 0x02, 0x00, 0xef, 0xfe,
|
||||
0x71, 0x7b, 0xfa, 0xfc, 0xa6, 0x03, 0x00, 0x71, 0x7a, 0xfa, 0xd7, 0x61, 0xcf,
|
||||
0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1,
|
||||
0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3,
|
||||
0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5,
|
||||
0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7,
|
||||
0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6,
|
||||
0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4,
|
||||
0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2,
|
||||
0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0,
|
||||
0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61,
|
||||
0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc,
|
||||
0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61,
|
||||
0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf,
|
||||
0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1,
|
||||
0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3,
|
||||
0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5,
|
||||
0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7,
|
||||
0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6,
|
||||
0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4,
|
||||
0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2,
|
||||
0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0,
|
||||
0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61,
|
||||
0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc,
|
||||
0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61,
|
||||
0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf,
|
||||
0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1,
|
||||
0xc3, 0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3,
|
||||
0xc5, 0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5,
|
||||
0xc7, 0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7,
|
||||
0xc6, 0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6,
|
||||
0xc4, 0xc2, 0xc0, 0x61, 0xfc, 0x61, 0xcf, 0xc1, 0xc3, 0xc5, 0xc7, 0xc6, 0xc4,
|
||||
0xc2, 0xc0, 0x61, 0xfc, 0xf5, 0x22, 0xff, 0xf5, 0x62, 0x00, 0xf5, 0x77, 0x00,
|
||||
0xf5, 0x79, 0x00, 0xf5, 0x75, 0x00, 0xf5, 0x7c, 0x00, 0xf5, 0x02, 0xff, 0xc9,
|
||||
0xf2, 0x02, 0xff, 0xc9, 0xf0, 0x00, 0x40, 0x00, 0xb6, 0xf0, 0xad, 0xf0, 0x44,
|
||||
0x00, 0x00, 0x61, 0xe8, 0xec, 0xec, 0x02, 0x00, 0xad, 0xf2, 0x16, 0x8b, 0x7c,
|
||||
0xfe, 0x9b, 0xc9, 0xf0, 0x00, 0x40, 0xec, 0xec, 0x02, 0x00, 0x20, 0x02, 0xcf,
|
||||
0xa0, 0xff, 0x14, 0xc9, 0xf0, 0xa1, 0xff, 0xad, 0xf0, 0x16, 0x71, 0xf2, 0x71,
|
||||
0x48, 0xa4, 0xff, 0x71, 0xe3, 0xf6, 0xb8, 0x00, 0x44, 0xa0, 0x00, 0x61, 0xf3,
|
||||
0xec, 0x39, 0x03, 0x00, 0x00, 0xa8, 0x00, 0xa1, 0xb8, 0x00, 0x44, 0xa0, 0x00,
|
||||
0x61, 0xe3, 0xec, 0x2a, 0x03, 0x00, 0xf5, 0xf3, 0x00, 0x71, 0x68, 0xa4, 0xff,
|
||||
0x71, 0x08, 0xa1, 0xff, 0x10, 0x02, 0xd7, 0xf5, 0x00, 0xff, 0xcf, 0x01, 0xff,
|
||||
0x07, 0xf5, 0x02, 0xff, 0xf5, 0x03, 0xff, 0xf5, 0x04, 0xff, 0xf5, 0x05, 0xff,
|
||||
0xf5, 0x06, 0xff, 0xf5, 0x07, 0xff, 0xf5, 0x0c, 0xff, 0xf5, 0x0d, 0xff, 0xf5,
|
||||
0x0e, 0xff, 0x51, 0x03, 0x9f, 0x30, 0x00, 0x51, 0xf3, 0x9f, 0x60, 0x00, 0x51,
|
||||
0xfe, 0x9f, 0x6c, 0x00, 0x51, 0x7f, 0x9f, 0x6e, 0x00, 0xe5, 0x76, 0x00, 0xcf,
|
||||
0x20, 0xff, 0x83, 0xf5, 0x21, 0xff, 0xf5, 0x22, 0xff, 0xcf, 0x23, 0xff, 0xfc,
|
||||
0xcf, 0x24, 0xff, 0xf1, 0xcf, 0x25, 0xff, 0xc0, 0xcf, 0x26, 0xff, 0xf0, 0xf5,
|
||||
0x27, 0xff, 0xcf, 0x2c, 0xff, 0xfe, 0xcf, 0x2e, 0xff, 0x3c, 0xd7, 0xf5, 0x77,
|
||||
0x00, 0xfc, 0x47, 0x03, 0x00, 0xfc, 0x09, 0x03, 0x00, 0xf5, 0xf0, 0x02, 0xf5,
|
||||
0x78, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ static void CORE1_FUNC(pcg32_fast_init)(uint64_t seed) {
|
|||
|
||||
|
||||
// ADC value is in low 12 bits of adc_read()
|
||||
// FIXME: length_min_us = -1 => adc breaks?
|
||||
// FIXME: length_min_us = -1 => adc breaks? | oops was signedness bug
|
||||
#define CORE1_PRE_CALC() /* BIG TODO HERE! */ \
|
||||
uint32_t off = param_cur.offset_min_us + \
|
||||
(pcg32_fast() % (param_cur.offset_max_us - param_cur.offset_min_us)), \
|
||||
|
@ -193,8 +193,9 @@ static void CORE0_FUNC(glitch_stop_no_clock_chg)(void) {
|
|||
hw_write_masked(&padsbank0_hw->io[param_cur.glitch_out_pin]
|
||||
, (PADS_BANK0_GPIO0_IE_BITS)
|
||||
| ((uint)GPIO_SLEW_RATE_SLOW << PADS_BANK0_GPIO0_SLEWFAST_LSB)
|
||||
| (PADS_BANK0_GPIO0_DRIVE_VALUE_2MA << PADS_BANK0_GPIO0_DRIVE_LSB)
|
||||
, (PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS)
|
||||
| (PADS_BANK0_GPIO0_SLEWFAST_BITS)
|
||||
| PADS_BANK0_GPIO0_SLEWFAST_BITS | PADS_BANK0_GPIO0_DRIVE_BITS
|
||||
);
|
||||
hw_write_masked(&iobank0_hw->io[param_cur.glitch_out_pin].ctrl
|
||||
, ((uint)GPIO_FUNC_NULL << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB)
|
||||
|
@ -277,6 +278,7 @@ bool CORE0_FUNC(glitch_ready)(const struct glitch_params* params) {
|
|||
}
|
||||
|
||||
//gpio_put(params->glitch_out_pin, false);
|
||||
// TODO: gpio_set_drive_strength(PIN_PULSE, GPIO_DRIVE_STRENGTH_12MA);
|
||||
//gpio_set_slew_rate(params->glitch_out_pin, GPIO_SLEW_RATE_FAST);
|
||||
//gpio_set_dir(params->glitch_out_pin, GPIO_OUT);
|
||||
//gpio_set_outover(params->glitch_out_pin,
|
||||
|
@ -287,17 +289,17 @@ bool CORE0_FUNC(glitch_ready)(const struct glitch_params* params) {
|
|||
sio_hw->gpio_clr = 1u << param_cur.glitch_out_pin;
|
||||
sio_hw->gpio_oe_set = 1u << param_cur.glitch_out_pin;
|
||||
hw_write_masked(&padsbank0_hw->io[param_cur.glitch_out_pin]
|
||||
, (PADS_BANK0_GPIO0_IE_BITS)
|
||||
, PADS_BANK0_GPIO0_IE_BITS
|
||||
| ((uint)GPIO_SLEW_RATE_FAST << PADS_BANK0_GPIO0_SLEWFAST_LSB)
|
||||
, (PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS)
|
||||
| (PADS_BANK0_GPIO0_SLEWFAST_BITS)
|
||||
| (PADS_BANK0_GPIO0_DRIVE_VALUE_12MA << PADS_BANK0_GPIO0_DRIVE_LSB)
|
||||
, PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS
|
||||
| PADS_BANK0_GPIO0_SLEWFAST_BITS | PADS_BANK0_GPIO0_DRIVE_BITS
|
||||
);
|
||||
hw_write_masked(&iobank0_hw->io[param_cur.glitch_out_pin].ctrl
|
||||
, (func << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB)
|
||||
| ((uint)(param_cur.glitch_out_polarity ? GPIO_OVERRIDE_INVERT
|
||||
: GPIO_OVERRIDE_NORMAL) << IO_BANK0_GPIO0_CTRL_OUTOVER_LSB)
|
||||
, (IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS)
|
||||
| (IO_BANK0_GPIO0_CTRL_OUTOVER_BITS)
|
||||
, IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS | IO_BANK0_GPIO0_CTRL_OUTOVER_BITS
|
||||
);
|
||||
|
||||
multicore_launch_core1(glitch_core1_thread);
|
||||
|
|
|
@ -19,8 +19,8 @@ enum glitch_impl {
|
|||
struct glitch_params {
|
||||
uint32_t offset_min_us;
|
||||
uint32_t offset_max_us;
|
||||
uint32_t length_min_us;
|
||||
uint32_t length_max_us;
|
||||
int32_t length_min_us;
|
||||
int32_t length_max_us;
|
||||
int trigger_in_pin; // use -1 for a signal coming from core 0
|
||||
int glitch_out_pin;
|
||||
enum glitch_polarity trigger_in_polarity;
|
||||
|
|
|
@ -2,12 +2,17 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hardware/clocks.h>
|
||||
#include <hardware/vreg.h>
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/binary_info.h>
|
||||
|
||||
#include "cli.h"
|
||||
|
||||
int main() {
|
||||
/*vreg_set_voltage(VREG_VOLTAGE_1_15);
|
||||
set_sys_clock_khz(200*1000, true);*/
|
||||
|
||||
cli_init();
|
||||
|
||||
while (true) {
|
||||
|
|
|
@ -79,6 +79,7 @@ static inline void tool78_uart_tx_program_init(PIO pio, uint sm, uint offset,
|
|||
%}
|
||||
|
||||
.program tool78_uart_rx
|
||||
;.side_set 1
|
||||
|
||||
; 8n1
|
||||
; no autopush
|
||||
|
@ -86,33 +87,40 @@ static inline void tool78_uart_tx_program_init(PIO pio, uint sm, uint offset,
|
|||
; bit period = 1/8 PIO cycle period
|
||||
|
||||
start:
|
||||
wait 0 pin 0 ; wait for start bit
|
||||
set x, 7 [10] ; 8 data bits. delay until middle of data bit period
|
||||
wait 0 pin 0 ;side 0 ; wait for start bit
|
||||
set x, 7 [10] ;side 1 ; 8 data bits. delay until middle of data bit period
|
||||
loop:
|
||||
in pins, 1 ; read the bit
|
||||
jmp x-- loop [ 6]
|
||||
in pins, 1 ;side 0 ; read the bit
|
||||
jmp x-- loop [ 6] ;side 0
|
||||
|
||||
jmp pin stop_ok ; if pin high (stop bit): all is ok
|
||||
public stopbit_magic:
|
||||
jmp pin stop_ok ;side 0 ; if pin high (stop bit): all is ok
|
||||
|
||||
irq 4 rel ; set sticky flag due to missing stop bit
|
||||
mov isr, null ; clear shift reg as the data is nonsense
|
||||
wait 1 pin 0 ; wait until line goes idle/high again
|
||||
jmp start ; restart
|
||||
irq 4 rel ;side 0 ; set sticky flag due to missing stop bit
|
||||
mov isr, null ;side 0 ; clear shift reg as the data is nonsense
|
||||
wait 1 pin 0 ;side 0 ; wait until line goes idle/high again
|
||||
jmp start ;side 0 ; restart
|
||||
|
||||
stop_ok:
|
||||
push
|
||||
public stop_ok:
|
||||
push ;side 0
|
||||
|
||||
% c-sdk {
|
||||
|
||||
static inline void tool78_uart_rx_program_init(PIO pio, uint sm, uint offset,
|
||||
uint pin, uint baudrate, bool en) {
|
||||
//const int PIN_DBG = 4;
|
||||
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false); // pin is input now
|
||||
pio_gpio_init(pio, pin);
|
||||
gpio_pull_up(pin);
|
||||
|
||||
//pio_sm_set_consecutive_pindirs(pio, sm, PIN_DBG, 1, true);
|
||||
//pio_gpio_init(pio, PIN_DBG);
|
||||
|
||||
pio_sm_config c = tool78_uart_rx_program_get_default_config(offset);
|
||||
sm_config_set_in_pins(&c, pin);
|
||||
sm_config_set_jmp_pin(&c, pin);
|
||||
//sm_config_set_sideset_pins(&c, PIN_DBG);
|
||||
|
||||
// no autopull, MSb first
|
||||
sm_config_set_in_shift(&c, false, false, 8);
|
||||
|
@ -123,8 +131,20 @@ static inline void tool78_uart_rx_program_init(PIO pio, uint sm, uint offset,
|
|||
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, en);
|
||||
gpio_put(3, true);
|
||||
}
|
||||
|
||||
//static inline void tool78_uart_rx_enable_stop(PIO pio, uint offset) {
|
||||
// /*pio->instr_mem[offset + tool78_uart_rx_offset_stopbit_magic] =
|
||||
// pio_encode_jmp_pin(offset + tool78_uart_rx_offset_stop_ok);*/
|
||||
//}
|
||||
//static inline void tool78_uart_rx_disable_stop(PIO pio, uint offset) {
|
||||
// /*pio->instr_mem[offset + tool78_uart_rx_offset_stopbit_magic] =
|
||||
// pio_encode_push(false, true)
|
||||
// //pio_encode_jmp(offset + tool78_uart_rx_offset_stop_ok)
|
||||
// ;*/
|
||||
//}
|
||||
|
||||
// TODO: IRQ handling!
|
||||
|
||||
%}
|
||||
|
|
|
@ -472,7 +472,7 @@ enum tool78_stat tool78_do_programming(struct tool78_hw* hw, uint32_t start,
|
|||
if (st != tool78_stat_ack) return st;
|
||||
}
|
||||
|
||||
st = tool78_wait_status(hw, 1, isrl78 ? tSS5 : (tWT5 * nblocks));
|
||||
st = tool78_wait_status(hw, 1, isrl78 ? (tSS5*10) : (tWT5 * nblocks));
|
||||
if (st != tool78_stat_ack) return st;
|
||||
|
||||
return st;
|
||||
|
@ -771,10 +771,20 @@ int tool78_ocd_version(struct tool78_hw* hw, uint16_t* ver) {
|
|||
int rr = hw->send(1, &bytes[0], -1);
|
||||
|
||||
// bytes[0] is tool78ocd_cmd_version echoed back
|
||||
rr = hw->recv(3, bytes, 100000);
|
||||
if (rr != 3) return -1;
|
||||
rr = hw->recv(3, bytes, 1000);
|
||||
if (rr != 3) {
|
||||
/*printf("OCDver rr: %d\n", rr);
|
||||
for (int iii = 0; iii < rr; ++iii) {
|
||||
printf("0x%02x%c", bytes[iii], (iii==rr-1)?'\n':' ');
|
||||
}*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ver = bytes[1] | ((uint16_t)bytes[2] << 8);
|
||||
if (rr == 3) {
|
||||
*ver = bytes[1] | ((uint16_t)bytes[2] << 8);
|
||||
} /*else {
|
||||
*ver = bytes[0] | ((uint16_t)bytes[1] << 8);
|
||||
}*/
|
||||
//printf("ver=%04x\n", *ver);
|
||||
return 0;
|
||||
}
|
||||
|
@ -786,8 +796,14 @@ int tool78_ocd_connect(struct tool78_hw* hw, const uint8_t passwd[10]) {
|
|||
int rr = hw->send(1, &stuff[0], -1);
|
||||
|
||||
// stuff[1] is tool78ocd_cmd_connect echoed back
|
||||
rr = hw->recv(2, &stuff[1], 100000);
|
||||
if (rr != 2) return -1;
|
||||
rr = hw->recv(2, &stuff[1], 1000);
|
||||
if (rr != 2) {
|
||||
/*printf("OCDconn rr: %d\n", rr);
|
||||
for (int iii = 0; iii < rr; ++iii) {
|
||||
printf("0x%02x%c", stuff[1+iii], (iii==rr-1)?'\n':' ');
|
||||
}*/
|
||||
//return -1;
|
||||
}
|
||||
connst=stuff[2];
|
||||
if (connst == 0xf0 || connst == 0xf4) return connst;
|
||||
// connst==0xf1
|
||||
|
@ -800,8 +816,14 @@ int tool78_ocd_connect(struct tool78_hw* hw, const uint8_t passwd[10]) {
|
|||
|
||||
// stuff[9] is the checksum byte echoed back
|
||||
rr = hw->recv(2, &stuff[9], 100000);
|
||||
//printf("conn rr=%d\n", rr);
|
||||
if (rr != 2) return -2;
|
||||
if (rr != 2) {
|
||||
/*printf("OCDconn2 rr: %d\n", rr);
|
||||
for (int iii = 0; iii < rr; ++iii) {
|
||||
printf("0x%02x%c", stuff[9+iii], (iii==rr-1)?'\n':' ');
|
||||
}*/
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
/*printf("cksum=0x%02x conn=%02x pw=%02x\n",
|
||||
cksum, connst, stuff[10]);*/
|
||||
|
@ -818,13 +840,13 @@ int tool78_ocd_read(struct tool78_hw* hw, uint16_t off, uint8_t len,
|
|||
hdr[2] = off >> 8;
|
||||
hdr[1] = off & 0xff;
|
||||
hdr[3] = len;
|
||||
printf("rd len=%u\n", len);
|
||||
//printf("rd len=%u\n", len);
|
||||
|
||||
int rr = hw->send(sizeof hdr, hdr, -1);
|
||||
rr = hw->recv(1, &hdr[2], 1000);
|
||||
// last byte of header sent echoed back
|
||||
if (rr != 1 || hdr[2] != hdr[3]) {
|
||||
printf("rd recv=%02x\n", hdr[2]);
|
||||
//printf("rd recv=%02x\n", hdr[2]);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -912,6 +934,8 @@ static enum tool78_stat tool78_init_common(struct tool78_hw* hw) {
|
|||
}
|
||||
|
||||
enum tool78_stat tool78_init_sfp(struct tool78_hw* hw, tool78_silicon_sig_t* sig) {
|
||||
hw->flags &= ~tool78_hw_flag_do_ocd;
|
||||
|
||||
enum tool78_stat st = tool78_init_common(hw);
|
||||
if (st != tool78_stat_ack) return st;
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ struct tool78_hw {
|
|||
// retval: negative if an rx overrun occurred
|
||||
int (*recv)(int len, uint8_t* data, int32_t timeout_ms);
|
||||
int (*send)(int len, const uint8_t* data, int32_t timeout_ms);
|
||||
|
||||
void (*rx_set_stop_bit)(bool enable);
|
||||
};
|
||||
|
||||
extern struct tool78_hw
|
||||
|
|
|
@ -58,6 +58,7 @@ static bool t78k0_spi_init(void) {
|
|||
return false; // OCD not supported with this phy
|
||||
vars.exclusive = false;
|
||||
vars.bitswap = false;
|
||||
//vars.nostopbit = false;
|
||||
|
||||
// extclk between 2 and 20 MHz
|
||||
tool78_entryseq_78k0(tool78_entry_78k0_spi);
|
||||
|
@ -100,6 +101,10 @@ static void t78k0_spi_set_baudrate(uint32_t baudrate) {
|
|||
pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smrx, div);
|
||||
}
|
||||
|
||||
/*static void t78k0_spi_rx_set_stop_bit(bool enable) {
|
||||
(void)enable;
|
||||
}*/
|
||||
|
||||
struct tool78_hw tool78_hw_78k0_spi = {
|
||||
.target = tool78k0_spi,
|
||||
|
||||
|
@ -110,6 +115,8 @@ struct tool78_hw tool78_hw_78k0_spi = {
|
|||
.has_available = t78k0_spi_has_available,
|
||||
|
||||
.recv = t78k0_spi_recv,
|
||||
.send = t78k0_spi_send
|
||||
.send = t78k0_spi_send,
|
||||
|
||||
//.rx_set_stop_bit = t78k0_spi_rx_set_stop_bit
|
||||
};
|
||||
|
||||
|
|
|
@ -79,6 +79,10 @@ static void t78k0_uart2_set_baudrate(uint32_t baudrate) {
|
|||
pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div);
|
||||
}
|
||||
|
||||
/*static void t78k0_uart2_rx_set_stop_bit(bool enable) {
|
||||
tool78_rx_set_stop_bit(&vars, enable);
|
||||
}*/
|
||||
|
||||
struct tool78_hw tool78_hw_78k0_uart2 = {
|
||||
.target = tool78k0_uart2,
|
||||
|
||||
|
@ -89,6 +93,8 @@ struct tool78_hw tool78_hw_78k0_uart2 = {
|
|||
.has_available = t78k0_uart2_has_available,
|
||||
|
||||
.recv = t78k0_uart2_recv,
|
||||
.send = t78k0_uart2_send
|
||||
.send = t78k0_uart2_send,
|
||||
|
||||
//.rx_set_stop_bit = t78k0_uart2_rx_set_stop_bit
|
||||
};
|
||||
|
||||
|
|
|
@ -87,6 +87,10 @@ static void t78k0_uart2_extclk_set_baudrate(uint32_t baudrate) {
|
|||
pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div);
|
||||
}
|
||||
|
||||
/*static void t78k0_uart2_extclk_rx_set_stop_bit(bool enable) {
|
||||
tool78_rx_set_stop_bit(&vars, enable);
|
||||
}*/
|
||||
|
||||
struct tool78_hw tool78_hw_78k0_uart2_extclk = {
|
||||
.target = tool78k0_uart2_extclk,
|
||||
|
||||
|
@ -97,6 +101,8 @@ struct tool78_hw tool78_hw_78k0_uart2_extclk = {
|
|||
.has_available = t78k0_uart2_extclk_has_available,
|
||||
|
||||
.recv = t78k0_uart2_extclk_recv,
|
||||
.send = t78k0_uart2_extclk_send
|
||||
.send = t78k0_uart2_extclk_send,
|
||||
|
||||
//.rx_set_stop_bit = t78k0_uart2_extclk_rx_set_stop_bit
|
||||
};
|
||||
|
||||
|
|
|
@ -78,6 +78,10 @@ static void t78k0r_uart1_set_baudrate(uint32_t baudrate) {
|
|||
pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div);
|
||||
}
|
||||
|
||||
/*static void t78k0r_uart1_rx_set_stop_bit(bool enable) {
|
||||
tool78_rx_set_stop_bit(&vars, enable);
|
||||
}*/
|
||||
|
||||
struct tool78_hw tool78_hw_78k0r_uart1 = {
|
||||
.target = tool78k0r_uart1,
|
||||
|
||||
|
@ -88,6 +92,8 @@ struct tool78_hw tool78_hw_78k0r_uart1 = {
|
|||
.has_available = t78k0r_uart1_has_available,
|
||||
|
||||
.recv = t78k0r_uart1_recv,
|
||||
.send = t78k0r_uart1_send
|
||||
.send = t78k0r_uart1_send,
|
||||
|
||||
//.rx_set_stop_bit = t78k0r_uart1_rx_set_stop_bit
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/pio.h>
|
||||
#include <pico/time.h>
|
||||
|
@ -86,6 +88,7 @@ bool tool78_hw_help_check_overrun(const struct tool78_pio_vars* vars) {
|
|||
pio_sm_exec(PINOUT_TOOL78_PIO, vars->smrx, pio_encode_jmp(vars->rxoff));
|
||||
pio_sm_set_enabled(PINOUT_TOOL78_PIO, vars->smrx, true);
|
||||
|
||||
//printf("rxover!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -100,10 +103,13 @@ int tool78_hw_has_available_help(const struct tool78_pio_vars* vars) {
|
|||
|
||||
int tool78_hw_help_recv(const struct tool78_pio_vars* vars,
|
||||
int len, uint8_t* data, int32_t timeout_us) {
|
||||
pio_sm_set_enabled(PINOUT_TOOL78_PIO, vars->smrx, true);
|
||||
|
||||
bool overrun = tool78_hw_help_check_overrun(vars);
|
||||
|
||||
bool blockinf = timeout_us < 0;
|
||||
int i = 0;
|
||||
uint8_t irq;
|
||||
|
||||
absolute_time_t at = make_timeout_time_us(timeout_us);
|
||||
timeout_state_t ts = {0};
|
||||
|
@ -123,14 +129,26 @@ int tool78_hw_help_recv(const struct tool78_pio_vars* vars,
|
|||
}
|
||||
|
||||
end:
|
||||
irq = PINOUT_TOOL78_PIO->irq;
|
||||
PINOUT_TOOL78_PIO->irq = irq;
|
||||
if (irq) {
|
||||
printf("irq: 0x%02x\n", irq);
|
||||
}
|
||||
irq = PINOUT_TOOL78_PIO->intr;
|
||||
if (irq&0xf00) {
|
||||
printf("intr: 0x%02x\n", irq);
|
||||
}
|
||||
|
||||
return overrun ? (!i ? (int)0x08000000 : -i) : i;
|
||||
}
|
||||
|
||||
int tool78_hw_help_send(const struct tool78_pio_vars* vars, uint32_t sleep_us_between_bytes,
|
||||
int len, const uint8_t* data, int32_t timeout_us) {
|
||||
|
||||
if (vars->exclusive)
|
||||
if (vars->exclusive) {
|
||||
//gpio_put(3, false);
|
||||
pio_sm_set_enabled(PINOUT_TOOL78_PIO, vars->smrx, false);
|
||||
}
|
||||
|
||||
bool blockinf = timeout_us < 0;
|
||||
absolute_time_t at = make_timeout_time_us(timeout_us);
|
||||
|
@ -150,13 +168,19 @@ int tool78_hw_help_send(const struct tool78_pio_vars* vars, uint32_t sleep_us_be
|
|||
// FIXME: THIS IS NOT HOW TO WAIT BETWEEN TWO BYTES YOU DOOFUS
|
||||
// (ok maybe it might work because of bad reasons, so let's fix this
|
||||
// once it causes problems)
|
||||
if (sleep_us_between_bytes && (i != len-1 || !(tool78_hw_rl78_uart1.flags & tool78_hw_flag_done_reset)))
|
||||
// FIXME: also remove the dependency on tool78_hw_rl78_uart1!
|
||||
if (sleep_us_between_bytes && ((i != len-1
|
||||
/*&& !(tool78_hw_rl78_uart1.flags & tool78_hw_flag_do_ocd)*/)
|
||||
|| !(tool78_hw_rl78_uart1.flags & tool78_hw_flag_done_reset))) {
|
||||
busy_wait_us_32(sleep_us_between_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (vars->exclusive) {
|
||||
if (tool78_hw_rl78_uart1.flags & tool78_hw_flag_done_reset) {
|
||||
// FIXME: remove the dependency on tool78_hw_rl78_uart1!
|
||||
if ((tool78_hw_rl78_uart1.flags & tool78_hw_flag_done_reset)
|
||||
/*&& !(tool78_hw_rl78_uart1.flags & tool78_hw_flag_do_ocd)*/) {
|
||||
// wait until everything is sent before reenabling the RX SM again
|
||||
while (!pio_sm_is_tx_fifo_empty(PINOUT_TOOL78_PIO, vars->smtx))
|
||||
; // wait until FIFO is clear
|
||||
|
@ -164,6 +188,7 @@ end:
|
|||
; // now wait for the SM to hang on the next 'pull'
|
||||
}
|
||||
|
||||
//gpio_put(3, true);
|
||||
pio_sm_set_enabled(PINOUT_TOOL78_PIO, vars->smrx, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,15 @@
|
|||
|
||||
#include <hardware/pio.h>
|
||||
|
||||
#include "tool78_defs.h"
|
||||
#include "tool78.pio.h"
|
||||
|
||||
struct tool78_pio_vars {
|
||||
uint txoff, rxoff;
|
||||
int smtx, smrx;
|
||||
// temporarily disable rx when doing tx (typically desired when doing
|
||||
// single-wire UART, as otherwise the data would be echoing back)
|
||||
bool exclusive, bitswap;
|
||||
bool exclusive, bitswap/*, nostopbit*/;
|
||||
};
|
||||
|
||||
// claims and inits program space & state machines, saves the offsets & SMs
|
||||
|
@ -45,6 +48,15 @@ void tool78_deinit_78k0r(void);
|
|||
void tool78_entryseq_rl78(enum tool78_entry typ);
|
||||
void tool78_deinit_rl78(void);
|
||||
|
||||
/*inline static void tool78_rx_set_stop_bit(struct tool78_pio_vars* vars,
|
||||
bool enable) {
|
||||
vars->nostopbit = !enable;
|
||||
if (enable) {
|
||||
tool78_uart_rx_enable_stop(PINOUT_TOOL78_PIO, vars->rxoff);
|
||||
} else {
|
||||
tool78_uart_rx_disable_stop(PINOUT_TOOL78_PIO, vars->rxoff);
|
||||
}
|
||||
}*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -70,6 +70,15 @@ static void trl78_uart1_set_baudrate(uint32_t baudrate) {
|
|||
pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div);
|
||||
}
|
||||
|
||||
/*static void trl78_uart1_rx_set_stop_bit(bool enable) {
|
||||
tool78_rx_set_stop_bit(&vars, enable);
|
||||
}
|
||||
|
||||
void trl78_uart1_set_exclusive(bool ex) {
|
||||
(void)ex;
|
||||
//vars.exclusive = ex;
|
||||
}*/
|
||||
|
||||
struct tool78_hw tool78_hw_rl78_uart1 = {
|
||||
.target = tool78rl_uart1,
|
||||
|
||||
|
@ -80,6 +89,8 @@ struct tool78_hw tool78_hw_rl78_uart1 = {
|
|||
.has_available = trl78_uart1_has_available,
|
||||
|
||||
.recv = trl78_uart1_recv,
|
||||
.send = trl78_uart1_send
|
||||
.send = trl78_uart1_send,
|
||||
|
||||
//.rx_set_stop_bit = trl78_uart1_rx_set_stop_bit
|
||||
};
|
||||
|
||||
|
|
|
@ -74,6 +74,10 @@ static void trl78_uart2_set_baudrate(uint32_t baudrate) {
|
|||
pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div);
|
||||
}
|
||||
|
||||
/*static void trl78_uart2_rx_set_stop_bit(bool enable) {
|
||||
tool78_rx_set_stop_bit(&vars, enable);
|
||||
}*/
|
||||
|
||||
struct tool78_hw tool78_hw_rl78_uart2 = {
|
||||
.target = tool78rl_uart2,
|
||||
|
||||
|
@ -84,6 +88,8 @@ struct tool78_hw tool78_hw_rl78_uart2 = {
|
|||
.has_available = trl78_uart2_has_available,
|
||||
|
||||
.recv = trl78_uart2_recv,
|
||||
.send = trl78_uart2_send
|
||||
.send = trl78_uart2_send,
|
||||
|
||||
//.rx_set_stop_bit = trl78_uart2_rx_set_stop_bit
|
||||
};
|
||||
|
||||
|
|
|
@ -60,6 +60,10 @@ static void test_set_baudrate(uint32_t baudrate) {
|
|||
pio_sm_set_clkdiv(PINOUT_TOOL78_PIO, vars.smtx, div);
|
||||
}
|
||||
|
||||
/*static void test_uart2_rx_set_stop_bit(bool enable) {
|
||||
tool78_rx_set_stop_bit(&vars, enable);
|
||||
}*/
|
||||
|
||||
struct tool78_hw tool78_hw_test_uart2 = {
|
||||
.target = tool78k0_uart2,
|
||||
|
||||
|
@ -70,6 +74,8 @@ struct tool78_hw tool78_hw_test_uart2 = {
|
|||
.has_available = test_has_available,
|
||||
|
||||
.recv = test_recv,
|
||||
.send = test_send
|
||||
.send = test_send,
|
||||
|
||||
//.rx_set_stop_bit = test_uart2_rx_set_stop_bit
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue