@@ -29,92 +29,92 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929/* JSBSIm SFunction 2021-07-08
3030 *
3131 * Several changes have been made to integrate Simulink with JSBSim Version 1.1.6
32- * For the original code, see
32+ * For the original code, see
3333 * https://se.mathworks.com/matlabcentral/fileexchange/25042-jsbsim-s-function-gui-0-3
34- * and
34+ * and
3535 * https://github.com/podhrmic/JSBSim-Matlab
36- * A big thanks to Michal Podhradsky for the work done.
36+ * A big thanks to Michal Podhradsky for the work done.
3737 *
38- * SFunction block parameters are changed to:
39- * 'ac_name_string', [u-fps v-fps w-fps p-radsec q-radsec r-radsec h-sl-ft long-gc-deg lat-gc-deg
38+ * SFunction block parameters are changed to:
39+ * 'ac_name_string', [u-fps v-fps w-fps p-radsec q-radsec r-radsec h-sl-ft long-gc-deg lat-gc-deg
4040 * phi-rad theta-rad psi-rad],
4141 * [throttle-cmd-norm aileron-cmd-norm elevator-cmd-norm rudder-cmd-norm mixture-cmd-norm set-running flaps-cmd-norm gear-cmd-norm],
4242 * [delta_T], 'script/scriptname'
43- *
43+ *
4444 * This means it is now possible to define a script as usual in JSBSim. If
45- * a valid script name is not defined, Simulink will try to load the specified
46- * aircraft and run the script using the input parameters.
45+ * a valid script name is not defined, Simulink will try to load the specified
46+ * aircraft and run the script using the input parameters.
4747 *
4848 * Input parameters: [throttle, aileron, elevator, rudder, mixture, set-running, flaps and gear]
4949 *
50- * Output parameters have been updated, there are 4 output ports.
50+ * Output parameters have been updated, there are 4 output ports.
5151 * 0 (states): [u-fps v-fps w-fps p-rad-sec q-rad-sec r-rad-sec h-sl-ft long-deg lat-deg phi-rad theta-rad psi-rad]
52- * 1 (Flight controls): [thr-pos-norm left-ail-pos-rad right-ail-pos-rad el-pos-rad rud-pos-rad flap-pos-norm
53- * speedbrake-pos-rad spoiler-pos-rad gear-pos-norm]
54- * 2: (Propulsion output): Not yet defined in the SFunction. Placeholder. Needs to be engine dependent.
55- * 3: (Pilot related output): [pilot-Nz alpha-rad alpha-dot-rad-sec beta-rad beta-dot-rad-sec vc-fps vc-kts
52+ * 1 (Flight controls): [thr-pos-norm left-ail-pos-rad right-ail-pos-rad el-pos-rad rud-pos-rad flap-pos-norm
53+ * speedbrake-pos-rad spoiler-pos-rad gear-pos-norm]
54+ * 2: (Propulsion output): Not yet defined in the SFunction. Placeholder. Needs to be engine dependent.
55+ * 3: (Pilot related output): [pilot-Nz alpha-rad alpha-dot-rad-sec beta-rad beta-dot-rad-sec vc-fps vc-kts
5656 * Vt-fps vg-fps mach climb-rate-fps qbar-psf]
5757 *
58- * Verbosity settings and JSBSim Multiplier have been removed.
59- *
60- * It is currently needed to run the clearSF.m function in the command window
61- * in matlab before each simulation. This should be fixed.
58+ * Verbosity settings and JSBSim Multiplier have been removed.
59+ *
60+ * It is currently needed to run the clearSF.m function in the command window
61+ * in matlab before each simulation. This should be fixed.
6262 *
6363 * 2021-07-08 Tilda Sikström
64- * Linköping, Sweden
64+ * Linköping, Sweden
65+ *
6566 *
66- *
6767 * ***********************************************************************************************
6868 * **************************************************************************************************
6969 * Bug fixes
7070 * %%% Fixed issues with Debug Verbosity settings
7171 * %%% Fixed problem with "verbose" Verbosity setting that did not allow simulation to run properly
72- * %%% Fixed issue with throttles not being initialized properly and angines not being properly spooled up to the
72+ * %%% Fixed issue with throttles not being initialized properly and angines not being properly spooled up to the
7373 * intended power setting
7474 *
7575 * 01/22/10 Brian Mills
76- *
76+ *
7777 * *********Discrete States Version******************************************************************
7878 * JSBSim calculates states. NO integration performed by Simulink.
7979 * Use fixed step discrete state solver
8080 * Basic implementation of a JSBSim S-Function that takes 5 input parameters
8181 * at the S-Function's block parameters dialog box:
82- * 'ac_name_string',
83- * [u-fps v-fps w-fps p-radsec q-radsec r-radsec h-sl-ft long-gc-deg lat-gc-deg
82+ * 'ac_name_string',
83+ * [u-fps v-fps w-fps p-radsec q-radsec r-radsec h-sl-ft long-gc-deg lat-gc-deg
8484 * phi-rad theta-rad psi-rad],
8585 * [throttle-cmd-norm aileron-cmd-norm elevator-cmd-norm rudder-cmd-norm mixture-cmd-norm set-running flaps-cmd-norm gear-cmd-norm],
8686 * [delta_T], 'script/scriptname'
8787 * The model currently takes 8 control inputs:throttle, aileron, elevator, rudder, mixture, set-running, flaps and gear.
88- * The model has 12 states:[u-fps v-fps w-fps p-rad-sec q-rad-sec r-rad-sec h-sl-ft long-deg lat-deg phi-rad theta-rad psi-rad]
88+ * The model has 12 states:[u-fps v-fps w-fps p-rad-sec q-rad-sec r-rad-sec h-sl-ft long-deg lat-deg phi-rad theta-rad psi-rad]
8989 * Model has 4 output ports: state vector, control output vector, propulsion output vector and calculated output vector.
90- * States output [u-fps v-fps w-fps p-rad-sec q-rad-sec r-rad-sec h-sl-ft long-deg lat-deg phi-rad theta-rad psi-rad]
91- * Flight Controls output [thr-pos-norm left-ail-pos-rad right-ail-pos-rad el-pos-rad rud-pos-rad flap-pos-norm
90+ * States output [u-fps v-fps w-fps p-rad-sec q-rad-sec r-rad-sec h-sl-ft long-deg lat-deg phi-rad theta-rad psi-rad]
91+ * Flight Controls output [thr-pos-norm left-ail-pos-rad right-ail-pos-rad el-pos-rad rud-pos-rad flap-pos-norm
9292 speedbrake-pos-rad spoiler-pos-rad gear-pos-norm]
93- * Propulsion output piston (per engine) [prop-rpm prop-thrust-lbs mixture fuel-flow-gph advance-ratio power-hp pt-lbs_sqft
93+ * Propulsion output piston (per engine) [prop-rpm prop-thrust-lbs mixture fuel-flow-gph advance-ratio power-hp pt-lbs_sqft
9494 * volumetric-efficiency bsfc-lbs_hphr prop-torque blade-angle prop-pitch]
95- * Propulsion output turbine (per engine) [thrust-lbs n1 n2 fuel-flow-pph fuel-flow-pps pt-lbs_sqft pitch-rad reverser-rad yaw-rad inject-cmd
95+ * Propulsion output turbine (per engine) [thrust-lbs n1 n2 fuel-flow-pph fuel-flow-pps pt-lbs_sqft pitch-rad reverser-rad yaw-rad inject-cmd
9696 * set-running fuel-dump]
97- * Calculated outputs [pilot-Nz alpha-rad alpha-dot-rad-sec beta-rad beta-dot-rad-sec vc-fps vc-kts
97+ * Calculated outputs [pilot-Nz alpha-rad alpha-dot-rad-sec beta-rad beta-dot-rad-sec vc-fps vc-kts
9898 * Vt-fps vg-fps mach climb-rate-fps]
9999 *
100100 * The UpdateStates method added to JSBSimInterface is called for every s-function simulation time step.
101- * Currently it is advised that if the AC model FCS has integrators, then after each simulation run "clearSF"
101+ * Currently it is advised that if the AC model FCS has integrators, then after each simulation run "clearSF"
102102 * should be entered at the Matlab command line to reset the simulation.
103- * This will ensure that every consecutive simulation run starts from the same initial states.
103+ * This will ensure that every consecutive simulation run starts from the same initial states.
104104 * It is planned to fix this in the near future.
105105 * Please look in the mdlInitializeSizes method for more detailed input port and output port details.
106106 * *************************************************************************************************************************
107107 * *************************************************************************************************************************
108108 * 08/08/09 JSBSimSFunction revision 1.0 for campatibility with JSBSim 1.0
109109 * Brian Mills
110110 * *************************************************************************************************************************
111- * JSBSimInterface written by Agostino De Marco for use in the JSBSimMexFunction project. Additional functions have been added and changes
111+ * JSBSimInterface written by Agostino De Marco for use in the JSBSimMexFunction project. Additional functions have been added and changes
112112 * made to work with SFunction API. Thanks to Agostino for providing the basis for this project.
113113 * *************************************************************************************************************************
114114
115115*/
116116#ifdef __cplusplus
117-
117+
118118#endif // defined within this scope
119119#define S_FUNCTION_NAME JSBSim_SFunction
120120#define S_FUNCTION_LEVEL 2
@@ -184,7 +184,7 @@ std::string getMxArrayString(const mxArray* mxArrayStr) {
184184
185185 mwSize strLen = mxGetNumberOfElements (mxArrayStr) + 1 ;
186186 char * strBuf = (char *) malloc (strLen * sizeof (char ));
187- mxGetString (mxArrayStr, strBuf, strLen);
187+ mxGetString (mxArrayStr, strBuf, strLen);
188188 std::string str = std::string (strBuf);
189189 free (strBuf);
190190 return str;
@@ -214,6 +214,41 @@ std::string getMxArrayString(const mxArray* mxArrayStr) {
214214 * See matlabroot/simulink/src/sfuntmpl_doc.c for more details.
215215 */
216216
217+ class LogMatlab : public FGLogConsole
218+ {
219+ public:
220+ LogMatlab (SimStruct *s) : S(s) {}
221+ void Format (LogFormat format) override {} // Ignore text formatting.
222+ void Flush (void ) override {
223+ static char error_msg[1024 ];
224+ std::string message = buffer.str ();
225+ switch (log_level) {
226+ case LogLevel::BULK:
227+ case LogLevel::DEBUG:
228+ case LogLevel::INFO:
229+ case LogLevel::STDOUT:
230+ mexPrintf (" JSBSim: %s" , message.c_str ());
231+ break ;
232+ case LogLevel::WARN:
233+ mexWarnMsgIdAndTxt (" JSBSim:Warning" , message.c_str ());
234+ break ;
235+ case LogLevel::ERROR:
236+ case LogLevel::FATAL:
237+ {
238+ snprintf (error_msg, sizeof (error_msg), " %s" , message.c_str ());
239+ ssSetErrorStatus (S, error_msg);
240+ break ;
241+ }
242+ default :
243+ break ;
244+ }
245+ buffer.str (" " );
246+ }
247+ private:
248+ SimStruct *S;
249+ };
250+
251+
217252/* ====================*
218253 * S-function methods *
219254 *====================*/
@@ -227,32 +262,32 @@ static void mdlCheckParameters(SimStruct *S)
227262 ssSetErrorStatus (S," JSBSim S-function must have 6 parameters." );
228263 return ;
229264 }
230-
265+
231266 if (!mxIsChar (ac_name)) {
232267 ssSetErrorStatus (S, " Parameter 1 to JSBSim S-function must be a string." );
233268 return ;
234269 }
235-
270+
236271 if (!mxIsNumeric (ssGetSFcnParam (S, TIME_STEP_PARAM)) || delta_t < 0 ) {
237272 ssSetErrorStatus (S, " Parameter 2 to JSBSim S-function must be a nonnegative number." );
238273 return ;
239274 }
240-
275+
241276 if (!mxIsNumeric (ssGetSFcnParam (S, USE_SCRIPT_PARAM)) || !(use_script == 1 || use_script == 0 )) {
242277 ssSetErrorStatus (S, " Parameter 3 to JSBSim S-function must be either 0 (disabled) or 1 (enabled)." );
243- return ;
278+ return ;
244279 }
245-
280+
246281 if (!mxIsChar (script_name)) {
247282 ssSetErrorStatus (S, " Parameter 4 to JSBSim S-function must be a string." );
248283 return ;
249284 }
250-
285+
251286 if (!mxIsChar (reset_name)) {
252287 ssSetErrorStatus (S, " Parameter 5 to JSBSim S-function must be a string." );
253288 return ;
254289 }
255-
290+
256291 if (!mxIsChar (io_config_file_name)) {
257292 ssSetErrorStatus (S, " Parameter 6 to JSBSim S-function must be a string." );
258293 return ;
@@ -316,7 +351,7 @@ static void mdlProcessParameters(SimStruct *S)
316351
317352 // Configure the output port(s).
318353 if (!ssSetNumOutputPorts (S, numOutputs)) return ;
319-
354+
320355 int i;
321356 Element* outputElement = outputsElement->FindElement (" output" );
322357 int outputSize;
@@ -329,7 +364,7 @@ static void mdlProcessParameters(SimStruct *S)
329364 // to set the name.
330365
331366 outputElement = outputsElement->FindNextElement (" output" );
332- }
367+ }
333368}
334369#endif /* MDL_PROCESS_PARAMETERS */
335370
@@ -342,7 +377,7 @@ static void mdlInitializeSizes(SimStruct *S)
342377{
343378
344379 /* See sfuntmpl_doc.c for more details on the macros below */
345- ssSetNumSFcnParams (S, NUM_PARAMS); /* Number of expected parameter vectors*/
380+ ssSetNumSFcnParams (S, NUM_PARAMS); /* Number of expected parameter vectors*/
346381 if (ssGetNumSFcnParams (S) == ssGetSFcnParamsCount (S)) {
347382 mdlCheckParameters (S);
348383 mdlProcessParameters (S);
@@ -352,7 +387,7 @@ static void mdlInitializeSizes(SimStruct *S)
352387 }
353388
354389 // Create the work vectors.
355- if (!ssSetNumDWork ( S, useWeather ? 2 + numOutputs : 1 + numOutputs)) return ; // HW change
390+ if (!ssSetNumDWork ( S, useWeather ? 2 + numOutputs : 1 + numOutputs)) return ; // HW change
356391
357392 // Work vector for input port.
358393 ssSetDWorkWidth ( S, 0 , ssGetInputPortWidth (S,0 ));
@@ -369,7 +404,7 @@ static void mdlInitializeSizes(SimStruct *S)
369404 ssSetDWorkWidth ( S, i+1 , ssGetOutputPortWidth (S,i));
370405 ssSetDWorkDataType ( S, i+1 , SS_DOUBLE);
371406 }
372-
407+
373408 // Reserve element in the pointers vector to store the JSBSimInterface.
374409 ssSetNumPWork (S, 1 );
375410
@@ -405,11 +440,12 @@ static void mdlInitializeSampleTimes(SimStruct *S)
405440* restarts execution to reset the states.
406441*/
407442static void mdlInitializeConditions (SimStruct *S)
408- {
409-
443+ {
444+
410445 mexPrintf (" \n JSBSim S-Function is initializing...\n\n " );
411-
446+
412447 // Create new JSBSimInterface object and initialize it with delta_t and num_outputs.
448+ SetLogger (std::make_shared<LogMatlab>(S));
413449 JSBSimInterface *JII = new JSBSimInterface (delta_t , numOutputs);
414450 ssGetPWork (S)[0 ] = (void *) JII;
415451
@@ -449,7 +485,7 @@ static void mdlInitializeConditions(SimStruct *S)
449485 return ;
450486 }
451487 }
452-
488+
453489 // Get the user provided input/output config.
454490 std::string io_config_file = getMxArrayString (io_config_file_name);
455491
@@ -529,8 +565,8 @@ static void mdlInitializeConditions(SimStruct *S)
529565 * block.
530566 */
531567static void mdlOutputs (SimStruct *S, int_T tid)
532- {
533-
568+ {
569+
534570 real_T* output;
535571 double * dWorkVector;
536572 int i;
@@ -555,8 +591,8 @@ static void mdlOutputs(SimStruct *S, int_T tid)
555591 */
556592static void mdlUpdate (SimStruct *S, int_T tid)
557593{
558- /* send update inputs to JSBSimInterface, run one cycle,
559- retrieve state vector, and update sim state vector
594+ /* send update inputs to JSBSimInterface, run one cycle,
595+ retrieve state vector, and update sim state vector
560596 */
561597
562598 JSBSimInterface* JII = (JSBSimInterface*) ssGetPWork (S)[0 ];
@@ -569,7 +605,7 @@ static void mdlUpdate(SimStruct *S, int_T tid)
569605 ctrlVec[i] = (double ) *ctrlCmdInput[i];
570606 dWorkCtrlCmdIn[i] = *ctrlCmdInput[i];
571607 }
572-
608+
573609 if (!JII->CopyInputControlsToJSBSim (ctrlVec)) {
574610 ssSetErrorStatus (S, " Issue copying control inputs to JSBSim.\n " );
575611 return ;
@@ -591,7 +627,7 @@ static void mdlUpdate(SimStruct *S, int_T tid)
591627 }
592628
593629 JII->Update ();
594-
630+
595631 double *dWorkVector;
596632 for (i = 0 ; i < numOutputs; i++) {
597633 dWorkVector = (double *) ssGetDWork (S,i+1 );
@@ -608,7 +644,7 @@ static void mdlUpdate(SimStruct *S, int_T tid)
608644 */
609645static void mdlTerminate (SimStruct *S)
610646{
611-
647+
612648 JSBSimInterface *JII = (JSBSimInterface *) ssGetPWork (S)[0 ];
613649 delete JII;
614650
0 commit comments