%% Spawn and Synchronize Execution of RTOS Task
% This example shows how to simulate and generate code for asynchronous events 
% on a real-time multitasking system. The model contains an Async Interrupt 
% block, a Task Sync block, asynchronously executed subsystems |Count| and 
% |Algorithm|, and Rate Transition blocks. The Async Interrupt block creates 
% two Versa Module Eurocard (VME) interrupt service routines (ISRs) that pass 
% interrupt signals to subsystem |Count| and the Task Sync block.|Count| 
% executes at interrupt level. |Algorithm| executes as an asynchronous task. 
% The code that the code generator produces for subsystems is tailored for the
% VxWorks(R) operating system. 
%
%% About the Example Model
% Open the example model |rtwdemo_async|.
%
model=('rtwdemo_async');
open_system(model);
%%
% You can place an Async Interrupt block between a simulated interrupt source 
% and one of these model elements:
% 
% * Function call subsystem
% * Task Sync block
% * A Stateflow(R) chart configured for a function call input event
% * A referenced model with an Inport block that connects to one of the
% preceding model elements
% 
% The Async Interrupt and Task Sync blocks enable the subsystems to execute 
% asynchronously. Reconfigure the Async Interrupt and Task
% Sync blocks to generate code for an alternative run-time environment.
%
% |Count| represents a simple interrupt service routine (ISR) that executes
% at interrupt level. It is best to keep ISRs as simple as possible. This 
% subsystem includes only a Discrete-Time Integrator block.  
%
% |Algorithm| includes more substance.  It includes multiple blocks and 
% produces two output values. Execution of larger subsystems at interrupt
% level can significantly impact response time for interrupts of equal and
% lower priority in the system. A better solution for larger subsystems is
% to use the Task Sync block to represent the ISR for the function-call subsystem.
% 
% The Async Interrupt block generates calls to ISRs. Place the block between 
% a simulated interrupt source and one of the following: 
% 
% * Function call subsystem
% * Task Sync block
% * A Stateflow(R) chart configured for a function call input event
%
% For each specified interrupt level, the block generates a Versa Module Eurocard 
% (VME) ISR that executes the connected subsystem, Task Sync block, or chart.  
%
% In the example model, the Async Interrupt block is configured for VME
% interrupts 1 and 2, by using interrupt vector offsets 192 and 193. Interrupt 1 
% connects directly to subsystem |Count|. Interrupt 2 connects to a Task Sync 
% block, which serves as the ISR for |Algorithm|. Place a Task Sync block 
% in one of the following locations:
%
% * Between an Async Interrupt block and a function-call subsystem or 
% Stateflow(R) chart.  
% * At the output port of a Stateflow(R) chart that has an event, |Output to
% Simulink|, that you configure as a function call. 
%  
% In the example model, the Task Sync block is between the Async Interrupt 
% block and function-call subsystem |Algorithm|. The Task Sync block 
% is configured with the task name |Task()|, a priority of 50, a stack size 
% of 8192, and data transfers of the task synchronized with the caller task. 
% The spawned task uses a semaphore to synchronize task execution. The Async
% Interrupt block triggers a release of the task semaphore. 
%
% Four Rate Transition blocks handle data transfers between ports that operate at
% different rates. In two instances, Protected Rate Transition blocks protect 
% data transfers (prevent them from being preempted and corrupted). In the 
% other two instances, Unprotected Rate Transition blocks introduce no special
% behavior. Their presence informs Simulink(R) of a rate transition.
%
% The code generated for the Async Interrupt and Task Sync blocks is tailored 
% for the example RTOS (VxWorks(R)). However, you can modify the blocks to 
% generate code specific to your run-time environment.
% 
%% Data Transfer Assumptions
% 
% * Data transfers occur between one reading task and one writing task.
% * A read or write operation on a byte-size variable is atomic.
% * When two tasks interact, only one can preempt the other. 
% * For periodic tasks, the task with the faster rate has higher priority 
% than the task with the slower rate. The task with the faster rate preempts 
% the tasks with slower rates.
% * Tasks run on a single processor. Time slicing is not allowed.
% * Processes do not stop and restart, especially while data is being transferred 
%   between tasks.
%
%% Simulate the Model
%
% Simulate the model. By default, the model is configured to show sample times 
% in different colors.  Discrete sample times for input and output appear 
% red and green, respectively. Constants are reddish-blue. Asynchronous
% interrupts and tasks are purple. The Rate Transition Blocks, which are a 
% hybrid rate (their input and output sample times can differ), are yellow.
% 
%% Generate Code and Report
%
% Generate code and a code generation report for the model. Generated code for 
% the Async Interrupt and Task Sync blocks is for the example RTOS (VxWorks(R)). 
% However, you can modify the blocks to generate code for another 
% run-time environment.
%
% 1. Create a temporary folder for the build and inspection process.
%
currentDir = pwd;
[~,cgDir] = rtwdemodir();
%%
% 2. Build the model.
rtwbuild(model);
%% Review Initialization Code
%
% Open the generated source file |rtwdemo_async.c|. The initialization
% code:
%
% 1. Creates and initializes the synchronization semaphore |Task0_semaphore|.
%
cfile = fullfile(cgDir, 'rtwdemo_async_tornado_rtw', 'rtwdemo_async.c');
rtwdemodbtype(cfile, ...
    '/* Spawn task: Task0 with priority 50 */', ...
    'rtwdemo_async_DW.SFunction_IWORK.TaskID = taskSpawn("Task0",', ... 
    0, 0);
