diff options
author | Uros Majstorovic <majstor@majstor.org> | 2021-08-27 02:50:19 +0200 |
---|---|---|
committer | Uros Majstorovic <majstor@majstor.org> | 2021-08-27 02:50:19 +0200 |
commit | 01270b114be7a82a4dbeae7a3d40c83495224842 (patch) | |
tree | a1a37b6fbc3a7e09c47695a0ef980500ad258320 /recipes-bsp/esp32spid/src | |
parent | 52bbf971706df3752d5a41879495740041a4a735 (diff) | |
parent | 5c6a2266ffa6780935959af6c96ffc8dd8e2dc1a (diff) |
Merge remote-tracking branch 'meta-bsp-rvphone/master'
Diffstat (limited to 'recipes-bsp/esp32spid/src')
-rw-r--r-- | recipes-bsp/esp32spid/src/Makefile | 15 | ||||
-rw-r--r-- | recipes-bsp/esp32spid/src/msgq.c | 42 | ||||
-rw-r--r-- | recipes-bsp/esp32spid/src/msgq.h | 19 | ||||
-rw-r--r-- | recipes-bsp/esp32spid/src/spi.c | 284 | ||||
-rw-r--r-- | recipes-bsp/esp32spid/src/spi.h | 24 | ||||
-rw-r--r-- | recipes-bsp/esp32spid/src/tun.c | 94 | ||||
-rw-r--r-- | recipes-bsp/esp32spid/src/tun.h | 8 |
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 |