%%
%%
%%
%%
%%Copyright1994-2013TheMathWorks,Inc.
%%
%%Abstract:TransportDelayblocktargetfile
 
%implements TransportDelay "C"
 
%include "tdelay_sup.tlc"
 
%%Function:FcnTDelayTypeSetup===============================================
%%Abstract:
%function BlockTypeSetup(block, system) void
  %<TDelayTypeSetup(block, system)>
%endfunction
 
%%Function:FcnTDelayStart====================================================
%%Abstract:
%%StartcodefortheTransportDelayblocks
%%
%%o)Initializetheworkvectors
%%
%function Start(block, system) Output
   %assign isRSIM = isRSim
  {
    %assign blockWidth = LibBlockOutputSignalWidth(0)
    %%
    %% Initialize
    %%
    %% For RSIM, we need to allocate the pBuffer for
    %% each element in the output port separately. This
    %% is because if we need to grow the buffer, then we
    %% we will free the memory associated with the buffer
    %% so there can't be a single buffer for the block.
    %if !isRSIM
      real_T *pBuffer = &%<LibBlockRWork(TUbufferArea, "", "", 0)>;
    %endif
     
    %% Do not change this value without updating the
    %% code below for allocating pbuffer
    %assign localRollThreshold = 2
     
    %%
    %% Declare a local constant buffer size array and/or initial output
    %% array if needed (when rolling)
    %%
    %assign useConstBufSzVect = 0
 
    %if WILL_ROLL(RollRegions, localRollThreshold)
      %%
      %% Buffer size array for roller
      %%
      %if SIZE(ParamSettings.BufferSize,1) > 1
        %<LibGenConstVectWithInit(ParamSettings.BufferSize,tSS_INT32,"bufSz")>
    %assign useConstBufSzVect = 1
      %endif
     
    %endif
 
    %assign rollVars = ["/Tail","/Head",...
      "/Last","/CircularBufSize",...
      "/TUbufferPtrs", "/InitialOutput"]
 
    %roll idx = RollRegions, lcv = localRollThreshold, block, "Roller", rollVars
             
      %%
      %% Compute buffer size
      %%
      %if lcv == ""
    %assign paramSettingIdx = idx
      %else
    %if idx == 0
      %assign paramSettingIdx = lcv
    %else
      %assign paramSettingIdx = "%<lcv> + %<idx>"
    %endif
      %endif
 
      %if useConstBufSzVect
    %assign bufSz = "bufSz[%<paramSettingIdx>]"
      %else
    %assign bufSz = (SIZE(ParamSettings.BufferSize,1) == 1? ...
      ParamSettings.BufferSize[0]: ...
      ParamSettings.BufferSize[paramSettingIdx])
      %endif
             
      %%
      %% Initialize the iwork and pointer work vectors
      %%
      %assign tail = LibBlockIWork(Tail,"",lcv,idx)
      %assign head = LibBlockIWork(Head,"",lcv,idx)
      %assign last = LibBlockIWork(Last,"",lcv,idx)
      %assign bufferSiz = LibBlockIWork(CircularBufSize,"",lcv,idx)
      %assign initOutput= LibBlockParameter(InitialOutput, "",lcv,idx)
       
      %if isRSIM
        %% We need an extra {} if we aren't rolling to make
        %% sure that we avoid symbol clashing for pbuffer
        %if lcv == ""
          {
        %endif
        %% first call unitility to generate rt_TDelayCreateBuf
        %% This is called instead of utMalloc() in order to avoid Windows-specific
        %% crash due to mallocing and freeing in different libs.
        %assign utilName = TDelay_CreateBuf(block)
        real_T *pBuffer = (real_T *)%<utilName>(2, %<bufSz>, sizeof(real_T));
        if (pBuffer == %<SLibGetNullDefinitionFromTfl()>) {
          %<RTMSetErrStat("/"tdelay memory allocation error/"")>;
          return;
        }
      %endif
 
      %<tail> = 0;
      %<head> = 0;
      %<last> = 0;
      %<bufferSiz> = %<bufSz>;
      %%
      pBuffer[0] = %<initOutput>;
      pBuffer[%<bufSz>] = %<LibGetT()>;
      %%
      %if lcv != ""
    %assign pUbuf = LibBlockPWork(TUbufferPtrs, "", lcv, idx)
    %assign pTbuf = LibBlockPWork(TUbufferPtrs, "", ...
      "%<lcv>+%<blockWidth>", idx)
      %else
    %assign pUbuf = LibBlockPWork(TUbufferPtrs, "", lcv, idx)
    %assign pTbuf = LibBlockPWork(TUbufferPtrs, "", lcv, idx+blockWidth)
      %endif
      %%
      %<pUbuf> = (void *) &pBuffer[0];
      %<pTbuf> = (void *) &pBuffer[%<bufSz>];
 
      %% Never do this for RSIM because we allocate separate pbuffers
      %% for each output element.
      %if !isRSIM && ((lcv != "") || (lcv == "" && idx < blockWidth-1))
    %if TYPE(bufSz) == "Number"
      pBuffer += %<2*bufSz>;
    %else
      pBuffer += 2*%<bufSz>;
    %endif
      %endif
       
      %if isRSIM && lcv == ""
        }
      %endif
    %endroll
  }
