aboutsummaryrefslogtreecommitdiff
path: root/src/net/posix
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2022-09-27 17:03:06 +0200
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2022-11-01 16:26:16 +0100
commit980858186149651df5543b6fc99a4f7db0cdd089 (patch)
treed347200b0a562d84df505097651ad0642f207fdd /src/net/posix
parent39f50e601d395bbd2d78d0147ac530b756da2fff (diff)
downloadjancity-980858186149651df5543b6fc99a4f7db0cdd089.tar.gz
WIP
Diffstat (limited to 'src/net/posix')
-rw-r--r--src/net/posix/src/serial.c276
1 files changed, 263 insertions, 13 deletions
diff --git a/src/net/posix/src/serial.c b/src/net/posix/src/serial.c
index b0357b9..852fa0b 100644
--- a/src/net/posix/src/serial.c
+++ b/src/net/posix/src/serial.c
@@ -1,40 +1,290 @@
#include <net.h>
#include <net/serial.h>
#include <net_private.h>
+#include <transport.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <errno.h>
#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
-int net_read_serial(struct net_socket_domain *const h, void *const buf,
- const size_t n)
+/* Based on https://en.wikibooks.org/wiki/Serial_Programming/termios */
+
+struct net_host_domain
{
- return -1;
+ int fd;
+ enum net_role role;
+ struct transport_handle h;
+ struct net_event ev;
+};
+
+int net_write_serial(struct net_host_domain *const h, const net_peer p,
+ const void *const buf, const size_t n)
+{
+ return transport_send(&h->h, buf, n);
}
-int net_write_serial(struct net_socket_domain *const h, const void *const buf,
- const size_t n)
+int net_close_serial(struct net_host_domain *const h)
{
- return -1;
+ if (h && h->fd >= 0)
+ close(h->fd);
+
+ free(h);
+ return 0;
}
-int net_close_serial(struct net_socket_domain *const h)
+int net_update_serial(struct net_host_domain *const h)
{
- return -1;
+ return transport_update(&h->h);
+}
+
+static void on_received(const struct transport_event *const ev,
+ void *const arg)
+{
+ struct net_host_domain *const h = arg;
+
+ net_serial_on_received(ev, &h->ev);
+}
+
+static int on_read(void *const buf, const size_t n, void *const arg)
+{
+ struct net_host_domain *const h = arg;
+ const ssize_t res = read(h->fd, buf, n);
+
+ if (res < 0)
+ switch (errno)
+ {
+ case EAGAIN:
+ /* Fall through. */
+ case EINTR:
+ return 0;
+
+ default:
+ return -1;
+ }
+
+ return res;
+}
+
+static int on_write(const void *const buf, const size_t n, void *const arg)
+{
+ struct net_host_domain *const h = arg;
+ const ssize_t res = write(h->fd, buf, n);
+
+ if (res < 0)
+ switch (errno)
+ {
+ case EAGAIN:
+ /* Fall through. */
+ case EINTR:
+ return 0;
+
+ default:
+ return -1;
+ }
+
+ return res;
}
-int net_update_serial(struct net_socket_domain *const h)
+static struct transport_cfg get_transport_cfg(void *const arg)
{
+ return (const struct transport_cfg)
+ {
+ .arg = arg,
+ .received = on_received,
+ .read = on_read,
+ .write = on_write
+ };
+}
+
+static int open_dev(const char *const dev)
+{
+ return open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
+}
+
+static int get_speed(const unsigned long baud, speed_t *const out_s)
+{
+#define BAUD(x) {.baud = x, .s = B##x}
+
+ static const struct speed
+ {
+ unsigned long baud;
+ speed_t s;
+ } speeds[] =
+ {
+ BAUD(19200),
+ BAUD(38400),
+ BAUD(57600),
+ BAUD(115200)
+ };
+
+#undef BAUD
+
+ for (size_t i = 0; i < sizeof speeds / sizeof *speeds; i++)
+ {
+ const struct speed *const s = &speeds[i];
+
+ if (baud == s->baud)
+ {
+ *out_s = s->s;
+ return 0;
+ }
+ }
+
return -1;
}
-struct net_socket_domain *net_connect_serial(const union net_connect *const srv)
+static int config_fd(const int fd, const unsigned long baud)
+{
+ struct termios t;
+ int ret = -1;
+
+ if (tcgetattr(fd, &t))
+ {
+ fprintf(stderr, "%s: tcgetattr(3) failed: %s\n", __func__,
+ strerror(errno));
+ goto end;
+ }
+
+ /* cfmakeraw(3) is non-portable, but its man page states the
+ * following attributes are set. */
+ t.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
+ | INLCR | IGNCR | ICRNL | IXON);
+ t.c_oflag &= ~OPOST;
+ t.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ t.c_cflag &= ~(CSIZE | PARENB);
+ t.c_cflag |= CS8;
+
+ /* Make read(2) immediately regardless how many data is available. */
+ t.c_cc[VMIN] = 0;
+ t.c_cc[VTIME] = 0;
+
+ speed_t s;
+
+ if (get_speed(baud, &s))
+ {
+ fprintf(stderr, "%s: get_speed failed\n", __func__);
+ goto end;
+ }
+ else if (cfsetispeed(&t, s))
+ {
+ fprintf(stderr, "%s: cfsetispeed(3) failed: %s\n", __func__,
+ strerror(errno));
+ goto end;
+ }
+ else if (cfsetospeed(&t, s))
+ {
+ fprintf(stderr, "%s: cfsetospeed(3) failed: %s\n", __func__,
+ strerror(errno));
+ goto end;
+ }
+ else if (tcsetattr(fd, TCSANOW, &t))
+ {
+ fprintf(stderr, "%s: tcsetattr(3) failed: %s\n", __func__,
+ strerror(errno));
+ goto end;
+ }
+
+ ret = 0;
+
+end:
+ return ret;
+}
+
+struct net_host_domain *net_connect_serial(const union net_connect *const c)
{
+ struct net_host_domain *const h = malloc(sizeof *h);
+ const struct net_serial_cfg *const cfg = &c->serial.cfg;
+
+ if (!h)
+ goto failure;
+
+ *h = (const struct net_host_domain)
+ {
+ .role = NET_ROLE_CLIENT,
+ .fd = open_dev(cfg->dev),
+ .h =
+ {
+ .cfg = get_transport_cfg(h)
+ }
+ };
+
+ if (h->fd < 0)
+ {
+ fprintf(stderr, "%s: open(2) failed: %s\n", __func__,
+ strerror(errno));
+ goto failure;
+ }
+ else if (config_fd(h->fd, cfg->baud))
+ {
+ fprintf(stderr, "%s: config_gf failed\n", __func__);
+ goto failure;
+ }
+ else if (transport_connect(&h->h))
+ {
+ fprintf(stderr, "%s: transport_connect failed\n", __func__);
+ goto failure;
+ }
+
+ return h;
+
+failure:
+ net_close_serial(h);
return NULL;
}
-struct net_socket_domain *net_server_serial(const union net_server *const srv)
+int net_set_event_serial(struct net_host_domain *const h,
+ const struct net_event *const ev)
+{
+ h->ev = *ev;
+ return 0;
+}
+
+struct net_host_domain *net_server_serial(const union net_server *const s)
{
+ struct net_host_domain *const h = malloc(sizeof *h);
+ const struct net_serial_cfg *const cfg = &s->serial.cfg;
+
+ if (!h)
+ goto failure;
+
+ *h = (const struct net_host_domain)
+ {
+ .role = NET_ROLE_SERVER,
+ .fd = open_dev(cfg->dev),
+ .h =
+ {
+ .cfg = get_transport_cfg(h)
+ }
+ };
+
+ if (h->fd < 0)
+ {
+ fprintf(stderr, "%s: open(2) failed: %s\n", __func__,
+ strerror(errno));
+ goto failure;
+ }
+ else if (config_fd(h->fd, cfg->baud))
+ {
+ fprintf(stderr, "%s: config_gf failed\n", __func__);
+ goto failure;
+ }
+
+ return h;
+
+failure:
+ net_close_serial(h);
return NULL;
}
+enum net_role net_role_serial(const struct net_host_domain *const h)
+{
+ return h->role;
+}
+
int net_init_serial(void)
{
return 0;
@@ -44,7 +294,7 @@ void net_deinit_serial(void)
{
}
-const char *const *net_serial_devices(size_t *const n)
+bool net_serial_unique(void)
{
- return NULL;
+ return false;
}