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;
|
|
|
|
|
2017-11-21 23:30:25 +00:00
|
|
|
ssize_t wrlen;
|
|
|
|
|
|
|
|
size_t remaining = (size_t)size,
|
|
|
|
offset = 0;
|
|
|
|
|
2017-11-21 22:24:52 +00:00
|
|
|
if (size > SKIPSTONE_MESSAGE_MAX_PAYLOAD) {
|
|
|
|
goto error_toobig;
|
|
|
|
}
|
|
|
|
|
|
|
|
header.size = htobe16(size);
|
|
|
|
header.endpoint = htobe16(endpoint);
|
|
|
|
|
2017-11-21 23:30:25 +00:00
|
|
|
if ((wrlen = write(link->serial.fd, &header, sizeof(header))) < 0) {
|
2017-11-21 22:24:52 +00:00
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
2017-11-21 23:30:25 +00:00
|
|
|
while (remaining) {
|
|
|
|
if ((wrlen = write(link->serial.fd, (uint8_t *)buf + offset, remaining)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
remaining -= (size_t)wrlen;
|
|
|
|
offset += (size_t)wrlen;
|
2017-11-21 22:24:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|