cava with pipe, and template
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
			
		||||
#include "rpi_gpio.h"
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
@@ -17,6 +18,8 @@
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
MEM_MAP gpio_regs;
 | 
			
		||||
 | 
			
		||||
@@ -24,9 +27,19 @@ char *gpio_mode_strs[] = {GPIO_MODE_STRS};
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
void gpio_set(int pin, int mode, int pull) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,37 @@
 | 
			
		||||
/** \file rpi_selector.c
 | 
			
		||||
 *  \brief This module is used to manage selector on gpio
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/***************************************************************************************************
 | 
			
		||||
 * Includes
 | 
			
		||||
 **************************************************************************************************/
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <wiringPi.h>
 | 
			
		||||
 | 
			
		||||
/***************************************************************************************************
 | 
			
		||||
 * Preprocessor Constants and Macros
 | 
			
		||||
 **************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/***************************************************************************************************
 | 
			
		||||
 * Type and Contant Definitions
 | 
			
		||||
 **************************************************************************************************/
 | 
			
		||||
unsigned const selectorPinNumber = 4;
 | 
			
		||||
/* TODO use GPIO function from ../gpio/gipo.h (same pin number) */
 | 
			
		||||
int selectorPins[4] = {5, 6, 26, 27};
 | 
			
		||||
 | 
			
		||||
void setup_selector() {
 | 
			
		||||
/***************************************************************************************************
 | 
			
		||||
 * Persistent Variables
 | 
			
		||||
 **************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/***************************************************************************************************
 | 
			
		||||
 * Internal Function Prototypes
 | 
			
		||||
 **************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/***************************************************************************************************
 | 
			
		||||
 * External Function Definitions
 | 
			
		||||
 **************************************************************************************************/
 | 
			
		||||
void selector_setup() {
 | 
			
		||||
  wiringPiSetupGpio();
 | 
			
		||||
 | 
			
		||||
  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) {
 | 
			
		||||
    if (digitalRead(selectorPins[i])) {
 | 
			
		||||
      return i;
 | 
			
		||||
@@ -23,10 +49,14 @@ int get_selector_position() {
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print_selector() {
 | 
			
		||||
void selector_print() {
 | 
			
		||||
  char modeStr[] = "0 | 0 | 0 | 0 \n";
 | 
			
		||||
  for (size_t i = 0; i < selectorPinNumber; ++i) {
 | 
			
		||||
    modeStr[i * 4] = digitalRead(selectorPins[i]) ? '1' : '0';
 | 
			
		||||
  }
 | 
			
		||||
  printf(modeStr);
 | 
			
		||||
}
 | 
			
		||||
  fprintf(stderr, modeStr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/***************************************************************************************************
 | 
			
		||||
 * Internal Function Definitions
 | 
			
		||||
 **************************************************************************************************/
 | 
			
		||||
@@ -1,10 +1,40 @@
 | 
			
		||||
/** \file rpi_selector.h
 | 
			
		||||
 *  \brief This module is used to manage selector on gpio
 | 
			
		||||
 */
 | 
			
		||||
/***************************************************************************************************
 | 
			
		||||
 * Includes
 | 
			
		||||
 **************************************************************************************************/
 | 
			
		||||
#if !defined(__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__ */
 | 
			
		||||
@@ -49,18 +49,10 @@ int main(int argc, char const *argv[]) {
 | 
			
		||||
    fprintf(stderr, "WARNING: Failed to set stepper thread to real-time priority\n");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setup_selector();
 | 
			
		||||
 | 
			
		||||
  // // 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);
 | 
			
		||||
 | 
			
		||||
  midi_controller_setup();
 | 
			
		||||
  selector_setup();
 | 
			
		||||
  leddriver_setup();
 | 
			
		||||
 | 
			
		||||
  setup_midi_controller();
 | 
			
		||||
  artnet_init();
 | 
			
		||||
  setup_cava();
 | 
			
		||||
 | 
			
		||||
@@ -68,8 +60,8 @@ int main(int argc, char const *argv[]) {
 | 
			
		||||
  while (1) {
 | 
			
		||||
    struct timespec loopStart;
 | 
			
		||||
    clock_gettime(CLOCK_MONOTONIC, &loopStart);
 | 
			
		||||
    int mode = get_selector_position();
 | 
			
		||||
    execute_midi_controller();
 | 
			
		||||
    int mode = selector_get_position();
 | 
			
		||||
    midi_controller_execute();
 | 
			
		||||
 | 
			
		||||
    if (mode != -1) {
 | 
			
		||||
      if (mode != previousMode) {
 | 
			
		||||
@@ -79,7 +71,7 @@ int main(int argc, char const *argv[]) {
 | 
			
		||||
        /* stop previous bg task */
 | 
			
		||||
        switch (previousMode) {
 | 
			
		||||
        case 1:
 | 
			
		||||
          stop_artnet_bg_worker();
 | 
			
		||||
          artnet_stop();
 | 
			
		||||
          break;
 | 
			
		||||
        case 2:
 | 
			
		||||
          stop_cava_bg_worker();
 | 
			
		||||
@@ -91,7 +83,7 @@ int main(int argc, char const *argv[]) {
 | 
			
		||||
        /* start new bg task */
 | 
			
		||||
        switch (mode) {
 | 
			
		||||
        case 1:
 | 
			
		||||
          start_artnet_bg_worker();
 | 
			
		||||
          artnet_start();
 | 
			
		||||
          break;
 | 
			
		||||
        case 2:
 | 
			
		||||
          start_cava_bg_worker();
 | 
			
		||||
 
 | 
			
		||||
@@ -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 setup_midi_controller() {
 | 
			
		||||
void midi_controller_setup() {
 | 
			
		||||
  if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK) != 0) {
 | 
			
		||||
    SNDERR("snd_seq_open");
 | 
			
		||||
  }
 | 
			
		||||
@@ -45,7 +45,7 @@ void setup_midi_controller() {
 | 
			
		||||
  subscribe_midi_controller(controller);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void execute_midi_controller() {
 | 
			
		||||
void midi_controller_execute() {
 | 
			
		||||
  snd_seq_event_t *ev = NULL;
 | 
			
		||||
  int ret;
 | 
			
		||||
  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() {
 | 
			
		||||
  snd_seq_addr_t sender = {.client = 0, .port = SND_SEQ_PORT_SYSTEM_ANNOUNCE};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,10 @@
 | 
			
		||||
#if !defined(__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__ */
 | 
			
		||||
@@ -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