kopia lustrzana https://github.com/conorpp/u2f-zero
cleaned up the printing situation
rodzic
a809d9dc37
commit
86a56dade4
|
|
@ -15,9 +15,7 @@ SI_SBIT(SCL, SFR_P1, 3); // and P1.3
|
|||
SI_SBIT (LED1, SFR_P1, 4); // LED green
|
||||
|
||||
// debug options
|
||||
//#define U2F_PRINT
|
||||
#define DBG_MESSAGE_SIZE 30
|
||||
#define DBG_MSG_COUNT 4
|
||||
#define U2F_PRINT
|
||||
|
||||
#define KEYHANDLES_START (EEPROM_DATA_START + 30)
|
||||
#define KEYHANDLES_COUNT 14
|
||||
|
|
@ -57,72 +55,10 @@ struct APP_DATA
|
|||
|
||||
extern data struct APP_DATA appdata;
|
||||
|
||||
struct debug_msg
|
||||
{
|
||||
char buf[DBG_MESSAGE_SIZE];
|
||||
};
|
||||
|
||||
void set_app_error(APP_ERROR_CODE ec);
|
||||
|
||||
|
||||
|
||||
|
||||
#define FIFO_HEADER(NAME, TYPE)\
|
||||
void NAME##_fifo_init();\
|
||||
int NAME##_fifo_append(TYPE* _data);\
|
||||
int NAME##_fifo_get(TYPE* _data)
|
||||
|
||||
|
||||
#ifdef U2F_PRINT
|
||||
FIFO_HEADER(debug, struct debug_msg);
|
||||
#else
|
||||
#define debug_fifo_init(x)
|
||||
#define debug_fifo_get(x)
|
||||
#define debug_fifo_append(x)
|
||||
#endif
|
||||
|
||||
#define FIFO_CREATE(NAME, TYPE, SIZE) \
|
||||
static SI_SEGMENT_VARIABLE(NAME##MEM[SIZE],TYPE,SI_SEG_XDATA);\
|
||||
volatile TYPE* NAME##WP;\
|
||||
volatile TYPE* NAME##RP;\
|
||||
void NAME##_fifo_init()\
|
||||
{\
|
||||
NAME##WP = NAME##MEM;\
|
||||
NAME##RP = NAME##MEM;\
|
||||
}\
|
||||
int NAME##_fifo_append(TYPE* _data)\
|
||||
{\
|
||||
volatile TYPE* next = 0;\
|
||||
next = NAME##WP + 1;\
|
||||
if (next == (NAME##MEM + SIZE))\
|
||||
{\
|
||||
next = NAME##MEM;\
|
||||
}\
|
||||
if (next == NAME##RP)\
|
||||
{\
|
||||
return -1;\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
*(NAME##WP) = *_data;\
|
||||
NAME##WP = next;\
|
||||
return 0;\
|
||||
}\
|
||||
}\
|
||||
int NAME##_fifo_get(TYPE* _data)\
|
||||
{\
|
||||
if (NAME##RP == NAME##WP)\
|
||||
{\
|
||||
return -1;\
|
||||
}\
|
||||
*_data = *(NAME##RP);\
|
||||
NAME##RP = NAME##RP + 1;\
|
||||
if (NAME##RP == &NAME##MEM[SIZE])\
|
||||
{\
|
||||
NAME##RP = NAME##MEM;\
|
||||
}\
|
||||
return 0;\
|
||||
}
|
||||
|
||||
|
||||
#endif /* APP_H_ */
|
||||
|
|
|
|||
|
|
@ -32,42 +32,43 @@ SI_SBIT(LED_G, SFR_P1, 4);
|
|||
|
||||
void u2f_delay(int16_t ms);
|
||||
|
||||
void u2f_write_s(char* d);
|
||||
|
||||
void usb_write(uint8_t* buf, uint8_t len);
|
||||
|
||||
|
||||
//void u2f_putv(uint32_t i, uint8_t base);
|
||||
//
|
||||
//#define u2f_put(i) u2f_putv(i,10)
|
||||
//#define u2f_putx(i) u2f_putv(i,16)
|
||||
void u2f_putb(uint8_t i);
|
||||
void u2f_putd(int16_t i);
|
||||
void u2f_putx(uint16_t i);
|
||||
void u2f_putl(int32_t i);
|
||||
void u2f_putlx(int32_t i);
|
||||
|
||||
#define u2f_prints(c) u2f_write_s(c)
|
||||
void u2f_printb(const char * tag, uint8_t c, ...);
|
||||
void u2f_printd(const char * tag, uint8_t c, ...);
|
||||
void u2f_printx(const char * tag, uint8_t c, ...);
|
||||
void u2f_printl(const char * tag, uint8_t c, ...);
|
||||
void u2f_printlx(const char * tag, uint8_t c, ...);
|
||||
|
||||
|
||||
#ifdef U2F_PRINT
|
||||
|
||||
void u2f_print(char* fmt, ...);
|
||||
|
||||
// not reentrant
|
||||
void dump_hex(uint8_t* hex, uint8_t len);
|
||||
void flush_messages();
|
||||
void u2f_putb(uint8_t i);
|
||||
void u2f_putd(int16_t i);
|
||||
void u2f_putx(uint16_t i);
|
||||
void u2f_putl(int32_t i);
|
||||
void u2f_putlx(int32_t i);
|
||||
|
||||
void u2f_prints(const char * str);
|
||||
void u2f_printb(const char * tag, uint8_t c, ...);
|
||||
void u2f_printd(const char * tag, uint8_t c, ...);
|
||||
void u2f_printx(const char * tag, uint8_t c, ...);
|
||||
void u2f_printl(const char * tag, uint8_t c, ...);
|
||||
void u2f_printlx(const char * tag, uint8_t c, ...);
|
||||
|
||||
#else
|
||||
#define u2f_print(x)
|
||||
// #define dump_hex(x)
|
||||
void dump_hex(uint8_t* hex, uint8_t len);
|
||||
#define flush_messages(x)
|
||||
|
||||
#define u2f_printx(x)
|
||||
#define u2f_printb(x)
|
||||
#define u2f_printlx(x)
|
||||
#define u2f_printl(x)
|
||||
#define u2f_printd(x)
|
||||
#define u2f_prints(x)
|
||||
|
||||
#define u2f_putx(x)
|
||||
#define u2f_putb(x)
|
||||
#define u2f_putl(x)
|
||||
#define u2f_putlx(x)
|
||||
|
||||
#define putf(x)
|
||||
#define dump_hex(x)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,6 @@ int8_t atecc_send_recv(uint8_t cmd, uint8_t p1, uint16_t p2,
|
|||
if (errors > 5)
|
||||
{
|
||||
u2f_printb("fail recv ", 1,appdata.error);
|
||||
flush_messages();
|
||||
}
|
||||
switch(appdata.error)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,51 +16,18 @@ void u2f_delay(uint16_t ms) {
|
|||
{}
|
||||
}
|
||||
|
||||
void usb_write(uint8_t* buf, uint8_t len)
|
||||
{
|
||||
int16_t ec;
|
||||
if (USB_STATUS_OK != (ec=USBD_Write(EP1IN, buf, len, false)))
|
||||
{
|
||||
u2f_printd("USB error",1, -ec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef U2F_PRINT
|
||||
|
||||
xdata struct debug_msg dbg;
|
||||
|
||||
void u2f_print(char* fmt, ...)
|
||||
{
|
||||
|
||||
struct debug_msg dbg;
|
||||
va_list args;
|
||||
|
||||
va_start(args,fmt);
|
||||
if(vsprintf(dbg.buf, fmt, args) > sizeof(struct debug_msg)-1)
|
||||
{
|
||||
u2f_write_s("vsprintf stack corrupt!\r\n");
|
||||
}
|
||||
va_end(args);
|
||||
debug_fifo_append(&dbg);
|
||||
}
|
||||
// not reentrant
|
||||
void dump_hex(uint8_t* hex, uint8_t len)
|
||||
{
|
||||
uint8_t i;
|
||||
flush_messages();
|
||||
for (i=0 ; i < len ; i++)
|
||||
{
|
||||
u2f_print("%02bx",hex[i]);
|
||||
//if ((i%4) == 3)
|
||||
// u2f_print("\r\n");
|
||||
flush_messages();
|
||||
|
||||
}
|
||||
u2f_print("\r\n");
|
||||
flush_messages();
|
||||
}
|
||||
|
||||
void flush_messages()
|
||||
{
|
||||
while(debug_fifo_get(&dbg) == 0)
|
||||
{
|
||||
u2f_write_s(dbg.buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
void dump_hex(uint8_t* hex, uint8_t len)
|
||||
|
|
@ -82,7 +49,7 @@ void putf(char c)
|
|||
for (i=0; i<200; i++){}
|
||||
}
|
||||
|
||||
void u2f_write_s(char* d)
|
||||
void u2f_prints(char* d)
|
||||
{
|
||||
static SI_SEG_DATA uint16_t i;
|
||||
while(*d)
|
||||
|
|
@ -158,106 +125,105 @@ char * __int2str16(int32_t i)
|
|||
|
||||
void u2f_putb(uint8_t i)
|
||||
{
|
||||
u2f_write_s(xint2str((uint32_t)i));
|
||||
u2f_prints(xint2str((uint32_t)i));
|
||||
}
|
||||
|
||||
void u2f_putd(int16_t i)
|
||||
{
|
||||
u2f_write_s(dint2str((int32_t)i));
|
||||
u2f_prints(dint2str((int32_t)i));
|
||||
}
|
||||
|
||||
void u2f_putx(uint16_t i)
|
||||
{
|
||||
u2f_write_s(xint2str((int32_t)i));
|
||||
u2f_prints(xint2str((int32_t)i));
|
||||
}
|
||||
|
||||
void u2f_putl(int32_t i)
|
||||
{
|
||||
u2f_write_s(dint2str((int32_t)i));
|
||||
u2f_prints(dint2str((int32_t)i));
|
||||
}
|
||||
void u2f_putlx(int32_t i)
|
||||
{
|
||||
u2f_write_s(xint2str((int32_t)i));
|
||||
u2f_prints(xint2str((int32_t)i));
|
||||
}
|
||||
|
||||
void u2f_printd(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
u2f_write_s(tag);
|
||||
u2f_prints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
u2f_putd(va_arg(args, int16_t));
|
||||
u2f_write_s(" ");
|
||||
u2f_prints(" ");
|
||||
}
|
||||
u2f_write_s("\r\n");
|
||||
u2f_prints("\r\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void u2f_printl(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
u2f_write_s(tag);
|
||||
u2f_prints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
u2f_putl(va_arg(args, int32_t));
|
||||
u2f_write_s(" ");
|
||||
u2f_prints(" ");
|
||||
}
|
||||
u2f_write_s("\r\n");
|
||||
u2f_prints("\r\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void u2f_printx(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
u2f_write_s(tag);
|
||||
u2f_prints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
u2f_putx(va_arg(args, uint16_t));
|
||||
u2f_write_s(" ");
|
||||
u2f_prints(" ");
|
||||
}
|
||||
u2f_write_s("\r\n");
|
||||
u2f_prints("\r\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void u2f_printb(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
u2f_write_s(tag);
|
||||
u2f_prints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
u2f_putb(va_arg(args, uint8_t));
|
||||
u2f_write_s(" ");
|
||||
u2f_prints(" ");
|
||||
}
|
||||
u2f_write_s("\r\n");
|
||||
u2f_prints("\r\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void u2f_printlx(const char * tag, uint8_t c, ...)
|
||||
{
|
||||
va_list args;
|
||||
u2f_write_s(tag);
|
||||
u2f_prints(tag);
|
||||
va_start(args,c);
|
||||
while(c--)
|
||||
{
|
||||
u2f_putlx(va_arg(args, int32_t));
|
||||
u2f_write_s(" ");
|
||||
u2f_prints(" ");
|
||||
}
|
||||
u2f_write_s("\r\n");
|
||||
u2f_prints("\r\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void usb_write(uint8_t* buf, uint8_t len)
|
||||
{
|
||||
int16_t ec;
|
||||
if (USB_STATUS_OK != (ec=USBD_Write(EP1IN, buf, len, false)))
|
||||
{
|
||||
u2f_printd("USB error",1, -ec);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -18,52 +18,20 @@
|
|||
data struct APP_DATA appdata;
|
||||
|
||||
|
||||
#ifdef U2F_PRINT
|
||||
|
||||
FIFO_CREATE(debug,struct debug_msg, DBG_MSG_COUNT)
|
||||
|
||||
#endif
|
||||
|
||||
static void init(struct APP_DATA* ap)
|
||||
{
|
||||
memset(ap,0, sizeof(struct APP_DATA));
|
||||
debug_fifo_init();
|
||||
u2f_hid_init();
|
||||
smb_init();
|
||||
atecc_idle();
|
||||
}
|
||||
|
||||
static void listen_for_pkt(struct APP_DATA* ap)
|
||||
{
|
||||
USBD_Read(EP1OUT, ap->hidmsgbuf, sizeof(ap->hidmsgbuf), true);
|
||||
}
|
||||
|
||||
|
||||
void set_app_error(APP_ERROR_CODE ec)
|
||||
{
|
||||
appdata.state = APP_ERROR;
|
||||
appdata.error = ec;
|
||||
}
|
||||
|
||||
//uint8_t readByte (uint16_t addr)
|
||||
//{
|
||||
//
|
||||
// uint8_t code * pread; // FLASH read pointer
|
||||
// uint8_t byte;
|
||||
// DISABLE_INTERUPTS();
|
||||
// pread = (uint8_t code *) addr;
|
||||
//
|
||||
// byte = *pread; // Read the byte
|
||||
//
|
||||
// ENABLE_INTERUPTS();
|
||||
//
|
||||
// return byte;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int8_t test_eeprom()
|
||||
{
|
||||
|
||||
|
|
@ -79,17 +47,9 @@ int16_t main(void) {
|
|||
data uint16_t ms_wink;
|
||||
data uint8_t winks = 0;
|
||||
|
||||
|
||||
uint8_t b = 0x66;
|
||||
uint16_t d = 7777;
|
||||
uint32_t l = 0x12345678;
|
||||
|
||||
|
||||
enter_DefaultMode_from_RESET();
|
||||
init(&appdata);
|
||||
|
||||
|
||||
|
||||
// STDIO library requires TI to print
|
||||
SCON0_TI = 1;
|
||||
|
||||
|
|
@ -98,9 +58,6 @@ int16_t main(void) {
|
|||
|
||||
u2f_prints("U2F ZERO\r\n");
|
||||
|
||||
u2f_printb("b:",1,b);
|
||||
u2f_printd("d:",1,d);
|
||||
u2f_printlx("lx:",1,l);
|
||||
run_tests();
|
||||
test_eeprom();
|
||||
|
||||
|
|
@ -117,7 +74,7 @@ int16_t main(void) {
|
|||
{
|
||||
if (!USBD_EpIsBusy(EP1OUT) && !USBD_EpIsBusy(EP1IN))
|
||||
{
|
||||
listen_for_pkt(&appdata);
|
||||
USBD_Read(EP1OUT, appdata.hidmsgbuf, sizeof(appdata.hidmsgbuf), true);
|
||||
u2f_prints("read added\r\n");
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +107,6 @@ int16_t main(void) {
|
|||
break;
|
||||
}
|
||||
|
||||
flush_messages();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,13 +44,9 @@ static struct hid_layer_param
|
|||
// total length of response in bytes
|
||||
uint16_t res_len;
|
||||
|
||||
#ifndef U2F_PRINT
|
||||
#define BUFFER_SIZE 300
|
||||
uint8_t buffer[BUFFER_SIZE];
|
||||
#else
|
||||
#define BUFFER_SIZE 70
|
||||
uint8_t buffer[BUFFER_SIZE];
|
||||
#endif
|
||||
|
||||
|
||||
} hid_layer;
|
||||
|
||||
|
|
|
|||
|
|
@ -64,40 +64,29 @@ static int test_sha()
|
|||
static void slot_dump(void* slot)
|
||||
{
|
||||
struct atecc_slot_config* a = (struct atecc_slot_config*) slot;
|
||||
flush_messages();
|
||||
u2f_print(" readkey %bx\r\n", a->readkey);
|
||||
if (a->nomac) u2f_print(" nomac\r\n");
|
||||
flush_messages();
|
||||
if (a->limiteduse) u2f_print(" limiteduse\r\n");
|
||||
if (a->encread) u2f_print(" encread\r\n");
|
||||
flush_messages();
|
||||
if (a->secret) u2f_print(" secret\r\n");
|
||||
u2f_print(" writekey %bx\r\n", a->writekey);
|
||||
flush_messages();
|
||||
u2f_print(" writeconfig %bx\r\n", a->writeconfig);
|
||||
flush_messages();
|
||||
u2f_printb(" readkey ",1,a->readkey);
|
||||
if (a->nomac) u2f_prints(" nomac\r\n");
|
||||
if (a->limiteduse) u2f_prints(" limiteduse\r\n");
|
||||
if (a->encread) u2f_prints(" encread\r\n");
|
||||
if (a->secret) u2f_prints(" secret\r\n");
|
||||
u2f_printb(" writekey ", 1,a->writekey);
|
||||
u2f_printb(" writeconfig ",1, a->writeconfig);
|
||||
}
|
||||
|
||||
static void key_dump(void* slot)
|
||||
{
|
||||
struct atecc_key_config* a = (struct atecc_slot_config*) slot;
|
||||
flush_messages();
|
||||
|
||||
if (a->private) u2f_print(" private\r\n");
|
||||
if (a->pubinfo) u2f_print(" pubinfo\r\n");
|
||||
flush_messages();
|
||||
u2f_print(" keytype %bx\r\n", a->keytype);
|
||||
if (a->lockable) u2f_print(" lockable\r\n");
|
||||
flush_messages();
|
||||
if (a->reqrandom) u2f_print(" reqrandom\r\n");
|
||||
if (a->reqauth) u2f_print(" reqauth\r\n");
|
||||
flush_messages();
|
||||
u2f_print(" authkey %bx\r\n", a->authkey);
|
||||
if (a->intrusiondisable) u2f_print(" intrusiondisable\r\n");
|
||||
flush_messages();
|
||||
if (a->rfu) u2f_print(" rfu\r\n");
|
||||
u2f_print(" x509id %bx\r\n", a->x509id);
|
||||
flush_messages();
|
||||
if (a->private) u2f_prints(" private\r\n");
|
||||
if (a->pubinfo) u2f_prints(" pubinfo\r\n");
|
||||
u2f_printb(" keytype ", 1,a->keytype);
|
||||
if (a->lockable) u2f_prints(" lockable\r\n");
|
||||
if (a->reqrandom) u2f_prints(" reqrandom\r\n");
|
||||
if (a->reqauth) u2f_prints(" reqauth\r\n");
|
||||
u2f_printb(" authkey ",1, a->authkey);
|
||||
if (a->intrusiondisable) u2f_prints(" intrusiondisable\r\n");
|
||||
if (a->rfu) u2f_prints(" rfu\r\n");
|
||||
u2f_printb(" x509id ",1, a->x509id);
|
||||
}
|
||||
|
||||
static int test_atecc_eeprom()
|
||||
|
|
@ -151,11 +140,11 @@ static int test_atecc_eeprom()
|
|||
ATECC_RW_CONFIG, 5,NULL,0,
|
||||
buf,sizeof(buf), &res);
|
||||
|
||||
u2f_print("-- slot 0 --\r\n");
|
||||
u2f_prints("-- slot 0 --\r\n");
|
||||
dump_hex(res.buf,2);
|
||||
slot_dump(res.buf);
|
||||
|
||||
u2f_print("-- slot 1 --\r\n");
|
||||
u2f_prints("-- slot 1 --\r\n");
|
||||
dump_hex(res.buf+2,2);
|
||||
slot_dump(res.buf+2);
|
||||
|
||||
|
|
@ -168,11 +157,11 @@ static int test_atecc_eeprom()
|
|||
ATECC_RW_CONFIG, 24,NULL,0,
|
||||
buf,sizeof(buf), &res);
|
||||
|
||||
u2f_print("-- key 0 --\r\n");
|
||||
u2f_prints("-- key 0 --\r\n");
|
||||
dump_hex(res.buf,2);
|
||||
key_dump(res.buf);
|
||||
|
||||
u2f_print("-- key 1 --\r\n");
|
||||
u2f_prints("-- key 1 --\r\n");
|
||||
dump_hex(res.buf+2,2);
|
||||
key_dump(res.buf+2);
|
||||
|
||||
|
|
@ -204,7 +193,7 @@ int test_key_signing()
|
|||
|
||||
dump_hex(res.buf, res.len);
|
||||
|
||||
u2f_print("sig:\r\n");
|
||||
u2f_prints("sig:\r\n");
|
||||
|
||||
atecc_send_recv(ATECC_CMD_SIGN,
|
||||
ATECC_SIGN_EXTERNAL, 0, NULL, 0,
|
||||
|
|
@ -296,7 +285,7 @@ void run_tests()
|
|||
if (rc == 0)
|
||||
PRINT("--- SHA TEST SUCCESS ---\r\n");
|
||||
else
|
||||
PRINT("--- SHA TEST FAILED %d ---\r\n",rc);
|
||||
PRINT("--- SHA TEST FAILED ---\r\n");
|
||||
#endif
|
||||
|
||||
#ifdef TEST_ATECC_EEPROM
|
||||
|
|
@ -305,7 +294,7 @@ void run_tests()
|
|||
if (rc == 0)
|
||||
PRINT("--- EEPROM TEST SUCCESS ---\r\n");
|
||||
else
|
||||
PRINT("--- EEPROM TEST FAILED %d ---\r\n",rc);
|
||||
PRINT("--- EEPROM TEST FAILED ---\r\n");
|
||||
#endif
|
||||
|
||||
#ifdef TEST_KEY_SIGNING
|
||||
|
|
@ -314,7 +303,7 @@ void run_tests()
|
|||
if (rc == 0)
|
||||
PRINT("--- KEY SIGNING SUCCESS ---\r\n");
|
||||
else
|
||||
PRINT("--- KEY SIGNING FAILED %d ---\r\n",rc);
|
||||
PRINT("--- KEY SIGNING FAILED ---\r\n");
|
||||
#endif
|
||||
|
||||
#ifdef TEST_EFM8UB1_EEPROM
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
#ifndef TESTS_H_
|
||||
#define TESTS_H_
|
||||
|
||||
#define ENABLE_TESTS
|
||||
//#define ENABLE_TESTS
|
||||
|
||||
//#define TEST_SHA
|
||||
//#define TEST_ATECC_EEPROM
|
||||
#define TEST_EFM8UB1_EEPROM
|
||||
//#define TEST_EFM8UB1_EEPROM
|
||||
//#define TEST_KEY_SIGNING // requires key and locked eeprom
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue