fmi2_capi_t* fmi2_capi_create_dllfmu(jm_callbacks* cb, const char* dllPath, const char* modelIdentifier, const fmi2_callback_functions_t* callBackFunctions, fmi2_fmu_kind_enu_t standard) { fmi2_capi_t* fmu = NULL; jm_log_debug(cb, FMI_CAPI_MODULE_NAME, "Initializing data structures for FMICAPI."); /* Minor check for the callbacks */ if (cb == NULL) { assert(0); return NULL; } /* Allocate memory for the FMU instance */ fmu = (fmi2_capi_t*)cb->calloc(1, sizeof(fmi2_capi_t)); if (fmu == NULL) { /* Could not allocate memory for the FMU struct */ jm_log_fatal(cb, FMI_CAPI_MODULE_NAME, "Could not allocate memory for the FMU struct."); return NULL; } /* Set the import package callback functions */ fmu->callbacks = cb; /* Set the FMI callback functions */ fmu->callBackFunctions = *callBackFunctions; /* Set FMI standard to load */ fmu->standard = standard; /* Set all memory alloated pointers to NULL */ fmu->dllPath = NULL; fmu->modelIdentifier = NULL; /* Copy DLL path */ fmu->dllPath = (char*)cb->calloc(sizeof(char), strlen(dllPath) + 1); if (fmu->dllPath == NULL) { jm_log_fatal(cb, FMI_CAPI_MODULE_NAME, "Could not allocate memory for the DLL path string."); fmi2_capi_destroy_dllfmu(fmu); return NULL; } strcpy((char*)fmu->dllPath, dllPath); /* Copy the modelIdentifier */ fmu->modelIdentifier = (char*)cb->calloc(sizeof(char), strlen(modelIdentifier) + 1); if (fmu->modelIdentifier == NULL) { jm_log_fatal(cb, FMI_CAPI_MODULE_NAME, "Could not allocate memory for the modelIdentifier string."); fmi2_capi_destroy_dllfmu(fmu); return NULL; } strcpy((char*)fmu->modelIdentifier, modelIdentifier); jm_log_debug(cb, FMI_CAPI_MODULE_NAME, "Successfully initialized data structures for FMICAPI."); /* Everything was successful */ return fmu; }
char* jm_create_URL_from_abs_path(jm_callbacks* cb, const char* path) { /* worst case: all symbols are 4-byte UTF-8 and need to be %-encoded */ #define MAX_URL_LENGTH (FILENAME_MAX * 4 * 3 + 7) char buffer[MAX_URL_LENGTH]; char* url; size_t urllen; if(!cb) { cb = jm_get_default_callbacks(); } #if defined(_WIN32) || defined(WIN32) { DWORD pathLen = MAX_URL_LENGTH; HRESULT code = UrlCreateFromPathA( path, buffer, &pathLen, 0); if( (code != S_FALSE) && (code != S_OK)) { jm_log_fatal(cb, module,"Could not constuct file URL from path %s", path); return 0; } urllen = pathLen; } #else { size_t i, len = strlen(path); char *curBuf = buffer + 7; unsigned char ch; strcpy(buffer, "file://"); for( i = 0; i < len; i++) { ch = (unsigned char)path[i]; if( (ch == '/') || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '-') || (ch == '_') || (ch == '.') ||(ch == '~')) { *curBuf = ch; curBuf++; continue; } sprintf(curBuf, "%%%2X", (int)ch);/*safe*/ curBuf+=3; } *curBuf = 0; urllen = curBuf - buffer; } #endif url = (char*)cb->malloc(urllen+1); if(!url) { jm_log_fatal(cb, module,"Could not allocate memory"); return 0; } strcpy(url, buffer); return url; }
char* jm_mk_temp_dir(jm_callbacks* cb, const char* systemTempDir, const char* tempPrefix) { size_t len; char tmpDir[FILENAME_MAX + 2]; char* tmpPath; if(!cb) { cb = jm_get_default_callbacks(); } if(!systemTempDir) { systemTempDir = jm_get_system_temp_dir(); if(!systemTempDir) systemTempDir = "./"; } if(!tempPrefix) { tempPrefix = "jm"; } len = strlen(systemTempDir); if(!jm_get_dir_abspath(cb, systemTempDir, tmpDir, FILENAME_MAX + 2)) { return 0; } len = strlen(tmpDir); if(tmpDir[len-1] != FMI_FILE_SEP[0]) { tmpDir[len] = FMI_FILE_SEP[0]; tmpDir[len+1] = 0; len++; } len += strlen(tempPrefix) + 6; if(len + 16 > FILENAME_MAX) { jm_log_fatal(cb,module, "Canonical name for the temporary files directory is too long (system limit for path length is %d)", FILENAME_MAX); return 0; } tmpPath = (char*)cb->malloc(len + 7); if(!tmpPath) { jm_log_fatal(cb, module,"Could not allocate memory"); return 0; } sprintf(tmpPath,"%s%sXXXXXX",tmpDir,tempPrefix);/*safe*/ if(!jm_mktemp(tmpPath)) { jm_log_fatal(cb, module,"Could not create a unique temporary directory name"); cb->free(tmpPath); return 0; } if(jm_mkdir(cb,tmpPath) != jm_status_success) { cb->free(tmpPath); return 0; } return tmpPath; }
/*#include "fmi1_import_vendor_annotations_impl.h" #include "fmi1_import_parser.h" */ fmi1_import_t* fmi1_import_allocate(jm_callbacks* cb) { fmi1_import_t* fmu = (fmi1_import_t*)cb->calloc(1, sizeof(fmi1_import_t)); if(!fmu || (jm_vector_init(char)(&fmu->logMessageBufferCoded,JM_MAX_ERROR_MESSAGE_SIZE,cb) < JM_MAX_ERROR_MESSAGE_SIZE)) { jm_log_fatal(cb, module, "Could not allocate memory"); if(fmu) cb->free(fmu); return 0; } fmu->dirPath = 0; fmu->location = 0; fmu->callbacks = cb; fmu->capi = 0; fmu->md = fmi1_xml_allocate_model_description(cb); fmu->registerGlobally = 0; jm_vector_init(char)(&fmu->logMessageBufferExpanded,0,cb); if(!fmu->md) { cb->free(fmu); return 0; } return fmu; }
fmi2_import_t* fmi2_import_parse_xml( fmi_import_context_t* context, const char* dirPath, fmi2_xml_callbacks_t* xml_callbacks) { char* xmlPath; char absPath[FILENAME_MAX + 2]; fmi2_import_t* fmu = 0; if(strlen(dirPath) + 20 > FILENAME_MAX) { jm_log_fatal(context->callbacks, module, "Directory path for FMU is too long"); return 0; } xmlPath = fmi_import_get_model_description_path(dirPath, context->callbacks); fmu = fmi2_import_allocate(context->callbacks); if(!fmu) { context->callbacks->free(xmlPath); return 0; } if(jm_get_dir_abspath(context->callbacks, dirPath, absPath, FILENAME_MAX + 2)) { size_t len = strlen(absPath); strcpy(absPath + len, FMI_FILE_SEP "resources"); fmu->resourceLocation = fmi_import_create_URL_from_abs_path(context->callbacks, absPath); } fmu->dirPath = context->callbacks->malloc(strlen(dirPath) + 1); if (!fmu->dirPath || !fmu->resourceLocation) { jm_log_fatal( context->callbacks, "FMILIB", "Could not allocated memory"); fmi2_import_free(fmu); context->callbacks->free(xmlPath); return 0; } strcpy(fmu->dirPath, dirPath); jm_log_verbose( context->callbacks, "FMILIB", "Parsing model description XML"); if(fmi2_xml_parse_model_description( fmu->md, xmlPath, xml_callbacks)) { fmi2_import_free(fmu); fmu = 0; } context->callbacks->free(xmlPath); if(fmu) jm_log_verbose( context->callbacks, "FMILIB", "Parsing finished successfully"); return fmu; }
jm_status_enu_t jm_mkdir(jm_callbacks* cb, const char* dir) { if(!cb) { cb = jm_get_default_callbacks(); } if(MKDIR(dir)) { jm_log_fatal(cb,module,"Could not create directory %s", dir); return jm_status_error; } else return jm_status_success; }
jm_status_enu_t fmi2_capi_load_dll(fmi2_capi_t* fmu) { assert(fmu && fmu->dllPath); fmu->dllHandle = jm_portability_load_dll_handle(fmu->dllPath); /* Load the shared library */ if (fmu->dllHandle == NULL) { jm_log_fatal(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Could not load the FMU binary: %s", jm_portability_get_last_dll_error()); return jm_status_error; } else { jm_log_verbose(fmu->callbacks, FMI_CAPI_MODULE_NAME, "Loaded FMU binary from %s", fmu->dllPath); return jm_status_success; } }
fmi_version_enu_t fmi_import_get_fmi_version( fmi_import_context_t* c, const char* fileName, const char* dirName) { fmi_version_enu_t ret = fmi_version_unknown_enu; jm_status_enu_t status; char* mdpath; jm_log_verbose(c->callbacks, MODULE, "Detecting FMI standard version"); if(!fileName || !*fileName) { jm_log_fatal(c->callbacks, MODULE, "No FMU filename specified"); return fmi_version_unknown_enu; } if(!dirName || !*dirName) { jm_log_fatal(c->callbacks, MODULE, "No temporary directory name specified"); return fmi_version_unknown_enu; } status = fmi_zip_unzip(fileName, dirName, c->callbacks); if(status == jm_status_error) return fmi_version_unknown_enu; mdpath = fmi_import_get_model_description_path(dirName, c->callbacks); ret = fmi_xml_get_fmi_version(c, mdpath); jm_log_info(c->callbacks, MODULE, "XML specifies FMI standard version %s", fmi_version_to_string(ret)); c->callbacks->free(mdpath); return ret; }
/* Loading shared library functions */ static jm_status_enu_t fmi1_capi_get_fcn(fmi1_capi_t* fmu, const char* function_name, jm_dll_function_ptr* dll_function_ptrptr) { char fname[FUNCTION_NAME_LENGTH_MAX]; if (strlen(fmu->modelIdentifier) + strlen(function_name) + 2 > FUNCTION_NAME_LENGTH_MAX) { jm_log_fatal(fmu->callbacks, FMI_CAPI_MODULE_NAME, "DLL function name is too long. Max name length is set to %s.", STRINGIFY(FUNCTION_NAME_LENGTH_MAX)); return jm_status_error; } sprintf(fname,"%s_%s",fmu->modelIdentifier, function_name); return jm_portability_load_dll_function(fmu->dllHandle, fname, dll_function_ptrptr); }
char* jm_get_dir_abspath(jm_callbacks* cb, const char* dir, char* outPath, size_t len) { char curDir[FILENAME_MAX + 2]; if(!cb) { cb = jm_get_default_callbacks(); } if( jm_portability_get_current_working_directory(curDir, FILENAME_MAX+1) != jm_status_success) { jm_log_fatal(cb,module, "Could not get current working directory (%s)", strerror(errno)); return 0; }; if(jm_portability_set_current_working_directory(dir) != jm_status_success) { jm_log_fatal(cb,module, "Could not change to the directory %s", dir); jm_portability_set_current_working_directory(curDir); return 0; }; if( jm_portability_get_current_working_directory(outPath, len) != jm_status_success) { jm_log_fatal(cb,module, "Could not get absolute path for the directory (%s)", strerror(errno)); jm_portability_set_current_working_directory(curDir); return 0; }; jm_portability_set_current_working_directory(curDir); return outPath; }
char* fmi_construct_dll_file_name(jm_callbacks* callbacks, const char* dll_dir_name, const char* model_identifier) { char* fname; size_t len; assert(callbacks && model_identifier); len = strlen(dll_dir_name) + strlen(model_identifier) + strlen(FMI_DLL_EXT) + 1; fname = (char*)callbacks->malloc(len); if (fname == NULL) { jm_log_fatal(callbacks, "FMIUT", "Failed to allocate memory."); return NULL; } sprintf(fname, "%s%s%s", dll_dir_name, model_identifier, FMI_DLL_EXT);/*safe */ return fname; }
fmi1_import_t* fmi1_import_parse_xml( fmi_import_context_t* context, const char* dirPath) { char* xmlPath; char absPath[FILENAME_MAX + 2]; jm_callbacks* cb; fmi1_import_t* fmu; if(!context) return 0; cb = context->callbacks; xmlPath = fmi_import_get_model_description_path(dirPath, context->callbacks); fmu = fmi1_import_allocate(context->callbacks); if(!fmu) { context->callbacks->free(xmlPath); return 0; } jm_log_verbose( cb, "FMILIB", "Parsing model description XML"); if(fmi1_xml_parse_model_description( fmu->md, xmlPath)) { fmi1_import_free(fmu); cb->free(xmlPath); return 0; } cb->free(xmlPath); fmu->dirPath = (char*)cb->calloc(strlen(dirPath) + 1, sizeof(char)); if(jm_get_dir_abspath(cb, dirPath, absPath, FILENAME_MAX + 2)) { fmu->location = fmi_import_create_URL_from_abs_path(cb, absPath); } if ((fmu->dirPath == NULL) || (fmu->location == 0)){ jm_log_fatal( cb, "FMILIB", "Could not allocated memory"); fmi1_import_free(fmu); cb->free(xmlPath); return 0; } strcpy(fmu->dirPath, dirPath); jm_log_verbose( cb, "FMILIB", "Parsing finished successfully"); return fmu; }
char* fmi_construct_dll_dir_name(jm_callbacks* callbacks, const char* fmu_unzipped_path) { char* dir_path; size_t len; assert( fmu_unzipped_path && callbacks); len = strlen(fmu_unzipped_path) + strlen(FMI_FILE_SEP) + strlen(FMI_BINARIES) + strlen(FMI_FILE_SEP) + strlen(FMI_PLATFORM) + strlen(FMI_FILE_SEP) + 1; dir_path = (char*)callbacks->malloc(len); if (dir_path == NULL) { jm_log_fatal(callbacks, "FMIUT", "Failed to allocate memory."); return NULL; } sprintf(dir_path, "%s%s%s%s%s%s", fmu_unzipped_path, FMI_FILE_SEP, FMI_BINARIES, FMI_FILE_SEP, FMI_PLATFORM, FMI_FILE_SEP);/*safe */ return dir_path; }
fmi1_xml_model_description_t * fmi1_xml_allocate_model_description( jm_callbacks* callbacks) { jm_callbacks* cb; fmi1_xml_model_description_t* md; if(callbacks) { cb = callbacks; } else { cb = jm_get_default_callbacks(); } md = (fmi1_xml_model_description_t*)cb->malloc(sizeof(fmi1_xml_model_description_t)); if(!md) { jm_log_fatal(cb, module, "Could not allocate memory"); return 0; } md->callbacks = cb; md->status = fmi1_xml_model_description_enu_empty; jm_vector_init(char)( & md->fmi1_xml_standard_version, 0,cb); jm_vector_init(char)(&md->modelName, 0,cb); jm_vector_init(char)(&md->modelIdentifier, 0,cb); jm_vector_init(char)(&md->GUID, 0,cb); jm_vector_init(char)(&md->description, 0,cb); jm_vector_init(char)(&md->author, 0,cb); jm_vector_init(char)(&md->version, 0,cb); jm_vector_init(char)(&md->generationTool, 0,cb); jm_vector_init(char)(&md->generationDateAndTime, 0,cb); md->namingConvension = fmi1_naming_enu_flat; md->numberOfContinuousStates = 0; md->numberOfEventIndicators = 0; md->defaultExperimentStartTime = 0; md->defaultExperimentStopTime = 1.0; md->defaultExperimentTolerance = FMI1_DEFAULT_EXPERIMENT_TOLERANCE; jm_vector_init(jm_voidp)(&md->vendorList, 0, cb); jm_vector_init(jm_named_ptr)(&md->unitDefinitions, 0, cb); jm_vector_init(jm_named_ptr)(&md->displayUnitDefinitions, 0, cb); fmi1_xml_init_type_definitions(&md->typeDefinitions, cb); jm_vector_init(jm_named_ptr)(&md->variablesByName, 0, cb); md->variablesOrigOrder = 0; md->variablesByVR = 0; md->inputVariables = 0; md->outputVariables = 0; jm_vector_init(jm_string)(&md->descriptions, 0, cb); md->fmuKind = fmi1_fmu_kind_enu_me; fmi1_xml_init_capabilities(&md->capabilities); jm_vector_init(jm_string)(&md->additionalModels, 0, cb); jm_vector_init(char)(&md->entryPoint, 0,cb); jm_vector_init(char)(&md->mimeType, 0,cb); return md; }
jm_status_enu_t fmi1_cs_simulate(fmu_check_data_t* cdata) { fmi1_status_t fmistatus; jm_status_enu_t jmstatus = jm_status_success; jm_callbacks* cb = &cdata->callbacks; fmi1_import_t* fmu = cdata->fmu1; fmi1_string_t fmuGUID = fmi1_import_get_GUID(fmu); fmi1_string_t mimeType; fmi1_real_t timeout = 0.0; fmi1_boolean_t visible = fmi1_false; fmi1_boolean_t interactive = fmi1_false; fmi1_real_t tstart = fmi1_import_get_default_experiment_start(fmu); fmi1_real_t tcur = tstart; fmi1_real_t hstep; fmi1_real_t tend = fmi1_import_get_default_experiment_stop(fmu); fmi1_boolean_t StopTimeDefined = fmi1_true; mimeType = fmi1_import_get_mime_type(fmu); if( (cdata->fmu1_kind == fmi1_fmu_kind_enu_cs_standalone) || !mimeType || !mimeType[0]) { mimeType = "application/x-fmu-sharedlibrary"; } else { if( strcmp(mimeType, "application/x-fmu-sharedlibrary") != 0 ) { jm_log_info(cb, fmu_checker_module,"The FMU requests simulator with MIME type '%s'.", mimeType); printf("\nPlease, start a simulator program for MIME type '%s'\nPress enter to continue.\n", mimeType); getchar(); } } if(cdata->stopTime > 0) { tend = cdata->stopTime; } if(cdata->stepSize > 0) { hstep = cdata->stepSize; } else { hstep = (tend - tstart) / cdata->numSteps; } cdata->instanceName = "Test FMI 1.0 CS"; jm_log_verbose(cb, fmu_checker_module, "Checker will instantiate the slave with \n" "\tFMU location ='%s'\n\tMIME type = '%s'", cdata->fmuLocation, mimeType); jmstatus = fmi1_import_instantiate_slave(fmu, cdata->instanceName, cdata->fmuLocation, mimeType, timeout, visible, interactive); if (jmstatus == jm_status_error) { jm_log_fatal(cb, fmu_checker_module, "Could not instantiate the model"); return jm_status_error; } fmistatus = fmi1_import_initialize_slave(fmu, tstart, StopTimeDefined, tend); if((fmistatus == fmi1_status_ok) || (fmistatus == fmi1_status_warning)) { jm_log_info(cb, fmu_checker_module, "Initialized FMU for simulation starting at time %g", tstart); fmistatus = fmi1_status_ok; } else { jm_log_fatal(cb, fmu_checker_module, "Failed to initialize FMU for simulation (FMU status: %s)", fmi1_status_to_string(fmistatus)); jmstatus = jm_status_error; } if(jmstatus != jm_status_error) { jm_log_verbose(cb, fmu_checker_module, "Writing simulation output for start time"); if(fmi1_write_csv_data(cdata, tstart) != jm_status_success){ jmstatus = jm_status_error; } } while ((tcur < tend) && (jmstatus != jm_status_error)) { fmi1_boolean_t newStep = fmi1_true; fmi1_real_t tnext = tcur + hstep; if(tnext > tend - 1e-3*hstep) { /* last step should be on tend */ hstep = tend - tcur; tnext = tend; } jm_log_verbose(cb, fmu_checker_module, "Simulation step from time: %g until: %g", tcur, tnext); fmistatus = fmi1_import_do_step(fmu, tcur, hstep, newStep); tcur = tnext; if(fmi1_write_csv_data(cdata, tcur) != jm_status_success){ jmstatus = jm_status_error; } if((fmistatus == fmi1_status_ok) || (fmistatus == fmi1_status_warning)) { fmistatus = fmi1_status_ok; } else jmstatus = jm_status_error; } if((fmistatus != fmi1_status_ok) && (fmistatus != fmi1_status_warning)) { jm_log_fatal(cb, fmu_checker_module, "Simulation loop terminated at time %g since FMU returned status: %s", tcur, fmi1_status_to_string(fmistatus)); jmstatus = jm_status_error; } else if(jmstatus != jm_status_error) { jm_log_info(cb, fmu_checker_module, "Simulation finished successfully at time %g", tcur); } fmistatus = fmi1_import_terminate_slave(fmu); if( fmistatus != fmi1_status_ok) { jm_log_error(cb, fmu_checker_module, "fmiTerminateSlave returned status: %s", fmi1_status_to_string(fmistatus)); } fmi1_import_free_slave_instance(fmu); return jmstatus; }
/* Load and destroy functions */ jm_status_enu_t fmi2_import_create_dllfmu(fmi2_import_t* fmu, fmi2_fmu_kind_enu_t fmuKind, const fmi2_callback_functions_t* callBackFunctions) { char curDir[FILENAME_MAX + 2]; char* dllDirPath = 0; char* dllFileName = 0; const char* modelIdentifier; fmi2_callback_functions_t defaultCallbacks; if (fmu == NULL) { assert(0); return jm_status_error; } if(fmu -> capi) { if(fmi2_capi_get_fmu_kind(fmu -> capi) == fmuKind) { jm_log_warning(fmu->callbacks, module, "FMU binary is already loaded"); return jm_status_success; } else fmi2_import_destroy_dllfmu(fmu); } if(fmuKind == fmi2_fmu_kind_me) modelIdentifier = fmi2_import_get_model_identifier_ME(fmu); else if(fmuKind == fmi2_fmu_kind_cs) modelIdentifier = fmi2_import_get_model_identifier_CS(fmu); else { assert(0); return jm_status_error; } if (modelIdentifier == NULL) { jm_log_error(fmu->callbacks, module, "No model identifier given"); return jm_status_error; } if( jm_portability_get_current_working_directory(curDir, FILENAME_MAX+1) != jm_status_success) { jm_log_warning(fmu->callbacks, module, "Could not get current working directory (%s)", strerror(errno)); curDir[0] = 0; }; dllDirPath = fmi_construct_dll_dir_name(fmu->callbacks, fmu->dirPath); dllFileName = fmi_construct_dll_file_name(fmu->callbacks, dllDirPath, modelIdentifier); if (!dllDirPath ||!dllFileName) { fmu->callbacks->free(dllDirPath); return jm_status_error; } if(!callBackFunctions) { jm_callbacks* cb = fmu->callbacks; defaultCallbacks.allocateMemory = cb->calloc; defaultCallbacks.freeMemory = cb->free; defaultCallbacks.componentEnvironment = fmu; defaultCallbacks.logger = fmi2_log_forwarding; defaultCallbacks.stepFinished = 0; callBackFunctions = &defaultCallbacks; } if(jm_portability_set_current_working_directory(dllDirPath) != jm_status_success) { jm_log_fatal(fmu->callbacks, module, "Could not change to the DLL directory %s", dllDirPath); if(ENOENT == errno) jm_log_fatal(fmu->callbacks, module, "No binary for this platform?"); else jm_log_fatal(fmu->callbacks, module, "System error: %s", strerror(errno)); } else { /* Allocate memory for the C-API struct */ fmu -> capi = fmi2_capi_create_dllfmu(fmu->callbacks, dllFileName, modelIdentifier, callBackFunctions, fmuKind); } /* Load the DLL handle */ if (fmu -> capi) { jm_log_info(fmu->callbacks, module, "Loading '" FMI_PLATFORM "' binary with '%s' platform types", fmi2_get_types_platform() ); if(fmi2_capi_load_dll(fmu -> capi) == jm_status_error) { fmi2_capi_destroy_dllfmu(fmu -> capi); fmu -> capi = NULL; } } if(curDir[0] && (jm_portability_set_current_working_directory(curDir) != jm_status_success)) { jm_log_error(fmu->callbacks, module, "Could not restore current working directory (%s)", strerror(errno)); } fmu->callbacks->free((jm_voidp)dllDirPath); fmu->callbacks->free((jm_voidp)dllFileName); if (fmu -> capi == NULL) { return jm_status_error; } /* Load the DLL functions */ if (fmi2_capi_load_fcn(fmu -> capi, fmi2_xml_get_capabilities(fmu->md)) == jm_status_error) { fmi2_capi_free_dll(fmu -> capi); fmi2_capi_destroy_dllfmu(fmu -> capi); fmu -> capi = NULL; return jm_status_error; } jm_log_verbose(fmu->callbacks, module, "Successfully loaded all the interface functions"); return jm_status_success; }