lslder_uni.cc 4.41 KB
Newer Older
1
// lslder.cc -- GW/20200110
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
2
//
3
4
5
// LSL Digital Event Recorder
//
// This program offers a maximum of eight LSL event streams, each triggered by positive edges on
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
6
7
8
9
10
11
12
13
14
// raspberry pi GPIO digital inputs. Visual feedback is provided bij eight LEDs.
// The stream type is "Digital Events - $HOSTNAME", where HOSTNAME is the ip hostname of
// the raspberry. This is to uniquely identify devices on the network.
// The data sent with the events is an int8 with value 1, with 1 indicating a rising edge.
// Falling edges can be sent with a 0 value. However this is not implemented in this
// program.
//
// Dependencies: labstreaminglayer C++ and wiringPi

15
16
17
// CHANGES
// GW/20180716 initial version for 8-channel LSL Digital Event Recorder

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
18
19
20
21
22
23
24
25
26
27
#include <lsl_cpp.h>
#include <stdlib.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"

Gunter Windau's avatar
Gunter Windau committed
28
#define DEBUG
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
29
30
31

using namespace lsl;

32
33
34
#ifdef LSLDER_1CHAN

// 1 channel portable version without LEDs
Gunter Windau's avatar
Gunter Windau committed
35
36
const int ngpio = 1;
const int gpioinp[ngpio] = { 8 };
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
37

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
const int *ledgpio = 0;
const int nled = 0;

#endif

#ifdef LSLDER_8CHAN

// 8-chan version with 8 LEDs
const int ngpio = 8;
const int gpioinp[ngpio] = { 12, 7, 8, 25, 24, 23, 18, 15 };

const int ledgpio[] = { 21, 20, 16, 13, 5, 14, 3, 2 };
const int nled = 8;

#endif

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
int ledtime=1; // in 1/50 sec., see infinite loop in main()
volatile int ledtimer[ngpio] = { 0, };
int ledstatus[ngpio] = { 0, };

#ifdef DEBUG
volatile int interrupt_count[ngpio] = { 0, };
#endif

stream_outlet *outlet[ngpio];
std::mutex lsl_mutex;
typedef char int8;

void gpioInterrupt(int channel)
{
    std::lock_guard<std::mutex> guard(lsl_mutex);

Gunter Windau's avatar
Gunter Windau committed
70
71
72
73
74
75
76
#ifdef DEBUG
    std::cout 
       << "Interrupt on channel " << channel 
       << " (GPIO " << gpioinp[channel] << ")"
       << std::endl;
#endif

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
77
78
79
80
81
82
83
84
85
86
87
88
    static int edge=1;
    outlet[channel]->push_sample(&edge);
    ledtimer[channel]=ledtime;

#ifdef DEBUG
    interrupt_count[channel]++;
    std::cout << channel << " (count=" << interrupt_count[channel] << ")" << std::endl;
#endif
}

void handleLeds()
{
Gunter Windau's avatar
Gunter Windau committed
89
    for (int i=0; (i<ngpio) && (i<nled); i++)
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
    {
       if (ledtimer[i] > 0) {
          if (!ledstatus[i]) {
             //std::lock_guard<std::mutex> guard(lsl_mutex);
             setled(i,1);
             ledstatus[i]=1;
          }
          ledtimer[i]--;
       }
       else {
          if (ledstatus[i]) {
             //std::lock_guard<std::mutex> guard(lsl_mutex);
             setled(i,0);
             ledstatus[i]=0;
          }
       }
Gunter Windau's avatar
Gunter Windau committed
106
   }
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
107
108
109
}


110
void gpioISR_0()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
111
112
113
114
{
    gpioInterrupt(0);
}

115
void gpioISR_1()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
116
117
118
119
{
    gpioInterrupt(1);
}

120
void gpioISR_2()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
121
122
123
124
{
    gpioInterrupt(2);
}

125
void gpioISR_3()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
126
127
128
129
{
    gpioInterrupt(3);
}

130
void gpioISR_4()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
131
132
133
134
{
    gpioInterrupt(4); 
}

135
void gpioISR_5()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
136
137
138
139
{
    gpioInterrupt(5);
}

140
void gpioISR_6()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
141
142
143
144
{
    gpioInterrupt(6);
}

145
void gpioISR_7()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
146
147
148
149
{
    gpioInterrupt(7);
}

150
151
typedef void(*gpioISR)();

Gunter Windau's avatar
Gunter Windau committed
152
153
gpioISR ISR[] = { gpioISR_0, gpioISR_1, gpioISR_2, gpioISR_3, 
                   gpioISR_4, gpioISR_5, gpioISR_6, gpioISR_7 };
154

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
155
156
157
158
159
int main(int argc, char* argv[]) {
        piHiPri(99);  // shortcut for running at real time priority
        
        // configure inputs 
        wiringPiSetupGpio();
160
161
162

        initleds(nled, ledgpio);

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
163
164
165
166
167
168
169
170
171
172
173
174
175
176
        for (int i=0; i<ngpio; i++)
        {
           pinMode(gpioinp[i], INPUT);
           pullUpDnControl(gpioinp[i], PUD_UP);
        }

        char hostname[255];
        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);

177
           char info_type[255+18];
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
178
179
180
181
182
183
184
185
186
           sprintf(info_type,"Digital Events @ %s",hostname);

           stream_info info(info_name, info_type, 1, lsl::IRREGULAR_RATE,
              lsl::cf_int8,"Raspberry Pi Digital Event Recorder");
           outlet[i] = new stream_outlet(info);
        }

        // The 4N35 optocoupler in the input circuit inverts the signal, we want to
        // detect rising edges in the input signal, so here we program INT_EDGE_FALLING.
Gunter Windau's avatar
Gunter Windau committed
187
188
189
190
        for (int i=0; i<ngpio; i++)
        {
           wiringPiISR(gpioinp[i], INT_EDGE_FALLING, ISR[i]);
        }
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
191
192
193

        // do this forever
        while(true) {
Gunter Windau's avatar
Gunter Windau committed
194
195
           std::this_thread::sleep_for(std::chrono::milliseconds(20));
           handleLeds();
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
196
197
198
199
        }
        return 0;
}