Commit 53231f31 authored by Your Name's avatar Your Name
Browse files

Merge branch 'lslder2021'

parents a2df09ab 5716363e
LSLBASE=../labstreaminglayer/build/install LSLBASE=../labstreaminglayer/build/install
CXXFLAGS+=-Wall -Wno-sign-compare -I$(LSLBASE)/include CXXFLAGS+=-Wall -Wno-sign-compare -I$(LSLBASE)/include
LDFLAGS+=-L$(LSLBASE)/lib -llsl32 -lwiringPi -lboost_system -lpthread LDFLAGS+=-L$(LSLBASE)/lib -llsl32 -lpigpio -lboost_system -lpthread
LDLIBS+=-lzmq -lpthread -lboost_system -lboost_regex -lboost_program_options LDLIBS+=-lzmq -lpthread -lboost_system -lboost_regex -lboost_program_options
#INCLUDE+=RS-232 #INCLUDE+=RS-232
...@@ -10,8 +10,7 @@ CXXFLAGS+=-Wall -std=c++11 ...@@ -10,8 +10,7 @@ CXXFLAGS+=-Wall -std=c++11
CXX=g++ CXX=g++
CC=g++ CC=g++
TARGETS=lslder_1chan lslder_4chan lslder_8chan sendrand lslder_4chan_proto TARGETS=lslder_1chan lslder_4chan lslder_8chan sendrand
all: $(TARGETS) all: $(TARGETS)
#lslder : CPPFLAGS+=-DLSLDER_8CHAN #lslder : CPPFLAGS+=-DLSLDER_8CHAN
...@@ -34,6 +33,7 @@ lslder_1chan.o: lslder_uni.cc ...@@ -34,6 +33,7 @@ lslder_1chan.o: lslder_uni.cc
sendrand: sendrand.cc sendrand: sendrand.cc
lslder_4chan_proto: lslder_4chan_proto.cc lslder_4chan_proto: lslder_4chan_proto.cc
lslder_4chan_proto: LDFLAGS+=-lwiringPi
clean: clean:
rm -f $(TARGETS) *.o rm -f $(TARGETS) *.o
......
#include "led.h" #include "led.h"
#include <wiringPi.h> #include <pigpio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
...@@ -16,7 +16,7 @@ void initleds(int _nled, const int *_ledgpio) ...@@ -16,7 +16,7 @@ void initleds(int _nled, const int *_ledgpio)
ledgpio = _ledgpio; ledgpio = _ledgpio;
for (int i=0; i<nled; i++) for (int i=0; i<nled; i++)
{ {
pinMode(ledgpio[i], OUTPUT); gpioSetMode(ledgpio[i], PI_OUTPUT);
} }
playleds(); playleds();
} }
...@@ -63,5 +63,10 @@ void setled(int lednr, int value) ...@@ -63,5 +63,10 @@ void setled(int lednr, int value)
else else
bit = 0; bit = 0;
digitalWrite(ledgpio[lednr], bit); int r= gpioWrite(ledgpio[lednr], bit);
if (r < 0)
{
perror("gpioWrite");
exit(1);
}
} }
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
...@@ -2,28 +2,34 @@ ...@@ -2,28 +2,34 @@
// //
// LSL Digital Event Recorder // LSL Digital Event Recorder
// //
// This program offers a maximum of eight LSL event streams, each triggered by positive edges on // This program offers a maximum of eight LSL event streams, each triggered by
// raspberry pi GPIO digital inputs. Visual feedback is provided bij eight LEDs. // positive edges on raspberry pi GPIO digital inputs. Visual feedback is
// The stream type is "Digital Events - $HOSTNAME", where HOSTNAME is the ip hostname of // provided bij eight LEDs. The stream type is "Digital Events - $HOSTNAME",
// the raspberry. This is to uniquely identify devices on the network. // where HOSTNAME is the ip hostname of the raspberry. This is to uniquely
// The data sent with the events is an int8 with value 1, with 1 indicating a rising edge. // identify devices on the network. The data sent with the events is an int8
// Falling edges can be sent with a 0 value. However this is not implemented in this // with value 1, with 1 indicating a rising edge. Falling edges can be sent with
// program. // a 0 value. However this is not implemented in this program.
// //
// Dependencies: labstreaminglayer C++ and wiringPi // Dependencies: labstreaminglayer C++
// CHANGES // CHANGES
// GW/20180716 initial version for 8-channel LSL Digital Event Recorder // GW/20180716 initial version for 8-channel LSL Digital Event Recorder
// GW/20210210 remove deprecated wiringPi and use pigpio instead
// TODO: use ISR tick for debounce timing
// TODO: add support to register falling edges
#include "led.h"
#include <chrono> // std::chrono::seconds
#include <cstring>
#include <iostream>
#include <lsl_cpp.h> #include <lsl_cpp.h>
#include <mutex>
#include <pigpio.h>
#include <sched.h>
#include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <thread> // std::this_thread::sleep_for
#include <unistd.h> #include <unistd.h>
#include <iostream>
#include <mutex>
#include <thread> // std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
#include <wiringPi.h>
#include "led.h"
#define DEBUG #define DEBUG
...@@ -33,7 +39,7 @@ using namespace lsl; ...@@ -33,7 +39,7 @@ using namespace lsl;
// 1 channel portable version without LEDs // 1 channel portable version without LEDs
const int ngpio = 1; const int ngpio = 1;
const int gpioinp[ngpio] = { 8 }; const int gpioinp[ngpio] = {8};
const int default_debouncetime = 100; const int default_debouncetime = 100;
...@@ -46,11 +52,11 @@ const int nled = 0; ...@@ -46,11 +52,11 @@ const int nled = 0;
// 4-chan version with 4 LEDs // 4-chan version with 4 LEDs
const int ngpio = 4; const int ngpio = 4;
const int gpioinp[ngpio] = { 24, 23, 18, 15 }; const int gpioinp[ngpio] = {15, 18, 23, 24};
const int default_debouncetime = 0; const int default_debouncetime = 0;
const int ledgpio[] = { 5, 14, 3, 2 }; const int ledgpio[] = {2, 3, 14, 5};
const int nled = 4; const int nled = 4;
#endif #endif
...@@ -59,172 +65,188 @@ const int nled = 4; ...@@ -59,172 +65,188 @@ const int nled = 4;
// 8-chan version with 8 LEDs // 8-chan version with 8 LEDs
const int ngpio = 8; const int ngpio = 8;
const int gpioinp[ngpio] = { 12, 7, 8, 25, 24, 23, 18, 15 }; const int gpioinp[ngpio] = {12, 7, 8, 25, 24, 23, 18, 15};
const int default_debouncetime = 0; const int default_debouncetime = 0;
const int ledgpio[] = { 21, 20, 16, 13, 5, 14, 3, 2 }; const int ledgpio[] = {21, 20, 16, 13, 5, 14, 3, 2};
const int nled = 8; const int nled = 8;
#endif #endif
int ledtime=2; // in 1/100 sec., see infinite loop in main() const int maxgpio = 54; // BCM chip has 54 GPIO
volatile int ledtimer[ngpio] = { 0, }; int gpiomap[maxgpio];
int ledstatus[ngpio] = { 0, };
void init_gpiomap() {
// map BNC input channel wiring 0..ngpio-1 to BCM GPIO
for (int bnc_input = 0; bnc_input < ngpio; bnc_input++) {
int bcmgpio = gpioinp[bnc_input];
gpiomap[bcmgpio] = bnc_input;
}
}
int debouncetimes[ngpio] = { 0, }; int ledtime = 2; // in 1/100 sec., see infinite loop in main()
volatile int debouncetimer[ngpio] = { 0, }; volatile int ledtimer[ngpio] = {
0,
};
int ledstatus[ngpio] = {
0,
};
int debouncetimes[ngpio] = {
0,
};
volatile int debouncetimer[ngpio] = {
0,
};
#ifdef DEBUG #ifdef DEBUG
volatile int interrupt_count[ngpio] = { 0, }; volatile int interrupt_count[ngpio] = {
0,
};
#endif #endif
stream_outlet *outlet[ngpio]; stream_outlet *outlet[ngpio];
std::mutex lsl_mutex; std::mutex lsl_mutex;
typedef char int8; typedef char int8;
void gpioInterrupt(int channel) volatile int run = 1;
{
if (debouncetimer[channel]) void stop(int signum) { run = 0; }
return;
void gpioISR(int gpio, int level, uint32_t tick) {
int bnc_input = gpiomap[gpio];
if (level == 2) // timeout call
return;
if (debouncetimer[bnc_input])
return;
else else
debouncetimer[channel] = debouncetimes[channel]; debouncetimer[bnc_input] = debouncetimes[bnc_input];
static int edge = 1;
std::lock_guard<std::mutex> guard(lsl_mutex);
#ifdef DEBUG #ifdef DEBUG
std::cout std::cout << "Interrupt on bnc_input " << bnc_input << " (GPIO "
<< "Interrupt on channel " << channel << gpioinp[bnc_input] << ")" << std::endl;
<< " (GPIO " << gpioinp[channel] << ")"
<< std::endl;
#endif #endif
outlet[bnc_input]->push_sample(&edge);
static int edge=1; ledtimer[bnc_input] = ledtime;
std::lock_guard<std::mutex> guard(lsl_mutex);
outlet[channel]->push_sample(&edge);
ledtimer[channel]=ledtime;
#ifdef DEBUG #ifdef DEBUG
interrupt_count[channel]++; interrupt_count[bnc_input]++;
std::cout << channel << " (count=" << interrupt_count[channel] << ")" << std::endl; std::cout << bnc_input << " (count=" << interrupt_count[bnc_input] << ")"
<< std::endl;
#endif #endif
} }
void handleLeds() void handleLeds() {
{ for (int i = 0; (i < ngpio) && (i < nled); i++) {
for (int i=0; (i<ngpio) && (i<nled); i++) if (ledtimer[i] > 0) {
{ if (!ledstatus[i]) {
if (ledtimer[i] > 0) { setled(i, 1);
if (!ledstatus[i]) { ledstatus[i] = 1;
setled(i,1); }
ledstatus[i]=1; ledtimer[i]--;
} }
ledtimer[i]--; else {
} if (ledstatus[i]) {
else { setled(i, 0);
if (ledstatus[i]) { ledstatus[i] = 0;
setled(i,0); }
ledstatus[i]=0; }
} }
}
}
} }
int rtpriority(int n) {
struct sched_param sched;
void gpioISR_0() memset(&sched, 0, sizeof(sched));
{
gpioInterrupt(0);
}
void gpioISR_1()
{
gpioInterrupt(1);
}
void gpioISR_2() if (n > sched_get_priority_max(SCHED_RR))
{ sched.sched_priority = sched_get_priority_max(SCHED_RR);
gpioInterrupt(2); else
} sched.sched_priority = n;
void gpioISR_3() return sched_setscheduler(0, SCHED_RR, &sched);
{
gpioInterrupt(3);
} }
void gpioISR_4() int main(int argc, char *argv[]) {
{ init_gpiomap();
gpioInterrupt(4);
}
void gpioISR_5() if (rtpriority(99) < 0) {
{ perror("rtpriority");
gpioInterrupt(5); return 1;
} }
void gpioISR_6() // configure input channels
{ int r = gpioInitialise(); // use Broadcom pin numbering
gpioInterrupt(6); if (r < 0) {
} perror("gpioInitialise");
return 1;
}
void gpioISR_7() gpioSetSignalFunc(SIGINT, stop);
{ gpioSetSignalFunc(SIGABRT, stop);
gpioInterrupt(7);
}
typedef void(*gpioISR)(); printf("Press control C to stop.\n");
gpioISR ISR[] = { gpioISR_0, gpioISR_1, gpioISR_2, gpioISR_3, initleds(nled, ledgpio);
gpioISR_4, gpioISR_5, gpioISR_6, gpioISR_7 };
int main(int argc, char* argv[]) { for (int i = 0; i < ngpio; i++) {
piHiPri(99); // shortcut for running at real time priority int bcmgpio = gpioinp[i]; // BCM GPIO number
//if (gpioSetMode(bcmgpio, PI_INPUT) < 0) {
// configure inputs // perror("gpioSetMode");
wiringPiSetupGpio(); // return 1;
// }
initleds(nled, ledgpio); debouncetimes[i] = default_debouncetime;
for (int i=0; i<ngpio; i++) const int timeout_ms = 10000;
{ // The 4N35 optocoupler in the input circuit inverts the signal, we want
pinMode(gpioinp[i], INPUT); // to detect rising edges in the input signal, so here we program
pullUpDnControl(gpioinp[i], PUD_UP); // FALLING_EDGE.
if (gpioSetISRFunc(bcmgpio, FALLING_EDGE, timeout_ms, gpioISR) < 0) {
perror("gpioSetISRFunc");
return 1;
} }
if (gpioSetPullUpDown(bcmgpio, PI_PUD_UP) < 0) {
for (int i=0; i<ngpio; i++) { perror("gpioSetMode");
debouncetimes[i] = default_debouncetime; return 1;
} }
char hostname[255]; #ifdef DEBUG
gethostname(hostname,255); std::cout << "Set IRQ handler for gpio " << bcmgpio << std::endl;
for (int i=0; i<ngpio; i++) #endif
{
// make a new stream_info and open an outlet with it }
char info_name[255];
sprintf(info_name, "Digital Events %d", i);
char info_type[255+18]; char hostname[255];
sprintf(info_type,"Digital Events @ %s",hostname); gethostname(hostname, 255);
for (int i = 0; i < ngpio; i++) {
// make a new stream_info and open an outlet with it
char info_name[255];
sprintf(info_name, "Digital Events %d", i);
stream_info info(info_name, info_type, 1, lsl::IRREGULAR_RATE, char info_type[255 + 18];
lsl::cf_int8,"Raspberry Pi Digital Event Recorder"); sprintf(info_type, "Digital Events @ %s", hostname);
outlet[i] = new stream_outlet(info);
}
// The 4N35 optocoupler in the input circuit inverts the signal, we want to stream_info info(info_name, info_type, 1, lsl::IRREGULAR_RATE,
// detect rising edges in the input signal, so here we program INT_EDGE_FALLING. lsl::cf_int8, "Raspberry Pi Digital Event Recorder");
for (int i=0; i<ngpio; i++) outlet[i] = new stream_outlet(info);
{ }
wiringPiISR(gpioinp[i], INT_EDGE_FALLING, ISR[i]);
}
// do this forever // do this forever
while(true) { while (run) {
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
handleLeds(); handleLeds();
for (int i=0; i<ngpio; i++) { for (int i = 0; i < ngpio; i++) {
if (debouncetimer[i] > 0) if (debouncetimer[i] > 0)
debouncetimer[i]--; debouncetimer[i]--;
}
} }
return 0; }
gpioTerminate();
return 0;
} }
No preview for this file type
No preview for this file type
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment