commit d4d3b901bd358661258e1f6405be3ffd44c7b7f8 Author: redoste Date: Sun May 21 19:20:17 2023 +0200 Initial commit diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..e209240 --- /dev/null +++ b/.clang-format @@ -0,0 +1,10 @@ +--- +BasedOnStyle: Chromium +AlignConsecutiveMacros: AcrossComments +ColumnLimit: '0' +ContinuationIndentWidth: '8' +IndentWidth: '8' +TabWidth: '8' +UseTab: ForContinuationAndIndentation + +... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac727e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# giteapc +build/ +giteapc-config.make + +# clangd +.cache/ +compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..747ad2c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.15) +project(fxlink-gdb-proxy VERSION 0.1 LANGUAGES C) + +list(APPEND CMAKE_MODULE_PATH "$ENV{HOME}/.local/lib/cmake") +if(DEFINED "$ENV{FXSDK_PATH}") + list(APPEND CMAKE_MODULE_PATH "$ENV{FXSDK_PATH}/lib/cmake") +endif() +find_package(LibFxlink 2.10 REQUIRED) + +add_compile_options(-Wall -Wextra -Wpedantic -Wstrict-prototypes -Wvla -Wswitch-enum -Werror) +add_executable(fxlink-gdb-proxy src/main.c) +target_link_libraries(fxlink-gdb-proxy PRIVATE LibFxlink::LibFxlink) + +install(TARGETS fxlink-gdb-proxy) diff --git a/giteapc.make b/giteapc.make new file mode 100644 index 0000000..5ee71fe --- /dev/null +++ b/giteapc.make @@ -0,0 +1,19 @@ +# giteapc: version=1 depends=Lephenixnoir/fxsdk + +-include giteapc-config.make + +PREFIX ?= $(GITEAPC_PREFIX) + +configure: + @ cmake -B build -DCMAKE_INSTALL_PREFIX="$(PREFIX)" + +build: + @ make -C build + +install: + @ make -C build install + +uninstall: + @ if [ -e build/install_manifest.txt ]; then xargs rm -v < build/install_manifest.txt; fi + +.PHONY: configure build install uninstall diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..ee3671e --- /dev/null +++ b/src/main.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +static struct fxlink_device* setup_calc(libusb_context* context) { + struct fxlink_filter filter = { + .intf_fxlink = true, + }; + delay_t delay = delay_infinite(); + fxlink_filter_clean_libusb(&filter); + + hlog("calculators"); + log_("wating for fxlink capable device...\n"); + struct fxlink_device* dev = fxlink_device_find_wait(context, &filter, &delay); + if (!dev) { + elog("unable to open fxlink_device\n"); + return NULL; + } + + if (!fxlink_device_claim_fxlink(dev)) { + elog("unable to claim fxlink\n"); + return NULL; + } + + return dev; +} + +static int setup_socket(const char* listen_path) { + int listen_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (listen_socket < 0) { + perror("socket"); + return -1; + } + + struct sockaddr_un listen_address = { + .sun_family = AF_UNIX, + .sun_path = {0}, + }; + strncpy(listen_address.sun_path, listen_path, sizeof(listen_address.sun_path) - 1); + if (bind(listen_socket, (struct sockaddr*)&listen_address, sizeof(listen_address)) < 0) { + close(listen_socket); + perror("bind"); + return -1; + } + + if (listen(listen_socket, 1024) < 0) { + close(listen_socket); + perror("listen"); + return -1; + } + + hlog("socket"); + log_("wating for client on \"%s\"...\n", listen_address.sun_path); + int client_socket = accept(listen_socket, NULL, NULL); + if (client_socket < 0) { + close(listen_socket); + perror("accept"); + return -1; + } + close(listen_socket); + return client_socket; +} + +int main(int argc, char* argv[]) { + if (argc != 2) { + elog("Usage : %s [listen path]\n", argv[0]); + return -1; + } + + libusb_context* context = NULL; + int err = libusb_init(&context); + if (err != 0) { + elog_libusb(err, "libusb_init"); + return -1; + } + struct fxlink_device* dev = setup_calc(context); + if (dev == NULL) { + return -1; + } + int client_socket = setup_socket(argv[1]); + if (client_socket < 0) { + return -1; + } + + struct pollfd client_socket_pollfd = {.fd = client_socket, .events = POLLIN}; + struct fxlink_pollfds fxlink_polled_fds; + fxlink_pollfds_track(&fxlink_polled_fds, context); + + if (!fxlink_device_start_bulk_IN(dev)) { + elog("unable to start bulk IN trasfer\n"); + return -1; + } + + // TODO : find a way to properly close socket or USB interface when the other side is disconnected + int ret = 0; + while (1) { + int err = fxlink_multipoll(-1, fxlink_polled_fds.fds, fxlink_polled_fds.count, + &client_socket_pollfd, 1, + NULL); + if (err < 0) { + perror("poll"); + ret = -1; + break; + } + + struct timeval zero = {0}; + libusb_handle_events_timeout(context, &zero); + struct fxlink_message* msg = fxlink_device_finish_bulk_IN(dev); + if (msg) { + if (!fxlink_message_is_apptype(msg, "gdb", "remote")) { + elog("unknown fxlink message type\n"); + ret = -1; + break; + } + ssize_t send_ret = send(client_socket, msg->data, msg->size, 0); + if (send_ret != msg->size) { + perror("send"); + ret = -1; + break; + } + fxlink_message_free(msg, true); + + // TODO : Uhu ? + /* if (!fxlink_device_start_bulk_IN(dev)) { + * elog("unable to start bulk IN trasfer\n"); + * return -1; + * } + */ + fxlink_device_start_bulk_IN(dev); + } + + int bytes_socket; + if (ioctl(client_socket, FIONREAD, &bytes_socket) < 0) { + perror("ioctl"); + ret = -1; + break; + } + if (bytes_socket > 0) { + char buf[1024]; + ssize_t recv_ret = recv(client_socket, buf, sizeof(buf), MSG_PEEK); + if (recv_ret < 0) { + perror("recv"); + ret = -1; + break; + } + // TODO : Figure out why we need this workaround when we go too fast + if (!fxlink_device_start_bulk_OUT(dev, "gdb", "remote", buf, recv_ret, false)) { + elog("unable to start bulk OUT trasfer\n"); + } else { + ssize_t recv_ret2 = recv(client_socket, buf, recv_ret, 0); + assert(recv_ret2 == recv_ret); + } + } + } + + fxlink_pollfds_stop(&fxlink_polled_fds); + fxlink_device_cleanup(dev); + free(dev); + libusb_exit(context); + return ret; +}