logging facility (log.c librarie), template, minor bug fixes, param init

This commit is contained in:
Tropicananass 2021-07-31 17:13:15 +01:00
parent a5da739f65
commit 0ccd9e7d46
17 changed files with 650 additions and 181 deletions

View File

@ -1,6 +1,6 @@
CC := gcc
CFLAGS := -Wall -g -D_DEBUG
LDFLAGS := -lwiringPi -lasound -lfftw3 -lpthread -lm
CFLAGS := -Wall -g -Ilibs/log.c/src
LDFLAGS := -lwiringPi -lasound -lfftw3 -lpthread -lm -L.libs
SRC := src
OBJ := obj
@ -9,20 +9,26 @@ BIN := bin/pixled
SOURCES := $(shell find $(SRC) -type f -name "*.c")
OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
.PHONY: all clean debug
all: $(BIN)
libs/log.c/obj/log.o: libs/log.c/src/log.c
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
$(CC) -c $< -o $@ -DLOG_USE_COLOR
.libs/log.la: libs/log.c/obj/log.o
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
ar r $@ $^
ranlib $@
$(OBJ)/%.o: $(SRC)/%.c
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
$(CC) -I$(SRC) -c $< -o $@ $(CFLAGS)
$(CC) -c $< -o $@ $(CFLAGS)
$(BIN) : $(OBJECTS)
if [ ! -d "$(dir $(BIN))" ]; then mkdir -p "$(dir $(BIN))"; fi
$(BIN): $(OBJECTS) .libs/log.la
if [ ! -d "$(dir $@)" ]; then mkdir -p "$(dir $@)"; fi
$(CC) -o $@ $^ $(LDFLAGS)
liblog.a: log.o
ar $(ARFLAGS) $@ $^
clean:
rm -rf $(OBJ)
rm -rf $(OBJ) .libs libs/*/obj

View File

@ -1,6 +1,7 @@
https://makersportal.com/blog/recording-stereo-audio-on-a-raspberry-pi
https://learn.adafruit.com/adafruit-i2s-mems-microphone-breakout/raspberry-pi-wiring-test
sudo apt install python3-pip
sudo pip3 install --upgrade adafruit-python-shell
cd /tmp
sudo wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/i2smic.py
@ -16,3 +17,13 @@ cp res/.asoundrc ~/.asoundrc
# alsa API
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

View File

@ -3,9 +3,12 @@
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include "log.h"
// Use mmap to obtain virtual address, given physical
void *map_periph(MEM_MAP *mp, void *phys, int size) {
mp->phys = phys;
@ -30,20 +33,24 @@ void *map_segment(void *addr, int size) {
void *mem;
size = PAGE_ROUNDUP(size);
if ((fd = open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0)
fprintf(stderr, "Error: can't open /dev/mem, run using sudo\n");
if ((fd = open("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0) {
log_fatal("can't open /dev/mem, run using sudo");
exit(-EXIT_FAILURE);
}
mem = mmap(0, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, (uint32_t)addr);
close(fd);
#if DEBUG
printf("Map %p -> %p\n", (void *)addr, mem);
#endif
if (mem == MAP_FAILED)
fprintf(stderr, "Error: can't map memory\n");
log_info("Map %p -> %p", (void *)addr, mem);
if (mem == MAP_FAILED) {
log_fatal("can't map memory");
exit(-EXIT_FAILURE);
}
return (mem);
}
// Free mapped memory
void unmap_segment(void *mem, int size) {
if (mem)
if (mem) {
munmap(mem, PAGE_ROUNDUP(size));
}
}

View File

@ -5,6 +5,8 @@
#include <sys/ioctl.h>
#include <unistd.h>
#include "log.h"
// Mailbox command/response structure
typedef struct {
uint32_t len, // Overall length (bytes)
@ -42,7 +44,7 @@ void *map_uncached_mem(MEM_MAP *mp, int size) {
(mp->virt = map_segment(BUS_PHYS_ADDR(mp->bus), mp->size)) != 0
? mp->virt
: 0;
printf("VC mem handle %u, phys %p, virt %p\n", mp->h, mp->bus, mp->virt);
log_info("VC mem handle %u, phys %p, virt %p", mp->h, mp->bus, mp->virt);
return (ret);
}
@ -93,7 +95,7 @@ int open_mbox(void) {
int fd;
if ((fd = open("/dev/vcio", 0)) < 0)
fprintf(stderr, "Error: can't open VC mailbox\n");
log_error("can't open VC mailbox");
return (fd);
}
// Close mailbox interface
@ -110,14 +112,15 @@ uint32_t msg_mbox(int fd, VC_MSG *msgp) {
msgp->uints[i++] = 0;
msgp->len = (msgp->blen + 6) * 4;
msgp->req = 0;
if (ioctl(fd, _IOWR(100, 0, void *), msgp) < 0)
printf("VC IOCTL failed\n");
else if ((msgp->req & 0x80000000) == 0)
printf("VC IOCTL error\n");
else if (msgp->req == 0x80000001)
printf("VC IOCTL partial error\n");
else
if (ioctl(fd, _IOWR(100, 0, void *), msgp) < 0) {
log_error("VC IOCTL failed");
} else if ((msgp->req & 0x80000000) == 0) {
log_error("VC IOCTL error");
} else if (msgp->req == 0x80000001) {
log_error("VC IOCTL partial error");
} else {
ret = msgp->uints[0];
}
#if DEBUG
disp_vc_msg(msgp);
#endif

View File

@ -4,6 +4,7 @@
#include <string.h>
#include <unistd.h>
#include "../../rpi_param.h"
#include "../common.h"
#include "../dma/rpi_dma.h"
@ -49,13 +50,12 @@ TXDATA_T tx_buffer[TX_BUFF_LEN(CHAN_MAXLEDS)];
void swap_bytes();
void leddriver_setup() {
gpio_setup();
videocore_setup(&vc_mem, VC_MEM_SIZE);
gpio_setup();
smi_setup(LED_NCHANS, SMI_TIMING, &vc_mem, TX_BUFF_LEN(CHAN_MAXLEDS), &txdata);
}
void leddriver_close() {
printf("Closing\n");
videocore_close(&vc_mem);
smi_close(LED_NCHANS);
gpio_close();
@ -130,3 +130,81 @@ void swap_bytes() {
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);
}

View File

@ -3,9 +3,6 @@
#include <stdint.h>
#define CHAN_MAXLEDS 6 * 60 // Maximum number of LEDs per channel
#define LED_NCHANS 8 // Number of LED channels (8 or 16)
void leddriver_setup();
void leddriver_close();

View File

@ -5,6 +5,8 @@
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include "rpi_selector.h"
#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>
@ -19,6 +21,7 @@
unsigned const selectorPinNumber = 4;
/* TODO use GPIO function from ../gpio/gipo.h (same pin number) */
int selectorPins[4] = {5, 6, 26, 27};
char modeStr[] = "0 | 0 | 0 | 0 \n";
/***************************************************************************************************
* Persistent Variables
@ -49,12 +52,11 @@ int selector_get_position() {
return -1;
}
void selector_print() {
char modeStr[] = "0 | 0 | 0 | 0 \n";
char *selector_tostr() {
for (size_t i = 0; i < selectorPinNumber; ++i) {
modeStr[i * 4] = digitalRead(selectorPins[i]) ? '1' : '0';
}
fprintf(stderr, modeStr);
return modeStr;
}
/***************************************************************************************************

View File

@ -33,8 +33,8 @@ void selector_setup();
int selector_get_position();
/**
* \brief debug: print the selector position
* \brief Get string with selector debug info
**/
void selector_print();
char *selector_tostr();
#endif /* __RPI_SELECTOR_H__ */

