/**************************************************************************
	Description: Программа - упаковщик.

	Автор: Улитовский Д.И.
	Дата последнего обновления: 2021.09.23
**************************************************************************/



#define S_FUNCTION_NAME wrapper_inu
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
#include "math.h"
#include "wrapper_inu.h"



#define MDL_UPDATE
/* Function: mdlUpdate ====================================================
 * Abstract:
 *    This function is called once for every major integration time step.
 *    Discrete states are typically updated here, but this function is useful
 *    for performing any tasks that should only take place once per
 *    integration step.
 */
static void mdlUpdate(SimStruct *S, int_T tid)
{
	const real_T	*u = (const real_T*) ssGetInputPortRealSignal(S,0);
	real_T			*xD = ssGetDiscStates(S);
	real_T			*rW = ssGetRWork(S);
	int_T			*iW = ssGetIWork(S);

	controller(S, u, xD, rW, iW);

}//end mdlUpdate



/* Function: mdlCheckParameters ===========================================
* Abstract:
*    mdlCheckParameters verifies new parameter settings whenever parameter
*    change or are re-evaluated during a simulation.
*/
#define MDL_CHECK_PARAMETERS   /* Change to #undef to remove function */
#if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE)
static void mdlCheckParameters(SimStruct *S)
{
	int i;

	// Проверяем и принимаем параметры и разрешаем или запрещаем их менять
	// в процессе моделирования
	for (i=0; i<NPARAMS; i++)
	{
		// Input parameter must be scalar or vector of type double
		if (!mxIsDouble(ssGetSFcnParam(S,i)) || mxIsComplex(ssGetSFcnParam(S,i)) ||
			mxIsEmpty(ssGetSFcnParam(S,i)))
		{
			ssSetErrorStatus(S,"Input parameter must be of type double");
			return;
		}
		// Параметр м.б. только скаляром, вектором или матрицей
		if (mxGetNumberOfDimensions(ssGetSFcnParam(S,i)) > 2)
		{
			ssSetErrorStatus(S,"Параметр м.б. только скаляром, вектором или матрицей");
			return;
		}

		// Parameter not tunable
//		ssSetSFcnParamTunable(S, i, SS_PRM_NOT_TUNABLE);
		// Parameter tunable (we must create a corresponding run-time parameter)
		ssSetSFcnParamTunable(S, i, SS_PRM_TUNABLE);
		// Parameter tunable only during simulation
//		ssSetSFcnParamTunable(S, i, SS_PRM_SIM_ONLY_TUNABLE);

	}//for (i=0; i<NPARAMS; i++)

}//end mdlCheckParameters

#endif //MDL_CHECK_PARAMETERS


#define MDL_PROCESS_PARAMETERS   /* Change to #undef to remove function */
#if defined(MDL_PROCESS_PARAMETERS) && defined(MATLAB_MEX_FILE)
/* Function: mdlProcessParameters =========================================
 * Abstract:
 *    This method will be called after mdlCheckParameters, whenever
 *    parameters change or get re-evaluated. The purpose of this method is
 *    to process the newly changed parameters. For example "caching" the
 *    parameter changes in the work vectors. Note this method is not
 *    called when it is used with the Real-Time Workshop. Therefore,
 *    if you use this method in an S-function which is being used with the
 *    Real-Time Workshop, you must write your S-function such that it doesn't
 *    rely on this method. This can be done by inlining your S-function
 *    via the Target Language Compiler.
 */
static void mdlProcessParameters(SimStruct *S)
{
	int_T *iW = ssGetIWork(S);

	iW[0] = 1;//processParameters
}
#endif //MDL_PROCESS_PARAMETERS



/* Function: mdlInitializeSizes ===========================================
 * Abstract:
 *    The sizes information is used by Simulink to determine the S-function
 *    block's characteristics (number of inputs, outputs, states, etc.).
 */
