Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addition of online plug-in for Neuroscan Scan recording software #2

Open
wants to merge 3 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions code/online_plugins/Neuroscan/BCILAB.readme
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
README for Neuroscan Scan Plugin for BCILAB
Author: Visual Attention and Cognition Lab, Dan Roberts, and Nick Pe�aranda, George Mason University, Spring 2014
Released under the GPLv3, see COPYING.txt
Based on the BrainVision BCILAB plug-in by Hal Greenwald


Plugin to stream EEG data and event markers from Neuroscan Scan software to BCILAB. Has been tested with Scan 4.3 and a NuAmps 40-channel amplifier

Associated Files:

BCILAB/code/online_plugins/Neuroscan:
ns_close.m
ns_open.m
ns_parseheader.m
ns_parseinfo.m
ns_read.m
ns_sendpacket.m
run_readneuroscan.m
674 changes: 674 additions & 0 deletions code/online_plugins/Neuroscan/COPYING.txt

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions code/online_plugins/Neuroscan/ns_close.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
function ns_close(h)
% Close a TCP connection to Neuroscan Scan
% ns_close(h)
%
%
% In:
% h : handle to an existing Neuroscan connection
%
% Author: Visual Attention and Cognition Lab, Dan Roberts, and Nick Pe�aranda, George Mason University, Spring 2014
% Released under the GPLv3, see COPYING.txt
% Based on the BrainVision BCILAB plug-in by Hal Greenwald


% send message to Scan to stop sending data
ns_sendpacket(TCP_Connection,'CTRL',3,4,0);
% and indicate that connection is closing
ns_sendpacket(TCP_Connection,'CTRL',1,2,0);

if ~h.initialized
return;
end
disp('Cleaning up connection to Neuroscan Scan');
pnet(h.handle, 'close');
if evalin('base', ['exist(' 'sprintf(''%s'', h.name)' ')'])
evalin('base',['clear ' sprintf('%s',h.name) ';']);
end
89 changes: 89 additions & 0 deletions code/online_plugins/Neuroscan/ns_open.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
function h = ns_open(hostname, port)
% Open a TCP connection to Neuroscan Recorder
% h = ns_open(Hostname, Port)
%
%
% In:
% Hostname: Source TCP hostname. Can be a computer name, URL, or IP
% address
%
% Port : the port on which to connect to the TCP host
%
% Out:
% h : handle to a newly opened Neuroscan connection
%
% Author: Visual Attention and Cognition Lab, Dan Roberts, and Nick Pe�aranda, George Mason University, Spring 2014
% Released under the GPLv3, see COPYING.txt
% Based on the BrainVision BCILAB plug-in by Hal Greenwald


% open the connection
h.handle = pnet('tcpconnect', hostname, port);
ConnectionStatus = pnet(h.handle,'status');

if ConnectionStatus > 0
disp('Neuroscan Scan connection established');
else
error('Neuroscan Scan connection failed - check the IP and port');
end

% flush the buffer
bufferData = pnet(h.handle,'read', 'noblock');
while ~isempty(bufferData);
bufferData = pnet(h.handle,'read', 'noblock');
end

% request basic header
ns_sendpacket(h.handle,'CTRL',3,5,0);

% try
% read reader and basic info
packetBytes = pnet(h.handle,'read', 40, 'uint8');

% parse header data
header = ns_parseheader(packetBytes(1:12));
basicinfo = ns_parseinfo(packetBytes(13:end));

% attach Neuroscan parameters to connection handle
infoFields = fields(basicinfo);
for f = 1:length(infoFields)
h.(infoFields{f}) = basicinfo.(infoFields{f});
end

h.totalChan = h.numChan + h.numEventChan;

if h.numEventChan ~= 0
h.markerChanIdx = h.numChan + 1;
end

% number of bytes for neuroscan header
h.headerSize = 12;

