// Copyright SIMetrix Technologies Ltd. 2004, All rights reserved. // Module UserFunctionInterface.h // created 17.05.04 // Library: // Notes: // This header file forms part of the User Function Interface SDK // You should not edit any part of this header file // // Please see the example files to see how to use the macros and // structures in this header filr // // A note to Linux users. For convenience we refer to your "DLL". This // of course is the Windows equivalent of a shared library // This must be compiled as C++. This is because it uses some of the // "convenience" features of C++ (e.g. anonymous unions) // not because it is object oriented. The basic programming techniques // used in the interface should be familiar to any 'C' programmer // 14.9.05 - Added DEFINE_DIALOG_2. Doesn't affect interface - no need to change version #ifndef UserFunctionInterface_H #define UserFunctionInterface_H #include #ifndef __cplusplus #error The UserFunctionInterface.h header must be compiled as C++ #endif //---------- Macro definitions ---------// #define MAX_NUM_SCRIPT_FUNC_ARGS 32 #define DFI_VERSION_NUMBER 2 // ***************************************************************** // ** ** // ** REGISTER_INTERFACE macros ** // ** ** // ***************************************************************** // There must be one and one only of either REGISTER_INTERFACE_STATIC // or REGISTER_INTERFACE_DYNAMIC in your dll code. Use REGISTER_INTERFACE_STATIC for release code // and REGISTER_INTERFACE_DYNAMIC during debugging #define REGISTER_INTERFACE(a) UserFunctionDeclaration *UserFunctionDeclaration::head ;\ static UserFunctionCallbacks global_Callbacks;\ extern "C" EXPORT void udf_GetFunctionDecls(\ UserFunctionDeclaration **funcDeclList, \ bool *dynamic,\ UserFunctionConfig *configInfo)\ {\ *dynamic = a ;\ configInfo->sizeOfFunctionDeclaration = sizeof(UserFunctionDeclaration) ;\ configInfo->sizeOfUserFunctionInterface = sizeof(UserFunctionInterface) ;\ configInfo->versionNumber = DFI_VERSION_NUMBER ;\ *funcDeclList = UserFunctionDeclaration::head ;\ }\ extern "C" EXPORT void udf_AssignCallbacks(UserFunctionCallbacks *callbackFunctions)\ {\ global_Callbacks = *callbackFunctions ;\ } #define REGISTER_INTERFACE_STATIC REGISTER_INTERFACE(false) #define REGISTER_INTERFACE_DYNAMIC REGISTER_INTERFACE(true) // ***************************************************************** // ** ** // ** Function definition macros ** // ** ** // ***************************************************************** // // Use this to define a general purpose function. See examples for // details on how to use it #define DEFINE_USER_FUNCTION(a,types,min) \ static void func2##a(UserFunctionInterface *iface, const char *funcName) ;\ static QObject *func##a(UserFunctionInterface *iface, const char *funcName) \ {\ func2##a(iface, funcName) ;\ return NULL ;\ } \ static UserFunctionArgType type##a[] = types ;\ static UserFunctionDeclaration funcdecl##a(#a, type##a, min, sizeof(type##a)/sizeof(*type##a), func##a);\ static void func2##a(UserFunctionInterface *iface, const char *funcName) #define DEFINE_USER_FUNCTION_ALIAS(aliasName, aliasTo) \ static UserFunctionDeclaration funcdecl##aliasName(#aliasName, type##aliasTo, funcdecl##aliasTo.minArgs, sizeof(type##aliasTo)/sizeof(*type##aliasTo), func##aliasTo) #define DEFINE_USER_FUNCTION_MD(a,types,mddefs,min) \ static void func2##a(UserFunctionInterface *iface, const char *funcName) ;\ static QObject *func##a(UserFunctionInterface *iface, const char *funcName) \ {\ func2##a(iface, funcName) ;\ return NULL ;\ } \ static UserFunctionArgType type##a[] = types ;\ static UserMultiDivDef mdddefs##a[] = mddefs ; \ static UserFunctionDeclaration funcdecl##a(#a, type##a, min, sizeof(type##a)/sizeof(*type##a), mdddefs##a, sizeof(mdddefs##a)/sizeof(*mdddefs##a), func##a);\ static void func2##a(UserFunctionInterface *iface, const char *funcName) // Use this to define a SIMetrix dialog box designed using the dialog editor // You will need to have a commercial Qt license to use this. #define DEFINE_DIALOG(name) \ typedef UserDialogClass name ; \ static QObject *func##name(UserFunctionInterface *iface, const char *funcName) ;\ static UserFunctionDeclaration funcdecl##name(#name, func##name);\ static QObject *func##name(UserFunctionInterface *iface, const char *funcName) \ { \ return new name(NULL, #name) ; \ } // As DEFINE_DIALOG but defines a function body allow initialisation // of object. Unlike DEFINE_DIALOG does not declare class itself. Either // use DECLARE_DIALOG_CLASS or do manually. #define DEFINE_DIALOG_2(name) \ static QObject *func##name(UserFunctionInterface *iface, const char *funcName) ;\ static UserFunctionDeclaration funcdecl##name(#name, func##name, UserDialogOptions());\ static void func2##name(UserFunctionInterface *iface, const char *funcName, name *dlg) ;\ static QObject *func##name(UserFunctionInterface *iface, const char *funcName) \ { \ name *dlg = new name(NULL, #name) ; \ func2##name(iface, funcName, dlg) ;\ return dlg ;\ } \ static void func2##name(UserFunctionInterface *iface, const char *funcName, name *dlg) #define DECLARE_DIALOG_CLASS(name) typedef UserDialogClass name #if defined(unix) #define EXPORT #elif defined(_WIN32) #define EXPORT __declspec(dllexport) #endif //--------------------------------------// //---------- Type definitions ----------// class complex ; struct UserFunctionInterface ; class QObject ; typedef QObject *(*UserFunctionInterfaceProc)(UserFunctionInterface *, const char *name) ; // Template for basic user dialog box used by DEFINE_DIALOG template class UserDialogClass : public T { public: UI_Def ui ; UserDialogClass(class QWidget *parent, const char *name) { setObjectName(name) ; ui.setupUi(this) ; } } ; enum UserDataType { UDT_Real, UDT_Complex, UDT_String, UDT_None, // Some compilers allow variable length enums. This forces // them to be 4 bytes UDT_Force4Byte = 100000L } ; // Used to define argument types enum UserFunctionArgType { // May be real or complex DAT_Num=0, // String only DAT_Str=1, // May be any type DAT_Both=2, // Not used DAT_X=3, // May be real only DAT_Real=4, DAT_Force4Byte = 100000L } ; // For functions defined using DEFINE_USER_FUNCTION_MD // Defines how multi-division data is handled for each argument. enum UserMultiDivDef { // Multi-division data not permitted for this argument MDD_None, // Function will be called multiple times - once for each division // If more than one arg has this definition then they must all receive // multi-division data with the same number of divisions MDD_Loop, // Function called once with multi-division data passed through as is MDD_NoLoop } ; enum ScriptFunctionError { SFE_Ok, // Function executed normally SFE_TooFewArgs, // Not enough arguments SFE_TooManyArgs, // Too many arguments SFE_BadArgType, // Argument types incorrect SFE_FuncNotExist, // There is no function of that name SFE_FuncFailed, // Function failed to execute SFE_MemoryException,// Out of memory exception SFE_OsException, // OS exception - access violation or floating point error SFE_OtherException, // Some other exception SFE_Unexpected // Bug in SIMetrix } ; #ifdef DEFINE_COMPLEX_TYPE class complex { public: double re, im ; } ; #endif struct UserDialogOptions { bool modal ; bool noSaveDims ; int qtflags ; UserDialogOptions(bool m=false, int qf=0) { modal=m ; qtflags=qf ; noSaveDims=false ;} } ; // Data passed for a single argument struct UserFunctionArgumentData { // y-values. Test dataType to see which union field // to use union { const double *realData ; const char * const *stringData ; const complex *complexData ; const void * const *genData ; } ; // x-values aka reference. Test refDataType to see which // union field to use union { const double *realRefData ; const complex *complexRefData ; } ; // Number of elements in the argument unsigned long length ; // see above UserDataType dataType, refDataType ; // Physical type - i.e. voltage, current etc. This will be one // of the values listed in the first column of the table found in // the description of the SetUnits function in the Script Reference // manual. You can also set the physical type of the return value // as long as it is real or complex. See makeReal etc below. const char *physType, *refPhysType ; // ******************* PLACE HOLDER FOR FUTURE EXPANSION******************* // int placeHolder[4] ; // // ************************************************************************ } ; // A pointer to one of these is passed to the function and provides the // complete interface struct UserFunctionInterface { // ******************* INTERNAL DO NOT USE ******************************** // A pointer needed by the interface. You do not need to // use this directly. Do not write to this value void *iface ; // // ************************************************************************ // ******************* ARGUMENT DATA ************************************** // // Argument data. Currently may be a maximum of 8 UserFunctionArgumentData data[MAX_NUM_SCRIPT_FUNC_ARGS] ; // Number of arguments actually passed by the user int numArgs ; // // ************************************************************************ // ******************* RETURN VALUES ************************************** // // You must call one and one only of the functions makeString, makeReal or // makeComplex to return a result. You must only call one of them and you // must call it ONLY ONCE. In some circumstances you might want to // return an empty vector in which case none of the functions should // be called. Typical situations where you would want to return empty are: // // 1. The function opens a dialog box which the user cancels // 2. The user passed invalid data to the function // Call this function if you want to return a string result // Function returns an array of string pointers. You MUST assign the // elements of the array using dupString. See below char ** (*makeString)(UserFunctionInterface *ptrToThisObject, unsigned long numElems) ; // Call this function if you want to return a real result // Function returns an array of doubles which may be assigned directly. // physType arg specifies physical type. See above description for // UserFunctionArgumentData::physType. physType may be NULL in which case // the physical type of the result will be "unknown". double * (*makeReal)(UserFunctionInterface *ptrToThisObject, unsigned long numElems, const char *physType) ; // Call this function if you want to return a complex result // Otherwise as makeReal. Note that you will need to define // DEFINE_COMPLEX_TYPE to use complex data, or, define your own complex // type that is data compatible. complex * (*makeComplex)(UserFunctionInterface *ptrToThisObject, unsigned long numElems, const char *physType) ; // Call if you want the return value to have a reference (x-values). // This function can only be meaningfully used if you also call either // makeReal or makeComplex. Note that this must be the same size as the // y-value data assigned with makeReal or makeComplex. double * (*makeRealRef)(UserFunctionInterface *ptrToThisObject, unsigned long numElems, const char *physType) ; // Use this to create string elements. DO NOT use strdup, malloc or new or // any other allocator char * (*dupString)(const char *) ; // ******************* CALLING SCRIPT FUNCTIONS *************************** // You can call any function in the script language directly from your user function. // You must pass arguments according to the specification given in the script manual using the "args" argument. // Note that implicit type conversion will not be performed if the argument type is incorrect and the function // will fail to execute in this situation. // The functions below support script function calls. // Use this function to call a regular SIMetrix script function. Function returns true if successful. // On failure, returns false and sets errCode with reason for failure. See definition ofScriptFunctionError // for errCode values. // You should always check the return value to detect failure and not solely rely on the value of errCode. bool (*callScriptFunction)( UserFunctionInterface *ptrToThisObject, const char *funcName, // Name of function to call UserFunctionArgumentData *args, // Arguments to function. This must comply with the // functions required argument. See Script Ref Manual for details int numArgs, // Number of arguments UserFunctionArgumentData *returnValue, // Data returned by function ScriptFunctionError *errCode) ; // Error code // Use this function to allocate data for use as real arguments to callScriptFunction - that is // for data[argidx].realData and data[argidx].realRefData. // You don't have to use this function to allocate these values; you can pass data // from any source. However if you do need to allocate memory to fill the argument data, using // this function has two benefits compared with using, for example, malloc or new: // a) You do not need to worry about de-allocating - this will be taken care of automatically // b) Its more memory efficient. If you use malloc or new, SIMetrix will need to make a copy // of the data it uses as it must have ownership of the data. double * (*allocateRealArg)(UserFunctionInterface *ptrToThisObject, int numElems) ; // As above but for complex data complex * (*allocateComplexArg)(UserFunctionInterface *ptrToThisObject, int numElems) ; // There are currently no equivalent functions for string data. Use regular allocation functions. // // ************************************************************************ // Size of object in bytes int numBytes ; // ******************* PLACE HOLDER FOR FUTURE EXPANSION******************* // int placeHolder[15] ; // // ************************************************************************ } ; // The remainder of this file defines structures used by the function // definition macros. Unless you wish to develop your own interfacing methods // there is no need to understand what these do. enum UserFunctionType { UFT_Simple, UFT_Dialog, UFT_Force4Byte = 100000L } ; struct UserFunctionDeclaration ; struct UserFunctionDeclarationBase { char name[64] ; UserFunctionArgType type[MAX_NUM_SCRIPT_FUNC_ARGS] ; UserMultiDivDef mddefs[MAX_NUM_SCRIPT_FUNC_ARGS] ; short minArgs ; short maxArgs ; UserFunctionInterfaceProc udtFunc ; // ******************* PLACE HOLDER FOR FUTURE EXPANSION******************* // int placeHolder[2] ; // // ************************************************************************ UserFunctionType functionType ; UserFunctionDeclaration *next ; void init(const char *n, UserFunctionInterfaceProc u, UserFunctionType ft, int mn, int mx) ; } ; struct UserFunctionDeclaration : public UserFunctionDeclarationBase { static UserFunctionDeclaration *head ; UserDialogOptions userDialogOptions ; UserFunctionDeclaration(const char *n, UserFunctionArgType *t, int nm, int mx, UserFunctionInterfaceProc u, UserFunctionType ft=UFT_Simple) ; UserFunctionDeclaration(const char *n, UserFunctionInterfaceProc u, UserFunctionType ft=UFT_Dialog) ; UserFunctionDeclaration(const char *n, UserFunctionInterfaceProc u, UserDialogOptions o) ; UserFunctionDeclaration(const char *n, UserFunctionArgType *t, int nm, int mx, UserMultiDivDef *mdefs, int nummdefs, UserFunctionInterfaceProc u, UserFunctionType ft=UFT_Simple) ; } ; struct UserFunctionConfig { int sizeOfUserFunctionInterface, // set to sizeof(UserFunctionInterface) sizeOfFunctionDeclaration, // set to sizeof(UserFunctionDeclaration) versionNumber ; // set to DFI_VERSION_NUMBER } ; // call back functions. These were not introduced until version 5.2 // Test function pointers before using typedef void (*PlaceHolderFuncPointer)() ; struct UserFunctionCallbacks { void (*openHelp)(const char *mode, const char *value, const char *unused) ; bool (*haveHelp)() ; // returns true if caller has a help system. (Its currently false on Linux) PlaceHolderFuncPointer placeHolder[30] ; } ; //--------------------------------------// //---------- Extern data ---------------// //--------------------------------------// //--------- Extern functions -----------// //--------------------------------------// //--------- Inline functions -----------// inline void UserFunctionDeclarationBase::init(const char *n, UserFunctionInterfaceProc u, UserFunctionType ft, int mn, int mx) { strncpy_s(name, sizeof(name), n, sizeof(name)-1) ; if (mx>(int)(sizeof(type)/sizeof(*type))) mx = sizeof(type)/sizeof(*type) ; else if (mx<0) mx = 0 ; int idx = mx ; minArgs = mn ; maxArgs = mx ; udtFunc = u ; functionType = ft ; idx = sizeof(mddefs)/sizeof(*mddefs) ; while(idx--) mddefs[idx] = MDD_None ; } inline UserFunctionDeclaration::UserFunctionDeclaration(const char *n, UserFunctionArgType *t, int mn, int mx, UserFunctionInterfaceProc u, UserFunctionType ft) : UserFunctionDeclarationBase() { init(n,u,ft,mn,mx) ; int idx = maxArgs ; while(idx--) type[idx] = t[idx] ; next = head ; head = this ; } inline UserFunctionDeclaration::UserFunctionDeclaration(const char *n, UserFunctionInterfaceProc u, UserFunctionType ft) : UserFunctionDeclarationBase() { init(n,u,ft,0,sizeof(type)/sizeof(*type)) ; int idx = maxArgs ; while(idx--) type[idx] = DAT_Str ; next = head ; head = this ; } inline UserFunctionDeclaration::UserFunctionDeclaration(const char *n, UserFunctionInterfaceProc u, UserDialogOptions o) : UserFunctionDeclarationBase() { init(n,u,UFT_Dialog,0,sizeof(type)/sizeof(*type)) ; int idx = maxArgs ; while(idx--) type[idx] = DAT_Str ; next = head ; head = this ; } inline UserFunctionDeclaration::UserFunctionDeclaration( const char *n, UserFunctionArgType *t, int mn, int mx, UserMultiDivDef *mdefs, int nummdefs, UserFunctionInterfaceProc u, UserFunctionType ft) : UserFunctionDeclarationBase() { init(n,u,ft,mn,mx) ; int idx = maxArgs ; while(idx--) type[idx] = t[idx] ; if (nummdefs>maxArgs) nummdefs = maxArgs ; idx = nummdefs ; while(idx--) mddefs[idx] = mdefs[idx] ; next = head ; head = this ; } //--------------------------------------// #endif