static void mdlInitializeSizes(SimStruct *S)
{
	//---------------------------------------------------------------------
	// Number of expected parameters
	ssSetNumSFcnParams(S, NPARAMS);

	// В нормальном режиме работы, для обработки параметров вызываем ф-цию
	// mdlCheckParameters()
	#ifdef	MATLAB_MEX_FILE
		// Кол-во ожидаемых и фактических параметров должно совпадать
		if(ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S))
		{
			// Проверяем и принимаем параметры
			mdlCheckParameters(S);
		}
		else
		{
			return;// Parameter mismatch will be reported by Simulink
		}
	#endif // MATLAB_MEX_FILE

	//---------------------------------------------------------------------
	// Register the number and type of states the S-Function uses
	ssSetNumContStates(S, 0);				// number of continuous states
	ssSetNumDiscStates(S, OUTPUT_0_WIDTH);	// number of discrete states

	//---------------------------------------------------------------------
	// Устанавливаем кол-во вх-ых портов
	if (!ssSetNumInputPorts(S, 1)) return;
	// Устанавливаем кол-во сигналов во вх-ом порту
	ssSetInputPortWidth(S, 0, INPUT_0_WIDTH);

	// Заявляем, что для нашего вх-го порта нет direct feedthrough
	ssSetInputPortDirectFeedThrough(S, 0, 0);

	// Требуем, чтобы сигналы во входном порту шли последовательно, а не
	// в разброс
	ssSetInputPortRequiredContiguous(S, 0, 1); // direct input signal access

	//---------------------------------------------------------------------
	// Устанавливаем кол-во вых-ых портов
	if (!ssSetNumOutputPorts(S, 1)) return;
	// Устанавливаем кол-во сигналов в вых-ом порту
	ssSetOutputPortWidth(S, 0, OUTPUT_0_WIDTH);

	//---------------------------------------------------------------------
	// Number of sample times
	ssSetNumSampleTimes(S, 1);

	//---------------------------------------------------------------------
	// Set size of the work vectors
	ssSetNumRWork(         S, RWORK_0_WIDTH);	// number of real work vector elements
	ssSetNumIWork(         S, IWORK_0_WIDTH);	// number of integer work vector elements
	ssSetNumPWork(         S, 0);	// number of pointer work vector elements
	ssSetNumModes(         S, 0);	// number of mode work vector elements
	ssSetNumNonsampledZCs( S, 0);	// number of nonsampled zero crossings
//	ssSetNumDWork(S, 1);

//	ssSetDWorkWidth(S, 0, 12);//Inm
//	ssSetDWorkDataType(S, 0, SS_DOUBLE);

	//---------------------------------------------------------------------
	/*
	 * All options have the form SS_OPTION_<name> and are documented in
	 * matlabroot/simulink/include/simstruc.h. The options should be
	 * bitwise or'd together as in
	 *   ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE | SS_OPTION_name2))
	 */
	// С помощью опции SS_OPTION_EXCEPTION_FREE_CODE обещаем, что в
	// нашей программе нет "исключений"
	ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE));

}//end mdlInitializeSizes



/* Function: mdlInitializeSampleTimes =====================================
 * Abstract:
 *    This function is used to specify the sample time(s) for your
 *    S-function. You must register the same number of sample times as
 *    specified in ssSetNumSampleTimes.
 */
static void mdlInitializeSampleTimes(SimStruct *S)
{
	double dt;

	// Шаг дискретизации
	dt = mxGetPr(ssGetSFcnParam(S,NPARAMS-1))[0];

	// Register one pair for each sample time
	ssSetSampleTime(S, 0, dt);
	ssSetOffsetTime(S, 0, 0.0);

}//end mdlInitializeSampleTimes


#define MDL_START  // Change to #undef to remove function
#if defined(MDL_START)
/* Function: mdlStart =====================================================
 * Abstract:
 *    This function is called once at start of model execution. If you
 *    have states that should be initialized once, this is the place
 *    to do it.
 */
static void mdlStart(SimStruct *S)
{
	int_T	*iW = ssGetIWork(S);

	iW[0] = 1;//processParameters
	iW[1] = 1;//start
}
#endif // MDL_START



/* Function: mdlOutputs ===================================================
 * Abstract:
 *    In this function, you compute the outputs of your S-function
 *    block. Generally outputs are placed in the output vector(s),
 *    ssGetOutputPortSignal.
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
	real_T		*y  = ssGetOutputPortRealSignal(S,0);
	real_T		*xD = ssGetDiscStates(S);

	int i;

	// OUTPUTS
	for (i=0; i<OUTPUT_0_WIDTH; i++)
		y[i] = xD[i];

}//end mdlOutputs



/* Function: mdlTerminate =================================================
 * Abstract:
 *    In this function, you should perform any actions that are necessary
 *    at the termination of a simulation.  For example, if memory was
 *    allocated in mdlStart, this is the place to free it.
 */
static void mdlTerminate(SimStruct *S)
{
}



/*=============================*
 * Required S-function trailer *
 *=============================*/

#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
