sk6812d/src/sk6812.c

125 lines
2.8 KiB
C

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "logger.h"
#include "sk6812.h"
int sk6812_init(struct sk6812_ctx *ctx, uint32_t gpio_idx, void *phys_baseptr, uint32_t num_modules)
{
ctx->gpio_idx = gpio_idx;
/*
* Setup memory map for LED memory.
*/
size_t mapsize = num_modules*sizeof(uint32_t);
size_t pagesize = (size_t)getpagesize();
if((mapsize % pagesize) != 0) {
mapsize = pagesize * (mapsize / pagesize + 1);
}
ctx->devmem_fd = open("/dev/mem", O_RDWR|O_SYNC);
if(ctx->devmem_fd == -1) {
LOG(LVL_ERR, "sk6812: open(/dev/mem) failed: %s.", strerror(errno));
return -1;
}
ctx->memptr = (struct sk6812_memory*)mmap(0, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, ctx->devmem_fd, (off_t)phys_baseptr);
if(ctx->memptr == MAP_FAILED) {
LOG(LVL_ERR, "sk6812: mmap(0x%08X) failed: %s.", phys_baseptr, strerror(errno));
close(ctx->devmem_fd);
return -1;
}
ctx->mapped_size = mapsize;
// write number of modules to mapped memory
ctx->memptr->num_leds = num_modules;
/*
* set up GPIO
*/
char filename[256];
char data[32];
int dlen;
int fd = open("/sys/class/gpio/export", O_WRONLY);
if(ctx->devmem_fd == -1) {
LOG(LVL_ERR, "sk6812: open(/sys/class/gpio/export, WRONLY) failed: %s.", strerror(errno));
return -1;
}
dlen = snprintf(data, 32, "%d\n", ctx->gpio_idx);
write(fd, data, dlen);
close(fd);
snprintf(filename, 256, "/sys/class/gpio/gpio%u/direction", ctx->gpio_idx);
fd = open(filename, O_WRONLY);
if(ctx->devmem_fd == -1) {
LOG(LVL_ERR, "sk6812: open(%s, WRONLY) failed: %s.", filename, strerror(errno));
return -1;
}
write(fd, "out\n", 4);
close(fd);
return 0;
}
void sk6812_shutdown(struct sk6812_ctx *ctx)
{
munmap(ctx->memptr, ctx->mapped_size);
close(ctx->devmem_fd);
}
void sk6812_set_colour(struct sk6812_ctx *ctx, uint32_t module, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
{
// despite the info in the datasheet, red and green are swapped :/
uint32_t value =
((uint32_t)green << 24U) |
((uint32_t)red << 16U) |
((uint32_t)blue << 8U) |
(uint32_t)white;
ctx->memptr->led_data[module] = value;
}
int sk6812_send_update(struct sk6812_ctx *ctx)
{
LOG(LVL_DEBUG, "Updating with LED count: %u", ctx->memptr->num_leds);
char filename[256];
snprintf(filename, 256, "/sys/class/gpio/gpio%u/value", ctx->gpio_idx);
int fd = open(filename, O_WRONLY);
if(ctx->devmem_fd == -1) {
LOG(LVL_ERR, "sk6812: open(%s, WRONLY) failed: %s.", filename, strerror(errno));
return -1;
}
write(fd, "0\n", 2);
close(fd);
fd = open(filename, O_WRONLY);
if(ctx->devmem_fd == -1) {
LOG(LVL_ERR, "sk6812: open(%s, WRONLY) failed: %s.", filename, strerror(errno));
return -1;
}
write(fd, "1\n", 2);
close(fd);
return 0;
}