The compile options that are typically required are
For example the command-line options used by the climate module is
compiler: /Od /I "../core" /I "../test/cppunit2/include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_CRT_SECURE_NO_DEPRECATE" /D "_WINDLL" /D "_MBCS" /Gm /EHsc /RTC1 /MDd /Fo"Win32\Debug\climate\" /Fd"Win32\Debug\climate\vc80.pdb" /W3 /nologo /c /Wp64 /ZI /TP /errorReport:prompt linker: /OUT:"Win32\Debug\climate.dll" /INCREMENTAL /NOLOGO /LIBPATH:"..\test\cppunit2\lib" /DLL /MANIFEST /MANIFESTFILE:"Win32\Debug\climate\climate.dll.intermediate.manifest" /DEBUG /PDB:"c:\projects\GridlabD\source\VS2005\Win32\Debug\climate.pdb" /SUBSYSTEM:WINDOWS /MACHINE:X86 /ERRORREPORT:PROMPT cppunitd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
The main.cpp file contains the code to load and unload both Windows DLL and Linux shared-object libraries:
// the version can be used to make sure the right module is loaded #define MAJOR 0 // TODO: set the major version of your module here #define MINOR 0 // TODO: set the minor version of your module here #define DLMAIN #include <stdlib.h> #include "gridlabd.h" EXPORT int do_kill(void*); EXPORT int major=MAJOR, minor=MINOR; #ifdef WIN32 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include <windows.h> BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: do_kill(hModule); break; } return TRUE; } #else // !WIN32 CDECL int dllinit() __attribute__((constructor)); CDECL int dllkill() __attribute__((destructor)); CDECL int dllinit() { return 0;} CDECL int dllkill() { do_kill(NULL);} #endif // !WIN32
The init.cpp file contains the code needed to initialize a module after it is loaded:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include "gridlabd.h" #include "myclass.h" EXPORT CLASS *init(CALLBACKS *fntable, MODULE *module, int argc, char *argv[]) { // set the GridLAB core API callback table callback = fntable; // TODO: register each object class by creating its first instance new myclass(module); // always return the first class registered return myclass::oclass; } CDECL int do_kill() { // if anything needs to be deleted or freed, this is a good time to do it return 0; }
You can also implement
to allow the core to request a check of the objects that are implemented by the module. This is particularly useful to perform topology checks for network models.If you implement the
EXPORT int import_file(char *file)
import command in the model definition.If you implement the
EXPORT int save(char *file)
.glm or .xml.The
EXPORT int setvar(char *varname, char *value)
EXPORT void* getvar(char *varname, char *value, unsigned int size)
network/varmap.c for an example.The
EXPORT int module_test(TEST_CALLBACKS *callbacks,int argc, char* argv[])
The
function is used to load modules written in foreign languages. Look at the gldjava project for examples of how this is used. This function needs to manually set the function pointers for any classes registered by subload-ed modules. A module subload is triggered with "module X::Y".The implementation of each class will require two files for each object class be included in your module's source code. The header file will usually include the following:
#ifndef _MYCLASS_H #define _MYCLASS_H #include "gridlabd.h" class myclass { public: // TODO: add your published variables here using GridLAB types (see PROPERTY) double myDouble; // just an example private: // TODO: add any unpublished variables here (any type is ok) double *pDouble; // just an example public: static CLASS *oclass; static myclass *defaults; public: myclass(MODULE *module); int create(void); int init(OBJECT *parent); TIMESTAMP sync(TIMESTAMP t0, TIMESTAMP t1); }; #endif
The implementation file should include the following:
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include "myclass.h" CLASS *myclass::oclass = NULL; myclass *myclass::defaults = NULL; myclass::myclass(MODULE *module) { if (oclass==NULL) { oclass = gl_register_class(module,"myclass",PC_BOTTOMUP); if (gl_publish_variable(oclass, // TODO: publish your variables here PT_double, "my_double", PADDR(myDouble), // just an example NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__); defaults = this; // TODO: initialize the default values that apply to all objects of this class myDouble = 1.23; // just an example pDouble = NULL; // just an example } } void myclass::create(void) { memcpy(this,defaults,sizeof(*this)); // TODO: initialize the defaults values that do not depend on relatioships with other objects } int myclass::init(OBJECT *parent) { // find the data in the parent object myclass *pMyClass = OBJECTDATA(parent,myclass); // just an example // TODO: initialize the default values that depend on relationships with other objects pDouble = &(pMyClass->double); // just an example // return 1 on success, 0 on failure return 1; } TIMESTAMP myclass::sync(TIMESTAMP t0, TIMESTAMP t1) { // TODO: update the state of the object myDouble = myDouble*1.01; // just an example // TODO: compute time to next state change return (TIMESTAMP)(t1 + myDouble/TS_SECOND); // just an example } // IMPLEMENTATION OF CORE LINKAGE EXPORT int create_myclass(OBJECT **obj, OBJECT *parent) { *obj = gl_create_object(myclass::oclass,sizeof(myclass)); if (*obj!=NULL) { myclass *my = OBJECTDATA(*obj,myclass); gl_set_parent(*obj,parent); my->create(); return 1; } return 0; } EXPORT int init_myclass(OBJECT *obj, OBJECT *parent) { if (obj!=NULL) { myclass *my = OBJECTDATA(obj,myclass); return my->init(parent); } return 0; } EXPORT TIMESTAMP sync_myclass(OBJECT *obj, TIMESTAMP t1) { TIMESTAMP t2 = OBJECTDATA(obj,myclass)->sync(obj->clock,t1); obj->clock = t1; return t2; }
There are a number of useful extended capabilities that can be added. These include
int notify_myclass(OBJECT *obj, NOTIFYMODULE msg)
int isa_myclass(OBJECT *obj, char *classname)
can be implemented to create default PLC code that can be overridden by attaching a child plc object.
can be implemented to create a recalculation triggered based on changes to properties made through object_set_value_by_addr() and related functions. A property can be made to trigger recalculation calls by adding PT_FLAGS, PF_RECALC after the property publish specification, e.g.,
(gl_publish_variable(oclass, PT_double, "resistance[ohm]", PADDR(resistance), PT_FLAGS, PF_RECALC, NULL);
A Linux GridLAB module must be a shared object library.
Defines | |
| #define | _STR(x) #x |
| #define | DLLOAD(P) dlopen(P,RTLD_LAZY) |
| #define | DLSYM(H, S) dlsym(H,S) |
| #define | LIBEXT .so |
| #define | LIBPREFIX "lib" |
| #define | STR(x) _STR(x) |
Typedefs | |
| typedef MODULE *(*) | LOADER (const char *, int, char *[]) |
| Load a runtime module. | |
Functions | |
| void | dlload_error (const char *filename) |
| int | get_exe_path (char *buf, int len, void *mod) |
| int | module_check (MODULE *mod) |
| int | module_checkall (void) |
| int | module_cmdargs (int argc, char **argv) |
| int | module_dumpall (void) |
| MODULE * | module_find (char *modname) |
| int | module_get_exe_path (char *buf, int len) |
| MODULE * | module_get_first (void) |
| int | module_get_path (char *buf, int len, MODULE *mod) |
| void * | module_getvar (MODULE *mod, char *varname, char *value, unsigned int size) |
| double * | module_getvar_addr (MODULE *mod, char *varname) |
| int | module_import (MODULE *mod, char *filename) |
| void | module_libinfo (char *module_name) |
| MODULE * | module_load (const char *file, int argc, char *argv[]) |
| int | module_save (MODULE *mod, char *filename) |
| int | module_saveall (FILE *fp) |
| int | module_saveall_xml (FILE *fp) |
| int | module_saveall_xml_old (FILE *fp) |
| int | module_saveobj_xml (FILE *fp, MODULE *mod) |
| int | module_setvar (MODULE *mod, char *varname, char *value) |
Variables | |
| MODULE * | first_module = NULL |
| MODULE * | last_module = NULL |
| int64 | lock_count |
| int64 | lock_spin |
| MODULE* module_load | ( | const char * | file, | |
| int | argc, | |||
| char * | argv[] | |||
| ) |
| file |
module filename, searches PATH |
| argc |
count of arguments in argv |
| argv | arguments passed from the command line |
Definition at line 556 of file module.c.
References class_get_first_class(), class_get_last_class(), init(), last_module, load_java_module(), load_python_module(), module_find(), module_load(), s_class_list::next, s_module_list::next, s_module_list::oclass, output_error(), output_verbose(), and s_module_list::subload.
Referenced by cmex_module(), module_libinfo(), module_load(), and output_xsd().
| int module_saveobj_xml | ( | FILE * | fp, | |
| MODULE * | mod | |||
| ) |
< the stream to write to
Definition at line 860 of file module.c.
References s_class_list::module, s_object_list::name, s_object_list::next, object_get_first(), and s_object_list::oclass.
Referenced by module_saveall_xml().