From ea9665a100d500f50e85bdc07624e9d6cbbac8dd Mon Sep 17 00:00:00 2001 From: empathicqubit Date: Tue, 27 Dec 2022 20:31:52 +0100 Subject: [PATCH] Add ability to send debug messages over GDB --- .vscode/launch.json | 2 +- .vscode/settings.json | 31 +++++- CMakeLists.txt | 8 ++ src/common/utils.c | 3 + src/tibridge.c | 90 +++++++++++----- src/tikeys.c | 238 +++++++++++++++++++++++++++++++++++------- 6 files changed, 305 insertions(+), 67 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 03f7772..cdba85d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -30,7 +30,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/build/tikeys", - "args": ["--subtype=mirage", "--log-level=trace"], + "args": ["--program=u1BERSHRD", "--log-level=trace"], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], diff --git a/.vscode/settings.json b/.vscode/settings.json index c6ab89f..79a20df 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,36 @@ "ticalcs.h": "c", "ticables.h": "c", "vector": "c", - "random": "c" + "random": "c", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "cmath": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "optional": "cpp", + "string_view": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "functional": "cpp", + "fstream": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "numeric": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "streambuf": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "typeinfo": "cpp", + "cstddef": "c" }, "cmake.configureOnOpen": true } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 369a82a..a29f462 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,9 +7,12 @@ find_package(PkgConfig REQUIRED) PKG_CHECK_MODULES(GLIB REQUIRED glib-2.0) PKG_CHECK_MODULES(TICABLES REQUIRED ticables2) PKG_CHECK_MODULES(TICALCS REQUIRED ticalcs2) +PKG_CHECK_MODULES(TIFILES REQUIRED tifiles2) file(GLOB COMMON_SRC src/common/*.c) +####################################### TIBRIDGE ############################### + file(GLOB TIBRIDGE_SRC src/tibridge.c) add_executable(tibridge ${COMMON_SRC} ${TIBRIDGE_SRC}) @@ -30,6 +33,8 @@ target_link_directories(tibridge PRIVATE ${TICABLES_LIBRARIES}) PKG_CHECK_MODULES(READLINE REQUIRED readline) +####################################### TIKEYS ############################### + file(GLOB TIKEYS_SRC src/tikeys.c) add_executable(tikeys ${COMMON_SRC} ${TIKEYS_SRC}) @@ -41,15 +46,18 @@ target_include_directories(tikeys PRIVATE ${GLIB_INCLUDE_DIRS} PRIVATE ${TICABLES_INCLUDE_DIRS} PRIVATE ${TICALCS_INCLUDE_DIRS} + PRIVATE ${TIFILES_INCLUDE_DIRS} PRIVATE ${READLINE_INCLUDE_DIRS} ) target_link_libraries(tikeys PRIVATE ${GLIB_LIBRARIES}) target_link_libraries(tikeys PRIVATE ${TICABLES_LIBRARIES}) target_link_libraries(tikeys PRIVATE ${TICALCS_LIBRARIES}) +target_link_libraries(tikeys PRIVATE ${TIFILES_LIBRARIES}) target_link_libraries(tikeys PRIVATE ${READLINE_LIBRARIES}) target_link_directories(tikeys PRIVATE ${GLIB_LIBRARY_DIRS}) target_link_directories(tikeys PRIVATE ${TICABLES_LIBRARIES}) target_link_directories(tikeys PRIVATE ${TICALCS_LIBRARIES}) +target_link_directories(tikeys PRIVATE ${TIFILES_LIBRARIES}) target_link_directories(tikeys PRIVATE ${READLINE_LIBRARIES}) \ No newline at end of file diff --git a/src/common/utils.c b/src/common/utils.c index e475b7c..c28b75c 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -42,6 +42,7 @@ void utils_parse_args(int argc, char *argv[]) { {0,0,0,0} }; + opterr = 0; optind = 0; int opt_index = 0; int opt; @@ -64,4 +65,6 @@ void utils_parse_args(int argc, char *argv[]) { } } } + + opterr = 1; } \ No newline at end of file diff --git a/src/tibridge.c b/src/tibridge.c index 48896da..5f43dea 100644 --- a/src/tibridge.c +++ b/src/tibridge.c @@ -2,35 +2,53 @@ #include #include #include -#include -#include #include -#include #include #include +#include #include "common/utils.h" -static CableDeviceInfo EmptyInfo; - static pthread_t tid; -static CableHandle* handle; +static CableHandle* cable_handle; -static CablePort port; -static CableModel model; +int hex(char ch) { + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +uint8_t *hex2mem(const char *buf, uint8_t *mem, uint32_t count) { + unsigned char ch; + for (int i = 0; i < count; i++) + { + ch = hex(*buf++) << 4; + ch = ch + hex(*buf++); + *(mem++) = (char)ch; + } + return (mem); +} void reset_cable(void) { - unsigned char err; - ticables_cable_reset(handle); - ticables_cable_close(handle); - ticables_handle_del(handle); - handle = ticables_handle_new(model, port); - ticables_options_set_delay(handle, 1); - ticables_options_set_timeout(handle, 5); + CablePort port; + CableModel model; + port = cable_handle->port; + model = cable_handle->model; + int err; + ticables_cable_reset(cable_handle); + ticables_cable_close(cable_handle); + ticables_handle_del(cable_handle); + cable_handle = ticables_handle_new(model, port); + ticables_options_set_delay(cable_handle, 1); + ticables_options_set_timeout(cable_handle, 5); - while(err = ticables_cable_open(handle)) { - fprintf(stderr, "Could not open cable: %d\n", err); + while(err = ticables_cable_open(cable_handle)) { + log(LEVEL_ERROR, "Could not open cable: %d\n", err); } } @@ -38,7 +56,7 @@ void retry_send(unsigned char* send, int sendCount) { unsigned char err = 0; log(LEVEL_DEBUG, "%d->", sendCount); log(LEVEL_TRACE, "%.*s\n", sendCount, send); - while(err = ticables_cable_send(handle, send, sendCount)) { + while(err = ticables_cable_send(cable_handle, send, sendCount)) { log(LEVEL_ERROR, "Error sending: %d", err); reset_cable(); } @@ -61,7 +79,6 @@ void retry_recv(unsigned char* recv, int recvCount) { } int main(int argc, char *argv[]) { - int err; // z88dk-gdb doesn't like the ACKs -/+, so we just hide them int handle_acks = 1; @@ -87,30 +104,33 @@ int main(int argc, char *argv[]) { log(LEVEL_DEBUG, "handle acks: %d\n", handle_acks); + int err; ticables_library_init(); log(LEVEL_INFO, "PROCESS ID: %d\n", getpid()); - handle = utils_setup_cable(); - if(handle == NULL) { + cable_handle = utils_setup_cable(); + if(cable_handle == NULL) { log(LEVEL_ERROR, "Cable not found!\n"); return 1; } - err = ticables_cable_open(handle); + //ticables_options_set_timeout(cable_handle , 1 * 60 * 60 * 10); + + err = ticables_cable_open(cable_handle); if(err) { log(LEVEL_ERROR, "Could not open cable: %d\n", err); return 1; } - CableDeviceInfo info = EmptyInfo; - err = ticables_cable_get_device_info(handle, &info); + CableDeviceInfo info; + err = ticables_cable_get_device_info(cable_handle, &info); if(err) { log(LEVEL_ERROR, "Could not read device info: %d\n", err); return 1; } - log(LEVEL_INFO, "INFO: Model %d, Port:%d, Family %d, Variant %d\n", model, port, info.family, info.variant); + log(LEVEL_INFO, "Cable Family %d, Variant %d\n", info.family, info.variant); bool handled_first_recv = false; @@ -124,7 +144,7 @@ int main(int argc, char *argv[]) { log(LEVEL_DEBUG, "RECEIVE PHASE\n"); while(true) { do { - if(err = ticables_cable_recv(handle, &recv[recvCount], 1)) { + if(err = ticables_cable_recv(cable_handle, &recv[recvCount], 1)) { log(LEVEL_ERROR, "error receiving: %d\n", err); } } while(err); @@ -132,12 +152,14 @@ int main(int argc, char *argv[]) { recvCount++; if(current == '#') { do { - if(err = ticables_cable_recv(handle, &recv[recvCount], 2)) { + if(err = ticables_cable_recv(cable_handle, &recv[recvCount], 2)) { log(LEVEL_ERROR, "error receiving: %d\n", err); } } while(err); recvCount += 2; + recv[recvCount] = '\0'; + if(!handle_acks || handled_first_recv) { retry_recv(recv, recvCount); } @@ -145,6 +167,20 @@ int main(int argc, char *argv[]) { log(LEVEL_DEBUG, "Discarded the first packet\n"); } + char *packet_char = strchr(recv, '$'); + if(packet_char) { + packet_char++; + + if(*packet_char == 'O') { + int data_size = (recvCount - 5) / 2; + char buf[data_size]; + hex2mem(&packet_char[1], buf, data_size); + log(LEVEL_INFO, "\n%.*s", data_size, buf); + recvCount = 0; + continue; + } + } + if(handle_acks) { log(LEVEL_DEBUG, "Injecting an ACK\n"); ack(); diff --git a/src/tikeys.c b/src/tikeys.c index 663a857..6e4a28b 100644 --- a/src/tikeys.c +++ b/src/tikeys.c @@ -1,39 +1,115 @@ -#include -#include -#include "common/utils.h" -#include -#include #include #include +#include -static char *subtype = "mirage"; +#include +#include + +#include +#include +#include +#include + +#include "common/utils.h" + +static char *subtype = ""; +static char *program = ""; +static char *keys = ""; +static int reset_ram = 0; static CalcHandle *calc_handle = NULL; +static CalcModel model = CALC_NONE; -void send_key(uint32_t key, int retry) { - usleep(250000); +static void send_key(uint32_t key, int retry) { + usleep(100000); int err; while(err = ticalcs_calc_send_key(calc_handle, key) && retry); } +static int compare(const void *a, const void *b) { + return strcmp(*(const char**)a, *(const char**)b); +} + +static int get_program_index(GNode *tree, char* program) { + char *names[1024]; + int n = 0; + + TreeInfo *info = tree->data; + for (int i = 0; i < (int)g_node_n_children(tree); i++) { + GNode *parent = g_node_nth_child(tree, i); + VarEntry *ve = parent->data; + + for (int j = 0; j < (int)g_node_n_children(parent); j++) { + GNode *child = g_node_nth_child(parent, j); + ve = child->data; + + if(ve != NULL) { + const char *str_type = tifiles_vartype2string(model, ve->type); + + if (strlen(str_type) >= 4 + && ( + strcmp(&str_type[strlen(str_type) - 4], "PRGM") == 0 + || strcmp(str_type, "APPL") == 0 + ) + ) { + names[n++] = ve->name; + } + } + } + } + + qsort(names, n, sizeof(names[0]), compare); + for(int i = 0; i < n; i++) { + if(strcmp(names[i], program) == 0) { + return i+1; // Finance is always at the beginning + } + } + + return -1; +} + +void show_help() { + log(LEVEL_INFO, "Syntax: tikeys [--reset-ram] [--keys=ABCDEFG123456789] [--subtype=mirage --program=PROGNAME]\n"); +} + int main(int argc, char *argv[]) { utils_parse_args(argc, argv); const struct option long_opts[] = { - //{name,arg,flag,val} {"subtype", required_argument, 0, 's'}, + {"program", required_argument, 0, 'p'}, + {"keys", required_argument, 0, 'k'}, + {"reset-ram", no_argument, &reset_ram, 1}, + {"help", no_argument, 0, 'h'}, {0,0,0,0} }; optind = 0; int opt_index = 0; int opt; - while((opt = getopt_long(argc, argv, "s:", long_opts, &opt_index)) != -1) { - if(opt == 's') { + while((opt = getopt_long(argc, argv, "s:p:", long_opts, &opt_index)) != -1) { + if(opt == 0 && long_opts[opt_index].flag) { + // Do nothing + } + else if(opt == 's') { subtype = optarg; } + else if(opt == 'p') { + program = optarg; + } + else if(opt == 'k') { + keys = optarg; + } + else if(opt == 'r') { + reset_ram = 1; + } + else if(opt == 'h') { + show_help(); + return 0; + } } + int err; ticables_library_init(); CableHandle *cable_handle = utils_setup_cable(); @@ -42,42 +118,128 @@ int main(int argc, char *argv[]) { return 1; } + err = ticables_cable_open(cable_handle); + if(err) { + log(LEVEL_ERROR, "Could not open cable: %d\n", err); + return 1; + } + + CableDeviceInfo info; + err = ticables_cable_get_device_info(cable_handle, &info); + if(err) { + log(LEVEL_ERROR, "Could not read device info: %d\n", err); + return 1; + } + + err = ticables_cable_close(cable_handle); + if(err) { + log(LEVEL_ERROR, "Could not close cable: %d\n", err); + return 1; + } + + ticables_handle_del(cable_handle); + + cable_handle = utils_setup_cable(); + ticables_options_set_timeout(cable_handle, 20); - calc_handle = ticalcs_handle_new(CALC_TI83P); + model = CALC_TI83P; + + calc_handle = ticalcs_handle_new(model); ticalcs_cable_attach(calc_handle, cable_handle); - send_key(KEY83P_Quit, 1); - send_key(KEY83P_Clear, 1); + if(reset_ram) { + send_key(KEY83P_Quit, 1); + send_key(KEY83P_Clear, 1); + + log(LEVEL_WARN, "Resetting RAM...\n"); + send_key(KEY83P_ResetMem, 0); + } + + if(strlen(keys) > 0) { + for(int i = 0; i < strlen(keys); i++) { + send_key(ticalcs_keys_83p(keys[i])->normal.value, 1); + } + } - int err; - if(strcmp(subtype, "asm") == 0) { - log(LEVEL_ERROR, "asm is not supported! Start it manually!\n"); - return 1; - } - else if(strcmp(subtype, "tse") == 0) { - log(LEVEL_ERROR, "tse is not supported! Start it manually!\n"); - return 1; - } - else if(strcmp(subtype, "ion") == 0) { - log(LEVEL_WARN, "ion will be started, but you still need to start the program yourself.\n"); - send_key(KEY83P_Prgm, 1); - send_key(ticalcs_keys_83p('A')->normal.value, 1); - send_key(KEY83P_Enter, 1); - send_key(KEY83P_Enter, 0); - } - else if(strcmp(subtype, "mirage") == 0) { - log(LEVEL_WARN, "Mirage will be started, but you still need to start the program yourself.\n"); - send_key(KEY83P_AppsMenu, 1); - send_key(ticalcs_keys_83p('M')->normal.value, 1); - send_key(KEY83P_Enter, 0); - } - else { - log(LEVEL_WARN, "Subtype was not recognized! Start it manually!\n"); + if(strlen(subtype) > 0 || strlen(program) > 0) { + send_key(KEY83P_Quit, 1); + send_key(KEY83P_Clear, 1); + + if(strcmp(subtype, "asm") == 0) { + log(LEVEL_ERROR, "asm is not supported! Start it manually!\n"); + return 1; + } + else if(strcmp(subtype, "tse") == 0) { + log(LEVEL_ERROR, "tse is not supported! Start it manually!\n"); + return 1; + } + else if(strcmp(subtype, "ion") == 0) { + log(LEVEL_WARN, "ion will be started, but you still need to start the program yourself.\n"); + send_key(KEY83P_Prgm, 1); + send_key(ticalcs_keys_83p('A')->normal.value, 1); + send_key(KEY83P_Enter, 1); + send_key(KEY83P_Enter, 0); + } + else if(strcmp(subtype, "mirage") == 0) { + log(LEVEL_WARN, "Mirage will be started, but you still need to start the program yourself.\n"); + send_key(KEY83P_AppsMenu, 1); + send_key(ticalcs_keys_83p('M')->normal.value, 1); + send_key(KEY83P_Enter, 0); + } + else if(strlen(program) > 0) { + if(strcmp(subtype, "noshell") != 0) { + log(LEVEL_WARN, "Subtype was not recognized! It will be started with noshell!\n"); + } + + log(LEVEL_INFO, "Verifying that noshell is correctly hooked.\n"); + + int err; + GNode *vars, *apps; + while(err = ticalcs_calc_get_dirlist(calc_handle, &vars, &apps)); + + log(LEVEL_DEBUG, "Got dirlist\n"); + + int noshell_idx = get_program_index(apps, "Noshell "); + if(noshell_idx == -1) { + log(LEVEL_ERROR, "Could not find noshell. Exiting\n"); + return 1; + } + + send_key(KEY83P_AppsMenu, 1); + for(int i = 0; i < noshell_idx; i++) { + send_key(KEY83P_Down, 1); + } + //send_key(KEY83P_Enter, 0); + + return 1; + + get_program_index(vars, program); + + // There has to be a better way to do this... + // Select a program then delete the name, + // keeping only the pgrm token + send_key(KEY83P_Prgm, 1); + send_key(KEY83P_Enter, 1); + send_key(KEY83P_Up, 1); + send_key(KEY83P_Right, 1); + for(int i = 0; i < 16; i++) { + send_key(KEY83P_Del, 1); + } + + // Actually input the name + for(int i = 0; i < strlen(program); i++) { + send_key(ticalcs_keys_83p(program[i])->normal.value, 1); + } + send_key(KEY83P_Enter, 0); + } } ticalcs_cable_detach(calc_handle); + ticalcs_handle_del(calc_handle); ticables_cable_close(cable_handle); + ticables_handle_del(cable_handle); + ticables_library_exit(); return 0; } \ No newline at end of file