0

After issues I met, trying to read from COM port with Simulink, as I wrote in this discussion, I would like to follow Phil Goddard's suggestion on writing a C S-function for that. My problem is that I am not able to write C-code, so I hope in some help from you. I have found this two scripts on the net about C S-function for serial communication:

1)

#define S_FUNCTION_NAME sfun_comport

#define S_FUNCTION_LEVEL 2

#include "simstruc.h"

#include "windows.h"

#include "Strsafe.h"

#define MDL_START

#if defined(MDL_START)

/* Function: mdlStart =================================================*/
static void mdlStart(SimStruct *S)
{
    HANDLE hCom;
    DCB dcb;
    COMMTIMEOUTS uCtm;
    char pcCommPort[10];
    uint8_T comport = 4;
      //-------------------------------------------------------------------
      StringCbPrintfA((STRSAFE_LPSTR)&pcCommPort,
                      sizeof(pcCommPort),
                      "COM%d",
                      comport);
      //-------------------------------------------------------------------
      hCom = CreateFileA (pcCommPort,
                          GENERIC_READ | GENERIC_WRITE,
                          0,
                          NULL,
                          OPEN_EXISTING,
                          0,
                          NULL);
      if (hCom == INVALID_HANDLE_VALUE)
      {
          ssSetErrorStatus(S,"COM-Port konnte nicht geoeffnet werden!");
          return;
      }
      //-------------------------------------------------------------------
      SecureZeroMemory(&dcb, sizeof(dcb));
      memset(&dcb, 0, sizeof(dcb));
      dcb.DCBlength = sizeof(dcb);
      dcb.BaudRate  = (uint16_T)9600;
      dcb.ByteSize  = 8;
      dcb.Parity    = NOPARITY;
      dcb.StopBits  = ONESTOPBIT;
      //-------------------------------------------------------------------
      uCtm.ReadIntervalTimeout         = MAXDWORD;
      uCtm.ReadTotalTimeoutMultiplier  = 0;
      uCtm.ReadTotalTimeoutConstant    = 0;
      uCtm.WriteTotalTimeoutMultiplier = 0;
      uCtm.WriteTotalTimeoutConstant   = 0;
      //-------------------------------------------------------------------
      if ((!SetCommState(hCom, &dcb)) | (!SetCommTimeouts(hCom, &uCtm)))
      {
          CloseHandle(hCom);
          ssSetErrorStatus(S,"Konfigurationsfehler des COM-Ports!");
          return;
      }
      //-------------------------------------------------------------------
      ssSetPWorkValue(S, 0, hCom);
  }
#endif
/* Function: mdlOutputs =================================================*/

static void mdlOutputs(SimStruct *S, int_T tid) {

    const real_T *u0 = (const real_T*) ssGetInputPortSignal(S,0);
    real_T       *y0 = ssGetOutputPortSignal(S,0);
    HANDLE hCom = (HANDLE*)ssGetPWorkValue(S, 0);
    uint32_T read_cnt;
    uint32_T write_cnt;
    char getbuffer[] = "test";
    char putbuffer[] = "Dies ist ein Test\r";
    //int i;
    //---------------------------------------------------------------------
    read_cnt = sizeof(putbuffer)-1;
    ReadFile(hCom, putbuffer, read_cnt, &read_cnt, NULL);
    //---------------------------------------------------------------------    
    write_cnt = sizeof(putbuffer)-1;
    WriteFile(hCom, putbuffer, write_cnt, &write_cnt, NULL);
    //---------------------------------------------------------------------
    Sleep(3000);
}
#define MDL_UPDATE

#if defined(MDL_UPDATE)

/* Function: mdlUpdate ================================================*/
static void mdlUpdate(SimStruct *S, int_T tid)
{
}
#endif
/* Function: mdlTerminate ===============================================*/

static void mdlTerminate(SimStruct *S) {

    CloseHandle((HANDLE*)ssGetPWorkValue(S, 0));
}



#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif

But when I try to compile it by mex sfun_comport.c it returns following errors:

