logging facility (log.c librarie), template, minor bug fixes, param init
This commit is contained in:
parent
a5da739f65
commit
0ccd9e7d46
@ -1,28 +1,34 @@
|
||||
CC := gcc
|
||||
CFLAGS := -Wall -g -D_DEBUG
|
||||
LDFLAGS := -lwiringPi -lasound -lfftw3 -lpthread -lm
|
||||
CFLAGS := -Wall -g -Ilibs/log.c/src
|
||||
LDFLAGS := -lwiringPi -lasound -lfftw3 -lpthread -lm -L.libs
|
||||
|
||||
SRC := src
|
||||
OBJ := obj
|
||||
BIN := bin/pixled
|
||||
|
||||
SOURCES := $(shell find $(SRC) -type f -name "*.c")
|
||||
SOURCES := $(shell find $(SRC) -type f -name "*.c")
|
||||
OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
|
||||
|
||||
|
||||
.PHONY: all clean debug
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
libs/log.c/obj/log.o: libs/log.c/src/log.c
|
||||
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
|
||||
$(CC) -c $< -o $@ -DLOG_USE_COLOR
|
||||
|
||||
.libs/log.la: libs/log.c/obj/log.o
|
||||
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
|
||||
ar r $@ $^
|
||||
ranlib $@
|
||||
|
||||
$(OBJ)/%.o: $(SRC)/%.c
|
||||
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
|
||||
$(CC) -I$(SRC) -c $< -o $@ $(CFLAGS)
|
||||
$(CC) -c $< -o $@ $(CFLAGS)
|
||||
|
||||
$(BIN) : $(OBJECTS)
|
||||
if [ ! -d "$(dir $(BIN))" ]; then mkdir -p "$(dir $(BIN))"; fi
|
||||
$(BIN): $(OBJECTS) .libs/log.la
|
||||
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
liblog.a: log.o
|
||||
ar $(ARFLAGS) $@ $^
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ)
|
||||
rm -rf $(OBJ) .libs libs/*/obj
|
@ -1,6 +1,7 @@
|
||||
https://makersportal.com/blog/recording-stereo-audio-on-a-raspberry-pi
|
||||
https://learn.adafruit.com/adafruit-i2s-mems-microphone-breakout/raspberry-pi-wiring-test
|
||||
|
||||
sudo apt install python3-pip
|
||||
sudo pip3 install --upgrade adafruit-python-shell
|
||||
cd /tmp
|
||||
sudo wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/i2smic.py
|
||||
@ -15,4 +16,14 @@ arecord -D plughw:1 -c1 -r 48000 -f S32_LE -t wav -V mono -v file.wav
|
||||
cp res/.asoundrc ~/.asoundrc
|
||||
|
||||
# alsa API
|
||||
http://www.equalarea.com/paul/alsa-audio.html
|
||||
http://www.equalarea.com/paul/alsa-audio.html
|
||||
|
||||
# for project
|
||||
sudo apt install libasound2-dev wiringpi
|
||||
|
||||
# for cava
|
||||
sudo apt install libfftw3-dev libasound2-dev libtool automake
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
@ -3,9 +3,12 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
// Use mmap to obtain virtual address, given physical
|
||||
void *map_periph(MEM_MAP *mp, void *phys, int size) {
|
||||
mp->phys = phys;
|
||||
@ -30,20 +33,24 @@ void *map_segment(void *addr, int size) {
|
||||
void *mem;
|
||||
|
||||
size = PAGE_ROUNDUP(size);
|
||||
if ((fd = open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0)
|
||||
fprintf(stderr, "Error: can't open /dev/mem, run using sudo\n");
|
||||
if ((fd = open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0) {
|
||||
log_fatal("can't open /dev/mem, run using sudo");
|
||||
exit(-EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mem = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, (uint32_t)addr);
|
||||
close(fd);
|
||||
#if DEBUG
|
||||
printf("Map %p -> %p\n", (void *)addr, mem);
|
||||
#endif
|
||||
if (mem == MAP_FAILED)
|
||||
fprintf(stderr, "Error: can't map memory\n");
|
||||
log_info("Map %p -> %p", (void *)addr, mem);
|
||||
if (mem == MAP_FAILED) {
|
||||
log_fatal("can't map memory");
|
||||
exit(-EXIT_FAILURE);
|
||||
}
|
||||
return (mem);
|
||||
}
|
||||
|
||||
// Free mapped memory
|
||||
void unmap_segment(void *mem, int size) {
|
||||
if (mem)
|
||||
if (mem) {
|
||||
munmap(mem, PAGE_ROUNDUP(size));
|
||||
}
|
||||
}
|
@ -5,6 +5,8 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
// Mailbox command/response structure
|
||||
typedef struct {
|
||||
uint32_t len, // Overall length (bytes)
|
||||
@ -42,7 +44,7 @@ void *map_uncached_mem(MEM_MAP *mp, int size) {
|
||||
(mp->virt = map_segment(BUS_PHYS_ADDR(mp->bus), mp->size)) != 0
|
||||
? mp->virt
|
||||
: 0;
|
||||
printf("VC mem handle %u, phys %p, virt %p\n", mp->h, mp->bus, mp->virt);
|
||||
log_info("VC mem handle %u, phys %p, virt %p", mp->h, mp->bus, mp->virt);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@ -93,7 +95,7 @@ int open_mbox(void) {
|
||||
int fd;
|
||||
|
||||
if ((fd = open("/dev/vcio", 0)) < 0)
|
||||
fprintf(stderr, "Error: can't open VC mailbox\n");
|
||||
log_error("can't open VC mailbox");
|
||||
return (fd);
|
||||
}
|
||||
// Close mailbox interface
|
||||
@ -110,14 +112,15 @@ uint32_t msg_mbox(int fd, VC_MSG *msgp) {
|
||||
msgp->uints[i++] = 0;
|
||||
msgp->len = (msgp->blen + 6) * 4;
|
||||
msgp->req = 0;
|
||||
if (ioctl(fd, _IOWR(100, 0, void *), msgp) < 0)
|
||||
printf("VC IOCTL failed\n");
|
||||
else if ((msgp->req & 0x80000000) == 0)
|
||||
printf("VC IOCTL error\n");
|
||||
else if (msgp->req == 0x80000001)
|
||||
printf("VC IOCTL partial error\n");
|
||||
else
|
||||
if (ioctl(fd, _IOWR(100, 0, void *), msgp) < 0) {
|
||||
log_error("VC IOCTL failed");
|
||||
} else if ((msgp->req & 0x80000000) == 0) {
|
||||
log_error("VC IOCTL error");
|
||||
} else if (msgp->req == 0x80000001) {
|
||||
log_error("VC IOCTL partial error");
|
||||
} else {
|
||||
ret = msgp->uints[0];
|
||||
}
|
||||
#if DEBUG
|
||||
disp_vc_msg(msgp);
|
||||
#endif
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../../rpi_param.h"
|
||||
#include "../common.h"
|
||||
|
||||
#include "../dma/rpi_dma.h"
|
||||
@ -49,13 +50,12 @@ TXDATA_T tx_buffer[TX_BUFF_LEN(CHAN_MAXLEDS)];
|
||||
void swap_bytes();
|
||||
|
||||
void leddriver_setup() {
|
||||
gpio_setup();
|
||||
videocore_setup(&vc_mem, VC_MEM_SIZE);
|
||||
gpio_setup();
|
||||
smi_setup(LED_NCHANS, SMI_TIMING, &vc_mem, TX_BUFF_LEN(CHAN_MAXLEDS), &txdata);
|
||||
}
|
||||
|
||||
void leddriver_close() {
|
||||
printf("Closing\n");
|
||||
videocore_close(&vc_mem);
|
||||
smi_close(LED_NCHANS);
|
||||
gpio_close();
|
||||
@ -129,4 +129,82 @@ void swap_bytes() {
|
||||
*wp = __builtin_bswap16(*wp);
|
||||
wp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* source :
|
||||
* https://github.com/adafruit/Adafruit_NeoPixel/blob/216ccdbff399750f5b02d4cc804c598399e39713/Adafruit_NeoPixel.cpp#L2414
|
||||
*/
|
||||
uint32_t ColorHSV(uint16_t hue, uint8_t sat, uint8_t val) {
|
||||
|
||||
uint8_t r, g, b;
|
||||
|
||||
// Remap 0-65535 to 0-1529. Pure red is CENTERED on the 64K rollover;
|
||||
// 0 is not the start of pure red, but the midpoint...a few values above
|
||||
// zero and a few below 65536 all yield pure red (similarly, 32768 is the
|
||||
// midpoint, not start, of pure cyan). The 8-bit RGB hexcone (256 values
|
||||
// each for red, green, blue) really only allows for 1530 distinct hues
|
||||
// (not 1536, more on that below), but the full unsigned 16-bit type was
|
||||
// chosen for hue so that one's code can easily handle a contiguous color
|
||||
// wheel by allowing hue to roll over in either direction.
|
||||
hue = (hue * 1530L + 32768) / 65536;
|
||||
// Because red is centered on the rollover point (the +32768 above,
|
||||
// essentially a fixed-point +0.5), the above actually yields 0 to 1530,
|
||||
// where 0 and 1530 would yield the same thing. Rather than apply a
|
||||
// costly modulo operator, 1530 is handled as a special case below.
|
||||
|
||||
// So you'd think that the color "hexcone" (the thing that ramps from
|
||||
// pure red, to pure yellow, to pure green and so forth back to red,
|
||||
// yielding six slices), and with each color component having 256
|
||||
// possible values (0-255), might have 1536 possible items (6*256),
|
||||
// but in reality there's 1530. This is because the last element in
|
||||
// each 256-element slice is equal to the first element of the next
|
||||
// slice, and keeping those in there this would create small
|
||||
// discontinuities in the color wheel. So the last element of each
|
||||
// slice is dropped...we regard only elements 0-254, with item 255
|
||||
// being picked up as element 0 of the next slice. Like this:
|
||||
// Red to not-quite-pure-yellow is: 255, 0, 0 to 255, 254, 0
|
||||
// Pure yellow to not-quite-pure-green is: 255, 255, 0 to 1, 255, 0
|
||||
// Pure green to not-quite-pure-cyan is: 0, 255, 0 to 0, 255, 254
|
||||
// and so forth. Hence, 1530 distinct hues (0 to 1529), and hence why
|
||||
// the constants below are not the multiples of 256 you might expect.
|
||||
|
||||
// Convert hue to R,G,B (nested ifs faster than divide+mod+switch):
|
||||
if (hue < 510) { // Red to Green-1
|
||||
b = 0;
|
||||
if (hue < 255) { // Red to Yellow-1
|
||||
r = 255;
|
||||
g = hue; // g = 0 to 254
|
||||
} else { // Yellow to Green-1
|
||||
r = 510 - hue; // r = 255 to 1
|
||||
g = 255;
|
||||
}
|
||||
} else if (hue < 1020) { // Green to Blue-1
|
||||
r = 0;
|
||||
if (hue < 765) { // Green to Cyan-1
|
||||
g = 255;
|
||||
b = hue - 510; // b = 0 to 254
|
||||
} else { // Cyan to Blue-1
|
||||
g = 1020 - hue; // g = 255 to 1
|
||||
b = 255;
|
||||
}
|
||||
} else if (hue < 1530) { // Blue to Red-1
|
||||
g = 0;
|
||||
if (hue < 1275) { // Blue to Magenta-1
|
||||
r = hue - 1020; // r = 0 to 254
|
||||
b = 255;
|
||||
} else { // Magenta to Red-1
|
||||
r = 255;
|
||||
b = 1530 - hue; // b = 255 to 1
|
||||
}
|
||||
} else { // Last 0.5 Red (quicker than % operator)
|
||||
r = 255;
|
||||
g = b = 0;
|
||||
}
|
||||
|
||||
// Apply saturation and value to R,G,B, pack into 32-bit result:
|
||||
uint32_t v1 = 1 + val; // 1 to 256; allows >>8 instead of /255
|
||||
uint16_t s1 = 1 + sat; // 1 to 256; same reason
|
||||
uint8_t s2 = 255 - sat; // 255 to 0
|
||||
return ((((((r * s1) >> 8) + s2) * v1) & 0xff00) << 8) |
|
||||
(((((g * s1) >> 8) + s2) * v1) & 0xff00) | (((((b * s1) >> 8) + s2) * v1) >> 8);
|
||||
}
|
||||
|
@ -3,9 +3,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define CHAN_MAXLEDS 6 * 60 // Maximum number of LEDs per channel
|
||||
#define LED_NCHANS 8 // Number of LED channels (8 or 16)
|
||||
|
||||
void leddriver_setup();
|
||||
|
||||
void leddriver_close();
|
||||
|
@ -5,6 +5,8 @@
|
||||
/***************************************************************************************************
|
||||
* Includes
|
||||
**************************************************************************************************/
|
||||
#include "rpi_selector.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wiringPi.h>
|
||||
@ -19,6 +21,7 @@
|
||||
unsigned const selectorPinNumber = 4;
|
||||
/* TODO use GPIO function from ../gpio/gipo.h (same pin number) */
|
||||
int selectorPins[4] = {5, 6, 26, 27};
|
||||
char modeStr[] = "0 | 0 | 0 | 0 \n";
|
||||
|
||||
/***************************************************************************************************
|
||||
* Persistent Variables
|
||||
@ -49,12 +52,11 @@ int selector_get_position() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void selector_print() {
|
||||
char modeStr[] = "0 | 0 | 0 | 0 \n";
|
||||
char *selector_tostr() {
|
||||
for (size_t i = 0; i < selectorPinNumber; ++i) {
|
||||
modeStr[i * 4] = digitalRead(selectorPins[i]) ? '1' : '0';
|
||||
}
|
||||
fprintf(stderr, modeStr);
|
||||
return modeStr;
|
||||
}
|
||||
|
||||
/***************************************************************************************************
|
||||
|
@ -33,8 +33,8 @@ void selector_setup();
|
||||
int selector_get_position();
|
||||
|
||||
/**
|
||||
* \brief debug: print the selector position
|
||||
* \brief Get string with selector debug info
|
||||
**/
|
||||
void selector_print();
|
||||
char *selector_tostr();
|
||||
|
||||
#endif /* __RPI_SELECTOR_H__ */
|
@ -1,4 +1,12 @@
|
||||
/** \file main.c
|
||||
* \brief This is the main exectution program
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Includes
|
||||
**************************************************************************************************/
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
@ -8,23 +16,51 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include "drivers/leddriver/rpi_leddriver.h"
|
||||
#include "drivers/selector/rpi_selector.h"
|
||||
|
||||
#include "rpi_midi_controller.h"
|
||||
#include "tasks/artnet/rpi_artnet.h"
|
||||
#include "tasks/cava/rpi_cava.h"
|
||||
|
||||
#include "rpi_midi_controller.h"
|
||||
#include "rpi_param.h"
|
||||
|
||||
/***************************************************************************************************
|
||||
* Preprocessor Constants and Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Type and Contant Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Persistent Variables
|
||||
**************************************************************************************************/
|
||||
/* Command-line parameters */
|
||||
bool IsTestMode = false;
|
||||
int chanLedCount = 0;
|
||||
int logLevel = 2;
|
||||
|
||||
pthread_t *bgTasks[4] = {NULL};
|
||||
int previousMode = -1;
|
||||
|
||||
unsigned long mainLoopCycle = 0;
|
||||
|
||||
pthread_mutex_t logLockMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/***************************************************************************************************
|
||||
* Internal Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
void parseCommandLineArgs(int argc, char const *argv[]);
|
||||
|
||||
void terminate(int sig);
|
||||
|
||||
void manage_tasks(int previousMode, int currentMode);
|
||||
|
||||
void execute_task(int mode);
|
||||
|
||||
void execute_test_mode();
|
||||
|
||||
void execute_artnet_mode();
|
||||
@ -35,86 +71,59 @@ void execute_manual_mode();
|
||||
|
||||
void adjust_loop(struct timespec const *loopStart);
|
||||
|
||||
int main(int argc, char const *argv[]) {
|
||||
int previousMode = -1;
|
||||
void log_lock_helper(bool lock, void *udata);
|
||||
|
||||
/***************************************************************************************************
|
||||
* External Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
int main(int argc, char const *argv[]) {
|
||||
// setup
|
||||
parseCommandLineArgs(argc, argv);
|
||||
log_set_level(logLevel);
|
||||
|
||||
signal(SIGINT, terminate);
|
||||
|
||||
struct sched_param sp;
|
||||
sp.sched_priority = 32;
|
||||
if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) {
|
||||
fprintf(stderr, "WARNING: Failed to set stepper thread to real-time priority\n");
|
||||
}
|
||||
// struct sched_param sp;
|
||||
// sp.sched_priority = 32;
|
||||
// if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) {
|
||||
// fprintf(stderr, "WARNING: Failed to set stepper thread to real-time priority: %s\n",
|
||||
// strerror(errno));
|
||||
// }
|
||||
|
||||
log_set_lock(log_lock_helper, &logLockMutex);
|
||||
|
||||
param_setup();
|
||||
midi_controller_setup();
|
||||
selector_setup();
|
||||
leddriver_setup();
|
||||
|
||||
artnet_init();
|
||||
setup_cava();
|
||||
// setup_cava();
|
||||
|
||||
// loop
|
||||
while (1) {
|
||||
struct timespec loopStart;
|
||||
int mode;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &loopStart);
|
||||
int mode = selector_get_position();
|
||||
if (IsTestMode) {
|
||||
if (mainLoopCycle % 300 < 150) {
|
||||
mode = 2;
|
||||
} else {
|
||||
mode = 1;
|
||||
}
|
||||
} else {
|
||||
mode = selector_get_position();
|
||||
}
|
||||
/* todo thread ? */
|
||||
midi_controller_execute();
|
||||
|
||||
if (mode != -1) {
|
||||
if (mode != previousMode) {
|
||||
#if defined(_DEBUG)
|
||||
printf("swtching to mode : %d\n", mode);
|
||||
#endif
|
||||
/* stop previous bg task */
|
||||
switch (previousMode) {
|
||||
case 1:
|
||||
artnet_stop();
|
||||
break;
|
||||
case 2:
|
||||
stop_cava_bg_worker();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* start new bg task */
|
||||
switch (mode) {
|
||||
case 1:
|
||||
artnet_start();
|
||||
break;
|
||||
case 2:
|
||||
start_cava_bg_worker();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
log_info("swtching to mode : %d", mode);
|
||||
manage_tasks(previousMode, mode);
|
||||
} else {
|
||||
switch (mode) {
|
||||
case 0:
|
||||
// mode test
|
||||
execute_test_mode();
|
||||
break;
|
||||
case 1:
|
||||
// artnet mode
|
||||
execute_artnet_mode();
|
||||
break;
|
||||
case 2:
|
||||
execute_autonomous_mode();
|
||||
break;
|
||||
case 3:
|
||||
// manual mode
|
||||
execute_manual_mode();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (mode != previousMode) {
|
||||
fprintf(stderr, "Error in selector\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
execute_task(mode);
|
||||
}
|
||||
previousMode = mode;
|
||||
}
|
||||
@ -122,6 +131,10 @@ int main(int argc, char const *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************************
|
||||
* Internal Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
void parseCommandLineArgs(int argc, char const *argv[]) {
|
||||
int args = 0;
|
||||
|
||||
@ -130,28 +143,90 @@ void parseCommandLineArgs(int argc, char const *argv[]) {
|
||||
if (argv[args][0] == '-') {
|
||||
switch (toupper(argv[args][1])) {
|
||||
case 'N': // -N: number of LEDs per channel
|
||||
if (args >= argc - 1)
|
||||
fprintf(stderr, "Error: no numeric value\n");
|
||||
else
|
||||
if (args >= argc - 1) {
|
||||
log_error("no numeric value");
|
||||
exit(-EXIT_FAILURE);
|
||||
} else {
|
||||
chanLedCount = atoi(argv[++args]);
|
||||
}
|
||||
break;
|
||||
case 'D': // -D: debug level
|
||||
if (args >= argc - 1) {
|
||||
log_error("no debug level");
|
||||
exit(-EXIT_FAILURE);
|
||||
} else {
|
||||
logLevel = atoi(argv[++args]);
|
||||
}
|
||||
break;
|
||||
case 'T': // -T: test mode
|
||||
IsTestMode = true;
|
||||
break;
|
||||
default: // Otherwise error
|
||||
printf("Unrecognised option '%c'\n", argv[args][1]);
|
||||
printf("Options:\n"
|
||||
" -n num number of LEDs per channel\n"
|
||||
" -t Test mode (flash LEDs)\n");
|
||||
exit(1);
|
||||
log_error("Unrecognised option '%c'\n", argv[args][1]);
|
||||
fprintf(stderr, "Options:\n"
|
||||
" -t Test mode (flash LEDs)\n"
|
||||
" -n num number of LEDs per channel\n"
|
||||
" -d lvl debug level\n");
|
||||
exit(-EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void terminate(int sig) {
|
||||
manage_tasks(previousMode, -1);
|
||||
leddriver_close();
|
||||
exit(0);
|
||||
log_info("Goodbye !");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void manage_tasks(int previousMode, int currentMode) {
|
||||
/* stop previous bg task */
|
||||
switch (previousMode) {
|
||||
case 1:
|
||||
artnet_stop();
|
||||
break;
|
||||
case 2:
|
||||
cava_stop();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* start new bg task */
|
||||
switch (currentMode) {
|
||||
case 1:
|
||||
artnet_start();
|
||||
break;
|
||||
case 2:
|
||||
cava_start();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void execute_task(int mode) {
|
||||
switch (mode) {
|
||||
case 0:
|
||||
// mode test
|
||||
execute_test_mode();
|
||||
break;
|
||||
case 1:
|
||||
// artnet mode
|
||||
execute_artnet_mode();
|
||||
break;
|
||||
case 2:
|
||||
execute_autonomous_mode();
|
||||
break;
|
||||
case 3:
|
||||
// manual mode
|
||||
execute_manual_mode();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer to uncached Tx data buffer
|
||||
@ -159,13 +234,13 @@ void terminate(int sig) {
|
||||
|
||||
void execute_test_mode() {
|
||||
// RGB values for test mode (1 value for each of 16 channels)
|
||||
uint32_t on_rgbs[] = {0xef0000, 0x00ef00, 0x0000ef, 0xefef00, 0xef00ef, 0x00efef, 0xefefef};
|
||||
uint32_t on_rgbs[] = {0x5f0000, 0x005f00, 0x00005f, 0x5f5f00, 0x5f005f, 0x005f5f, 0x5f5f5f};
|
||||
uint32_t off_rgbs = 0x000000;
|
||||
|
||||
static int i = 0, offset = 0;
|
||||
|
||||
for (size_t ledIndex = 0; ledIndex < chanLedCount; ++ledIndex) {
|
||||
set_color(ledIndex <= offset % chanLedCount ? on_rgbs[i] : off_rgbs, ledIndex);
|
||||
set_color(ledIndex <= offset % chanLedCount ? on_rgbs[i] * .5 : off_rgbs, ledIndex);
|
||||
}
|
||||
|
||||
leddriver_refresh();
|
||||
@ -205,7 +280,7 @@ void execute_autonomous_mode() {
|
||||
int ret;
|
||||
uint16_t *buffer;
|
||||
|
||||
if ((ret = get_cava_buffer(&buffer)) == 0) {
|
||||
if ((ret = cava_get_buffer(&buffer)) == 0) {
|
||||
for (size_t ledBarIndex = 0; ledBarIndex < 4; ++ledBarIndex) {
|
||||
uint16_t barMax = 0;
|
||||
for (size_t bar = 0; bar < 20 / 4; ++bar) {
|
||||
@ -230,7 +305,15 @@ void execute_autonomous_mode() {
|
||||
}
|
||||
}
|
||||
|
||||
void execute_manual_mode() {}
|
||||
void execute_manual_mode() {
|
||||
for (size_t ledBarIndex = 0; ledBarIndex < LED_NCHANS; ++ledBarIndex) {
|
||||
for (size_t i = 0; i < chanLedCount; ++i) {
|
||||
rgb_data[i][ledBarIndex] = 0x000000;
|
||||
rgb_txdata(rgb_data[i], i);
|
||||
}
|
||||
}
|
||||
leddriver_refresh();
|
||||
}
|
||||
|
||||
void adjust_loop(struct timespec const *loopStart) {
|
||||
struct timespec loopEnd;
|
||||
@ -242,11 +325,21 @@ void adjust_loop(struct timespec const *loopStart) {
|
||||
remainingTimeUs = 16000 - elapsedTimeUs;
|
||||
|
||||
if (remainingTimeUs >= 0) {
|
||||
// printf("loop remaining time %ld\n", remainingTimeUs);
|
||||
log_trace("cycle %lu, loop remaining time %ld", mainLoopCycle, remainingTimeUs);
|
||||
usleep(remainingTimeUs);
|
||||
} else {
|
||||
printf("loop overlap by %06ldus\n", -remainingTimeUs);
|
||||
printf("loop start %ld.%09lds\n", loopStart->tv_sec, loopStart->tv_nsec);
|
||||
printf("loop end %ld.%09lds\n", loopEnd.tv_sec, loopEnd.tv_nsec);
|
||||
log_warn("loop overlap by %06ldus", -remainingTimeUs);
|
||||
log_info("loop start %ld.%09lds - loop end %ld.%09lds", loopStart->tv_sec, loopStart->tv_nsec,
|
||||
loopEnd.tv_sec, loopEnd.tv_nsec);
|
||||
}
|
||||
}
|
||||
++mainLoopCycle;
|
||||
}
|
||||
|
||||
void log_lock_helper(bool lock, void *udata) {
|
||||
pthread_mutex_t *pLogLockMutex = (pthread_mutex_t *)(udata);
|
||||
if (lock) {
|
||||
pthread_mutex_lock(pLogLockMutex);
|
||||
} else {
|
||||
pthread_mutex_unlock(pLogLockMutex);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,85 @@
|
||||
/** \file .c
|
||||
* \brief This module
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Includes
|
||||
**************************************************************************************************/
|
||||
|
||||
#include "rpi_midi_controller.h"
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include "rpi_param.h"
|
||||
|
||||
/***************************************************************************************************
|
||||
* Preprocessor Constants and Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
#define C3 0x30
|
||||
|
||||
/***************************************************************************************************
|
||||
* Type and Contant Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Persistent Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Boolean for interrupting the main thread loop
|
||||
*/
|
||||
static snd_seq_t *seq_handle;
|
||||
|
||||
/**
|
||||
* Boolean for interrupting the main thread loop
|
||||
*/
|
||||
static int sys_port;
|
||||
|
||||
/**
|
||||
* Boolean for interrupting the main thread loop
|
||||
*/
|
||||
static int in_port;
|
||||
|
||||
/* state machine */
|
||||
int destChannel = 0xf;
|
||||
|
||||
/***************************************************************************************************
|
||||
* Internal Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*/
|
||||
void subscribe_system_port();
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*
|
||||
* \param controller
|
||||
*/
|
||||
void subscribe_midi_controller(snd_seq_addr_t controller);
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*
|
||||
* \param ev
|
||||
*/
|
||||
void handle_system_port_events(snd_seq_event_t *ev);
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*
|
||||
* \param ev
|
||||
*/
|
||||
void handle_in_port_events(snd_seq_event_t *ev);
|
||||
|
||||
/***************************************************************************************************
|
||||
* External Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
void midi_controller_setup() {
|
||||
if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK) != 0) {
|
||||
SNDERR("snd_seq_open");
|
||||
@ -23,8 +89,8 @@ void midi_controller_setup() {
|
||||
SNDERR("snd_seq_set_client_name");
|
||||
}
|
||||
|
||||
sys_port = snd_seq_create_simple_port(seq_handle, "listen:in",
|
||||
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT,
|
||||
sys_port = snd_seq_create_simple_port(seq_handle, "sys:in",
|
||||
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
|
||||
SND_SEQ_PORT_TYPE_APPLICATION);
|
||||
|
||||
if (sys_port < 0) {
|
||||
@ -52,10 +118,9 @@ void midi_controller_execute() {
|
||||
if (ev->dest.port == sys_port) {
|
||||
handle_system_port_events(ev);
|
||||
} else if (ev->dest.port == in_port) {
|
||||
printf("ev %02d : %#010x - %#010x - %#010x\n", ev->type, ev->data.raw32.d[0],
|
||||
ev->data.raw32.d[1], ev->data.raw32.d[2]);
|
||||
handle_in_port_events(ev);
|
||||
} else {
|
||||
fprintf(stderr, "unkonwn midi dest port\n");
|
||||
log_warn("Unkonwn midi dest port %d", ev->dest.port);
|
||||
}
|
||||
}
|
||||
if (ret < 0 && ret != -EAGAIN) {
|
||||
@ -65,6 +130,10 @@ void midi_controller_execute() {
|
||||
|
||||
void midi_controller_close() {}
|
||||
|
||||
/***************************************************************************************************
|
||||
* Internal Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
void subscribe_system_port() {
|
||||
snd_seq_addr_t sender = {.client = 0, .port = SND_SEQ_PORT_SYSTEM_ANNOUNCE};
|
||||
snd_seq_connect_from(seq_handle, sys_port, sender.client, sender.port);
|
||||
@ -78,17 +147,60 @@ void handle_system_port_events(snd_seq_event_t *ev) {
|
||||
if (ev->type == SND_SEQ_EVENT_PORT_START) {
|
||||
snd_seq_addr_t *newport = (snd_seq_addr_t *)&ev->data;
|
||||
if (newport->client != snd_seq_client_id(seq_handle)) {
|
||||
fprintf(stdout, "New port %d:%d\n", newport->client, newport->port);
|
||||
log_info("New port %d:%d", newport->client, newport->port);
|
||||
subscribe_midi_controller(*newport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handle_in_port_events(snd_seq_event_t *ev) {
|
||||
switch (ev->type) {
|
||||
case SND_SEQ_EVENT_PGMCHANGE:
|
||||
if (ev->data.control.value < LED_NCHANS) {
|
||||
if (ev->data.control.value != destChannel) {
|
||||
destChannel = ev->data.control.value;
|
||||
log_info("Control param channel %d", ev->data.control.value);
|
||||
}
|
||||
} else {
|
||||
log_debug("PGMCHANGE : ch %#04x - param %u - value %d", ev->data.control.channel,
|
||||
ev->data.control.param, ev->data.control.value);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_NOTEON:
|
||||
if (ev->data.note.note == C3) {
|
||||
if (destChannel != 0xf) {
|
||||
destChannel = 0xf;
|
||||
log_info("Control global param");
|
||||
}
|
||||
} else {
|
||||
log_debug("NOTEON : ch %#04x - note %d - vel %d", ev->data.note.channel, ev->data.note.note,
|
||||
ev->data.note.velocity);
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SEQ_EVENT_CONTROLLER:
|
||||
switch (ev->data.control.param) {
|
||||
case 1:
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
log_debug("CONTROLLER : ch %#04x - param %u - value %d", ev->data.control.channel,
|
||||
ev->data.control.param, ev->data.control.value);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_debug("ev %02d : %#010x - %#010x - %#010x", ev->type, ev->data.raw32.d[0],
|
||||
ev->data.raw32.d[1], ev->data.raw32.d[2]);
|
||||
break;
|
||||
}
|
||||
if (ev->type == SND_SEQ_EVENT_PORT_START) {
|
||||
snd_seq_addr_t *newport = (snd_seq_addr_t *)&ev->data;
|
||||
if (newport->client != snd_seq_client_id(seq_handle)) {
|
||||
fprintf(stdout, "New port %d:%d\n", newport->client, newport->port);
|
||||
log_debug("New port %d:%d", newport->client, newport->port);
|
||||
subscribe_midi_controller(*newport);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,42 @@
|
||||
/** \file .h
|
||||
* \brief This module
|
||||
*/
|
||||
#if !defined(__RPI_MIDI_CONTROLLER_H__)
|
||||
#define __RPI_MIDI_CONTROLLER_H__
|
||||
|
||||
/***************************************************************************************************
|
||||
* Includes
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Preprocessor Constants and Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Type and Contant Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* External Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*/
|
||||
void midi_controller_setup();
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*/
|
||||
void midi_controller_execute();
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*/
|
||||
void midi_controller_close();
|
||||
|
||||
#endif /* __RPI_MIDI_CONTROLLER_H__ */
|
@ -1 +1,58 @@
|
||||
/** \file .c
|
||||
* \brief This module
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Includes
|
||||
**************************************************************************************************/
|
||||
|
||||
#include "rpi_param.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/***************************************************************************************************
|
||||
* Preprocessor Constants and Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Type and Contant Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
pixled_param_t const dummyPixledParam = {.intensity = .5, .hue = 0};
|
||||
auton_param_t const dummyAutonParam = {.sensitivity = 1};
|
||||
ledbar_param_t const dummyLedbarParam = {.sensitivity = 1};
|
||||
|
||||
/***************************************************************************************************
|
||||
* Persistent Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
param_t param;
|
||||
|
||||
/***************************************************************************************************
|
||||
* Internal Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* External Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
void param_setup() {
|
||||
param.pixled = dummyPixledParam;
|
||||
param.auton = dummyAutonParam;
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
param.ledbar[i] = dummyLedbarParam;
|
||||
}
|
||||
param_access = ¶m;
|
||||
}
|
||||
|
||||
void set_sensitivity(int channel, unsigned int sensitivity) {
|
||||
if (channel >= 10) {
|
||||
param.auton.sensitivity = sensitivity;
|
||||
} else {
|
||||
param.ledbar[channel].sensitivity = sensitivity;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************************
|
||||
* Internal Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
@ -1,4 +1,80 @@
|
||||
/** \file .h
|
||||
* \brief This module
|
||||
*/
|
||||
|
||||
#if !defined(__RPI_PARAM_H__)
|
||||
#define __RPI_PARAM_H__
|
||||
|
||||
/***************************************************************************************************
|
||||
* Includes
|
||||
**************************************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/***************************************************************************************************
|
||||
* Preprocessor Constants and Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
#define CHAN_MAXLEDS 6 * 60 // Maximum number of LEDs per channel
|
||||
#define LED_NCHANS 8 // Number of LED channels (8 or 16)
|
||||
|
||||
/***************************************************************************************************
|
||||
* Type and Contant Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t intensity;
|
||||
int hue;
|
||||
} pixled_param_t;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int sensitivity;
|
||||
} auton_param_t;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int sensitivity;
|
||||
} ledbar_param_t;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
pixled_param_t pixled;
|
||||
auton_param_t auton;
|
||||
ledbar_param_t ledbar[10];
|
||||
} param_t;
|
||||
|
||||
/***************************************************************************************************
|
||||
* Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
static param_t *param_access;
|
||||
|
||||
/***************************************************************************************************
|
||||
* External Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*/
|
||||
void param_setup();
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*
|
||||
* \param[in] channel
|
||||
*
|
||||
* \param[in] sensitivity
|
||||
*/
|
||||
void set_sensitivity(int channel, unsigned int sensitivity);
|
||||
|
||||
#endif /* __RPI_PARAM_H__ */
|
@ -20,6 +20,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "rpi_artnet_utils.h"
|
||||
|
||||
/***************************************************************************************************
|
||||
@ -33,6 +34,7 @@
|
||||
/***************************************************************************************************
|
||||
* Persistent Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Boolean for interrupting the main thread loop
|
||||
*/
|
||||
@ -76,7 +78,7 @@ void artnet_start() {
|
||||
isUdpListenerRunning = true;
|
||||
|
||||
if (pthread_create(&udpListener, NULL, artnet_udp_handler, NULL) < 0) {
|
||||
perror("pthread_create");
|
||||
log_error("pthread_create: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,23 +86,25 @@ void artnet_stop() {
|
||||
isUdpListenerRunning = false;
|
||||
|
||||
if (pthread_join(udpListener, NULL) != 0) {
|
||||
perror("pthread_join");
|
||||
log_error("pthread_join: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
int artnet_get_dmx_data(unsigned int univerve, uint8_t *dmxData[]) {
|
||||
if (univerve > 8) {
|
||||
fprintf(stderr, "Universe %d out of bounds %d\n", univerve, 16);
|
||||
log_error("Universe %d out of bounds %d\n", univerve, 16);
|
||||
*dmxData = NULL;
|
||||
return -1;
|
||||
}
|
||||
*dmxData = artDmxBufferArray[univerve];
|
||||
log_trace("%d;%d;%d;%d", (*dmxData)[0], (*dmxData)[1], (*dmxData)[2], (*dmxData)[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************************************
|
||||
* Internal Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void *artnet_udp_handler(void *arg) {
|
||||
int fdUdpSocket = -1;
|
||||
struct pollfd pollFdArray[1];
|
||||
@ -113,7 +117,7 @@ static void *artnet_udp_handler(void *arg) {
|
||||
/* Create UDP socket */
|
||||
fdUdpSocket = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fdUdpSocket < 0) {
|
||||
perror("Opening socket failed");
|
||||
log_error("Opening socket failed: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* Set non-blocking socket */
|
||||
@ -170,7 +174,7 @@ static void *artnet_udp_handler(void *arg) {
|
||||
}
|
||||
|
||||
} else if (pollReturn < 0) {
|
||||
fprintf(stderr, "error polling %d: %s\n", fdUdpSocket, strerror(errno));
|
||||
log_error("error polling %d: %s", fdUdpSocket, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +191,7 @@ static void artnet_send_poll_reply(int fdUdpSocket, struct sockaddr_in senderAdd
|
||||
|
||||
if (sendto(fdUdpSocket, (uint8_t *)&artPollReply, sizeof(artPollReply_t), 0,
|
||||
(struct sockaddr *)&senderAddr, sizeof(senderAddr)) < 0) {
|
||||
fprintf(stderr, "Error sending poll reply to %s:%d: %s\n", inet_ntoa(senderAddr.sin_addr),
|
||||
strerror(errno));
|
||||
log_error("%s: sending poll reply to \"%s:%d\": %s", inet_ntoa(senderAddr.sin_addr),
|
||||
senderAddr.sin_port, strerror(errno));
|
||||
}
|
||||
}
|
@ -139,7 +139,7 @@ typedef struct {
|
||||
uint8_t Filler[26]; // Filler bytes, currently zero.
|
||||
} artPollReply_t;
|
||||
|
||||
static artPollReply_t artPollReply = {
|
||||
static artPollReply_t const artPollReply = {
|
||||
.ID = "Art-Net",
|
||||
.OpCode = OpPollReply,
|
||||
.IPAddr = {0},
|
||||
|
@ -17,6 +17,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wait.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
/***************************************************************************************************
|
||||
* Preprocessor Constants and Macros
|
||||
@ -65,48 +68,29 @@ uint16_t buffer[128 + 2];
|
||||
*/
|
||||
static void *fifo_to_buffer(void *arg);
|
||||
|
||||
static int start_cava_process();
|
||||
|
||||
static void stop_cava_process();
|
||||
|
||||
/***************************************************************************************************
|
||||
* External Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
void setup_cava() {
|
||||
if ((cavaPid = fork()) == -1) {
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (cavaPid == 0) {
|
||||
/* Child process*/
|
||||
char *args[] = {"/usr/local/bin/cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL};
|
||||
|
||||
if (execv(args[0], args) != 0) {
|
||||
perror("execv");
|
||||
}
|
||||
|
||||
} else {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void close_cava() {
|
||||
stop_cava_bg_worker();
|
||||
kill(cavaPid, SIGTERM);
|
||||
}
|
||||
|
||||
void start_cava_bg_worker() {
|
||||
void cava_start() {
|
||||
isFifoReaderRunning = true;
|
||||
pthread_create(&fifoReader, NULL, fifo_to_buffer, NULL);
|
||||
}
|
||||
|
||||
void stop_cava_bg_worker() {
|
||||
void cava_stop() {
|
||||
isFifoReaderRunning = false;
|
||||
if (pthread_join(fifoReader, NULL) != 0) {
|
||||
perror("pthread_join");
|
||||
log_error("pthread_join: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
int get_cava_buffer(uint16_t **buffer_dst) {
|
||||
int cava_get_buffer(uint16_t **buffer_dst) {
|
||||
*buffer_dst = buffer;
|
||||
log_trace("%d;%d;%d;%d", buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -122,12 +106,8 @@ static void *fifo_to_buffer(void *arg) {
|
||||
char strValue[6] = "0\0";
|
||||
bool hasToBeDiscarded = true;
|
||||
|
||||
if start_cava_process ()
|
||||
;
|
||||
if ((fdCavaInput = open("/tmp/cava_output", O_RDONLY | O_NONBLOCK)) < 0) {
|
||||
perror("open");
|
||||
close_cava();
|
||||
exit(1);
|
||||
if ((fdCavaInput = start_cava_process()) < 0) {
|
||||
log_error("y'a un truc qui a pas marché");
|
||||
}
|
||||
|
||||
memset(fds, 0, sizeof(fds));
|
||||
@ -165,26 +145,27 @@ static void *fifo_to_buffer(void *arg) {
|
||||
valueIndex = 0;
|
||||
|
||||
if (valueIndex > 129) {
|
||||
fprintf(stderr, "Buffer overflow, \\n missed, discarding next\n");
|
||||
log_warn("Buffer overflow, \\n missed, discarding next");
|
||||
hasToBeDiscarded = true;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "Unexpected char %d [%c]\n", current, current);
|
||||
log_warn("Unexpected char %d [%c]\n", current, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (errno != EAGAIN) {
|
||||
perror("read");
|
||||
log_error("read: %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
} else if (ret < 0) {
|
||||
fprintf(stderr, "error polling %d: %s\n", fdCavaInput, strerror(errno));
|
||||
log_error("polling %d: %s\n", fdCavaInput, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
stop_cava_process();
|
||||
close(fdCavaInput);
|
||||
|
||||
return NULL;
|
||||
@ -194,17 +175,18 @@ static int start_cava_process() {
|
||||
int fdCavaPipe[2];
|
||||
|
||||
if (pipe(fdCavaPipe) < 0) {
|
||||
fprintf(stderr, "Cava pipe failure: %s\n", strerror(errno));
|
||||
log_error("Cava pipe failure: %s", strerror(errno));
|
||||
return -EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if ((cavaPid = fork()) < 0) {
|
||||
fprintf(stderr, "Cava fork failure: %s\n", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
log_error("Cava fork failure: %s", strerror(errno));
|
||||
exit(-EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (cavaPid == 0) {
|
||||
/* Child process*/
|
||||
int fdLogOut;
|
||||
char *args[] = {"cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL};
|
||||
|
||||
/* Close reading end of the pipe */
|
||||
@ -214,10 +196,16 @@ static int start_cava_process() {
|
||||
/* Close writing end of the pipe */
|
||||
close(fdCavaPipe[1]);
|
||||
|
||||
/* Open / create a log file for cava */
|
||||
fdLogOut = open("/dev/null", O_WRONLY, NULL);
|
||||
/* Dup file in place of stderr */
|
||||
dup2(fdLogOut, STDERR_FILENO);
|
||||
|
||||
execvp(args[0], args);
|
||||
fprintf(stderr, "Cava execvp failure or return: %s\n", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
log_error("Cava execvp failure or return: %s", strerror(errno));
|
||||
exit(-EXIT_FAILURE);
|
||||
} else {
|
||||
int flags;
|
||||
/* Close writing end of the pipe */
|
||||
close(fdCavaPipe[1]);
|
||||
/* Set reading end of the pipe non-blocking */
|
||||
@ -231,4 +219,7 @@ static int start_cava_process() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void stop_cava_process() { kill(cavaPid, SIGTERM); }
|
||||
static void stop_cava_process() {
|
||||
kill(cavaPid, SIGTERM);
|
||||
waitpid(0, NULL, WNOHANG);
|
||||
}
|
||||
|
@ -30,12 +30,12 @@
|
||||
**/
|
||||
void setup_cava();
|
||||
|
||||
int get_cava_buffer(uint16_t **buffer_dst);
|
||||
int cava_get_buffer(uint16_t **buffer_dst);
|
||||
|
||||
void close_cava();
|
||||
|
||||
void start_cava_bg_worker();
|
||||
void cava_start();
|
||||
|
||||
void stop_cava_bg_worker();
|
||||
void cava_stop();
|
||||
|
||||
#endif /* __RPI_CAVA_H__ */
|
Loading…
Reference in New Issue
Block a user