commit 6fdadc45b6739300116308b97ee123552e6758bf Author: empathicqubit Date: Sat Dec 24 11:32:32 2022 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..2ada58c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Starten", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/ticat", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "preLaunchTask": "build", + "setupCommands": [ + { + "description": "Automatische Strukturierung und Einrückung für \"gdb\" aktivieren", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2299e8c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "cmdz80.h": "c", + "ticalcs.h": "c", + "ticables.h": "c", + "vector": "c", + "random": "c" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..05d462b --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,16 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "cd build && make", + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8ce3b58 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.16) +find_package (ticables2) +find_package (pthread) +add_executable (tibridge main.c) +target_link_libraries (tibridge LINK_PUBLIC ticables2) +target_link_libraries (tibridge LINK_PUBLIC pthread) diff --git a/main.c b/main.c new file mode 100644 index 0000000..8d89c24 --- /dev/null +++ b/main.c @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static CableDeviceInfo EmptyInfo; + +static pthread_t tid; + +static CableHandle* handle; + +static pthread_mutex_t lock; + +static CablePort port; + +void reset_cable(void) { + unsigned char err; + ticables_cable_reset(handle); + ticables_cable_close(handle); + ticables_handle_del(handle); + handle = ticables_handle_new(CABLE_SLV, port); + ticables_options_set_delay(handle, 1); + ticables_options_set_timeout(handle, 5); + + while(err = ticables_cable_open(handle)) { + fprintf(stderr, "Could not open cable: %d\n", err); + } +} + +typedef enum { + LEVEL_ERROR, + LEVEL_WARN, + LEVEL_INFO, + LEVEL_DEBUG, + LEVEL_TRACE, +} LOG_LEVEL; + +static LOG_LEVEL current_log_level = LEVEL_TRACE; + +#define log(level, fmt, values...) if(level <= current_log_level) { fprintf(stderr, fmt, ## values); fflush(stderr); } + +void retry_send(unsigned char* send, int sendCount) { + unsigned char err = 0; + log(LEVEL_DEBUG, "SENDING %d BYTES \n", sendCount); + log(LEVEL_TRACE, "%.*s\n", sendCount, send); + while(err = ticables_cable_send(handle, send, sendCount)) { + log(LEVEL_ERROR, "Error sending: %d", err); + reset_cable(); + } +} + +void retry_recv(unsigned char* recv, int recvCount) { + log(LEVEL_DEBUG, "RECEIVED %d BYTES\n", recvCount); + log(LEVEL_TRACE, "%.*s\n", recvCount, recv) + for(int c = 0; c < recvCount; c++) { + putchar(recv[c]); + } + fflush(stdout); +} + +void INThandler(int sig) { + signal(sig, SIG_IGN); + char rest[1024]; + int count = read(0, rest, sizeof(rest)); + fwrite(rest, count, 1, stderr); + fflush(stderr); +} + +int main(void) { + int **cables = NULL; + int err; + +/* + signal(SIGINT, INThandler); + signal(SIGSTOP, INThandler); + signal(SIGTERM, INThandler); + signal(SIGQUIT, INThandler); + */ + + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stdin, NULL, _IONBF, 0); + + log(LEVEL_INFO, "PROCESS ID: %d\n", getpid()); + + if (pthread_mutex_init(&lock, NULL) != 0) { + fprintf(stderr, "mutex init has failed\n"); + return 1; + } + + ticables_library_init(); + + // search for all USB cables (faster) + log(LEVEL_INFO, "Searching for link cables...\n"); + err = ticables_probing_do(&cables, 5, PROBE_USB | PROBE_FIRST); + if(err) + { + log(LEVEL_ERROR, "Could not probe cable: %d\n", err); + ticables_probing_finish(&cables); + return 1; + } + + int *ports = cables[CABLE_SLV]; + int i; + for(i = 0; !ports[i] && i < 5; i++); + + port = ports[i]; + handle = ticables_handle_new(CABLE_SLV, port); + ticables_options_set_delay(handle, 1); + ticables_options_set_timeout(handle, 5); + + err = ticables_cable_open(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); + if(err) { + log(LEVEL_ERROR, "Could not read device info: %d\n", err); + return 1; + } + + log(LEVEL_INFO, "INFO: Family %d, Variant %d\n", info.family, info.variant); + + // FIXME Option to ignore first command or not + bool handled_first_recv = false; + + while(true) { + unsigned char recv[255]; + unsigned char current = 0; + unsigned char recvCount = 0; + int c; + + log(LEVEL_DEBUG, "RECEIVE PHASE\n"); + while(true) { + do { + if(err = ticables_cable_recv(handle, &recv[recvCount], 1)) { + log(LEVEL_ERROR, "error receiving: %d\n", err); + } + } while(err); + current = recv[recvCount]; + recvCount++; + if(current == '#') { + do { + if(err = ticables_cable_recv(handle, &recv[recvCount], 2)) { + log(LEVEL_ERROR, "error receiving: %d\n", err); + } + } while(err); + recvCount += 2; + if(handled_first_recv) { + retry_recv(recv, recvCount); + } + recvCount = 0; + break; + } + else if(recvCount == 1) { + if(current == '-') { + retry_recv(recv, recvCount); + recvCount = 0; + break; + } + else if(current == '+') { + continue; + } + } + } + + if(!handled_first_recv) { + handled_first_recv = true; + retry_send("+", 1); + continue; + } + + fd_set set; + FD_ZERO(&set); + FD_SET(0, &set); + struct timeval timeout = { 1, 0 }; + + log(LEVEL_DEBUG, "SEND PHASE\n"); + while(select(1, &set, NULL, NULL, &timeout)) { + unsigned char send[255]; + int sendCount = 0; + + while(true) { + while((c = read(0, &send[sendCount], 1)) <= 0); + current = send[sendCount]; + sendCount++; + if(current == '#') { + read(0, &send[sendCount], 2); + sendCount += 2; + break; + } + else if(sendCount == 1 && (current == '-' || current == '+')) { + break; + } + } + + retry_send(send, sendCount); + break; + } + } +}