Troubles compiling a diagram with a DLL inside

Altair Forum User
Altair Forum User
Altair Employee
edited October 2020 in Community Q&A

Submitted by ctedie on Mon, 02/21/2011 - 22:07 


I have done a DLL with the DLLWizard in Visual C++ 2010. (It's a DLL which copy the In to the Out, it's for test) Then, I've call the DLL in Vissim with the userBlock.

Now I've these errors on the compilation :

undefined symbol | first referenced in file

_myFunc | Essai01.obj

_myFuncSE | Essai01.obj

_myFuncSS | Essai01.obj

error: unresolved symbols remain

error: errors encountered during linking; 'Essai01.out' not built

I think I have a problem with some declarations.

Could you help me, or provide me an example?

Thanks

Tagged:

Answers

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

     

    Submitted by Anders89 on Tue, 02/22/2011 - 00:41.

     

    You must include the .lib from your DLL in the batch file for compiling. The two files to edit are \vissim70\cg\vsmdll32.bat and \vissim70\cg\vsmcg32.bat
    Open both files in notepad, find the line 'set USERLIBS=' and add your libraries (or .objs) after the '='.
    Now when you compile out of VisSim for the PC Host target you will link in your hand coded DLL that runs in VisSim.

    OK, that advice above works for PC targets, but I see now that your error is 'Essai01.out not built'. That means you are targeting a TI embedded processor. The advice for this is similar but a bit different. You must find the bat file for your target in \vissim70\dsp\'cl.bat'. For F280x target it is 'F280xcl.bat', open this file in notepad and find the line 'set USER_OBJS=' and add the path to the .obj for your code compiled in CCS. Note that the SE and SS functions are generated if you do not supply codegen response strings in your block event function.
    VisSim will send several Code Gen event codes during code generation for include files, data structure declaration, in-line code generation, and output in reference. The code fragment below is from the event handler for the mean smooth filter block.

       case WM_VSM_GET_CODEGEN_ALLOC_STRING:    // Allocate data for this instance of our filter         pi = (MEAN_SMOOTH_INFO *)vissimRequest(VR_GET_BLOCK_PARAMS, blockHandle, 0);  // Get params from block handle             outSig = (SIGNAL *)vissimRequest(VR_GET_BLOCK_OUTPUT, blockHandle, 0);       dim1 = 1;       dim2 = pi->nAveWin; // static MATRIX_DECL(2) _vt13_data={0,2,1,0}; // static MATRIX * vt13=(MATRIX*)&_vt13_data;       sprintf(cgBuf, 'static MATRIX_DECL(%d) %s = {0,%d,%d,0};\n', dim1*dim2         , getMatDataResultName(blockHandle), dim1, dim2);       sprintf(cgBuf+strlen(cgBuf), 'static MATRIX * %s = (MATRIX*)&%s;\n', getMatResultName(blockHandle), getMatDataResultName(blockHandle));       sprintf(cgBuf+strlen(cgBuf), 'static CGDOUBLE %s;\n', getScalarResultName(blockHandle));     return cgBuf;    case WM_VSM_GET_CODEGEN_STRING:  // Generate code for the filter operation     pi = (MEAN_SMOOTH_INFO *)vissimRequest(VR_GET_BLOCK_PARAMS, blockHandle, 0);  // Get params from block handle     sprintf(cgBuf, '  matCircBuffer(%s,%%1);\n', getMatResultName(blockHandle));     sprintf(cgBuf+strlen(cgBuf), '  %s = vsum( %s )*%.15g;\n', getScalarResultName(blockHandle), getMatResultName(blockHandle), 1./pi->nAveWin);         return cgBuf;    case WM_VSM_GET_CODEGEN_PORT_STORAGE:  // Generate a reference to the output of our filter     return (LPSTR)getScalarResultName(blockHandle);   case WM_VSM_GET_CODEGEN_START_STRING:   case WM_VSM_GET_CODEGEN_END_STRING:     return ''; // Suppress SS and SE calls    case WM_VSM_CREATE:  // use port storage event to reference result     return (LPSTR)(VBF_USE_SIGNAL_DESCRIPTORS|VBF_CG_BLK_HAS_NO_RETURN_VALUE);
  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by ctedie on Tue, 02/22/2011 - 20:46.

    Thank you for your advices, it help me for the SE and SS fuctions. But it didn't work for myFunc.

    I've also tried the sinTest block in \vissim/DSP\Example\F280x and it gave me the same error :

    Undefined Symbol | first referenced in file

    _DSP_Comm | sinTest.obj

    _DSP_CommSE | sinTest.obj

    _DSP_CommSS | sinTest.obj

    sinTest.out not built

    If the example supplied by the software doesn't work, I think I've a big problem.

    Have you some idea?

    Also, you said that I've to add the path of my .obj compiled with CCS. But I compile with Vissim Codgen. Do I need to compile with CCS4? (The Vissim/Code Composer Studio plugin doesn't appear in my CCS4)

    Thanks

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by Anders89 on Tue, 02/22/2011 - 23:15.

    This diagram contains a fixed point sin inside the compound named 'sin'. It also contains a DSP/targetInterface block that will communicate to the target MCU. You must select the 'sin' compound, choose Tools > Codegen..., check 'Include VisSim Communication Interface' and then compile. Then when you run the diagram, the dsp/targetInterface block will download the sin.out file you built and read the sin values in realtime over the JTAG with results showing on the plot.
    If you compile the whole diagram, then VisSim will generate code for the targetInterface block, and you get undefined Symbol for DSP_Comm, since it is meant only for PC to target communication, not target to itself.
    Yes, in order for your hand coded C functions to run on the TI MCU, you must compile them with the TI CCS compiler. We do not have a CCS v4 plugin yet, so you must follow TI direction to create a CCS v4 project. It is not so hard.

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by ctedie on Thu, 02/24/2011 - 00:53.

    Thank you again for your advices. I'll try that.

    But there is one thing I don't understand. This thing is how can I : - Create a personal block ( a DLL in Visual C++ 2010) - Add it in a diagram in Vissim ( a diagram using the the block ) - Compile and transfer the diagram in a F280X target ( for a use with or without vissim )

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by ctedie on Tue, 03/15/2011 - 21:10.

    Hi,

    Since my last post, i've tried many things to get my DLL ready to generate C code, but but without success.
    So I'll describe the procedure I've done:

    1. I've created a project with the DLLWizard in visual C++ 2010
    2. I've made the 'myFunc' function that it will copy the input to the output (outSig[0]=inSig[0])
    3. I've suppress SE and SS function call in the 'myFuncEvent' function
    4. I've built the DLL in visual C++
    5. I've created a diagram named test.vsm in which I call the DLL by binding it with the 'userFunction' block
    6. The DLL work properly in sumulation mode
    7. I try to target the F28345, so i run codegen

    At the compilation it's said that _myFunc is not referenced in test.obj

    Which is the .obj I have to add in the 'Userobj' line in F280Xcl.bat to reference the DLL?
    And what is the link with CCS4?

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by Anders89 on Wed, 03/16/2011 - 09:47.

    Ctedie, There are 3 concepts you need to understand.
    1) The TI C2000 processor uses a different binary pattern for its instruction set, so your C code needs to be compiled with the TI C Compiler (CCS v3 or 4) to run on the TI part and with the Microsoft compiler to run on the PC.

    2) In order to resolve the call to myFunc() that you emit in the VisSim codegen, you must compile the function with CCS, which will produce a .obj file (myFunc.obj). Then you must put myFunc.obj in the file \vissim70\dsp\f280xcl.bat. The first line of f280xcl.bat reads:
    set USER_OBJS=
    You must change it to read
    set USER_OBJS=myFunc.obj

    3) The myFunc() call you made is for simulation on the PC. It uses the inSig and outSig vectors to communicate with VisSim. The codegen can also use exactly this form, however it is not efficient since it involves a function call and dereference of argument arrays, so VisSim allows a custom codegen interface for more efficient generation. Let's say, for example, your function adds input one to input 2 and then multiplies by 2. In the VisSim dll function the code might look like 'outSig[0]=2*(inSig[0]+inSig[1])', however, for efficient code generation, you can return a string containing your code in response to the WM_VSM_GET_CODEGEN_STRING event. In this case you could return '2*(%1+%2)' and this code would be expanded in-line by the VisSim code generator. The %1 will be replaced with the code generated by input 1, and %2 is expanded by VisSim to be the code generated by input 2.

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by ctedie on Wed, 03/16/2011 - 18:00.

    Ok,
    I've done the Solution 2) and it works fine. Thanks
    Now, so if I've well understood, with the codegen it's impossible to call a function which is in the dll?
    And Also I've a problem with the WM_VSM_GET_CODEGEN_PORT_STORAGE event:
    My blocks has 2 outputs and the code in the DLL is
    case WM_VSM_GET_CODEGEN_PORT_STORAGE:
    cgBuf.Format('myStruct%d.output[%d]', getBlockId(blockHandle), wParam);
    return (LPSTR)(LPCSTR)cgBuf;

    The codegen give me:
    if (((int) myStruct1.output[1]))
    GPBSET = 0x400000L;
    else
    GPBCLEAR = 0x400000L;
    if (((int) myStruct1.output[1]))
    GPBSET = 0x800000L;
    else
    GPBCLEAR = 0x800000L;


    The output pin doesn't change.

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by Anders89 on Wed, 03/16/2011 - 23:09.

    Please send us the C code for myFunc() or attach it to your forum post using the 'File Attachments' option so we might understand why you see this unexpected behavior.

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited November 2020

    Submitted by ctedie on Thu, 03/17/2011 - 15:03.

    I join 3 files to the post:

    vsi.cpp the code done with MSVC++ 2010

    FonctionPersos.c the code done and compiled in CCS4 which contains the function called by the DLL codegen

    Compteur.vsm My Vissim Diagram

    I target a F28345.

    Unable to find an attachment - read this blog

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

     

    Submitted by Anders89 on Fri, 03/18/2011 - 19:41.

    One immediate problem is that you declare an output array of 2 elements

           cgBuf.Format('static struct {\n int input1;\n int output[2];\n} myStruct%d;\n', getBlockId(blockHandle)); 

    but you write to 4 elements:

         out[0]=(cpt & 1);     out[1]=(cpt & 2);     out[2]=(cpt & 4);     out[3]=(cpt & 8); 

    This can cause any number of strange behaviors.

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by ctedie on Fri, 03/18/2011 - 20:50.

    I've changed this, thanks. But the problem is the same.

  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by Anders89 on Mon, 03/21/2011 - 10:40.

     

    OK, we made a few more changes and it works fine for us. The project is attached below. We added some code to vsi.cpp: myFuncEvent() and created FonctionPersos.h from the function header in FonctionPersos.c. Then we included the header both in vsi.c and in the auto generated code. Here are the changes:
    1. We returned a flag from WM_CREATE to tell VisSim to use SIGNAL descriptors instead of a double vector.

     case WM_VSM_CREATE:      return (LPSTR)VBF_USE_SIGNAL_DESCRIPTORS; 
    1. We changed myFunc() to use SIGNALS instead of doubles. Plus we called Compte()instead of replicating its code.
       myFunc(vsmAddon3_INFO \*pi, SIGNAL\* inSig[], SIGNAL outSig[]) { int outVec[4];   SIGNAL \*sig  = inSig[0];   if (!sig) return; // Check for unconnected input   Compte( sig->u.Int!=0, outVec);   outSig[0].u.Int = outVec[0];   outSig[1].u.Int = outVec[1]; }
    1. We added FonctionPersos.c (defines your Compte function) to the project. This lets you test your embedded C on the PC in a VisSim diagram.
    2. We added WM_VSM_GET_CONNECTOR_TYPE case to myFuncEvent() to control data type of input and output pins:
         case WM_VSM_GET_CONNECTOR_TYPE:       port = wParam;       if (port > 0) return (LPSTR)inCxType[port-1];       if (port < 0) return (LPSTR)outCxType[-port-1];       return 0;
    1. We subtracted one from the VisSim port (wParam) since it is 1 based and the array index in C is zero based.
     case WM_VSM_GET_CODEGEN_PORT_STORAGE:       cgBuf.Format('myStruct%d.output[%d]', getBlockId(blockHandle), wParam-1);
  • Altair Forum User
    Altair Forum User
    Altair Employee
    edited June 2016

    Submitted by ctedie on Tue, 03/22/2011 - 17:56.

    For now it's OK. I try to create a new DLL based on your example and it work. Thank you

    I've noticed that your diagram is made with Vissim 8(also the path of include in your Visual C project 'vissim80/vdsk'). Is there a Vissim 8 ?