dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
uavobjecttemplate.m
Go to the documentation of this file.
1 function [] = LogConvert(varargin)
2 % Convert log files into matlab structures
3 %
4 % If called with no arguements this function will present a
5 % file chooser. If called with a string arguement it will
6 % process that file name.
7 %
8 % To process Overo files call with
9 % LogConvert(path_to_file, true)
10 %
11 % Tau Labs (C) 2012-2013
12 % dRonin (C) 2016
13 
14 %% Define indices and arrays of structures to hold data
15 % THIS FILE IS AUTOMATICALLY GENERATED.
16 
17 % dRonin git branch:
18 uavoImporterHash= '${TAG_OR_BRANCH}:${HASH8}${DIRTY} ${DATETIME}';
19 UAVO_HASH = '${UAVOSHA1TXT}';
20 
21 outputType='mat'; %Default output is a .mat file
22 checkCRC = false;
23 wrongSyncByte=0;
24 wrongMessageByte=0;
25 lastWrongSyncByte=0;
26 lastWrongMessageByte=0;
27 str1=[]; %#ok<NASGU>
28 str2=[];
29 str3=[];
30 str4=[];
31 str5=[];
32 multipleInstanceLookup = zeros(0,2);
33 overo = false;
34 
35 fprintf('\n\n***dRonin log parser***\n\n');
36 global crc_table;
37 crc_table = [ ...
38  hex2dec('00'),hex2dec('07'),hex2dec('0e'),hex2dec('09'),hex2dec('1c'),hex2dec('1b'),hex2dec('12'),hex2dec('15'),hex2dec('38'),hex2dec('3f'),hex2dec('36'),hex2dec('31'),hex2dec('24'),hex2dec('23'),hex2dec('2a'),hex2dec('2d'), ...
39  hex2dec('70'),hex2dec('77'),hex2dec('7e'),hex2dec('79'),hex2dec('6c'),hex2dec('6b'),hex2dec('62'),hex2dec('65'),hex2dec('48'),hex2dec('4f'),hex2dec('46'),hex2dec('41'),hex2dec('54'),hex2dec('53'),hex2dec('5a'),hex2dec('5d'), ...
40  hex2dec('e0'),hex2dec('e7'),hex2dec('ee'),hex2dec('e9'),hex2dec('fc'),hex2dec('fb'),hex2dec('f2'),hex2dec('f5'),hex2dec('d8'),hex2dec('df'),hex2dec('d6'),hex2dec('d1'),hex2dec('c4'),hex2dec('c3'),hex2dec('ca'),hex2dec('cd'), ...
41  hex2dec('90'),hex2dec('97'),hex2dec('9e'),hex2dec('99'),hex2dec('8c'),hex2dec('8b'),hex2dec('82'),hex2dec('85'),hex2dec('a8'),hex2dec('af'),hex2dec('a6'),hex2dec('a1'),hex2dec('b4'),hex2dec('b3'),hex2dec('ba'),hex2dec('bd'), ...
42  hex2dec('c7'),hex2dec('c0'),hex2dec('c9'),hex2dec('ce'),hex2dec('db'),hex2dec('dc'),hex2dec('d5'),hex2dec('d2'),hex2dec('ff'),hex2dec('f8'),hex2dec('f1'),hex2dec('f6'),hex2dec('e3'),hex2dec('e4'),hex2dec('ed'),hex2dec('ea'), ...
43  hex2dec('b7'),hex2dec('b0'),hex2dec('b9'),hex2dec('be'),hex2dec('ab'),hex2dec('ac'),hex2dec('a5'),hex2dec('a2'),hex2dec('8f'),hex2dec('88'),hex2dec('81'),hex2dec('86'),hex2dec('93'),hex2dec('94'),hex2dec('9d'),hex2dec('9a'), ...
44  hex2dec('27'),hex2dec('20'),hex2dec('29'),hex2dec('2e'),hex2dec('3b'),hex2dec('3c'),hex2dec('35'),hex2dec('32'),hex2dec('1f'),hex2dec('18'),hex2dec('11'),hex2dec('16'),hex2dec('03'),hex2dec('04'),hex2dec('0d'),hex2dec('0a'), ...
45  hex2dec('57'),hex2dec('50'),hex2dec('59'),hex2dec('5e'),hex2dec('4b'),hex2dec('4c'),hex2dec('45'),hex2dec('42'),hex2dec('6f'),hex2dec('68'),hex2dec('61'),hex2dec('66'),hex2dec('73'),hex2dec('74'),hex2dec('7d'),hex2dec('7a'), ...
46  hex2dec('89'),hex2dec('8e'),hex2dec('87'),hex2dec('80'),hex2dec('95'),hex2dec('92'),hex2dec('9b'),hex2dec('9c'),hex2dec('b1'),hex2dec('b6'),hex2dec('bf'),hex2dec('b8'),hex2dec('ad'),hex2dec('aa'),hex2dec('a3'),hex2dec('a4'), ...
47  hex2dec('f9'),hex2dec('fe'),hex2dec('f7'),hex2dec('f0'),hex2dec('e5'),hex2dec('e2'),hex2dec('eb'),hex2dec('ec'),hex2dec('c1'),hex2dec('c6'),hex2dec('cf'),hex2dec('c8'),hex2dec('dd'),hex2dec('da'),hex2dec('d3'),hex2dec('d4'), ...
48  hex2dec('69'),hex2dec('6e'),hex2dec('67'),hex2dec('60'),hex2dec('75'),hex2dec('72'),hex2dec('7b'),hex2dec('7c'),hex2dec('51'),hex2dec('56'),hex2dec('5f'),hex2dec('58'),hex2dec('4d'),hex2dec('4a'),hex2dec('43'),hex2dec('44'), ...
49  hex2dec('19'),hex2dec('1e'),hex2dec('17'),hex2dec('10'),hex2dec('05'),hex2dec('02'),hex2dec('0b'),hex2dec('0c'),hex2dec('21'),hex2dec('26'),hex2dec('2f'),hex2dec('28'),hex2dec('3d'),hex2dec('3a'),hex2dec('33'),hex2dec('34'), ...
50  hex2dec('4e'),hex2dec('49'),hex2dec('40'),hex2dec('47'),hex2dec('52'),hex2dec('55'),hex2dec('5c'),hex2dec('5b'),hex2dec('76'),hex2dec('71'),hex2dec('78'),hex2dec('7f'),hex2dec('6a'),hex2dec('6d'),hex2dec('64'),hex2dec('63'), ...
51  hex2dec('3e'),hex2dec('39'),hex2dec('30'),hex2dec('37'),hex2dec('22'),hex2dec('25'),hex2dec('2c'),hex2dec('2b'),hex2dec('06'),hex2dec('01'),hex2dec('08'),hex2dec('0f'),hex2dec('1a'),hex2dec('1d'),hex2dec('14'),hex2dec('13'), ...
52  hex2dec('ae'),hex2dec('a9'),hex2dec('a0'),hex2dec('a7'),hex2dec('b2'),hex2dec('b5'),hex2dec('bc'),hex2dec('bb'),hex2dec('96'),hex2dec('91'),hex2dec('98'),hex2dec('9f'),hex2dec('8a'),hex2dec('8d'),hex2dec('84'),hex2dec('83'), ...
53  hex2dec('de'),hex2dec('d9'),hex2dec('d0'),hex2dec('d7'),hex2dec('c2'),hex2dec('c5'),hex2dec('cc'),hex2dec('cb'),hex2dec('e6'),hex2dec('e1'),hex2dec('e8'),hex2dec('ef'),hex2dec('fa'),hex2dec('fd'),hex2dec('f4'),hex2dec('f3') ...
54  ];
55 
56 if nargin==0
57  %%
58  if (exist('uigetfile')) %#ok<EXIST>
59  [FileName, PathName]=uigetfile({'*.drlog;*.tll','dRonin Log Files (*.drlog, *.tll)'});
60  logfile=fullfile(PathName, FileName);
61 
62  else
63  error('Your technical computing program does not support file choosers. Please input the file name in the argument. ')
64  end
65 elseif nargin>0
66  logfile=varargin{1};
67  if nargin>1 && strcmp(class(varargin{2}),'char') == 1
68  outputType=varargin{2};
69  elseif nargin>1 && strcmp(class(varargin{2}),'logical') == 1
70  overo = varargin{2};
71  end
72 end
73 
74 if ~strcmpi(outputType,'mat') && ~strcmpi(outputType,'csv')
75  error('Incorrect file format specified. Second argument must be ''mat'' or ''csv''.');
76 end
77 
78 $(INSTANTIATIONCODE)
79 
80 
81 fid = fopen(logfile);
82 
83 fgetl(fid); %Read first line
84 gitLogfileHash = fgetl(fid); %Read second line
85 uavoLogfileHash = fgetl(fid); %Read third line
86 
87 
88 if strcmp(gitLogfileHash,uavoImporterHash) == 0
89  warning('Git hashes do not match. Incorrect file importer.'); %#ok<WNTAG>
90 end
91 if strcmp(uavoLogfileHash,UAVO_HASH) == 0
92  warning('UAVO hashes do not match. Incorrect file importer.'); %#ok<WNTAG>
93 end
94 
95 
96 
97 
98 buffer=fread(fid,Inf,'uchar=>uchar');
99 
100 
101 bufferIdx=1;
102 
103 correctMsgByte=hex2dec('20');
104 correctSyncByte=hex2dec('3C');
105 unknownObjIDList=zeros(1,2);
106 
107 % Parse log file, entry by entry
108 % prebuf = buffer(1:12);
109 
110 last_print = -1e10;
111 
112 startTime=clock;
113 
114 if overo
115  instanceIdOffset = -2;
116  timestampWraparound = 2^16;
117 else
118  instanceIdOffset = 0;
119  timestampWraparound = 2^32;
120 end
121 
122 timestampAccumulator = 0;
123 lastTimestamp = 0;
124 
125 buffer_len = length(buffer);
126 
127 while bufferIdx < (buffer_len - 20)
128  %% Read message header
129  % get sync field (0x3C, 1 byte)
130  if ~overo
131  sync = buffer(bufferIdx+12);
132  else
133  sync = buffer(bufferIdx);
134  end
135 
136  if sync ~= correctSyncByte
137  bufferIdx=bufferIdx+1;
138  if ~overo || sync ~= 255
139  wrongSyncByte = wrongSyncByte + 1;
140  end
141  continue
142  end
143 
144  if ~overo
145  % For GCS logging the format is as follows
146  % 4 bytes timestamp (milliseconds)
147  % 8 bytes data size
148  % UAVTalk packet (always without timestamped packets)
149  % Sync val (0x3c)
150  % Message type (1 byte)
151  % Length (2 bytes)
152  % Object ID (4 bytes)
153  % Instance ID (optional, 2 bytes)
154  % Data (variable length)
155  % Checksum (1 byte)
156 
157  % Process header, if we are aligned
158  datasizeBufferIdx = bufferIdx; %Just grab the index. We'll do a typecast later, if necessary
159  datasizeLength = 4;
160  msgType = buffer(bufferIdx+13); % get msg type (quint8 1 byte ) should be 0x20, ignore the rest?
161  objID = typecast(buffer(bufferIdx+16:bufferIdx+ 16+4-1), 'uint32'); % get obj id (quint32 4 bytes)
162  timestamp = double(typecast(buffer(bufferIdx:bufferIdx+4-1),'uint32'));
163 
164  % Advance buffer past header to where data is (or instance ID)
165  bufferIdx=bufferIdx + 20;
166  else
167  % For Overo logging the format is
168  % UAVTalk packet (with timestamped packet)
169  % Sync val (0x3c)
170  % Message type (1 byte, adds 0x80)
171  % Length (2 bytes)
172  % Object ID (4 bytes)
173  % Instance ID (optional, 2 bytes)
174  % Timestamp (2 bytes)
175  % Data (variable length)
176  % Checksum (1 byte)
177 
178  % Process header for overo
179  datasizeBufferIdx = bufferIdx + 2;
180  datasizeLength = 2;
181  msgType = buffer(bufferIdx+1) - 128;
182  objID = typecast(buffer(bufferIdx+4:bufferIdx+ 4+4-1), 'uint32');
183 
184  singleInstance = multipleInstanceLookup(multipleInstanceLookup(:,1) == objID, 2);
185  if singleInstance
186  timestamp = double(typecast(buffer(bufferIdx+8:bufferIdx+10-1),'uint16'));
187  else
188  timestamp = double(typecast(buffer(bufferIdx+12:bufferIdx+14-1),'uint16'));
189  end
190 
191  % Advance buffer past header to where data is. In the case of a
192  % multiple instance object this will be where the timstamp is but
193  % the parsing code will advance by two more.
194  bufferIdx = bufferIdx + 10;
195 
196  end
197 
198  if timestamp < lastTimestamp
199  timestampAccumulator = timestampAccumulator + timestampWraparound;
200  end
201  lastTimestamp = timestamp;
202  timestamp = timestamp + timestampAccumulator;
203 
204  %Check that message type is correct
205  if msgType ~= correctMsgByte
206  wrongMessageByte = wrongMessageByte + 1;
207  continue
208  end
209 
210  if (isempty(objID)) %End of file
211  break;
212  end
213 
214  %% Read object
215  try
216  switch objID
217 $(SWITCHCODE)
218  otherwise
219  unknownObjIDListIdx=find(unknownObjIDList(:,1)==objID, 1, 'first');
220  if isempty(unknownObjIDListIdx)
221  unknownObjIDList=[unknownObjIDList; uint32(objID) 1]; %#ok<AGROW>
222  else
223  unknownObjIDList(unknownObjIDListIdx,2)=unknownObjIDList(unknownObjIDListIdx,2)+1;
224  end
225 
226  datasize = typecast(buffer(datasizeBufferIdx + 4:datasizeBufferIdx + 12-1), 'uint64');
227 
228  msgBytesLeft = datasize - 1 - 1 - 2 - 4;
229  if msgBytesLeft > 255
230  msgBytesLeft = 0;
231  end
232  bufferIdx=bufferIdx+double(msgBytesLeft);
233  end
234  catch
235  % One of the reads failed - indicates EOF
236  break;
237  end
238 
239  if (wrongSyncByte ~= lastWrongSyncByte || wrongMessageByte~=lastWrongMessageByte ) ||...
240  bufferIdx - last_print > 5e4 %Every 50,000 bytes show the status update
241 
244 
245  str1=[];
246  for i=1:length([str2 str3 str4 str5]);
247  str1=[str1 sprintf('\b')]; %#ok<AGROW>
248  end
249  str2=sprintf('wrongSyncByte instances: % 10d\n', wrongSyncByte );
250  str3=sprintf('wrongMessageByte instances: % 10d\n\n', wrongMessageByte );
251 
252  str4=sprintf('Completed bytes: % 9d of % 9d\n', bufferIdx, buffer_len);
253 
254  % Arbitrary times two so that it is at least as long
255  estTimeRemaining=(buffer_len-bufferIdx)/(bufferIdx/etime(clock,startTime)) * 2;
256  h=floor(estTimeRemaining/3600);
257  m=floor((estTimeRemaining-h*3600)/60);
258  s=ceil(estTimeRemaining-h*3600-m*60);
259 
260  str5=sprintf('Est. time remaining, %02dh:%02dm:%02ds \n', h,m,s);
261 
263 
264  fprintf([str1 str2 str3 str4 str5]);
265  end
266 
267  %Check if at end of file. If not, load next prebuffer
268  if bufferIdx+12-1 > buffer_len
269  break;
270  end
271 % bufferIdx=bufferIdx+12;
272 
273 end
274 
275 
276 for i=2:size(unknownObjIDList,1) %Don't show the first one, as it was simply a dummy placeholder
277  disp(['Unknown object ID: 0x' dec2hex(unknownObjIDList(i,1),8) ' appeared ' int2str(unknownObjIDList(i,2)) ' times.']);
278 end
279 
280 %% Clean Up and Save mat file
281 fclose(fid);
282 
283 %% Prune vectors
284 $(CLEANUPCODE)
285 
286 
287 %% Perform typecasting on vectors
288 $(ALLOCATIONCODE)
289 
290 %% Save data to file
291 if strcmpi(outputType,'mat')
292  [path, name]=fileparts(logfile);
293  matfile = fullfile(path,[name '.mat']);
294  save(matfile $(SAVEOBJECTSCODE));
295 else
296 $(EXPORTCSVCODE)
297 end
298 
299 fprintf('%d records in %0.2f seconds.\n', buffer_len, etime(clock,startTime));
300 
301 
302 
303 
304 function OPLog2csv(structIn, structName, logfile)
305  %Get each field name from the structure
306  fieldNames = fieldnames(structIn);
307 
308  %Create a text string with the field names
309  headerOut=sprintf('%s,',fieldNames{:});
310  headerOut=headerOut(1:end-1); %Trim off last `,` and `\t`
311 
312  %Assign the structure arrays to a matrix.
313  matOut=zeros(max(size(structIn.(fieldNames{1}))), length(fieldNames));
314 
315  if isempty(structIn.(fieldNames{1}));
316  matOut=[];
317  else
318  for i=1:length(fieldNames)
319  matOut(:,i)=structIn.(fieldNames{i});
320  end
321  end
322  % Create filename by replacing opl by csv
323  [path, name] = fileparts(logfile);
324  csvDirName=[name '_csv'];
325  [dummyA, dummyB]=mkdir(fullfile(path, csvDirName)); %Dummy outputs so the program doens't throw warnings about "Directory already exists"
326  csvfile=fullfile(path, csvDirName , [name '.csv']);
327 
328  %Write to csv.
329  dlmwrite(csvfile, headerOut, '');
330  dlmwrite(csvfile, matOut, '-append');
331 
332 function crc = compute_crc(data)
333  global crc_table;
334  crc = 0;
335  for i = 1:length(data)
336  crc = crc_table(1+bitxor(data(i),crc));
337  end
338 
340 %% This function was inspired by Bruno Luong's 'mcolon'. The name is kept the same as his 'mcolon'
341 % function, found on Matlab's file exchange. The two functions return identical
342 % results, although his is much faster. Unfortunately, C-compiled mex
343 % code would make this function non-cross-platform, so a Matlab scripted
344 % version is provided here.
345  if size(inStart,1) > 1 || size(inFinish,1) > 1
346  if size(inStart,2) > 1 || size(inFinish,2) > 1
347  error('Inputs must be vectors, i.e just one column wide.')
348  else
349  inStart=inStart';
350  inFinish=inFinish';
351  end
352  end
353 
354  diffIn=diff([inStart; inFinish]);
355  numElements=sum(diffIn)+length(inStart);
356 
357  out=zeros(1,numElements);
358 
359  idx=1;
360  for i=1:length(inStart)
361  out(idx:idx+diffIn(i))=inStart(i):inFinish(i);
362  idx=idx+diffIn(i)+1;
363  end
correctMsgByte
function[]
if isempty(structIn.(fieldNames{1}))
lastWrongMessageByte
etime(clock, startTime))
end buffer
const char t[]
Definition: coreconstants.h:40
diff
Definition: OPPlots.m:68
Trim off and t Assign the structure arrays to a matrix matOut
Arbitrary times two so that it is at least as long estTimeRemaining
end end diffIn
global crc_table
end end Create filename by replacing opl by csv[path, name]
while bufferIdx< (buffer_len-20)%%Read message header%get sync field(0x3C, 1 byte) if~overo sync=buffer(bufferIdx+12);else sync=buffer(bufferIdx);end if sync~=correctSyncByte bufferIdx=bufferIdx+1;if~overo||sync~=255 wrongSyncByte=wrongSyncByte+1;end continue end if~overo%For GCS logging the format is as follows%4 bytes timestamp(milliseconds)%8 bytes data size%UAVTalk packet(always without timestamped packets)%Sync val(0x3c)%Message type(1 byte)%Length(2 bytes)%Object ID(4 bytes)%Instance ID(optional, 2 bytes)%Data(variable length)%Checksum(1 byte)%Process header, if we are aligned datasizeBufferIdx=bufferIdx;%Just grab the index.We'll do a typecast later, if necessary datasizeLength=4;msgType=buffer(bufferIdx+13);%get msg type(quint8 1 byte) should be 0x20, ignore the rest?objID=typecast(buffer(bufferIdx+16:bufferIdx+16+4-1), 'uint32');%get obj id(quint32 4 bytes) timestamp=double(typecast(buffer(bufferIdx:bufferIdx+4-1),'uint32'));%Advance buffer past header to where data is(or instance ID) bufferIdx=bufferIdx+20;else%For Overo logging the format is%UAVTalk packet(with timestamped packet)%Sync val(0x3c)%Message type(1 byte, adds 0x80)%Length(2 bytes)%Object ID(4 bytes)%Instance ID(optional, 2 bytes)%Timestamp(2 bytes)%Data(variable length)%Checksum(1 byte)%Process header for overo datasizeBufferIdx=bufferIdx+2;datasizeLength=2;msgType=buffer(bufferIdx+1)-128;objID=typecast(buffer(bufferIdx+4:bufferIdx+4+4-1), 'uint32');singleInstance=multipleInstanceLookup(multipleInstanceLookup(:, 1)==objID, 2);if singleInstance timestamp=double(typecast(buffer(bufferIdx+8:bufferIdx+10-1),'uint16'));else timestamp=double(typecast(buffer(bufferIdx+12:bufferIdx+14-1),'uint16'));end%Advance buffer past header to where data is.In the case of a%multiple instance object this will be where the timstamp is but%the parsing code will advance by two more.bufferIdx=bufferIdx+10;end if timestamp< lastTimestamp timestampAccumulator=timestampAccumulator+timestampWraparound;end lastTimestamp=timestamp;timestamp=timestamp+timestampAccumulator;%Check that message type is correct if msgType~=correctMsgByte wrongMessageByte=wrongMessageByte+1;continue end if(isempty(objID))%End of file break;end%%Read object try switch objID $(SWITCHCODE) otherwise unknownObjIDListIdx=find(unknownObjIDList(:, 1)==objID, 1, 'first');if isempty(unknownObjIDListIdx) unknownObjIDList=[unknownObjIDList;uint32(objID) 1];%#ok< AGROW > else unknownObjIDList(unknownObjIDListIdx, 2)=unknownObjIDList(unknownObjIDListIdx, 2)+1;end datasize=typecast(buffer(datasizeBufferIdx+4:datasizeBufferIdx+12-1), 'uint64');msgBytesLeft=datasize-1-1-2-4;if msgBytesLeft > 255 msgBytesLeft=0;end bufferIdx=bufferIdx+double(msgBytesLeft);end catch%One of the reads failed-indicates EOF break;end if(wrongSyncByte~=lastWrongSyncByte||wrongMessageByte~=lastWrongMessageByte)||...bufferIdx-last_print > Every
buffer_len
Dummy outputs so the program doens t throw warnings about Directory already exists csvfile
Create a text string with the field names headerOut
end Check if at end of file If not
unknownObjIDList
wrongMessageByte
DataFields data
else(EXPORTCSVCODE) end fprintf('%d records in%0.2f seconds.\n'
end a
Definition: OPPlots.m:98
Write to csv dlmwrite(csvfile, headerOut, '')
end function found on Matlab s file exchange The two functions return identical although his is much faster Unfortunately
Parse log file
end function out
Prune vectors(CLEANUPCODE)%%Perform typecasting on vectors $(ALLOCATIONCODE)%%Save data to file if strcmpi(outputType
end(INSTANTIATIONCODE) fid
for i
numElements
lastTimestamp
last_print
Eccentricity n
Definition: OPPlots.m:137
Prune mat[path, name]
multipleInstanceLookup
load(matfile)
lastWrongSyncByte
csvDirName
end function found on Matlab s file exchange The two functions return identical results
else error('Your technical computing program does not support file choosers.Please input the file name in the argument. ') end elseif nargin >0 logfile
x
Definition: OPPlots.m:100
end timestampAccumulator
wrongSyncByte
function crc
'Inputs must be vectors, i.e just one column wide.' inStart()
fprintf('\n\n ***dRonin log parser ***\n\n')
e
Definition: OPPlots.m:99
timestampWraparound