%endfunction %%End FcnTDelayStart
 
 
%%Function:FcnIsReal=========================================================
%%Abstract:
%%Givenastring,doesevaluationofthisstringresultinanumber.
%%Forexampleifstr="1.0",then%<str>==1.0
%%Ifstr="a2",then%<str>wouldbeanerror.
%%
 
%%ThisfunctionisneededbecauseLibBlockParameteralwaysreturnsastring,
%%weneedtofindoutifthisstringisanumber.TodothisweuseFEVAL
%%tocallamatlabfunctionthatparsestheresultanttype.
%%
 
%function FcnIsReal(strValue)
 
  %assign temp = FEVAL("sscanf",strValue,"%f%1s")
  %return SIZE(temp,0) == 1
 
%endfunction %%End FcnIsReal
 
 
%%Function:FcnTDelayOutputs==================================================
%%Abstract:
%%Usingthetransportdelay'state'information,delaytheinputbythe
%%specifiedamountoftime,simulatingatimedelay.
%%y=u[t-delay]
%function Outputs(block, system) Output
  {
    %assign blockWidth = LibBlockOutputSignalWidth(0)
    %assign inport0Width = LibBlockInputSignalWidth(0)
    %%
    %% If needed, setup static const vectors to capture:
    %% - what input port 0 signals are discrete
    %% - what the buffer sizes are
    %% This is done, only if the block will 'roll' and these vectors are
    %% of length greater than 1.
    %%
    %assign useConstIsDiscVect = 0
    %assign localRollThreshold = 2
    %assign tMinusDelayValue = ""
 
    %if WILL_ROLL(RollRegions, localRollThreshold)
 
      %if SIZE(ParamSettings.DiscreteInput,1) > 1
    %<LibGenConstVectWithInit(ParamSettings.DiscreteInput,...
      tSS_BOOLEAN,"isDiscrete")>
    %assign useConstIsDiscVect = 1
      %endif
              
    %elseif blockWidth == 1
 
      %assign delay = LibBlockParameter(DelayTime, "", "", 0)
       
      %if FcnIsReal(delay)
    %if %<delay> > 0.0
      %assign tMinusDelayValue = "= simTime - %<delay>"
    %else
      %assign tMinusDelayValue = "= simTime"
    %endif
      %else
    %assign tMinusDelayValue = "= simTime - %<delay>"
      %endif
     
    %endif
    %%
    %% Declare local variables
    %%
     
    %% Simple y = u csae
    %assign notTunable = !SLibBlockParameterIsTunable(DelayTime)
    %assign hasZeroDelay = (ParamSettings.DirectFeedThrough == "yes")
 
    %% hard to determine here, just use width =1 for now.
    %assign allDelayAreZeros = (blockWidth == 1)
    %assign notTunableZeroDelay = notTunable && hasZeroDelay && allDelayAreZeros
 
    %if !notTunableZeroDelay
         
        real_T **uBuffer = (real_T**)&%<LibBlockPWork(TUbufferPtrs,"","",0)>;
        real_T **tBuffer = (real_T**)&%<LibBlockPWork(TUbufferPtrs,"","",blockWidth)>;
        real_T simTime = %<LibGetT()>;
 
        real_T tMinusDelay %<tMinusDelayValue>;
    %endif
     
    %if ::CompiledModel.StartTime != 0.0
      %assign tStart = RTMGet("TStart")
    %else
      %assign tStart = 0.0
    %endif
        
     
    %%
    %% Produce the output (roll it!)
    %%
     
    %if ParamSettings.DirectFeedThrough == "no"
      %assign rollVars = ["y0","/DelayTime",...
      "/InitialOutput ", "/Tail","/Head",...
      "/Last","/CircularBufSize"]
    %else
      %assign rollVars = ["y0","u0","/DelayTime",...
      "/InitialOutput","/Tail","/Head",...
      "/Last","/CircularBufSize"]
    %endif
   
    %roll idx = RollRegions, lcv = localRollThreshold, block, "Roller", rollVars
     
      %assign tail = LibBlockIWork(Tail, "", lcv, idx)
      %assign head = LibBlockIWork(Head, "", lcv, idx)
      %assign last = LibBlockIWork(Last, "", lcv, idx)
      %assign initOutput = LibBlockParameter(InitialOutput, "",lcv,idx)
       
      %assign y = LibBlockOutputSignal(0, "", lcv, idx)
                      
      %if lcv == ""
    %assign paramSettingIdx = idx
      %else
    %if idx == 0
      %assign paramSettingIdx = lcv
    %else
      %assign paramSettingIdx = "%<lcv> + %<idx>"
    %endif
      %endif
 
      %if useConstIsDiscVect
    %assign isDiscrete = "isDiscrete[%<paramSettingIdx>]"
      %else
    %assign isDiscrete = (SIZE(ParamSettings.DiscreteInput,1) == 1? ...
      ParamSettings.DiscreteInput[0]: ...
      ParamSettings.DiscreteInput[paramSettingIdx])
      %endif
 
      %assign bufSz = LibBlockIWork(CircularBufSize, "", lcv, idx)
           
      %if ( Accelerator || isRSim || ...
    CodeFormat == "S-Function" || ...
    SolverType == "VariableStep" || ...
    IsModelReferenceForASimstructBasedTarget() )
    %assign minorStepAndTAtLastMajorOutput = ...
      "(boolean_T) " ...
      "(%<RTMIs("MinorTimeStep")> && " ...
      "(%<RTMGet("TimeOfLastOutput")> == %<LibGetT()>))"
      %else
    %assign minorStepAndTAtLastMajorOutput = 0
      %endif
         
      %if tMinusDelayValue == ""
     
    %assign delay = LibBlockParameter(DelayTime, "", lcv, idx)
         
    %if FcnIsReal(delay)
      %if %<delay> > 0.0
        tMinusDelay = simTime - %<delay>;
      %else
        tMinusDelay = simTime;
      %endif
    %else
      tMinusDelay = ((%<delay> > 0.0) ? %<delay> : 0.0);
      tMinusDelay = simTime - tMinusDelay;
    %endif
      %endif
 
      %% The cast to boolean_T above is to avoid MSVC warning C4761:
      %% "integral size mismatch in argument; conversion supplied"
       
      %% First call unitility to generate rt_TDelayInterpolate
      %assign utilName = TDelay_Interpolate(block)
      %% Then call it.
       
      %if (!SLibBlockParameterIsTunable(DelayTime)) && (blockWidth == 1)
        %if ParamSettings.DirectFeedThrough == "no"
          %<y> = %<utilName>(
          tMinusDelay,
          %<tStart>,
          *tBuffer,
          *uBuffer,
          %<bufSz>,
          &%<last>,
          %<tail>,
          %<head>,
          %<initOutput>,
          %<isDiscrete>,
          %<minorStepAndTAtLastMajorOutput>);
        %else
          %assign u0 = LibBlockInputSignal(0, "", lcv, idx)
          /* Delay time is 0 and inline parameter is on */
          %<y> = %<u0>;
        %endif
      %else
        %%
        %if ParamSettings.DirectFeedThrough == "yes"
          if (%<delay> == 0.0)
          %assign u0 = LibBlockInputSignal(0, "", lcv, idx)
          %<y> = %<u0>;
          else
        %endif
         
        %<y> = %<utilName>(
        tMinusDelay,
        %<tStart>,
        *tBuffer,
        *uBuffer,
        %<bufSz>,
        &%<last>,
        %<tail>,
        %<head>,
        %<initOutput>,
        %<isDiscrete>,
        %<minorStepAndTAtLastMajorOutput>);
      %endif
       
      %if (lcv != "") || (lcv == "" && idx < blockWidth-1)
    tBuffer++; uBuffer++;
      %endif
       
    %endroll
  }
