lslder_uni.cc 4.78 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

Gunter Windau's avatar
Gunter Windau committed
38
39
const int default_debouncetime = 100;

40
41
42
43
44
45
46
47
48
49
50
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 };

Gunter Windau's avatar
Gunter Windau committed
51
52
const int default_debouncetime = 0;

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

#endif

Gunter Windau's avatar
Gunter Windau committed
58
int ledtime=2; // in 1/100 sec., see infinite loop in main()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
59
60
61
volatile int ledtimer[ngpio] = { 0, };
int ledstatus[ngpio] = { 0, };

Gunter Windau's avatar
Gunter Windau committed
62
63
64
int debouncetimes[ngpio] = { 0, };
volatile int debouncetimer[ngpio] = { 0, };

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
65
66
67
68
69
70
71
72
73
74
#ifdef DEBUG
volatile int interrupt_count[ngpio] = { 0, };
#endif

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

void gpioInterrupt(int channel)
{
Gunter Windau's avatar
Gunter Windau committed
75
76
77
78
    if (debouncetimer[channel])
       return;
    else
       debouncetimer[channel] = debouncetimes[channel];
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
79

Gunter Windau's avatar
Gunter Windau committed
80
81
82
83
84
85
86
#ifdef DEBUG
    std::cout 
       << "Interrupt on channel " << channel 
       << " (GPIO " << gpioinp[channel] << ")"
       << std::endl;
#endif

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
87
    static int edge=1;
Gunter Windau's avatar
Gunter Windau committed
88
    std::lock_guard<std::mutex> guard(lsl_mutex);
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
89
90
91
92
93
94
95
96
97
98
99
    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
100
    for (int i=0; (i<ngpio) && (i<nled); i++)
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    {
       if (ledtimer[i] > 0) {
          if (!ledstatus[i]) {
             setled(i,1);
             ledstatus[i]=1;
          }
          ledtimer[i]--;
       }
       else {
          if (ledstatus[i]) {
             setled(i,0);
             ledstatus[i]=0;
          }
       }
Gunter Windau's avatar
Gunter Windau committed
115
   }
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
116
117
118
}


119
void gpioISR_0()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
120
121
122
123
{
    gpioInterrupt(0);
}

124
void gpioISR_1()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
125
126
127
128
{
    gpioInterrupt(1);
}

129
void gpioISR_2()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
130
131
132
133
{
    gpioInterrupt(2);
}

134
void gpioISR_3()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
135
136
137
138
{
    gpioInterrupt(3);
}

139
void gpioISR_4()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
140
141
142
143
{
    gpioInterrupt(4); 
}

144
void gpioISR_5()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
145
146
147
148
{
    gpioInterrupt(5);
}

149
void gpioISR_6()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
150
151
152
153
{
    gpioInterrupt(6);
}

154
void gpioISR_7()
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
155
156
157
158
{
    gpioInterrupt(7);
}

159
160
typedef void(*gpioISR)();

Gunter Windau's avatar
Gunter Windau committed
161
162
gpioISR ISR[] = { gpioISR_0, gpioISR_1, gpioISR_2, gpioISR_3, 
                   gpioISR_4, gpioISR_5, gpioISR_6, gpioISR_7 };
163

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
164
165
166
167
168
int main(int argc, char* argv[]) {
        piHiPri(99);  // shortcut for running at real time priority
        
        // configure inputs 
        wiringPiSetupGpio();
169
170
171

        initleds(nled, ledgpio);

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
172
173
174
175
176
177
        for (int i=0; i<ngpio; i++)
        {
           pinMode(gpioinp[i], INPUT);
           pullUpDnControl(gpioinp[i], PUD_UP);
        }

Gunter Windau's avatar
Gunter Windau committed
178
179
180
181
        for (int i=0; i<ngpio; i++) {
           debouncetimes[i] = default_debouncetime;
        }

Gunter Windau's avatar
azmq rm  
Gunter Windau committed
182
183
184
185
186
187
188
189
        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);

190
           char info_type[255+18];
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
191
192
193
194
195
196
197
198
199
           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
200
201
202
203
        for (int i=0; i<ngpio; i++)
        {
           wiringPiISR(gpioinp[i], INT_EDGE_FALLING, ISR[i]);
        }
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
204
205
206

        // do this forever
        while(true) {
Gunter Windau's avatar
Gunter Windau committed
207
           std::this_thread::sleep_for(std::chrono::milliseconds(10));
Gunter Windau's avatar
Gunter Windau committed
208
           handleLeds();
Gunter Windau's avatar
Gunter Windau committed
209
210
211
212
213

           for (int i=0; i<ngpio; i++) {
              if (debouncetimer[i] > 0)
                 debouncetimer[i]--;
           }
Gunter Windau's avatar
azmq rm  
Gunter Windau committed
214
215
216
217
        }
        return 0;
}