From f5bc521c83d95d35e852747402a44d1411252c2b Mon Sep 17 00:00:00 2001 From: Bernard Blackham Date: Tue, 22 Jun 2004 09:29:21 +0000 Subject: [PATCH] Lots of changes! Takes us to rom S --- ROM2/chime.h | 1 + ROM2/helpers.c | 17 +- ROM2/main_basic.c | 413 +++++++++++++++++++++++++++++++++++----------- ROM2/motors.c | 33 ++-- ROM2/sci.c | 48 ++++-- ROM2/sci.h | 5 +- ROM2/vend.h | 3 + 7 files changed, 391 insertions(+), 129 deletions(-) diff --git a/ROM2/chime.h b/ROM2/chime.h index 88e8b15..bd93ab4 100644 --- a/ROM2/chime.h +++ b/ROM2/chime.h @@ -10,6 +10,7 @@ extern volatile u8 chime_count; /* outside world interface */ extern inline void chime_start() { chime_count = CHIME_TIME; } +extern inline void chime_for(u8 time) { chime_count = time; } void chime(); /* RTI interrupt */ diff --git a/ROM2/helpers.c b/ROM2/helpers.c index 5f0da09..ad52123 100644 --- a/ROM2/helpers.c +++ b/ROM2/helpers.c @@ -10,12 +10,13 @@ void delay(u16 ms) { * parsing C -> asm, but before asm -> machine code. */ //asm volatile ("pshx\npsha\npshb\n"); /* save registers */ - asm volatile ("ldx %0\n" :: "m" (ms)); + asm volatile ("ldx %0\n" :: "m" (ms) : "x"); asm volatile ( "delay_loop:\n" " dex\n" /* 3 */ " beq delay_out\n" /* 3 */ - " ldd #327\n" /* 3 */ + //" ldd #327\n" /* 3 */ + " ldd #150\n" /* 3 */ "delay_inner_loop:\n" /* 15 cycles each */ " cpd #0x0000\n" /* 5 */ " beq delay_inner_loop_end\n" /* 3 */ @@ -23,7 +24,7 @@ void delay(u16 ms) { " bra delay_inner_loop\n" /* 3 */ "delay_inner_loop_end:\n" " bra delay_loop\n" /* 3 */ - "delay_out:\n"); + "delay_out:\n" ::: "x", "d"); /*" pulb\n" " pula\n" " pulx\n");*/ @@ -35,6 +36,16 @@ void my_strncpy(char* dst, char* src, u8 max_size) { if (src[i] == 0 && i < max_size) dst[i] = 0; /* null terminator */ } +bool my_strncmp(char* a, char* b, u8 len) { + u8 i; + for (i = 0; i < len; i++) { + if (*a != *b) return 0; + a++; + b++; + } + return 1; +} + void my_memcpy(char* dst, char* src, u8 size) { u8 i = 0; for (i = 0; i < size; i++) dst[i] = src[i]; diff --git a/ROM2/main_basic.c b/ROM2/main_basic.c index 44e0944..5c35aab 100644 --- a/ROM2/main_basic.c +++ b/ROM2/main_basic.c @@ -4,6 +4,8 @@ * and snacks. */ +#define VERSION_STRING "R 20040622" + #include "display_basic.h" #include "keypad.h" #include "chime.h" @@ -12,39 +14,90 @@ #include "sci.h" #include "vend.h" -void motor_reply(char* slotptr, u8 code) { +u8 last_standalone; +u8 last_switch_input; +u8 last_misc_input; +u16 last_coin_value; +bool last_door_open; +char display_buf[11]; +/* cur_motor[0] is 0 for nothing, or 1..10, or 0xff to say redraw. + * cur_motor[1] is 0..9 and only meaningful is cur_motor[0] != 0. */ +u8 cur_motor[2]; + +bool check_standalone() { + if (is_standalone()) { + send_string("011 In standalone mode. Function disabled." CRLF); + return 1; + } + return 0; +} + +void unknown_command() { + send_string("012 Unknown command. Type HELP for help." CRLF); +} + +void motor_reply(u8 code) { /* returns a message of the form MXYY - X is return code, YY is motor */ - wait_for_tx_free(); - sci_tx_buf[0] = 'M'; - sci_tx_buf[1] = code + '0'; - sci_tx_buf[2] = *slotptr; - sci_tx_buf[3] = *(slotptr+1); - sci_tx_buf[4] = '\n'; - sci_tx_buf[5] = 0; - send_packet(); + switch (code) { + case MOTOR_SUCCESS: + send_string("100 Vend successful." CRLF); + break; + case MOTOR_NOSLOT: + send_string("151 No motor there." CRLF); + break; + case MOTOR_CURRENT_FAIL: + send_string("152 Over current." CRLF); + break; + case MOTOR_HOME_FAIL: + send_string("153 Home sensors failing." CRLF); + break; + default: + send_string("159 Unknown motor error." CRLF); + } } void dispense_something() { /* process a message VXX in sci_rx_buf where XX is motor number */ u8 slot; + if (check_standalone()) return; + + if (my_strncmp("ALL", (char*)sci_rx_buf+1, 3)) { + char motor[3]; + motor[2] = '\0'; + send_string("102 Vend all motors starting." CRLF); + for (motor[0] = '0'; motor[0] <= '9'; motor[0]++) { + for (motor[1] = '0'; motor[1] <= '9'; motor[1]++) { + send_string("101 Vending "); + send_string(motor); + send_string(CRLF); + motor_reply(dispense_motor(motor[0]*10+motor[1])); + } + } + send_string("102 Vend all motors complete." CRLF); + return; + } + if ((sci_rx_buf[1] < '0') || (sci_rx_buf[1] > '9') || (sci_rx_buf[2] < '0') || (sci_rx_buf[2] > '9')) { sci_rx_buf[1] = sci_rx_buf[2] = '0'; - motor_reply((char*)&sci_rx_buf[1], MOTOR_NOSLOT); + motor_reply(MOTOR_NOSLOT); return; } slot = (sci_rx_buf[1] - '0') * 10; slot += sci_rx_buf[2] - '0'; - motor_reply((char*)&sci_rx_buf[1], dispense_motor(slot)); + motor_reply(dispense_motor(slot)); } void write_to_display() { - /* process a message in the form DXXXXXXXXXXX to send to display */ + /* process a message in the form DXXXXXXXXXX to send to display */ u8 i; - char buf[10]; + char buf[11]; + + if (check_standalone()) return; + for (i = 0; i < 10; i++) if (sci_rx_buf[i+1]) buf[i] = sci_rx_buf[i+1]; @@ -53,13 +106,13 @@ void write_to_display() { for (; i < 10; i++) /* pad the rest out with spaces */ buf[i] = ' '; + buf[i] = '\0'; set_msg(buf); - send_ack(); + send_string("300 Written." CRLF); } void send_balance() { - wait_for_tx_free(); sci_tx_buf[0] = 'C'; sci_tx_buf[1] = have_change?'0':'1'; sci_tx_buf[2] = (coin_value/10000)%10; @@ -67,9 +120,8 @@ void send_balance() { sci_tx_buf[4] = (coin_value/100)%10; sci_tx_buf[5] = (coin_value/10)%10; sci_tx_buf[6] = coin_value%10; - sci_tx_buf[7] = '\n'; sci_tx_buf[8] = 0; - send_packet(); + send_buffer(1); } void give_change() { @@ -94,52 +146,174 @@ void give_change() { void send_keypress(u8 key) { /* send a packet of the form KX with X being the key, or R for reset */ - wait_for_tx_free(); - sci_tx_buf[0] = 'K'; - if (key == KEY_RESET) - sci_tx_buf[1] = 'R'; - else - sci_tx_buf[1] = (key%10)+'0'; - sci_tx_buf[2] = '\n'; - sci_tx_buf[3] = 0; - send_packet(); + if (is_standalone()) return; + + sci_tx_buf[0] = '2'; + if (key == KEY_RESET) { + sci_tx_buf[1] = '1'; + sci_tx_buf[2] = '1'; + } else { + sci_tx_buf[1] = '0'; + sci_tx_buf[2] = (key%10)+'0'; + } + sci_tx_buf[3] = '\0'; + send_buffer(0); + send_string(" key." CRLF); } void send_door_msg(bool open) { - wait_for_tx_free(); - sci_tx_buf[0] = 'D'; - sci_tx_buf[1] = open?'1':'0'; - sci_tx_buf[2] = '\n'; - sci_tx_buf[3] = 0; - send_packet(); + if (is_standalone()) return; + sci_tx_buf[0] = '4'; + sci_tx_buf[1] = '0'; + sci_tx_buf[2] = open?'1':'0'; + send_buffer(0); + if (open) + send_string(" door open." CRLF); + else + send_string(" door closed." CRLF); +} + +u8 hexchar2u8(char b) { + if (b >= '0' && b <= '9') return b-'0'; + if (b >= 'a' && b <= 'f') return b-'a'+0x0a; + if (b >= 'A' && b <= 'F') return b-'A'+0x0a; + return 0; +} + +char nibble2hexchar(u8 b) { + if (b <= 9) return b+'0'; + if (b >= 10 && b <= 15) return b+'A'; + return 'X'; +} + +u8 hex2u8(char msb, char lsb) { + return (hexchar2u8(msb) << 4) + hexchar2u8(lsb); +} + +static char hexconv_buf[3]; +char* u82hex(u8 a) { + hexconv_buf[0] = nibble2hexchar((a&0xf0) >> 4); + hexconv_buf[1] = nibble2hexchar(a&0x0f); + hexconv_buf[2] = '\0'; + return hexconv_buf; } void do_chime() { - chime_start(); - send_ack(); + if (check_standalone()) return; + if (sci_rx_buf[1] == '\0') + chime_start(); + else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0') + chime_start(hex2u8(sci_rx_buf[1], sci_rx_buf[2])); + else { + send_string("510 Unknown chime duration." CRLF); + return; + } + send_string("500 Chimed." CRLF); +} + +void print_switches(u8 prompted) { + if (prompted) + send_string("600 "); + else + send_string("610 "); + send_string(u82hex(misc_input)); + send_string(" "); + send_string(u82hex(switch_input)); + send_string(CRLF); } void ping_pong() { /* make sure it's really a ping */ - if (sci_rx_buf[1] != 'I' || - sci_rx_buf[2] != 'N' || - sci_rx_buf[3] != 'G' || - sci_rx_buf[4] != '\0') { - send_nack(); + if (!my_strncmp("ING", (char*)sci_rx_buf+1, 3)) { + unknown_command(); return; } /* respond with ack & pong */ - wait_for_tx_free(); - my_strncpy(sci_tx_buf, "PONG\n", BUFFER_LEN); - send_packet(); + send_string("000 PONG!" CRLF); } -u16 last_coin_value; -bool last_door_open; -char display_buf[11]; -/* cur_motor[0] is 0 for nothing, or 1..10, or 0xff to say redraw. - * cur_motor[1] is 0..9 and only meaningful is cur_motor[0] != 0. */ -u8 cur_motor[2]; +void send_prompt() { + send_string(is_standalone()?"$ ":"# "); +} + +void about() { + if (!my_strncmp("BOUT", (char*)sci_rx_buf+1, 4)) { + unknown_command(); + return; + } + send_string( + "-----------------------------------------------------------------" CRLF + " ROM2 (C) 2004 Bernard Blackham " CRLF + "-----------------------------------------------------------------" CRLF + " Revision " VERSION_STRING CRLF + "" CRLF + " This snack machine was brought to you by " CRLF + " Bernard Blackham" CRLF + " Mark Tearle" CRLF + " Harry McNally" CRLF + " Michal Gornisiewicz" CRLF + " and others." CRLF + "" CRLF + " Another UCC project in action. http://www.ucc.asn.au/" CRLF + ); +} + +void set_echo() { + if (my_strncmp("CHO ON", (char*)sci_rx_buf+1, 6)) + sci_echo = 1; + else if (my_strncmp("CHO OFF", (char*)sci_rx_buf+1, 7)) + sci_echo = 0; + else + unknown_command(); +} + +void moo() { + if (!my_strncmp("OO", (char*)sci_rx_buf+1, 2)) { + unknown_command(); + return; + } + send_string( +" ____________" CRLF +" |__________|" CRLF +" / /\\" CRLF +" / U C C / \\" CRLF +" /___________/___/|" CRLF +" | | |" CRLF +" | ==\\ /== | |" CRLF +" | O O | \\ \\ |" CRLF +" | < | \\ \\|" CRLF +" /| | \\ \\" CRLF +" / | \\_____/ | / /" CRLF +" / /| | / /|" CRLF +"/||\\| | /||\\/" CRLF +" -------------| " CRLF +" | | | | " CRLF +" <__/ \\__>" CRLF + ); +} + +void help() { + send_string( + "Valid commands are:" CRLF + " ABOUT ROM information" CRLF + " PING pongs" CRLF + " ECHO {ON|OFF} turn echo on or off" CRLF + " Vnn vend an item" CRLF + " VALL vend all items" CRLF + " DXXXXXXXXXX show a message on the display" CRLF + " B[nn] beep for a duration nn (optional)" CRLF + " S[...] query all internal switch states" CRLF + " H[...] this help screen" CRLF + "Comments start with a #" CRLF + ); +} + +void quit() { + if (my_strncmp("UIT", (char*)sci_rx_buf+1, 3)) + send_string("013 You can't quit you doofus." CRLF); + else + unknown_command(); +} int main() { u8 i; @@ -153,7 +327,7 @@ int main() { _io_ports[M6811_DDRD] = 0x3e; _io_ports[M6811_SPCR] = M6811_MSTR | M6811_SPR1; set_misc_output(0x00); - + display_init(); set_msg(" HELLO "); delay(1000); @@ -176,10 +350,18 @@ int main() { chime_start(); - my_strncpy(sci_tx_buf, "5N4X0RZRUS\n", BUFFER_LEN); - send_packet(); + send_string("5N4X0RZ R US" CRLF); - cur_motor[0] = 0xff; + last_standalone = is_standalone(); + if (last_standalone) + cur_motor[0] = 0xff; + else + cur_motor[0] = 0; + send_prompt(); + + last_switch_input = switch_input; + last_misc_input = misc_input; + while(1) { if (cur_motor[0] == 0xff) { /* signal to say redraw screen */ set_msg("*5N4X0RZ* "); @@ -193,8 +375,36 @@ int main() { set_msg(last_door_open?"DOOR OPEN ":"DOOR CLOSE"); } + if (last_standalone != is_standalone()) { + /* somebody flicked the standalone switch */ + msg_clr(); + send_string(CRLF); + send_prompt(); + last_standalone = is_standalone(); + } + + if (last_misc_input != misc_input) { + print_switches(0); + last_misc_input = misc_input; + } + + if (last_switch_input != switch_input) { + print_switches(0); + last_switch_input = switch_input; + } + if (sci_have_packet) { switch (sci_rx_buf[0]) { + case '\0': + case '#': + send_string(CRLF); + break; + case 'E': + set_echo(); + break; + case 'H': + help(); + break; case 'V': dispense_something(); break; @@ -204,66 +414,75 @@ int main() { case 'B': do_chime(); break; - case 'U': - send_balance(); - break; - case 'G': - give_change(); - break; case 'P': ping_pong(); break; + case 'A': + about(); + break; + case 'S': + print_switches(1); + break; + case 'M': + moo(); + break; + case 'Q': + quit(); + break; default: // shurg - send_nack(); + unknown_command(); break; } msg_clr(); + send_prompt(); } keypad_read(); if (keypad_pressed()) { - if (last_key == KEY_RESET) { - cur_motor[0] = 0xff; - } else { - if (cur_motor[0]) { - u8 motor_num; - cur_motor[1] = last_key%10; - display_buf[1] = cur_motor[1]+'0'; - set_msg(display_buf); - - motor_num = cur_motor[0]%10; - motor_num *= 10; - motor_num += cur_motor[1]; - switch (dispense_motor(motor_num)) { - case MOTOR_HOME_FAIL: - set_msg(" HOME FAIL "); - break; - case MOTOR_CURRENT_FAIL: - set_msg(" OVER CRNT "); - break; - case MOTOR_SUCCESS: - set_msg("THANK YOU"); - break; - case MOTOR_NOSLOT: - set_msg(" NO MOTOR "); - break; - default: - set_msg("ERRRRRRRR?"); - break; - } - - display_buf[0] = ' '; - display_buf[1] = ' '; + if (is_standalone()) { + if (last_key == KEY_RESET) { cur_motor[0] = 0xff; - delay(500); } else { - cur_motor[0] = last_key; - display_buf[0] = (last_key%10)+'0'; - set_msg(display_buf); + if (cur_motor[0]) { + u8 motor_num; + cur_motor[1] = last_key%10; + display_buf[1] = cur_motor[1]+'0'; + set_msg(display_buf); + + motor_num = cur_motor[0]%10; + motor_num *= 10; + motor_num += cur_motor[1]; + switch (dispense_motor(motor_num)) { + case MOTOR_HOME_FAIL: + set_msg(" HOME FAIL "); + break; + case MOTOR_CURRENT_FAIL: + set_msg(" OVER CRNT "); + break; + case MOTOR_SUCCESS: + set_msg("THANK YOU"); + break; + case MOTOR_NOSLOT: + set_msg(" NO MOTOR "); + break; + default: + set_msg("ERRRRRRRR?"); + break; + } + + display_buf[0] = ' '; + display_buf[1] = ' '; + cur_motor[0] = 0xff; + delay(500); + } else { + cur_motor[0] = last_key; + display_buf[0] = (last_key%10)+'0'; + set_msg(display_buf); + } } - } - send_keypress(last_key); + } else + send_keypress(last_key); } /* diff --git a/ROM2/motors.c b/ROM2/motors.c index e7cb6b5..efed7cc 100644 --- a/ROM2/motors.c +++ b/ROM2/motors.c @@ -36,7 +36,7 @@ void motor_shift_send(u8 data) { } } -void motor_on(u8 slot) { +void set_motor(u8 slot) { u8 row, col; row = slot%10; col = slot/10; @@ -61,30 +61,38 @@ void motor_on(u8 slot) { motor_shift_send(1 << (row-1)); /* rows from 1..8 here */ bclr((void*)&_io_ports[M6811_PORTA], PORTA_MOTOR_CLOCK); +} + +void motor_start() { bclr_changer_output(A3000_MOTOR_ROW_DISABLE); } -void motors_off() { +void motor_pause() { + bset_changer_output(A3000_MOTOR_ROW_DISABLE); +} + +void motor_stop() { bset_changer_output(A3000_MOTOR_ROW_DISABLE); - delay(10); /* XXX cf motors_off */ bset((void*)&_io_ports[M6811_PORTA], PORTA_MOTOR_COL_DISABLE); bclr_misc_output(A3800_MOTOR_COL8_ENABLE | A3800_MOTOR_COL9_ENABLE); } bool motor_here(u8 slot) { u8 i, c = 0; + set_motor(slot); for (i=0; i < 8; i++) { - motor_on(slot); + motor_start(); delay(5); if ((_io_ports[M6811_PORTE] & PORTE_MOTOR_OVERVOLTAGE) == 0) { c++; if (c == 3) { - motors_off(); + motor_stop(); return 1; } } - motors_off(); + motor_pause(); } + motor_stop(); return 0; } @@ -98,14 +106,15 @@ bool start_motor(u8 slot) { u8 r = slot%10; if (r >= 5) r--; r = 1 << (r-1); - motor_on(slot); - delay(100); + set_motor(slot); + motor_start(); + delay(50); for (i = 0; i < 1000; i++) { if ((home_sensors & r) != 0) return 1; delay(1); } /* it never left */ - motors_off(); + motor_stop(); return 0; } @@ -139,15 +148,15 @@ bool motor_overcurrent() { u8 dispense_motor(u8 slot) { if (!is_motor(slot)) return MOTOR_NOSLOT; if (!start_motor(slot)) return MOTOR_HOME_FAIL; + delay(100); while (1) { if (motor_overcurrent()) { - motors_off(); + motor_stop(); return MOTOR_CURRENT_FAIL; } - /* something should call motor_here? */ if (back_home(slot)) { - motors_off(); + motor_stop(); return MOTOR_SUCCESS; } } diff --git a/ROM2/sci.c b/ROM2/sci.c index 668e865..d7c9f28 100644 --- a/ROM2/sci.c +++ b/ROM2/sci.c @@ -5,6 +5,7 @@ char sci_tx_buf[BUFFER_LEN]; volatile char sci_rx_buf[BUFFER_LEN]; volatile bool sci_have_packet; volatile u8 sci_rx_buf_ptr; +volatile bool sci_echo; void sci_init() { /* assumes clock of 4.91Mhz */ @@ -18,9 +19,10 @@ void sci_init() { sci_have_packet = 0; sci_rx_buf_ptr = 0; + sci_echo = 0; } -void send_packet() { +void send_buffer(bool crlf) { char* c; for (c = sci_tx_buf; *c; c++) { /* wait for TX ready */ @@ -29,28 +31,44 @@ void send_packet() { /* send byte */ _io_ports[M6811_SCDR] = *c; } + if (!crlf) return; + /* send CRLF */ + while (!(_io_ports[M6811_SCSR] & M6811_TDRE)); + _io_ports[M6811_SCDR] = '\r'; + while (!(_io_ports[M6811_SCSR] & M6811_TDRE)); + _io_ports[M6811_SCDR] = '\n'; +} + +void send_string(char* c) { + for (; *c; c++) { + while (!(_io_ports[M6811_SCSR] & M6811_TDRE)); /* wait for TX ready */ + _io_ports[M6811_SCDR] = *c; /* send byte */ + } } void sci_rx_int() { + char buf = _io_ports[M6811_SCDR]; + if (sci_echo) { + while (!(_io_ports[M6811_SCSR] & M6811_TDRE)); /* wait for TX ready */ + _io_ports[M6811_SCDR] = buf; /* send byte */ + } + /* XXX FIXME we should do something about errors. nack? */ if (sci_have_packet) { /* overrun :( */ - _io_ports[M6811_SCDR]; /* read it anyway */ return; } - sci_rx_buf[sci_rx_buf_ptr] = _io_ports[M6811_SCDR]; - if (sci_rx_buf[sci_rx_buf_ptr] == '\n' || - sci_rx_buf[sci_rx_buf_ptr] == '\r') { - if (sci_rx_buf_ptr == 0) return; /* we've read a blank packet in */ + sci_rx_buf[sci_rx_buf_ptr] = buf; + + if (buf == '\n' || buf == '\r') { sci_rx_buf[sci_rx_buf_ptr] = '\0'; sci_have_packet = 1; - sci_rx_buf_ptr = 0; } - sci_rx_buf_ptr++; - if (sci_rx_buf_ptr >= BUFFER_LEN) { - sci_rx_buf[BUFFER_LEN] = '\0'; /* this is as much as we could fit */ - sci_have_packet = 1; - sci_rx_buf_ptr = 0; + + if (sci_rx_buf_ptr+1 < BUFFER_LEN) + sci_rx_buf_ptr++; + else { + sci_rx_buf[BUFFER_LEN-1] = '\0'; /* this is as much as we could fit */ } } @@ -67,11 +85,9 @@ void msg_clr() { } void send_ack() { - my_strncpy(sci_tx_buf, "!\n", BUFFER_LEN); - send_packet(); + send_string("!" CRLF); } void send_nack() { - my_strncpy(sci_tx_buf, "?\n", BUFFER_LEN); - send_packet(); + send_string("?" CRLF); } diff --git a/ROM2/sci.h b/ROM2/sci.h index 4b3a6d1..0db4b64 100644 --- a/ROM2/sci.h +++ b/ROM2/sci.h @@ -4,10 +4,12 @@ #include "vend.h" #define BUFFER_LEN 12 +#define CRLF "\r\n" void sci_init(); void msg_clr(); -void send_packet(); +void send_buffer(bool crlf); +void send_string(char* s); void send_ack(); void send_nack(); #define wait_for_tx_free() do { } while(0) @@ -15,5 +17,6 @@ void send_nack(); extern char sci_tx_buf[BUFFER_LEN]; extern volatile char sci_rx_buf[BUFFER_LEN]; extern volatile u8 sci_have_packet; +extern volatile bool sci_echo; #endif /* _SCI_H_ */ diff --git a/ROM2/vend.h b/ROM2/vend.h index 17ba674..460aa71 100644 --- a/ROM2/vend.h +++ b/ROM2/vend.h @@ -26,11 +26,14 @@ extern volatile u8 _misc_input; extern volatile u8 _home_sensors; #define home_sensors _home_sensors +#define is_standalone() (misc_input & 0x01) /* DIP sw 1 */ + extern u16 _stack; /******* from helpers.c *******/ void delay(u16 ms); void my_strncpy(char* dst, char* src, u8 max_size); /* for null-term strings */ +bool my_strncmp(char* a, char* b, u8 len); void my_memcpy(char* dst, char* src, u8 size); /******** Some meaningful bits ******/ -- 2.20.1