Change in ...osmo-ccid-firmware[master]: 'cuart' Card-UART abstraction + driver for simple serial reader

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

laforge gerrit-no-reply at lists.osmocom.org
Mon Oct 7 21:35:24 UTC 2019


laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/15691


Change subject: 'cuart' Card-UART abstraction + driver for simple serial reader
......................................................................

'cuart' Card-UART abstraction + driver for simple serial reader

Change-Id: Ic7e324d99f78b3bfb98fc667d9a1b7fa363f092d
---
M ccid/Makefile
A ccid/cuart.c
A ccid/cuart.h
A ccid/cuart_driver_tty.c
A ccid/cuart_test.c
A ccid/utils_ringbuffer.c
A ccid/utils_ringbuffer.h
7 files changed, 833 insertions(+), 1 deletion(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/91/15691/1

diff --git a/ccid/Makefile b/ccid/Makefile
index 5f784ba..a0d6952 100644
--- a/ccid/Makefile
+++ b/ccid/Makefile
@@ -1,13 +1,18 @@
 CFLAGS=-Wall -g
 
+all: ccid_functionfs hub_functionfs cuart_test
+
 ccid_functionfs: ccid_main_functionfs.o logging.o ccid_proto.o ccid_device.o ccid_slot_sim.o
 	$(CC) $(CFLAGS) -o $@ $^ -lasan -losmocore -ltalloc -laio
 
 hub_functionfs: hub_main_functionfs.o
 	$(CC) $(CFLAGS) -o $@ $^ -lasan -losmocore -ltalloc -laio
 
+cuart_test: cuart_test.o cuart.o cuart_driver_tty.o utils_ringbuffer.o
+	$(CC) $(CFLAGS) -o $@ $^ -lasan -losmocore -ltalloc
+
 %.o: %.c
 	$(CC) $(CFLAGS) -o $@ -c $^
 
 clean:
-	rm ccid_functionfs *.o
+	rm ccid_functionfs hub_functionfs cuart_test *.o
diff --git a/ccid/cuart.c b/ccid/cuart.c
new file mode 100644
index 0000000..2c0428e
--- /dev/null
+++ b/ccid/cuart.c
@@ -0,0 +1,133 @@
+#include <errno.h>
+#include <string.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/utils.h>
+
+#include "cuart.h"
+
+static LLIST_HEAD(g_cuart_drivers);
+
+const struct value_string card_uart_event_vals[] = {
+	OSMO_VALUE_STRING(CUART_E_RX_SINGLE),
+	OSMO_VALUE_STRING(CUART_E_RX_COMPLETE),
+	OSMO_VALUE_STRING(CUART_E_RX_TIMEOUT),
+	OSMO_VALUE_STRING(CUART_E_TX_COMPLETE),
+	{ 0, NULL }
+};
+
+static struct card_uart_driver *cuart_drv_by_name(const char *driver_name)
+{
+	struct card_uart_driver *drv;
+	llist_for_each_entry(drv, &g_cuart_drivers, list) {
+		if (!strcmp(drv->name, driver_name))
+			return drv;
+	}
+	return NULL;
+}
+
+int card_uart_open(struct card_uart *cuart, const char *driver_name, const char *device_name)
+{
+	struct card_uart_driver *drv = cuart_drv_by_name(driver_name);
+	int rc;
+
+	if (!drv)
+		return -ENODEV;
+
+	cuart->rx_enabled = true;
+	cuart->rx_threshold = 1;
+
+	rc = drv->ops->open(cuart, device_name);
+	if (rc < 0)
+		return rc;
+
+	cuart->driver = drv;
+	return 0;
+}
+
+int card_uart_close(struct card_uart *cuart)
+{
+	OSMO_ASSERT(cuart);
+	OSMO_ASSERT(cuart->driver);
+	OSMO_ASSERT(cuart->driver->ops);
+	OSMO_ASSERT(cuart->driver->ops->close);
+	return cuart->driver->ops->close(cuart);
+}
+
+int card_uart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, bool enable)
+{
+	int rc;
+	OSMO_ASSERT(cuart);
+	OSMO_ASSERT(cuart->driver);
+	OSMO_ASSERT(cuart->driver->ops);
+	OSMO_ASSERT(cuart->driver->ops->ctrl);
+	rc = cuart->driver->ops->ctrl(cuart, ctl, enable);
+	if (rc < 0)
+		return rc;
+
+	switch (ctl) {
+	case CUART_CTL_RX:
+		cuart->rx_enabled = enable;
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+int card_uart_tx(struct card_uart *cuart, const uint8_t *data, size_t len, bool rx_after_complete)
+{
+	OSMO_ASSERT(cuart);
+	OSMO_ASSERT(cuart->driver);
+	OSMO_ASSERT(cuart->driver->ops);
+	OSMO_ASSERT(cuart->driver->ops->async_tx);
+
+	OSMO_ASSERT(!cuart->tx_busy);
+	cuart->tx_busy = true;
+	/* disable receiver to avoid receiving what we transmit */
+	card_uart_ctrl(cuart, CUART_CTL_RX, false);
+
+	return cuart->driver->ops->async_tx(cuart, data, len, rx_after_complete);
+}
+
+int card_uart_rx(struct card_uart *cuart, uint8_t *data, size_t len)
+{
+	OSMO_ASSERT(cuart);
+	OSMO_ASSERT(cuart->driver);
+	OSMO_ASSERT(cuart->driver->ops);
+	OSMO_ASSERT(cuart->driver->ops->async_rx);
+	return cuart->driver->ops->async_rx(cuart, data, len);
+}
+
+void card_uart_set_rx_threshold(struct card_uart *cuart, size_t rx_threshold)
+{
+	cuart->rx_threshold = rx_threshold;
+}
+
+void card_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data)
+{
+	OSMO_ASSERT(cuart);
+	OSMO_ASSERT(cuart->handle_event);
+
+	switch (evt) {
+	case CUART_E_TX_COMPLETE:
+		cuart->tx_busy = false;
+		/* re-enable receiver if we're done with transmit */
+		sleep(1);
+		card_uart_ctrl(cuart, CUART_CTL_RX, true);
+		break;
+	default:
+		break;
+	}
+
+	cuart->handle_event(cuart, evt, data);
+}
+
+int card_uart_driver_register(struct card_uart_driver *drv)
+{
+	OSMO_ASSERT(!cuart_drv_by_name(drv->name));
+	OSMO_ASSERT(drv->name);
+	OSMO_ASSERT(drv->ops);
+	llist_add_tail(&drv->list, &g_cuart_drivers);
+	return 0;
+}
diff --git a/ccid/cuart.h b/ccid/cuart.h
new file mode 100644
index 0000000..7e217db
--- /dev/null
+++ b/ccid/cuart.h
@@ -0,0 +1,107 @@
+#pragma once
+#include <stdint.h>
+#include <stdbool.h>
+#include <osmocom/core/linuxlist.h>
+
+#include <osmocom/core/select.h>
+#include "utils_ringbuffer.h"
+
+enum card_uart_event {
+	/* a single byte was received, it's present at the (uint8_t *) data location */
+	CUART_E_RX_SINGLE,
+	/* an entire block of data was received */
+	CUART_E_RX_COMPLETE,
+	CUART_E_RX_TIMEOUT,
+	/* an entire block of data was written, as instructed in prior card_uart_tx() call */
+	CUART_E_TX_COMPLETE,
+};
+
+extern const struct value_string card_uart_event_vals[];
+
+enum card_uart_ctl {
+	CUART_CTL_RX,
+	CUART_CTL_POWER,
+	CUART_CTL_CLOCK,
+	CUART_CTL_RST,
+};
+
+struct card_uart;
+
+struct card_uart_ops {
+	int (*open)(struct card_uart *cuart, const char *device_name);
+	int (*close)(struct card_uart *cuart);
+	int (*async_tx)(struct card_uart *cuart, const uint8_t *data, size_t len, bool rx_after_complete);
+	int (*async_rx)(struct card_uart *cuart, uint8_t *data, size_t len);
+
+	int (*ctrl)(struct card_uart *cuart, enum card_uart_ctl ctl, bool enable);
+};
+
+/* Card UART driver */
+struct card_uart_driver {
+	/* global list of card UART drivers */
+	struct llist_head list;
+	/* human-readable name of driver */
+	const char *name;
+	/* operations implementing the driver */
+	const struct card_uart_ops *ops;
+};
+
+struct card_uart {
+	/* member in global list of UARTs */
+	struct llist_head list;
+	/* driver serving this UART */
+	const struct card_uart_driver *driver;
+	/* event-handler function */
+	void (*handle_event)(struct card_uart *cuart, enum card_uart_event evt, void *data);
+	/* opaque pointer for user */
+	void *priv;
+
+	/* is the transmitter currently busy (true) or not (false)? */
+	bool tx_busy;
+	/* is the receiver currently enabled or not? */
+	bool rx_enabled;
+
+	/*! after how many bytes should we notify the user? If this is '1', we will
+	 *  issue CUART_E_RX_SINGLE; if it is > 1, we will issue CUART_E_RX_COMPLETE */
+	uint32_t rx_threshold;
+
+	/* driver-specific private data */
+	union {
+		struct {
+			/* ringbuffer on receive side */
+			uint8_t rx_buf[256];
+			struct ringbuffer rx_ringbuf;
+
+			/* pointer to (user-allocated) transmit buffer and length */
+			const uint8_t *tx_buf;
+			size_t tx_buf_len;
+			/* index: offset of next to be transmitted byte in tx_buf */
+			size_t tx_index;
+
+			struct osmo_fd ofd;
+			unsigned int baudrate;
+		} tty;
+	} u;
+};
+
+/*! Open the Card UART */
+int card_uart_open(struct card_uart *cuart, const char *driver_name, const char *device_name);
+
+/*! Close the Card UART */
+int card_uart_close(struct card_uart *cuart);
+
+/*! Schedule (asynchronous) transmit data via UART; optionally enable Rx after completion */
+int card_uart_tx(struct card_uart *cuart, const uint8_t *data, size_t len, bool rx_after_complete);
+
+/*! Schedule (asynchronous) receive data via UART (after CUART_E_RX_COMPLETE) */
+int card_uart_rx(struct card_uart *cuart, uint8_t *data, size_t len);
+
+int card_uart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, bool enable);
+
+/*! Set the Rx notification threshold in number of bytes received */
+void card_uart_set_rx_threshold(struct card_uart *cuart, size_t rx_threshold);
+
+void card_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data);
+
+int card_uart_driver_register(struct card_uart_driver *drv);
+
diff --git a/ccid/cuart_driver_tty.c b/ccid/cuart_driver_tty.c
new file mode 100644
index 0000000..6bd2b52
--- /dev/null
+++ b/ccid/cuart_driver_tty.c
@@ -0,0 +1,287 @@
+/* Card (ICC) UART driver for simple serial readers attached to tty.
+ * This allows you to use the CCID core in Linux userspace against a serial reader */
+
+#include <unistd.h>
+#include <termios.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/serial.h>
+#include <osmocom/core/utils.h>
+
+#include "cuart.h"
+#include "utils_ringbuffer.h"
+
+/***********************************************************************
+ * low-level helper routines
+ ***********************************************************************/
+
+static int _init_uart(int fd)
+{
+	struct termios tio;
+	int rc;
+
+	rc = tcgetattr(fd, &tio);
+	if (rc < 0) {
+		perror("tcgetattr()");
+		return -EIO;
+	}
+
+	tio.c_iflag = 0;
+	tio.c_oflag = 0;
+	tio.c_lflag = 0;
+	tio.c_cflag = CREAD | CLOCAL | CSTOPB | PARENB | CS8 | B9600;
+
+	rc = tcsetattr(fd, TCSANOW, &tio);
+	if (rc < 0) {
+		perror("tcsetattr()");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void _set_dtr(int fd, bool dtr)
+{
+	int status, rc;
+
+	rc = ioctl(fd, TIOCMGET, &status);
+	OSMO_ASSERT(rc == 0);
+	if (dtr) /* set DTR */
+		status |= TIOCM_DTR;
+	else
+		status &= ~TIOCM_DTR;
+	rc = ioctl(fd, TIOCMSET, &status);
+	OSMO_ASSERT(rc == 0);
+}
+
+static void _set_rts(int fd, bool rts)
+{
+	int status, rc;
+
+	rc = ioctl(fd, TIOCMGET, &status);
+	OSMO_ASSERT(rc == 0);
+	if (rts) /* set RTS */
+		status |= TIOCM_RTS;
+	else
+		status &= ~TIOCM_RTS;
+	rc = ioctl(fd, TIOCMSET, &status);
+	OSMO_ASSERT(rc == 0);
+}
+
+static int read_timeout(int fd, uint8_t *out, size_t len, unsigned long timeout_ms)
+{
+	struct timeval tv = { .tv_sec = timeout_ms / 1000, .tv_usec = (timeout_ms % 1000) * 1000 };
+	fd_set rd_set;
+	int rc;
+
+	FD_ZERO(&rd_set);
+	FD_SET(fd, &rd_set);
+	rc = select(fd+1, &rd_set, NULL, NULL, &tv);
+	if (rc == 0)
+		return -ETIMEDOUT;
+	else if (rc < 0)
+		return rc;
+
+	return read(fd, out, len);
+}
+
+static int _flush(int fd)
+{
+#if 0
+	uint8_t buf[1];
+	int rc;
+
+	while (1) {
+		rc = read_timeout(fd, buf, sizeof(buf), 10);
+		if (rc == -ETIMEDOUT)
+			return 0;
+		else if (rc < 0)
+			return rc;
+	}
+#else
+	return tcflush(fd, TCIFLUSH);
+#endif
+}
+
+/***********************************************************************
+ * Interface with card_uart (cuart) core
+ ***********************************************************************/
+
+/* forward-declaration */
+static struct card_uart_driver tty_uart_driver;
+static int tty_uart_close(struct card_uart *cuart);
+
+static int tty_uart_fd_cb(struct osmo_fd *ofd, unsigned int what)
+{
+	struct card_uart *cuart = (struct card_uart *) ofd->data;
+	uint8_t buf[256];
+	int rc;
+
+	if (what & OSMO_FD_READ) {
+		int i;
+		/* read any pending bytes and feed them into ring buffer */
+		rc = read(ofd->fd, buf, sizeof(buf));
+		OSMO_ASSERT(rc > 0);
+		for (i = 0; i < rc; i++) {
+			/* work-around for https://bugzilla.kernel.org/show_bug.cgi?id=205033 */
+			if (!cuart->rx_enabled)
+				continue;
+
+			if (cuart->rx_threshold == 1) {
+				/* bypass ringbuffer and report byte directly */
+				card_uart_notification(cuart, CUART_E_RX_SINGLE, &buf[i]);
+			} else {
+				/* go via ringbuffer and notify only after threshold */
+				ringbuffer_put(&cuart->u.tty.rx_ringbuf, buf[i]);
+				if (ringbuffer_num(&cuart->u.tty.rx_ringbuf) >= cuart->rx_threshold)
+					card_uart_notification(cuart, CUART_E_RX_COMPLETE, NULL);
+			}
+		}
+	}
+	if (what & OSMO_FD_WRITE) {
+		unsigned int to_tx;
+		OSMO_ASSERT(cuart->u.tty.tx_buf_len > cuart->u.tty.tx_index);
+		/* push as many pending transmit bytes as possible */
+		to_tx = cuart->u.tty.tx_buf_len - cuart->u.tty.tx_index;
+		rc = write(ofd->fd, cuart->u.tty.tx_buf + cuart->u.tty.tx_index, to_tx);
+		OSMO_ASSERT(rc > 0);
+		cuart->u.tty.tx_index += rc;
+
+		/* if no more bytes to transmit, disable OSMO_FD_WRITE */
+		if (cuart->u.tty.tx_index >= cuart->u.tty.tx_buf_len) {
+			ofd->when &= ~BSC_FD_WRITE;
+			/* ensure everything is written (tx queue/fifo drained) */
+			tcdrain(cuart->u.tty.ofd.fd);
+			osmo_select_main(true);
+			cuart->tx_busy = false;
+			/* notify */
+			card_uart_notification(cuart, CUART_E_TX_COMPLETE, (void *)cuart->u.tty.tx_buf);
+		}
+	}
+	return 0;
+}
+
+static int tty_uart_open(struct card_uart *cuart, const char *device_name)
+{
+	int rc;
+
+	rc = ringbuffer_init(&cuart->u.tty.rx_ringbuf, cuart->u.tty.rx_buf, sizeof(cuart->u.tty.rx_buf));
+	if (rc < 0)
+		return rc;
+
+	cuart->u.tty.ofd.fd = -1;
+	rc = osmo_serial_init(device_name, B9600);
+	if (rc < 0)
+		return rc;
+
+	osmo_fd_setup(&cuart->u.tty.ofd, rc, BSC_FD_READ, tty_uart_fd_cb, cuart, 0);
+        cuart->u.tty.baudrate = B9600;
+
+	rc = _init_uart(cuart->u.tty.ofd.fd);
+	if (rc < 0) {
+		tty_uart_close(cuart);
+		return rc;
+	}
+
+	_flush(cuart->u.tty.ofd.fd);
+
+	osmo_fd_register(&cuart->u.tty.ofd);
+
+        return 0;
+}
+
+static int tty_uart_close(struct card_uart *cuart)
+{
+	OSMO_ASSERT(cuart->driver == &tty_uart_driver);
+	if (cuart->u.tty.ofd.fd != -1) {
+		osmo_fd_unregister(&cuart->u.tty.ofd);
+		close(cuart->u.tty.ofd.fd);
+		cuart->u.tty.ofd.fd = -1;
+	}
+	return 0;
+}
+
+static int tty_uart_async_tx(struct card_uart *cuart, const uint8_t *data, size_t len, bool rx_after)
+{
+	OSMO_ASSERT(cuart->driver == &tty_uart_driver);
+
+	cuart->u.tty.tx_buf = data;
+	cuart->u.tty.tx_buf_len = len;
+	cuart->u.tty.tx_buf_len = len;
+	cuart->tx_busy = true;
+	cuart->u.tty.ofd.when |= OSMO_FD_WRITE;
+
+	return 0;
+}
+
+static int tty_uart_async_rx(struct card_uart *cuart, uint8_t *data, size_t len)
+{
+	int rc, i;
+	OSMO_ASSERT(cuart->driver == &tty_uart_driver);
+
+	/* FIXME: actually do this asynchronously */
+	for (i = 0; i < len; i++) {
+		rc = ringbuffer_get(&cuart->u.tty.rx_ringbuf, &data[i]);
+		if (rc < 0)
+			return i;
+	}
+
+	return i;
+}
+
+static int tty_uart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, bool enable)
+{
+	struct termios tio;
+	int rc;
+
+	switch (ctl) {
+	case CUART_CTL_RX:
+		rc = tcgetattr(cuart->u.tty.ofd.fd, &tio);
+		if (rc < 0) {
+			perror("tcgetattr()");
+			return -EIO;
+		}
+		/* We do our best here, but lots of [USB] serial drivers seem to ignore
+		 * CREAD, see https://bugzilla.kernel.org/show_bug.cgi?id=205033 */
+		if (enable)
+			tio.c_cflag |= CREAD;
+		else
+			tio.c_cflag &= ~CREAD;
+		rc = tcsetattr(cuart->u.tty.ofd.fd, TCSANOW, &tio);
+		if (rc < 0) {
+			perror("tcsetattr()");
+			return -EIO;
+		}
+		break;
+	case CUART_CTL_RST:
+		_set_rts(cuart->u.tty.ofd.fd, enable);
+		if (enable)
+			_flush(cuart->u.tty.ofd.fd);
+		break;
+	case CUART_CTL_POWER:
+	case CUART_CTL_CLOCK:
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct card_uart_ops tty_uart_ops = {
+	.open = tty_uart_open,
+	.close = tty_uart_close,
+	.async_tx = tty_uart_async_tx,
+	.async_rx = tty_uart_async_rx,
+	.ctrl = tty_uart_ctrl,
+};
+
+static struct card_uart_driver tty_uart_driver = {
+	.name = "tty",
+	.ops = &tty_uart_ops,
+};
+
+static __attribute__((constructor)) void on_dso_load_cuart_tty(void)
+{
+	card_uart_driver_register(&tty_uart_driver);
+}
diff --git a/ccid/cuart_test.c b/ccid/cuart_test.c
new file mode 100644
index 0000000..aff9de7
--- /dev/null
+++ b/ccid/cuart_test.c
@@ -0,0 +1,76 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <osmocom/core/utils.h>
+
+#include "cuart.h"
+
+static struct card_uart g_cuart;
+
+
+static void handle_event(struct card_uart *cuart, enum card_uart_event evt, void *data)
+{
+	printf("Handle Event '%s'\n", get_value_string(card_uart_event_vals, evt));
+	switch (evt) {
+	case CUART_E_RX_SINGLE:
+		printf("\t%02x\n", *(uint8_t *)data);
+		break;
+	}
+
+}
+
+
+static int get_atr(uint8_t *atr, size_t max_len)
+{
+	int rc;
+	int i = 0;
+
+	card_uart_ctrl(&g_cuart, CUART_CTL_RST, true);
+	usleep(100000);
+	card_uart_ctrl(&g_cuart, CUART_CTL_RST, false);
+
+	sleep(1);
+	osmo_select_main(true);
+
+	for (i = 0; i < max_len; i++) {
+		rc = card_uart_rx(&g_cuart, &atr[i], 1);
+		if (rc <= 0)
+			break;
+	}
+
+	return i;
+}
+
+static void test_apdu(void)
+{
+	const uint8_t select_mf[] = "\xa0\xa4\x04\x00\x02\x3f\x00";
+	card_uart_tx(&g_cuart, select_mf, 5, true);
+
+	osmo_select_main(true);
+	/* we should get an RX_SINGLE event here */
+}
+
+
+int main(int argc, char **argv)
+{
+	uint8_t atr[64];
+	int rc;
+
+	g_cuart.handle_event = &handle_event;
+	rc = card_uart_open(&g_cuart, "tty", "/dev/ttyUSB5");
+	if (rc < 0) {
+		perror("opening UART");
+		exit(1);
+	}
+
+	rc = get_atr(atr, sizeof(atr));
+	if (rc < 0) {
+		perror("getting ATR");
+		exit(1);
+	}
+	printf("ATR: %s\n", osmo_hexdump(atr, rc));
+
+	test_apdu();
+
+	exit(0);
+}
diff --git a/ccid/utils_ringbuffer.c b/ccid/utils_ringbuffer.c
new file mode 100644
index 0000000..49c273c
--- /dev/null
+++ b/ccid/utils_ringbuffer.c
@@ -0,0 +1,109 @@
+/**
+ * \file
+ *
+ * \brief Ringbuffer functionality implementation.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#include <errno.h>
+#include "utils_ringbuffer.h"
+
+/**
+ * \brief Ringbuffer init
+ */
+int32_t ringbuffer_init(struct ringbuffer *const rb, void *buf, uint32_t size)
+{
+	/*
+	 * buf size must be aligned to power of 2
+	 */
+	if ((size & (size - 1)) != 0) {
+		return -EINVAL;
+	}
+
+	/* size - 1 is faster in calculation */
+	rb->size        = size - 1;
+	rb->read_index  = 0;
+	rb->write_index = rb->read_index;
+	rb->buf         = (uint8_t *)buf;
+
+	return 0;
+}
+
+/**
+ * \brief Get one byte from ringbuffer
+ *
+ */
+int32_t ringbuffer_get(struct ringbuffer *const rb, uint8_t *data)
+{
+	if (rb->write_index != rb->read_index) {
+		*data = rb->buf[rb->read_index & rb->size];
+		rb->read_index++;
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+/**
+ * \brief Put one byte to ringbuffer
+ *
+ */
+int32_t ringbuffer_put(struct ringbuffer *const rb, uint8_t data)
+{
+	rb->buf[rb->write_index & rb->size] = data;
+
+	/*
+	 * buffer full strategy: new data will overwrite the oldest data in
+	 * the buffer
+	 */
+	if ((rb->write_index - rb->read_index) > rb->size) {
+		rb->read_index = rb->write_index - rb->size;
+	}
+
+	rb->write_index++;
+
+	return 0;
+}
+
+/**
+ * \brief Return the element number of ringbuffer
+ */
+uint32_t ringbuffer_num(const struct ringbuffer *const rb)
+{
+	return rb->write_index - rb->read_index;
+}
+
+/**
+ * \brief Flush ringbuffer
+ */
+uint32_t ringbuffer_flush(struct ringbuffer *const rb)
+{
+	rb->read_index = rb->write_index;
+
+	return 0;
+}
diff --git a/ccid/utils_ringbuffer.h b/ccid/utils_ringbuffer.h
new file mode 100644
index 0000000..07043a6
--- /dev/null
+++ b/ccid/utils_ringbuffer.h
@@ -0,0 +1,115 @@
+/**
+ * \file
+ *
+ * \brief Ringbuffer declaration.
+ *
+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Subject to your compliance with these terms, you may use Microchip
+ * software and any derivatives exclusively with Microchip products.
+ * It is your responsibility to comply with third party license terms applicable
+ * to your use of third party software (including open source software) that
+ * may accompany Microchip software.
+ *
+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
+ *
+ * \asf_license_stop
+ *
+ */
+#ifndef _UTILS_RINGBUFFER_H_INCLUDED
+#define _UTILS_RINGBUFFER_H_INCLUDED
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup doc_driver_hal_utils_ringbuffer
+ *
+ * @{
+ */
+
+/**
+ * \brief Ring buffer element type
+ */
+struct ringbuffer {
+	uint8_t *buf;         /** Buffer base address */
+	uint32_t size;        /** Buffer size */
+	uint32_t read_index;  /** Buffer read index */
+	uint32_t write_index; /** Buffer write index */
+};
+
+/**
+ * \brief Ring buffer init
+ *
+ * \param[in] rb The pointer to a ring buffer structure instance
+ * \param[in] buf Space to store the data
+ * \param[in] size The buffer length, must be aligned with power of 2
+ *
+ * \return ERR_NONE on success, or an error code on failure.
+ */
+int32_t ringbuffer_init(struct ringbuffer *const rb, void *buf, uint32_t size);
+
+/**
+ * \brief Get one byte from ring buffer, the user needs to handle the concurrent
+ * access on buffer via put/get/flush
+ *
+ * \param[in] rb The pointer to a ring buffer structure instance
+ * \param[in] data One byte space to store the read data
+ *
+ * \return ERR_NONE on success, or an error code on failure.
+ */
+int32_t ringbuffer_get(struct ringbuffer *const rb, uint8_t *data);
+
+/**
+ * \brief Put one byte to ring buffer, the user needs to handle the concurrent access
+ * on buffer via put/get/flush
+ *
+ * \param[in] rb The pointer to a ring buffer structure instance
+ * \param[in] data One byte data to be put into ring buffer
+ *
+ * \return ERR_NONE on success, or an error code on failure.
+ */
+int32_t ringbuffer_put(struct ringbuffer *const rb, uint8_t data);
+
+/**
+ * \brief Return the element number of ring buffer
+ *
+ * \param[in] rb The pointer to a ring buffer structure instance
+ *
+ * \return The number of elements in ring buffer [0, rb->size]
+ */
+uint32_t ringbuffer_num(const struct ringbuffer *const rb);
+
+/**
+ * \brief Flush ring buffer, the user needs to handle the concurrent access on buffer
+ * via put/get/flush
+ *
+ * \param[in] rb The pointer to a ring buffer structure instance
+ *
+ * \return ERR_NONE on success, or an error code on failure.
+ */
+uint32_t ringbuffer_flush(struct ringbuffer *const rb);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _UTILS_RINGBUFFER_H_INCLUDED */

-- 
To view, visit https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/15691
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-ccid-firmware
Gerrit-Branch: master
Gerrit-Change-Id: Ic7e324d99f78b3bfb98fc667d9a1b7fa363f092d
Gerrit-Change-Number: 15691
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge at osmocom.org>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20191007/0b40365e/attachment.htm>


More information about the gerrit-log mailing list