%%
% 2. Spawns task |task0| and assigns the task priority 50.
%
cfile = fullfile(cgDir, 'rtwdemo_async_tornado_rtw', 'rtwdemo_async.c');
rtwdemodbtype(cfile, ...
    'rtwdemo_async_DW.SFunction_IWORK.TaskID = taskSpawn("Task0",', ... 
    '/* End of Start for S-Function (vxinterrupt1): ''<Root>/Async Interrupt'' */', ... 
    1, 0);
%%
% 3. Connects and enables ISR |isr_num1_vec192| for interrupt 1 and ISR 
% |isr_num2_vec193| for interrupt 2.
%
cfile = fullfile(cgDir, 'rtwdemo_async_tornado_rtw', 'rtwdemo_async.c');
rtwdemodbtype(cfile, ...
    '/* End of Start for S-Function (vxinterrupt1): ''<Root>/Async Interrupt'' */', ... 
    '/* InitializeConditions for DiscretePulseGenerator: ''<Root>/20 Hz ISR'' */', ... 
    0, 0);
%%
% The order of these operations is important. Before the code generator enables 
% the interrupt that activates the task, it must spawn the task.
%
%% Review Task and Task Synchronization Code
%
% In the generated source file |rtwdemo_async.c|, review the task and task 
% synchronization code. 
%
% The code generator produces the code for function |Task0| from the Task 
% Sync block. That function includes a small amount of interrupt-level code
% and runs as an RTOS task.
%
% The task waits in an infinite |for| loop until the system releases a 
% synchronization semaphore. If the system releases the semaphore, the 
% function updates its task timer and calls the code generated for the 
% |Algorithm| subsystem.
%
% In the example model, the *Synchronize the data transfer of this task with  
% the caller task* parameter for the Task Sync block is set. This parameter 
% setting updates the timer associated with the Task Sync block 
% (|rtM->Timing.clockTick2|) with the value of the timer that the Async 
% Interrupt block (|rtM->Timing.clockTick3|) maintains. As a result, code 
% for blocks within the |Algorithm| subsystem use timer values that are based 
% on the time of the most recent interrupt, rather than the most recent 
% activation of |Task0|.
%
cfile = fullfile(cgDir, 'rtwdemo_async_tornado_rtw', 'rtwdemo_async.c');
rtwdemodbtype(cfile, ...
    'void Task0(void)', ... 
    'time_T rt_SimUpdateDiscreteEvents(', ... 
    0, 1);
%%
% The code generator produces code for ISRs |isr_num1_vec192| and 
% |isr_num2_vec293|. ISR |isr_num2_vec192|:
%
% * Disables interrupts.
% * Saves floating-point context.
% * Calls the code generated for the subsystem that connects 
% to the referenced model Inport block, which receives the interrupt.
% * Restores floating-point context.
% * Reenables interrupts. 
%
cfile = fullfile(cgDir, 'rtwdemo_async_tornado_rtw', 'rtwdemo_async.c');
rtwdemodbtype(cfile, ...
    'void isr_num1_vec192(void)', ...
    'void isr_num2_vec193(void)', ... 
    1, 0);
%%
% ISR |isr_num2_vec293| maintains a timer that stores the tick count at the 
% time that the interrupt occurs. After updating the timer, the ISR releases  
% the semaphore that activates |Task0|.
%
cfile = fullfile(cgDir, 'rtwdemo_async_tornado_rtw', 'rtwdemo_async.c');
rtwdemodbtype(cfile, ...
    '/* Spawned with priority: 50 */', ... 
    'void isr_num2_vec193(void)', ...
    1, 0);
%
%% Review Task Termination Code
% The Task Sync block generates the following termination code.
%
cfile = fullfile(cgDir, 'rtwdemo_async_tornado_rtw', 'rtwdemo_async.c');
rtwdemodbtype(cfile, ...
    'static void rtwdemo_async_terminate(void)', ...
    '/*========================================================================*', ... 
    1, 0);
%% Related Information
% * <docid:rtw_ref.bu_98v5 Async Interrupt>
% * <docid:rtw_ref.bqnrjmx-1 Task Sync>
% * <docid:rtw_ug.f9453 Generate Interrupt Service Routines>
% * <docid:rtw_ug.f29370 Timers in Asynchronous Tasks>
% * <docid:rtw_ug.f10041 Create a Customized Asynchronous Library>
% * <docid:rtw_ug.bsyjz_c Import Asynchronous Event Data for Simulation>
% * <docid:simulink_ug.bsuwmmp Load Data to Root-Level Input Ports>
% * <docid:rtw_ug.f23284 Asynchronous Events>
% * <docid:rtw_ug.f10930 Rate Transitions and Asynchronous Blocks>
% * <docid:rtw_ug.bqpnsgq Asynchronous Support Limitations>
%%
bdclose(model);
rtwdemoclean;
cd(currentDir);

%% 
% Copyright 2019 The MathWorks, Inc.