diff --git a/@osqp/codegen.m b/@osqp/codegen.m index d753762..3bd3958 100644 --- a/@osqp/codegen.m +++ b/@osqp/codegen.m @@ -1,31 +1,34 @@ %% -function codegen(this, target_dir, varargin) +function codegen(this, out, varargin) % CODEGEN generate C code for the parametric problem % % codegen(target_dir,options) % Parse input arguments p = inputParser; - defaultProject = ''; - expectedProject = {'', 'Makefile', 'MinGW Makefiles', 'Unix Makefiles', 'CodeBlocks', 'Xcode'}; - defaultParams = 'vectors'; - expectedParams = {'vectors', 'matrices'}; - defaultMexname = 'emosqp'; - defaultFloat = false; - defaultLong = true; - defaultFW = false; - - addRequired(p, 'target_dir', @isstr); - addParameter(p, 'project_type', defaultProject, ... - @(x) ischar(validatestring(x, expectedProject))); - addParameter(p, 'parameters', defaultParams, ... - @(x) ischar(validatestring(x, expectedParams))); - addParameter(p, 'mexname', defaultMexname, @isstr); - addParameter(p, 'FLOAT', defaultFloat, @islogical); - addParameter(p, 'LONG', defaultLong, @islogical); - addParameter(p, 'force_rewrite', defaultFW, @islogical); - - parse(p, target_dir, varargin{:}); + defaultPrefix = 'prob1_'; % Prefix for filenames and C variables; useful if generating multiple problems + defaultForceRewrite = true; % Force rewrite if output folder exists? + defaultParameters = 'vectors'; % What do we wish to update in the generated code? + % One of 'vectors' (allowing update of q/l/u through prob.update_data_vec) + % or 'matrices' (allowing update of P/A/q/l/u + % through prob.update_data_vec or prob.update_data_mat) + defaultUseFloat = false; % Use single precision in generated code? + defaultPrintingEnable = false; % Enable solver printing? + defaultProfilingEnable = false; % Enable solver profiling? + defaultInterruptEnable = false; % Enable user interrupt (Ctrl-C)? + defaultEnableDerivatives = false; % Enable derivatives? + + addRequired(p, 'out', @isstr); + addOptional(p, 'prefix', defaultPrefix, @isstr); + addParameter(p, 'force_rewrite', defaultForceRewrite, @isboolean); + addParameter(p, 'parameters', defaultParameters, @isstr); + addParameter(p, 'float_type', defaultUseFloat, @isboolean); + addParameter(p, 'printing_enable', defaultPrintingEnable, @isboolean); + addParameter(p, 'profiling_enable', defaultProfilingEnable, @isboolean); + addParameter(p, 'interrupt_enable', defaultInterruptEnable, @isboolean); + addParameter(p, 'derivatives_enable', defaultEnableDerivatives, @isboolean); + + parse(p, out, varargin{:}); % Set internal variables if strcmp(p.Results.parameters, 'vectors') @@ -33,41 +36,19 @@ function codegen(this, target_dir, varargin) else embedded = 2; end - if p.Results.FLOAT - float_flag = 'ON'; - else - float_flag = 'OFF'; - end - if p.Results.LONG - long_flag = 'ON'; - else - long_flag = 'OFF'; - end - if strcmp(p.Results.project_type, 'Makefile') - if (ispc) - project_type = 'MinGW Makefiles'; % Windows - elseif (ismac || isunix) - project_type = 'Unix Makefiles'; % Unix - end - else - project_type = p.Results.project_type; - end - % Check whether the specified directory already exists - if exist(target_dir, 'dir') - if p.Results.force_rewrite - rmdir(target_dir, 's'); - else - while(1) - prompt = sprintf('Directory "%s" already exists. Do you want to replace it? y/n [y]: ', target_dir); - str = input(prompt, 's'); - if any(strcmpi(str, {'','y'})) - rmdir(target_dir, 's'); - break; - elseif strcmpi(str, 'n') - return; - end + % Check whether the specified directory already exists + if exist(out, 'dir') + while(1) + prompt = sprintf('Directory "%s" already exists. Do you want to replace it? y/n [y]: ', out); + str = input(prompt, 's'); + + if any(strcmpi(str, {'','y'})) + rmdir(out, 's'); + break; + elseif strcmpi(str, 'n') + return; end end end @@ -79,20 +60,17 @@ function codegen(this, target_dir, varargin) addpath(fullfile(osqp_path, 'codegen')); % Path of osqp module - cg_dir = fullfile(osqp_path, 'codegen'); + cg_dir = fullfile(osqp_path, '..', 'codegen'); files_to_generate_path = fullfile(cg_dir, 'files_to_generate'); - % Get workspace structure - work = osqp_mex('get_workspace', this.objectHandle); - % Make target directory fprintf('Creating target directories...\t\t\t\t\t'); - target_configure_dir = fullfile(target_dir, 'configure'); - target_include_dir = fullfile(target_dir, 'include'); - target_src_dir = fullfile(target_dir, 'src'); + target_configure_dir = fullfile(out, 'configure'); + target_include_dir = fullfile(out, 'include'); + target_src_dir = fullfile(out, 'src'); - if ~exist(target_dir, 'dir') - mkdir(target_dir); + if ~exist(out, 'dir') + mkdir(out); end if ~exist(target_configure_dir, 'dir') mkdir(target_configure_dir); @@ -105,104 +83,66 @@ function codegen(this, target_dir, varargin) end fprintf('[done]\n'); - % Copy source files to target directory - fprintf('Copying OSQP source files...\t\t\t\t\t'); - cdir = fullfile(cg_dir, 'sources', 'src'); - cfiles = dir(fullfile(cdir, '*.c')); - for i = 1 : length(cfiles) - if embedded == 1 - % Do not copy kkt.c if embedded is 1 - if ~strcmp(cfiles(i).name, 'kkt.c') - copyfile(fullfile(cdir, cfiles(i).name), ... - fullfile(target_src_dir, 'osqp', cfiles(i).name)); - end - else - copyfile(fullfile(cdir, cfiles(i).name), ... - fullfile(target_src_dir, 'osqp', cfiles(i).name)); - end - end - configure_dir = fullfile(cg_dir, 'sources', 'configure'); - configure_files = dir(fullfile(configure_dir, '*.h.in')); - for i = 1 : length(configure_files) - copyfile(fullfile(configure_dir, configure_files(i).name), ... - fullfile(target_configure_dir, configure_files(i).name)); - end - hdir = fullfile(cg_dir, 'sources', 'include'); - hfiles = dir(fullfile(hdir, '*.h')); - for i = 1 : length(hfiles) - if embedded == 1 - % Do not copy kkt.h if embedded is 1 - if ~strcmp(hfiles(i).name, 'kkt.h') - copyfile(fullfile(hdir, hfiles(i).name), ... - fullfile(target_include_dir, hfiles(i).name)); - end - else - copyfile(fullfile(hdir, hfiles(i).name), ... - fullfile(target_include_dir, hfiles(i).name)); - end - end - - % Copy cmake files - copyfile(fullfile(cdir, 'CMakeLists.txt'), ... - fullfile(target_src_dir, 'osqp', 'CMakeLists.txt')); - copyfile(fullfile(hdir, 'CMakeLists.txt'), ... - fullfile(target_include_dir, 'CMakeLists.txt')); - fprintf('[done]\n'); - - % Copy example.c - copyfile(fullfile(files_to_generate_path, 'example.c'), target_src_dir); - - % Render CMakeLists.txt - fidi = fopen(fullfile(files_to_generate_path, 'CMakeLists.txt'),'r'); - fido = fopen(fullfile(target_dir, 'CMakeLists.txt'),'w'); - while ~feof(fidi) - l = fgetl(fidi); % read line - % Replace EMBEDDED_FLAG in CMakeLists.txt by a numerical value - newl = strrep(l, 'EMBEDDED_FLAG', num2str(embedded)); - fprintf(fido, '%s\n', newl); - end - fclose(fidi); - fclose(fido); - - % Render workspace.h and workspace.c - work_hfile = fullfile(target_include_dir, 'workspace.h'); - work_cfile = fullfile(target_src_dir, 'osqp', 'workspace.c'); - fprintf('Generating workspace.h/.c...\t\t\t\t\t\t'); - render_workspace(work, work_hfile, work_cfile, embedded); - fprintf('[done]\n'); - - % Create project - if ~isempty(project_type) - - % Extend path for CMake mac (via Homebrew) - PATH = getenv('PATH'); - if ((ismac) && (isempty(strfind(PATH, '/usr/local/bin')))) - setenv('PATH', [PATH ':/usr/local/bin']); - end - - fprintf('Creating project...\t\t\t\t\t\t\t\t'); - orig_dir = pwd; - cd(target_dir); - mkdir('build') - cd('build'); - cmd = sprintf('cmake -G "%s" ..', project_type); - [status, output] = system(cmd); - if(status) - fprintf('\n'); - fprintf(output); - error('Error configuring CMake environment'); - else - fprintf('[done]\n'); - end - cd(orig_dir); - end - - % Make mex interface to the generated code - mex_cfile = fullfile(files_to_generate_path, 'emosqp_mex.c'); - make_emosqp(target_dir, mex_cfile, embedded, float_flag, long_flag); - - % Rename the mex file - old_mexfile = ['emosqp_mex.', mexext]; - new_mexfile = [p.Results.mexname, '.', mexext]; - movefile(old_mexfile, new_mexfile); + %TODO: Fix the copying stuff + % % Copy source files to target directory + % fprintf('Copying OSQP source files...\t\t\t\t\t'); + % cdir = fullfile(cg_dir, 'sources', 'src'); + % cfiles = dir(fullfile(cdir, '*.c')); + % for i = 1 : length(cfiles) + % if embedded == 1 + % % Do not copy kkt.c if embedded is 1 + % if ~strcmp(cfiles(i).name, 'kkt.c') + % copyfile(fullfile(cdir, cfiles(i).name), ... + % fullfile(target_src_dir, 'osqp', cfiles(i).name)); + % end + % else + % copyfile(fullfile(cdir, cfiles(i).name), ... + % fullfile(target_src_dir, 'osqp', cfiles(i).name)); + % end + % end + % configure_dir = fullfile(cg_dir, 'sources', 'configure'); + % configure_files = dir(fullfile(configure_dir, '*.h.in')); + % for i = 1 : length(configure_files) + % copyfile(fullfile(configure_dir, configure_files(i).name), ... + % fullfile(target_configure_dir, configure_files(i).name)); + % end + % hdir = fullfile(cg_dir, 'sources', 'inc'); + % hfiles = dir(fullfile(hdir, '*.h')); + % for i = 1 : length(hfiles) + % if embedded == 1 + % % Do not copy kkt.h if embedded is 1 + % if ~strcmp(hfiles(i).name, 'kkt.h') + % copyfile(fullfile(hdir, hfiles(i).name), ... + % fullfile(target_include_dir, hfiles(i).name)); + % end + % else + % copyfile(fullfile(hdir, hfiles(i).name), ... + % fullfile(target_include_dir, hfiles(i).name)); + % end + % end + % + % % Copy cmake files + % copyfile(fullfile(cdir, 'CMakeLists.txt'), ... + % fullfile(target_src_dir, 'osqp', 'CMakeLists.txt')); + % copyfile(fullfile(hdir, 'CMakeLists.txt'), ... + % fullfile(target_include_dir, 'CMakeLists.txt')); + % fprintf('[done]\n'); + % + % % Copy example.c + % copyfile(fullfile(files_to_generate_path, 'example.c'), target_src_dir); + + % Update codegen defines + update_codegen_defines(this, 'embedded_mode', embedded, 'float_type', p.Results.float_type, 'printing_enable', p.Results.printing_enable, 'profiling_enable', p.Results.profiling_enable, 'interrupt_enable', p.Results.interrupt_enable, 'derivatives_enable', p.Results.derivatives_enable); + % Call codegen + osqp_mex('codegen', this.objectHandle, out, p.Results.prefix); + + % TODO: Do we want to keep this? + % % Make mex interface to the generated code + % mex_cfile = fullfile(files_to_generate_path, 'emosqp_mex.c'); + % make_emosqp(out, mex_cfile, embedded, float_flag, long_flag); + % + % % Rename the mex file + % old_mexfile = ['emosqp_mex.', mexext]; + % new_mexfile = [p.Results.mexname, '.', mexext]; + % movefile(old_mexfile, new_mexfile); end \ No newline at end of file diff --git a/@osqp/osqp.m b/@osqp/osqp.m index cc58bcd..ba91633 100644 --- a/@osqp/osqp.m +++ b/@osqp/osqp.m @@ -8,20 +8,21 @@ % % osqp Methods: % - % setup - configure solver with problem data - % solve - solve the QP - % update - modify problem vectors - % warm_start - set warm starting variables x and y + % setup - configure solver with problem data + % solve - solve the QP + % update - modify problem vectors + % warm_start - set warm starting variables x and y % - % default_settings - create default settings structure - % current_settings - get the current solver settings structure - % update_settings - update the current solver settings structure + % default_settings - create default settings structure + % current_settings - get the current solver settings structure + % update_settings - update the current solver settings structure % - % get_dimensions - get the number of variables and constraints - % version - return OSQP version - % constant - return a OSQP internal constant + % get_dimensions - get the number of variables and constraints + % version - return OSQP version + % constant - return a OSQP internal constant % - % codegen - generate embeddable C code for the problem + % update_codegen_defines - update the current codegen defines + % codegen - generate embeddable C code for the problem properties(SetAccess = private, Hidden = true) diff --git a/@osqp/update_codegen_defines.m b/@osqp/update_codegen_defines.m new file mode 100644 index 0000000..8f9efa0 --- /dev/null +++ b/@osqp/update_codegen_defines.m @@ -0,0 +1,16 @@ +function update_codegen_defines(this, varargin) + % UPDATE_CODEGEN_DEFINES update the current codegen defines + + % Check for structure style input + if(isstruct(varargin{1})) + newSettings = varargin{1}; + assert(length(varargin) == 1, 'too many input arguments'); + else + newSettings = struct(varargin{:}); + end + + % Write the new codegen defiens. The C-function checks for input + % validity. + osqp_mex('update_codegen_defines', this.objectHandle, newSettings); +end + diff --git a/c_sources/CMakeLists.txt b/c_sources/CMakeLists.txt index 5c42782..c552db2 100644 --- a/c_sources/CMakeLists.txt +++ b/c_sources/CMakeLists.txt @@ -69,6 +69,7 @@ matlab_add_mex( NAME osqp_mex ${CMAKE_CURRENT_SOURCE_DIR}/memory_matlab.c ${CMAKE_CURRENT_SOURCE_DIR}/osqp_struct_info.cpp ${CMAKE_CURRENT_SOURCE_DIR}/osqp_struct_settings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/osqp_struct_codegen_defines.cpp LINK_TO osqpstatic ${UT_LIBRARY} # Force compilation in the traditional C API (equivalent to the -R2017b flag) diff --git a/c_sources/osqp_mex.cpp b/c_sources/osqp_mex.cpp index 05f82b3..9892a1b 100755 --- a/c_sources/osqp_mex.cpp +++ b/c_sources/osqp_mex.cpp @@ -1,9 +1,9 @@ #include +#include #include "mex.h" #include "matrix.h" #include "osqp.h" - // Mex-specific functionality #include "osqp_mex.hpp" #include "osqp_struct.h" @@ -13,15 +13,21 @@ //TODO: Check if this definition is required, and maybe replace it with: // enum linsys_solver_type { QDLDL_SOLVER, MKL_PARDISO_SOLVER }; #define QDLDL_SOLVER 0 //Based on the previous API +#define CMD_MAX_LEN 64 +#define OUTPUT_DIR_MAX_LEN 256 +#define PREFIX_MAX_LEN 128 + +using std::string; // Wrapper class to pass the OSQP solver back and forth with Matlab class OsqpData { public: OsqpData() : - solver(NULL) + solver(NULL), defines(NULL) {} OSQPSolver* solver; + OSQPCodegenDefines* defines; }; @@ -33,6 +39,98 @@ static void setToNaN(double* arr_out, OSQPInt len){ } } +// This is a utility function that uses mexErrMsgTxt using std::string instead of char*. +void mexErrMsgTxt(string str) { + mexErrMsgTxt(str.c_str()); +} + +/** + * This is a utility function that assigns prhs[ind] to char. + * + * @param nrhs Number of input arguments + * @param prhs Matlab input arrays + * @param ind prhs index + * @param str Target string + * @param max_len Maximum allowed length of the string. If passed 0 (default), use sizeof(str) instead. +*/ +void setString(int nrhs, const mxArray *prhs[], int ind, char *str, int max_len){ + int str_max_len = sizeof(str); + if (max_len>0) str_max_len = max_len; + if (nrhs < (ind+1) || mxGetString(prhs[ind], str, str_max_len)){ + mexErrMsgTxt("Input #" + std::to_string(ind) + " should be less than " + std::to_string(str_max_len) + " characters long."); + } +} + +/** + * This function validates the inputs to OSQPCodegenDefines. Calls mexErrMsgTxt if a NULL or an invalid input is passed. + * + * @param defines OSQPCodegenDefines object +*/ +void validateCodegenDefines(const OSQPCodegenDefines* defines) { + if (!defines) mexErrMsgTxt("A NULL defines object has been passed."); + + if (defines->embedded_mode){ + if (defines->embedded_mode != 1 && defines->embedded_mode != 2) mexErrMsgTxt("Invalid embedded mode."); + } + + if (defines->float_type){ + if (defines->float_type != 0 && defines->float_type != 1) mexErrMsgTxt("Invalid float type."); + } + + if (defines->printing_enable){ + if (defines->printing_enable != 0 && defines->printing_enable != 1) mexErrMsgTxt("Invalid printing enable."); + } + + if (defines->profiling_enable) { + if (defines->profiling_enable != 0 && defines->profiling_enable != 1) mexErrMsgTxt("Invalid profiling enable."); + } + + if (defines->interrupt_enable) { + if (defines->interrupt_enable != 0 && defines->interrupt_enable != 1) mexErrMsgTxt("Invalid interrupt enable."); + } + + if (defines->derivatives_enable) { + if (defines->derivatives_enable != 0 && defines->derivatives_enable != 1) mexErrMsgTxt("Invalid derivatives enable."); + } +} + + + +/** + * This function updates CodegenDefines object. Calls mexErrMsgTxt if a NULL or an invalid input is passed. + * + * @param target_defines Pointer to the target OSQPCodegenDefines object. + * @param new_defines Pointer to the OSQPCodegenDefines object witht he new values. +*/ +void updateCodegenDefines(OSQPCodegenDefines* target_defines, + const OSQPCodegenDefines* new_defines) { + if (!target_defines) mexErrMsgTxt("Defines is uninitialized. No codegen defines have been configured."); + validateCodegenDefines(new_defines); + + if (new_defines->embedded_mode){ + target_defines->embedded_mode = new_defines->embedded_mode; + } + + if (new_defines->float_type){ + target_defines->float_type = new_defines->float_type; + } + + if (new_defines->printing_enable){ + target_defines->printing_enable = new_defines->printing_enable; + } + + if (new_defines->profiling_enable) { + target_defines->profiling_enable = new_defines->profiling_enable; + } + + if (new_defines->interrupt_enable) { + target_defines->interrupt_enable = new_defines->interrupt_enable; + } + + if (new_defines->derivatives_enable) { + target_defines->derivatives_enable = new_defines->derivatives_enable; + } +} // Main mex function void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) @@ -44,11 +142,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) OSQPInt exitflag = 0; // Get the command string - char cmd[64]; - - if (nrhs < 1 || mxGetString(prhs[0], cmd, sizeof(cmd))) - mexErrMsgTxt("First input should be a command string less than 64 characters long."); + char cmd[CMD_MAX_LEN]; + setString(nrhs, prhs, 0, cmd, CMD_MAX_LEN); + /* * First check to see if a new object was requested */ @@ -59,6 +156,8 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } // Return a handle to a new C++ wrapper instance osqpData = new OsqpData; + osqpData->defines = new OSQPCodegenDefines; + osqp_set_default_codegen_defines(osqpData->defines); plhs[0] = convertPtr2Mat(osqpData); return; } @@ -115,7 +214,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) char constant[64]; int constantLength = mxGetN(prhs[1]) + 1; - mxGetString(prhs[1], constant, constantLength); + setString(nrhs, prhs, 1, constant, constantLength); auto ci = intConstants.find(constant); @@ -147,16 +246,13 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) */ // Check for a second input, which should be the class instance handle - if (nrhs < 2) - mexErrMsgTxt("Second input should be a class instance handle."); - + if (nrhs < 2) mexErrMsgTxt("Second input should be a class instance handle."); // Get the class instance pointer from the second input osqpData = convertMat2Ptr(prhs[1]); // delete the object and its data if (!strcmp("delete", cmd)) { - osqp_cleanup(osqpData->solver); destroyObject(prhs[1]); // Warn if other commands were ignored @@ -169,10 +265,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) if (!strcmp("current_settings", cmd)) { // Throw an error if this is called before solver is configured if(!osqpData->solver) { - mexErrMsgTxt("Solver is uninitialized. No settings have been configured."); + mexErrMsgTxt("Solver is uninitialized. No settings have been configured."); } if(!osqpData->solver->settings) { - mexErrMsgTxt("Solver settings is uninitialized. No settings have been configured."); + mexErrMsgTxt("Solver settings is uninitialized. No settings have been configured."); } // Report the current settings @@ -188,7 +284,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) // and for all error checking // throw an error if this is called before solver is configured if(!osqpData->solver){ - mexErrMsgTxt("Solver is uninitialized. No settings have been configured."); + mexErrMsgTxt("Solver is uninitialized. No settings have been configured."); } OSQPSettingsWrapper settings(prhs[2]); @@ -499,6 +595,50 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } + if (!strcmp("default_codegen_defines", cmd)) { + // Warn if other commands were ignored + if (nrhs > 2) + mexWarnMsgTxt("Default codegen settings: unexpected number of arguments."); + + // Create a Settings structure in default form and report the results + OSQPCodegenDefinesWrapper codegen_settings; + plhs[0] = codegen_settings.GetMxStruct(); + return; + } + + if (!strcmp("update_codegen_defines", cmd)) { + // Overwrite the current settings. Mex function is responsible + // for disallowing overwrite of selected settings after initialization, + // and for all error checking + // throw an error if this is called before solver is configured + if(!osqpData->defines){ + mexErrMsgTxt("Defines is uninitialized. No codegen defines have been configured."); + } + + OSQPCodegenDefinesWrapper defines(prhs[2]); + updateCodegenDefines(osqpData->defines, defines.GetOSQPStruct()); + return; + } + + if (!strcmp("codegen", cmd)) { + + //Check that the correct number of arguments is passed + if (nrhs != 4) mexErrMsgTxt("Codegen: unexpected number of arguments"); + char output_dir[OUTPUT_DIR_MAX_LEN]; + char prefix[PREFIX_MAX_LEN]; + setString(nrhs, prhs, 2, output_dir, OUTPUT_DIR_MAX_LEN); + setString(nrhs, prhs, 3, prefix, PREFIX_MAX_LEN); + + //Check that the solver was initialized + if(!osqpData->solver) mexErrMsgTxt("Solver has not been initialized."); + if(!osqpData->defines) mexErrMsgTxt("Codegen defines has not been initialized."); + + exitflag = osqp_codegen(osqpData->solver,output_dir, prefix, osqpData->defines); + + if (exitflag) mexErrMsgTxt("Codegen failed with exitflag = " + std::to_string(exitflag)); + return; + } + // Got here, so command not recognized mexErrMsgTxt("Command not recognized."); } diff --git a/c_sources/osqp_struct.h b/c_sources/osqp_struct.h index 94a432f..7971dd0 100644 --- a/c_sources/osqp_struct.h +++ b/c_sources/osqp_struct.h @@ -202,4 +202,10 @@ typedef OSQPStructWrapper OSQPSettingsWrapper; */ typedef OSQPStructWrapper OSQPInfoWrapper; +/** + * Wrapper around the OSQPCodegenDefines struct + */ +typedef OSQPStructWrapper OSQPCodegenDefinesWrapper; + + #endif \ No newline at end of file diff --git a/c_sources/osqp_struct_codegen_defines.cpp b/c_sources/osqp_struct_codegen_defines.cpp new file mode 100644 index 0000000..c13eca9 --- /dev/null +++ b/c_sources/osqp_struct_codegen_defines.cpp @@ -0,0 +1,28 @@ +#include +#include "osqp_struct.h" + +/* + * Specialization for the codegen_defines struct + */ +template<> +void OSQPStructWrapper::registerFields() { + m_struct = static_cast(c_calloc(1, sizeof(OSQPCodegenDefines))); + if(!m_struct) + mexErrMsgTxt("Failed to allocate a OSQPCodegenDefines object."); + + osqp_set_default_codegen_defines(m_struct); + + /* + * Register the mapping between struct field name and the settings memory location + */ + m_structFields.push_back(new OSQPStructField(&m_struct->embedded_mode, "embedded_mode")); + m_structFields.push_back(new OSQPStructField(&m_struct->float_type, "float_type")); + m_structFields.push_back(new OSQPStructField(&m_struct->printing_enable, "printing_enable")); + m_structFields.push_back(new OSQPStructField(&m_struct->profiling_enable, "profiling_enable")); + m_structFields.push_back(new OSQPStructField(&m_struct->interrupt_enable, "interrupt_enable")); + m_structFields.push_back(new OSQPStructField(&m_struct->derivatives_enable,"derivatives_enable")); +} + + +// Instantiate the OSQPCodegenDefines wrapper class +template class OSQPStructWrapper; \ No newline at end of file