#include #include #include #include #include #include #include #include #include "logger.h" #include "hat_spi.h" static const char *spi_dev = "/dev/spidev0.0"; static const uint32_t spi_speed = 12000000; // clock freq in Hz static const uint16_t spi_delay = 0; // us static const uint8_t spi_bits = 8; // bits per word int hat_spi_init(struct hat_spi_ctx *ctx) { // Initialize SPI uint8_t spi_mode = 0; ctx->spidev_fd = open(spi_dev, O_RDWR); if(ctx->spidev_fd < 0) { LOG(LVL_ERR, "hat_spi: cannot open %s: %s", spi_dev, strerror(errno)); return -1; } if(ioctl(ctx->spidev_fd, SPI_IOC_WR_MODE, &spi_mode) == -1) { LOG(LVL_ERR, "hat_spi: cannot change SPI mode: %s", strerror(errno)); return -1; } if(ioctl(ctx->spidev_fd, SPI_IOC_WR_BITS_PER_WORD, &spi_bits) == -1) { LOG(LVL_ERR, "hat_spi: cannot change SPI bits per word: %s", strerror(errno)); return -1; } if(ioctl(ctx->spidev_fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi_speed) == -1) { LOG(LVL_ERR, "hat_spi: cannot change SPI speed: %s", strerror(errno)); return -1; } return 0; } int hat_spi_set_data(struct hat_spi_ctx *ctx, uint8_t strip, size_t len, uint8_t *data) { uint8_t message[4 + len]; message[0] = 0x02; // cmd message[1] = strip; // buffer index message[2] = 0x00; // start offset (LSB) message[3] = 0x00; // start offset (MSB) memcpy(message + 4, data, len); struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)message, .rx_buf = (unsigned long)NULL, .len = sizeof(message), .delay_usecs = spi_delay, .speed_hz = spi_speed, .bits_per_word = 8 }; int ret; if((ret = ioctl(ctx->spidev_fd, SPI_IOC_MESSAGE(1), &tr)) < 0) { LOG(LVL_ERR, "ws2801: set_data: could not send SPI message: %s", strerror(errno)); } return ret; } int hat_spi_flush(struct hat_spi_ctx *ctx) { uint8_t message[1]; message[0] = 0x80; // cmd struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)message, .rx_buf = (unsigned long)NULL, .len = sizeof(message), .delay_usecs = spi_delay, .speed_hz = spi_speed, .bits_per_word = 8 }; int ret; if((ret = ioctl(ctx->spidev_fd, SPI_IOC_MESSAGE(1), &tr)) < 0) { LOG(LVL_ERR, "ws2801: flush: could not send SPI message: %s", strerror(errno)); } return ret; } int hat_spi_config(struct hat_spi_ctx *ctx, uint16_t data_len) { uint8_t message[3]; message[0] = 0x01; // cmd message[1] = data_len & 0xFF; // bytes per strip (LSB) message[2] = (data_len >> 8) & 0xFF; // bytes per strip (MSB) struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)message, .rx_buf = (unsigned long)NULL, .len = sizeof(message), .delay_usecs = spi_delay, .speed_hz = spi_speed, .bits_per_word = 8 }; int ret; if((ret = ioctl(ctx->spidev_fd, SPI_IOC_MESSAGE(1), &tr)) < 0) { LOG(LVL_ERR, "ws2801: flush: could not send SPI message: %s", strerror(errno)); } return ret; } void hat_spi_shutdown(struct hat_spi_ctx *ctx) { close(ctx->spidev_fd); }