%endfunction %%End FcnTDelayOutputs
 
 
%%Function:FcnTDelayUpdate===================================================
%%Abstract:
%%Updatethestateinformationofthetransportdelay.
%%
%function Update(block, system) Output
  {
    %assign blockWidth = LibBlockOutputSignalWidth(0)
    %assign inport0Width = LibBlockInputSignalWidth(0)
    real_T **uBuffer = (real_T**)&%<LibBlockPWork(TUbufferPtrs,"","",0)>;
    real_T **tBuffer = (real_T**)&%<LibBlockPWork(TUbufferPtrs,"","",...
      blockWidth)>;
        
    real_T simTime = %<LibGetT()>;
     
    %if (ParamSettings.FixedBuffer == "yes" )
      %assign isFixedbuf = TLC_TRUE
      boolean_T bufferisfull = %;
    %else
      %assign isFixedbuf = TLC_FALSE
    %endif
     
    %assign rollVars = ["u0", "/Tail","/Head", ...
      "/CircularBufSize"]
         
    %if Accelerator || isRSim
      %assign delayPrm = "DelayTime"
      %assign rollVars = ["u0", "/Tail","/Head", ...
    "/Last", "/CircularBufSize", "/%<delayPrm>"]
      %assign maxNewBufSz = LibBlockIWork(MaxNewBufSize, "", "", 0)
    %endif
 
    %roll idx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars
      %assign tail = LibBlockIWork(Tail, "", lcv, idx)
      %assign head = LibBlockIWork(Head, "", lcv, idx)
      %assign bufSz = LibBlockIWork(CircularBufSize, "", lcv, idx)
       
      %<head> = ((%<head> < (%<bufSz>-1)) ? (%<head>+1) : 0);
 
      if (%<head> == %<tail>) {
        %if isFixedbuf
          bufferisfull = %;
        %endif
         
        %if Accelerator || isRSim
      %assign last = LibBlockIWork(Last, "", lcv, idx)
      %assign tDelay = LibBlockParameter(%<delayPrm>, "", lcv, idx)
      %assign tMinusDelay = "simTime - %<tDelay>"
           
          %% first call unitility to generate rt_TDelayUpdateTailOrGrowBuf
          %assign utilName = TDelay_UpdateTailOrGrowBuf(block)
           
          %% Then call this function
      if (!%<utilName>( &%<bufSz>, ...
        &%<tail>, &%<head>, &%<last>, %<tMinusDelay>, ...
        tBuffer, uBuffer, %<SLibGetNullDefinitionFromTfl()>, (boolean_T)%<isFixedbuf>, ...
            %, &%<maxNewBufSz>)) {
            %<RTMSetErrStat("/"tdelay memory allocation error/"")>;
            return;
          }
    %else
      %% Handle buffer overflows by loosing oldest data.
      %<tail> = ((%<tail> < (%<bufSz>-1)) ? (%<tail>+1) : 0);
    %endif
      }
       
      %if (lcv != "") || (lcv == "" && idx < blockWidth-1)
    %assign pp = "++"
      %else
    %assign pp = ""
      %endif
      (*tBuffer%<pp>)[%<head>] = simTime;
      %if (inport0Width == 1)
        %% Input is scalar, no need to roll here, see g1408910
        (*uBuffer%<pp>)[%<head>] = %<LibBlockInputSignal(0, "", "", 0)>;
      %else
        (*uBuffer%<pp>)[%<head>] = %<LibBlockInputSignal(0, "", lcv, idx)>;
      %endif
    %endroll
    %if isFixedbuf
      if (bufferisfull){
        %<RTMSetBlockStateForSolverChangedAtMajorStep()>;
        %<RTMSetContTimeOutputInconsistentWithStateAtMajorStep()>;
      }
    %endif
  }
%endfunction %%End FcnTDelayUpdate
 
%%Function:Terminate========================================================
%%Abstract:
%%FreePWorksusedwithRSimtarget
%%
%function Terminate(block, system) Output
  %<TDelay_Terminate(block, system)>
%endfunction %% Terminate
 
 
%%[EOF]tdelay.tlc