Untested serial implementation for windows

This commit is contained in:
Aaron Cook 2023-09-01 00:08:44 -05:00
commit 4eaac6d822
9 changed files with 213 additions and 70 deletions

View file

@ -1,27 +1,30 @@
TARGET_OS=LINUX 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
DIR_SRC=src DIR_SRC=src
DIR_BUILD=build DIR_BUILD=build
DIR_OBJ=$(DIR_BUILD)/obj DIR_OBJ=$(DIR_BUILD)/obj
DIR_BIN=$(DIR_BUILD)/bin 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 DEBUG ?= 0
ifeq ($(DEBUG), 1) ifeq ($(DEBUG), 1)
@ -40,10 +43,10 @@ install:
uninstall: uninstall:
rm -f /usr/local/bin/bytenuts rm -f /usr/local/bin/bytenuts
$(TARGET): $(OBJS) $(TARGET): $(OBJS) $(LIB_DEPS)
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
@echo "link and compile for $@" @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 $(DIR_OBJ)/$(DIR_SRC)/%.o: $(DIR_SRC)/%.c
@mkdir -p $(dir $@) @mkdir -p $(dir $@)

View file

@ -58,10 +58,16 @@ bytenuts_run(int argc, char **argv)
} }
bytenuts.serial_fd = serial_open(bytenuts.config.serial_path, bytenuts.config.baud); 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; return -1;
} }
printf("Opened \"%s\"\r\n", bytenuts.config.serial_path);
#ifndef __MINGW32__ #ifndef __MINGW32__
/* use pseudo-terminals for testing purposes */ /* use pseudo-terminals for testing purposes */
if (!strcmp(bytenuts.config.serial_path, "/dev/ptmx")) { if (!strcmp(bytenuts.config.serial_path, "/dev/ptmx")) {
@ -111,11 +117,13 @@ bytenuts_run(int argc, char **argv)
cheerios_start(&bytenuts); cheerios_start(&bytenuts);
ingest_start(&bytenuts); ingest_start(&bytenuts);
#ifndef __MINGW32__
if (!strcmp(bytenuts.config.serial_path, "/dev/ptmx")) { if (!strcmp(bytenuts.config.serial_path, "/dev/ptmx")) {
char info[128]; char info[128];
snprintf(info, sizeof(info), "Opened PTY port %s", ptsname(bytenuts.serial_fd)); snprintf(info, sizeof(info), "Opened PTY port %s", ptsname(bytenuts.serial_fd));
cheerios_info(info); cheerios_info(info);
} }
#endif
if (bytenuts.resume) { if (bytenuts.resume) {
load_state(); load_state();
@ -157,7 +165,7 @@ bytenuts_kill()
delwin(bytenuts.out_win); delwin(bytenuts.out_win);
endwin(); endwin();
close(bytenuts.serial_fd); serial_close(bytenuts.serial_fd);
} }
int int
@ -302,10 +310,17 @@ parse_args(int argc, char **argv)
/* setup default options first */ /* setup default options first */
bytenuts.config = CONFIG_DEFAULT; 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 *home = getenv("HOME");
char path[] = "/.config/bytenuts/config"; char path[] = "/.config/bytenuts/config";
bytenuts.config.config_path = malloc(strlen(home) + strlen(path) + 1); bytenuts.config.config_path = malloc(strlen(home) + strlen(path) + 1);
sprintf(bytenuts.config.config_path, "%s%s", home, path); sprintf(bytenuts.config.config_path, "%s%s", home, path);
#endif
} }
for (int i = 1; i < argc - 1; i++) { for (int i = 1; i < argc - 1; i++) {

View file

@ -3,7 +3,6 @@
#else #else
# include <ncurses.h> # include <ncurses.h>
#endif #endif
#include <poll.h>
#include <pthread.h> #include <pthread.h>
#include <sched.h> #include <sched.h>
#include <stdio.h> #include <stdio.h>
@ -54,14 +53,14 @@ cheerios_start(bytenuts_t *bytenuts)
pid = getpid(); pid = getpid();
name_len = snprintf( name_len = snprintf(
NULL, 0, NULL, 0,
"%s/.config/bytenuts/outbuf.%d.log", "%s/.config/bytenuts/outbuf.%lld.log",
home, pid home, (long long)pid
); );
cheerios.backup_filename = calloc(1, name_len + 1); cheerios.backup_filename = calloc(1, name_len + 1);
snprintf( snprintf(
cheerios.backup_filename, name_len + 1, cheerios.backup_filename, name_len + 1,
"%s/.config/bytenuts/outbuf.%d.log", "%s/.config/bytenuts/outbuf.%lld.log",
home, pid home, (long long)pid
); );
cheerios.backup = fopen(cheerios.backup_filename, "w"); cheerios.backup = fopen(cheerios.backup_filename, "w");
} }
@ -161,9 +160,22 @@ cheerios_stop()
int int
cheerios_input(const char *buf, size_t len) cheerios_input(const char *buf, size_t len)
{ {
size_t len_left = len;
size_t p = 0;
pthread_mutex_lock(&cheerios.lock); 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); pthread_mutex_unlock(&cheerios.lock);
return 0; return 0;
} }
@ -295,6 +307,7 @@ cheerios_getmaxy()
{ {
int y, x; int y, x;
getmaxyx(cheerios.output, y, x); getmaxyx(cheerios.output, y, x);
(void)x;
return y; return y;
} }
@ -303,6 +316,7 @@ cheerios_getmaxx()
{ {
int y, x; int y, x;
getmaxyx(cheerios.output, y, x); getmaxyx(cheerios.output, y, x);
(void)y;
return x; return x;
} }
@ -325,7 +339,6 @@ cheerios_thread(void *arg)
{ {
char buf[1024]; char buf[1024];
ssize_t read_ret = 0; ssize_t read_ret = 0;
struct pollfd fds;
while (cheerios.running) { while (cheerios.running) {
pthread_mutex_lock(&cheerios.lock); pthread_mutex_lock(&cheerios.lock);
@ -334,17 +347,7 @@ cheerios_thread(void *arg)
pthread_cond_wait(&cheerios.cond, &cheerios.lock); pthread_cond_wait(&cheerios.cond, &cheerios.lock);
} }
fds.fd = cheerios.ser_fd; read_ret = serial_read(cheerios.ser_fd, buf, sizeof(buf));
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));
if (read_ret > 0) { if (read_ret > 0) {
insert_buf(&cheerios.lines, buf, read_ret); insert_buf(&cheerios.lines, buf, read_ret);
} }