C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(449) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(1692) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(1701) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(1724) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2373) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2380) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2393) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2402) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2408) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2448) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2459) : error C2065: 'mdlInitializeSizes' : undeclared identifier 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2459) : warning C4047: '=' : 'mdlInitializeSizesFcn' differs in levels of indirection from 'int' 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2548) : error C2065: 'mdlInitializeSampleTimes' : undeclared identifier 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2548) : warning C4047: '=' : 'mdlInitializeSampleTimesFcn' differs in levels of indirection from 'int' 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2679) : warning C4013: 'mdlInitializeSizes' undefined; assuming extern returning int 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2948) : warning C4013: 'mdlInitializeSampleTimes' undefined; assuming extern returning int 

  C:\PROGRA~1\MATLAB\R2013B\BIN\MEX.PL: Error: Compile of 'sfun_comport.c' failed. 

2)

#define S_FUNCTION_NAME  sfun_tryserial
#define S_FUNCTION_LEVEL 2


#include "simstruc.h" 
#include "windows.h" 
#include "strsafe.h" 
#include "stdio.h" 
#include "string.h" 
#include "stdlib.h" 


static void mdlStart(SimStruct *S) 
{ 
    HANDLE hCom; 
    DCB dcb; 
    COMMTIMEOUTS uCtm;     
    char pcCommPort[12]; 
    //char pcCommPort[10]="COM4"; 
    uint8_T comport = mxGetScalar(ssGetSFcnParam(S, 0)); 

    StringCbPrintfA((STRSAFE_LPSTR)&pcCommPort, sizeof(pcCommPort), "COM%d:", comport); 
    //--------------------------------------------------------------- 
    hCom = CreateFileA (pcCommPort, 
               GENERIC_READ | GENERIC_WRITE, 
               0, 
               NULL, 
               OPEN_EXISTING, 
               0, 
               NULL); 

    if (hCom == INVALID_HANDLE_VALUE) 
    { 
   ssSetErrorStatus(S,"COM-Port konnte nicht geoeffnet werden!"); 
        return; 
    } 
    //--------------------------------------------------------------- 
    SecureZeroMemory(&dcb, sizeof(dcb)); 
    memset(&dcb, 0, sizeof(dcb)); 
    dcb.DCBlength = sizeof(dcb); 
    dcb.BaudRate = (uint16_T)9600; 
    dcb.ByteSize = 8; 
    dcb.Parity = NOPARITY; 
    dcb.StopBits = ONESTOPBIT; 
    //dcb.fDtrControl = 0X01; //ENABLE 
    //dcb.fRtsControl = 0x01; //ENABLE 
    //---------------------------------------------------------------   
    uCtm.ReadIntervalTimeout = MAXDWORD; 
    uCtm.ReadTotalTimeoutMultiplier = 0; 
    uCtm.ReadTotalTimeoutConstant = 0; 
    uCtm.WriteTotalTimeoutMultiplier = 0; 
    uCtm.WriteTotalTimeoutConstant = 0; 
    //--------------------------------------------------------------- 
    if ((!SetCommState(hCom, &dcb)) | (!SetCommTimeouts(hCom, &uCtm))) 
    { 
        CloseHandle(hCom); 
        ssSetErrorStatus(S,"Konfigurationsfehler des COM-Ports!"); 
        return; 
    } 
    //--------------------------------------------------------------- 
    ssSetErrorStatus(S,"Konfigurationsfehler des COM-Ports!"); 
    ssSetPWorkValue(S, 0, &hCom); 
} 


static void mdlOutputs(SimStruct *S, int_T tid) 
{ 
    const real_T   *u0 = (const real_T*)ssGetInputPortSignal(S, 0); 
    real_T           *y0 = (real_T *)ssGetOutputPortRealSignal(S, 0); 

    uint32_T read_cnt; 
    uint32_T write_cnt; 
    char getbuffer[255] = {0}; 
    char putbuffer[255] = {0}; 

    HANDLE hCom = (HANDLE*)ssGetPWorkValue(S, 0); 

    //++++++++++++++++++++++++++++++++++++++++++++++ 
    if (ReadFile(hCom, getbuffer, sizeof(getbuffer), &read_cnt, NULL)) 
    { 
        // Daten auswerten, read_cnt enthält die Anzahl gelesener Bytes 
    } 
    else 
    { 
        // keine Daten empfangen 
        // z.B. Fehlermeldung oder nix machen 
    }     
     //++++++++++++++++++++++++++++++++++++++++++++++ 
    if (!WriteFile(hCom, putbuffer, write_cnt, &read_cnt, NULL)); 
    { 
        // Fehlermeldung, weil die Daten nicht verschickt werden konnten 
    } 
    //++++++++++++++++++++++++++++++++++++++++++++++ 
} 

static void mdlTerminate(SimStruct *S) 
{ 
    CloseHandle((HANDLE*)ssGetPWorkValue(S, 0)); 
} 

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */
#include "simulink.c"      /* MEX-file interface mechanism */
#else
#include "cg_sfun.h"       /* Code generation registration function */
#endif

This produces:

sfun_tryserial.c(20) : warning C4244: 'initializing' : conversion from 'double' to 'uint8_T', possible loss of data 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(449) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(1692) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(1701) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(1724) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2373) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2380) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2393) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2402) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2408) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2448) : warning C4995: 'sprintf': name was marked as #pragma deprecated 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2459) : error C2065: 'mdlInitializeSizes' : undeclared identifier 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2459) : warning C4047: '=' : 'mdlInitializeSizesFcn' differs in levels of indirection from 'int' 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2548) : error C2065: 'mdlInitializeSampleTimes' : undeclared identifier 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2548) : warning C4047: '=' : 'mdlInitializeSampleTimesFcn' differs in levels of indirection from 'int' 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2679) : warning C4013: 'mdlInitializeSizes' undefined; assuming extern returning int 
C:\Program Files\MATLAB\R2013b\simulink\include\simulink.c(2948) : warning C4013: 'mdlInitializeSampleTimes' undefined; assuming extern returning int 

  C:\PROGRA~1\MATLAB\R2013B\BIN\MEX.PL: Error: Compile of 'sfun_provaseriale2.c' failed. 

As you can notice common errors between two S-function are about:

'mdlInitializeSizes'
'mdlInitializeSizesFcn'
'mdlInitializeSampleTimes'
'mdlInitializeSampleTimesFcn'
'mdlInitializeSizes'

Do you have some suggestion to fix those errors ?

PS: I have MATLAB 2013b 64-bit, 64-bit Windows 7, Microsoft Visual C++ 2010 (32-bit) as compiler (it has worked fine in 64-bit matlab to produce mex files)

Community
  • 1
  • 1
cyberdyne
  • 426
  • 3
  • 5
  • 23
  • If you have the Instrument Control Toolbox, you could simply use the [Serial Receive](http://uk.mathworks.com/help/instrument/serialreceive.html) and [Serial Send](http://uk.mathworks.com/help/instrument/serialsend.html) blocks. – am304 Dec 22 '14 at 09:57
  • Actually, since in the same simulink model I have to get a video (by Image acquisition toolbox), when I try to use 'Serial' blocks it seems simulink's scheduler gives priority to image acquisition block therefore serial receive doesn't work at real-time. I have read that problem is because the 'Serial' class (thus also the `serial()`) is not supported by code generation (someone said it is beacause `serial()` has a java "engine" in its background). So I am searching for a C (or C++) function to be supported by code generation, which could work at a "low-level". – cyberdyne Dec 22 '14 at 11:35
  • That's correct, see http://uk.mathworks.com/matlabcentral/answers/10859-serial-port-access-and-code-generation-errors. For any serial read operation to go through code generation & run in (hard) real-time, it will have to be hardware-dependent, so your question doesn't really make sense... See for example the [Arduino Support Package for Simulink](http://uk.mathworks.com/hardware-support/arduino-simulink.html), which has some serial blocks, supporting code generation (but only for Arduino platforms). – am304 Dec 22 '14 at 12:14
  • Ehm, my issue is very old and as you can read in [this](http://stackoverflow.com/questions/21883900/serial-block-doesnt-work-with-simulink-coder) discussion I am already using Arduino and it is actually the device that send me data over serial. Why do you think a C S-function has not sense? I believe by libraries independent from matlab/simulink (Windows-based for example) I could avoid the problem. The fact is that I cannot program in C. – cyberdyne Dec 22 '14 at 19:50
  • Then I understand even less... If the Arduino (presumably already running some code) is sending you data via serial, why go to all the trouble of writing a custom C S-function and generate code from it? What are you trying to achieve? Where is that generated code going to run, and what's it going to do? – am304 Dec 23 '14 at 09:13
  • I am just trying to read by PC data that Arduino sends over serial. Since Simulink's Serial Blocks do not work in real-time if in the Simulink Model there are other blocks especially if those others take a big deal of resources (the example of the CV toolbox). So since I have verified code generation improves speed and make simulink to run in real-time, I would like compile also Serial blocks. – cyberdyne Dec 23 '14 at 10:57
  • Code generation *might* improve speed, but not necessarily, and probably not for I/O operations. Simulink runs on Windows/OSX/Linux, which are not RTOS, so no model will ever run in real-time, it'll simply go as fast as it can, based on whatever other tasks the OS has to do at that time. Now, if the model runs faster than real-time, you can slow it down to "pseudo" real-time, there are various blocks that do that. – am304 Dec 23 '14 at 11:04
  • If however, it runs runs slower than real-time, then you need to simplify the model, change the solver settings, whatever but writing custom S-functions and using code generation is NOT the way to go about it. – am304 Dec 23 '14 at 11:04
  • Thank you for your answers. The model is composed by the `Serial Receive` (and configuration) block that leads data to a `To Workspace` block and a `From Video Device` block that acquires from a webcam and send it to a `To Multimedia File` block. Video acquisition works fine but there is a delay in the reading from the serial. The Simulation configuration is composed by a fixed step and discrete mode (no solvers). What do you suggest to simplify the model for real-time ? – cyberdyne Dec 23 '14 at 23:16
  • It may that it's simply not possible to read all the messages sent by the Arduino that fast. You may need to slow down the rate at which the Arduino is sending messages so that you have enough time to process them in Simulink. Have you tried reading from the serial port seperately (i.e. without the video processing)? Do you still have the delay? It may be due to a combination of the block and model parameters. – am304 Jan 03 '15 at 13:48
  • I have replaced the `Scope` blocks with the DSP Toolbox's `Time Scope` and instead to apply one for each measure (I read a gyroscope measure, so I have a measure for each axis) I have connected just a Time Scope` block and now it seems to read data from serial at real-time (actually I don't know why). But when the webcam slows down, for example during changes of brightness in the scene, reading data lose synchrony. – cyberdyne Jan 03 '15 at 15:15
  • Scopes are notoriously bad, as they have to write to memory and possibly to the hard drive, if you log for long enough. What you are saying about the webcam suggest that your model is right on the edge of being able to run in "pseudo" real-time. You probably need to run your model with a larger time step (and send serial messages at a lower frequency). – am304 Jan 05 '15 at 09:17

1 Answers1

0

You still have to write those functions by yourself. As you can see from their names, they define the sizes and sample time of the S-Function. They are required components of a complete and functional S-Function.

For example:

static void mdlInitializeSizes(SimStruct *S) describes the sizes information that is used by Simulink to determine the S-function block's characteristics (number of inputs, outputs, states, etc.).

static void mdlInitializeSampleTimes(SimStruct *S) is used to specify the sample time(s) for your S-function.

See also:

http://de.mathworks.com/help/simulink/sfg/mdlinitializesizes.html http://de.mathworks.com/help/simulink/sfg/mdlinitializesampletimes.html

GitaarLAB
  • 14,536
  • 11
  • 60
  • 80
Manxiu Zhan
  • 151
  • 1
  • 4