From 21714911e8e8a1e3cc3af91aebb77f4898186d80 Mon Sep 17 00:00:00 2001 From: James Cotton Date: Sun, 1 Jan 2012 13:14:18 -0600 Subject: [PATCH] Convert log files to structure of array instead of array of struct from Kenz --- .../plugins/uavobjects/uavobjecttemplate.m | 79 ++++++++++++++++--- .../matlab/uavobjectgeneratormatlab.cpp | 69 +++++++++------- .../matlab/uavobjectgeneratormatlab.h | 1 + 3 files changed, 110 insertions(+), 39 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjecttemplate.m b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecttemplate.m index 5cfcb6068..96d727dff 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobjecttemplate.m +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjecttemplate.m @@ -1,39 +1,54 @@ -function [] = OPLogConvert(logfile) +function [] = OPLogConvert(varargin) %% Define indices and arrays of structures to hold data % THIS FILE IS AUTOMATICALLY GENERATED. -$(ALLOCATIONCODE) + +outputType='mat'; %Default output is a .mat file if nargin==0 %% if (exist('uigetfile')) - [FileName, PathName]=uigetfile; + [FileName, PathName]=uigetfile('*.opl'); logfile=fullfile(PathName, FileName); else error('Your technical computing program does not support file choosers. Please input the file name in the argument. ') + end +elseif nargin>0 + logfile=varargin{1}; + if nargin>1 + outputType=varargin{2}; end end +if ~strcmpi(outputType,'mat') && ~strcmpi(outputType,'csv') + error('Incorrect file format specified. Second argument must be ''mat'' or ''csv''.'); +end + +$(ALLOCATIONCODE) + + fid = fopen(logfile); +correctMsgByte=hex2dec('20'); +correctSyncByte=hex2dec('3C'); % Parse log file, entry by entry while (1) %% Read logging header - timestamp = fread(fid, 1, 'uint32'); + timestamp = fread(fid, 1, '*uint32'); if (feof(fid)); break; end - datasize = fread(fid, 1, 'int64'); + datasize = fread(fid, 1, '*int64'); %% Read message header % get sync field (0x3C, 1 byte) sync = fread(fid, 1, 'uint8'); - if sync ~= hex2dec('3C') + if sync ~= correctSyncByte disp ('Wrong sync byte'); return end % get msg type (quint8 1 byte ) should be 0x20, ignore the rest? msgType = fread(fid, 1, 'uint8'); - if msgType ~= hex2dec('20') + if msgType ~= correctMsgByte disp ('Wrong msgType'); return end @@ -42,12 +57,15 @@ while (1) % get obj id (quint32 4 bytes) objID = fread(fid, 1, 'uint32'); + if (isempty(objID)) %End of file + break; + end %% Read object switch objID $(SWITCHCODE) otherwise - disp(['Unknown object ID: 0x' dec2hex(objID)]); + disp(['Unknown object ID: 0x' dec2hex(objID)]); msgBytesLeft = datasize - 1 - 1 - 2 - 4; fread(fid, msgBytesLeft, 'uint8'); end @@ -60,13 +78,52 @@ fclose(fid); % Trim output structs $(CLEANUPCODE) -matfile = strrep(logfile,'opl','mat'); -save(matfile $(SAVEOBJECTSCODE)); - +if strcmpi(outputType,'mat') + matfile = strrep(logfile,'opl','mat'); + save(matfile $(SAVEOBJECTSCODE)); +else +$(EXPORTCSVCODE); +end %% Object reading functions $(FUNCTIONSCODE) +% This function prunes the excess pre-allocated space +function [structOut]=PruneStructOfArrays(structIn, lastIndex) + + fieldNames = fieldnames(structIn); + for i=1:length(fieldNames) + structOut.(fieldNames{i})=structIn.(fieldNames{i})(1:lastIndex); + end + + +function OPLog2csv(structIn, structName, logfile) + %Get each field name from the structure + fieldNames = fieldnames(structIn); + + %Create a text string with the field names + headerOut=sprintf('%s,',fieldNames{:}); + headerOut=headerOut(1:end-1); %Trim off last `,` and `\t` + + %Assign the structure arrays to a matrix. + matOut=zeros(max(size(structIn.(fieldNames{1}))), length(fieldNames)); + + if isempty(structIn.(fieldNames{1})); + matOut=[]; + else + for i=1:length(fieldNames) + matOut(:,i)=structIn.(fieldNames{i}); + end + end + % Create filename by replacing opl by csv + [path, name] = fileparts(logfile); + csvDirName=[name '_csv']; + [dummyA, dummyB]=mkdir(fullfile(path, csvDirName)); %Dummy outputs so the program doens't throw warnings about "Directory already exists" + csvfile=fullfile(path, csvDirName , [name '.csv']); + + %Write to csv. + dlmwrite(csvfile, headerOut, ''); + dlmwrite(csvfile, matOut, '-append'); diff --git a/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.cpp b/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.cpp index c7cedddda..9f160ad52 100644 --- a/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.cpp +++ b/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.cpp @@ -54,6 +54,7 @@ bool UAVObjectGeneratorMatlab::generate(UAVObjectParser* parser,QString template matlabCodeTemplate.replace( QString("$(CLEANUPCODE)"), matlabCleanupCode); matlabCodeTemplate.replace( QString("$(SAVEOBJECTSCODE)"), matlabSaveObjectsCode); matlabCodeTemplate.replace( QString("$(FUNCTIONSCODE)"), matlabFunctionsCode); + matlabCodeTemplate.replace( QString("$(EXPORTCSVCODE)"), matlabExportCsvCode); bool res = writeFile( matlabOutputPath.absolutePath() + "/OPLogConvert.m", matlabCodeTemplate ); if (!res) { @@ -78,7 +79,7 @@ bool UAVObjectGeneratorMatlab::process_object(ObjectInfo* info) QString objectTableName(objectName); QString tableIdxName(objectName.toLower() + "Idx"); QString functionName("Read" + info->name + "Object"); - QString functionCall(functionName + "(fid, timestamp)"); + QString functionCall(functionName + "(fid, timestamp, "); QString objectID(QString().setNum(info->id)); QString isSingleInst = boolTo01String( info->isSingleInst ); @@ -87,7 +88,7 @@ bool UAVObjectGeneratorMatlab::process_object(ObjectInfo* info) // Generate allocation code (will replace the $(ALLOCATIONCODE) tag) // //===================================================================// // matlabSwitchCode.append("\t\tcase " + objectID + "\n"); - matlabAllocationCode.append("\n\t" + tableIdxName + " = 1;\n"); + matlabAllocationCode.append("\n\t" + tableIdxName + " = 0;\n"); QString type; QString allocfields; if (0){ @@ -97,7 +98,7 @@ bool UAVObjectGeneratorMatlab::process_object(ObjectInfo* info) type = fieldTypeStrMatlab[info->fields[n]->type]; // Append field if ( info->fields[n]->numElements > 1 ) - allocfields.append("\t" + objectTableName + "(1)." + info->fields[n]->name + " = zeros(1," + QString::number(info->fields[n]->numElements, 10) + ");\n"); + allocfields.append("\t" + objectTableName + "(1)." + info->fields[n]->name + " = zeros(" + QString::number(info->fields[n]->numElements, 10) + ",1);\n"); else allocfields.append("\t" + objectTableName + "(1)." + info->fields[n]->name + " = 0;\n"); } @@ -112,52 +113,64 @@ bool UAVObjectGeneratorMatlab::process_object(ObjectInfo* info) type = fieldTypeStrMatlab[info->fields[n]->type]; // Append field if ( info->fields[n]->numElements > 1 ) - allocfields.append(",...\n\t\t '" + info->fields[n]->name + "', zeros(1," + QString::number(info->fields[n]->numElements, 10) + ")"); + allocfields.append(",...\n\t\t '" + info->fields[n]->name + "', zeros(" + QString::number(info->fields[n]->numElements, 10) + ",1)"); else allocfields.append(",...\n\t\t '" + info->fields[n]->name + "', 0"); } allocfields.append(");\n"); - } + } matlabAllocationCode.append(allocfields); - matlabAllocationCode.append("\t" + objectTableName.toUpper() + "_OBJID=" + objectID + ";\n"); + matlabAllocationCode.append("\t" + objectTableName.toUpper() + "_OBJID=" + objectID + ";\n"); - //=============================================================// + //==============================================================// // Generate 'Switch:' code (will replace the $(SWITCHCODE) tag) // - //=============================================================// + //==============================================================// + + + matlabSwitchCode.append("\t\tcase " + objectTableName.toUpper() + "_OBJID\n"); - matlabSwitchCode.append("\t\t\t" + objectTableName + "(" + tableIdxName +") = " + functionCall + ";\n"); - matlabSwitchCode.append("\t\t\t" + tableIdxName + " = " + tableIdxName +" + 1;\n"); - matlabSwitchCode.append("\t\t\tif " + tableIdxName + " > length(" + objectTableName +")\n"); - matlabSwitchCode.append("\t\t\t\t" + objectTableName + "(" + tableIdxName + "*2+1) = " + objectTableName +"(end);\n"); - matlabSwitchCode.append("\t\t\t\t" + objectTableName +"(end)=[];\n"); +// matlabSwitchCode.append("\t\t\t" + objectTableName + "(" + tableIdxName +") = " + functionCall + ";\n"); + matlabSwitchCode.append("\t\t\t" + tableIdxName + " = " + tableIdxName +" + 1;\n"); + matlabSwitchCode.append("\t\t\t" + objectTableName + "= " + functionCall + objectTableName + ", " + tableIdxName + ");\n"); + matlabSwitchCode.append("\t\t\tif " + tableIdxName + " >= length(" + objectTableName +") %Check to see if pre-allocated memory is exhausted\n"); + matlabSwitchCode.append("\t\t\t\tFieldNames= fieldnames(" + objectTableName +");\n"); + matlabSwitchCode.append("\t\t\t\tfor i=1:length(FieldNames) %Grow structure\n"); + matlabSwitchCode.append("\t\t\t\t\t" + objectTableName + ".(FieldNames{i})(:," + tableIdxName + "*2+1) = 0;\n"); + matlabSwitchCode.append("\t\t\t\tend;\n"); matlabSwitchCode.append("\t\t\tend\n"); - //=============================================================// + //============================================================// // Generate 'Cleanup:' code (will replace the $(CLEANUP) tag) // - //=============================================================// - matlabCleanupCode.append(objectTableName + "(" + tableIdxName +":end) = [];\n"); + //============================================================// + matlabCleanupCode.append(objectTableName + "=PruneStructOfArrays(" + objectTableName + "," + tableIdxName +"); %#ok\n" ); + - - //=============================================================================// - // Generate objects saving code code (will replace the $(SAVEOBJECTSCODE) tag) // - //=============================================================================// + //========================================================================// + // Generate objects saving code (will replace the $(SAVEOBJECTSCODE) tag) // + //========================================================================// matlabSaveObjectsCode.append(",'"+objectTableName+"'"); - matlabFunctionsCode.append("%%\n% " + objectName + " read function\n"); + //==========================================================================// + // Generate objects csv export code (will replace the $(EXPORTCSVCODE) tag) // + //==========================================================================// + matlabExportCsvCode.append("\tOPLog2csv(" + objectTableName + ", '"+objectTableName+"', logfile);\n"); +// OPLog2csv(ActuatorCommand, 'ActuatorCommand', logfile) //=================================================================// // Generate functions code (will replace the $(FUNCTIONSCODE) tag) // //=================================================================// - //Generate function description comment - matlabFunctionsCode.append("function [" + objectName + "] = " + functionCall + "\n"); - matlabFunctionsCode.append("\t" + objectName + ".timestamp = timestamp;\n"); + //Generate function description comment + matlabFunctionsCode.append("%%\n% " + objectName + " read function\n"); + + matlabFunctionsCode.append("function [" + objectName + "] = " + functionCall + objectTableName + ", " + tableIdxName + ")" + "\n"); + matlabFunctionsCode.append("\t" + objectName + ".timestamp(" + tableIdxName + ")= timestamp;\n"); matlabFunctionsCode.append("\tif " + isSingleInst + "\n"); matlabFunctionsCode.append("\t\theaderSize = 8;\n"); matlabFunctionsCode.append("\telse\n"); - matlabFunctionsCode.append("\t\t" + objectName + ".instanceID = fread(fid, 1, 'uint16');\n"); + matlabFunctionsCode.append("\t\t" + objectName + ".instanceID(" + tableIdxName + ") = (fread(fid, 1, 'uint16'));\n"); matlabFunctionsCode.append("\t\theaderSize = 10;\n"); matlabFunctionsCode.append("\tend\n\n"); @@ -169,14 +182,14 @@ bool UAVObjectGeneratorMatlab::process_object(ObjectInfo* info) type = fieldTypeStrMatlab[info->fields[n]->type]; // Append field if ( info->fields[n]->numElements > 1 ) - funcfields.append("\t" + objectName + "." + info->fields[n]->name + " = double(fread(fid, " + QString::number(info->fields[n]->numElements, 10) + ", '" + type + "'));\n"); + funcfields.append("\t" + objectName + "." + info->fields[n]->name + "(:," + tableIdxName + ") = double(fread(fid, " + QString::number(info->fields[n]->numElements, 10) + ", '" + type + "'));\n"); else - funcfields.append("\t" + objectName + "." + info->fields[n]->name + " = double(fread(fid, 1, '" + type + "'));\n"); + funcfields.append("\t" + objectName + "." + info->fields[n]->name + "(" + tableIdxName + ") = double(fread(fid, 1, '" + type + "'));\n"); } matlabFunctionsCode.append(funcfields); matlabFunctionsCode.append("\t% read CRC\n"); - matlabFunctionsCode.append("\tfread(fid, 1, 'uint8');\n"); + matlabFunctionsCode.append("\tfread(fid, 1, '*uint8');\n"); matlabFunctionsCode.append("\n\n"); diff --git a/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.h b/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.h index b86b001a5..c4025a4f4 100644 --- a/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.h +++ b/ground/uavobjgenerator/generators/matlab/uavobjectgeneratormatlab.h @@ -40,6 +40,7 @@ private: QString matlabSwitchCode; QString matlabCleanupCode; QString matlabSaveObjectsCode; + QString matlabExportCsvCode; QString matlabFunctionsCode; QStringList fieldTypeStrMatlab;