First steps towards RaspberryPi hat support

- Allow to have multiple faders/strips
- Added strip ID to UDP protocol
This commit is contained in:
Thomas Kolb 2018-07-30 22:56:18 +02:00
parent 3afbd516b4
commit 8bc5d05ec1
5 changed files with 136 additions and 120 deletions

View file

@ -6,102 +6,80 @@
#include "fader.h" #include "fader.h"
uint32_t numModules; int fader_init(struct fader_ctx *ctx, uint32_t nMod, struct sk6812_ctx *ledCtx)
float fadestep = 1;
double nextFrame;
int somethingChanged = 0; // indicates when a sk6812 update is required
static const double interval = 1.0f / 75.0f;
struct Colour {
float red, green, blue, white; // value range is 0.0 to 255.0
};
struct Colour *curColour;
struct Colour *targetColour;
struct sk6812_ctx *ledCtx; // global context for the one strip we control
int fader_init(uint32_t nMod, struct sk6812_ctx *ctx)
{ {
numModules = nMod; ctx->num_modules = nMod;
ctx->fadestep = 1;
curColour = malloc(nMod * sizeof(struct Colour)); ctx->cur_colour = malloc(nMod * sizeof(struct fader_colour));
if(!curColour) { if(!ctx->cur_colour) {
LOG(LVL_ERR, "fader: could not allocate the array of current colours!"); LOG(LVL_ERR, "fader: could not allocate the array of current colours!");
return -1; return -1;
} }
targetColour = malloc(nMod * sizeof(struct Colour)); ctx->target_colour = malloc(nMod * sizeof(struct fader_colour));
if(!targetColour) { if(!ctx->target_colour) {
LOG(LVL_ERR, "fader: could not allocate the array of target colours!"); LOG(LVL_ERR, "fader: could not allocate the array of target colours!");
return -1; return -1;
} }
for(uint32_t i = 0; i < numModules; i++) { for(uint32_t i = 0; i < ctx->num_modules; i++) {
curColour[i].red = targetColour[i].red = 0; ctx->cur_colour[i].red = ctx->target_colour[i].red = 0;
curColour[i].green = targetColour[i].green = 0; ctx->cur_colour[i].green = ctx->target_colour[i].green = 0;
curColour[i].blue = targetColour[i].blue = 0; ctx->cur_colour[i].blue = ctx->target_colour[i].blue = 0;
curColour[i].white = targetColour[i].white = 0; ctx->cur_colour[i].white = ctx->target_colour[i].white = 0;
} }
// store LED context (initalized externally) // store LED context (initalized externally)
ledCtx = ctx; ctx->led_ctx = ledCtx;
// timestamp for the first frame
nextFrame = get_hires_time() + interval;
return 0; return 0;
} }
void fader_shutdown(void) void fader_shutdown(struct fader_ctx *ctx)
{ {
free(curColour); free(ctx->cur_colour);
free(targetColour); free(ctx->target_colour);
} }
void fader_set_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w) void fader_set_colour(struct fader_ctx *ctx, uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{ {
curColour[module].red = targetColour[module].red = r; ctx->cur_colour[module].red = ctx->target_colour[module].red = r;
curColour[module].green = targetColour[module].green = g; ctx->cur_colour[module].green = ctx->target_colour[module].green = g;
curColour[module].blue = targetColour[module].blue = b; ctx->cur_colour[module].blue = ctx->target_colour[module].blue = b;
curColour[module].white = targetColour[module].white = w; ctx->cur_colour[module].white = ctx->target_colour[module].white = w;
somethingChanged = 1; ctx->something_changed = 1;
} }
void fader_fade_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w) void fader_fade_colour(struct fader_ctx *ctx, uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{ {
targetColour[module].red = r; ctx->target_colour[module].red = r;
targetColour[module].green = g; ctx->target_colour[module].green = g;
targetColour[module].blue = b; ctx->target_colour[module].blue = b;
targetColour[module].white = w; ctx->target_colour[module].white = w;
} }
void fader_add_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w) void fader_add_colour(struct fader_ctx *ctx, uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{ {
curColour[module].red += r; ctx->cur_colour[module].red += r;
curColour[module].green += g; ctx->cur_colour[module].green += g;
curColour[module].blue += b; ctx->cur_colour[module].blue += b;
curColour[module].white += w; ctx->cur_colour[module].white += w;
if(curColour[module].red > 255) { curColour[module].red = 255; } if(ctx->cur_colour[module].red > 255) { ctx->cur_colour[module].red = 255; }
if(curColour[module].green > 255) { curColour[module].green = 255; } if(ctx->cur_colour[module].green > 255) { ctx->cur_colour[module].green = 255; }
if(curColour[module].blue > 255) { curColour[module].blue = 255; } if(ctx->cur_colour[module].blue > 255) { ctx->cur_colour[module].blue = 255; }
if(curColour[module].white > 255) { curColour[module].white = 255; } if(ctx->cur_colour[module].white > 255) { ctx->cur_colour[module].white = 255; }
targetColour[module] = curColour[module]; ctx->target_colour[module] = ctx->cur_colour[module];
somethingChanged = 1; ctx->something_changed = 1;
} }
void fader_set_fadestep(uint8_t newFadestep) void fader_set_fadestep(struct fader_ctx *ctx, uint8_t newFadestep)
{ {
// The original avr implementition had a frame rate of 25fps (interval 0,04 sec.). ctx->fadestep = newFadestep;
// This scales the fadestep to the current frame rate.
fadestep = (float)newFadestep * interval / 0.04f;
} }
/*! /*!
@ -111,53 +89,47 @@ void fader_set_fadestep(uint8_t newFadestep)
* \param target The target value that should be reached. * \param target The target value that should be reached.
* \param changed Output value which is set to 1 if cur was changed. * \param changed Output value which is set to 1 if cur was changed.
*/ */
void fade_colour(float *cur, const float *target, int *changed) void fade_colour(struct fader_ctx *ctx, float *cur, const float *target, int *changed)
{ {
float diff; float diff;
if(*cur > *target) { if(*cur > *target) {
diff = *cur - *target; diff = *cur - *target;
if(diff < fadestep) { if(diff < ctx->fadestep) {
*cur = *target; *cur = *target;
} else { } else {
*cur -= fadestep; *cur -= ctx->fadestep;
} }
*changed = 1; *changed = 1;
} else if(*cur < *target) { } else if(*cur < *target) {
diff = *target - *cur; diff = *target - *cur;
if(diff < fadestep) { if(diff < ctx->fadestep) {
*cur = *target; *cur = *target;
} else { } else {
*cur += fadestep; *cur += ctx->fadestep;
} }
*changed = 1; *changed = 1;
} }
} }
void fader_update(void) void fader_update(struct fader_ctx *ctx)
{ {
for(uint32_t i = 0; i < numModules; i++) { for(uint32_t i = 0; i < ctx->num_modules; i++) {
fade_colour(&(curColour[i].red), &(targetColour[i].red), &somethingChanged); fade_colour(ctx, &(ctx->cur_colour[i].red), &(ctx->target_colour[i].red), &ctx->something_changed);
fade_colour(&(curColour[i].green), &(targetColour[i].green), &somethingChanged); fade_colour(ctx, &(ctx->cur_colour[i].green), &(ctx->target_colour[i].green), &ctx->something_changed);
fade_colour(&(curColour[i].blue), &(targetColour[i].blue), &somethingChanged); fade_colour(ctx, &(ctx->cur_colour[i].blue), &(ctx->target_colour[i].blue), &ctx->something_changed);
fade_colour(&(curColour[i].white), &(targetColour[i].white), &somethingChanged); fade_colour(ctx, &(ctx->cur_colour[i].white), &(ctx->target_colour[i].white), &ctx->something_changed);
sk6812_set_colour(ledCtx, i, sk6812_set_colour(ctx->led_ctx, i,
(uint8_t)curColour[i].red, (uint8_t)ctx->cur_colour[i].red,
(uint8_t)curColour[i].green, (uint8_t)ctx->cur_colour[i].green,
(uint8_t)curColour[i].blue, (uint8_t)ctx->cur_colour[i].blue,
(uint8_t)curColour[i].white); (uint8_t)ctx->cur_colour[i].white);
} }
if(somethingChanged) { if(ctx->something_changed) {
sk6812_send_update(ledCtx); sk6812_send_update(ctx->led_ctx);
somethingChanged = 0; ctx->something_changed = 0;
} }
} }
void fader_wait_frame(void)
{
sleep_until(nextFrame);
nextFrame += interval;
}

View file

@ -5,13 +5,29 @@
struct sk6812_ctx; struct sk6812_ctx;
int fader_init(uint32_t nMod, struct sk6812_ctx *ctx); struct fader_colour {
void fader_shutdown(void); float red, green, blue, white; // value range is 0.0 to 255.0
void fader_set_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w); };
void fader_fade_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void fader_add_colour(uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w); struct fader_ctx {
void fader_set_fadestep(uint8_t newFadestep); uint32_t num_modules;
void fader_update(void);
void fader_wait_frame(void); struct fader_colour *cur_colour;
struct fader_colour *target_colour;
struct sk6812_ctx *led_ctx;
uint8_t something_changed;
float fadestep;
};
int fader_init(struct fader_ctx *ctx, uint32_t nMod, struct sk6812_ctx *ledCtx);
void fader_shutdown(struct fader_ctx *ctx);
void fader_set_colour(struct fader_ctx *ctx, uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void fader_fade_colour(struct fader_ctx *ctx, uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void fader_add_colour(struct fader_ctx *ctx, uint32_t module, uint8_t r, uint8_t g, uint8_t b, uint8_t w);
void fader_set_fadestep(struct fader_ctx *ctx, uint8_t newFadestep);
void fader_update(struct fader_ctx *ctx);
#endif // FADER_H #endif // FADER_H

View file

@ -11,6 +11,7 @@
#include "logger.h" #include "logger.h"
#include "fader.h" #include "fader.h"
#include "udpproto.h" #include "udpproto.h"
#include "utils.h"
#define PORT 2703 #define PORT 2703
@ -18,6 +19,8 @@
#define GPIO_IDX 960 #define GPIO_IDX 960
#define BASE_ADDR ((void*)0x40000000U) #define BASE_ADDR ((void*)0x40000000U)
#define INTERVAL 0.01
struct CmdLineArgs { struct CmdLineArgs {
uint16_t port; uint16_t port;
void *base_addr; void *base_addr;
@ -25,6 +28,12 @@ struct CmdLineArgs {
uint32_t num_modules; uint32_t num_modules;
}; };
void wait_frame(double *nextFrame, double interval)
{
sleep_until(*nextFrame);
*nextFrame += interval;
}
int parse_args(int argc, char **argv, struct CmdLineArgs *args) int parse_args(int argc, char **argv, struct CmdLineArgs *args)
{ {
int opt; int opt;
@ -67,9 +76,12 @@ int parse_args(int argc, char **argv, struct CmdLineArgs *args)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct sk6812_ctx ctx; struct sk6812_ctx ctx;
struct fader_ctx fader_ctx;
struct CmdLineArgs args; struct CmdLineArgs args;
double nextFrame = get_hires_time() + INTERVAL;
// initialize logger // initialize logger
logger_init(); logger_init();
@ -86,12 +98,6 @@ int main(int argc, char **argv)
return 1; return 1;
} }
// initialise the UDP server
if(udpproto_init(PORT) == -1) {
LOG(LVL_FATAL, "Could not initialize the UDP server.");
return 1;
}
// initialize ws2801 library // initialize ws2801 library
if(sk6812_init(&ctx, GPIO_IDX, BASE_ADDR, NUM_MODULES) == -1) { if(sk6812_init(&ctx, GPIO_IDX, BASE_ADDR, NUM_MODULES) == -1) {
LOG(LVL_FATAL, "Could not initialize SK6812 library."); LOG(LVL_FATAL, "Could not initialize SK6812 library.");
@ -99,23 +105,29 @@ int main(int argc, char **argv)
} }
// initialise the LED fader // initialise the LED fader
if(fader_init(NUM_MODULES, &ctx) == -1) { if(fader_init(&fader_ctx, NUM_MODULES, &ctx) == -1) {
LOG(LVL_FATAL, "Could not initialize the LED fader."); LOG(LVL_FATAL, "Could not initialize the LED fader.");
return 1; return 1;
} }
// initialise the UDP server
if(udpproto_init(PORT, &fader_ctx, 1) == -1) {
LOG(LVL_FATAL, "Could not initialize the UDP server.");
return 1;
}
LOG(LVL_INFO, "Initialisation complete."); LOG(LVL_INFO, "Initialisation complete.");
while(1) { while(1) {
udpproto_process(); udpproto_process();
fader_update(); fader_update(&fader_ctx);
fader_wait_frame(); wait_frame(&nextFrame, INTERVAL);
} }
// shut down all modules // shut down all modules
fader_shutdown();
sk6812_shutdown(&ctx);
udpproto_shutdown(); udpproto_shutdown();
fader_shutdown(&fader_ctx);
sk6812_shutdown(&ctx);
return 0; return 0;
} }

View file

@ -17,14 +17,19 @@
#define ADD_COLOUR 2 #define ADD_COLOUR 2
#define SET_FADESTEP 3 #define SET_FADESTEP 3
#define BYTES_PER_PACKET 7 #define BYTES_PER_PACKET 8
int sock; int sock;
struct fader_ctx *udpproto_faders;
uint32_t udpproto_nstrips;
int udpproto_init(uint16_t port) int udpproto_init(uint16_t port, struct fader_ctx *faders, uint32_t nstrips)
{ {
struct sockaddr_in listen_addr; struct sockaddr_in listen_addr;
udpproto_nstrips = nstrips;
udpproto_faders = faders;
// initialize UDP server socket // initialize UDP server socket
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sock == -1) { if(sock == -1) {
@ -52,10 +57,12 @@ int udpproto_process(void)
uint8_t pkgbuf[65536]; uint8_t pkgbuf[65536];
ssize_t rcvbytes, offset = 0; ssize_t rcvbytes, offset = 0;
uint8_t r, g, b, w, action; uint8_t r, g, b, w, action, strip;
uint16_t module; uint16_t module;
int fds_ready; int fds_ready;
struct fader_ctx *fader;
// check if there is data to be read (to prevent blocking) // check if there is data to be read (to prevent blocking)
struct pollfd pfd = { struct pollfd pfd = {
.fd = sock, .fd = sock,
@ -86,29 +93,36 @@ int udpproto_process(void)
offset = 0; offset = 0;
while(offset <= rcvbytes - BYTES_PER_PACKET) { while(offset <= rcvbytes - BYTES_PER_PACKET) {
action = pkgbuf[offset + 0]; action = pkgbuf[offset + 0];
module = (uint16_t)pkgbuf[offset + 1] << 8; strip = pkgbuf[offset + 1];
module |= pkgbuf[offset + 2]; module = (uint16_t)pkgbuf[offset + 2] << 8;
r = pkgbuf[offset + 3]; module |= pkgbuf[offset + 3];
g = pkgbuf[offset + 4]; r = pkgbuf[offset + 4];
b = pkgbuf[offset + 5]; g = pkgbuf[offset + 5];
w = pkgbuf[offset + 6]; b = pkgbuf[offset + 6];
w = pkgbuf[offset + 7];
offset += BYTES_PER_PACKET; offset += BYTES_PER_PACKET;
if(strip > udpproto_nstrips) {
continue;
}
fader = udpproto_faders + strip;
switch(action) { switch(action) {
case SET_COLOUR: case SET_COLOUR:
fader_set_colour(module, r, g, b, w); fader_set_colour(fader, module, r, g, b, w);
break; break;
case FADE_COLOUR: case FADE_COLOUR:
fader_fade_colour(module, r, g, b, w); fader_fade_colour(fader, module, r, g, b, w);
break; break;
case ADD_COLOUR: case ADD_COLOUR:
fader_add_colour(module, r, g, b, w); fader_add_colour(fader, module, r, g, b, w);
break; break;
case SET_FADESTEP: case SET_FADESTEP:
fader_set_fadestep(r); // red channel contains the fadestep in this case fader_set_fadestep(fader, r); // red channel contains the fadestep in this case
break; break;
default: default:

View file

@ -3,7 +3,9 @@
#include <stdint.h> #include <stdint.h>
int udpproto_init(uint16_t port); struct fader_ctx;
int udpproto_init(uint16_t port, struct fader_ctx *faders, uint32_t nstrips);
int udpproto_process(void); int udpproto_process(void);
void udpproto_shutdown(void); void udpproto_shutdown(void);