Hi! I try to write a simple s-function with openGL/freeglut. I compile it within Visual Studio ( how to do it ). When i run my s-function in Simulink it works only the first time. The second attempt of running the model results in Matlab crash, but the matlab process steel exist in a memory.
May be there is a mistake with memory or thread manipulation? I find out that Matlab crashes at glutInit function
Will be very glad if somebody can help me because i have found almost no information about s-function used with multithreading or openGL.
Here is the code:
#define S_FUNCTION_NAME my_sf #define S_FUNCTION_LEVEL 2 #include <simstruc.h> #include <freeglut.h> #include <Math.h> #include <windows.h> #include <process.h> #include <stdio.h> struct data_st { unsigned ThreadId; HANDLE hThread, hEvent; }; void display() { glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer with current clearing color // Define shapes enclosed within a pair of glBegin and glEnd glBegin(GL_QUADS); // Each set of 4 vertices form a quad glColor3f(1.0f, 0.0f, 0.0f); // Red glVertex2f(-0.8f, 0.1f); // Define vertices in counter-clockwise (CCW) order glVertex2f(-0.2f, 0.1f); // so that the normal (front-face) is facing you glVertex2f(-0.2f, 0.7f); glVertex2f(-0.8f, 0.7f); glColor3f(0.0f, 1.0f, 0.0f); // Green glVertex2f(-0.7f, -0.6f); glVertex2f(-0.1f, -0.6f); glVertex2f(-0.1f, 0.0f); glVertex2f(-0.7f, 0.0f); glColor3f(0.2f, 0.2f, 0.2f); // Dark Gray glVertex2f(-0.9f, -0.7f); glColor3f(1.0f, 1.0f, 1.0f); // White glVertex2f(-0.5f, -0.7f); glColor3f(0.2f, 0.2f, 0.2f); // Dark Gray glVertex2f(-0.5f, -0.3f); glColor3f(1.0f, 1.0f, 1.0f); // White glVertex2f(-0.9f, -0.3f); glEnd(); glBegin(GL_TRIANGLES); // Each set of 3 vertices form a triangle glColor3f(0.0f, 0.0f, 1.0f); // Blue glVertex2f(0.1f, -0.6f); glVertex2f(0.7f, -0.6f); glVertex2f(0.4f, -0.1f); glColor3f(1.0f, 0.0f, 0.0f); // Red glVertex2f(0.3f, -0.4f); glColor3f(0.0f, 1.0f, 0.0f); // Green glVertex2f(0.9f, -0.4f); glColor3f(0.0f, 0.0f, 1.0f); // Blue glVertex2f(0.6f, -0.9f); glEnd(); glBegin(GL_POLYGON); // These vertices form a closed polygon glColor3f(1.0f, 1.0f, 0.0f); // Yellow glVertex2f(0.4f, 0.2f); glVertex2f(0.6f, 0.2f); glVertex2f(0.7f, 0.4f); glVertex2f(0.6f, 0.6f); glVertex2f(0.4f, 0.6f); glVertex2f(0.3f, 0.4f); glEnd(); glFlush(); // Render now } void do_nothing(void) { return; } unsigned __stdcall plot(struct data_st* data) { char *argv[1]; int argc = 1; argv[0] = strdup("Myappname"); glutInit(&argc, argv); // Initialize GLUT glutCreateWindow("Vertex, Primitive & Color"); // Create window with the given title glutInitWindowSize(320, 320); // Set the window's initial width & height glutInitWindowPosition(50, 50); // Position the window's initial top-left corner glutDisplayFunc(do_nothing); // Register callback handler for window re-paint event glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); while (WaitForSingleObject(data->hEvent, 0) != WAIT_OBJECT_0) { display(); glutMainLoopEvent(); } //glutDestroyWindow( glutGetWindow() ); return(0); } /* Function: mdlInitializeSizes =============================================== * Abstract: * Setup sizes of the various vectors. */ static void mdlInitializeSizes(SimStruct *S) { ssSetNumSFcnParams(S, 0); if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; /* Parameter mismatch will be reported by Simulink */ } if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, 1); ssSetInputPortDirectFeedThrough(S, 0, 1); if (!ssSetNumOutputPorts(S,1)) return; ssSetOutputPortWidth(S, 0, 1); ssSetNumSampleTimes(S, 1); /* specify the sim state compliance to be same as a built-in block */ ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE); ssSetNumDWork(S, 1); ssSetDWorkWidth(S, 0, 1); ssSetDWorkDataType(S, 0, SS_POINTER); ssSetOptions(S, SS_OPTION_WORKS_WITH_CODE_REUSE | SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_USE_TLC_WITH_ACCELERATOR); } #define MDL_START void mdlStart(SimStruct *S) { void **Ptrs = (void**)ssGetDWork(S, 0); struct data_st* data; data = (void*)malloc(sizeof(struct data_st)); Ptrs[0] = data; data -> hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); data -> hThread = (HANDLE)_beginthreadex(NULL, 0, plot, data, 0, &(data->ThreadId)); if (data->hThread == 0) return; } /* Function: mdlInitializeSampleTimes ========================================= * Abstract: * Specifiy that we inherit our sample time from the driving block. */ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); ssSetModelReferenceSampleTimeDefaultInheritance(S); } /* Function: mdlOutputs ======================================================= * Abstract: * y = 2*u */ static void mdlOutputs(SimStruct *S, int_T tid) { InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); real_T *y = ssGetOutputPortRealSignal(S,0); *y = 2.0 *(*uPtrs[0]); } /* Function: mdlTerminate ===================================================== * Abstract: * No termination needed, but we are required to have this routine. */ static void mdlTerminate(SimStruct *S) { void **Ptrs = (void**)ssGetDWork(S, 0); struct data_st* data; data = Ptrs[0]; SetEvent(data->hEvent); // init event for thread stop WaitForSingleObject(data->hThread, INFINITE); // wait thread to be finised CloseHandle(data->hEvent); CloseHandle(data->hThread); free(data); } #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
Best Answer