View file

@ -59,14 +59,14 @@ ingest_start(bytenuts_t *bytenuts)
pid = getpid(); pid = getpid();
name_len = snprintf( name_len = snprintf(
NULL, 0, NULL, 0,
"%s/.config/bytenuts/inbuf.%d.log", "%s/.config/bytenuts/inbuf.%lld.log",
HOME, pid HOME, (long long)pid
); );
ingest.history_filename = calloc(1, name_len + 1); ingest.history_filename = calloc(1, name_len + 1);
snprintf( snprintf(
ingest.history_filename, name_len + 1, ingest.history_filename, name_len + 1,
"%s/.config/bytenuts/inbuf.%d.log", "%s/.config/bytenuts/inbuf.%lld.log",
HOME, pid HOME, (long long)pid
); );
ingest.history_fd = fopen(ingest.history_filename, "w"); ingest.history_fd = fopen(ingest.history_filename, "w");
@ -209,7 +209,6 @@ ingest_set_history(char **history, int history_len)
static void * static void *
ingest_thread(void *arg) ingest_thread(void *arg)
{ {
int esc_flag;
int ch; int ch;
memset(ingest.inbuf, 0, sizeof(ingest.inbuf)); memset(ingest.inbuf, 0, sizeof(ingest.inbuf));
@ -218,8 +217,6 @@ ingest_thread(void *arg)
bytenuts_set_status(STATUS_INGEST, "normal"); bytenuts_set_status(STATUS_INGEST, "normal");
while (ingest.running) { while (ingest.running) {
esc_flag = 0;
pthread_mutex_lock(ingest.term_lock); pthread_mutex_lock(ingest.term_lock);
ch = wgetch(ingest.input); ch = wgetch(ingest.input);
pthread_mutex_unlock(ingest.term_lock); pthread_mutex_unlock(ingest.term_lock);

View file

@ -4,16 +4,20 @@
#include "bytenuts.h" #include "bytenuts.h"
#ifndef __MINGW32__
static void sigint_handler(int s); static void sigint_handler(int s);
#endif
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
#ifndef __MINGW32__
struct sigaction act; struct sigaction act;
act.sa_handler = sigint_handler; act.sa_handler = sigint_handler;
sigemptyset(&act.sa_mask); sigemptyset(&act.sa_mask);
act.sa_flags = 0; act.sa_flags = 0;
sigaction(SIGINT, &act, NULL); sigaction(SIGINT, &act, NULL);
#endif
if (bytenuts_run(argc, argv)) { if (bytenuts_run(argc, argv)) {
bytenuts_stop(); bytenuts_stop();
@ -23,9 +27,11 @@ main(int argc, char **argv)
exit(0); exit(0);
} }
#ifndef __MINGW32__
static void static void
sigint_handler(int s) sigint_handler(int s)
{ {
bytenuts_kill(); bytenuts_kill();
exit(1); exit(1);
} }
#endif

View file

@ -3,15 +3,18 @@
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <time.h>
#include <stdint.h>
#include "serial.h" #include "serial.h"
#ifdef __MINGW32__ #ifdef __MINGW32__
# include <windows.h> # include <windows.h>
serial_t serial_t
serial_open(const char *comport, long bps) serial_open(const char *comport, long bps)
{ {
DCB dcb = { 0 }; /* referred to: https://github.com/waynix/SPinGW/tree/master */
HANDLE serial = CreateFile( HANDLE serial = CreateFile(
comport, comport,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
@ -21,15 +24,112 @@ serial_open(const char *comport, long bps)
0, 0,
0 0
); );
DCB serial_params = { 0 };
COMMTIMEOUTS timeouts = { 0 };
if (serial == INVALID_HANDLE_VALUE) { 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; return -1;
} }
/* TODO return ret;
* reference: https://github.com/waynix/SPinGW/tree/master */
return serial;
} }
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 #else
# include <termios.h> # include <termios.h>
# include <poll.h> # include <poll.h>
@ -46,7 +146,7 @@ serial_open(const char *path, long bps)
fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY); fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) { if (fd == -1) {
return -1; return SERIAL_INVALID;
} }
tcgetattr(fd, &otio); tcgetattr(fd, &otio);
@ -88,25 +188,37 @@ serial_open(const char *path, long bps)
return fd; return fd;
} }
int ssize_t
serial_read(serial_t serial, void *buf, size_t len) 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; struct pollfd fds;
fds.fd = serial; fds.fd = serial;
fds.events = POLLIN; fds.events = POLLIN;
fds.revents = 0; fds.revents = 0;
if (poll(&fds, 1, 1) == 0) { if (poll(&fds, 1, to_ms) == 0) {
return 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 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 static speed_t

View file

@ -8,8 +8,24 @@ typedef HANDLE serial_t;
typedef int serial_t; typedef int serial_t;
#endif #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); 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_ */ #endif /* _SERIAL_H_ */

View file

@ -1,4 +1,3 @@
#include <poll.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -8,7 +7,7 @@
#include "xmodem.h" #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); uint16_t _xmodem_crc(const uint8_t *buf, size_t len);
uint8_t _xmodem_csum(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 int
xmodem_send( xmodem_send(
int dest_fd, serial_t dest_fd,
int in_fd, int in_fd,
size_t sz, size_t sz,
int block_sz, int block_sz,
@ -106,7 +105,7 @@ xmodem_send(
goto end_of_transmission; 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; return XMODEM_ERR_WRITE;
} }
@ -138,7 +137,7 @@ end_of_transmission:
return XMODEM_ERR_TIMEOUT; return XMODEM_ERR_TIMEOUT;
} }
write(dest_fd, &(uint8_t){XMODEM_EOT}, 1); serial_write(dest_fd, &(uint8_t){XMODEM_EOT}, 1);
if ( if (
!_xmodem_wait(dest_fd, &ack_char, XMODEM_TIMEOUT) && !_xmodem_wait(dest_fd, &ack_char, XMODEM_TIMEOUT) &&
@ -154,20 +153,12 @@ end_of_transmission:
} }
int 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; if (serial_read_to(fd, ret, 1, timeout_ms) != 1) {
pfd.fd = fd;
pfd.events = POLLIN;
pfd.revents = 0;
if (poll(&pfd, 1, timeout_ms) <= 0) {
return -1; return -1;
} }
read(fd, ret, 1);
return 0; return 0;
} }

View file

@ -30,7 +30,7 @@
* length of `block_sz`. * length of `block_sz`.
*/ */
int xmodem_send( int xmodem_send(
int dest_fd, serial_t dest_fd,
int in_fd, int in_fd,
size_t sz, size_t sz,
int block_sz, int block_sz,