% save the block size, equal to the number of channels (including
% marker channel) x the number of samples per block x the number of
% bytes per sample
h.dataBlockSize = (basicinfo.numChan + basicinfo.numEventChan) ...
* basicinfo.samplesPerBlock * basicinfo.bytesPerSample;

% save the data type (16 or 32 bit integer) for later casting
if h.bytesPerSample == 2
h.datatype = 'int16';
elseif h.bytesPerSample == 4
h.datatype = 'int32';
else
error('expecting either 2 or 4 bytes per sample');
end

h.cleanup = onCleanup(@()pnet(h.handle, 'close'));

% instruct Scan to begin sending data
ns_sendpacket(h.handle,'CTRL',3,3,0);
h.initialized = true;

% catch er
% disp(er.message);
% return;
% end

end

36 changes: 36 additions & 0 deletions code/online_plugins/Neuroscan/ns_parseheader.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
function hdr = ns_parseheader(header)
% Parse the header info packet returned by Neuroscan Scan server
% hdr = ns_parseinfo(dataBytes)
%
%
% In:
% dataBytes : 12 byte array returned by Neuroscan server as header
%
% Out:
% hdr: Structure containing each element of packet header as a field.
% Header information includes:
%
% id: ID string, 'CTRL', 'FILE', or 'DATA'
%
% code: Control code, 1 (General), 2 (Server), or 3 (Client)
%
% req: Request value, see the Neuroscan Acquire manual
%
% bodysize: Size (in bytes) of message attached to header,
% or 0 if packet does not contain a data body (for example start
% or stop acquisition messages)
%
%
% Author: Visual Attention and Cognition Lab, Dan Roberts, and Nick Pe�aranda, George Mason University, Spring 2014
% Released under the GPLv3, see COPYING.txt
% Based on the BrainVision BCILAB plug-in by Hal Greenwald


hdr = struct('id',[],'code',[],'req',[],'bodysize',[]);

hdr.id = char(header(1:4));
hdr.code = double(typecast(fliplr(uint8(header(5:6))), 'uint16'));
hdr.req = double(typecast(fliplr(uint8(header(7:8))), 'uint16'));
hdr.bodysize = double(typecast(fliplr(uint8(header(9:12))), 'uint32'));


47 changes: 47 additions & 0 deletions code/online_plugins/Neuroscan/ns_parseinfo.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
function basicinfo = ns_parseinfo(dataBytes)
% Parse the basic info packet returned by Neuroscan Scan
% basicinfo = ns_parseinfo(dataBytes)
%
%
% In:
% dataBytes : 28 byte array returned by Neuroscan server after requesting
% basic info
%
% Out:
% basicinfo: Structure containing each element of basic EEG info as a
% field. EEG info includes:
%
% size: size of info array (in bytes)
%
% numChan: number of EEG data channels
%
% numEventChan: number of event marker channels
%
% samplesPerBlock: the number of data samples transmitted each block
%
% srate: data sampling rate in Hz
%
% bytesPerSamples: number of bytes per sample, either 2 (16 bits
% per sample) or 4 (32 bits per sample)
%
% resolution: the value in microvolts represented by the least
% significant bit
%
%
% Author: Visual Attention and Cognition Lab, Dan Roberts, and Nick Pe�aranda, George Mason University, Spring 2014
% Released under the GPLv3, see COPYING.txt
% Based on the BrainVision BCILAB plug-in by Hal Greenwald

% basic EEG info
basicinfo = struct('size',[],'numChan',[],'numEventChan',[],'samplesPerBlock',[],...
'srate', [], 'bytesPerSample', [], 'resolution', []);

