2121
2222 */
2323
24+ // API docs: https://open-ephys.github.io/gui-docs/Developer-Guide/Open-Ephys-Plugin-API/Data-Threads.html
25+ // Sample code: https://github.com/sccn/liblsl/blob/master/examples/ReceiveDataInChunks.cpp
26+
2427#include " DataThreadPlugin.h"
2528
2629#include " DataThreadPluginEditor.h"
@@ -40,28 +43,37 @@ LSLInletPlugin::~LSLInletPlugin()
4043
4144bool LSLInletPlugin::updateBuffer ()
4245{
43- // https://open-ephys.github.io/gui-docs/Developer-Guide/Open-Ephys-Plugin-API/Data-Threads.html
44- // TODO: inlet->pull chunk
45- // TODO: add to buffer
46- // dataBuffer->addToBuffer(scaled_samples, scaled_numbers, timestamps, event_codes, numRead)
46+ // TODO: For each inlet + optional TTL_event inlet pair
47+ // std::size_t num_read = inlet->pull_chunk_multiplexed(float *data_buffer, double *timestamp_buffer,
48+ // std::size_t buff_samps*chans, std::size_t buff_samps, double timeout = 0.0);
49+ // .. similar for TTL_event inlet...
50+ // .. TODO: Check to see if we need to transpose data_buffer into scaled_samples
51+ // .. TODO: Find out what the common time base is, if any, and convert timestamps as needed.
52+ // sourceBuffers[ix]->addToBuffer(scaled_samples, scaled_numbers, timestamps, event_codes, num_read);
4753 return true ;
4854}
4955
5056bool LSLInletPlugin::foundInputSource ()
5157{
52- // TODO: Create resolver
58+ // TODO: For each entry in GUI settings, call lsl::resolve_stream
59+ // TODO: Create an inlet for each and store the inlet in a private container.
60+ // TODO: Need to decide if we will do inlet.set_postprocessing(lsl::post_ALL);
5361 return true ;
5462}
5563
5664bool LSLInletPlugin::startAcquisition ()
5765{
58- // TODO: Create inlet(s)
66+ // TODO: For each inlet:
67+ // Pre-allocate buffers
68+ // - std::vector<std::vector<T>> chunk and std::vector<double> timestamps
69+ // inlet.open_stream();
70+ // This begins buffering so the next call to pull_chunk should retrieve data.
5971 return true ;
6072}
6173
6274bool LSLInletPlugin::stopAcquisition ()
6375{
64- // TODO: Destroy inlet(s)
76+ // TODO: for each inlet: inlet.close_stream();
6577 return true ;
6678}
6779
@@ -73,8 +85,58 @@ void LSLInletPlugin::updateSettings(OwnedArray<ContinuousChannel>* continuousCha
7385 OwnedArray<DeviceInfo>* devices,
7486 OwnedArray<ConfigurationObject>* configurationObjects)
7587{
76-
77-
88+ sourceStreams->clear ();
89+ continuousChannels->clear ();
90+ eventChannels->clear ();
91+
92+ // TODO: For each inlet,
93+ // Get lsl::stream_info info = inlet->info(),
94+ // If the info.nominal_srate() != 0 then build the DataStream::Settings for that inlet.
95+ // Note that any irregular rate inlets with int dtype will have to be attached to a regular-rate
96+ // inlet in a single DataStream. i.e., we need at least 1 regular rate inlet for each event inlet.
97+ /*
98+
99+ DataStream::Settings settings
100+ {
101+ info.name(), // stream name, get from info.name()
102+ "description", // stream description
103+ "identifier", // stream identifier, get from info.source_id() if exists
104+ info.nominal_srate() // stream sample rate, info.nominal_srate()
105+ };
106+
107+ DataStream* stream = new DataStream(settings);
108+
109+ sourceStreams->add(stream); // add pointer to owned array
110+
111+ lsl::xml_element desc = info.desc();
112+ // TODO: Unfortunately there aren't any great C++ examples for parsing the xml info to get channel names.
113+ // The best I could find is in Python: https://github.com/intheon/stream_viewer/blob/a48d38b72ef95b0eac35f7903924facd4be6f197/stream_viewer/data/stream_lsl.py#L159-L174
114+
115+ for (int i = 0; i < numChannels; i++)
116+ {
117+ ContinuousChannel::Settings settings{
118+ ContinuousChannel::Type::ELECTRODE, // channel type
119+ "CH" + String(i+1), // channel name
120+ "description", // channel description
121+ "identifier", // channel identifier
122+ 0.195, // channel bitvolts scaling
123+ stream // associated data stream
124+ };
125+
126+ continuousChannels->add(new ContinuousChannel(settings));
127+ }
128+
129+ EventChannel::Settings settings{
130+ EventChannel::Type::TTL, // channel type (must be TTL)
131+ "Device Event Channel", // channel name
132+ "description", // channel description
133+ "identifier", // channel identifier
134+ stream, // associated data stream
135+ 8 // maximum number of TTL lines
136+ };
137+
138+ eventChannels->add(new EventChannel(settings));
139+ */
78140}
79141
80142
@@ -86,7 +148,8 @@ void LSLInletPlugin::resizeBuffers()
86148
87149std::unique_ptr<GenericEditor> LSLInletPlugin::createEditor (SourceNode* sn)
88150{
89-
151+ // https://open-ephys.github.io/gui-docs/Tutorials/How-To-Make-Your-Own-Plugin.html#adding-ui-components-to-the-editor
152+
90153 std::unique_ptr<DataThreadPluginEditor> editor = std::make_unique<DataThreadPluginEditor>(sn);
91154
92155 return editor;
0 commit comments