logging facility (log.c librarie), template, minor bug fixes, param init
This commit is contained in:
parent
a5da739f65
commit
0ccd9e7d46
@ -1,6 +1,6 @@
|
|||||||
CC := gcc
|
CC := gcc
|
||||||
CFLAGS := -Wall -g -D_DEBUG
|
CFLAGS := -Wall -g -Ilibs/log.c/src
|
||||||
LDFLAGS := -lwiringPi -lasound -lfftw3 -lpthread -lm
|
LDFLAGS := -lwiringPi -lasound -lfftw3 -lpthread -lm -L.libs
|
||||||
|
|
||||||
SRC := src
|
SRC := src
|
||||||
OBJ := obj
|
OBJ := obj
|
||||||
@ -9,20 +9,26 @@ 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))
|
OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
|
||||||
|
|
||||||
|
.PHONY: all clean debug
|
||||||
|
|
||||||
all: $(BIN)
|
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
|
$(OBJ)/%.o: $(SRC)/%.c
|
||||||
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
|
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
|
||||||
$(CC) -I$(SRC) -c $< -o $@ $(CFLAGS)
|
$(CC) -c $< -o $@ $(CFLAGS)
|
||||||
|
|
||||||
$(BIN) : $(OBJECTS)
|
$(BIN): $(OBJECTS) .libs/log.la
|
||||||
if [ ! -d "$(dir $(BIN))" ]; then mkdir -p "$(dir $(BIN))"; fi
|
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
|
||||||
$(CC) -o $@ $^ $(LDFLAGS)
|
$(CC) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
liblog.a: log.o
|
|
||||||
ar $(ARFLAGS) $@ $^
|
|
||||||
|
|
||||||
clean:
|
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://makersportal.com/blog/recording-stereo-audio-on-a-raspberry-pi
|
||||||
https://learn.adafruit.com/adafruit-i2s-mems-microphone-breakout/raspberry-pi-wiring-test
|
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
|
sudo pip3 install --upgrade adafruit-python-shell
|
||||||
cd /tmp
|
cd /tmp
|
||||||
sudo wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/i2smic.py
|
sudo wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/i2smic.py
|
||||||
@ -16,3 +17,13 @@ cp res/.asoundrc ~/.asoundrc
|
|||||||
|
|
||||||
# alsa API
|
# 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 <fcntl.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
// Use mmap to obtain virtual address, given physical
|
// Use mmap to obtain virtual address, given physical
|
||||||
void *map_periph(MEM_MAP *mp, void *phys, int size) {
|
void *map_periph(MEM_MAP *mp, void *phys, int size) {
|
||||||
mp->phys = phys;
|
mp->phys = phys;
|
||||||
@ -30,20 +33,24 @@ void *map_segment(void *addr, int size) {
|
|||||||
void *mem;
|
void *mem;
|
||||||
|
|
||||||
size = PAGE_ROUNDUP(size);
|
size = PAGE_ROUNDUP(size);
|
||||||
if ((fd = open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0)
|
if ((fd = open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0) {
|
||||||
fprintf(stderr, "Error: can't open /dev/mem, run using sudo\n");
|
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);
|
mem = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, (uint32_t)addr);
|
||||||
close(fd);
|
close(fd);
|
||||||
#if DEBUG
|
log_info("Map %p -> %p", (void *)addr, mem);
|
||||||
printf("Map %p -> %p\n", (void *)addr, mem);
|
if (mem == MAP_FAILED) {
|
||||||
#endif
|
log_fatal("can't map memory");
|
||||||
if (mem == MAP_FAILED)
|
exit(-EXIT_FAILURE);
|
||||||
fprintf(stderr, "Error: can't map memory\n");
|
}
|
||||||
return (mem);
|
return (mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free mapped memory
|
// Free mapped memory
|
||||||
void unmap_segment(void *mem, int size) {
|
void unmap_segment(void *mem, int size) {
|
||||||
if (mem)
|
if (mem) {
|
||||||
munmap(mem, PAGE_ROUNDUP(size));
|
munmap(mem, PAGE_ROUNDUP(size));
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,6 +5,8 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
// Mailbox command/response structure
|
// Mailbox command/response structure
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t len, // Overall length (bytes)
|
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 = map_segment(BUS_PHYS_ADDR(mp->bus), mp->size)) != 0
|
||||||
? mp->virt
|
? mp->virt
|
||||||
: 0;
|
: 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);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +95,7 @@ int open_mbox(void) {
|
|||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if ((fd = open("/dev/vcio", 0)) < 0)
|
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);
|
return (fd);
|
||||||
}
|
}
|
||||||
// Close mailbox interface
|
// Close mailbox interface
|
||||||
@ -110,14 +112,15 @@ uint32_t msg_mbox(int fd, VC_MSG *msgp) {
|
|||||||
msgp->uints[i++] = 0;
|
msgp->uints[i++] = 0;
|
||||||
msgp->len = (msgp->blen + 6) * 4;
|
msgp->len = (msgp->blen + 6) * 4;
|
||||||
msgp->req = 0;
|
msgp->req = 0;
|
||||||
if (ioctl(fd, _IOWR(100, 0, void *), msgp) < 0)
|
if (ioctl(fd, _IOWR(100, 0, void *), msgp) < 0) {
|
||||||
printf("VC IOCTL failed\n");
|
log_error("VC IOCTL failed");
|
||||||
else if ((msgp->req & 0x80000000) == 0)
|
} else if ((msgp->req & 0x80000000) == 0) {
|
||||||
printf("VC IOCTL error\n");
|
log_error("VC IOCTL error");
|
||||||
else if (msgp->req == 0x80000001)
|
} else if (msgp->req == 0x80000001) {
|
||||||
printf("VC IOCTL partial error\n");
|
log_error("VC IOCTL partial error");
|
||||||
else
|
} else {
|
||||||
ret = msgp->uints[0];
|
ret = msgp->uints[0];
|
||||||
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
disp_vc_msg(msgp);
|
disp_vc_msg(msgp);
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "../../rpi_param.h"
|
||||||
#include "../common.h"
|
#include "../common.h"
|
||||||
|
|
||||||
#include "../dma/rpi_dma.h"
|
#include "../dma/rpi_dma.h"
|
||||||
@ -49,13 +50,12 @@ TXDATA_T tx_buffer[TX_BUFF_LEN(CHAN_MAXLEDS)];
|
|||||||
void swap_bytes();
|
void swap_bytes();
|
||||||
|
|
||||||
void leddriver_setup() {
|
void leddriver_setup() {
|
||||||
gpio_setup();
|
|
||||||
videocore_setup(&vc_mem, VC_MEM_SIZE);
|
videocore_setup(&vc_mem, VC_MEM_SIZE);
|
||||||
|
gpio_setup();
|
||||||
smi_setup(LED_NCHANS, SMI_TIMING, &vc_mem, TX_BUFF_LEN(CHAN_MAXLEDS), &txdata);
|
smi_setup(LED_NCHANS, SMI_TIMING, &vc_mem, TX_BUFF_LEN(CHAN_MAXLEDS), &txdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void leddriver_close() {
|
void leddriver_close() {
|
||||||
printf("Closing\n");
|
|
||||||
videocore_close(&vc_mem);
|
videocore_close(&vc_mem);
|
||||||
smi_close(LED_NCHANS);
|
smi_close(LED_NCHANS);
|
||||||
gpio_close();
|
gpio_close();
|
||||||
@ -130,3 +130,81 @@ void swap_bytes() {
|
|||||||
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>
|
#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_setup();
|
||||||
|
|
||||||
void leddriver_close();
|
void leddriver_close();
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* Includes
|
* Includes
|
||||||
**************************************************************************************************/
|
**************************************************************************************************/
|
||||||
|
#include "rpi_selector.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wiringPi.h>
|
#include <wiringPi.h>
|
||||||
@ -19,6 +21,7 @@
|
|||||||
unsigned const selectorPinNumber = 4;
|
unsigned const selectorPinNumber = 4;
|
||||||
/* TODO use GPIO function from ../gpio/gipo.h (same pin number) */
|
/* 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};
|
||||||
|
char modeStr[] = "0 | 0 | 0 | 0 \n";
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* Persistent Variables
|
* Persistent Variables
|
||||||
@ -49,12 +52,11 @@ int selector_get_position() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void selector_print() {
|
char *selector_tostr() {
|
||||||
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';
|
||||||
}
|
}
|
||||||
fprintf(stderr, modeStr);
|
return modeStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
|
@ -33,8 +33,8 @@ void selector_setup();
|
|||||||
int selector_get_position();
|
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__ */
|
#endif /* __RPI_SELECTOR_H__ */
|
@ -1,4 +1,12 @@
|
|||||||
|
/** \file main.c
|
||||||
|
* \brief This is the main exectution program
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* Includes
|
||||||
|
**************************************************************************************************/
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -8,23 +16,51 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#include "drivers/leddriver/rpi_leddriver.h"
|
#include "drivers/leddriver/rpi_leddriver.h"
|
||||||
#include "drivers/selector/rpi_selector.h"
|
#include "drivers/selector/rpi_selector.h"
|
||||||
|
|
||||||
#include "rpi_midi_controller.h"
|
|
||||||
#include "tasks/artnet/rpi_artnet.h"
|
#include "tasks/artnet/rpi_artnet.h"
|
||||||
#include "tasks/cava/rpi_cava.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 */
|
/* Command-line parameters */
|
||||||
bool IsTestMode = false;
|
bool IsTestMode = false;
|
||||||
int chanLedCount = 0;
|
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 parseCommandLineArgs(int argc, char const *argv[]);
|
||||||
|
|
||||||
void terminate(int sig);
|
void terminate(int sig);
|
||||||
|
|
||||||
|
void manage_tasks(int previousMode, int currentMode);
|
||||||
|
|
||||||
|
void execute_task(int mode);
|
||||||
|
|
||||||
void execute_test_mode();
|
void execute_test_mode();
|
||||||
|
|
||||||
void execute_artnet_mode();
|
void execute_artnet_mode();
|
||||||
@ -35,86 +71,59 @@ void execute_manual_mode();
|
|||||||
|
|
||||||
void adjust_loop(struct timespec const *loopStart);
|
void adjust_loop(struct timespec const *loopStart);
|
||||||
|
|
||||||
int main(int argc, char const *argv[]) {
|
void log_lock_helper(bool lock, void *udata);
|
||||||
int previousMode = -1;
|
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* External Function Definitions
|
||||||
|
**************************************************************************************************/
|
||||||
|
|
||||||
|
int main(int argc, char const *argv[]) {
|
||||||
// setup
|
// setup
|
||||||
parseCommandLineArgs(argc, argv);
|
parseCommandLineArgs(argc, argv);
|
||||||
|
log_set_level(logLevel);
|
||||||
|
|
||||||
signal(SIGINT, terminate);
|
signal(SIGINT, terminate);
|
||||||
|
|
||||||
struct sched_param sp;
|
// struct sched_param sp;
|
||||||
sp.sched_priority = 32;
|
// sp.sched_priority = 32;
|
||||||
if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) {
|
// if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) {
|
||||||
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: %s\n",
|
||||||
}
|
// strerror(errno));
|
||||||
|
// }
|
||||||
|
|
||||||
|
log_set_lock(log_lock_helper, &logLockMutex);
|
||||||
|
|
||||||
|
param_setup();
|
||||||
midi_controller_setup();
|
midi_controller_setup();
|
||||||
selector_setup();
|
selector_setup();
|
||||||
leddriver_setup();
|
leddriver_setup();
|
||||||
|
|
||||||
artnet_init();
|
// setup_cava();
|
||||||
setup_cava();
|
|
||||||
|
|
||||||
// loop
|
// loop
|
||||||
while (1) {
|
while (1) {
|
||||||
struct timespec loopStart;
|
struct timespec loopStart;
|
||||||
|
int mode;
|
||||||
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &loopStart);
|
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();
|
midi_controller_execute();
|
||||||
|
|
||||||
if (mode != -1) {
|
if (mode != -1) {
|
||||||
if (mode != previousMode) {
|
if (mode != previousMode) {
|
||||||
#if defined(_DEBUG)
|
log_info("swtching to mode : %d", mode);
|
||||||
printf("swtching to mode : %d\n", mode);
|
manage_tasks(previousMode, 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;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
switch (mode) {
|
execute_task(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
previousMode = mode;
|
previousMode = mode;
|
||||||
}
|
}
|
||||||
@ -122,6 +131,10 @@ int main(int argc, char const *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* Internal Function Definitions
|
||||||
|
**************************************************************************************************/
|
||||||
|
|
||||||
void parseCommandLineArgs(int argc, char const *argv[]) {
|
void parseCommandLineArgs(int argc, char const *argv[]) {
|
||||||
int args = 0;
|
int args = 0;
|
||||||
|
|
||||||
@ -130,28 +143,90 @@ void parseCommandLineArgs(int argc, char const *argv[]) {
|
|||||||
if (argv[args][0] == '-') {
|
if (argv[args][0] == '-') {
|
||||||
switch (toupper(argv[args][1])) {
|
switch (toupper(argv[args][1])) {
|
||||||
case 'N': // -N: number of LEDs per channel
|
case 'N': // -N: number of LEDs per channel
|
||||||
if (args >= argc - 1)
|
if (args >= argc - 1) {
|
||||||
fprintf(stderr, "Error: no numeric value\n");
|
log_error("no numeric value");
|
||||||
else
|
exit(-EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
chanLedCount = atoi(argv[++args]);
|
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;
|
break;
|
||||||
case 'T': // -T: test mode
|
case 'T': // -T: test mode
|
||||||
IsTestMode = true;
|
IsTestMode = true;
|
||||||
break;
|
break;
|
||||||
default: // Otherwise error
|
default: // Otherwise error
|
||||||
printf("Unrecognised option '%c'\n", argv[args][1]);
|
log_error("Unrecognised option '%c'\n", argv[args][1]);
|
||||||
printf("Options:\n"
|
fprintf(stderr, "Options:\n"
|
||||||
" -n num number of LEDs per channel\n"
|
" -t Test mode (flash LEDs)\n"
|
||||||
" -t Test mode (flash LEDs)\n");
|
" -n num number of LEDs per channel\n"
|
||||||
exit(1);
|
" -d lvl debug level\n");
|
||||||
|
exit(-EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void terminate(int sig) {
|
void terminate(int sig) {
|
||||||
|
manage_tasks(previousMode, -1);
|
||||||
leddriver_close();
|
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
|
// Pointer to uncached Tx data buffer
|
||||||
@ -159,13 +234,13 @@ void terminate(int sig) {
|
|||||||
|
|
||||||
void execute_test_mode() {
|
void execute_test_mode() {
|
||||||
// RGB values for test mode (1 value for each of 16 channels)
|
// 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;
|
uint32_t off_rgbs = 0x000000;
|
||||||
|
|
||||||
static int i = 0, offset = 0;
|
static int i = 0, offset = 0;
|
||||||
|
|
||||||
for (size_t ledIndex = 0; ledIndex < chanLedCount; ++ledIndex) {
|
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();
|
leddriver_refresh();
|
||||||
@ -205,7 +280,7 @@ void execute_autonomous_mode() {
|
|||||||
int ret;
|
int ret;
|
||||||
uint16_t *buffer;
|
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) {
|
for (size_t ledBarIndex = 0; ledBarIndex < 4; ++ledBarIndex) {
|
||||||
uint16_t barMax = 0;
|
uint16_t barMax = 0;
|
||||||
for (size_t bar = 0; bar < 20 / 4; ++bar) {
|
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) {
|
void adjust_loop(struct timespec const *loopStart) {
|
||||||
struct timespec loopEnd;
|
struct timespec loopEnd;
|
||||||
@ -242,11 +325,21 @@ void adjust_loop(struct timespec const *loopStart) {
|
|||||||
remainingTimeUs = 16000 - elapsedTimeUs;
|
remainingTimeUs = 16000 - elapsedTimeUs;
|
||||||
|
|
||||||
if (remainingTimeUs >= 0) {
|
if (remainingTimeUs >= 0) {
|
||||||
// printf("loop remaining time %ld\n", remainingTimeUs);
|
log_trace("cycle %lu, loop remaining time %ld", mainLoopCycle, remainingTimeUs);
|
||||||
usleep(remainingTimeUs);
|
usleep(remainingTimeUs);
|
||||||
} else {
|
} else {
|
||||||
printf("loop overlap by %06ldus\n", -remainingTimeUs);
|
log_warn("loop overlap by %06ldus", -remainingTimeUs);
|
||||||
printf("loop start %ld.%09lds\n", loopStart->tv_sec, loopStart->tv_nsec);
|
log_info("loop start %ld.%09lds - loop end %ld.%09lds", loopStart->tv_sec, loopStart->tv_nsec,
|
||||||
printf("loop end %ld.%09lds\n", loopEnd.tv_sec, loopEnd.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 "rpi_midi_controller.h"
|
||||||
|
|
||||||
#include <alsa/asoundlib.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;
|
static snd_seq_t *seq_handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boolean for interrupting the main thread loop
|
||||||
|
*/
|
||||||
static int sys_port;
|
static int sys_port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boolean for interrupting the main thread loop
|
||||||
|
*/
|
||||||
static int in_port;
|
static int in_port;
|
||||||
|
|
||||||
|
/* state machine */
|
||||||
|
int destChannel = 0xf;
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* Internal Function Prototypes
|
||||||
|
**************************************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief
|
||||||
|
*/
|
||||||
void subscribe_system_port();
|
void subscribe_system_port();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief
|
||||||
|
*
|
||||||
|
* \param controller
|
||||||
|
*/
|
||||||
void subscribe_midi_controller(snd_seq_addr_t controller);
|
void subscribe_midi_controller(snd_seq_addr_t controller);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief
|
||||||
|
*
|
||||||
|
* \param ev
|
||||||
|
*/
|
||||||
void handle_system_port_events(snd_seq_event_t *ev);
|
void handle_system_port_events(snd_seq_event_t *ev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief
|
||||||
|
*
|
||||||
|
* \param ev
|
||||||
|
*/
|
||||||
void handle_in_port_events(snd_seq_event_t *ev);
|
void handle_in_port_events(snd_seq_event_t *ev);
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* External Function Definitions
|
||||||
|
**************************************************************************************************/
|
||||||
|
|
||||||
void midi_controller_setup() {
|
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");
|
||||||
@ -23,8 +89,8 @@ void midi_controller_setup() {
|
|||||||
SNDERR("snd_seq_set_client_name");
|
SNDERR("snd_seq_set_client_name");
|
||||||
}
|
}
|
||||||
|
|
||||||
sys_port = snd_seq_create_simple_port(seq_handle, "listen:in",
|
sys_port = snd_seq_create_simple_port(seq_handle, "sys:in",
|
||||||
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT,
|
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
|
||||||
SND_SEQ_PORT_TYPE_APPLICATION);
|
SND_SEQ_PORT_TYPE_APPLICATION);
|
||||||
|
|
||||||
if (sys_port < 0) {
|
if (sys_port < 0) {
|
||||||
@ -52,10 +118,9 @@ void midi_controller_execute() {
|
|||||||
if (ev->dest.port == sys_port) {
|
if (ev->dest.port == sys_port) {
|
||||||
handle_system_port_events(ev);
|
handle_system_port_events(ev);
|
||||||
} else if (ev->dest.port == in_port) {
|
} else if (ev->dest.port == in_port) {
|
||||||
printf("ev %02d : %#010x - %#010x - %#010x\n", ev->type, ev->data.raw32.d[0],
|
handle_in_port_events(ev);
|
||||||
ev->data.raw32.d[1], ev->data.raw32.d[2]);
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "unkonwn midi dest port\n");
|
log_warn("Unkonwn midi dest port %d", ev->dest.port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret < 0 && ret != -EAGAIN) {
|
if (ret < 0 && ret != -EAGAIN) {
|
||||||
@ -65,6 +130,10 @@ void midi_controller_execute() {
|
|||||||
|
|
||||||
void midi_controller_close() {}
|
void midi_controller_close() {}
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* Internal Function Definitions
|
||||||
|
**************************************************************************************************/
|
||||||
|
|
||||||
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};
|
||||||
snd_seq_connect_from(seq_handle, sys_port, sender.client, sender.port);
|
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) {
|
if (ev->type == SND_SEQ_EVENT_PORT_START) {
|
||||||
snd_seq_addr_t *newport = (snd_seq_addr_t *)&ev->data;
|
snd_seq_addr_t *newport = (snd_seq_addr_t *)&ev->data;
|
||||||
if (newport->client != snd_seq_client_id(seq_handle)) {
|
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);
|
subscribe_midi_controller(*newport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_in_port_events(snd_seq_event_t *ev) {
|
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) {
|
if (ev->type == SND_SEQ_EVENT_PORT_START) {
|
||||||
snd_seq_addr_t *newport = (snd_seq_addr_t *)&ev->data;
|
snd_seq_addr_t *newport = (snd_seq_addr_t *)&ev->data;
|
||||||
if (newport->client != snd_seq_client_id(seq_handle)) {
|
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);
|
subscribe_midi_controller(*newport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,42 @@
|
|||||||
|
/** \file .h
|
||||||
|
* \brief This module
|
||||||
|
*/
|
||||||
#if !defined(__RPI_MIDI_CONTROLLER_H__)
|
#if !defined(__RPI_MIDI_CONTROLLER_H__)
|
||||||
#define __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();
|
void midi_controller_setup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief
|
||||||
|
*/
|
||||||
void midi_controller_execute();
|
void midi_controller_execute();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief
|
||||||
|
*/
|
||||||
void midi_controller_close();
|
void midi_controller_close();
|
||||||
|
|
||||||
#endif /* __RPI_MIDI_CONTROLLER_H__ */
|
#endif /* __RPI_MIDI_CONTROLLER_H__ */
|
@ -1 +1,58 @@
|
|||||||
|
/** \file .c
|
||||||
|
* \brief This module
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* Includes
|
||||||
|
**************************************************************************************************/
|
||||||
|
|
||||||
#include "rpi_param.h"
|
#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__)
|
#if !defined(__RPI_PARAM_H__)
|
||||||
#define __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__ */
|
#endif /* __RPI_PARAM_H__ */
|
@ -20,6 +20,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
#include "rpi_artnet_utils.h"
|
#include "rpi_artnet_utils.h"
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
@ -33,6 +34,7 @@
|
|||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* Persistent Variables
|
* Persistent Variables
|
||||||
**************************************************************************************************/
|
**************************************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boolean for interrupting the main thread loop
|
* Boolean for interrupting the main thread loop
|
||||||
*/
|
*/
|
||||||
@ -76,7 +78,7 @@ 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) {
|
||||||
perror("pthread_create");
|
log_error("pthread_create: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,23 +86,25 @@ void artnet_stop() {
|
|||||||
isUdpListenerRunning = false;
|
isUdpListenerRunning = false;
|
||||||
|
|
||||||
if (pthread_join(udpListener, NULL) != 0) {
|
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[]) {
|
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);
|
log_error("Universe %d out of bounds %d\n", univerve, 16);
|
||||||
*dmxData = NULL;
|
*dmxData = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*dmxData = artDmxBufferArray[univerve];
|
*dmxData = artDmxBufferArray[univerve];
|
||||||
|
log_trace("%d;%d;%d;%d", (*dmxData)[0], (*dmxData)[1], (*dmxData)[2], (*dmxData)[3]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* Internal Function Definitions
|
* Internal Function Definitions
|
||||||
**************************************************************************************************/
|
**************************************************************************************************/
|
||||||
|
|
||||||
static void *artnet_udp_handler(void *arg) {
|
static void *artnet_udp_handler(void *arg) {
|
||||||
int fdUdpSocket = -1;
|
int fdUdpSocket = -1;
|
||||||
struct pollfd pollFdArray[1];
|
struct pollfd pollFdArray[1];
|
||||||
@ -113,7 +117,7 @@ static void *artnet_udp_handler(void *arg) {
|
|||||||
/* Create UDP socket */
|
/* Create UDP socket */
|
||||||
fdUdpSocket = socket(PF_INET, SOCK_DGRAM, 0);
|
fdUdpSocket = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
if (fdUdpSocket < 0) {
|
if (fdUdpSocket < 0) {
|
||||||
perror("Opening socket failed");
|
log_error("Opening socket failed: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set non-blocking socket */
|
/* Set non-blocking socket */
|
||||||
@ -170,7 +174,7 @@ static void *artnet_udp_handler(void *arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (pollReturn < 0) {
|
} 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,
|
if (sendto(fdUdpSocket, (uint8_t *)&artPollReply, sizeof(artPollReply_t), 0,
|
||||||
(struct sockaddr *)&senderAddr, sizeof(senderAddr)) < 0) {
|
(struct sockaddr *)&senderAddr, sizeof(senderAddr)) < 0) {
|
||||||
fprintf(stderr, "Error sending poll reply to %s:%d: %s\n", inet_ntoa(senderAddr.sin_addr),
|
log_error("%s: sending poll reply to \"%s:%d\": %s", inet_ntoa(senderAddr.sin_addr),
|
||||||
strerror(errno));
|
senderAddr.sin_port, strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -139,7 +139,7 @@ typedef struct {
|
|||||||
uint8_t Filler[26]; // Filler bytes, currently zero.
|
uint8_t Filler[26]; // Filler bytes, currently zero.
|
||||||
} artPollReply_t;
|
} artPollReply_t;
|
||||||
|
|
||||||
static artPollReply_t artPollReply = {
|
static artPollReply_t const artPollReply = {
|
||||||
.ID = "Art-Net",
|
.ID = "Art-Net",
|
||||||
.OpCode = OpPollReply,
|
.OpCode = OpPollReply,
|
||||||
.IPAddr = {0},
|
.IPAddr = {0},
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <wait.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* Preprocessor Constants and Macros
|
* Preprocessor Constants and Macros
|
||||||
@ -65,48 +68,29 @@ uint16_t buffer[128 + 2];
|
|||||||
*/
|
*/
|
||||||
static void *fifo_to_buffer(void *arg);
|
static void *fifo_to_buffer(void *arg);
|
||||||
|
|
||||||
|
static int start_cava_process();
|
||||||
|
|
||||||
|
static void stop_cava_process();
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* External Function Definitions
|
* External Function Definitions
|
||||||
**************************************************************************************************/
|
**************************************************************************************************/
|
||||||
|
|
||||||
void setup_cava() {
|
void cava_start() {
|
||||||
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() {
|
|
||||||
isFifoReaderRunning = true;
|
isFifoReaderRunning = true;
|
||||||
pthread_create(&fifoReader, NULL, fifo_to_buffer, NULL);
|
pthread_create(&fifoReader, NULL, fifo_to_buffer, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop_cava_bg_worker() {
|
void cava_stop() {
|
||||||
isFifoReaderRunning = false;
|
isFifoReaderRunning = false;
|
||||||
if (pthread_join(fifoReader, NULL) != 0) {
|
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;
|
*buffer_dst = buffer;
|
||||||
|
log_trace("%d;%d;%d;%d", buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,12 +106,8 @@ static void *fifo_to_buffer(void *arg) {
|
|||||||
char strValue[6] = "0\0";
|
char strValue[6] = "0\0";
|
||||||
bool hasToBeDiscarded = true;
|
bool hasToBeDiscarded = true;
|
||||||
|
|
||||||
if start_cava_process ()
|
if ((fdCavaInput = start_cava_process()) < 0) {
|
||||||
;
|
log_error("y'a un truc qui a pas marché");
|
||||||
if ((fdCavaInput = open("/tmp/cava_output", O_RDONLY | O_NONBLOCK)) < 0) {
|
|
||||||
perror("open");
|
|
||||||
close_cava();
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(fds, 0, sizeof(fds));
|
memset(fds, 0, sizeof(fds));
|
||||||
@ -165,26 +145,27 @@ static void *fifo_to_buffer(void *arg) {
|
|||||||
valueIndex = 0;
|
valueIndex = 0;
|
||||||
|
|
||||||
if (valueIndex > 129) {
|
if (valueIndex > 129) {
|
||||||
fprintf(stderr, "Buffer overflow, \\n missed, discarding next\n");
|
log_warn("Buffer overflow, \\n missed, discarding next");
|
||||||
hasToBeDiscarded = true;
|
hasToBeDiscarded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unexpected char %d [%c]\n", current, current);
|
log_warn("Unexpected char %d [%c]\n", current, current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (errno != EAGAIN) {
|
if (errno != EAGAIN) {
|
||||||
perror("read");
|
log_error("read: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ret < 0) {
|
} 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);
|
close(fdCavaInput);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -194,17 +175,18 @@ static int start_cava_process() {
|
|||||||
int fdCavaPipe[2];
|
int fdCavaPipe[2];
|
||||||
|
|
||||||
if (pipe(fdCavaPipe) < 0) {
|
if (pipe(fdCavaPipe) < 0) {
|
||||||
fprintf(stderr, "Cava pipe failure: %s\n", strerror(errno));
|
log_error("Cava pipe failure: %s", strerror(errno));
|
||||||
return -EXIT_FAILURE;
|
return -EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cavaPid = fork()) < 0) {
|
if ((cavaPid = fork()) < 0) {
|
||||||
fprintf(stderr, "Cava fork failure: %s\n", strerror(errno));
|
log_error("Cava fork failure: %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(-EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cavaPid == 0) {
|
if (cavaPid == 0) {
|
||||||
/* Child process*/
|
/* Child process*/
|
||||||
|
int fdLogOut;
|
||||||
char *args[] = {"cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL};
|
char *args[] = {"cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL};
|
||||||
|
|
||||||
/* Close reading end of the pipe */
|
/* Close reading end of the pipe */
|
||||||
@ -214,10 +196,16 @@ static int start_cava_process() {
|
|||||||
/* Close writing end of the pipe */
|
/* Close writing end of the pipe */
|
||||||
close(fdCavaPipe[1]);
|
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);
|
execvp(args[0], args);
|
||||||
fprintf(stderr, "Cava execvp failure or return: %s\n", strerror(errno));
|
log_error("Cava execvp failure or return: %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(-EXIT_FAILURE);
|
||||||
} else {
|
} else {
|
||||||
|
int flags;
|
||||||
/* Close writing end of the pipe */
|
/* Close writing end of the pipe */
|
||||||
close(fdCavaPipe[1]);
|
close(fdCavaPipe[1]);
|
||||||
/* Set reading end of the pipe non-blocking */
|
/* Set reading end of the pipe non-blocking */
|
||||||
@ -231,4 +219,7 @@ static int start_cava_process() {
|
|||||||
return -1;
|
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();
|
void setup_cava();
|
||||||
|
|
||||||
int get_cava_buffer(uint16_t **buffer_dst);
|
int cava_get_buffer(uint16_t **buffer_dst);
|
||||||
|
|
||||||
void close_cava();
|
void close_cava();
|
||||||
|
|
||||||
void start_cava_bg_worker();
|
void cava_start();
|
||||||
|
|
||||||
void stop_cava_bg_worker();
|
void cava_stop();
|
||||||
|
|
||||||
#endif /* __RPI_CAVA_H__ */
|
#endif /* __RPI_CAVA_H__ */
|
Loading…
Reference in New Issue
Block a user