summaryrefslogtreecommitdiff
path: root/recipes-bsp/esp32spid/src
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-bsp/esp32spid/src')
-rw-r--r--recipes-bsp/esp32spid/src/Makefile15
-rw-r--r--recipes-bsp/esp32spid/src/msgq.c42
-rw-r--r--recipes-bsp/esp32spid/src/msgq.h19
-rw-r--r--recipes-bsp/esp32spid/src/spi.c284
-rw-r--r--recipes-bsp/esp32spid/src/spi.h24
-rw-r--r--recipes-bsp/esp32spid/src/tun.c94
-rw-r--r--recipes-bsp/esp32spid/src/tun.h8
7 files changed, 486 insertions, 0 deletions
diff --git a/recipes-bsp/esp32spid/src/Makefile b/recipes-bsp/esp32spid/src/Makefile
new file mode 100644
index 0000000..fcecbd5
--- /dev/null
+++ b/recipes-bsp/esp32spid/src/Makefile
@@ -0,0 +1,15 @@
+#CFLAGS =
+LDFLAGS = -pthread -lgpiod
+TARGET = esp32spid
+obj = msgq.o spi.o tun.o
+
+all: $(TARGET)
+
+%.o: %.c %.h
+ $(CC) $(CFLAGS) -c $<
+
+$(TARGET): $(obj)
+ $(CC) $(obj) $(LDFLAGS) -o $@
+
+clean:
+ rm -f $(TARGET) *.o
diff --git a/recipes-bsp/esp32spid/src/msgq.c b/recipes-bsp/esp32spid/src/msgq.c
new file mode 100644
index 0000000..ff9f59e
--- /dev/null
+++ b/recipes-bsp/esp32spid/src/msgq.c
@@ -0,0 +1,42 @@
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "msgq.h"
+
+#define IDX_MASK(IDX, SIZE) ((IDX) & ((SIZE) - 1))
+
+int msgq_init(MSGQueue *msgq, unsigned char **array, uint16_t size) {
+ int rv;
+
+ msgq->idx_r = 0;
+ msgq->idx_w = 0;
+ msgq->size = size;
+ msgq->array = array;
+ rv = pthread_mutex_init(&msgq->mutex, NULL);
+ if (rv) {
+ return MSGQ_ERR;
+ }
+
+ rv = pthread_cond_init(&msgq->cond, NULL);
+ if (rv) {
+ pthread_mutex_destroy(&msgq->mutex);
+ return MSGQ_ERR;
+ }
+}
+
+int msgq_push(MSGQueue *msgq, unsigned char *buffer) {
+ if ((uint16_t)(msgq->idx_w - msgq->idx_r) == msgq->size) return MSGQ_ERR_FULL;
+
+ msgq->array[IDX_MASK(msgq->idx_w++, msgq->size)] = buffer;
+ return MSGQ_OK;
+}
+
+unsigned char *msgq_pop(MSGQueue *msgq) {
+ if (msgq->idx_r == msgq->idx_w) return NULL;
+
+ return msgq->array[IDX_MASK(msgq->idx_r++, msgq->size)];
+}
+
+uint16_t msgq_len(MSGQueue *msgq) {
+ return (uint16_t)(msgq->idx_w - msgq->idx_r);
+}
diff --git a/recipes-bsp/esp32spid/src/msgq.h b/recipes-bsp/esp32spid/src/msgq.h
new file mode 100644
index 0000000..665be32
--- /dev/null
+++ b/recipes-bsp/esp32spid/src/msgq.h
@@ -0,0 +1,19 @@
+#include <stdint.h>
+
+#define MSGQ_OK 0
+#define MSGQ_ERR -1
+#define MSGQ_ERR_FULL -10
+
+typedef struct MSGQueue {
+ uint16_t idx_r;
+ uint16_t idx_w;
+ uint16_t size;
+ unsigned char **array;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+} MSGQueue;
+
+int msgq_init(MSGQueue *msgq, unsigned char **array, uint16_t size);
+int msgq_push(MSGQueue *msgq, unsigned char *buffer);
+unsigned char *msgq_pop(MSGQueue *msgq);
+uint16_t msgq_len(MSGQueue *msgq);
diff --git a/recipes-bsp/esp32spid/src/spi.c b/recipes-bsp/esp32spid/src/spi.c
new file mode 100644
index 0000000..5bd0718
--- /dev/null
+++ b/recipes-bsp/esp32spid/src/spi.c
@@ -0,0 +1,284 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <linux/spi/spidev.h>
+
+#include <gpiod.h>
+#include <pthread.h>
+
+#include "msgq.h"
+#include "tun.h"
+#include "spi.h"
+
+static pthread_t rtscts_thd;
+static pthread_t worker_thd;
+static pthread_t handler_thd;
+static pthread_mutex_t mutex;
+
+struct gpiod_line *gpio_rts, *gpio_cts;
+static struct gpiod_line_bulk gpio_rtscts;
+
+static MSGQueue spi_bufq;
+static unsigned char *spi_bufq_array[SPI_SIZE_BUFQ];
+
+static MSGQueue spi_msgq_in;
+static unsigned char *spi_msgq_in_array[SPI_SIZE_MSGQ];
+
+static MSGQueue spi_msgq_out;
+static unsigned char *spi_msgq_out_array[SPI_SIZE_MSGQ];
+
+static uint32_t spi_speed = 5000000;
+static int spi_fd;
+
+static int _spi_xchg(unsigned char *buffer) {
+ int rv;
+ uint16_t len_tx;
+ uint16_t len_rx;
+ struct spi_ioc_transfer tr;
+
+ memset(&tr, 0, sizeof(tr));
+ tr.tx_buf = (unsigned long)buffer;
+ tr.rx_buf = (unsigned long)buffer;
+ tr.speed_hz = spi_speed,
+
+ len_tx = (uint16_t)buffer[1] << 8;
+ len_tx |= (uint16_t)buffer[2] & 0xFF;
+ if (len_tx > SPI_MTU) return SPI_ERR;
+
+ len_tx += SPI_SIZE_HDR;
+ // esp32 dma workaraund
+ if (len_tx < 8) {
+ len_tx = 8;
+ } else if (len_tx % 4 != 0) {
+ len_tx = (len_tx / 4 + 1) * 4;
+ }
+
+ tr.len = len_tx;
+
+ pthread_mutex_lock(&mutex);
+ rv = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr);
+ if (rv < 0) return SPI_ERR_MSG;
+
+ len_rx = (uint16_t)buffer[1] << 8;
+ len_rx |= (uint16_t)buffer[2] & 0xFF;
+ if (len_rx > SPI_MTU) return SPI_ERR;
+
+ len_rx += SPI_SIZE_HDR;
+ if (len_rx > len_tx) {
+ tr.tx_buf = (unsigned long)NULL;
+ tr.rx_buf = (unsigned long)(buffer + len_tx);
+
+ len_tx = len_rx - len_tx;
+ // esp32 dma workaraund
+ if (len_tx < 8) {
+ len_tx = 8;
+ } else if (len_tx % 4 != 0) {
+ len_tx = (len_tx / 4 + 1) * 4;
+ }
+
+ tr.len = len_tx;
+
+ pthread_mutex_lock(&mutex);
+ rv = ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr);
+ if (rv < 0) return SPI_ERR_MSG;
+ }
+
+ return SPI_OK;
+}
+
+static void *spi_rtscts_handler(void *arg) {
+ MSGQueue *msgq_out = &spi_msgq_out;
+ int i, rv;
+ struct gpiod_line_bulk evt_lines;
+ struct gpiod_line_event event;
+
+ while (1) {
+ rv = gpiod_line_event_wait_bulk(&gpio_rtscts, NULL, &evt_lines);
+ if (rv < 0) continue;
+
+ for (i=0; i<gpiod_line_bulk_num_lines(&evt_lines); i++) {
+ struct gpiod_line *line;
+
+ line = gpiod_line_bulk_get_line(&evt_lines, i);
+ rv = gpiod_line_event_read(line, &event);
+ if (rv || (event.event_type != GPIOD_LINE_EVENT_RISING_EDGE)) continue;
+
+ switch (gpiod_line_offset(line)) {
+ case SPI_GPIO_RTS:
+ pthread_mutex_lock(&msgq_out->mutex);
+ pthread_cond_signal(&msgq_out->cond);
+ pthread_mutex_unlock(&msgq_out->mutex);
+ break;
+ case SPI_GPIO_CTS:
+ pthread_mutex_unlock(&mutex);
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+
+static void *spi_worker(void *arg) {
+ MSGQueue *bufq = &spi_bufq;
+ MSGQueue *msgq_in = &spi_msgq_in;
+ MSGQueue *msgq_out = &spi_msgq_out;
+ int rv;
+ unsigned char *buffer;
+
+ while (1) {
+ pthread_mutex_lock(&msgq_out->mutex);
+ buffer = msgq_pop(msgq_out);
+ if ((buffer == NULL) && (gpiod_line_get_value(gpio_rts) == 1)) {
+ pthread_mutex_lock(&bufq->mutex);
+ buffer = msgq_pop(bufq);
+ pthread_mutex_unlock(&bufq->mutex);
+ }
+ if (buffer == NULL) {
+ pthread_cond_wait(&msgq_out->cond, &msgq_out->mutex);
+ buffer = msgq_pop(msgq_out);
+ }
+ pthread_mutex_unlock(&msgq_out->mutex);
+ if (buffer) {
+ rv = _spi_xchg(buffer);
+ if (rv || (buffer[0] == 0)) {
+ buffer[1] = 0;
+ buffer[2] = 0;
+ pthread_mutex_lock(&bufq->mutex);
+ rv = msgq_push(bufq, buffer);
+ pthread_mutex_unlock(&bufq->mutex);
+ } else {
+ pthread_mutex_lock(&msgq_in->mutex);
+ rv = msgq_push(msgq_in, buffer);
+ pthread_cond_signal(&msgq_in->cond);
+ pthread_mutex_unlock(&msgq_in->mutex);
+ }
+ }
+ }
+ return NULL;
+}
+
+static void *spi_handler(void *arg) {
+ MSGQueue *bufq = &spi_bufq;
+ MSGQueue *msgq_in = &spi_msgq_in;
+ unsigned char *buffer;
+ unsigned char mtype;
+ uint16_t len;
+ int rv;
+
+ while (1) {
+ pthread_mutex_lock(&msgq_in->mutex);
+ buffer = msgq_pop(msgq_in);
+ if (buffer == NULL) {
+ pthread_cond_wait(&msgq_in->cond, &msgq_in->mutex);
+ buffer = msgq_pop(msgq_in);
+ }
+ pthread_mutex_unlock(&msgq_in->mutex);
+ if (buffer) {
+ mtype = buffer[0];
+ len = (uint16_t)buffer[1] << 8;
+ len |= (uint16_t)buffer[2] & 0xFF;
+
+ switch (mtype) {
+ case SPI_MTYPE_TUN:
+ tun_write(buffer + SPI_SIZE_HDR, len);
+ break;
+ }
+ buffer[0] = 0;
+ buffer[1] = 0;
+ buffer[2] = 0;
+ pthread_mutex_lock(&bufq->mutex);
+ rv = msgq_push(bufq, buffer);
+ pthread_mutex_unlock(&bufq->mutex);
+ }
+ }
+}
+
+unsigned char *spi_alloc(void) {
+ MSGQueue *bufq = &spi_bufq;
+ unsigned char *ret;
+
+ pthread_mutex_lock(&bufq->mutex);
+ ret = msgq_pop(bufq);
+ pthread_mutex_unlock(&bufq->mutex);
+
+ return ret;
+}
+
+void spi_free(unsigned char *buffer) {
+ MSGQueue *bufq = &spi_bufq;
+
+ buffer[0] = 0;
+ buffer[1] = 0;
+ buffer[2] = 0;
+ pthread_mutex_lock(&bufq->mutex);
+ msgq_push(bufq, buffer);
+ pthread_mutex_unlock(&bufq->mutex);
+}
+
+int spi_xchg(unsigned char mtype, unsigned char *buffer, uint16_t len) {
+ int rv;
+ MSGQueue *msgq_out = &spi_msgq_out;
+
+ buffer[0] = mtype;
+ buffer[1] = len >> 8;
+ buffer[2] = len & 0xFF;
+
+ pthread_mutex_lock(&msgq_out->mutex);
+ rv = msgq_push(msgq_out, buffer);
+ pthread_cond_signal(&msgq_out->cond);
+ pthread_mutex_unlock(&msgq_out->mutex);
+
+ return rv;
+}
+
+int spi_init(char *fname) {
+ int rv, i;
+ struct gpiod_chip *gpio_chip;
+
+ spi_fd = open(fname, O_RDWR);
+ if (spi_fd < 0) return SPI_ERR_OPEN;
+
+ rv = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed);
+ if (rv == -1) return SPI_ERR;
+
+ gpio_chip = gpiod_chip_open_by_name(SPI_GPIO_BANK);
+ if (gpio_chip == NULL) return SPI_ERR;
+
+ gpio_rts = gpiod_chip_get_line(gpio_chip, SPI_GPIO_RTS);
+ gpio_cts = gpiod_chip_get_line(gpio_chip, SPI_GPIO_CTS);
+ if ((gpio_rts == NULL) || (gpio_cts == NULL)) return SPI_ERR;
+
+ gpiod_line_bulk_init(&gpio_rtscts);
+ gpiod_line_bulk_add(&gpio_rtscts, gpio_rts);
+ gpiod_line_bulk_add(&gpio_rtscts, gpio_cts);
+ rv = gpiod_line_request_bulk_rising_edge_events(&gpio_rtscts, "rtscts");
+ if (rv) return SPI_ERR;
+
+ msgq_init(&spi_bufq, spi_bufq_array, SPI_SIZE_BUFQ);
+ msgq_init(&spi_msgq_in, spi_msgq_in_array, SPI_SIZE_MSGQ);
+ msgq_init(&spi_msgq_out, spi_msgq_out_array, SPI_SIZE_MSGQ);
+ for (i=0; i<SPI_SIZE_BUFQ; i++) {
+ msgq_push(&spi_bufq, malloc(SPI_SIZE_BUF));
+ }
+
+ rv = pthread_mutex_init(&mutex, NULL);
+ rv = pthread_create(&rtscts_thd, NULL, spi_rtscts_handler, NULL);
+ rv = pthread_create(&worker_thd, NULL, spi_worker, NULL);
+ rv = pthread_create(&handler_thd, NULL, spi_handler, NULL);
+
+ return SPI_OK;
+}
+
+int main(int argc, char *argv[]) {
+ int rv;
+
+ rv = spi_init("/dev/spidev0.0");
+ if (rv) printf("SPI INIT ERR\n");
+ rv = tun_init();
+ if (rv) printf("TUN INIT ERR\n");
+ tun_read(NULL);
+}
diff --git a/recipes-bsp/esp32spid/src/spi.h b/recipes-bsp/esp32spid/src/spi.h
new file mode 100644
index 0000000..c1a4d94
--- /dev/null
+++ b/recipes-bsp/esp32spid/src/spi.h
@@ -0,0 +1,24 @@
+#include <stdint.h>
+
+#define SPI_GPIO_BANK "gpiochip2"
+#define SPI_GPIO_CTS 3
+#define SPI_GPIO_RTS 4
+
+#define SPI_MTU 1500
+#define SPI_SIZE_BUF (SPI_MTU + 8)
+#define SPI_SIZE_HDR 3
+
+#define SPI_SIZE_BUFQ 64
+#define SPI_SIZE_MSGQ 256
+
+#define SPI_MTYPE_TUN 1
+
+#define SPI_OK 0
+#define SPI_ERR -1
+#define SPI_ERR_OPEN -10
+#define SPI_ERR_MSG -11
+
+unsigned char *spi_alloc(void);
+void spi_free(unsigned char *buffer);
+int spi_xchg(unsigned char mtype, unsigned char *buffer, uint16_t len);
+int spi_init(char *fname); \ No newline at end of file
diff --git a/recipes-bsp/esp32spid/src/tun.c b/recipes-bsp/esp32spid/src/tun.c
new file mode 100644
index 0000000..d75edc4
--- /dev/null
+++ b/recipes-bsp/esp32spid/src/tun.c
@@ -0,0 +1,94 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+#include <pthread.h>
+
+#include "spi.h"
+#include "tun.h"
+
+static pthread_t read_thd;
+
+static int tun_fd;
+static char tun_name[IFNAMSIZ];
+
+static int tun_alloc(char *dev, int flags) {
+ struct ifreq ifr;
+ int fd, err;
+ char *clonedev = "/dev/net/tun";
+
+ /* Arguments taken by the function:
+ *
+ * char *dev: the name of an interface (or '\0'). MUST have enough
+ * space to hold the interface name if '\0' is passed
+ * int flags: interface flags (eg, IFF_TUN etc.)
+ */
+
+ fd = open(clonedev, O_RDWR);
+ if (fd < 0) {
+ return fd;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */
+
+ if (*dev) {
+ /* if a device name was specified, put it in the structure; otherwise,
+ * the kernel will try to allocate the "next" device of the
+ * specified type */
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ }
+
+ /* try to create the device */
+ err = ioctl(fd, TUNSETIFF, (void *) &ifr);
+ if (err < 0) {
+ close(fd);
+ return err;
+ }
+
+ /* if the operation was successful, write back the name of the
+ * interface to the variable "dev", so the caller can know
+ * it. Note that the caller MUST reserve space in *dev (see calling
+ * code below) */
+ strcpy(dev, ifr.ifr_name);
+
+ /* this is the special file descriptor that the caller will use to talk
+ * with the virtual interface */
+ return fd;
+}
+
+void *tun_read(void *arg) {
+ unsigned char *buffer;
+ int len;
+
+ while (1) {
+ buffer = spi_alloc();
+ if (buffer == NULL) continue;
+ len = read(tun_fd, buffer + SPI_SIZE_HDR, SPI_SIZE_BUF - SPI_SIZE_HDR);
+ if (len < 0) {
+ perror("tun read");
+ continue;
+ }
+ spi_xchg(SPI_MTYPE_TUN, buffer, len);
+ }
+}
+
+int tun_write(unsigned char *buffer, uint16_t len) {
+ return write(tun_fd, buffer, len);
+}
+
+int tun_init(void) {
+ int rv;
+
+ strcpy(tun_name, "tun0");
+ tun_fd = tun_alloc(tun_name, IFF_TUN | IFF_NO_PI);
+ if (tun_fd < 0) return TUN_ERR;
+
+ return TUN_OK;
+}
diff --git a/recipes-bsp/esp32spid/src/tun.h b/recipes-bsp/esp32spid/src/tun.h
new file mode 100644
index 0000000..bcfdac5
--- /dev/null
+++ b/recipes-bsp/esp32spid/src/tun.h
@@ -0,0 +1,8 @@
+#include <stdint.h>
+
+#define TUN_OK 0
+#define TUN_ERR -1
+
+void *tun_read(void *arg);
+int tun_write(unsigned char *buffer, uint16_t len);
+int tun_init(void); \ No newline at end of file