cava with pipe, and template
This commit is contained in:
@@ -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 <arpa/inet.h>
|
||||
@@ -13,19 +22,57 @@
|
||||
|
||||
#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;
|
||||
/**
|
||||
* Task thread identifier
|
||||
*/
|
||||
pthread_t udpListener;
|
||||
/**
|
||||
* Buffer for storing artnet dmx data received
|
||||
*/
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
fprintf(stderr, "Universe %d out of bounds %d\n", univerve, 16);
|
||||
*dmxData = NULL;
|
||||
@@ -51,27 +98,32 @@ int artnet_get_dmx_data(unsigned int univerve, uint8_t **dmxData) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************************************
|
||||
* Internal Function Definitions
|
||||
**************************************************************************************************/
|
||||
static void *artnet_udp_handler(void *arg) {
|
||||
struct sockaddr_in serverAddr;
|
||||
struct pollfd fds[1];
|
||||
int fdUdpSocket = -1;
|
||||
struct pollfd pollFdArray[1];
|
||||
int timeoutMs;
|
||||
int ret;
|
||||
int flags;
|
||||
char buffer[ARTNET_MAX_BUFFER];
|
||||
struct sockaddr_in serverAddr, srcAddr;
|
||||
socklen_t srcLen = sizeof(struct sockaddr_in);
|
||||
|
||||
/* Create UDP socket */
|
||||
udpSocket = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (udpSocket < 0) {
|
||||
fdUdpSocket = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (fdUdpSocket < 0) {
|
||||
perror("Opening socket failed");
|
||||
}
|
||||
|
||||
/* Set non-blocking socket */
|
||||
flags = fcntl(udpSocket, F_GETFL, 0);
|
||||
fcntl(udpSocket, F_SETFL, flags | O_NONBLOCK);
|
||||
flags = fcntl(fdUdpSocket, F_GETFL, 0);
|
||||
fcntl(fdUdpSocket, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
/* pollfd structure and timeout */
|
||||
memset(fds, 0, sizeof(fds));
|
||||
fds[0].fd = udpSocket;
|
||||
fds[0].events = POLLIN;
|
||||
memset(pollFdArray, 0, sizeof(pollFdArray));
|
||||
pollFdArray[0].fd = fdUdpSocket;
|
||||
pollFdArray[0].events = POLLIN;
|
||||
timeoutMs = 10;
|
||||
|
||||
/* 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));
|
||||
|
||||
/* Bind socket with address struct */
|
||||
bind(udpSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
|
||||
|
||||
struct sockaddr_in srcAddr;
|
||||
socklen_t srcLen = sizeof(srcAddr);
|
||||
bind(fdUdpSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
|
||||
|
||||
while (isUdpListenerRunning) {
|
||||
|
||||
if ((ret = poll(fds, 1, timeoutMs)) == 1) {
|
||||
int pollReturn;
|
||||
if ((pollReturn = poll(pollFdArray, 1, timeoutMs)) == 1) {
|
||||
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)) {
|
||||
artnetHeader_t *artnetHeader = (artnetHeader_t *)buffer;
|
||||
@@ -110,7 +160,7 @@ static void *artnet_udp_handler(void *arg) {
|
||||
break;
|
||||
|
||||
case OpPoll:
|
||||
artnet_send_poll_reply(srcAddr);
|
||||
artnet_send_poll_reply(fdUdpSocket, srcAddr);
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
srcAddr.sin_family = AF_INET;
|
||||
srcAddr.sin_port = htons(ARTNET_PORT);
|
||||
memset(srcAddr.sin_zero, '\0', sizeof(srcAddr.sin_zero));
|
||||
senderAddr.sin_family = AF_INET;
|
||||
senderAddr.sin_port = htons(ARTNET_PORT);
|
||||
memset(senderAddr.sin_zero, '\0', sizeof(senderAddr.sin_zero));
|
||||
|
||||
sendto(udpSocket, (uint8_t *)&artPollReply, sizeof(artPollReply_t), 0,
|
||||
(struct sockaddr *)&srcAddr, sizeof(srcAddr));
|
||||
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));
|
||||
}
|
||||
}
|
@@ -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__)
|
||||
#define __RPI_ARTNET_H__
|
||||
|
||||
/***************************************************************************************************
|
||||
* Includes
|
||||
**************************************************************************************************/
|
||||
#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__ */
|
||||
|
@@ -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 <errno.h>
|
||||
@@ -9,23 +16,59 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#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
|
||||
|
||||
/***************************************************************************************************
|
||||
* Type and Contant Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Persistent Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Cava process id
|
||||
*/
|
||||
pid_t cavaPid;
|
||||
/**
|
||||
* Boolean for interrupting the main thread loop
|
||||
*/
|
||||
bool isFifoReaderRunning = false;
|
||||
/**
|
||||
* Task thread identifier
|
||||
*/
|
||||
pthread_t fifoReader;
|
||||
int cavaFifo;
|
||||
|
||||
int fdCavaInput;
|
||||
char lineBuffer[MAXLINECHAR];
|
||||
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);
|
||||
|
||||
/***************************************************************************************************
|
||||
* External Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
void setup_cava() {
|
||||
if ((cavaPid = fork()) == -1) {
|
||||
perror("fork");
|
||||
@@ -34,7 +77,6 @@ void setup_cava() {
|
||||
|
||||
if (cavaPid == 0) {
|
||||
/* Child process*/
|
||||
pthread_setschedprio(pthread_self(), 30);
|
||||
char *args[] = {"/usr/local/bin/cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL};
|
||||
|
||||
if (execv(args[0], args) != 0) {
|
||||
@@ -68,33 +110,36 @@ int get_cava_buffer(uint16_t **buffer_dst) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t valueIndex = 0, charOffset = 0;
|
||||
char strValue[6] = "0\0";
|
||||
bool hasToBeDiscarded = false;
|
||||
/***************************************************************************************************
|
||||
* Internal Function Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void *fifo_to_buffer(void *arg) {
|
||||
struct pollfd fds[1];
|
||||
int timeoutMs;
|
||||
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");
|
||||
close_cava();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(fds, 0, sizeof(fds));
|
||||
fds[0].fd = cavaFifo;
|
||||
fds[0].fd = fdCavaInput;
|
||||
fds[0].events = POLLIN;
|
||||
timeoutMs = 10;
|
||||
|
||||
hasToBeDiscarded = true;
|
||||
|
||||
while (isFifoReaderRunning) {
|
||||
|
||||
if ((ret = poll(fds, 1, timeoutMs)) == 1) {
|
||||
int nread;
|
||||
nread = read(cavaFifo, lineBuffer, 128 + 1);
|
||||
nread = read(fdCavaInput, lineBuffer, 128 + 1);
|
||||
|
||||
if (nread >= 0) {
|
||||
for (size_t i = 0; i < nread; ++i) {
|
||||
@@ -136,11 +181,54 @@ static void *fifo_to_buffer(void *arg) {
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
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); }
|
||||
|
@@ -1,8 +1,33 @@
|
||||
/** \file rpi_cava.h
|
||||
* \brief This module contains continuous tasks for cava (spectrum analyzer) comunication
|
||||
*/
|
||||
#if !defined(__RPI_CAVA_H__)
|
||||
#define __RPI_CAVA_H__
|
||||
|
||||
/***************************************************************************************************
|
||||
* Includes
|
||||
**************************************************************************************************/
|
||||
#include <stdint.h>
|
||||
|
||||
/***************************************************************************************************
|
||||
* Preprocessor Constants and Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Type and Contant Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/***************************************************************************************************
|
||||
* External Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
/**
|
||||
* \brief Start artnet node module
|
||||
**/
|
||||
void setup_cava();
|
||||
|
||||
int get_cava_buffer(uint16_t **buffer_dst);
|
||||
|
Reference in New Issue
Block a user