From 4eaac6d822ee06c4bc9db1e41b73e5d8d7cd6fd2 Mon Sep 17 00:00:00 2001 From: Aaron Cook Date: Fri, 1 Sep 2023 00:08:44 -0500 Subject: [PATCH] Untested serial implementation for windows --- Makefile | 43 ++++++++-------- src/bytenuts.c | 19 ++++++- src/cheerios.c | 39 ++++++++------- src/ingest.c | 11 ++--- src/main.c | 6 +++ src/serial.c | 132 +++++++++++++++++++++++++++++++++++++++++++++---- src/serial.h | 20 +++++++- src/xmodem.c | 21 +++----- src/xmodem.h | 2 +- 9 files changed, 218 insertions(+), 75 deletions(-) diff --git a/Makefile b/Makefile index e09ca14..02282fd 100644 --- a/Makefile +++ b/Makefile @@ -1,27 +1,30 @@ -TARGET_OS=LINUX - -CFLAGS=-Wall -MMD -pthread -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=199309L - -SRCS=$(wildcard $(DIR_SRC)/*.c) -OBJS=$(addprefix $(DIR_OBJ)/,$(addsuffix .o,$(basename $(SRCS)))) -DEPS=$(addprefix $(DIR_OBJ)/,$(addsuffix .d,$(basename $(SRCS)))) - -ifeq ($(TARGET_OS), LINUX) - CC=clang -else - CC=x86_64-w64-mingw32-gcc - CFLAGS+=-Llib/PDCurses/wincon -Llib/PDCurses - DEPS+=PDCurses -endif - -LDFLAGS=-lpthread -lncurses +OS=LINUX DIR_SRC=src DIR_BUILD=build DIR_OBJ=$(DIR_BUILD)/obj DIR_BIN=$(DIR_BUILD)/bin -TARGET=$(DIR_BIN)/bytenuts +CFLAGS=-Wall -MMD -pthread -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=199309L +LIB_DEPS= +LIB_OBJS= + +SRCS=$(wildcard $(DIR_SRC)/*.c) +OBJS=$(addprefix $(DIR_OBJ)/,$(addsuffix .o,$(basename $(SRCS)))) +DEPS=$(addprefix $(DIR_OBJ)/,$(addsuffix .d,$(basename $(SRCS)))) + +ifeq ($(OS), LINUX) + CC=clang + LDFLAGS=-lncurses -lpthread + TARGET=$(DIR_BIN)/bytenuts +else + CC=x86_64-w64-mingw32-gcc + CFLAGS+=-Ilib/PDCurses/wincon/ -Ilib/PDCurses/ + LDFLAGS=-lpthread -static + LIB_DEPS+=PDCurses + LIB_OBJS+=lib/PDCurses/wincon/*.o + TARGET=$(DIR_BIN)/bytenuts.exe +endif DEBUG ?= 0 ifeq ($(DEBUG), 1) @@ -40,10 +43,10 @@ install: uninstall: rm -f /usr/local/bin/bytenuts -$(TARGET): $(OBJS) +$(TARGET): $(OBJS) $(LIB_DEPS) @mkdir -p $(dir $@) @echo "link and compile for $@" - @$(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(OBJS) + @$(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(OBJS) $(LIB_OBJS) $(DIR_OBJ)/$(DIR_SRC)/%.o: $(DIR_SRC)/%.c @mkdir -p $(dir $@) diff --git a/src/bytenuts.c b/src/bytenuts.c index 908ac61..ff6a585 100644 --- a/src/bytenuts.c +++ b/src/bytenuts.c @@ -58,10 +58,16 @@ bytenuts_run(int argc, char **argv) } bytenuts.serial_fd = serial_open(bytenuts.config.serial_path, bytenuts.config.baud); - if (bytenuts.serial_fd < 0) { + if (bytenuts.serial_fd == SERIAL_INVALID) { + printf( + "Failed to open serial port \"%s\"\r\n", + bytenuts.config.serial_path + ); return -1; } + printf("Opened \"%s\"\r\n", bytenuts.config.serial_path); + #ifndef __MINGW32__ /* use pseudo-terminals for testing purposes */ if (!strcmp(bytenuts.config.serial_path, "/dev/ptmx")) { @@ -111,11 +117,13 @@ bytenuts_run(int argc, char **argv) cheerios_start(&bytenuts); ingest_start(&bytenuts); +#ifndef __MINGW32__ if (!strcmp(bytenuts.config.serial_path, "/dev/ptmx")) { char info[128]; snprintf(info, sizeof(info), "Opened PTY port %s", ptsname(bytenuts.serial_fd)); cheerios_info(info); } +#endif if (bytenuts.resume) { load_state(); @@ -157,7 +165,7 @@ bytenuts_kill() delwin(bytenuts.out_win); endwin(); - close(bytenuts.serial_fd); + serial_close(bytenuts.serial_fd); } int @@ -302,10 +310,17 @@ parse_args(int argc, char **argv) /* setup default options first */ bytenuts.config = CONFIG_DEFAULT; { +#ifdef __MINGW32__ + char *home = getenv("HOMEPATH"); + char path[] = "\\.config\\bytenuts\\config"; + bytenuts.config.config_path = malloc(strlen(home) + strlen(path) + 4); + sprintf(bytenuts.config.config_path, "C:\\%s%s", home, path); +#else char *home = getenv("HOME"); char path[] = "/.config/bytenuts/config"; bytenuts.config.config_path = malloc(strlen(home) + strlen(path) + 1); sprintf(bytenuts.config.config_path, "%s%s", home, path); +#endif } for (int i = 1; i < argc - 1; i++) { diff --git a/src/cheerios.c b/src/cheerios.c index f0f6b99..9c25d7c 100644 --- a/src/cheerios.c +++ b/src/cheerios.c @@ -3,7 +3,6 @@ #else # include #endif -#include #include #include #include @@ -54,14 +53,14 @@ cheerios_start(bytenuts_t *bytenuts) pid = getpid(); name_len = snprintf( NULL, 0, - "%s/.config/bytenuts/outbuf.%d.log", - home, pid + "%s/.config/bytenuts/outbuf.%lld.log", + home, (long long)pid ); cheerios.backup_filename = calloc(1, name_len + 1); snprintf( cheerios.backup_filename, name_len + 1, - "%s/.config/bytenuts/outbuf.%d.log", - home, pid + "%s/.config/bytenuts/outbuf.%lld.log", + home, (long long)pid ); cheerios.backup = fopen(cheerios.backup_filename, "w"); } @@ -161,9 +160,22 @@ cheerios_stop() int cheerios_input(const char *buf, size_t len) { + size_t len_left = len; + size_t p = 0; + pthread_mutex_lock(&cheerios.lock); - write(cheerios.ser_fd, buf, len); + while (len_left > 0) { + ssize_t tmp = serial_write(cheerios.ser_fd, &buf[p], len_left); + + if (tmp < 0) { + pthread_mutex_unlock(&cheerios.lock); + return -1; + } + + len_left -= tmp; + } pthread_mutex_unlock(&cheerios.lock); + return 0; } @@ -295,6 +307,7 @@ cheerios_getmaxy() { int y, x; getmaxyx(cheerios.output, y, x); + (void)x; return y; } @@ -303,6 +316,7 @@ cheerios_getmaxx() { int y, x; getmaxyx(cheerios.output, y, x); + (void)y; return x; } @@ -325,7 +339,6 @@ cheerios_thread(void *arg) { char buf[1024]; ssize_t read_ret = 0; - struct pollfd fds; while (cheerios.running) { pthread_mutex_lock(&cheerios.lock); @@ -334,17 +347,7 @@ cheerios_thread(void *arg) pthread_cond_wait(&cheerios.cond, &cheerios.lock); } - fds.fd = cheerios.ser_fd; - fds.events = POLLIN; - fds.revents = 0; - - if (poll(&fds, 1, 1) == 0) { - pthread_mutex_unlock(&cheerios.lock); - nanosleep(&(struct timespec){ 0, 100000 }, NULL); - continue; - } - - read_ret = read(cheerios.ser_fd, buf, sizeof(buf)); + read_ret = serial_read(cheerios.ser_fd, buf, sizeof(buf)); if (read_ret > 0) { insert_buf(&cheerios.lines, buf, read_ret); } diff --git a/src/ingest.c b/src/ingest.c index d374626..6203077 100644 --- a/src/ingest.c +++ b/src/ingest.c @@ -59,14 +59,14 @@ ingest_start(bytenuts_t *bytenuts) pid = getpid(); name_len = snprintf( NULL, 0, - "%s/.config/bytenuts/inbuf.%d.log", - HOME, pid + "%s/.config/bytenuts/inbuf.%lld.log", + HOME, (long long)pid ); ingest.history_filename = calloc(1, name_len + 1); snprintf( ingest.history_filename, name_len + 1, - "%s/.config/bytenuts/inbuf.%d.log", - HOME, pid + "%s/.config/bytenuts/inbuf.%lld.log", + HOME, (long long)pid ); ingest.history_fd = fopen(ingest.history_filename, "w"); @@ -209,7 +209,6 @@ ingest_set_history(char **history, int history_len) static void * ingest_thread(void *arg) { - int esc_flag; int ch; memset(ingest.inbuf, 0, sizeof(ingest.inbuf)); @@ -218,8 +217,6 @@ ingest_thread(void *arg) bytenuts_set_status(STATUS_INGEST, "normal"); while (ingest.running) { - esc_flag = 0; - pthread_mutex_lock(ingest.term_lock); ch = wgetch(ingest.input); pthread_mutex_unlock(ingest.term_lock); diff --git a/src/main.c b/src/main.c index b75957c..6e1e64b 100644 --- a/src/main.c +++ b/src/main.c @@ -4,16 +4,20 @@ #include "bytenuts.h" +#ifndef __MINGW32__ static void sigint_handler(int s); +#endif int main(int argc, char **argv) { +#ifndef __MINGW32__ struct sigaction act; act.sa_handler = sigint_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); +#endif if (bytenuts_run(argc, argv)) { bytenuts_stop(); @@ -23,9 +27,11 @@ main(int argc, char **argv) exit(0); } +#ifndef __MINGW32__ static void sigint_handler(int s) { bytenuts_kill(); exit(1); } +#endif diff --git a/src/serial.c b/src/serial.c index 16d0016..1368584 100644 --- a/src/serial.c +++ b/src/serial.c @@ -3,15 +3,18 @@ #include #include #include +#include +#include #include "serial.h" #ifdef __MINGW32__ # include + serial_t serial_open(const char *comport, long bps) { - DCB dcb = { 0 }; + /* referred to: https://github.com/waynix/SPinGW/tree/master */ HANDLE serial = CreateFile( comport, GENERIC_READ | GENERIC_WRITE, @@ -21,15 +24,112 @@ serial_open(const char *comport, long bps) 0, 0 ); + DCB serial_params = { 0 }; + COMMTIMEOUTS timeouts = { 0 }; if (serial == INVALID_HANDLE_VALUE) { + return SERIAL_INVALID; + } + + serial_params.DCBlength = sizeof(serial_params); + if (!GetCommState(serial, &serial_params)) { + return SERIAL_INVALID; + } + + /* 8n1 */ + serial_params.BaudRate = bps; + serial_params.ByteSize = 8; + serial_params.StopBits = 1; + serial_params.Parity = NOPARITY; + + if (!SetCommState(serial, &serial_params)) { + return SERIAL_INVALID; + } + + timeouts.ReadIntervalTimeout = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + + if (!SetCommTimeouts(serial, &timeouts)) { + return SERIAL_INVALID; + } + + return serial; +} + +ssize_t +serial_read(serial_t serial, void *buf, size_t len) +{ + DWORD ret = 0; + + if (!ReadFile(serial, buf, len, &ret, NULL)) { return -1; } - /* TODO - * reference: https://github.com/waynix/SPinGW/tree/master */ - return serial; + return ret; } + +ssize_t +serial_read_to(serial_t serial, void *buf, size_t len, unsigned int to_ms) +{ + DWORD ret = -1; + size_t p = 0; + size_t len_left = len; + + while (to_ms > 0) { + DWORD tmp = 0; + + if (!ReadFile(serial, &((uint8_t *)buf)[p], len_left, &tmp, NULL)) { + return ret; + } + + if (tmp > 0) { + if (ret < 0) { + ret = tmp; + } else { + ret += tmp; + } + + len_left -= tmp; + p += tmp; + } + + if (len_left == 0) { + return ret; + } + + /* sleep 1ms */ + nanosleep(&(struct timespec){ 0, 1000000 }, NULL); + to_ms--; + } + + if (ret < 0) { + ret = 0; + } + + return ret; +} + +ssize_t +serial_write(serial_t serial, const void *buf, size_t len) +{ + DWORD ret = 0; + + if (!WriteFile(serial, buf, len, &ret, NULL)) { + return -1; + } + + return ret; +} + +int +serial_close(serial_t serial) +{ + return (CloseHandle(serial) != 0); +} + #else # include # include @@ -46,7 +146,7 @@ serial_open(const char *path, long bps) fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { - return -1; + return SERIAL_INVALID; } tcgetattr(fd, &otio); @@ -88,25 +188,37 @@ serial_open(const char *path, long bps) return fd; } -int +ssize_t serial_read(serial_t serial, void *buf, size_t len) +{ + return serial_read_to(serial, buf, len, 0); +} + +ssize_t +serial_read_to(serial_t serial, void *buf, size_t len, unsigned int to_ms) { struct pollfd fds; fds.fd = serial; fds.events = POLLIN; fds.revents = 0; - if (poll(&fds, 1, 1) == 0) { + if (poll(&fds, 1, to_ms) == 0) { return 0; } - return (int)read(serial, buf, len); + return read(serial, buf, len); +} + +ssize_t +serial_write(serial_t serial, const void *buf, size_t len) +{ + return write(serial, buf, len); } int -serial_write(serial_t serial, void *buf, size_t len) +serial_close(serial_t serial) { - return (int)write(serial, buf, len); + return close(serial); } static speed_t diff --git a/src/serial.h b/src/serial.h index bcae708..eff7835 100644 --- a/src/serial.h +++ b/src/serial.h @@ -8,8 +8,24 @@ typedef HANDLE serial_t; typedef int serial_t; #endif +#define SERIAL_INVALID (serial_t)(-1) + +/* Open a serial port with the given speed and return a handle that can be used + * in the other serial APIs*/ serial_t serial_open(const char *path, long bps); -int serial_read(serial_t serial, void *buf, size_t len); -int serial_write(serial_t serial, void *buf, size_t len); + +/* Read up to len bytes (non-blocking), length read is returned */ +ssize_t serial_read(serial_t serial, void *buf, size_t len); + +/* Read up to len bytes, or until to_ms milliseconds have elapsed, length read + * is returned */ +ssize_t serial_read_to(serial_t serial, void *buf, size_t len, unsigned int to_ms); + +/* Write len bytes onto the serial port, actual number of bytes written is + * returned */ +ssize_t serial_write(serial_t serial, const void *buf, size_t len); + +/* Close the serial file */ +int serial_close(serial_t serial); #endif /* _SERIAL_H_ */ diff --git a/src/xmodem.c b/src/xmodem.c index 9bf850d..3752184 100644 --- a/src/xmodem.c +++ b/src/xmodem.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -8,7 +7,7 @@ #include "xmodem.h" -int _xmodem_wait(int fd, uint8_t *ret, int timeout_ms); +int _xmodem_wait(serial_t fd, uint8_t *ret, int timeout_ms); uint16_t _xmodem_crc(const uint8_t *buf, size_t len); uint8_t _xmodem_csum(const uint8_t *buf, size_t len); @@ -16,7 +15,7 @@ void _xmodem_status_print(size_t sent, size_t total); int xmodem_send( - int dest_fd, + serial_t dest_fd, int in_fd, size_t sz, int block_sz, @@ -106,7 +105,7 @@ xmodem_send( goto end_of_transmission; } - if (write(dest_fd, buf, buf_sz) != buf_sz){ + if (serial_write(dest_fd, buf, buf_sz) != buf_sz){ return XMODEM_ERR_WRITE; } @@ -138,7 +137,7 @@ end_of_transmission: return XMODEM_ERR_TIMEOUT; } - write(dest_fd, &(uint8_t){XMODEM_EOT}, 1); + serial_write(dest_fd, &(uint8_t){XMODEM_EOT}, 1); if ( !_xmodem_wait(dest_fd, &ack_char, XMODEM_TIMEOUT) && @@ -154,20 +153,12 @@ end_of_transmission: } int -_xmodem_wait(int fd, uint8_t *ret, int timeout_ms) +_xmodem_wait(serial_t fd, uint8_t *ret, int timeout_ms) { - struct pollfd pfd; - - pfd.fd = fd; - pfd.events = POLLIN; - pfd.revents = 0; - - if (poll(&pfd, 1, timeout_ms) <= 0) { + if (serial_read_to(fd, ret, 1, timeout_ms) != 1) { return -1; } - read(fd, ret, 1); - return 0; } diff --git a/src/xmodem.h b/src/xmodem.h index ac65b02..c9a44ca 100644 --- a/src/xmodem.h +++ b/src/xmodem.h @@ -30,7 +30,7 @@ * length of `block_sz`. */ int xmodem_send( - int dest_fd, + serial_t dest_fd, int in_fd, size_t sz, int block_sz,