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 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

View File

@ -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

View File

@ -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));
} }
}

View File

@ -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

View File

@ -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);
}

View File

@ -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();

View File

@ -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;
} }
/*************************************************************************************************** /***************************************************************************************************

View File

@ -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__ */

View File

@ -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,63 +71,142 @@ 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 } 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 */ /* stop previous bg task */
switch (previousMode) { switch (previousMode) {
case 1: case 1:
artnet_stop(); artnet_stop();
break; break;
case 2: case 2:
stop_cava_bg_worker(); cava_stop();
break; break;
default: default:
break; break;
} }
/* start new bg task */ /* start new bg task */
switch (mode) { switch (currentMode) {
case 1: case 1:
artnet_start(); artnet_start();
break; break;
case 2: case 2:
start_cava_bg_worker(); cava_start();
break; break;
default: default:
break; break;
} }
} else { }
void execute_task(int mode) {
switch (mode) { switch (mode) {
case 0: case 0:
// mode test // mode test
@ -110,62 +225,22 @@ int main(int argc, char const *argv[]) {
break; break;
default: default:
if (mode != previousMode) {
fprintf(stderr, "Error in selector\n");
}
break; 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 // Pointer to uncached Tx data buffer
// TXDATA_T tx_buffer[TX_BUFF_LEN(CHAN_MAXLEDS)]; // Tx buffer for assembling data // TXDATA_T tx_buffer[TX_BUFF_LEN(CHAN_MAXLEDS)]; // Tx buffer for assembling data
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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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__ */

View File

@ -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 = &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__) #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__ */

View File

@ -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));
} }
} }

View File

@ -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},

View File

@ -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);
}

View File

@ -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__ */