125 lines
2.8 KiB
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;
|
|
}
|
|
|