basicinfo.size = double(typecast((uint8(dataBytes(1:4))), 'int32'));
basicinfo.numChan = double(typecast((uint8(dataBytes(5:8))), 'int32'));
basicinfo.numEventChan = double(typecast((uint8(dataBytes(9:12))), 'int32'));
basicinfo.samplesPerBlock = double(typecast((uint8(dataBytes(13:16))), 'int32'));
basicinfo.srate = double(typecast((uint8(dataBytes(17:20))), 'int32'));
basicinfo.bytesPerSample = double(typecast((uint8(dataBytes(21:24))), 'int32'));
basicinfo.resolution = double(typecast((uint8(dataBytes(25:28))), 'single'));

end
84 changes: 84 additions & 0 deletions code/online_plugins/Neuroscan/ns_read.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
function block = ns_read(h)
% Block reader for Neuroscan Scan Recorder
% ns_read(h)
%
%
% In:
% h : handle to an existing Neuroscan connection
%
% Out:
% block: cell array data block containing EEG and event values
%
% Author: Visual Attention and Cognition Lab, Dan Roberts, and Nick Pe�aranda, George Mason University, Spring 2014
% Released under the GPLv3, see COPYING.txt
% Based on the BrainVision BCILAB plug-in by Hal Greenwald

data = [];
if (~h.initialized)
return;
end

try
% check for existing data in socket buffer
headerBytes = pnet(h.handle, 'read', h.headerSize, 'uint8', 'noblock');

events = [];

if ~isempty(headerBytes)

headerData = ns_parseheader(headerBytes);

if strcmp(headerData.id, 'DATA')

% wait until the data packet body is available
dataPreview = [];
while length(dataPreview) < headerData.bodysize
% wait until the rest of the packet is available
dataPreview = pnet(h.handle, 'read', headerData.bodysize,...
'uint8', 'view', 'noblock');
end

% read the data packet body
dataBytes = pnet(h.handle, 'read', headerData.bodysize, 'uint8', 'noblock');

dataBytes = reshape(uint8(dataBytes), [h.bytesPerSample, h.totalChan, h.samplesPerBlock]);

markerValues = squeeze((dataBytes(1,h.markerChanIdx, :)));
markerPoints = find(markerValues);

if ~isempty(markerPoints)
markers = markerValues(markerPoints);
latencies = markerPoints;
for m = 1:length(markers)
events(m).type = num2str(markers(m)); %#ok<AGROW>
events(m).latency = latencies(m); %#ok<AGROW>
end
else
events = [];
end

dataBytes(:,h.markerChanIdx, :) = [];

dataCell = squeeze(num2cell(dataBytes, 1));
dataBlock = cellfun(@(x) typecast(x, h.datatype), dataCell);
data = horzcat(data, dataBlock);

else
disp('unknown message');
end

end


catch er
disp(er.message);
rethrow(er);
end

if ~isempty(data)
% scale data to uV units
data = bsxfun(@times,data,h.resolution);
end

block = {data,events};

35 changes: 35 additions & 0 deletions code/online_plugins/Neuroscan/ns_sendpacket.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
function ns_sendpacket(h,id,code,request,bodysize)
% Prepare and send a data packet to Neuroscan Scan server
% ns_sendpacket(h,id,code,request,bodysize)
%
%
% In:
% h: PNET connection handle
%
% id: Neuroscan message ID string
%
% code: Neuroscan message code value
%
% request: Neuroscan message request value
%
% bodysize: Size of message body
%
% Note: See the Neuroscan Scan documentation for description of message ID,
% code, and request values
%
% Author: Visual Attention and Cognition Lab, Dan Roberts, and Nick Pe�aranda, George Mason University, Spring 2014
% Released under the GPLv3, see COPYING.txt
% Based on the BrainVision BCILAB plug-in by Hal Greenwald


% assemble the packet
packet = zeros(12,1,'uint8');
packet(1:4) = id;
packet(5:6) = fliplr(typecast(int16(code),'int8'));
packet(7:8) = fliplr(typecast(int16(request),'int8'));
packet(9:12) = fliplr(typecast(int32(bodysize),'int8'));
% write the packet
pnet(h,'write', packet)

end

Loading