Replace c-periphery with submodule
This commit is contained in:
parent
f92b27e439
commit
32e7570259
|
@ -0,0 +1,3 @@
|
|||
[submodule "sys/arm-linux/c-periphery"]
|
||||
path = sys/arm-linux/c-periphery
|
||||
url = https://github.com/vsergeev/c-periphery
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 2379567960b9f72ccfb8f9db7271092612e89bdf
|
|
@ -0,0 +1 @@
|
|||
./c-periphery/src
|
File diff suppressed because it is too large
Load Diff
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* c-periphery
|
||||
* https://github.com/vsergeev/c-periphery
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
#ifndef _PERIPHERY_GPIO_H
|
||||
#define _PERIPHERY_GPIO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum gpio_error_code {
|
||||
GPIO_ERROR_ARG = -1, /* Invalid arguments */
|
||||
GPIO_ERROR_OPEN = -2, /* Opening GPIO */
|
||||
GPIO_ERROR_NOT_FOUND = -3, /* Line name not found */
|
||||
GPIO_ERROR_QUERY = -4, /* Querying GPIO attributes */
|
||||
GPIO_ERROR_CONFIGURE = -5, /* Configuring GPIO attributes */
|
||||
GPIO_ERROR_UNSUPPORTED = -6, /* Unsupported attribute or operation */
|
||||
GPIO_ERROR_INVALID_OPERATION = -7, /* Invalid operation */
|
||||
GPIO_ERROR_IO = -8, /* Reading/writing GPIO */
|
||||
GPIO_ERROR_CLOSE = -9, /* Closing GPIO */
|
||||
};
|
||||
|
||||
typedef enum gpio_direction {
|
||||
GPIO_DIR_IN, /* Input */
|
||||
GPIO_DIR_OUT, /* Output, initialized to low */
|
||||
GPIO_DIR_OUT_LOW, /* Output, initialized to low */
|
||||
GPIO_DIR_OUT_HIGH, /* Output, initialized to high */
|
||||
} gpio_direction_t;
|
||||
|
||||
typedef enum gpio_edge {
|
||||
GPIO_EDGE_NONE, /* No interrupt edge */
|
||||
GPIO_EDGE_RISING, /* Rising edge 0 -> 1 */
|
||||
GPIO_EDGE_FALLING, /* Falling edge 1 -> 0 */
|
||||
GPIO_EDGE_BOTH /* Both edges X -> !X */
|
||||
} gpio_edge_t;
|
||||
|
||||
typedef enum gpio_bias {
|
||||
GPIO_BIAS_DEFAULT, /* Default line bias */
|
||||
GPIO_BIAS_PULL_UP, /* Pull-up */
|
||||
GPIO_BIAS_PULL_DOWN, /* Pull-down */
|
||||
GPIO_BIAS_DISABLE, /* Disable line bias */
|
||||
} gpio_bias_t;
|
||||
|
||||
typedef enum gpio_drive {
|
||||
GPIO_DRIVE_DEFAULT, /* Default line drive (push-pull) */
|
||||
GPIO_DRIVE_OPEN_DRAIN, /* Open drain */
|
||||
GPIO_DRIVE_OPEN_SOURCE, /* Open source */
|
||||
} gpio_drive_t;
|
||||
|
||||
/* Configuration structure for gpio_open_*advanced() functions */
|
||||
typedef struct gpio_config {
|
||||
gpio_direction_t direction;
|
||||
gpio_edge_t edge;
|
||||
gpio_bias_t bias;
|
||||
gpio_drive_t drive;
|
||||
bool inverted;
|
||||
const char *label; /* Can be NULL for default consumer label */
|
||||
} gpio_config_t;
|
||||
|
||||
typedef struct gpio_handle gpio_t;
|
||||
|
||||
/* Primary Functions */
|
||||
gpio_t *gpio_new(void);
|
||||
int gpio_open(gpio_t *gpio, const char *path, unsigned int line, gpio_direction_t direction);
|
||||
int gpio_open_name(gpio_t *gpio, const char *path, const char *name, gpio_direction_t direction);
|
||||
int gpio_open_advanced(gpio_t *gpio, const char *path, unsigned int line, const gpio_config_t *config);
|
||||
int gpio_open_name_advanced(gpio_t *gpio, const char *path, const char *name, const gpio_config_t *config);
|
||||
int gpio_open_sysfs(gpio_t *gpio, unsigned int line, gpio_direction_t direction);
|
||||
int gpio_read(gpio_t *gpio, bool *value);
|
||||
int gpio_write(gpio_t *gpio, bool value);
|
||||
int gpio_poll(gpio_t *gpio, int timeout_ms);
|
||||
int gpio_close(gpio_t *gpio);
|
||||
void gpio_free(gpio_t *gpio);
|
||||
|
||||
/* Read Event (for character device GPIOs) */
|
||||
int gpio_read_event(gpio_t *gpio, gpio_edge_t *edge, uint64_t *timestamp);
|
||||
|
||||
/* Poll Multiple */
|
||||
int gpio_poll_multiple(gpio_t **gpios, size_t count, int timeout_ms, bool *gpios_ready);
|
||||
|
||||
/* Getters */
|
||||
int gpio_get_direction(gpio_t *gpio, gpio_direction_t *direction);
|
||||
int gpio_get_edge(gpio_t *gpio, gpio_edge_t *edge);
|
||||
int gpio_get_bias(gpio_t *gpio, gpio_bias_t *bias);
|
||||
int gpio_get_drive(gpio_t *gpio, gpio_drive_t *drive);
|
||||
int gpio_get_inverted(gpio_t *gpio, bool *inverted);
|
||||
|
||||
/* Setters */
|
||||
int gpio_set_direction(gpio_t *gpio, gpio_direction_t direction);
|
||||
int gpio_set_edge(gpio_t *gpio, gpio_edge_t edge);
|
||||
int gpio_set_bias(gpio_t *gpio, gpio_bias_t bias);
|
||||
int gpio_set_drive(gpio_t *gpio, gpio_drive_t drive);
|
||||
int gpio_set_inverted(gpio_t *gpio, bool inverted);
|
||||
|
||||
/* Miscellaneous Properties */
|
||||
unsigned int gpio_line(gpio_t *gpio);
|
||||
int gpio_fd(gpio_t *gpio);
|
||||
int gpio_name(gpio_t *gpio, char *str, size_t len);
|
||||
int gpio_label(gpio_t *gpio, char *str, size_t len);
|
||||
int gpio_chip_fd(gpio_t *gpio);
|
||||
int gpio_chip_name(gpio_t *gpio, char *str, size_t len);
|
||||
int gpio_chip_label(gpio_t *gpio, char *str, size_t len);
|
||||
int gpio_tostring(gpio_t *gpio, char *str, size_t len);
|
||||
|
||||
/* Error Handling */
|
||||
int gpio_errno(gpio_t *gpio);
|
||||
const char *gpio_errmsg(gpio_t *gpio);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,136 +0,0 @@
|
|||
/*
|
||||
* c-periphery
|
||||
* https://github.com/vsergeev/c-periphery
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
struct i2c_handle {
|
||||
int fd;
|
||||
|
||||
struct {
|
||||
int c_errno;
|
||||
char errmsg[96];
|
||||
} error;
|
||||
};
|
||||
|
||||
static int _i2c_error(i2c_t *i2c, int code, int c_errno, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
i2c->error.c_errno = c_errno;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(i2c->error.errmsg, sizeof(i2c->error.errmsg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Tack on strerror() and errno */
|
||||
if (c_errno) {
|
||||
char buf[64];
|
||||
strerror_r(c_errno, buf, sizeof(buf));
|
||||
snprintf(i2c->error.errmsg+strlen(i2c->error.errmsg), sizeof(i2c->error.errmsg)-strlen(i2c->error.errmsg), ": %s [errno %d]", buf, c_errno);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
i2c_t *i2c_new(void) {
|
||||
i2c_t *i2c = calloc(1, sizeof(i2c_t));
|
||||
if (i2c == NULL)
|
||||
return NULL;
|
||||
|
||||
i2c->fd = -1;
|
||||
|
||||
return i2c;
|
||||
}
|
||||
|
||||
void i2c_free(i2c_t *i2c) {
|
||||
free(i2c);
|
||||
}
|
||||
|
||||
int i2c_open(i2c_t *i2c, const char *path) {
|
||||
unsigned long supported_funcs;
|
||||
|
||||
memset(i2c, 0, sizeof(i2c_t));
|
||||
|
||||
/* Open device */
|
||||
if ((i2c->fd = open(path, O_RDWR)) < 0)
|
||||
return _i2c_error(i2c, I2C_ERROR_OPEN, errno, "Opening I2C device \"%s\"", path);
|
||||
|
||||
/* Query supported functions */
|
||||
if (ioctl(i2c->fd, I2C_FUNCS, &supported_funcs) < 0) {
|
||||
int errsv = errno;
|
||||
close(i2c->fd);
|
||||
i2c->fd = -1;
|
||||
return _i2c_error(i2c, I2C_ERROR_QUERY, errsv, "Querying I2C functions");
|
||||
}
|
||||
|
||||
if (!(supported_funcs & I2C_FUNC_I2C)) {
|
||||
close(i2c->fd);
|
||||
i2c->fd = -1;
|
||||
return _i2c_error(i2c, I2C_ERROR_NOT_SUPPORTED, 0, "I2C not supported on %s", path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_transfer(i2c_t *i2c, struct i2c_msg *msgs, size_t count) {
|
||||
struct i2c_rdwr_ioctl_data i2c_rdwr_data;
|
||||
|
||||
/* Prepare I2C transfer structure */
|
||||
memset(&i2c_rdwr_data, 0, sizeof(struct i2c_rdwr_ioctl_data));
|
||||
i2c_rdwr_data.msgs = msgs;
|
||||
i2c_rdwr_data.nmsgs = count;
|
||||
|
||||
/* Transfer */
|
||||
if (ioctl(i2c->fd, I2C_RDWR, &i2c_rdwr_data) < 0)
|
||||
return _i2c_error(i2c, I2C_ERROR_TRANSFER, errno, "I2C transfer");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_close(i2c_t *i2c) {
|
||||
if (i2c->fd < 0)
|
||||
return 0;
|
||||
|
||||
/* Close fd */
|
||||
if (close(i2c->fd) < 0)
|
||||
return _i2c_error(i2c, I2C_ERROR_CLOSE, errno, "Closing I2C device");
|
||||
|
||||
i2c->fd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_tostring(i2c_t *i2c, char *str, size_t len) {
|
||||
return snprintf(str, len, "I2C (fd=%d)", i2c->fd);
|
||||
}
|
||||
|
||||
const char *i2c_errmsg(i2c_t *i2c) {
|
||||
return i2c->error.errmsg;
|
||||
}
|
||||
|
||||
int i2c_errno(i2c_t *i2c) {
|
||||
return i2c->error.c_errno;
|
||||
}
|
||||
|
||||
int i2c_fd(i2c_t *i2c) {
|
||||
return i2c->fd;
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* c-periphery
|
||||
* https://github.com/vsergeev/c-periphery
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
#ifndef _PERIPHERY_I2C_H
|
||||
#define _PERIPHERY_I2C_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
|
||||
enum i2c_error_code {
|
||||
I2C_ERROR_ARG = -1, /* Invalid arguments */
|
||||
I2C_ERROR_OPEN = -2, /* Opening I2C device */
|
||||
I2C_ERROR_QUERY = -3, /* Querying I2C device attributes */
|
||||
I2C_ERROR_NOT_SUPPORTED = -4, /* I2C not supported on this device */
|
||||
I2C_ERROR_TRANSFER = -5, /* I2C transfer */
|
||||
I2C_ERROR_CLOSE = -6, /* Closing I2C device */
|
||||
};
|
||||
|
||||
typedef struct i2c_handle i2c_t;
|
||||
|
||||
/* Primary Functions */
|
||||
i2c_t *i2c_new(void);
|
||||
int i2c_open(i2c_t *i2c, const char *path);
|
||||
int i2c_transfer(i2c_t *i2c, struct i2c_msg *msgs, size_t count);
|
||||
int i2c_close(i2c_t *i2c);
|
||||
void i2c_free(i2c_t *i2c);
|
||||
|
||||
/* Miscellaneous */
|
||||
int i2c_fd(i2c_t *i2c);
|
||||
int i2c_tostring(i2c_t *i2c, char *str, size_t len);
|
||||
|
||||
/* Error Handling */
|
||||
int i2c_errno(i2c_t *i2c);
|
||||
const char *i2c_errmsg(i2c_t *i2c);
|
||||
|
||||
/* struct i2c_msg from <linux/i2c.h>:
|
||||
|
||||
struct i2c_msg {
|
||||
__u16 addr;
|
||||
__u16 flags;
|
||||
#define I2C_M_TEN 0x0010
|
||||
#define I2C_M_RD 0x0001
|
||||
#define I2C_M_STOP 0x8000
|
||||
#define I2C_M_NOSTART 0x4000
|
||||
#define I2C_M_REV_DIR_ADDR 0x2000
|
||||
#define I2C_M_IGNORE_NAK 0x1000
|
||||
#define I2C_M_NO_RD_ACK 0x0800
|
||||
#define I2C_M_RECV_LEN 0x0400
|
||||
__u16 len;
|
||||
__u8 *buf;
|
||||
};
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,404 +0,0 @@
|
|||
/*
|
||||
* c-periphery
|
||||
* https://github.com/vsergeev/c-periphery
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
#include "spi.h"
|
||||
|
||||
struct spi_handle {
|
||||
int fd;
|
||||
|
||||
struct {
|
||||
int c_errno;
|
||||
char errmsg[96];
|
||||
} error;
|
||||
};
|
||||
|
||||
static int _spi_error(spi_t *spi, int code, int c_errno, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
spi->error.c_errno = c_errno;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(spi->error.errmsg, sizeof(spi->error.errmsg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Tack on strerror() and errno */
|
||||
if (c_errno) {
|
||||
char buf[64];
|
||||
strerror_r(c_errno, buf, sizeof(buf));
|
||||
snprintf(spi->error.errmsg+strlen(spi->error.errmsg), sizeof(spi->error.errmsg)-strlen(spi->error.errmsg), ": %s [errno %d]", buf, c_errno);
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
spi_t *spi_new(void) {
|
||||
spi_t *spi = calloc(1, sizeof(spi_t));
|
||||
if (spi == NULL)
|
||||
return NULL;
|
||||
|
||||
spi->fd = -1;
|
||||
|
||||
return spi;
|
||||
}
|
||||
|
||||
void spi_free(spi_t *spi) {
|
||||
free(spi);
|
||||
}
|
||||
|
||||
int spi_open(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed) {
|
||||
return spi_open_advanced(spi, path, mode, max_speed, MSB_FIRST, 8, 0);
|
||||
}
|
||||
|
||||
int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint8_t extra_flags) {
|
||||
return spi_open_advanced2(spi, path, mode, max_speed, bit_order, bits_per_word, extra_flags);
|
||||
}
|
||||
|
||||
int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint32_t extra_flags) {
|
||||
uint32_t data32;
|
||||
uint8_t data8;
|
||||
|
||||
/* Validate arguments */
|
||||
if (mode & ~0x3)
|
||||
return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid mode (can be 0,1,2,3)");
|
||||
if (bit_order != MSB_FIRST && bit_order != LSB_FIRST)
|
||||
return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid bit order (can be MSB_FIRST,LSB_FIRST)");
|
||||
#ifndef SPI_IOC_WR_MODE32
|
||||
if (extra_flags > 0xff)
|
||||
return _spi_error(spi, SPI_ERROR_UNSUPPORTED, 0, "Kernel version does not support 32-bit SPI mode flags");
|
||||
#endif
|
||||
|
||||
memset(spi, 0, sizeof(spi_t));
|
||||
|
||||
/* Open device */
|
||||
if ((spi->fd = open(path, O_RDWR)) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_OPEN, errno, "Opening SPI device \"%s\"", path);
|
||||
|
||||
/* Set mode, bit order, extra flags */
|
||||
#ifndef SPI_IOC_WR_MODE32
|
||||
(void)data32;
|
||||
|
||||
data8 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags;
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode");
|
||||
}
|
||||
#else
|
||||
if (extra_flags > 0xff) {
|
||||
/* Use 32-bit mode if extra_flags is wider than 8-bits */
|
||||
data32 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags;
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE32, &data32) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode");
|
||||
}
|
||||
} else {
|
||||
/* Prefer 8-bit mode, in case this library is inadvertently used on an
|
||||
* older kernel. */
|
||||
data8 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags;
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set max speed */
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI max speed");
|
||||
}
|
||||
|
||||
/* Set bits per word */
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0) {
|
||||
int errsv = errno;
|
||||
close(spi->fd);
|
||||
spi->fd = -1;
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI bits per word");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len) {
|
||||
struct spi_ioc_transfer spi_xfer;
|
||||
|
||||
/* Prepare SPI transfer structure */
|
||||
memset(&spi_xfer, 0, sizeof(struct spi_ioc_transfer));
|
||||
spi_xfer.tx_buf = (uintptr_t)txbuf;
|
||||
spi_xfer.rx_buf = (uintptr_t)rxbuf;
|
||||
spi_xfer.len = len;
|
||||
spi_xfer.delay_usecs = 0;
|
||||
spi_xfer.speed_hz = 0;
|
||||
spi_xfer.bits_per_word = 0;
|
||||
spi_xfer.cs_change = 0;
|
||||
|
||||
/* Transfer */
|
||||
if (ioctl(spi->fd, SPI_IOC_MESSAGE(1), &spi_xfer) < 1)
|
||||
return _spi_error(spi, SPI_ERROR_TRANSFER, errno, "SPI transfer");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_close(spi_t *spi) {
|
||||
if (spi->fd < 0)
|
||||
return 0;
|
||||
|
||||
/* Close fd */
|
||||
if (close(spi->fd) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CLOSE, errno, "Closing SPI device");
|
||||
|
||||
spi->fd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_mode(spi_t *spi, unsigned int *mode) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode");
|
||||
|
||||
*mode = data8 & (SPI_CPHA | SPI_CPOL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_max_speed(spi_t *spi, uint32_t *max_speed) {
|
||||
uint32_t data32;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MAX_SPEED_HZ, &data32) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI max speed");
|
||||
|
||||
*max_speed = data32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_bit_order(spi_t *spi, spi_bit_order_t *bit_order) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_LSB_FIRST, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI bit order");
|
||||
|
||||
if (data8)
|
||||
*bit_order = LSB_FIRST;
|
||||
else
|
||||
*bit_order = MSB_FIRST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_bits_per_word(spi_t *spi, uint8_t *bits_per_word) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_BITS_PER_WORD, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI bits per word");
|
||||
|
||||
*bits_per_word = data8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_extra_flags(spi_t *spi, uint8_t *extra_flags) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode flags");
|
||||
|
||||
/* Extra mode flags without mode 0-3 and bit order */
|
||||
*extra_flags = data8 & ~( SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_get_extra_flags32(spi_t *spi, uint32_t *extra_flags) {
|
||||
#ifdef SPI_IOC_RD_MODE32
|
||||
uint32_t mode32;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE32, &mode32) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting 32-bit SPI mode flags");
|
||||
|
||||
/* Extra mode flags without mode 0-3 and bit order */
|
||||
*extra_flags = mode32 & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
(void)extra_flags;
|
||||
|
||||
return _spi_error(spi, SPI_ERROR_UNSUPPORTED, 0, "Kernel version does not support 32-bit SPI mode flags");
|
||||
#endif
|
||||
}
|
||||
|
||||
int spi_set_mode(spi_t *spi, unsigned int mode) {
|
||||
uint8_t data8;
|
||||
|
||||
if (mode & ~0x3)
|
||||
return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid mode (can be 0,1,2,3)");
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode");
|
||||
|
||||
data8 &= ~(SPI_CPOL | SPI_CPHA);
|
||||
data8 |= mode;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI mode");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_set_bit_order(spi_t *spi, spi_bit_order_t bit_order) {
|
||||
uint8_t data8;
|
||||
|
||||
if (bit_order != MSB_FIRST && bit_order != LSB_FIRST)
|
||||
return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid bit order (can be MSB_FIRST,LSB_FIRST)");
|
||||
|
||||
if (bit_order == LSB_FIRST)
|
||||
data8 = 1;
|
||||
else
|
||||
data8 = 0;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_LSB_FIRST, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI bit order");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_set_extra_flags(spi_t *spi, uint8_t extra_flags) {
|
||||
uint8_t data8;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting SPI mode flags");
|
||||
|
||||
/* Keep mode 0-3 and bit order */
|
||||
data8 &= (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST);
|
||||
/* Set extra flags */
|
||||
data8 |= extra_flags;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI mode flags");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_set_extra_flags32(spi_t *spi, uint32_t extra_flags) {
|
||||
#ifdef SPI_IOC_WR_MODE32
|
||||
uint32_t mode32;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_RD_MODE32, &mode32) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_QUERY, errno, "Getting 32-bit SPI mode flags");
|
||||
|
||||
/* Keep mode 0-3 and bit order */
|
||||
mode32 &= (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST);
|
||||
/* Set extra flags */
|
||||
mode32 |= extra_flags;
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MODE32, &mode32) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting 32-bit SPI mode flags");
|
||||
|
||||
return 0;
|
||||
#else
|
||||
(void)extra_flags;
|
||||
|
||||
return _spi_error(spi, SPI_ERROR_UNSUPPORTED, 0, "Kernel version does not support 32-bit SPI mode flags");
|
||||
#endif
|
||||
}
|
||||
|
||||
int spi_set_max_speed(spi_t *spi, uint32_t max_speed) {
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI max speed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_set_bits_per_word(spi_t *spi, uint8_t bits_per_word) {
|
||||
|
||||
if (ioctl(spi->fd, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0)
|
||||
return _spi_error(spi, SPI_ERROR_CONFIGURE, errno, "Setting SPI bits per word");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_tostring(spi_t *spi, char *str, size_t len) {
|
||||
unsigned int mode;
|
||||
char mode_str[2];
|
||||
uint32_t max_speed;
|
||||
char max_speed_str[16];
|
||||
uint8_t bits_per_word;
|
||||
char bits_per_word_str[4];
|
||||
spi_bit_order_t bit_order;
|
||||
const char *bit_order_str;
|
||||
uint8_t extra_flags8;
|
||||
uint32_t extra_flags32;
|
||||
char extra_flags_str[11];
|
||||
|
||||
if (spi_get_mode(spi, &mode) < 0)
|
||||
strcpy(mode_str, "?");
|
||||
else
|
||||
snprintf(mode_str, sizeof(mode_str), "%u", mode);
|
||||
|
||||
if (spi_get_max_speed(spi, &max_speed) < 0)
|
||||
strcpy(max_speed_str, "?");
|
||||
else
|
||||
snprintf(max_speed_str, sizeof(max_speed_str), "%u", max_speed);
|
||||
|
||||
if (spi_get_bit_order(spi, &bit_order) < 0)
|
||||
bit_order_str = "?";
|
||||
else
|
||||
bit_order_str = (bit_order == LSB_FIRST) ? "LSB_FIRST" : "MSB_FIRST";
|
||||
|
||||
if (spi_get_bits_per_word(spi, &bits_per_word) < 0)
|
||||
strcpy(bits_per_word_str, "?");
|
||||
else
|
||||
snprintf(bits_per_word_str, sizeof(bits_per_word_str), "%u", bits_per_word);
|
||||
|
||||
if (spi_get_extra_flags32(spi, &extra_flags32) < 0) {
|
||||
if (spi_get_extra_flags(spi, &extra_flags8) < 0)
|
||||
strcpy(extra_flags_str, "?");
|
||||
else
|
||||
snprintf(extra_flags_str, sizeof(extra_flags_str), "0x%02x", extra_flags8);
|
||||
} else {
|
||||
snprintf(extra_flags_str, sizeof(extra_flags_str), "0x%08x", extra_flags32);
|
||||
}
|
||||
|
||||
return snprintf(str, len, "SPI (fd=%d, mode=%s, max_speed=%s, bit_order=%s, bits_per_word=%s, extra_flags=%s)", spi->fd, mode_str, max_speed_str, bit_order_str, bits_per_word_str, extra_flags_str);
|
||||
}
|
||||
|
||||
const char *spi_errmsg(spi_t *spi) {
|
||||
return spi->error.errmsg;
|
||||
}
|
||||
|
||||
int spi_errno(spi_t *spi) {
|
||||
return spi->error.c_errno;
|
||||
}
|
||||
|
||||
int spi_fd(spi_t *spi) {
|
||||
return spi->fd;
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* c-periphery
|
||||
* https://github.com/vsergeev/c-periphery
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
#ifndef _PERIPHERY_SPI_H
|
||||
#define _PERIPHERY_SPI_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
enum spi_error_code {
|
||||
SPI_ERROR_ARG = -1, /* Invalid arguments */
|
||||
SPI_ERROR_OPEN = -2, /* Opening SPI device */
|
||||
SPI_ERROR_QUERY = -3, /* Querying SPI device attributes */
|
||||
SPI_ERROR_CONFIGURE = -4, /* Configuring SPI device attributes */
|
||||
SPI_ERROR_TRANSFER = -5, /* SPI transfer */
|
||||
SPI_ERROR_CLOSE = -6, /* Closing SPI device */
|
||||
SPI_ERROR_UNSUPPORTED = -7, /* Unsupported attribute or operation */
|
||||
};
|
||||
|
||||
typedef enum spi_bit_order {
|
||||
MSB_FIRST,
|
||||
LSB_FIRST,
|
||||
} spi_bit_order_t;
|
||||
|
||||
typedef struct spi_handle spi_t;
|
||||
|
||||
/* Primary Functions */
|
||||
spi_t *spi_new(void);
|
||||
int spi_open(spi_t *spi, const char *path, unsigned int mode,
|
||||
uint32_t max_speed);
|
||||
int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode,
|
||||
uint32_t max_speed, spi_bit_order_t bit_order,
|
||||
uint8_t bits_per_word, uint8_t extra_flags);
|
||||
int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode,
|
||||
uint32_t max_speed, spi_bit_order_t bit_order,
|
||||
uint8_t bits_per_word, uint32_t extra_flags);
|
||||
int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len);
|
||||
int spi_close(spi_t *spi);
|
||||
void spi_free(spi_t *spi);
|
||||
|
||||
/* Getters */
|
||||
int spi_get_mode(spi_t *spi, unsigned int *mode);
|
||||
int spi_get_max_speed(spi_t *spi, uint32_t *max_speed);
|
||||
int spi_get_bit_order(spi_t *spi, spi_bit_order_t *bit_order);
|
||||
int spi_get_bits_per_word(spi_t *spi, uint8_t *bits_per_word);
|
||||
int spi_get_extra_flags(spi_t *spi, uint8_t *extra_flags);
|
||||
int spi_get_extra_flags32(spi_t *spi, uint32_t *extra_flags);
|
||||
|
||||
/* Setters */
|
||||
int spi_set_mode(spi_t *spi, unsigned int mode);
|
||||
int spi_set_max_speed(spi_t *spi, uint32_t max_speed);
|
||||
int spi_set_bit_order(spi_t *spi, spi_bit_order_t bit_order);
|
||||
int spi_set_bits_per_word(spi_t *spi, uint8_t bits_per_word);
|
||||
int spi_set_extra_flags(spi_t *spi, uint8_t extra_flags);
|
||||
int spi_set_extra_flags32(spi_t *spi, uint32_t extra_flags);
|
||||
|
||||
/* Miscellaneous */
|
||||
int spi_fd(spi_t *spi);
|
||||
int spi_tostring(spi_t *spi, char *str, size_t len);
|
||||
|
||||
/* Error Handling */
|
||||
int spi_errno(spi_t *spi);
|
||||
const char *spi_errmsg(spi_t *spi);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue