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)
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