diff --git a/adaptors/matlab/analogout.c b/adaptors/matlab/analogout.c index e545ab93cd860c48a222857451a2f43e588c972f..a8ea2a01d4d393da65d563328150bbe040c38dce 100644 --- a/adaptors/matlab/analogout.c +++ b/adaptors/matlab/analogout.c @@ -33,13 +33,24 @@ 1 moberg_analog_out pointer[1] ... - */ + RWork: 0 exit_value[0] (optional) + 1 exit_value[1] (optional) + ... + +*/ #define MDL_CHECK_PARAMETERS static void mdlCheckParameters(SimStruct *S) { + int number_of_params = ssGetSFcnParamsCount(S); + + if (number_of_params < 2 || 3 < number_of_params) { + ssSetErrorStatus(S, "block accepts 2 or 3 parameters"); + return; + } + /* 1st parameter: sampling interval */ - { + if (number_of_params >= 1) { if (!mxIsDouble(ssGetSFcnParam(S,0)) || mxGetNumberOfElements(ssGetSFcnParam(S,0)) != 1) { ssSetErrorStatus(S, "sampling time must be a scalar"); @@ -47,8 +58,8 @@ static void mdlCheckParameters(SimStruct *S) } } - /* 2nd parameter: input channels */ - { + /* 2nd parameter: output channels */ + if (number_of_params >= 2) { int number_of_dims = mxGetNumberOfDimensions(ssGetSFcnParam(S,1)); if (!mxIsDouble(ssGetSFcnParam(S,1)) || @@ -57,19 +68,36 @@ static void mdlCheckParameters(SimStruct *S) return; } } + + /* 3nd parameter: (optional) exit output values */ + if (number_of_params >= 3) { + int number_of_dims = mxGetNumberOfDimensions(ssGetSFcnParam(S,2)); + + if (!mxIsDouble(ssGetSFcnParam(S,2)) || + number_of_dims != 2 || mxGetM(ssGetSFcnParam(S,2)) != 1) { + ssSetErrorStatus(S, "exit output values must be a scalar or a vector"); + return; + } + + if (mxGetN(ssGetSFcnParam(S,1)) != mxGetN(ssGetSFcnParam(S,2))) { + ssSetErrorStatus(S, "exit output values must same size as channels"); + return; + } + } } static void mdlInitializeSizes(SimStruct *S) { int channelCount; + int number_of_params = ssGetSFcnParamsCount(S); - ssSetNumSFcnParams(S, 2); - if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) { - mdlCheckParameters(S); - if (ssGetErrorStatus(S) != NULL) { return; } - } else { + if (number_of_params < 2 || 3 < number_of_params) { + ssSetErrorStatus(S, "block accepts 2 or 3 parameters"); return; } + ssSetNumSFcnParams(S, number_of_params); + mdlCheckParameters(S); + if (ssGetErrorStatus(S) != NULL) { return; } channelCount = mxGetN(ssGetSFcnParam(S,1)); @@ -87,9 +115,15 @@ static void mdlInitializeSizes(SimStruct *S) ssSetNumSampleTimes(S, 1); ssSetNumPWork(S, channelCount); /* 0: moberg_analog_out pointer[0] - 1: moberg_analog_out pointer[1] - ... - */ + * 1: moberg_analog_out pointer[1] + * ... + */ + if (number_of_params == 3) { + ssSetNumRWork(S, channelCount); /* 0: exit_value[0] + * 1: exit_value[1] + * ... + */ + } ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); @@ -106,24 +140,30 @@ static void mdlInitializeSampleTimes(SimStruct *S) static void mdlInitializeConditions(SimStruct *S) { void **pwork = ssGetPWork(S); + real_T *rwork = ssGetRWork(S); double *channel = mxGetPr(ssGetSFcnParam(S,1)); - int channel_count = mxGetN(ssGetSFcnParam(S,1)); int i; - for (i = 0 ; i < channel_count ; i++) { + if (rwork) { + real_T *exit_value = mxGetPr(ssGetSFcnParam(S,2)); + for (i = 0 ; i < ssGetNumRWork(S) ; i++) { + rwork[i] = exit_value[i]; + } + } + + for (i = 0 ; i < ssGetNumPWork(S) ; i++) { pwork[i] = moberg4simulink_analog_out_open(channel[i]); if (! pwork[i]) { static char error[256]; sprintf(error, "Failed to open analogout #%d", (int)channel[i]); ssSetErrorStatus(S, error); + return; } } } static void mdlOutputs(SimStruct *S, int_T tid) { - void **pwork = ssGetPWork(S); - { /* Propagate the dummy sorting signal */ InputRealPtrsType up = ssGetInputPortRealSignalPtrs(S,0); @@ -133,6 +173,7 @@ static void mdlOutputs(SimStruct *S, int_T tid) { int i; InputRealPtrsType up = ssGetInputPortRealSignalPtrs(S,1); + void **pwork = ssGetPWork(S); for (i = 0 ; i < ssGetNumPWork(S) ; i++) { struct moberg_analog_out *aout = (struct moberg_analog_out*)pwork[i]; @@ -150,10 +191,21 @@ static void mdlTerminate(SimStruct *S) { int i; void **pwork = ssGetPWork(S); + real_T *rwork = ssGetRWork(S); double *channel = mxGetPr(ssGetSFcnParam(S,1)); - int channel_count = mxGetN(ssGetSFcnParam(S,1)); - for (i = 0 ; i < channel_count ; i++) { + for (i = 0 ; i < ssGetNumPWork(S) && i < ssGetNumRWork(S) ; i++) { + struct moberg_analog_out *aout = (struct moberg_analog_out*)pwork[i]; + if (aout == NULL) continue; + if (! moberg_OK(aout->write(aout->context, rwork[i], NULL))) { + static char error[256]; + double *channel = mxGetPr(ssGetSFcnParam(S,1)); + sprintf(error, "Failed to write analogout #%d", (int)channel[i]); + ssSetErrorStatus(S, error); + } + } + + for (i = 0 ; i < ssGetNumPWork(S) ; i++) { if (pwork[i]) { struct moberg_analog_out *aout = (struct moberg_analog_out*)pwork[i]; moberg4simulink_analog_out_close(channel[i], aout); diff --git a/adaptors/matlab/digitalout.c b/adaptors/matlab/digitalout.c index be8d48e9e85e3e9d786797d4b73f7a705519cd81..b12903f2b51c8ea41066aa7e352905e29fae84a9 100644 --- a/adaptors/matlab/digitalout.c +++ b/adaptors/matlab/digitalout.c @@ -33,13 +33,24 @@ 1 moberg_digital_out pointer[1] ... - */ + RWork: 0 exit_value[0] (optional) + 1 exit_value[1] (optional) + ... + +*/ #define MDL_CHECK_PARAMETERS static void mdlCheckParameters(SimStruct *S) { + int number_of_params = ssGetSFcnParamsCount(S); + + if (number_of_params < 2 || 3 < number_of_params) { + ssSetErrorStatus(S, "block accepts 2 or 3 parameters"); + return; + } + /* 1st parameter: sampling interval */ - { + if (number_of_params >= 1) { if (!mxIsDouble(ssGetSFcnParam(S,0)) || mxGetNumberOfElements(ssGetSFcnParam(S,0)) != 1) { ssSetErrorStatus(S, "sampling time must be a scalar"); @@ -47,8 +58,8 @@ static void mdlCheckParameters(SimStruct *S) } } - /* 2nd parameter: input channels */ - { + /* 2nd parameter: output channels */ + if (number_of_params >= 2) { int number_of_dims = mxGetNumberOfDimensions(ssGetSFcnParam(S,1)); if (!mxIsDouble(ssGetSFcnParam(S,1)) || @@ -57,20 +68,37 @@ static void mdlCheckParameters(SimStruct *S) return; } } + + /* 3nd parameter: (optional) exit output values */ + if (number_of_params >= 3) { + int number_of_dims = mxGetNumberOfDimensions(ssGetSFcnParam(S,2)); + + if (!mxIsDouble(ssGetSFcnParam(S,2)) || + number_of_dims != 2 || mxGetM(ssGetSFcnParam(S,2)) != 1) { + ssSetErrorStatus(S, "exit output values must be a scalar or a vector"); + return; + } + + if (mxGetN(ssGetSFcnParam(S,1)) != mxGetN(ssGetSFcnParam(S,2))) { + ssSetErrorStatus(S, "exit output values must same size as channels"); + return; + } + } } static void mdlInitializeSizes(SimStruct *S) { int channelCount; + int number_of_params = ssGetSFcnParamsCount(S); - ssSetNumSFcnParams(S, 2); - if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) { - mdlCheckParameters(S); - if (ssGetErrorStatus(S) != NULL) { return; } - } else { + if (number_of_params < 2 || 3 < number_of_params) { + ssSetErrorStatus(S, "block accepts 2 or 3 parameters"); return; } - + ssSetNumSFcnParams(S, number_of_params); + mdlCheckParameters(S); + if (ssGetErrorStatus(S) != NULL) { return; } + channelCount = mxGetN(ssGetSFcnParam(S,1)); ssSetNumContStates(S, 0); @@ -87,9 +115,15 @@ static void mdlInitializeSizes(SimStruct *S) ssSetNumSampleTimes(S, 1); ssSetNumPWork(S, channelCount); /* 0: moberg_digital_out pointer[0] - 1: moberg_digital_out pointer[1] - ... - */ + * 1: moberg_digital_out pointer[1] + * ... + */ + if (number_of_params == 3) { + ssSetNumRWork(S, channelCount); /* 0: exit_value[0] + * 1: exit_value[1] + * ... + */ + } ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); @@ -106,24 +140,30 @@ static void mdlInitializeSampleTimes(SimStruct *S) static void mdlInitializeConditions(SimStruct *S) { void **pwork = ssGetPWork(S); + real_T *rwork = ssGetRWork(S); double *channel = mxGetPr(ssGetSFcnParam(S,1)); - int channel_count = mxGetN(ssGetSFcnParam(S,1)); int i; - for (i = 0 ; i < channel_count ; i++) { + if (rwork) { + real_T *exit_value = mxGetPr(ssGetSFcnParam(S,2)); + for (i = 0 ; i < ssGetNumRWork(S) ; i++) { + rwork[i] = exit_value[i]; + } + } + + for (i = 0 ; i < ssGetNumPWork(S) ; i++) { pwork[i] = moberg4simulink_digital_out_open(channel[i]); if (! pwork[i]) { static char error[256]; sprintf(error, "Failed to open digitalout #%d", (int)channel[i]); ssSetErrorStatus(S, error); + return; } } } static void mdlOutputs(SimStruct *S, int_T tid) { - void **pwork = ssGetPWork(S); - { /* Propagate the dummy sorting signal */ InputRealPtrsType up = ssGetInputPortRealSignalPtrs(S,0); @@ -133,6 +173,7 @@ static void mdlOutputs(SimStruct *S, int_T tid) { int i; InputRealPtrsType up = ssGetInputPortRealSignalPtrs(S,1); + void **pwork = ssGetPWork(S); for (i = 0 ; i < ssGetNumPWork(S) ; i++) { struct moberg_digital_out *dout = (struct moberg_digital_out*)pwork[i]; @@ -150,10 +191,21 @@ static void mdlTerminate(SimStruct *S) { int i; void **pwork = ssGetPWork(S); + real_T *rwork = ssGetRWork(S); double *channel = mxGetPr(ssGetSFcnParam(S,1)); - int channel_count = mxGetN(ssGetSFcnParam(S,1)); - for (i = 0 ; i < channel_count ; i++) { + for (i = 0 ; i < ssGetNumPWork(S) && i < ssGetNumRWork(S) ; i++) { + struct moberg_digital_out *dout = (struct moberg_digital_out*)pwork[i]; + if (dout == NULL) continue; + if (! moberg_OK(dout->write(dout->context, rwork[i], NULL))) { + static char error[256]; + double *channel = mxGetPr(ssGetSFcnParam(S,1)); + sprintf(error, "Failed to write analogout #%d", (int)channel[i]); + ssSetErrorStatus(S, error); + } + } + + for (i = 0 ; i < ssGetNumPWork(S) ; i++) { if (pwork[i]) { struct moberg_digital_out *dout = (struct moberg_digital_out*)pwork[i]; moberg4simulink_digital_out_close(channel[i], dout);