1function HDR=bdf2biosig_events(HDR, Mode)
2% BDF2BIOSIG_EVENTS converts BDF Status channel into BioSig Event codes.
3%
4%  HDR = bdf2biosig_events(HDR [,Mode])
5%
6% INPUT:
7%   HDR is the header structure generated by SOPEN, SLOAD or mexSLOAD
8%	from loading a Biosemi (BDF) file.
9%	Specifically, HDR.BDF.ANNONS contains the info of the status channel.
10%   Mode [default = 4]
11%	determines how the BDF status channel is converted into
12% 	the event table HDR.EVENT. Currently, the following modes are
13%	supported:
14%	 1: epoching information is derived from bit17
15%	    only lower 8 bits are supported
16%	 2: suggested decoding if standardized event codes (according to
17%	    .../biosig/doc/eventcodes.txt) are used
18%	 3: Trigger Input 1-15, raising and falling edges
19%	 4: [default] Trigger Input 1-15, raising edges
20%	 5: Trigger input 1-8, raising and falling edges are considered
21%	 6: Trigger input 1-8, only raising edges are considered
22%	 7: bit-based decoding
23%	99: not recommended, because it could break some functionality in BioSig
24% Output:
25%   HDR.EVENT contains the generated Event table.
26%
27% see also: doc/eventcodes.txt, doc/header.txt, SOPEN, SLOAD
28%
29%
30% Referenzes:
31% [1] http://www.biosemi.com/faq/file_format.htm
32% [2] http://www.biosemi.com/faq/trigger_signals.htm
33
34
35%	$Id$
36%	Copyright (C) 2007,2008,2009,2011 by Alois Schloegl <alois.schloegl@gmail.com>
37%    	This is part of the BIOSIG-toolbox http://biosig.sf.net/
38
39% This library is free software; you can redistribute it and/or
40% modify it under the terms of the GNU Library General Public
41% License as published by the Free Software Foundation; either
42% Version 2 of the License, or (at your option) any later version.
43%
44% This library is distributed in the hope that it will be useful,
45% but WITHOUT ANY WARRANTY; without even the implied warranty of
46% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
47% Library General Public License for more details.
48%
49% You should have received a copy of the GNU Library General Public
50% License along with this library; if not, write to the
51% Free Software Foundation, Inc., 59 Temple Place - Suite 330,
52% Boston, MA  02111-1307, USA.
53
54
55if nargin<2 || isempty(Mode),
56	Mode = 4;
57end;
58
59if ~isfield(HDR,'BDF') || ~isfield(HDR.BDF,'ANNONS')
60	%% is not a BDF file
61	return;
62end;
63t = HDR.BDF.ANNONS;
64
65ix1 = diff(double([0;bitand(t,2^16)]));	% start of epoch
66ix2 = diff(double([0;bitand(t,2^16-1)]));	% labels
67
68% defines mapping of the BDF-status channel to BioSig event codes
69switch Mode,    % determines default decoding
70
71case 1,
72	% epoching information is derived from bit17
73	% only lower 8 bits are supported
74	POS = [find(ix1>0);find(ix2>0);find(ix1<0);find(ix2<0)];
75	TYP = [repmat(hex2dec('7ffe'),sum(ix1>0),1); bitand(t(ix2>0),255); repmat(hex2dec('fffe'),sum(ix1<0),1); bitor(bitand(t(find(ix2<0)-1),255),2^15)];
76
77case 2,
78	% suggested decoding if standardized event codes (according to
79	% .../biosig/doc/eventcodes.txt) are used
80	POS = [find(ix2>0)];
81	TYP = [bitand(t(ix2>0),2^16-1)];
82
83case 3,
84	% Trigger Input 1-15, raising and falling edges
85	t = bitand(HDR.BDF.ANNONS,2^16-1);
86	t(~~bitand(HDR.BDF.ANNONS,2^16)) = 0;
87	ix2 = diff(double([0;bitand(t,2^16-1)]));	% labels
88	POS = [find(ix2)];
89 	TYP = [t(ix2>0); t(find(ix2<0)-1)+hex2dec('8000')];
90
91case 4,
92	% Trigger Input 1-15, raising edges
93	t = bitand(HDR.BDF.ANNONS,2^16-1);
94	t(~~bitand(HDR.BDF.ANNONS,2^16)) = 0;
95	ix2 = diff(double([0;bitand(t,2^16-1)]));	% labels
96	POS = [find(ix2>0)];
97	TYP = [t(ix2>0)];
98
99case 5,
100	% Trigger input 1-8, raising and falling edges are considered
101	t = bitand(HDR.BDF.ANNONS,255);			% only bit1-8 are considered, useful if bit9-16 are open/undefined
102	t(~~bitand(HDR.BDF.ANNONS,2^16)) = 0;
103	ix2 = diff(double([0;bitand(t,2^16-1)]));	% labels
104	POS = [find(ix2)];
105 	TYP = [t(ix2>0); t(find(ix2<0)-1)+hex2dec('8000')];
106
107case 6,
108	% Trigger input 1-8, only raising edges are considered
109	t = bitand(HDR.BDF.ANNONS,255);			% only bit1-8 are considered, useful if bit9-16 are open/undefined
110	t(~~bitand(HDR.BDF.ANNONS,2^16)) = 0;
111	ix2 = diff(double([0;bitand(t,2^16-1)]));	% labels
112	POS = [find(ix2>0)];
113	TYP = [t(ix2>0)];
114
115case 7,
116	%% bit-based decoding
117	POS = [];
118	TYP = [];
119	for k=1:16,
120		t = bitand(HDR.BDF.ANNONS,2^(k-1));
121		t = t~=t(1);			% support of low-active and high-active
122		ix2 = diff(double([0;t]));	% labels
123		POS = [POS; find(ix2>0); find(ix2<0)];
124 		TYP = [TYP; repmat(k,sum(ix2>0),1); repmat(k+hex2dec('8000'),sum(ix2<0),1)];
125 		HDR.EVENT.CodeDesc{k} = sprintf('bit %i',k);
126	end;
127case 8,
128	%% bit-based decoding with only high-active
129	POS = [];
130	TYP = [];
131	for k=1:16,
132		t = bitand(HDR.BDF.ANNONS,2^(k-1));
133		ix2 = diff(double([0;t]));
134		POS = [POS; find(ix2>0)];
135		TYP = [TYP; repmat(k,sum(ix2>0),1)];
136		HDR.EVENT.CodeDesc{k} = sprintf('bit %i',k);
137	end;
138
139case 9, % according to Tobias Feldmann-Wustefeld, this is how the BVA import works
140	t = bitand(HDR.BDF.ANNONS,2^16-1);
141	ix2 = diff([0;t])~=0;
142	POS = find(ix2);
143	TYP = t(ix2);
144	if any(TYP > 255),
145		warning('event table use codes outside the range for user-specified events');
146	end
147
148case 99,
149	% not recommended, because it could break some functionality in BioSig
150	POS = [find(ix2>0);find(ix2<0)];
151 	TYP = [bitand(t(ix2>0),2^16-1); bitor(bitand(t(find(ix2<0)-1),2^16-1),2^15)];
152
153otherwise,
154	fprintf(HDR.FILE.stderr,'Warning BDF2BIOSIG_EVENTS: Mode BDF:%d not supported\n', Mode);
155
156end;
157HDR.EVENT = [];
158[HDR.EVENT.POS,ix] = sort(POS);
159HDR.EVENT.TYP = TYP(ix);
160
161
162%%%% BDF Trigger and status
163t = bitand(HDR.BDF.ANNONS,hex2dec('00ffff'));
164ix = diff(double([0;t]));
165HDR.BDF.Trigger.POS = find(ix);
166HDR.BDF.Trigger.TYP = t(HDR.BDF.Trigger.POS);
167
168t = bitand(bitshift(HDR.BDF.ANNONS,-16),hex2dec('00ff'));
169ix = diff(double([0;t]));
170HDR.BDF.Status.POS = find(ix);
171HDR.BDF.Status.TYP = t(HDR.BDF.Status.POS);
172
173%HDR.BDF.ANNONS = []; 	% not needed anymore, saves memory
174