File: SendData.cpp

package info (click to toggle)
liblsl 1.16.2b1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 1,724 kB
  • sloc: cpp: 12,515; ansic: 666; python: 28; sh: 25; makefile: 18
file content (115 lines) | stat: -rw-r--r-- 4,241 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "lsl_cpp.h"
#include <array>
#include <iostream>
#include <stdlib.h>
#include <thread>
#include <time.h>

/**
 * This example program offers an 8-channel stream, float-formatted, that resembles EEG data.
 * The example demonstrates also how per-channel meta-data can be specified using the .desc() field
 * of the stream information object.
 *
 * Note that the timer used in the send loop of this program is not particularly accurate.
 */


const char *channels[] = {"C3", "C4", "Cz", "FPz", "POz", "CPz", "O1", "O2"};

int main(int argc, char *argv[]) {
	std::string name, type;
	if (argc < 3) {
		std::cout
			<< "This opens a stream under some user-defined name and with a user-defined content "
			   "type."
			<< std::endl;
		std::cout << "SendData Name Type n_channels[8] srate[100] max_buffered[360] sync[false] "
					 "contig[true]"
				  << std::endl;
		std::cout
			<< "Please enter the stream name and the stream type (e.g. \"BioSemi EEG\" (without "
			   "the quotes)):"
			<< std::endl;
		std::cin >> name >> type;
	} else {
		name = argv[1];
		type = argv[2];
	}
	int n_channels = argc > 3 ? std::stol(argv[3]) : 8;
	n_channels = n_channels < 8 ? 8 : n_channels;
	int samplingrate = argc > 4 ? std::stol(argv[4]) : 100;
	int max_buffered = argc > 5 ? std::stol(argv[5]) : 360;
	bool sync = argc > 6 ? std::stol(argv[6]) > 0 : false;
	bool contig = argc > 7 ? std::stol(argv[7]) > 0 : true;

	try {
		//		if (!sync && !contig) {
		//			throw std::invalid_argument( "async is incompatible with discontig
		//push_numeric_bufs (except for strings, not used here)." );
		//		}

		// make a new stream_info (100 Hz)
		lsl::stream_info info(
			name, type, n_channels, samplingrate, lsl::cf_float32, std::string(name) += type);

		// add some description fields
		info.desc().append_child_value("manufacturer", "LSL");
		lsl::xml_element chns = info.desc().append_child("channels");
		for (int k = 0; k < n_channels; k++)
			chns.append_child("channel")
				.append_child_value("label", k < 8 ? channels[k] : "Chan-" + std::to_string(k + 1))
				.append_child_value("unit", "microvolts")
				.append_child_value("type", type);

		// make a new outlet
		lsl::stream_outlet outlet(
			info, 0, max_buffered, sync ? transp_sync_blocking : transp_default);

		// Initialize 2 discontiguous data arrays.
		std::vector<float> sample(8, 0.0);
		std::vector<float> extra(n_channels - 8, 0.0);
		// If this is contiguous mode (default) then we combine the arrays.
		if (contig) sample.insert(sample.end(), extra.begin(), extra.end());

		// bytes is used in !contig mode because we need to know how big each buffer is.
		std::array<uint32_t, 2> bytes = {
			8 * sizeof(float), static_cast<uint32_t>((n_channels - 8) * sizeof(float))};

		// Your device might have its own timer. Or you can decide how often to poll
		//  your device, as we do here.
		int32_t sample_dur_us = 1000000 / (samplingrate > 0 ? samplingrate : 100);
		auto t_start = std::chrono::high_resolution_clock::now();
		auto next_sample_time = t_start;

		// send data forever
		std::cout << "Now sending data... " << std::endl;
		for (unsigned t = 0;; t++) {
			// Create random data for the first 8 channels.
			for (int c = 0; c < 8; c++) sample[c] = (float)((rand() % 1500) / 500.0 - 1.5);
			// For the remaining channels, fill them with a sample counter (wraps at 1M).
			if (contig)
				std::fill(sample.begin() + 8, sample.end(), (float)(t % 1000000));
			else
				std::fill(extra.begin(), extra.end(), (float)(t % 1000000));

			// Wait until the next expected sample time.
			next_sample_time += std::chrono::microseconds(sample_dur_us);
			std::this_thread::sleep_until(next_sample_time);

			// send the sample
			if (contig) {
				std::cout << sample[0] << "\t" << sample[n_channels-1] << std::endl;
				outlet.push_sample(sample);
			} else {
				// Advanced: Push set of discontiguous buffers.
				std::array<float *, 2> bufs = {sample.data(), extra.data()};
				outlet.push_numeric_bufs(
					(void **)bufs.data(), bytes.data(), 2, lsl::local_clock(), true);
			}
		}

	} catch (std::exception &e) { std::cerr << "Got an exception: " << e.what() << std::endl; }
	std::cout << "Press any key to exit. " << std::endl;
	std::cin.get();
	return 0;
}