cava with pipe, and template

This commit is contained in:
Nathan GOUARDERES 2021-07-30 10:59:34 +02:00
parent 7117cbbe4c
commit 6add75c64e
12 changed files with 378 additions and 85 deletions

View File

@ -12,7 +12,7 @@ source = plughw:1
method = raw method = raw
channels = mono channels = mono
mono_option = left mono_option = left
raw_target = /tmp/cava_output ;raw_target = /dev/stdout
data_format = ascii data_format = ascii
ascii_max_range=65535 ascii_max_range=65535
bit_format = 16bit bit_format = 16bit

View File

@ -0,0 +1,25 @@
[general]
framerate = 60
autosens = 0
sensitivity = 200
bars = 128
[input]
method = alsa
source = plughw:1
[output]
method = raw
channels = mono
mono_option = left
raw_target = /tmp/cava_output
data_format = ascii
ascii_max_range=65535
bit_format = 16bit
[smoothing]
integral = 0
monstercat = 1
waves = 0
gravity = 0

View File

@ -1,5 +1,6 @@
#include "rpi_gpio.h" #include "rpi_gpio.h"
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@ -17,6 +18,8 @@
#define GPIO_MODE_STRS "IN", "OUT", "ALT5", "ALT4", "ALT0", "ALT1", "ALT2", "ALT3" #define GPIO_MODE_STRS "IN", "OUT", "ALT5", "ALT4", "ALT0", "ALT1", "ALT2", "ALT3"
bool isInitialized = false;
// Virtual memory pointers to acceess GPIO, DMA and PWM from user space // Virtual memory pointers to acceess GPIO, DMA and PWM from user space
MEM_MAP gpio_regs; MEM_MAP gpio_regs;
@ -24,9 +27,19 @@ char *gpio_mode_strs[] = {GPIO_MODE_STRS};
// definitions // definitions
void gpio_setup() { map_periph(&gpio_regs, (void *)GPIO_BASE, PAGE_SIZE); } void gpio_setup() {
if (!isInitialized) {
map_periph(&gpio_regs, (void *)GPIO_BASE, PAGE_SIZE);
isInitialized = true;
}
}
void gpio_close() { unmap_periph_mem(&gpio_regs); } void gpio_close() {
if (isInitialized) {
unmap_periph_mem(&gpio_regs);
isInitialized = true;
}
}
// Set input or output with pullups // Set input or output with pullups
void gpio_set(int pin, int mode, int pull) { void gpio_set(int pin, int mode, int pull) {

View File

@ -1,11 +1,37 @@
/** \file rpi_selector.c
* \brief This module is used to manage selector on gpio
*/
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <wiringPi.h> #include <wiringPi.h>
/***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
/***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
unsigned const selectorPinNumber = 4; unsigned const selectorPinNumber = 4;
/* TODO use GPIO function from ../gpio/gipo.h (same pin number) */
int selectorPins[4] = {5, 6, 26, 27}; int selectorPins[4] = {5, 6, 26, 27};
void setup_selector() { /***************************************************************************************************
* Persistent Variables
**************************************************************************************************/
/***************************************************************************************************
* Internal Function Prototypes
**************************************************************************************************/
/***************************************************************************************************
* External Function Definitions
**************************************************************************************************/
void selector_setup() {
wiringPiSetupGpio(); wiringPiSetupGpio();
for (size_t i = 0; i < selectorPinNumber; ++i) { for (size_t i = 0; i < selectorPinNumber; ++i) {
@ -14,7 +40,7 @@ void setup_selector() {
} }
} }
int get_selector_position() { int selector_get_position() {
for (size_t i = 0; i < selectorPinNumber; ++i) { for (size_t i = 0; i < selectorPinNumber; ++i) {
if (digitalRead(selectorPins[i])) { if (digitalRead(selectorPins[i])) {
return i; return i;
@ -23,10 +49,14 @@ int get_selector_position() {
return -1; return -1;
} }
void print_selector() { void selector_print() {
char modeStr[] = "0 | 0 | 0 | 0 \n"; char modeStr[] = "0 | 0 | 0 | 0 \n";
for (size_t i = 0; i < selectorPinNumber; ++i) { for (size_t i = 0; i < selectorPinNumber; ++i) {
modeStr[i * 4] = digitalRead(selectorPins[i]) ? '1' : '0'; modeStr[i * 4] = digitalRead(selectorPins[i]) ? '1' : '0';
} }
printf(modeStr); fprintf(stderr, modeStr);
} }
/***************************************************************************************************
* Internal Function Definitions
**************************************************************************************************/

View File

@ -1,10 +1,40 @@
/** \file rpi_selector.h
* \brief This module is used to manage selector on gpio
*/
/***************************************************************************************************
* Includes
**************************************************************************************************/
#if !defined(__RPI_SELECTOR_H__) #if !defined(__RPI_SELECTOR_H__)
#define __RPI_SELECTOR_H__ #define __RPI_SELECTOR_H__
void setup_selector(); /***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
int get_selector_position(); /***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
void print_selector(); /***************************************************************************************************
* Global Variables
**************************************************************************************************/
/***************************************************************************************************
* External Function Prototypes
**************************************************************************************************/
/**
* \brief setup the selector module
**/
void selector_setup();
/**
* \brief get the selector position
**/
int selector_get_position();
/**
* \brief debug: print the selector position
**/
void selector_print();
#endif /* __RPI_SELECTOR_H__ */ #endif /* __RPI_SELECTOR_H__ */

View File

@ -49,18 +49,10 @@ int main(int argc, char const *argv[]) {
fprintf(stderr, "WARNING: Failed to set stepper thread to real-time priority\n"); fprintf(stderr, "WARNING: Failed to set stepper thread to real-time priority\n");
} }
setup_selector(); midi_controller_setup();
selector_setup();
// // setup led
// map_devices();
// init_smi(LED_NCHANS, SMI_TIMING);
// map_uncached_mem(&vc_mem, VC_MEM_SIZE);
// setup_smi_dma(&vc_mem, TX_BUFF_LEN(chanLedCount), &txdata);
leddriver_setup(); leddriver_setup();
setup_midi_controller();
artnet_init(); artnet_init();
setup_cava(); setup_cava();
@ -68,8 +60,8 @@ int main(int argc, char const *argv[]) {
while (1) { while (1) {
struct timespec loopStart; struct timespec loopStart;
clock_gettime(CLOCK_MONOTONIC, &loopStart); clock_gettime(CLOCK_MONOTONIC, &loopStart);
int mode = get_selector_position(); int mode = selector_get_position();
execute_midi_controller(); midi_controller_execute();
if (mode != -1) { if (mode != -1) {
if (mode != previousMode) { if (mode != previousMode) {
@ -79,7 +71,7 @@ int main(int argc, char const *argv[]) {
/* stop previous bg task */ /* stop previous bg task */
switch (previousMode) { switch (previousMode) {
case 1: case 1:
stop_artnet_bg_worker(); artnet_stop();
break; break;
case 2: case 2:
stop_cava_bg_worker(); stop_cava_bg_worker();
@ -91,7 +83,7 @@ int main(int argc, char const *argv[]) {
/* start new bg task */ /* start new bg task */
switch (mode) { switch (mode) {
case 1: case 1:
start_artnet_bg_worker(); artnet_start();
break; break;
case 2: case 2:
start_cava_bg_worker(); start_cava_bg_worker();

View File

@ -14,7 +14,7 @@ void handle_system_port_events(snd_seq_event_t *ev);
void handle_in_port_events(snd_seq_event_t *ev); void handle_in_port_events(snd_seq_event_t *ev);
void setup_midi_controller() { void midi_controller_setup() {
if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK) != 0) { if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK) != 0) {
SNDERR("snd_seq_open"); SNDERR("snd_seq_open");
} }
@ -45,7 +45,7 @@ void setup_midi_controller() {
subscribe_midi_controller(controller); subscribe_midi_controller(controller);
} }
void execute_midi_controller() { void midi_controller_execute() {
snd_seq_event_t *ev = NULL; snd_seq_event_t *ev = NULL;
int ret; int ret;
while ((ret = snd_seq_event_input(seq_handle, &ev)) > 0) { while ((ret = snd_seq_event_input(seq_handle, &ev)) > 0) {
@ -63,7 +63,7 @@ void execute_midi_controller() {
} }
} }
void close_midi_controller() {} void midi_controller_close() {}
void subscribe_system_port() { void subscribe_system_port() {
snd_seq_addr_t sender = {.client = 0, .port = SND_SEQ_PORT_SYSTEM_ANNOUNCE}; snd_seq_addr_t sender = {.client = 0, .port = SND_SEQ_PORT_SYSTEM_ANNOUNCE};

View File

@ -1,10 +1,10 @@
#if !defined(__RPI_MIDI_CONTROLLER_H__) #if !defined(__RPI_MIDI_CONTROLLER_H__)
#define __RPI_MIDI_CONTROLLER_H__ #define __RPI_MIDI_CONTROLLER_H__
void setup_midi_controller(); void midi_controller_setup();
void execute_midi_controller(); void midi_controller_execute();
void close_midi_controller(); void midi_controller_close();
#endif /* __RPI_MIDI_CONTROLLER_H__ */ #endif /* __RPI_MIDI_CONTROLLER_H__ */

View File

@ -1,3 +1,12 @@
/** \file rpi_artnet.c
* \brief This module contains continuous tasks for artnet node communications.
*
* This is the implementation file.
*/
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include "rpi_artnet.h" #include "rpi_artnet.h"
#include <arpa/inet.h> #include <arpa/inet.h>
@ -13,19 +22,57 @@
#include "rpi_artnet_utils.h" #include "rpi_artnet_utils.h"
int udpSocket = -1; /***************************************************************************************************
char buffer[1024]; * Preprocessor Constants and Macros
**************************************************************************************************/
/***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
/***************************************************************************************************
* Persistent Variables
**************************************************************************************************/
/**
* Boolean for interrupting the main thread loop
*/
bool isUdpListenerRunning = false; bool isUdpListenerRunning = false;
/**
* Task thread identifier
*/
pthread_t udpListener; pthread_t udpListener;
/**
* Buffer for storing artnet dmx data received
*/
uint8_t artDmxBufferArray[16][512]; uint8_t artDmxBufferArray[16][512];
/***************************************************************************************************
* Internal Function Prototypes
**************************************************************************************************/
/**
* \brief This function is used to thread main execution function
*
* \param arg not used.
*
* \return NULL.
*/
static void *artnet_udp_handler(void *arg); static void *artnet_udp_handler(void *arg);
void artnet_send_poll_reply(struct sockaddr_in srcAddr); /**
* \brief This function is used to send an artnet poll reply packet
*
* \param[in] fdUdpSocket The UDP socket file descriptor.
*
* \param[in] senderAddr The adress of poll emiter.
*/
static void artnet_send_poll_reply(int fdUdpSocket, struct sockaddr_in senderAddr);
void artnet_init() {} /***************************************************************************************************
* External Function Definitions
**************************************************************************************************/
void start_artnet_bg_worker() { void artnet_start() {
isUdpListenerRunning = true; isUdpListenerRunning = true;
if (pthread_create(&udpListener, NULL, artnet_udp_handler, NULL) < 0) { if (pthread_create(&udpListener, NULL, artnet_udp_handler, NULL) < 0) {
@ -33,7 +80,7 @@ void start_artnet_bg_worker() {
} }
} }
void stop_artnet_bg_worker() { void artnet_stop() {
isUdpListenerRunning = false; isUdpListenerRunning = false;
if (pthread_join(udpListener, NULL) != 0) { if (pthread_join(udpListener, NULL) != 0) {
@ -41,7 +88,7 @@ void stop_artnet_bg_worker() {
} }
} }
int artnet_get_dmx_data(unsigned int univerve, uint8_t **dmxData) { int artnet_get_dmx_data(unsigned int univerve, uint8_t *dmxData[]) {
if (univerve > 8) { if (univerve > 8) {
fprintf(stderr, "Universe %d out of bounds %d\n", univerve, 16); fprintf(stderr, "Universe %d out of bounds %d\n", univerve, 16);
*dmxData = NULL; *dmxData = NULL;
@ -51,27 +98,32 @@ int artnet_get_dmx_data(unsigned int univerve, uint8_t **dmxData) {
return 0; return 0;
} }
/***************************************************************************************************
* Internal Function Definitions
**************************************************************************************************/
static void *artnet_udp_handler(void *arg) { static void *artnet_udp_handler(void *arg) {
struct sockaddr_in serverAddr; int fdUdpSocket = -1;
struct pollfd fds[1]; struct pollfd pollFdArray[1];
int timeoutMs; int timeoutMs;
int ret;
int flags; int flags;
char buffer[ARTNET_MAX_BUFFER];
struct sockaddr_in serverAddr, srcAddr;
socklen_t srcLen = sizeof(struct sockaddr_in);
/* Create UDP socket */ /* Create UDP socket */
udpSocket = socket(PF_INET, SOCK_DGRAM, 0); fdUdpSocket = socket(PF_INET, SOCK_DGRAM, 0);
if (udpSocket < 0) { if (fdUdpSocket < 0) {
perror("Opening socket failed"); perror("Opening socket failed");
} }
/* Set non-blocking socket */ /* Set non-blocking socket */
flags = fcntl(udpSocket, F_GETFL, 0); flags = fcntl(fdUdpSocket, F_GETFL, 0);
fcntl(udpSocket, F_SETFL, flags | O_NONBLOCK); fcntl(fdUdpSocket, F_SETFL, flags | O_NONBLOCK);
/* pollfd structure and timeout */ /* pollfd structure and timeout */
memset(fds, 0, sizeof(fds)); memset(pollFdArray, 0, sizeof(pollFdArray));
fds[0].fd = udpSocket; pollFdArray[0].fd = fdUdpSocket;
fds[0].events = POLLIN; pollFdArray[0].events = POLLIN;
timeoutMs = 10; timeoutMs = 10;
/* Configure settings in address struct */ /* Configure settings in address struct */
@ -81,16 +133,14 @@ static void *artnet_udp_handler(void *arg) {
memset(serverAddr.sin_zero, '\0', sizeof(serverAddr.sin_zero)); memset(serverAddr.sin_zero, '\0', sizeof(serverAddr.sin_zero));
/* Bind socket with address struct */ /* Bind socket with address struct */
bind(udpSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); bind(fdUdpSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
struct sockaddr_in srcAddr;
socklen_t srcLen = sizeof(srcAddr);
while (isUdpListenerRunning) { while (isUdpListenerRunning) {
if ((ret = poll(fds, 1, timeoutMs)) == 1) { int pollReturn;
if ((pollReturn = poll(pollFdArray, 1, timeoutMs)) == 1) {
ssize_t bufferLen = ssize_t bufferLen =
recvfrom(udpSocket, buffer, ARTNET_MAX_BUFFER, 0, (struct sockaddr *)&srcAddr, &srcLen); recvfrom(fdUdpSocket, buffer, ARTNET_MAX_BUFFER, 0, (struct sockaddr *)&srcAddr, &srcLen);
if (bufferLen <= ARTNET_MAX_BUFFER && bufferLen > sizeof(artnetHeader_t)) { if (bufferLen <= ARTNET_MAX_BUFFER && bufferLen > sizeof(artnetHeader_t)) {
artnetHeader_t *artnetHeader = (artnetHeader_t *)buffer; artnetHeader_t *artnetHeader = (artnetHeader_t *)buffer;
@ -110,7 +160,7 @@ static void *artnet_udp_handler(void *arg) {
break; break;
case OpPoll: case OpPoll:
artnet_send_poll_reply(srcAddr); artnet_send_poll_reply(fdUdpSocket, srcAddr);
break; break;
default: default:
@ -118,22 +168,26 @@ static void *artnet_udp_handler(void *arg) {
} }
} }
} }
} else if (ret < 0) {
fprintf(stderr, "error polling %d: %s\n", udpSocket, strerror(errno)); } else if (pollReturn < 0) {
fprintf(stderr, "error polling %d: %s\n", fdUdpSocket, strerror(errno));
} }
} }
close(udpSocket); close(fdUdpSocket);
return NULL; return NULL;
} }
void artnet_send_poll_reply(struct sockaddr_in srcAddr) { static void artnet_send_poll_reply(int fdUdpSocket, struct sockaddr_in senderAddr) {
/* Configure settings in address struct */ /* Configure settings in address struct */
srcAddr.sin_family = AF_INET; senderAddr.sin_family = AF_INET;
srcAddr.sin_port = htons(ARTNET_PORT); senderAddr.sin_port = htons(ARTNET_PORT);
memset(srcAddr.sin_zero, '\0', sizeof(srcAddr.sin_zero)); memset(senderAddr.sin_zero, '\0', sizeof(senderAddr.sin_zero));
sendto(udpSocket, (uint8_t *)&artPollReply, sizeof(artPollReply_t), 0, if (sendto(fdUdpSocket, (uint8_t *)&artPollReply, sizeof(artPollReply_t), 0,
(struct sockaddr *)&srcAddr, sizeof(srcAddr)); (struct sockaddr *)&senderAddr, sizeof(senderAddr)) < 0) {
fprintf(stderr, "Error sending poll reply to %s:%d: %s\n", inet_ntoa(senderAddr.sin_addr),
strerror(errno));
}
} }

View File

@ -1,14 +1,50 @@
/** \file rpi_artnet.h
* \brief This module contains continuous tasks for artnet node communications.
*
* This is the header file for the definition of services to allow managing thread acting as artnet
* node.
*/
#if !defined(__RPI_ARTNET_H__) #if !defined(__RPI_ARTNET_H__)
#define __RPI_ARTNET_H__ #define __RPI_ARTNET_H__
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include "rpi_artnet_packets.h" #include "rpi_artnet_packets.h"
void artnet_init(); /***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
void start_artnet_bg_worker(); /***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
void stop_artnet_bg_worker(); /***************************************************************************************************
* Global Variables
**************************************************************************************************/
int artnet_get_dmx_data(unsigned int univerve, uint8_t **dmxData); /***************************************************************************************************
* External Function Prototypes
**************************************************************************************************/
#endif // __RPI_ARTNET_H__ /**
* \brief Start artnet node module
**/
void artnet_start();
/**
* \brief Stop artnet node module
*/
void artnet_stop();
/**
* \brief Get last DMX data received for the specified universe
*
* \param[in] univerve The universe to get data from
*
* \param[out] dmxData The pointer to the DMX data array
*/
int artnet_get_dmx_data(unsigned int univerve, uint8_t *dmxData[]);
#endif /* __RPI_ARTNET_H__ */

View File

@ -1,3 +1,10 @@
/** \file rpi_cava.h
* \brief This module contains continuous tasks for cava (spectrum analyzer) comunication
*/
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include "rpi_cava.h" #include "rpi_cava.h"
#include <errno.h> #include <errno.h>
@ -9,23 +16,59 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h> #include <unistd.h>
#endif
/***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
/**
* Constant for Maximum char in a line (128 number of (5 char + 1 delim) + \n )
*/
#define MAXLINECHAR 128 * (5 + 1) + 1 #define MAXLINECHAR 128 * (5 + 1) + 1
/***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
/***************************************************************************************************
* Persistent Variables
**************************************************************************************************/
/**
* Cava process id
*/
pid_t cavaPid; pid_t cavaPid;
/**
* Boolean for interrupting the main thread loop
*/
bool isFifoReaderRunning = false; bool isFifoReaderRunning = false;
/**
* Task thread identifier
*/
pthread_t fifoReader; pthread_t fifoReader;
int cavaFifo;
int fdCavaInput;
char lineBuffer[MAXLINECHAR]; char lineBuffer[MAXLINECHAR];
uint16_t buffer[128 + 2]; uint16_t buffer[128 + 2];
/***************************************************************************************************
* Internal Function Prototypes
**************************************************************************************************/
/**
* \brief This function is used to thread main execution function
*
* \param arg not used.
*
* \return NULL.
*/
static void *fifo_to_buffer(void *arg); static void *fifo_to_buffer(void *arg);
/***************************************************************************************************
* External Function Definitions
**************************************************************************************************/
void setup_cava() { void setup_cava() {
if ((cavaPid = fork()) == -1) { if ((cavaPid = fork()) == -1) {
perror("fork"); perror("fork");
@ -34,7 +77,6 @@ void setup_cava() {
if (cavaPid == 0) { if (cavaPid == 0) {
/* Child process*/ /* Child process*/
pthread_setschedprio(pthread_self(), 30);
char *args[] = {"/usr/local/bin/cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL}; char *args[] = {"/usr/local/bin/cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL};
if (execv(args[0], args) != 0) { if (execv(args[0], args) != 0) {
@ -68,33 +110,36 @@ int get_cava_buffer(uint16_t **buffer_dst) {
return 0; return 0;
} }
size_t valueIndex = 0, charOffset = 0; /***************************************************************************************************
char strValue[6] = "0\0"; * Internal Function Definitions
bool hasToBeDiscarded = false; **************************************************************************************************/
static void *fifo_to_buffer(void *arg) { static void *fifo_to_buffer(void *arg) {
struct pollfd fds[1]; struct pollfd fds[1];
int timeoutMs; int timeoutMs;
int ret; int ret;
size_t valueIndex = 0, charOffset = 0;
char strValue[6] = "0\0";
bool hasToBeDiscarded = true;
if ((cavaFifo = open("/tmp/cava_output", O_RDONLY | O_NONBLOCK)) < 0) { if start_cava_process ()
;
if ((fdCavaInput = open("/tmp/cava_output", O_RDONLY | O_NONBLOCK)) < 0) {
perror("open"); perror("open");
close_cava(); close_cava();
exit(1); exit(1);
} }
memset(fds, 0, sizeof(fds)); memset(fds, 0, sizeof(fds));
fds[0].fd = cavaFifo; fds[0].fd = fdCavaInput;
fds[0].events = POLLIN; fds[0].events = POLLIN;
timeoutMs = 10; timeoutMs = 10;
hasToBeDiscarded = true;
while (isFifoReaderRunning) { while (isFifoReaderRunning) {
if ((ret = poll(fds, 1, timeoutMs)) == 1) { if ((ret = poll(fds, 1, timeoutMs)) == 1) {
int nread; int nread;
nread = read(cavaFifo, lineBuffer, 128 + 1); nread = read(fdCavaInput, lineBuffer, 128 + 1);
if (nread >= 0) { if (nread >= 0) {
for (size_t i = 0; i < nread; ++i) { for (size_t i = 0; i < nread; ++i) {
@ -136,11 +181,54 @@ static void *fifo_to_buffer(void *arg) {
} }
} }
} else if (ret < 0) { } else if (ret < 0) {
fprintf(stderr, "error polling %d: %s\n", cavaFifo, strerror(errno)); fprintf(stderr, "error polling %d: %s\n", fdCavaInput, strerror(errno));
} }
} }
close(cavaFifo); close(fdCavaInput);
return NULL; return NULL;
} }
static int start_cava_process() {
int fdCavaPipe[2];
if (pipe(fdCavaPipe) < 0) {
fprintf(stderr, "Cava pipe failure: %s\n", strerror(errno));
return -EXIT_FAILURE;
}
if ((cavaPid = fork()) < 0) {
fprintf(stderr, "Cava fork failure: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (cavaPid == 0) {
/* Child process*/
char *args[] = {"cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL};
/* Close reading end of the pipe */
close(fdCavaPipe[0]);
/* Dup writing end of the pipe in place of stdout */
dup2(fdCavaPipe[1], STDOUT_FILENO);
/* Close writing end of the pipe */
close(fdCavaPipe[1]);
execvp(args[0], args);
fprintf(stderr, "Cava execvp failure or return: %s\n", strerror(errno));
exit(EXIT_FAILURE);
} else {
/* Close writing end of the pipe */
close(fdCavaPipe[1]);
/* Set reading end of the pipe non-blocking */
flags = fcntl(fdCavaPipe[0], F_GETFL, 0);
fcntl(fdCavaPipe[0], F_SETFL, flags | O_NONBLOCK);
/* Return reading end of the pipe */
return fdCavaPipe[0];
}
/* Unreachable */
return -1;
}
static void stop_cava_process() { kill(cavaPid, SIGTERM); }

View File

@ -1,8 +1,33 @@
/** \file rpi_cava.h
* \brief This module contains continuous tasks for cava (spectrum analyzer) comunication
*/
#if !defined(__RPI_CAVA_H__) #if !defined(__RPI_CAVA_H__)
#define __RPI_CAVA_H__ #define __RPI_CAVA_H__
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include <stdint.h> #include <stdint.h>
/***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
/***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
/***************************************************************************************************
* Global Variables
**************************************************************************************************/
/***************************************************************************************************
* External Function Prototypes
**************************************************************************************************/
/**
* \brief Start artnet node module
**/
void setup_cava(); void setup_cava();
int get_cava_buffer(uint16_t **buffer_dst); int get_cava_buffer(uint16_t **buffer_dst);