Well, this is really starting to work
This commit is contained in:
parent
5302ea3190
commit
00180393ae
10 changed files with 566 additions and 35 deletions
11
Makefile
Normal file
11
Makefile
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
all:
|
||||||
|
$(MAKE) -C src all
|
||||||
|
$(MAKE) -C examples all
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(MAKE) -C src install
|
||||||
|
$(MAKE) -C examples install
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C src clean
|
||||||
|
$(MAKE) -C examples clean
|
100
configure
vendored
Executable file
100
configure
vendored
Executable file
|
@ -0,0 +1,100 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
OS=`uname -s`
|
||||||
|
DEBUG=0
|
||||||
|
|
||||||
|
create_linux_config_h() {
|
||||||
|
cat <<EOF > src/config.h
|
||||||
|
#ifndef _CONFIG_H
|
||||||
|
#define _CONFIG_H
|
||||||
|
#include <endian.h>
|
||||||
|
#endif /* _CONFIG_H */
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
create_darwin_config_h() {
|
||||||
|
cat <<EOF > src/config.h
|
||||||
|
#ifndef _CONFIG_H
|
||||||
|
#define _CONFIG_H
|
||||||
|
#include <architecture/byte_order.h>
|
||||||
|
|
||||||
|
#ifdef __LITTLE_ENDIAN__
|
||||||
|
#define __DO_SWAP_BYTES
|
||||||
|
#endif /* _DO_SWAP_BYTES */
|
||||||
|
#endif /* _CONFIG_H */
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
create_common_build_mk() {
|
||||||
|
if [ "$DEBUG" = 1 ]; then
|
||||||
|
cat <<'EOF' > mk/build.mk
|
||||||
|
CGFLAGS = -g -fno-inline
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat <<'EOF' > mk/build.mk
|
||||||
|
CGFLAGS =
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<'EOF' >> mk/build.mk
|
||||||
|
CWFLAGS = -Wall
|
||||||
|
COFLAGS = -O2
|
||||||
|
CFLAGS = $(CGFLAGS) $(CWFLAGS) $(COFLAGS)
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
create_linux_build_mk() {
|
||||||
|
create_common_build_mk $@
|
||||||
|
|
||||||
|
cat <<'EOF' >> mk/build.mk
|
||||||
|
LLFLAGS = -shared -Wl,-soname=$(SONAME)
|
||||||
|
|
||||||
|
STATIC = lib$(LIBNAME).a
|
||||||
|
|
||||||
|
SONAME_SHORT = lib$(LIBNAME).so
|
||||||
|
SONAME = $(SONAME_SHORT).$(VERSION_MAJOR)
|
||||||
|
SONAME_FULL = $(SONAME_SHORT).$(VERSION)
|
||||||
|
|
||||||
|
PREFIX = /usr/local
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
create_darwin_build_mk() {
|
||||||
|
create_common_build_mk $@
|
||||||
|
|
||||||
|
cat <<'EOF' >> mk/build.mk
|
||||||
|
LLFLAGS = -dynamiclib -current_version $(VERSION)
|
||||||
|
|
||||||
|
STATIC = lib$(LIBNAME).a
|
||||||
|
|
||||||
|
SONAME_SHORT = lib$(LIBNAME).dylib
|
||||||
|
SONAME = lib$(LIBNAME).$(VERSION_MAJOR).dylib
|
||||||
|
SONAME_FULL = lib$(LIBNAME).$(VERSION).dylib
|
||||||
|
|
||||||
|
PREFIX = /usr/local
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
for arg in $@; do
|
||||||
|
case $arg in
|
||||||
|
"--enable-debug")
|
||||||
|
DEBUG=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! -d "mk" ]; then
|
||||||
|
mkdir -m 0755 mk
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $OS in
|
||||||
|
Linux)
|
||||||
|
create_linux_config_h
|
||||||
|
create_linux_build_mk
|
||||||
|
;;
|
||||||
|
|
||||||
|
Darwin)
|
||||||
|
create_darwin_config_h
|
||||||
|
create_darwin_build_mk
|
||||||
|
;;
|
||||||
|
esac
|
20
examples/Makefile
Normal file
20
examples/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
include ../mk/build.mk
|
||||||
|
|
||||||
|
CC = $(CROSS)cc
|
||||||
|
|
||||||
|
INCLUDE_PATH = ../include
|
||||||
|
|
||||||
|
CFLAGS += -I$(INCLUDE_PATH)
|
||||||
|
LDFLAGS = -L../src -lskipstone
|
||||||
|
|
||||||
|
EXAMPLES = read
|
||||||
|
|
||||||
|
RM = /bin/rm
|
||||||
|
|
||||||
|
all: $(EXAMPLES)
|
||||||
|
|
||||||
|
$(EXAMPLES): %: %.c $(STATICLIB)
|
||||||
|
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $(EXAMPLES)
|
45
examples/read.c
Normal file
45
examples/read.c
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <skipstone/skipstone.h>
|
||||||
|
|
||||||
|
static void usage(int argc, char **argv) {
|
||||||
|
fprintf(stderr, "usage: %s /dev/rfcommX\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
skipstone_watch_link *link;
|
||||||
|
void *buf;
|
||||||
|
uint16_t len, endpoint;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
usage(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf = malloc(SKIPSTONE_MESSAGE_MAX_PAYLOAD)) == NULL) {
|
||||||
|
goto error_malloc_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((link = skipstone_watch_link_open_serial(argv[1])) == NULL) {
|
||||||
|
goto error_watch_link_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (skipstone_recv(link, buf, &len, &endpoint) >= 0) {
|
||||||
|
printf("Received message %hu bytes for endpoint %hu\n",
|
||||||
|
len, endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
perror("skipstone_recv()");
|
||||||
|
|
||||||
|
skipstone_watch_link_close(link);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_watch_link_open:
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
error_malloc_buf:
|
||||||
|
return 1;
|
||||||
|
}
|
45
examples/read.c-e
Normal file
45
examples/read.c-e
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <skipstone/skipstone.h>
|
||||||
|
|
||||||
|
static void usage(int argc, char **argv) {
|
||||||
|
fprintf(stderr, "usage: %s /dev/rfcommX\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
skipstone_watch_link *link;
|
||||||
|
void *buf;
|
||||||
|
uint16_t len, endpoint;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
usage(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf = malloc(SKIPSTONE_MESSAGE_MAX_PAYLOAD)) == NULL) {
|
||||||
|
goto error_malloc_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((link = skipstone_watch_link_open_serial(argv[1])) == NULL) {
|
||||||
|
goto error_watch_link_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (skipstone_recv(link, buf, &len, &endpoint) >= 0) {
|
||||||
|
printf("Received message %hu bytes for endpoint %hu\n",
|
||||||
|
len, endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
perror("skipstone_recv()");
|
||||||
|
|
||||||
|
skipstone_watch_link_close(link);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_watch_link_open:
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
error_malloc_buf:
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
#ifndef _SKIPSTONE_H
|
|
||||||
#define _SKIPSTONE_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define SKIPSTONE_MESSAGE_MAX_PAYLOAD 4096
|
|
||||||
|
|
||||||
typedef struct _skipstone_message {
|
|
||||||
uint16_t size, endpoint;
|
|
||||||
} skipstone_message;
|
|
||||||
|
|
||||||
typedef struct _skipstone_watch_link skipstone_watch_link;
|
|
||||||
|
|
||||||
skipstone_watch_link *skipstone_watch_link_open_serial(const char *device);
|
|
||||||
|
|
||||||
void skipstone_watch_close(skipstone_watch_link *link);
|
|
||||||
|
|
||||||
int16_t skipstone_send(skipstone_watch_link *link, void *buf, uint16_t size);
|
|
||||||
|
|
||||||
int16_t skipstone_recv(skipstone_watch_link *link, void *buf, uint16_t size);
|
|
||||||
|
|
||||||
#endif /* _SKIPSTONE_H */
|
|
31
include/skipstone/skipstone.h
Normal file
31
include/skipstone/skipstone.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef _SKIPSTONE_H
|
||||||
|
#define _SKIPSTONE_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define SKIPSTONE_MESSAGE_MAX_PAYLOAD 4096
|
||||||
|
|
||||||
|
enum skipstone_message_endpoint {
|
||||||
|
SKIPSTONE_MESSAGE_ENDPOINT_NONE = 0,
|
||||||
|
SKIPSTONE_MESSAGE_ENDPOINT_FIRMWARE = 1,
|
||||||
|
SKIPSTONE_MESSAGE_ENDPOINT_TIME = 11,
|
||||||
|
SKIPSTONE_MESSAGE_ENDPOINT_VERSIONS = 16,
|
||||||
|
SKIPSTONE_MESSAGE_ENDPOINT_PHONE_VERSION = 17,
|
||||||
|
SKIPSTONE_MESSAGE_ENDPOINT_SYSTEM_MESSAGE = 18,
|
||||||
|
SKIPSTONE_MESSAGE_ENDPOINT_MUSIC_CONTROL = 32,
|
||||||
|
SKIPSTONE_MESSAGE_ENDPOINT_PHONE_CONTROL = 33,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _skipstone_watch_link skipstone_watch_link;
|
||||||
|
|
||||||
|
skipstone_watch_link *skipstone_watch_link_open_serial(const char *device);
|
||||||
|
|
||||||
|
int skipstone_watch_link_close(skipstone_watch_link *link);
|
||||||
|
|
||||||
|
int skipstone_send(skipstone_watch_link *link, void *buf, uint16_t size, uint16_t endpoint);
|
||||||
|
|
||||||
|
int skipstone_recv(skipstone_watch_link *link, void *buf, uint16_t *size, uint16_t *endpoint);
|
||||||
|
|
||||||
|
#endif /* _SKIPSTONE_H */
|
58
src/Makefile
Normal file
58
src/Makefile
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
include ../mk/build.mk
|
||||||
|
|
||||||
|
INCLUDE_PATH = ../include
|
||||||
|
HEADER_SUBDIR = skipstone
|
||||||
|
|
||||||
|
CC = $(CROSS)cc
|
||||||
|
CFLAGS += -fPIC -I$(INCLUDE_PATH)
|
||||||
|
LDFLAGS =
|
||||||
|
|
||||||
|
HEADERS = skipstone.h
|
||||||
|
|
||||||
|
OBJS = skipstone.o
|
||||||
|
|
||||||
|
VERSION_MAJOR = 0
|
||||||
|
VERSION_MINOR = 0.1
|
||||||
|
VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
|
||||||
|
|
||||||
|
LIBNAME = skipstone
|
||||||
|
|
||||||
|
HEADERS_BUILD = $(addprefix $(INCLUDE_PATH)/$(HEADER_SUBDIR)/, $(HEADERS))
|
||||||
|
|
||||||
|
AR = $(CROSS)ar
|
||||||
|
RANLIB = $(CROSS)ranlib
|
||||||
|
|
||||||
|
RM = /bin/rm
|
||||||
|
LN = /bin/ln
|
||||||
|
RMDIR = /bin/rmdir
|
||||||
|
INSTALL = /usr/bin/install
|
||||||
|
|
||||||
|
all: $(STATIC) $(SONAME_FULL) $(SONAME) $(SONAME_SHORT)
|
||||||
|
|
||||||
|
$(STATIC): $(OBJS)
|
||||||
|
$(AR) rc $(STATIC) $(OBJS)
|
||||||
|
$(RANLIB) $(STATIC)
|
||||||
|
|
||||||
|
$(SONAME_FULL): $(OBJS)
|
||||||
|
$(CC) $(LLFLAGS) $(OBJS) $(LDFLAGS) -o $(SONAME_FULL)
|
||||||
|
|
||||||
|
$(SONAME): $(SONAME_FULL)
|
||||||
|
$(LN) -s $< $@
|
||||||
|
|
||||||
|
$(SONAME_SHORT): $(SONAME_FULL)
|
||||||
|
$(LN) -s $< $@
|
||||||
|
|
||||||
|
$(OBJS): %.o: %.c $(HEADERS_BUILD)
|
||||||
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
|
install: $(SONAME_FULL) $(STATIC)
|
||||||
|
$(INSTALL) -d -m 0755 $(PREFIX)/lib
|
||||||
|
$(INSTALL) -c -m 0644 $(STATIC) $(PREFIX)/lib
|
||||||
|
$(INSTALL) -c -m 0755 $(SONAME_FULL) $(PREFIX)/lib
|
||||||
|
$(LN) -s -f $(SONAME_FULL) $(PREFIX)/lib/$(SONAME)
|
||||||
|
$(LN) -s -f $(SONAME_FULL) $(PREFIX)/lib/$(SONAME_SHORT)
|
||||||
|
$(INSTALL) -d -m 0755 $(PREFIX)/include/$(HEADER_SUBDIR)
|
||||||
|
$(INSTALL) -c -m 0644 $(HEADERS_BUILD) $(PREFIX)/include/$(HEADER_SUBDIR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $(SONAME_SHORT) $(SONAME) $(SONAME_FULL) $(STATIC) $(OBJS)
|
138
src/skipstone.c
138
src/skipstone.c
|
@ -1,19 +1,36 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <endian.h>
|
||||||
|
|
||||||
#include <skipstone.h>
|
#include <skipstone/skipstone.h>
|
||||||
|
|
||||||
enum skipstone_watch_link_type {
|
enum skipstone_watch_link_type {
|
||||||
SKIPSTONE_WATCH_LINK_SERIAL = 1
|
SKIPSTONE_WATCH_LINK_SERIAL = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _skipstone_watch_link {
|
struct _skipstone_watch_link {
|
||||||
enum skipstone_watch_link_type link_type;
|
enum skipstone_watch_link_type type;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
int serial_fd;
|
struct {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
struct termios attr_old,
|
||||||
|
attr_new;
|
||||||
|
} serial;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _skipstone_message_header {
|
||||||
|
uint16_t size,
|
||||||
|
endpoint;
|
||||||
|
} skipstone_message_header;
|
||||||
|
|
||||||
skipstone_watch_link *skipstone_watch_link_open_serial(const char *device) {
|
skipstone_watch_link *skipstone_watch_link_open_serial(const char *device) {
|
||||||
skipstone_watch_link *link;
|
skipstone_watch_link *link;
|
||||||
|
|
||||||
|
@ -21,22 +38,127 @@ skipstone_watch_link *skipstone_watch_link_open_serial(const char *device) {
|
||||||
goto error_malloc_link;
|
goto error_malloc_link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
return link;
|
return link;
|
||||||
|
|
||||||
|
error_io:
|
||||||
|
close(link->serial.fd);
|
||||||
|
|
||||||
|
error_open:
|
||||||
|
free(link);
|
||||||
|
|
||||||
error_malloc_link:
|
error_malloc_link:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void skipstone_watch_close(skipstone_watch_link *link) {
|
static int _watch_link_close_serial(skipstone_watch_link *link) {
|
||||||
|
if (tcsetattr(link->serial.fd, TCSANOW, &link->serial.attr_old) < 0) {
|
||||||
|
goto error_io;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t skipstone_send(skipstone_watch_link *link, void *buf, uint16_t size) {
|
return close(link->serial.fd);
|
||||||
|
|
||||||
|
error_io:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t skipstone_recv(skipstone_watch_link *link, void *buf, uint16_t size) {
|
int skipstone_watch_link_close(skipstone_watch_link *link) {
|
||||||
|
switch (link->type) {
|
||||||
|
case SKIPSTONE_WATCH_LINK_SERIAL: {
|
||||||
|
return _watch_link_close_serial(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_io:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,36 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <endian.h>
|
||||||
|
|
||||||
#include <skipstone.h>
|
#include <skipstone/skipstone.h>
|
||||||
|
|
||||||
enum skipstone_watch_link_type {
|
enum skipstone_watch_link_type {
|
||||||
SKIPSTONE_WATCH_LINK_SERIAL = 1
|
SKIPSTONE_WATCH_LINK_SERIAL = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _skipstone_watch_link {
|
struct _skipstone_watch_link {
|
||||||
enum skipstone_watch_link_type link_type;
|
enum skipstone_watch_link_type type;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
int serial_fd;
|
struct {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
struct termios attr_old,
|
||||||
|
attr_new;
|
||||||
|
} serial;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _skipstone_message_header {
|
||||||
|
uint16_t size,
|
||||||
|
endpoint;
|
||||||
|
} skipstone_message_header;
|
||||||
|
|
||||||
skipstone_watch_link *skipstone_watch_link_open_serial(const char *device) {
|
skipstone_watch_link *skipstone_watch_link_open_serial(const char *device) {
|
||||||
skipstone_watch_link *link;
|
skipstone_watch_link *link;
|
||||||
|
|
||||||
|
@ -21,22 +38,127 @@ skipstone_watch_link *skipstone_watch_link_open_serial(const char *device) {
|
||||||
goto error_malloc_link;
|
goto error_malloc_link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
return link;
|
return link;
|
||||||
|
|
||||||
|
error_io:
|
||||||
|
close(link->serial.fd);
|
||||||
|
|
||||||
|
error_open:
|
||||||
|
free(link);
|
||||||
|
|
||||||
error_malloc_link:
|
error_malloc_link:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void skipstone_watch_close(skipstone_watch_link *link) {
|
static int _watch_link_close_serial(skipstone_watch_link *link) {
|
||||||
|
if (tcsetattr(link->serial.fd, TCSANOW, &link->serial.attr_old) < 0) {
|
||||||
|
goto error_io;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t skipstone_send(skipstone_watch_link *link, void *buf, uint16_t size) {
|
return close(link->serial.fd);
|
||||||
|
|
||||||
|
error_io:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t skipstone_recv(skipstone_watch_link *link, void *buf, uint16_t size) {
|
int skipstone_watch_link_close(skipstone_watch_link *link) {
|
||||||
|
switch (link->type) {
|
||||||
|
case SKIPSTONE_WATCH_LINK_SERIAL: {
|
||||||
|
return _watch_link_close_serial(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_io:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue