Falcon
Loading...
Searching...
No Matches
nlx.hpp
1// ---------------------------------------------------------------------
2// This file is part of falcon-core.
3//
4// Copyright (C) 2015, 2016, 2017 Neuro-Electronics Research Flanders
5//
6// Falcon-server is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// Falcon-server is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with falcon-core. If not, see <http://www.gnu.org/licenses/>.
18// ---------------------------------------------------------------------
19
20#pragma once
21
22#include <netinet/in.h>
23
24#include <array>
25#include <cmath>
26#include <cstdint>
27#include <limits>
28#include <vector>
29#include "logging/log.hpp"
30
31namespace nlx {
32
33// a digilynx raw packet has the following layout
34// int32 | start of transmission identifier == 2048
35// int32 | packet type identifier == 1
36// int32 | packet size == #channels + #extra
37// uint32 | timestamp (high order bits)
38// uint32 | timestamp (low order bits)
39// int32 | status (reserved)
40// uint32 | parallel input port value
41// int32[10] | extra values (reserved)
42// int32[nchannels] | data values (nchannels == number of channels in
43// acquisition system) int32 | CRC value for record
44
45// some values are needed at compile time
46constexpr uint16_t NLX_NFIELDS_EXTRA = 10;
47constexpr uint16_t NLX_FIELDBYTESIZE = 4;
48constexpr uint16_t NLX_NFIELDS(uint16_t c) {
49 return (8 + NLX_NFIELDS_EXTRA + (c));
50}
51constexpr uint16_t NLX_PACKETBYTESIZE(uint16_t c) {
52 return (NLX_FIELDBYTESIZE * NLX_NFIELDS(c));
53}
54constexpr uint16_t NLX_NCHANNELS_FROM_PACKETBYTESIZE(uint16_t sz) {
55 return ((sz / NLX_FIELDBYTESIZE) - 8 - NLX_NFIELDS_EXTRA);
56}
57constexpr uint16_t NLX_NCHANNELS_FROM_NFIELDS(uint16_t n) {
58 return n - 8 - NLX_NFIELDS_EXTRA;
59}
60
61constexpr uint16_t SUCCESS_READING_BUFFER = 0;
62constexpr uint16_t ERROR_NLX_FIELD_STX = 2;
63constexpr uint16_t ERROR_NLX_FIELD_RAWPACKETID = 3;
64constexpr uint16_t ERROR_NLX_FIELD_PACKETSIZE = 5;
65constexpr uint16_t ERROR_TOO_SMALL_PACKET = 4;
66constexpr uint16_t ERROR_BAD_CRC = 1;
67
68constexpr uint16_t NLX_FIELD_STX = 0;
69constexpr uint16_t NLX_FIELD_RAWPACKETID = 1;
70constexpr uint16_t NLX_FIELD_PACKETSIZE = 2;
71constexpr uint16_t NLX_FIELD_TIMESTAMP_HIGH = 3;
72constexpr uint16_t NLX_FIELD_TIMESTAMP_LOW = 4;
73constexpr uint16_t NLX_FIELD_DIO = 6;
74constexpr uint16_t NLX_FIELD_EXTRA_FIRST = 7;
75constexpr uint16_t NLX_FIELD_DATA_FIRST = NLX_FIELD_EXTRA_FIRST + NLX_NFIELDS_EXTRA;
76
77// constexpr double NLX_AD_BIT_MICROVOLTS = 0.015624999960550667;
78constexpr double NLX_AD_BIT_MICROVOLTS = 0.000000305175781250000006;
79constexpr int32_t NLX_STX = 2048;
80constexpr int32_t NLX_RAWPACKETID = 1;
81constexpr uint16_t NLX_DEFAULT_NCHANNELS = 128;
82constexpr uint16_t NLX_MAX_NCHANNELS = 1024;
83constexpr double NLX_SIGNAL_SAMPLING_FREQUENCY = 32000;
84constexpr unsigned int NLX_DEFAULT_BUFFERSIZE = NLX_PACKETBYTESIZE(NLX_DEFAULT_NCHANNELS);
85
86const double NLX_VIDEO_SAMPLING_FREQUENCY = 25;
87const int VTRecNumTransitionBitfields = 400;
89const int VTRecNumTargets = 50;
91const std::uint16_t VTRecSWST = 0x800;
92
93typedef struct { // from Neuralynx header Nlx_DataTypes.h
94 std::uint16_t swstx;
95 std::uint16_t swid;
96 std::uint16_t swdata_size;
97 std::uint64_t qwTimeStamp;
98 std::uint32_t dwPoints[VTRecNumTransitionBitfields];
102 std::int16_t sncrc;
103 std::int32_t dnextracted_x;
105 std::int32_t dnextracted_y;
107 std::int32_t dnextracted_angle;
109 std::int32_t dntargets[VTRecNumTargets];
112} __attribute__((__packed__)) VideoRec; // packing does not hurt perfomance on x64 CPUs
113// used here in order to guarantee sizeof(VideoRec) == swdata_size so that is
114// read correctly (otherwise it is NOT!) read more on:
115// https://attractivechaos.wordpress.com/2013/05/02/does-packed-struct-hurt-performance-on-x86_64/
116
117struct ErrorNLXVT { // wrapped to avoid namespace conflict
118 enum Code {
119 UNKNOWN = -1,
120 NO_ERROR = 0,
121 SWSTX,
122 SWID,
123 SWDATA_SIZE,
124 NEGATIVE_COORDINATE,
125 OUT_OF_RESOLUTION
126 };
127};
128
129const std::array<std::int32_t, 2> NLX_VIDEO_RESOLUTION = {{720, 576}};
130
131bool valid_nlx_vt(VideoRec* vt_record, std::uint16_t vt_id, ErrorNLXVT::Code& error_code,
132 decltype(NLX_VIDEO_RESOLUTION) resolution);
133
134inline const unsigned int nlx_field_data_last(unsigned int nchannels = NLX_DEFAULT_NCHANNELS) {
135 return NLX_FIELD_DATA_FIRST + nchannels - 1;
136}
137inline const unsigned int nlx_field_crc(unsigned int nchannels = NLX_DEFAULT_NCHANNELS) {
138 return NLX_FIELD_DATA_FIRST + nchannels;
139}
140inline const int32_t nlx_packetsize(unsigned int nchannels = NLX_DEFAULT_NCHANNELS) {
141 return nchannels + NLX_NFIELDS_EXTRA;
142}
143
144class NlxSignalRecord {
145 public:
146 NlxSignalRecord(unsigned int nchannels = NLX_DEFAULT_NCHANNELS, bool convert_byte_order = true);
147
148 unsigned int nchannels() const;
149 void set_nchannels(unsigned int n);
150
151 bool convert_byte_order() const;
152 void set_convert_byte_order(bool b);
153
154 int FromNetworkBuffer(const char* buffer, size_t n);
155
156 template <typename T>
157 int FromNetworkBuffer(const std::vector<T>& buffer) {
158 return FromNetworkBuffer((char*) buffer.data(), buffer.size() * sizeof(T));
159 }
160
161 size_t ToNetworkBuffer(char* buffer, size_t n);
162
163 template <typename T>
164 size_t ToNetworkBuffer(std::vector<T>& buffer) {
165 // check size
166 if (buffer.size() < (nlx_packetbytesize_ / sizeof(T))) {
167 buffer.resize(nlx_packetbytesize_ / sizeof(T));
168 }
169
170 return ToNetworkBuffer((char*) buffer.data(), buffer.size() * sizeof(T));
171 }
172
173 void Initialize(); // set required fields 1-3
174 void Finalize(); // compute CRC
175
176 int32_t crc() const;
177
178 bool initialized() const;
179 bool finalized() const;
180
181 int valid(std::vector<int32_t> buffer);
182
183 // timestamp access functions
184 uint64_t timestamp() const;
185 void set_timestamp(uint64_t t);
186 void inc_timestamp(uint64_t delta);
187 void inc_timestamp(double delta);
188
189 // digital input/output access methods
190 uint32_t parallel_port() const;
191 void set_parallel_port(uint32_t dio = 0);
192
193 // data (int32) getter methods
194 void data(std::vector<int32_t>& v) const; // will copy
195 std::vector<int32_t>::iterator data(std::vector<int32_t>::iterator it) const; // will copy
196 int32_t sample(unsigned int index) const;
197
198 // data (int32) setter methods
199 void set_data(int32_t value = 0);
200 void set_data(std::vector<int32_t>& v);
201 void set_data(std::vector<int32_t>::iterator it);
202
203 // data (microVolt) getter methods
204 void data(std::vector<double>& v) const; // will convert to uV and copy
205 std::vector<double>::iterator data(std::vector<double>::iterator it) const;
206 double sample_microvolt(unsigned int index) const;
207
208 // data (microVolt) setter methods
209 void set_data(double value = 0);
210 void set_data(std::vector<double>& v);
211 void set_data(std::vector<double>::iterator it);
212
213 std::vector<int32_t> buffer_;
214 int32_t nlx_packetsize_;
215
216 protected:
217 std::vector<int32_t>::iterator data_begin();
218 std::vector<int32_t>::iterator data_end();
219
220 std::vector<int32_t>::const_iterator data_begin() const;
221 std::vector<int32_t>::const_iterator data_end() const;
222
223 bool convert_byte_order_;
224 unsigned int nchannels_;
225 bool initialized_ = false;
226 bool finalized_ = false;
227
228 unsigned int nlx_nfields_;
229 unsigned int nlx_packetbytesize_;
230 uint16_t nlx_field_crc_;
231 uint16_t nlx_field_data_last_;
232};
233
234// timestamp related constants
235// sampling period (microseconds)
236constexpr decltype(NLX_SIGNAL_SAMPLING_FREQUENCY) SAMPLING_PERIOD_MICROSEC =
237 1e6 / NLX_SIGNAL_SAMPLING_FREQUENCY;
238// maximum tolerated difference between two timestamps that
239// is not considered a gap with missing data packets
240const uint64_t MAX_ALLOWABLE_TIMEGAP_MICROSECONDS = trunc(SAMPLING_PERIOD_MICROSEC) + 1;
241// value for an invalid timestamp
242constexpr uint64_t INVALID_TIMESTAMP = std::numeric_limits<uint64_t>::max();
243
244class NlxStatistics {
245 public:
246 NlxStatistics() : n_invalid(0), n_duplicated(0), n_outoforder(0), n_missed(0), n_gaps(0) {}
247
248 public:
249 uint64_t n_invalid;
250 uint64_t n_duplicated;
251 uint64_t n_outoforder;
252 uint64_t n_missed;
253 uint64_t n_gaps;
254
255 void clear();
256};
257
258uint64_t CheckTimestamp(const NlxSignalRecord& rec, uint64_t& last_timestamp, NlxStatistics& stats);
259} // namespace nlx
Definition nlx.hpp:144
Definition nlx.hpp:244
Definition nlx.hpp:117
Definition nlx.hpp:93
std::int32_t dntargets[VTRecNumTargets]
Definition nlx.hpp:109
std::uint16_t swdata_size
The size of the VT record in bytes.
Definition nlx.hpp:96
std::int32_t dnextracted_y
Definition nlx.hpp:105
std::int32_t dnextracted_angle
Definition nlx.hpp:107
std::uint32_t dwPoints[VTRecNumTransitionBitfields]
Definition nlx.hpp:98
std::int32_t dnextracted_x
Definition nlx.hpp:103
std::uint16_t swid
The ID assigned to the video tracker that created this record.
Definition nlx.hpp:95
std::uint64_t qwTimeStamp
Timestamp of this record in microseconds.
Definition nlx.hpp:97
std::int16_t sncrc
Ignored, relic from Cheetah160VT.
Definition nlx.hpp:102
std::uint16_t swstx
Value is always NlxDataTypes::NLX_VTREC_SWSTX.
Definition nlx.hpp:94