skipstone/src/skipstone.c

165 lines
3.6 KiB
C
Raw Normal View History

2017-11-21 00:59:27 +00:00
#include <string.h>
2017-11-21 22:24:52 +00:00
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <endian.h>
2017-11-21 00:59:27 +00:00
2017-11-21 22:24:52 +00:00
#include <skipstone/skipstone.h>
2017-11-21 00:59:27 +00:00
enum skipstone_watch_link_type {
SKIPSTONE_WATCH_LINK_SERIAL = 1
};
struct _skipstone_watch_link {
2017-11-21 22:24:52 +00:00
enum skipstone_watch_link_type type;
2017-11-21 00:59:27 +00:00
union {
2017-11-21 22:24:52 +00:00
struct {
int fd;
struct termios attr_old,
attr_new;
} serial;
2017-11-21 00:59:27 +00:00
};
};
2017-11-21 22:24:52 +00:00
typedef struct _skipstone_message_header {
uint16_t size,
endpoint;
} skipstone_message_header;
2017-11-21 00:59:27 +00:00
skipstone_watch_link *skipstone_watch_link_open_serial(const char *device) {
skipstone_watch_link *link;
if ((link = malloc(sizeof(*link))) == NULL) {
goto error_malloc_link;
}
2017-11-21 22:24:52 +00:00
link->type = SKIPSTONE_WATCH_LINK_SERIAL;
if ((link->serial.fd = open(device, O_RDWR | O_NOCTTY)) < 0) {
goto error_open;
}
if (tcgetattr(link->serial.fd, &link->serial.attr_old) < 0) {
goto error_io;
}
memset(&link->serial.attr_new, 0, sizeof(struct termios));
2017-11-21 00:59:27 +00:00
2017-11-21 22:24:52 +00:00
link->serial.attr_new.c_cflag = CS8 | HUPCL;
link->serial.attr_new.c_ispeed = B115200;
link->serial.attr_new.c_ospeed = B115200;
link->serial.attr_new.c_iflag = IGNPAR;
link->serial.attr_new.c_oflag = 0;
link->serial.attr_new.c_lflag = 0;
link->serial.attr_new.c_cc[VTIME] = 0;
link->serial.attr_new.c_cc[VMIN] = 1;
if (tcsetattr(link->serial.fd, TCSANOW, &link->serial.attr_new) < 0) {
goto error_io;
}
if (fcntl(link->serial.fd, F_SETFL, 0) < 0) {
goto error_io;
}
2017-11-21 00:59:27 +00:00
return link;
2017-11-21 22:24:52 +00:00
error_io:
close(link->serial.fd);
error_open:
free(link);
2017-11-21 00:59:27 +00:00
error_malloc_link:
return NULL;
}
2017-11-21 22:24:52 +00:00
static int _watch_link_close_serial(skipstone_watch_link *link) {
if (tcsetattr(link->serial.fd, TCSANOW, &link->serial.attr_old) < 0) {
goto error_io;
}
return close(link->serial.fd);
2017-11-21 00:59:27 +00:00
2017-11-21 22:24:52 +00:00
error_io:
return -1;
2017-11-21 00:59:27 +00:00
}
2017-11-21 22:24:52 +00:00
int skipstone_watch_link_close(skipstone_watch_link *link) {
switch (link->type) {
case SKIPSTONE_WATCH_LINK_SERIAL: {
return _watch_link_close_serial(link);
}
2017-11-21 00:59:27 +00:00
2017-11-21 22:24:52 +00:00
default: break;
}
return -1;
2017-11-21 00:59:27 +00:00
}
2017-11-21 22:24:52 +00:00
int skipstone_send(skipstone_watch_link *link, void *buf, uint16_t size, uint16_t endpoint) {
skipstone_message_header header;
if (size > SKIPSTONE_MESSAGE_MAX_PAYLOAD) {
goto error_toobig;
}
header.size = htobe16(size);
header.endpoint = htobe16(endpoint);
if (write(link->serial.fd, &header, sizeof(header)) < 0) {
goto error_io;
}
if (write(link->serial.fd, buf, (size_t)size) < 0) {
goto error_io;
}
return 0;
error_io:
error_toobig:
return -1;
}
int skipstone_recv(skipstone_watch_link *link, void *buf, uint16_t *size, uint16_t *endpoint) {
skipstone_message_header header;
while (1) {
ssize_t len_read;
size_t len_wanted, offset = 0;
if (read(link->serial.fd, &header, sizeof(header)) < 0) {
goto error_io;
}
len_wanted = (size_t)be16toh(header.size);
if (len_wanted > SKIPSTONE_MESSAGE_MAX_PAYLOAD) {
goto error_io;
}
while (len_wanted) {
if ((len_read = read(link->serial.fd, (uint8_t *)buf + offset, len_wanted)) < 0) {
goto error_io;
}
len_wanted -= len_read;
offset += len_read;
}
*size = be16toh(header.size);
*endpoint = be16toh(header.endpoint);
return 0;
}
2017-11-21 00:59:27 +00:00
2017-11-21 22:24:52 +00:00
error_io:
return -1;
2017-11-21 00:59:27 +00:00
}