View File

@ -1,4 +1,12 @@
/** \file main.c
* \brief This is the main exectution program
*/
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include <ctype.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
@ -8,23 +16,51 @@
#include <time.h>
#include <unistd.h>
#include "log.h"
#include "drivers/leddriver/rpi_leddriver.h"
#include "drivers/selector/rpi_selector.h"
#include "rpi_midi_controller.h"
#include "tasks/artnet/rpi_artnet.h"
#include "tasks/cava/rpi_cava.h"
#include "rpi_midi_controller.h"
#include "rpi_param.h"
/***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
/***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
/***************************************************************************************************
* Persistent Variables
**************************************************************************************************/
/* Command-line parameters */
bool IsTestMode = false;
int chanLedCount = 0;
int logLevel = 2;
pthread_t *bgTasks[4] = {NULL};
int previousMode = -1;
unsigned long mainLoopCycle = 0;
pthread_mutex_t logLockMutex = PTHREAD_MUTEX_INITIALIZER;
/***************************************************************************************************
* Internal Function Prototypes
**************************************************************************************************/
void parseCommandLineArgs(int argc, char const *argv[]);
void terminate(int sig);
void manage_tasks(int previousMode, int currentMode);
void execute_task(int mode);
void execute_test_mode();
void execute_artnet_mode();
@ -35,63 +71,142 @@ void execute_manual_mode();
void adjust_loop(struct timespec const *loopStart);
int main(int argc, char const *argv[]) {
int previousMode = -1;
void log_lock_helper(bool lock, void *udata);
/***************************************************************************************************
* External Function Definitions
**************************************************************************************************/
int main(int argc, char const *argv[]) {
// setup
parseCommandLineArgs(argc, argv);
log_set_level(logLevel);
signal(SIGINT, terminate);
struct sched_param sp;
sp.sched_priority = 32;
if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) {
fprintf(stderr, "WARNING: Failed to set stepper thread to real-time priority\n");
}
// struct sched_param sp;
// sp.sched_priority = 32;
// if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) {
// fprintf(stderr, "WARNING: Failed to set stepper thread to real-time priority: %s\n",
// strerror(errno));
// }
log_set_lock(log_lock_helper, &logLockMutex);
param_setup();
midi_controller_setup();
selector_setup();
leddriver_setup();
artnet_init();
setup_cava();
// setup_cava();
// loop
while (1) {
struct timespec loopStart;
int mode;
clock_gettime(CLOCK_MONOTONIC, &loopStart);
int mode = selector_get_position();
if (IsTestMode) {
if (mainLoopCycle % 300 < 150) {
mode = 2;
} else {
mode = 1;
}
} else {
mode = selector_get_position();
}
/* todo thread ? */
midi_controller_execute();
if (mode != -1) {
if (mode != previousMode) {
#if defined(_DEBUG)
printf("swtching to mode : %d\n", mode);
#endif
log_info("swtching to mode : %d", mode);
manage_tasks(previousMode, mode);
} else {
execute_task(mode);
}
previousMode = mode;
}
adjust_loop(&loopStart);
}
}
/***************************************************************************************************
* Internal Function Definitions
**************************************************************************************************/
void parseCommandLineArgs(int argc, char const *argv[]) {
int args = 0;
while (argc > ++args) // Process command-line args
{
if (argv[args][0] == '-') {
switch (toupper(argv[args][1])) {
case 'N': // -N: number of LEDs per channel
if (args >= argc - 1) {
log_error("no numeric value");
exit(-EXIT_FAILURE);
} else {
chanLedCount = atoi(argv[++args]);
}
break;
case 'D': // -D: debug level
if (args >= argc - 1) {
log_error("no debug level");
exit(-EXIT_FAILURE);
} else {
logLevel = atoi(argv[++args]);
}
break;
case 'T': // -T: test mode
IsTestMode = true;
break;
default: // Otherwise error
log_error("Unrecognised option '%c'\n", argv[args][1]);
fprintf(stderr, "Options:\n"
" -t Test mode (flash LEDs)\n"
" -n num number of LEDs per channel\n"
" -d lvl debug level\n");
exit(-EXIT_FAILURE);
}
}
}
}
void terminate(int sig) {
manage_tasks(previousMode, -1);
leddriver_close();
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:
stop_cava_bg_worker();
cava_stop();
break;
default:
break;
}
/* start new bg task */
switch (mode) {
switch (currentMode) {
case 1:
artnet_start();
break;
case 2:
start_cava_bg_worker();
cava_start();
break;
default:
break;
}
} else {
}
void execute_task(int mode) {
switch (mode) {
case 0:
// mode test
@ -110,62 +225,22 @@ int main(int argc, char const *argv[]) {
break;
default:
if (mode != previousMode) {
fprintf(stderr, "Error in selector\n");
}
break;
}
}
previousMode = mode;
}
adjust_loop(&loopStart);
}
}
void parseCommandLineArgs(int argc, char const *argv[]) {
int args = 0;
while (argc > ++args) // Process command-line args
{
if (argv[args][0] == '-') {
switch (toupper(argv[args][1])) {
case 'N': // -N: number of LEDs per channel
if (args >= argc - 1)
fprintf(stderr, "Error: no numeric value\n");
else
chanLedCount = atoi(argv[++args]);
break;
case 'T': // -T: test mode
IsTestMode = true;
break;
default: // Otherwise error
printf("Unrecognised option '%c'\n", argv[args][1]);
printf("Options:\n"
" -n num number of LEDs per channel\n"
" -t Test mode (flash LEDs)\n");
exit(1);
}
}
}
}
void terminate(int sig) {
leddriver_close();
exit(0);
}
// Pointer to uncached Tx data buffer
// TXDATA_T tx_buffer[TX_BUFF_LEN(CHAN_MAXLEDS)]; // Tx buffer for assembling data
void execute_test_mode() {
// RGB values for test mode (1 value for each of 16 channels)
uint32_t on_rgbs[] = {0xef0000, 0x00ef00, 0x0000ef, 0xefef00, 0xef00ef, 0x00efef, 0xefefef};
uint32_t on_rgbs[] = {0x5f0000, 0x005f00, 0x00005f, 0x5f5f00, 0x5f005f, 0x005f5f, 0x5f5f5f};
uint32_t off_rgbs = 0x000000;
static int i = 0, offset = 0;
for (size_t ledIndex = 0; ledIndex < chanLedCount; ++ledIndex) {
set_color(ledIndex <= offset % chanLedCount ? on_rgbs[i] : off_rgbs, ledIndex);
set_color(ledIndex <= offset % chanLedCount ? on_rgbs[i] * .5 : off_rgbs, ledIndex);
}
leddriver_refresh();
@ -205,7 +280,7 @@ void execute_autonomous_mode() {
int ret;
uint16_t *buffer;
if ((ret = get_cava_buffer(&buffer)) == 0) {
if ((ret = cava_get_buffer(&buffer)) == 0) {
for (size_t ledBarIndex = 0; ledBarIndex < 4; ++ledBarIndex) {
uint16_t barMax = 0;
for (size_t bar = 0; bar < 20 / 4; ++bar) {
@ -230,7 +305,15 @@ void execute_autonomous_mode() {
}
}
void execute_manual_mode() {}
void execute_manual_mode() {
for (size_t ledBarIndex = 0; ledBarIndex < LED_NCHANS; ++ledBarIndex) {
for (size_t i = 0; i < chanLedCount; ++i) {
rgb_data[i][ledBarIndex] = 0x000000;
rgb_txdata(rgb_data[i], i);
}
}
leddriver_refresh();
}
void adjust_loop(struct timespec const *loopStart) {
struct timespec loopEnd;
@ -242,11 +325,21 @@ void adjust_loop(struct timespec const *loopStart) {
remainingTimeUs = 16000 - elapsedTimeUs;
if (remainingTimeUs >= 0) {
// printf("loop remaining time %ld\n", remainingTimeUs);
log_trace("cycle %lu, loop remaining time %ld", mainLoopCycle, remainingTimeUs);
usleep(remainingTimeUs);
} else {
printf("loop overlap by %06ldus\n", -remainingTimeUs);
printf("loop start %ld.%09lds\n", loopStart->tv_sec, loopStart->tv_nsec);
printf("loop end %ld.%09lds\n", loopEnd.tv_sec, loopEnd.tv_nsec);
log_warn("loop overlap by %06ldus", -remainingTimeUs);
log_info("loop start %ld.%09lds - loop end %ld.%09lds", loopStart->tv_sec, loopStart->tv_nsec,
loopEnd.tv_sec, loopEnd.tv_nsec);
}
++mainLoopCycle;
}
void log_lock_helper(bool lock, void *udata) {
pthread_mutex_t *pLogLockMutex = (pthread_mutex_t *)(udata);
if (lock) {
pthread_mutex_lock(pLogLockMutex);
} else {
pthread_mutex_unlock(pLogLockMutex);
}
}

View File

@ -1,19 +1,85 @@
/** \file .c
* \brief This module
*/
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include "rpi_midi_controller.h"
#include <alsa/asoundlib.h>
#include "log.h"
#include "rpi_param.h"
/***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
#define C3 0x30
/***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
/***************************************************************************************************
* Persistent Variables
**************************************************************************************************/
/**
* Boolean for interrupting the main thread loop
*/
static snd_seq_t *seq_handle;
/**
* Boolean for interrupting the main thread loop
*/
static int sys_port;
/**
* Boolean for interrupting the main thread loop
*/
static int in_port;
/* state machine */
int destChannel = 0xf;
/***************************************************************************************************
* Internal Function Prototypes
**************************************************************************************************/
/**
* \brief
*/
void subscribe_system_port();
/**
* \brief
*
* \param controller
*/
void subscribe_midi_controller(snd_seq_addr_t controller);
/**
* \brief
*
* \param ev
*/
void handle_system_port_events(snd_seq_event_t *ev);
/**
* \brief
*
* \param ev
*/
void handle_in_port_events(snd_seq_event_t *ev);
/***************************************************************************************************
* External Function Definitions
**************************************************************************************************/
void midi_controller_setup() {
if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK) != 0) {
SNDERR("snd_seq_open");
@ -23,8 +89,8 @@ void midi_controller_setup() {
SNDERR("snd_seq_set_client_name");
}
sys_port = snd_seq_create_simple_port(seq_handle, "listen:in",
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT,
sys_port = snd_seq_create_simple_port(seq_handle, "sys:in",
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
SND_SEQ_PORT_TYPE_APPLICATION);
if (sys_port < 0) {
@ -52,10 +118,9 @@ void midi_controller_execute() {
if (ev->dest.port == sys_port) {
handle_system_port_events(ev);
} else if (ev->dest.port == in_port) {
printf("ev %02d : %#010x - %#010x - %#010x\n", ev->type, ev->data.raw32.d[0],
ev->data.raw32.d[1], ev->data.raw32.d[2]);
handle_in_port_events(ev);
} else {
fprintf(stderr, "unkonwn midi dest port\n");
log_warn("Unkonwn midi dest port %d", ev->dest.port);
}
}
if (ret < 0 && ret != -EAGAIN) {
@ -65,6 +130,10 @@ void midi_controller_execute() {
void midi_controller_close() {}
/***************************************************************************************************
* Internal Function Definitions
**************************************************************************************************/
void subscribe_system_port() {
snd_seq_addr_t sender = {.client = 0, .port = SND_SEQ_PORT_SYSTEM_ANNOUNCE};
snd_seq_connect_from(seq_handle, sys_port, sender.client, sender.port);
@ -78,17 +147,60 @@ void handle_system_port_events(snd_seq_event_t *ev) {
if (ev->type == SND_SEQ_EVENT_PORT_START) {
snd_seq_addr_t *newport = (snd_seq_addr_t *)&ev->data;
if (newport->client != snd_seq_client_id(seq_handle)) {
fprintf(stdout, "New port %d:%d\n", newport->client, newport->port);
log_info("New port %d:%d", newport->client, newport->port);
subscribe_midi_controller(*newport);
}
}
}
void handle_in_port_events(snd_seq_event_t *ev) {
switch (ev->type) {
case SND_SEQ_EVENT_PGMCHANGE:
if (ev->data.control.value < LED_NCHANS) {
if (ev->data.control.value != destChannel) {
destChannel = ev->data.control.value;
log_info("Control param channel %d", ev->data.control.value);
}
} else {
log_debug("PGMCHANGE : ch %#04x - param %u - value %d", ev->data.control.channel,
ev->data.control.param, ev->data.control.value);
}
break;
case SND_SEQ_EVENT_NOTEON:
if (ev->data.note.note == C3) {
if (destChannel != 0xf) {
destChannel = 0xf;
log_info("Control global param");
}
} else {
log_debug("NOTEON : ch %#04x - note %d - vel %d", ev->data.note.channel, ev->data.note.note,
ev->data.note.velocity);
}
break;
case SND_SEQ_EVENT_CONTROLLER:
switch (ev->data.control.param) {
case 1:
break;
default:
break;
}
log_debug("CONTROLLER : ch %#04x - param %u - value %d", ev->data.control.channel,
ev->data.control.param, ev->data.control.value);
break;
default:
log_debug("ev %02d : %#010x - %#010x - %#010x", ev->type, ev->data.raw32.d[0],
ev->data.raw32.d[1], ev->data.raw32.d[2]);
break;
}
if (ev->type == SND_SEQ_EVENT_PORT_START) {
snd_seq_addr_t *newport = (snd_seq_addr_t *)&ev->data;
if (newport->client != snd_seq_client_id(seq_handle)) {
fprintf(stdout, "New port %d:%d\n", newport->client, newport->port);
log_debug("New port %d:%d", newport->client, newport->port);
subscribe_midi_controller(*newport);
}
}

View File

@ -1,10 +1,42 @@
/** \file .h
* \brief This module
*/
#if !defined(__RPI_MIDI_CONTROLLER_H__)
#define __RPI_MIDI_CONTROLLER_H__
/***************************************************************************************************
* Includes
**************************************************************************************************/
/***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
/***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
/***************************************************************************************************
* Global Variables
**************************************************************************************************/
/***************************************************************************************************
* External Function Prototypes
**************************************************************************************************/
/**
* \brief
*/
void midi_controller_setup();
/**
* \brief
*/
void midi_controller_execute();
/**
* \brief
*/
void midi_controller_close();
#endif /* __RPI_MIDI_CONTROLLER_H__ */

View File

@ -1 +1,58 @@
/** \file .c
* \brief This module
*/
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include "rpi_param.h"
#include <stdlib.h>
/***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
/***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
pixled_param_t const dummyPixledParam = {.intensity = .5, .hue = 0};
auton_param_t const dummyAutonParam = {.sensitivity = 1};
ledbar_param_t const dummyLedbarParam = {.sensitivity = 1};
/***************************************************************************************************
* Persistent Variables
**************************************************************************************************/
param_t param;
/***************************************************************************************************
* Internal Function Prototypes
**************************************************************************************************/
/***************************************************************************************************
* External Function Definitions
**************************************************************************************************/
void param_setup() {
param.pixled = dummyPixledParam;
param.auton = dummyAutonParam;
for (size_t i = 0; i < 10; ++i) {
param.ledbar[i] = dummyLedbarParam;
}
param_access = &param;
}
void set_sensitivity(int channel, unsigned int sensitivity) {
if (channel >= 10) {
param.auton.sensitivity = sensitivity;
} else {
param.ledbar[channel].sensitivity = sensitivity;
}
}
/***************************************************************************************************
* Internal Function Definitions
**************************************************************************************************/

View File

@ -1,4 +1,80 @@
/** \file .h
* \brief This module
*/
#if !defined(__RPI_PARAM_H__)
#define __RPI_PARAM_H__
/***************************************************************************************************
* Includes
**************************************************************************************************/
#include <stdint.h>
/***************************************************************************************************
* Preprocessor Constants and Macros
**************************************************************************************************/
#define CHAN_MAXLEDS 6 * 60 // Maximum number of LEDs per channel
#define LED_NCHANS 8 // Number of LED channels (8 or 16)
/***************************************************************************************************
* Type and Contant Definitions
**************************************************************************************************/
/**
*
*/
typedef struct {
uint8_t intensity;
int hue;
} pixled_param_t;
/**
*
*/
typedef struct {
unsigned int sensitivity;
} auton_param_t;
/**
*
*/
typedef struct {
unsigned int sensitivity;
} ledbar_param_t;
/**
*
*/
typedef struct {
pixled_param_t pixled;
auton_param_t auton;
ledbar_param_t ledbar[10];
} param_t;
/***************************************************************************************************
* Global Variables
**************************************************************************************************/
static param_t *param_access;
/***************************************************************************************************
* External Function Prototypes
**************************************************************************************************/
/**
* \brief
*/
void param_setup();
/**
* \brief
*
* \param[in] channel
*
* \param[in] sensitivity
*/
void set_sensitivity(int channel, unsigned int sensitivity);
#endif /* __RPI_PARAM_H__ */

View File

@ -20,6 +20,7 @@
#include <sys/socket.h>
#include <unistd.h>
#include "log.h"
#include "rpi_artnet_utils.h"
/***************************************************************************************************
@ -33,6 +34,7 @@
/***************************************************************************************************
* Persistent Variables
**************************************************************************************************/
/**
* Boolean for interrupting the main thread loop
*/
@ -76,7 +78,7 @@ void artnet_start() {
isUdpListenerRunning = true;
if (pthread_create(&udpListener, NULL, artnet_udp_handler, NULL) < 0) {
perror("pthread_create");
log_error("pthread_create: %s", strerror(errno));
}
}
@ -84,23 +86,25 @@ void artnet_stop() {
isUdpListenerRunning = false;
if (pthread_join(udpListener, NULL) != 0) {
perror("pthread_join");
log_error("pthread_join: %s", strerror(errno));
}
}
int artnet_get_dmx_data(unsigned int univerve, uint8_t *dmxData[]) {
if (univerve > 8) {
fprintf(stderr, "Universe %d out of bounds %d\n", univerve, 16);
log_error("Universe %d out of bounds %d\n", univerve, 16);
*dmxData = NULL;
return -1;
}
*dmxData = artDmxBufferArray[univerve];
log_trace("%d;%d;%d;%d", (*dmxData)[0], (*dmxData)[1], (*dmxData)[2], (*dmxData)[3]);
return 0;
}
/***************************************************************************************************
* Internal Function Definitions
**************************************************************************************************/
static void *artnet_udp_handler(void *arg) {
int fdUdpSocket = -1;
struct pollfd pollFdArray[1];
@ -113,7 +117,7 @@ static void *artnet_udp_handler(void *arg) {
/* Create UDP socket */
fdUdpSocket = socket(PF_INET, SOCK_DGRAM, 0);
if (fdUdpSocket < 0) {
perror("Opening socket failed");
log_error("Opening socket failed: %s", strerror(errno));
}
/* Set non-blocking socket */
@ -170,7 +174,7 @@ static void *artnet_udp_handler(void *arg) {
}
} else if (pollReturn < 0) {
fprintf(stderr, "error polling %d: %s\n", fdUdpSocket, strerror(errno));
log_error("error polling %d: %s", fdUdpSocket, strerror(errno));
}
}
@ -187,7 +191,7 @@ static void artnet_send_poll_reply(int fdUdpSocket, struct sockaddr_in senderAdd
if (sendto(fdUdpSocket, (uint8_t *)&artPollReply, sizeof(artPollReply_t), 0,
(struct sockaddr *)&senderAddr, sizeof(senderAddr)) < 0) {
fprintf(stderr, "Error sending poll reply to %s:%d: %s\n", inet_ntoa(senderAddr.sin_addr),
strerror(errno));
log_error("%s: sending poll reply to \"%s:%d\": %s", inet_ntoa(senderAddr.sin_addr),
senderAddr.sin_port, strerror(errno));
}
}

View File

@ -139,7 +139,7 @@ typedef struct {
uint8_t Filler[26]; // Filler bytes, currently zero.
} artPollReply_t;
static artPollReply_t artPollReply = {
static artPollReply_t const artPollReply = {
.ID = "Art-Net",
.OpCode = OpPollReply,
.IPAddr = {0},

View File

@ -17,6 +17,9 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include "log.h"
/***************************************************************************************************
* Preprocessor Constants and Macros
@ -65,48 +68,29 @@ uint16_t buffer[128 + 2];
*/
static void *fifo_to_buffer(void *arg);
static int start_cava_process();
static void stop_cava_process();
/***************************************************************************************************
* External Function Definitions
**************************************************************************************************/
void setup_cava() {
if ((cavaPid = fork()) == -1) {
perror("fork");
exit(1);
}
if (cavaPid == 0) {
/* Child process*/
char *args[] = {"/usr/local/bin/cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL};
if (execv(args[0], args) != 0) {
perror("execv");
}
} else {
sleep(1);
}
}
void close_cava() {
stop_cava_bg_worker();
kill(cavaPid, SIGTERM);
}
void start_cava_bg_worker() {
void cava_start() {
isFifoReaderRunning = true;
pthread_create(&fifoReader, NULL, fifo_to_buffer, NULL);
}
void stop_cava_bg_worker() {
void cava_stop() {
isFifoReaderRunning = false;
if (pthread_join(fifoReader, NULL) != 0) {
perror("pthread_join");
log_error("pthread_join: %s", strerror(errno));
}
}
int get_cava_buffer(uint16_t **buffer_dst) {
int cava_get_buffer(uint16_t **buffer_dst) {
*buffer_dst = buffer;
log_trace("%d;%d;%d;%d", buffer[0], buffer[1], buffer[2], buffer[3]);
return 0;
}
@ -122,12 +106,8 @@ static void *fifo_to_buffer(void *arg) {
char strValue[6] = "0\0";
bool hasToBeDiscarded = true;
if start_cava_process ()
;
if ((fdCavaInput = open("/tmp/cava_output", O_RDONLY | O_NONBLOCK)) < 0) {
perror("open");
close_cava();
exit(1);
if ((fdCavaInput = start_cava_process()) < 0) {
log_error("y'a un truc qui a pas marché");
}
memset(fds, 0, sizeof(fds));
@ -165,26 +145,27 @@ static void *fifo_to_buffer(void *arg) {
valueIndex = 0;
if (valueIndex > 129) {
fprintf(stderr, "Buffer overflow, \\n missed, discarding next\n");
log_warn("Buffer overflow, \\n missed, discarding next");
hasToBeDiscarded = true;
}
}
} else {
fprintf(stderr, "Unexpected char %d [%c]\n", current, current);
log_warn("Unexpected char %d [%c]\n", current, current);
}
}
}
} else {
if (errno != EAGAIN) {
perror("read");
log_error("read: %s", strerror(errno));
}
}
} else if (ret < 0) {
fprintf(stderr, "error polling %d: %s\n", fdCavaInput, strerror(errno));
log_error("polling %d: %s\n", fdCavaInput, strerror(errno));
}
}
stop_cava_process();
close(fdCavaInput);
return NULL;
@ -194,17 +175,18 @@ static int start_cava_process() {
int fdCavaPipe[2];
if (pipe(fdCavaPipe) < 0) {
fprintf(stderr, "Cava pipe failure: %s\n", strerror(errno));
log_error("Cava pipe failure: %s", strerror(errno));
return -EXIT_FAILURE;
}
if ((cavaPid = fork()) < 0) {
fprintf(stderr, "Cava fork failure: %s\n", strerror(errno));
exit(EXIT_FAILURE);
log_error("Cava fork failure: %s", strerror(errno));
exit(-EXIT_FAILURE);
}
if (cavaPid == 0) {
/* Child process*/
int fdLogOut;
char *args[] = {"cava", "-p", "/home/pi/LedBars/RpiLedBars/cava_config", NULL};
/* Close reading end of the pipe */
@ -214,10 +196,16 @@ static int start_cava_process() {
/* Close writing end of the pipe */
close(fdCavaPipe[1]);
/* Open / create a log file for cava */
fdLogOut = open("/dev/null", O_WRONLY, NULL);
/* Dup file in place of stderr */
dup2(fdLogOut, STDERR_FILENO);
execvp(args[0], args);
fprintf(stderr, "Cava execvp failure or return: %s\n", strerror(errno));
exit(EXIT_FAILURE);
log_error("Cava execvp failure or return: %s", strerror(errno));
exit(-EXIT_FAILURE);
} else {
int flags;
/* Close writing end of the pipe */
close(fdCavaPipe[1]);
/* Set reading end of the pipe non-blocking */
@ -231,4 +219,7 @@ static int start_cava_process() {
return -1;
}
static void stop_cava_process() { kill(cavaPid, SIGTERM); }
static void stop_cava_process() {
kill(cavaPid, SIGTERM);
waitpid(0, NULL, WNOHANG);
}

View File

@ -30,12 +30,12 @@
**/
void setup_cava();
int get_cava_buffer(uint16_t **buffer_dst);
int cava_get_buffer(uint16_t **buffer_dst);
void close_cava();
void start_cava_bg_worker();
void cava_start();
void stop_cava_bg_worker();
void cava_stop();
#endif /* __RPI_CAVA_H__ */