From 0a61ffc523381f7736619e13e7b3b547fe76e9f5 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sun, 12 Mar 2023 20:55:18 +0100 Subject: [PATCH] fxlink: basic TUI commands --- fxlink/devices.c | 7 +-- fxlink/include/fxlink/devices.h | 6 ++- fxlink/include/fxlink/protocol.h | 7 ++- fxlink/modes/tui-interactive.c | 88 ++++++++++++++++++++++++-------- fxlink/protocol.c | 8 ++- 5 files changed, 87 insertions(+), 29 deletions(-) diff --git a/fxlink/devices.c b/fxlink/devices.c index 69e3322..9dff247 100644 --- a/fxlink/devices.c +++ b/fxlink/devices.c @@ -490,7 +490,6 @@ struct fxlink_message *fxlink_device_finish_bulk_IN(struct fxlink_device *fdev) version_major, version_minor, msg->application, msg->type, fxlink_size_string(msg->size)); - fxlink_transfer_free(comm->ftransfer_IN); comm->ftransfer_IN = NULL; return msg; } @@ -554,13 +553,15 @@ static void bulk_OUT_callback(struct libusb_transfer *transfer) } void fxlink_device_start_bulk_OUT(struct fxlink_device *fdev, - char const *app, char const *type, void const *data, int size) + char const *app, char const *type, void const *data, int size, + bool own_data) { struct fxlink_comm *comm = fdev->comm; if(!comm || !comm->claimed || comm->ftransfer_OUT) return; - comm->ftransfer_OUT = fxlink_transfer_make_OUT(app, type, data, size); + comm->ftransfer_OUT = + fxlink_transfer_make_OUT(app, type, data, size, own_data); if(!comm->ftransfer_OUT) { elog("allocation of OUT transfer (protocol) failed\n"); return; diff --git a/fxlink/include/fxlink/devices.h b/fxlink/include/fxlink/devices.h index 41e56b2..5406374 100644 --- a/fxlink/include/fxlink/devices.h +++ b/fxlink/include/fxlink/devices.h @@ -210,9 +210,11 @@ void fxlink_device_start_bulk_IN(struct fxlink_device *fdev); struct fxlink_message *fxlink_device_finish_bulk_IN( struct fxlink_device *fdev); -/* Start an OUT transfer on the device. */ +/* Start an OUT transfer on the device. If `own_data` is set, the transfer will + free(data) when it completes. */ void fxlink_device_start_bulk_OUT(struct fxlink_device *fdev, - char const *app, char const *type, void const *data, int size); + char const *app, char const *type, void const *data, int size, + bool own_data); /* Interrupt any active transfers on the device. */ void fxlink_device_interrupt_transfers(struct fxlink_device *fdev); diff --git a/fxlink/include/fxlink/protocol.h b/fxlink/include/fxlink/protocol.h index 7f839d2..5c61e32 100644 --- a/fxlink/include/fxlink/protocol.h +++ b/fxlink/include/fxlink/protocol.h @@ -113,6 +113,8 @@ struct fxlink_transfer { uint8_t direction; /* Size of data sent or received so far */ int processed_size; + /* Whether we own msg.data and should free(3) it */ + bool own_data; }; enum { @@ -130,7 +132,8 @@ enum { struct fxlink_transfer *fxlink_transfer_make_IN(void *data, int size); /* If the provided IN transfer is finished, extract the message and free the - transfer pointer. Otherwise, return NULL. */ + transfer (do not fxlink_transfer_free(tr) later!). Returns NULL if the + transfer isn't finished yet. */ struct fxlink_message *fxlink_transfer_finish_IN(struct fxlink_transfer *tr); /* Append data to a previously-initialized inbound transfer. */ @@ -138,7 +141,7 @@ void fxlink_transfer_receive(struct fxlink_transfer *tr, void *data, int size); /* Make an outbound transfer structure. */ struct fxlink_transfer *fxlink_transfer_make_OUT(char const *application, - char const *type, void const *data, int size); + char const *type, void const *data, int size, bool own_data); /* Check whether a transfer is complete. */ bool fxlink_transfer_complete(struct fxlink_transfer const *tr); diff --git a/fxlink/modes/tui-interactive.c b/fxlink/modes/tui-interactive.c index 1c681e9..20fcc13 100644 --- a/fxlink/modes/tui-interactive.c +++ b/fxlink/modes/tui-interactive.c @@ -21,6 +21,25 @@ #include #include +/* +Plan for the TUI command set. + +fxlink commands: + select Select the calculator we're talking to + remote-control Enable/disable/setup remote calculator control + +Protocol commands (executed by the calculator): + /identify Send calculator identification information + /echo Echo a message + /screenshot Take a screenshot + /video Enable/disable video capture + +Application-specific commands: + gintctl read-long Transmission tests (long messages) + gintctl read-alignment Pipe reading alignment + gintctl bench USB transfer speed benchmark +*/ + static struct TUIData { /* SIGWINCH flag */ bool resize_needed; @@ -402,6 +421,50 @@ static void handle_fxlink_log(int display_fmt, char const *str) wattroff(TUI.wLogs, attr); } +static void execute_command(char const *command) +{ + /* Connected device (TODO: Use the "selected" device) */ + struct fxlink_device *fdev = NULL; + for(int i = 0; i < TUI.devices.count; i++) { + if(TUI.devices.devices[i].status == FXLINK_FDEV_STATUS_CONNECTED) { + fdev = &TUI.devices.devices[i]; + break; + } + } + + /* The following commands require a connected device */ + if(!fdev) { + print(TUI.wConsole, "no connected device!\n"); + return; + } + print(TUI.wConsole, "using device %s (%s)\n", + fxlink_device_id(fdev), fdev->calc->serial); + + if(!strncmp(command, "/echo", 5)) { + int len = strlen(command+1); + fxlink_device_start_bulk_OUT(fdev, + "fxlink", "command", strdup(command+1), len, true); + return; + } + else if(!strcmp(command, "/identify")) { + fxlink_device_start_bulk_OUT(fdev, + "fxlink", "command", "identify", 8, false); + return; + } + else if(!strcmp(command, "gintctl read-long")) { + int count = 128; // 2048; + uint32_t *data = malloc(count * 4); + for(int i = 0; i < count; i++) + data[i] = i; + fxlink_device_start_bulk_OUT(fdev, + "gintctl", "echo-bounds", data, count * 4, true); + return; + } + + fprint(TUI.wConsole, FMT_RED, "error: "); + print(TUI.wConsole, "unrecognized command '%s'\n", command); +} + int main_tui_interactive(libusb_context *ctx) { if(!TUI_setup()) @@ -480,27 +543,12 @@ int main_tui_interactive(libusb_context *ctx) char *command = input.data; if(command[0] != 0) log_("command: '%s'\n", command); - if(!strcmp(command, "q")) + if(!strcmp(command, "")) + {} + else if(!strcmp(command, "q") || !strcmp(command, "quit")) break; - if(!strcmp(command, "test")) { - /* Find a device */ - struct fxlink_device *fdev = NULL; - for(int i = 0; i < TUI.devices.count; i++) { - fdev = &TUI.devices.devices[i]; - if(fdev->status == FXLINK_FDEV_STATUS_CONNECTED) - break; - else fdev = NULL; - } - if(fdev) { - print(TUI.wConsole, "using device %s (%s)\n", - fxlink_device_id(fdev), fdev->calc->serial); - fxlink_device_start_bulk_OUT(fdev, - "fxlink", "command", "test", 4); - } - else { - print(TUI.wConsole, "no connected device!\n"); - } - } + else + execute_command(command); fxlink_TUI_input_free(&input); print(TUI.wConsole, "%s", prompt); fxlink_TUI_input_init(&input, TUI.wConsole, 16); diff --git a/fxlink/protocol.c b/fxlink/protocol.c index 06d4101..435d4b0 100644 --- a/fxlink/protocol.c +++ b/fxlink/protocol.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "fxlink.h" bool fxlink_message_is_apptype(struct fxlink_message const *msg, @@ -236,6 +237,7 @@ struct fxlink_transfer *fxlink_transfer_make_IN(void *data, int size) tr->msg.data = malloc(tr->msg.size); tr->direction = FXLINK_TRANSFER_IN; tr->processed_size = 0; + tr->own_data = true; if(!tr->msg.data) { elog("cannot allocate buffer for %d bytes\n", tr->msg.size); @@ -262,6 +264,7 @@ struct fxlink_message *fxlink_transfer_finish_IN(struct fxlink_transfer *tr) log_("extracting completed message (%d bytes)\n", tr->msg.size); /* Shallow copy the malloc()'d data pointer */ + assert(tr->own_data && "Can't shallow copy data if we don't own it!"); memcpy(msg, &tr->msg, sizeof *msg); free(tr); return msg; @@ -283,7 +286,7 @@ void fxlink_transfer_receive(struct fxlink_transfer *tr, void *data, int size) } struct fxlink_transfer *fxlink_transfer_make_OUT(char const *application, - char const *type, void const *data, int size) + char const *type, void const *data, int size, bool own_data) { struct fxlink_transfer *tr = calloc(1, sizeof *tr); if(!tr) @@ -297,6 +300,7 @@ struct fxlink_transfer *fxlink_transfer_make_OUT(char const *application, tr->msg.data = (void *)data; tr->direction = FXLINK_TRANSFER_OUT; tr->processed_size = -1; + tr->own_data = own_data; return tr; } @@ -307,7 +311,7 @@ bool fxlink_transfer_complete(struct fxlink_transfer const *tr) void fxlink_transfer_free(struct fxlink_transfer *tr) { - if(tr->direction == FXLINK_TRANSFER_IN) + if(tr->own_data) free(tr->msg.data); free(tr); }