%% $Revision: 1.1.6.21 $
%% 
%%
%% Copyright 1994-2004 The MathWorks, Inc.
%%
%% Abstract:
%%   This TLC library file contains the general purpose utility functions.
%%

%if EXISTS("_UTILLIB_") == 0
%assign _UTILLIB_ = 1


%% Function: SLibGenerateCodeOnly ===============================================
%% Abstract:
%%   Return true if the code generation only button is not selected, and false
%%   otherwise.
%%
%function SLibGenerateCodeOnly() void
  %return FEVAL("rtwprivate","rtwattic","getParam",Name,...
    "RTWGenerateCodeOnly") == "on"
%endfunction

%% Function: SLibIndentFile =====================================================
%% Abstract:
%%   Indent a file with c_indent from within TLC.
%%
%function SLibIndentFile(name,opts) void
  %if opts == ""
    %<FEVAL("rtwprivate","rtwattic","c_indent_from_tlc",name)>
  %else
    %<FEVAL("rtwprivate","rtwattic","c_indent_from_tlc",name,opts)>
  %endif
%endfunction

%% DocFunction{BlkPathAndErrFcns}: LibBlockReportWarning =======================
%% Abstract:
%%   This should be used when reporting warnings for a block. This function
%%   is designed to be used from block target files (e.g. the TLC file for an
%%   inlined S-function).
%%
%%   This function can be called with or without the block record scoped.
%%   To call this function without a block record scoped, pass the block record.
%%   To call this function when the block is scoped, pass block = [].
%%   Specifically:
%%
%%     LibBlockReportWarning([],"warn string")          -- If block is scoped
%%     LibBlockReportWarning(blockrecord,"warn string") -- If block record is
%%                                                         available
%%
%function LibBlockReportWarning(block,warnstring) void

 %if TYPE(block) != "Vector"
    %assign blockName = LibGetFormattedBlockPath(block)
    %assign type      = block.Type
  %else
    %assign blockName = LibMangledPathName(Name)
    %assign type      = Type
  %endif

  %openfile warnMessage
Real-Time Workshop -- In block "%<blockName>", block type "%<type>": %<warnstring>
  %closefile warnMessage

  %warning %<warnMessage>

%endfunction %% LibBlockReportWarning


%% DocFunction{BlkPathAndErrFcns}: LibBlockReportError =========================
%% Abstract:
%%   This should be used when reporting errors for a block. This function
%%   is designed to be used from block target files (e.g. the TLC file for
%%   an inlined S-function).
%%
%%   This function can be called with or without the block record scoped.
%%   To call this function without a block record scoped, pass the block
%%   record. To call this function when the block is scoped, pass block = [].
%%   Specifically:
%%
%%     LibBlockReportError([],"error string")          -- If block is scoped
%%     LibBlockReportError(blockrecord,"error string") -- If block record is
%%                                                        available
%%
%function LibBlockReportError(block,errorstring) void

  %<SLibReportError("Real-Time Workshop Error",block,errorstring)>

%endfunction %% LibBlockReportError


%% DocFunction{BlkPathAndErrFcns}: LibBlockReportFatalError ====================
%% Abstract:
%%   This should be used when reporting fatal (assert) errors for a block.
%%   Use this function for defensive programming. TLC Error Message appendix in
%%   the TLC reference manual.
%%
%function LibBlockReportFatalError(block,errorstring) void

  %setcommandswitch "-v1"
  %<SLibReportError("Real-Time Workshop Fatal",block,errorstring)>

%endfunction %% LibBlockReportFatalError


%% Function{BlkPathAndErrFcns}: LibReportWarning ===============================
%% Abstract:
%%   This should be used when reporting non-block based warnings. This
%%   function prepends the errorstring argument with 'Real-Time Workshop: '
%%
%function LibReportWarning(warnstring) void
  %openfile warnMessage
Real-Time Workshop: %<warnstring>
  %closefile warnMessage

  %warning %<warnMessage>

%endfunction %% LibReportWarning


%% Function: LibReportError{BlkPathAndErrFcns} =================================
%% Abstract:
%%   This should be used when reporting non-block based errors. This
%%   function prepends the errorstring argument with 'Real-Time Workshop
%%   Error: ').
%%
%function LibReportError(errorstring) void
  %openfile errorMessage
Real-Time Workshop Error: %<errorstring>
  %closefile errorMessage

  %exit %<errorMessage>

%endfunction %% LibReportError


%% Function{BlkPathAndErrFcns}: LibReportFatalError ============================
%% Abstract:
%%   This should be used when reporting non-block based fatal errors.
%%   This function should only be used for asserts. See the TLC Error
%%   Message appendix in the TLC reference manual. This function prepends
%%   the errorstring argument with 'Real-Time Workshop Fatal: ').
%%
%function LibReportFatalError(errorstring) void
  %setcommandswitch "-v1"
  %openfile errorMessage
Real-Time Workshop Fatal: %<errorstring>
  %closefile errorMessage

  %exit %<errorMessage>

%endfunction %% LibReportFatalError


%% Function{BlkPathAndErrFcns}: SLibReportError ================================
%% Abstract:
%%   Report either a usage or fatal error for a block.
%%
%function SLibReportError(location,block,errorstring) void

 %if TYPE(block) != "Vector"
    %assign blockName = LibGetFormattedBlockPath(block)
    %assign type      = block.Type
  %else
    %assign blockName = LibMangledPathName(Name)
    %assign type      = Type
  %endif

  %openfile errorMessage
%<location> in block: "%<blockName>", block type "%<type>": %<errorstring>
  %closefile errorMessage

  %exit %<errorMessage>
%endfunction %% SLibReportError



%% DocFunction{Other Useful Functions}: LibIsComplex ===========================
%% Abstract:
%%   Returns 1 if the argument passed in is complex, 0 otherwise.
%%
%function LibIsComplex(arg) void
  %% This function determines if the argument passed in is complex.

  %%---------------------------------------
  %% Argument         Real        Complex
  %%---------------------------------------
  %% Double:          Real        Complex
  %% Single:          Real32      Complex32
  %% Signed ints:     Number      Gaussian
  %% Unsigned ints:   Unsigned    UnsignedGaussian
  %%---------------------------------------

  %assign arg_type = TYPE(arg[0])
  %return ( (arg_type == "Complex") || ...
            (arg_type == "Complex32") || ...
            (arg_type == "Gaussian") || ...
            (arg_type == "UnsignedGaussian") )

%endfunction %% LibIsComplex


%% DocFunction{Sample Time Functions}: LibIsDiscrete ===========================
%% Abstract:
%%   Returns 1 if the specified task identifier (TID) is discrete, 0 otherwise.
%%   Note, task identifiers equal to "triggered" or "constant" are not discrete.
%%
%function LibIsDiscrete(TID) void
  %if TYPE(TID) == "Number" || TYPE(TID) == "Vector"
    %assign period = CompiledModel.SampleTime[TID[0]].PeriodAndOffset[0]
    %if period > 0.0
      %return 1
    %else
      %return 0
    %endif
  %elseif LibTriggeredTID(TID) || ISEQUAL(TID, "constant")
    %return 0
  %else
    %<LibReportFatalError("Invalid TID (%<TID>)")>
  %endif
%endfunction %% LibIsDiscrete


%% DocFunction{Sample Time Functions}: LibIsContinuous =========================
%% Abstract:
%%   Returns 1 if the specified task identifier (TID) is continuous, 0 otherwise.
%%   Note, TIDs equal to "triggered" or "constant" are not continuous.
%%
%function LibIsContinuous(TID) void
  %if TYPE(TID) == "Number"
    %assign period = CompiledModel.SampleTime[TID].PeriodAndOffset[0]
    %assign offset = CompiledModel.SampleTime[TID].PeriodAndOffset[1]
    %if period == 0.0 && offset == 0.0
      %return 1
    %else
      %return 0
    %endif
  %elseif LibTriggeredTID(TID) || ISEQUAL(TID, "constant")
    %return 0
  %else
    %<LibReportFatalError("Invalid TID (%<TID>)")>
  %endif
%endfunction %% LibIsContinuous

%% DocFunction{Sample Time Functions}: LibIsZOHContinuous ======================
%% Abstract:
%%   Returns 1 if the specified task identifier (TID) is ZOH continuous, 
%%   0 otherwise.
%%   Note, TIDs equal to "triggered" or "constant" are not ZOH continuous.
%%
%function LibIsZOHContinuous(TID) void
  %if TYPE(TID) == "Number"
    %assign period = CompiledModel.SampleTime[TID].PeriodAndOffset[0]
    %assign offset = CompiledModel.SampleTime[TID].PeriodAndOffset[1]
    %if period == 0.0 && offset == 1.0
      %return 1
    %else
      %return 0
    %endif
  %elseif LibTriggeredTID(TID) || ISEQUAL(TID, "constant")
    %return 0
  %else
    %<LibReportFatalError("Invalid TID (%<TID>)")>
  %endif
%endfunction %% LibIsContinuous


%% DocFunction{Other Useful Functions}: LibIsMinorTimeStep=====================
%% Abstract:
%%  
%%   Returns a string to access whether the current simulation step is
%%   is a minor time step.
%%
%%   This function is the TLC version of the SimStruct macro:  ssIsMinorTimeStep
%%
%function LibIsMinorTimeStep() void

  %return RTMIs("MinorTimeStep")

%endfunction %% LibIsMinorTimeStep


%% DocFunction{Other Useful Functions}: LibIsMajorTimeStep=====================
%% Abstract:
%%  
%%   Returns a string to access whether the current simulation step is
%%   is a major time step.
%%
%%   This function is the TLC version of the SimStruct macro: ssIsMajorTimeStep
%%
%function LibIsMajorTimeStep() void

  %return RTMIs("MajorTimeStep")

%endfunction %% LibIsMajorTimeStep


%% DocFunction{Other Useful Functions}: LibGetT ================================
%% Abstract:
%%   Return a string to access the absolute time. You should only use this
%%   function to access time. 
%%
%%   This function is the TLC version of the SimStruct macro: ssGetT.
%%
%function LibGetT() void
  %if CodeFormat == "Embedded-C"
    %return LibGetTaskTime(0)
  %else
    %return RTMGet("T")
  %endif

%endfunction %% LibGetT


%% DocFunction{Other Useful Functions}: LibGenConstVectWithInit ================
%% Abstract:
%%   Return an initialized static constant variable string of form:
%%
%%      static const typeName varId[] = { data };
%%
%%   The typeName is generated from typeId which can be one of:
%%     tSS_DOUBLE, tSS_SINGLE, tSS_BOOLEAN, tSS_INT8, tSS_UINT8, 
%%     tSS_INT16, tSS_UINT16, tSS_INT32, tSS_UINT32,
%%
%%   The data input argument must be a numeric scalar or vector and must
%%   be finite (no Inf, -Inf, or NaN values).
%%
%%   Note, this function is provided for C-code targets only.
%%
%function LibGenConstVectWithInit(data, typeId, varId) 

  %if SIZE(data,0) > 1 && SIZE(data,1) 
    %assign err = "LibGenConstVectWithInit must be called with a scalar"...
      "or vector data"
    %<LibReportError(err)>
  %endif

  %assign tmpVar = temp { Value  data ; DataTypeIdx typeId }
  %assign vals   = LibPrepParameter(temp)
  %openfile initializer
  %assign nonFiniteIndices = GENERATE_FORMATTED_VALUE(vals, "")
  %closefile initializer
  
  
  %if nonFiniteIndices[0][0] > 0
    %assign err = "LibGenConstVectWithInit called with nonfinite " ...
      "data values"
    %<LibReportError(err)>
  %endif
  %assign type = LibGetDataTypeNameFromId(typeId)

  %openfile str
  %if SIZE(data,0) == 1 && SIZE(data,1) == 1
    %assign brackets = ""
  %else
    %assign brackets = "[]"
  %endif
  static const %<type> %<varId>%<brackets> = %<initializer>;
  %closefile str
  
  %return str

%endfunction %% end LibGenConstVectWithInit 


%% Function: LibTaskComment ====================================================
%% Abstract:
%%   Produces a sample time comment containing period
%%   and offset given a task identifier.
%%
%function LibTaskComment(tid) void
  %if TYPE(tid) == "Number"
    %assign period = CompiledModel.SampleTime[tid].PeriodAndOffset[0]
    %assign offset = CompiledModel.SampleTime[tid].PeriodAndOffset[1]
    %return "/* Sample time: [%<period>s, %<offset>s] */"
  %elseif WHITE_SPACE(tid)
    %return ""
  %else
    %return "/* Sample time: %<tid> */"
  %endif
%endfunction %% LibTaskComment


%% Function: LibNeedTID ========================================================
%% Abstract:
%%   LibNeedTID sets the global flag CompiledModel.NeedTID to TLC_TRUE.
%%   TID is a argument that must be passed in from the parent, so the
%%   subsystem block propagates this flag up in the system hierarchy.
%%
%function LibNeedTID() void
  %assign ::CompiledModel.NeedTID = TLC_TRUE
%endfunction %% LibNeedTID


%% Function: LibNeedCPI ========================================================
%% Abstract:
%%   LibNeedCPI sets the system flag NeedCPIInOutputUpdate (Control Port
%%   Index) flag.  This flag is needed when a function-call subsystem
%%   trigger port block has outputs and the control width is greater
%%   than one.  It needs to be attached to the system because system code
%%   generation recurses and using one global flag is not possible.
%%
%function LibNeedCPI(system) void
  %<LibSetSystemField(system, "NeedCPIInOutputUpdate", TLC_TRUE)>
%endfunction


%% Function: LibTID ============================================================
%% Abstract:
%%   LibTID returns tid and informs the code generator that the tid is
%%   used in the context of this call.
%%   This function should always be used instead of hard-coding %<tTID>.
%%
%function LibTID() void
  %<LibNeedTID()>
  %return tTID
%endfunction %% LibTID


%% DocFunction{Sample Time Functions}: LibGetTaskTimeFromTID ===================
%% Abstract:
%%   Returns a string to access the absolute time of the task accociated with
%%   the block. 
%%   If the block is constant or the system is single rate, this is the TLC 
%%   version of the SimStruct macro: "ssGetT(S)" and "ssGetTaskTime(S, tid)" 
%%   otherwise.  In both cases, S is the name of the SimStruct. 
%%
%function LibGetTaskTimeFromTID(block) void
  %% ----------------------
  %% This warning message it temporary turned off because State-flow has not updated yet.
  %% This warning message need to be turned after state-flow blocks have be updated, and 
  %% register NeedAbsoluteTime whenever absolute time is required. 
  %% ---------------------
  %% %if !ISFIELD(block, "NeedAbsoluteTime")
  %%   %LibBlockReportWarnin(block, "Absolute time is required. The block does not " + ...
  %% "regesiter NeedAbsolute Time. Obsolete absoluter time will be used."
  %% %endif
    
  %if CodeFormat == "Embedded-C"
    %assign tid = SLibGetNumericTID(block)
    %return RTMGetTaskTimeForTID(tid)
  %else
    %if ISEQUAL(TID, "constant") || ...
      LibIsSingleRateSystem(System[NumSystems-1])
      %return RTMGet("T")
    %else
      %return RTMGetTaskTimeForTID(LibTID())
    %endif
  %endif
%endfunction %% LibGetTaskTimeFromTID

%% DocFunction{Sample Time Functions}: LibGetTaskTime ===================
%% Abstract:
%%   Returns a string to access the absolute time of the task. 
%% This function is the TLC version of the SimStruct macro:  "ssGetTaskTime(S,tid)"
%%
%function LibGetTaskTime(tid) void

  %return RTMGetTaskTimeForTID(tid)
%endfunction %% LibGetTaskTime

%% DocFunction{Sample Time Functions}: LibGetClockTick ===================
%% Abstract:
%%   Returns integer task time (current clock tick of the task timer). 
%% The resolution of the timer can be obtained from 
%% LibGetClockTickStepSize(tid). The data type id of the timer can 
%% be obtained from LibGetClockTickDataTypeId(tid).
%% 
%function LibGetClockTick(tid) void
  %assert TYPE(tid) == "Number" && tid >= 0
  
  %if ClockTickForTIDIsReqFcn(tid) 
    %return RTMGet("ClockTick%<tid>")
  %else 
    %assign timer_resolution = SampleTime[tid].ClockTickStepSize
    %if timer_resolution == 0 
       %return LibGetTaskTime(tid)
     %else
       %return "floor(%<LibGetTaskTime(tid)> / %<timer_resolution>+0.5)"
     %endif
  %endif
%endfunction %% LibGetClockTick

%%DocFunction{Sample Time Functions}: LibGetClockTickHigh ===================
%% Abstract:
%%   Returns high order word of integer task time. This function is used  
%% when uint32 pairs are used to store absolute time. 
%% The resolution of the timer can be obtained from 
%% LibGetClockTickStepSize(tid).
%%
%function LibGetClockTickHigh(tid) void
  %assert TYPE(tid) == "Number" && tid >= 0
  
  %if LongClockTickForTIDIsReqFcn(tid)
    %return RTMGet("ClockTickH%<tid>")
  %else
    %assign timer_resolution  = SampleTime[tid].ClockTickStepSize
    %assign weighedResolution = timer_resolution * 4.294967296e+09
    %assert timer_resolution > 0 
    %return "floor(%<LibGetTaskTime(tid)>/(%<weighedResolution>)+0.5)"
  %endif
%endfunction %% LibGetClockTick

%% DocFunction{Sample Time Functions}: LibGetClockTickStepSize ==================
%% Abstract: 
%%   Returns clock tick step size, which is the resolution of 
%% the integer task time. 
%%   This function can't be used if the task doesn't have a timer.
%% 
%function LibGetClockTickStepSize(tid) void
  %assert TYPE(tid) == "Number" && tid >= 0
  %assert ClockTickForTIDIsReqFcn(tid) 

  %return SampleTime[tid].ClockTickStepSize
%endfunction %% LibGetClockTickStepSize


%% DocFunction{Sample Time Functions}: LibGetClockTickDataTypeId ==================
%% Abstract: 
%%   Returns clock tick data type id.
%% 
%function LibGetClockTickDataTypeId(tid) void
  %assert TYPE(tid) == "Number" && tid >= 0
  %assert ClockTickForTIDIsReqFcn(tid) 

  %return SampleTime[tid].ClockTickDataTypeId
%endfunction %% LibGetClockTickDataTypeId


%% SLibGetDbBufReadBuf ======================
%% Abstract:
%%  Returns DbBufReadBuf. This flag is used by a double 
%% buffer algorithm. The algorithm insures data integrity when 
%% asynchronous task reads absolute time from base rate. 
%%
%function SLibGetDbBufReadBuf(tid)
  %assert RTMClockTick0DbBufIsReqFcn(%<tid>) || RTMContTDbBufIsReqFcn(%<tid>)
  
  %return RTMGet("DbBufReadBuf%<tid>")
%endfunction %%SLibGetDbBufReadBuf 

%% SLibGetDbBufWriteBuf ======================
%% Abstract:
%%  Returns DbBufWriteBuf. This flag is used by a double 
%% buffer algorithm. The algorithm insures data integrity when 
%% asynchronous task reads absolute time from base rate. 
%%
%function SLibGetDbBufWriteBuf(tid)
  %assert RTMClockTick0DbBufIsReqFcn(%<tid>) || RTMContTDbBufIsReqFcn(%<tid>)
  
  %return RTMGet("DbBufWriteBuf%<tid>")
%endfunction %%SLibGetDbBufWriteBuf 

%% SLibGetDbBufLastBufWr ======================
%% Abstract:
%%  Returns DbBufLastBufWr(last buffer written) . This flag is used by a double 
%% buffer algorithm. The algorithm insures data integrity when 
%% asynchronous task reads absolute time from base rate. %%
%function SLibGetDbBufLastBufWr(tid)
  %assert RTMClockTick0DbBufIsReqFcn(%<tid>) || RTMContTDbBufIsReqFcn(%<tid>)
  
  %return RTMGet("DbBufLastBufWr%<tid>")
%endfunction %%SLibGetDbBufLastBufWr


%% SLibGetDbBufClockTickForTid ==================================
%% Abstract:
%%  Returns the pointer of clock tick double buffers for specific tid. 
%% The double is used to insures data integrity when 
%% asynchronous task reads absolute time from base rate. 
%%
%function SLibGetDbBufClockTickForTID(tid)
  %assert RTMClockTick0DbBufIsReqFcn(%<tid>)
  
  %return RTMGet("DbBufClockTick%<tid>")
%endfunction %%SLibGetDbBufClockTickForTID


%% SLibGetDbBufClockTickHForTID ==================================
%% Abstract:
%%  Returns the pointer of clock tick high word double buffers 
%% for specific tid. The double is used to insures data integrity when 
%% asynchronous task reads absolute time from base rate. 
%%
%%
%function SLibGetDbBufClockTickHForTID(tid)
  %assert RTMClockTick0DbBufIsReqFcn(%<tid>) && LongClockTickForTIDIsReqFcn(0)
  
  %return RTMGet("DbBufClockTickH%<tid>")
%endfunction %%SLibGetDbBufClockTickHForTID

%% SLibGetDbBufContTForTID ===================================
%% Abstract::
%%  Returns the pointer of continuous double buffers for specific tid. 
%% The double is used to insures data integrity when 
%% asynchronous task reads absolute time from base rate. 
%%
%function SLibGetDbBufContTForTID(tid)
  %assert RTMContTDbBufIsReqFcn(tid)
  
  %return RTMGet("DbBufContT%<tid>")
%endfunction %% SLibGetDbBufContTForTID


%% SLibGetH2LBufBeingRead ======================
%% Abstract:
%%  Return flag in Timing H2LBufBeingRead.
%%  This flag help to ensured data integrity 
%%  of time when lower priority async task
%%  read time from base rate task. This flag
%%  keep track which buffer is being read
%%
%function SLibGetH2LBufBeingRead(tid)
  %assert RTMClockTick0H2LIsReqFcn(tid) || RTMContTH2LIsReqFcn(tid)
  
  %return RTMGet("H2LBufBeingRead%<tid>")
%endfunction %%SLibGetH2LBufBeingRead

%% SLibGetH2LLastBufWr ============================
%% Abstract:
%%  Return flag in Timing H2LLastBufWr. 
%%  This flag help to insured data integrity 
%%  of time when lower priority async task
%%  read time from base rate task. This flag
%%  keep track what is the buffer being written last.
%%
%function SLibGetH2LLastBufWr(tid)
  %assert RTMClockTick0H2LIsReqFcn(tid) || RTMContTH2LIsReqFcn(tid)
  
  %return RTMGet("H2LLastBufWr%<tid>")
%endfunction %%SLibGetH2LLastBufWr

%% SLibGetH2LDbBufClockTickForTID ==================================
%% Abstract::
%%  Return pointer of double buffer for clocktick0 used for H2L
%%  data transfer: H2LDbBufClockTick0 
%%
%function SLibGetH2LDbBufClockTickForTID(tid)
  %assert RTMClockTick0H2LIsReqFcn(tid) 
  
  %return RTMGet("H2LDbBufClockTick%<tid>")
%endfunction %%SLibGetH2LDbBufClockTickForTID

%% SLibGetH2LDbBufClockTickHForTID ==================================
%% Abstract::
%%  Return pointer of double buffer for clocktick0H used for H2L
%%  data transfer: H2LDbBufClockTickH0 
%%
%function SLibGetH2LDbBufClockTickHForTID(tid)
  %assert RTMClockTick0H2LIsReqFcn(tid) && LongClockTickForTIDIsReqFcn(0)
  
  %return RTMGet("H2LDbBufClockTickH%<tid>")
%endfunction %%SLibGetH2LDbBufClockTickHForTID

%% SLibGetH2LDbBufContTForTID ===================================
%% Abstract::
%%  Return pointer of double buffer for ContT used for H2L
%%  data transfer: H2LDbBufContT
%%
%function SLibGetH2LDbBufContTForTID(tid)
  %assert RTMContTH2LIsReqFcn(tid) 
  
  %return RTMGet("H2LDbBufContT%<tid>")
%endfunction %% SLibGetH2LDbBufContTForTID

%% SLibGetL2HLastBufWr ======================================
%% Abstract::
%%  Return flag in Timing L2HLastBufWr. 
%%  This flag help to insured data integrity 
%%  of time when higher priority async task
%%  read time from base rate task. This flag
%%  keep track what is the buffer being written last.
%%
%function SLibGetL2HLastBufWr() 
  %assert RTMClockTick0L2HIsReqFcn() || RTMContTL2HIsReqFcn()
  
  %return RTMGet("L2HLastBufWr")
%endfunction %% SLibGetL2HLastBufWr

%% SLibGetL2HDbBufClockTick ==================================
%% Abstract::
%%  Return pointer of double buffer for clocktick0 used for L2H
%%  data transfer: L2HDbBufClockTick 
%%
%function SLibGetL2HDbBufClockTick()
  %assert RTMClockTick0L2HIsReqFcn() 
  
  %return RTMGet("L2HDbBufClockTick")
%endfunction %%SLibGetL2HDbBufClockTick

%% SLibGetL2HDbBufClockTickH ==================================
%% Abstract::
%%  Return pointer of double buffer for clocktick0H used for L2H
%%  data transfer: L2HDbBufClockTickH 
%%
%function SLibGetL2HDbBufClockTickH()
  %assert RTMClockTick0L2HIsReqFcn() && LongClockTickForTIDIsReqFcn(0)
  
  %return RTMGet("L2HDbBufClockTickH")
%endfunction %%SLibGetL2HDbBufClockTickH

%% SLibGetL2HDbBufContT ===================================
%% Abstract::
%%  Return pointer of double buffer for ContT used for L2H
%%  data transfer: L2HDbBufContT
%%
%function SLibGetL2HDbBufContT()
  %assert RTMContTL2HIsReqFcn() 
  
  %return RTMGet("L2HDbBufContT")
%endfunction %%SLibGetL2HDbBufContT


%% DocFunction{Sample Time Functions}: LibGetElapseTimeCounter =================
%% Abstract:
%%     Returns an integer elapsed time. This is the number of clock ticks 
%%  elapsed since the last time the system started. To get realworld elapsed time, 
%%  this integer elapsed time must be multiplied by the applicable resolution. 
%%  You can obtain the resolution by calling LibGetElapseTimeResolution(system).
%%  You can obtain the data type id of integer elapsed time counter 
%%  by calling LibGetElapseTimeCounterDTypeId(system)
%%
%function LibGetElapseTimeCounter(system) void
  %assign callSites      = system.CallSites
  %assign graphParentSys = CompiledModel.System[callSites[0][2]]
  %assign ssOwnerSSBlock = graphParentSys.Block[callSites[0][3]]

  %%assert !Accelerator
  %if !SysMaintainsElapseTime(system)
    %assert graphParentSys.Type != "root"
    %return LibGetElapseTimeCounter(graphParentSys)
  %else 
    %assign sysIdx = system.CallSites[0][2]
    %assign blkIdx = system.CallSites[0][3]
    %assign ssBlock = System[sysIdx].Block[blkIdx]
    
    %% Iterator system reset when it runs, elapse time always is zero.
    %% don't need caculate.
    %if SLibGetElapseTimeIsConstantZero(system)
      %return "0"
    %else 
      %return "rt_elapseTime"
    %endif
  %endif
  
%endfunction %% LibGetElapseTimeCounter


%% SLibGetElapseTimeCounterUsesVector  =========================
%%  Determine if the Elapse Time Counter uses a two element
%%  vector of uint32_T's
%%
%function SLibGetElapseTimeCounterUsesVector(system) void
  %%
  %assign dtypeId = LibGetElapseTimeCounterDTypeId(system)
  %%  
  %assign isVector = (dtypeId == tSS_TIMER_UINT32_PAIR)
  %return isVector
  %%
%endfunction %% SLibGetElapseTimeCounterUsesVector

%% LibBlockGetElapseTimeCounter =================
%% Abstract:
%%   This is a hack!!!
%%   for non timer_uint32_pair, return rt_elapsetime,
%%   for timer_uint32_pair, return rt_elapsetime[0]
%function LibBlockGetElapseTimeCounter(system) void
  %%
  %assign useCounter = 1
  %assign elapseTimeLabel = LibGetElapseTimeCounter(system)
  %%
  %if SLibGetElapseTimeCounterUsesVector(system)
    %%
    %% Elapse Time Counter is a vector of two uint32_T
    %% this block only uses the least significant word.
    %%
    %assign elapseTimeLabel = "((%<elapseTimeLabel>)[0])"
    %%
  %endif
  %%
  %return elapseTimeLabel
  %%
%endfunction

%% SLibCGIRBlockGetElapseTimeCounter =================
%%
%function SLibCGIRBlockGetElapseTimeCounter(sysIdx) void
  %assign system = System[sysIdx]
  %return(LibBlockGetElapseTimeCounter(system))
%endfunction

%% DocFunction{Sample Time Functions}: LibGetElapseTimeCounterDTypeId ===
%% Abstract: 
%%  Returns the date type id of the integer elapsed time returned by
%% LibGetElapseTimeCounter(system)
%%
%function LibGetElapseTimeCounterDTypeId(system) void
  %assert ISFIELD(system,"ElapseTimeDataTypeId")

  %return system.ElapseTimeDataTypeId

%endfunction %% LibGetElapseTimeCounterDTypeId

%% DocFunction{Sample Time Functions}: LibGetElapseTimeResolution ===
%% Abstract:
%%  Returns resolution of integer elapsed time returned by
%% LibGetElapseTimeCounter
%%
%function LibGetElapseTimeResolution(system) void
  %assign sysIdx = system.CallSites[0][2]
  %assign blkIdx = system.CallSites[0][3]
  %assign ssBlock = System[sysIdx].Block[blkIdx]
  
  %with ssBlock
    %if LibAsynchronousTriggeredTID(SubsystemTID)
      %assign t_resolution =  SampleTime[SubsystemTID].ClockTickStepSize
    %else
      %assign tid = SLibGetNumericTID(ssBlock)
      %assign t_resolution = SampleTime[tid].ClockTickStepSize
    %endif
  %endwith
 
  %return t_resolution
  
%endfunction %% LibGetElapseTimeResolution

%% SLibGetElapseTimeIsConstantZero(system) ========
%% Abstract: 
%%  This function returns true if system elapse is
%% always zero.
%%
%function SLibGetElapseTimeIsConstantZero(system) void
  %assign retVal = TLC_FALSE  %% assume
  %assign sysIdx = system.CallSites[0][2]
  %assign blkIdx = system.CallSites[0][3]
  %assign ssBlock = System[sysIdx].Block[blkIdx]
  %%
  %% Iterator system reset when it runs, elapse time always is zero.
  %% don't need caculate.
  %if system.Type == "iterator" && ...
    SLibXBInitRequired(system,ssBlock,[],"","",0)
    %assign retVal = TLC_TRUE
  %endif
  %if ISEQUAL(ssBlock.SubsystemTID, "constant" ) || ...
    (ISEQUAL(ssBlock.SubsystemTID,"triggered") && ...
    ISEQUAL(ssBlock.TriggerTID, "constant"))
    %assign retVal = TLC_TRUE
  %endif
  
  %% Remove this optimization for now because it is causing
  %% test failure. Will do this in simulation (byu, dyang)
  %return TLC_FALSE
  %%return retVal 
%endfunction

%% DocFunction{Sample Time Functions}: LibGetElapseTime ===================
%% Abstract:
%%  Returns time elapsed since the last time the 
%% subsystem started. 
%%
%function LibGetElapseTime(system) void
  %assign callSites      = system.CallSites
  %assign graphParentSys = CompiledModel.System[callSites[0][2]]
  %assign ssOwnerSSBlock = graphParentSys.Block[callSites[0][3]]
  
  %if !SysMaintainsElapseTime(system)
    %assert graphParentSys.Type != "root"
    %return LibGetElapseTime(graphParentSys)
  %else 
    %if SLibGetElapseTimeIsConstantZero(system)
      %return "0"
    %endif
    %assign t_resolution = LibGetElapseTimeResolution(system)
    %if t_resolution == 0
      %return "rt_elapseTime"
    %endif
    %%
    %if LibGetElapseTimeCounterDTypeId(system) == tSS_TIMER_UINT32_PAIR
      %assign intElapseTArray = LibGetElapseTimeCounter(system)
      %if t_resolution == 1
	%return "(%<intElapseTArray>[0] + " + ...
	  "(%<LibGetDataTypeNameFromId(tSS_DOUBLE)>)" + ...
	  "(%<intElapseTArray>[1])*4294967296.0)"
      %else 
	%return "(%<intElapseTArray>[0] + " + ...
	  "(%<LibGetDataTypeNameFromId(tSS_DOUBLE)>)" + ...
	  "(%<intElapseTArray>[1])*4294967296.0)" + ...
	  " * %<t_resolution>"
      %endif
    %else
      %if t_resolution == 1
	%return "(%<LibGetElapseTimeCounter(system)>)"
      %else 
	%return "(%<LibGetElapseTimeCounter(system)> * %<t_resolution>)"
      %endif
    %endif
  %endif
  
%endfunction %% LibGetElapseTime

%% SLibCGIRGetElapseTime =================
%%
%function SLibCGIRGetElapseTime(sysIdx) void
  %assign system = System[sysIdx]
  %return(LibGetElapseTime(system))
%endfunction

%% Function: LibNeedRealNonFinite ==============================================
%% Abstract:
%%   Set appropriate flags:
%%      o CompiledModel.NeedRealInf
%%      o CompiledModel.NeedRealMinusInf
%%      o CompiledModel.NeedRealNaN
%%   to indicate that non-finite values are being accessed.
%%
%%   The value argument can be one of: {inf, -inf, nan, "inf", "-inf", "nan"}
%%
%function LibNeedRealNonFinite(value) void
  %% Error out if this model should not be using nonfinites.
  %% This check should be migrated to TgtFcnLib which will
  %% cover both TLC and CGIR
  %if CodeFormat == "Embedded-C"
    %if EXISTS("OrigName")      
      %assign modelName = CompiledModel.OrigName
    %else
      %assign modelName = CompiledModel.Name
    %endif      
    %assign supportNonFinite = FEVAL("uget_param","%<modelName>","SupportNonFinite")
    %if TYPE(supportNonFinite) == "String" && supportNonFinite == "off"
      %assign errTxt = "The nonfinite '%<value>' is required but nonfinite support is not selected. Please enable nonfinite support."
      %<LibReportError(errTxt)>
    %endif
  %endif
  %%
  %% Get past a TLC bug which says
  %%  nan == inf
  %%  nan == -inf
  %% Also get past a TLC bug that doesn't allow you to change
  %% the value mid-stream of the if-then-else evaluation.
  %%
  %assign vType = TYPE(value) 
  %if vType == "Real" || vType == "Real32"
    %if ISNAN(value)
      %assign newValue = "nan"
    %elseif value == rtInf
      %assign newValue = "inf"
    %elseif value == rtMinusInf
      %assign newValue = "-inf"
    %else
      %<LibReportFatalError("Unknown value: %<value>")>
    %endif
    %assign value = newValue
  %endif

  %switch value
    %case "inf"
      %assign ::CompiledModel.NeedRealInf = 1
      %break
    %case "-inf"
      %assign ::CompiledModel.NeedRealMinusInf = 1
      %break
    %case "nan"
      %assign ::CompiledModel.NeedRealNaN = 1
      %break
    %default
      %<LibReportFatalError("Unknown non-finite value: %<value>")>
  %endswitch

%endfunction %% end LibNeedRealNonFinite



%% Function: LibRealNonFinite ==================================================
%% Abstract:
%%   LibRealNonFinite returns the appropriate non-finite and sets the
%%   corresponding global flag indicating the non-finite value's usage.
%%   This function should always be used instead of hard-coding %<tInf>,
%%   %<tMinusInf>, or %<tNaN>.
%%   
%%   Arguments:
%%      value: One of {inf, -inf, nan, "inf", "-inf", "nan"}
%%
%function LibRealNonFinite(value) void
  %%
  %% Get past a TLC bug which say
  %%  nan == inf
  %%  nan == -inf
  %% Also get past a TLC bug that doesn't allow you to change
  %% the value mid-stream of the if-then-else evaluation.
  %%
  %if TYPE(value) == "Real"
    %if ISNAN(value)
      %assign newValue = "nan"
    %elseif value == rtInf
      %assign newValue = "inf"
    %elseif value == rtMinusInf
      %assign newValue = "-inf"
    %else
      %<LibReportFatalError("Unknown value: %<value>")>
    %endif
    %assign value = newValue
  %endif

  %switch value
    %case "inf"
      %<LibNeedRealNonFinite("inf")>
      %return tInf
    %case "-inf"
      %<LibNeedRealNonFinite("-inf")>
      %return tMinusInf
    %case "nan"
      %<LibNeedRealNonFinite("nan")>
      %return tNaN
    %default
      %<LibReportFatalError("Unknown non-finite value: %<value>")>
  %endswitch
%endfunction %% end LibRealNonFinite


%% Function: LibCheckValue =====================================================
%% Abstract:
%%   LibCheckValue determines if a value is non-finite and if so, sets the
%%   appropriate access flag.
%%
%function LibCheckValue(reserved, value) void
  %if !ISFINITE(value)
    %<LibNeedRealNonFinite(value)>
  %endif
%endfunction %% LibCheckValue


%% Function: SLibRealNonFinitesRequired ========================================
%% Abstract:
%%   SLibRealNonFinitesRequired returns one if a non-finite value was used
%%   in the generated code or there is non-inline sfunction. 
%%   
%%
%function SLibRealNonFinitesRequired() void
  %assign retVal = (NeedRealInf || NeedRealMinusInf || NeedRealNaN) ? 1 : 0
  %assign retVal = retVal || NumChildSFunctions > 0 || MatFileLogging
  
  %% Consider nonfinite rtIsInf(F)/rtIsNaN(F) TFL function access
  %if EXISTS(::OrigName)      
    %assign modelName = CompiledModel.OrigName
  %else
    %assign modelName = CompiledModel.Name
  %endif
  %assign numcbs = FEVAL("rtwprivate","rtw_get_tfl_cb_info","%<modelName>",-1)
  %foreach i = numcbs
    %assign fctInfo = FEVAL("rtwprivate","rtw_get_tfl_cb_info","%<modelName>",i+1)
    %if fctInfo.FcnName == "rtIsInf" || fctInfo.FcnName == "rtIsInfF"
      %% Invoke error check to ensure nonfinite support is selected
      %<LibRealNonFinite("inf")>
      %assign retVal = 1
      %break
    %elseif fctInfo.FcnName == "rtIsNaN" || fctInfo.FcnName == "rtIsNaNF"
      %% Invoke error check to ensure nonfinite support is selected
      %<LibRealNonFinite("nan")>
      %assign retVal = 1
    %endif
  %endforeach
  
  %% make sure both non-finite support and floating point support are enabled
  %% if noninlined S-Functions exist
  %if (NumChildSFunctions > 0) && ((SupportNonFinite==0) || (PurelyIntegerCode==1))
    %assign errTxt = "To support noninlined S-Functions, both floating point number "...
      "and non-finite number support must be enabled."
    %<LibReportError(errTxt)>
  %endif
  %return retVal
%endfunction %% SLibRealNonFinitesRequired


%% DocFunction{Sample Time Functions}: LibTriggeredTID =========================
%% Abstract:
%%   Returns whether this TID corresponds to a triggered rate
%%
%function LibTriggeredTID(tid) void

  %return ISEQUAL(tid, "triggered") || ...
    ISEQUAL(tid, -1) || ...
    LibAsynchronousTriggeredTID(tid)
  
%endfunction %% LibTriggeredTID


%% DocFunction{Sample Time Functions}: LibAsynchronousTriggeredTID ===================
%% Abstract:
%%   Returns whether this TID corresponds to a asynchronous triggered rate
%%
%function LibAsynchronousTriggeredTID(tid) void

  %return TYPE(tid) == "Number" && tid >= 0 && ...
    SampleTime[tid].Asynchronous == "yes"
  
%endfunction %% LibAsynchronousTriggeredTID


%% DocFunction{Sample Time Functions}: LibGetNumSFcnSampleTimes ================
%% Abstract:
%%   Returns the number of S-function sample times for a block.
%%
%function LibGetNumSFcnSampleTimes(block) void

  %%   See also:
  %%     LibIsSFcnSingleRate
  %%     LibGetGlobalTIDFromLocalSFcnTID
  %%     LibIsSFcnSampleHit
  %%     LibIsSFcnSpecialSampleHit
  %%     LibGetSFcnTIDType
  %%

  %return SIZE(TID,1)

%endfunction %% LibGetNumSFcnSampleTimes


%% DocFunction{Sample Time Functions}: LibIsSFcnSingleRate  ====================
%% Abstract:
%%   LibIsSFcnSingleRate returns a boolean value (1 or 0) indicating 
%%   whether the S-function is single rate (one sample time) or multirate
%%   (multiple sample times).
%%
%function LibIsSFcnSingleRate(block) void

  %% See also:
  %%     LibIsRateTransitionBlock   (must be single rate block)
  %%     LibGetNumSFcnSampleTimes
  %%     LibGetGlobalTIDFromLocalSFcnTID
  %%     LibIsSFcnSampleHit
  %%     LibIsSFcnSpecialSampleHit
  %%     LibGetSFcnTIDType
  %%

  %return SIZE(TID,1) == 1
  
%endfunction %% LibIsSFcnSingleRate


%% DocFunction{Sample Time Functions}: LibGetGlobalTIDFromLocalSFcnTID =========
%% Abstract:
%%   Returns the model task identifier (sample time index) corresponding to the
%%   specified local S-function task identifier or port sample time.
%%   This function allows you to use one function to determine a global
%%   TID, independent of port- or block-based sample times.
%%
%%   Calling this function with an integer argument is equivalent to the
%%   statement SampleTimesToSet[sfcnTID][1]. SampleTimesToSet is a matrix
%%   that maps local S-function TIDs to global TIDs.
%%
%%   The input argument to this function should be either:
%%
%%      sfcnTID: integer (e.g. 2)
%%               For block-based sample times (e.g. in S-function
%%               mdlInitializeSizes, ssSetNumSampleTimes(S,N) with N > 1 was
%%               specified), sfcnTID is an integer corresponding local
%%               S-function sample time.
%%         or
%%
%%      sfcnTID: string of the form "InputPortIdxI", "OutputPortIdxI" where I
%%               is a number ranging from 0 to the number of ports (e.g.,
%%               "InputPortIdx0", "OutputPortIdx7").  For port-based sample
%%               times (e.g. in S-function mdlInitializeSizes,
%%               ssSetNumSampleTimes(S,PORT_BASED_SAMPLE_TIMES) was specified),
%%               sfcnTID is a string giving the input (or output) port index.
%%
%%   Examples:
%%   1) Multirate block:
%%      %assign globalTID = LibGetGlobalTIDFromLocalSFcnTID(2)
%%        or
%%      %assign globalTID = LibGetGlobalTIDFromLocalSFcnTID("InputPortIdx4")
%%
%%      %assign period  = CompiledModel.SampleTime[globalTID].PeriodAndOffset[0]
%%      %assign offset  = CompiledModel.SampleTime[globalTID].PeriodAndOffset[1]
%%
%%   2) Inherited sample time block:
%%      %switch (LibGetSFcnTIDType(0))
%%        %case "discrete"
%%        %case "continuous"
%%           %assign globalTID = LibGetGlobalTIDFromLocalSFcnTID(2)
%%           %assign period  = ...
%%             CompiledModel.SampleTime[globalTID].PeriodAndOffset[0]
%%           %assign offset  = ...
%%             CompiledModel.SampleTime[globalTID].PeriodAndOffset[1]
%%           %breaksw
%%        %case "triggered"
%%           %assign period = -1
%%           %assign offset = -1
%%           %breaksw
%%        %case "constant"
%%           %assign period = rtInf
%%           %assign offset = 0
%%           %breaksw
%%        %default
%%           %<LibBlockReportFatalError([],"Unknown tid type")>
%%      %endswitch
%%
%function LibGetGlobalTIDFromLocalSFcnTID(sfcnTID) void

  %% See also:
  %%   LibGetNumSFcnSampleTimes
  %%   LibIsSFcnSingleRate
  %%   LibIsSFcnSampleHit
  %%   LibIsSFcnSpecialSampleHit
  %%   LibGetSFcnTIDType
  %%
  %if TYPE(TID) == "String"
    %<LibReportFatalError("Invalid sample time (%<TID>)")>
  %endif

  %with ParamSettings

    %if TYPE(sfcnTID) == "String"
      %if PortBasedSampleTimes != "yes"
        %<LibReportFatalError("Incorrect sfcnTID argument")>
      %endif
      %return LibBlockPortSampleTime(sfcnTID)
    %elseif TYPE(sfcnTID) == "Number"
      %%
      %% SampleTimesToSet:
      %%   First column  = local TID (always the vector [0,1,...])
      %%   Second column = global TID
      %%
      %if PortBasedSampleTimes != "no"
        %<LibReportFatalError("Incorrect sfcnTID argument")>
      %endif

      %if !EXISTS("SampleTimesToSet")
        %<LibReportFatalError("S-function sample time translation table " ...
          "not found")>
      %endif

      %if sfcnTID < 0 || sfcnTID >= SIZE(SampleTimesToSet,0)
        %<LibReportFatalError("Invalid sample time index")>
      %endif
      %return SampleTimesToSet[sfcnTID][1]
    %endif

  %endwith

  %<LibReportFatalError("Invalid argument")>

%endfunction %% LibGetGlobalTIDFromLocalSFcnTID



%% DocFunction{Sample Time Functions}: LibIsSFcnSampleHit ======================
%% Abstract:
%%   Returns 1 if a sample hit occurs for the specified local S-function task
%%   identifier (TID), 0 otherwise.
%%
%%   The input argument to this function should be either:
%%
%%      sfcnTID: integer (e.g. 2)
%%               For block-based sample times (e.g. in S-function
%%               mdlInitializeSizes, ssSetNumSampleTimes(S,N)
%%               with N > 1 was specified), sfcnTID is an integer starting at
%%               0 of the corresponding local S-function sample time.
%%         or
%%
%%      sfcnTID: "InputPortIdxI", "OutputPortIdxI" (e.g. "InputPortIdx0",
%%               "OutputPortIdx7") For port based sample times (e.g. in
%%               S-function mdlInitializeSizes,
%%               ssSetNumSampleTimes(S,PORT_BASED_SAMPLE_TIMES) was specified),
%%               sfcnTID is a string giving the input (or output) port index.
%%
%%   Examples:
%%   1) Consider a multirate S-function block with 4 block sample times.
%%      The call LibIsSFcnSampleHit(2) will return the code to check
%%      for a sample hit on the 3rd S-function block sample time.
%%
%%   2) Consider a multirate S-function block with 3 input and 8 output
%%      sample times. The call LibIsSFcnSampleHit("InputPortIdx0") returns the
%%      code to check for a sample hit on the first input port. The call
%%      LibIsSFcnSampleHit("OutputPortIdx7") returns the code to check for
%%      a sample hit on the eight output port.
%%
%function LibIsSFcnSampleHit(sfcnTID) void

  %% See also:
  %%   LibGetNumSFcnSampleTimes
  %%   LibIsSFcnSingleRate
  %%   LibGetGlobalTIDFromLocalSFcnTID
  %%   LibIsSFcnSpecialSampleHit
  %%   LibGetSFcnTIDType
  %%   LibIsSampleHit
  %%   LibIsSpecialSampleHit
  %%

  %if Type != "S-Function"
    %<LibReportFatalError("Called with non-S-Function block")>
  %endif
  %if  ((SIZE(TID,1) == 1) && (PortBasedSampleTimes != "yes"))
    %<LibReportFatalError("Called non-multirate S-function block")>
  %endif
  %return LibIsSampleHit(LibGetGlobalTIDFromLocalSFcnTID(sfcnTID))
%endfunction %% LibIsSFcnSampleHit



%% DocFunction{Sample Time Functions}: LibIsSFcnSpecialSampleHit ===============
%% Abstract:
%%   Returns the Simulink macro to promote a slow task (sfcnSTI) into a faster
%%   task (sfcnTID).
%%
%%   This advanced function is specifically intended for use in rate transition
%%   blocks. This function determines the global TID from the S-function TID 
%%   and calls LibIsSpecialSampleHit using the global TIDs for both the sample
%%   time index (sti) and the task id (tid).
%%
%%   The input arguments to this function are:
%%
%%   o) For multirate S-function blocks:
%%      sfcnSTI: local S-function sample time index (sti) of the slow task that
%%               is to be promoted
%%      sfcnTID: local S-function task Id (tid) of the fast task where the slow
%%               task will be run.
%%
%%   o) For single rate S-function blocks using SS_OPTION_RATE_TRANSITION,
%%      the sfcnSTI and sfcnTID are ignored and should be specified as "".
%%
%%   The format of sfcnSTI and sfcnTID must follow that of the argument
%%   to LibIsSFcnSampleHit
%%
%%   Examples:
%%     1) A rate transition S-function (one sample time with
%%        SS_OPTION_RATE_TRANSITION):
%%  
%%        if (%<LibIsSFcnSpecialSampleHit("","")>) {
%%
%%     2) A multi-rate S-function with port-based sample times where the
%%        output rate is slower than the input rate (e.g. a zero-order
%%        hold operation):
%%
%%        if (%<LibIsSFcnSpecialSampleHit("OutputPortIdx0","InputPortIdx0")>) {
%%
%function LibIsSFcnSpecialSampleHit(sfcnSTI, sfcnTID)

  %% See also:
  %%   LibGetNumSFcnSampleTimes
  %%   LibIsSFcnSingleRate
  %%   LibGetGlobalTIDFromLocalSFcnTID
  %%   LibIsSFcnSampleHit
  %%   LibGetSFcnTIDType
  %%   LibIsSampleHit
  %%   LibIsSpecialSampleHit
  %%
  
  %if SIZE(TID,1) == 1
    %if !EXISTS("SampleTimeIdx")
      %<LibReportFatalError("Called with non-multirate S-function block")>
    %endif
    %assign sti = SampleTimeIdx
    %assign tid = TID
  %else
    %assign sti = LibGetGlobalTIDFromLocalSFcnTID(sfcnSTI)
    %assign tid = LibGetGlobalTIDFromLocalSFcnTID(sfcnTID)
  %endif
  %% Run in task tid but at frequency of sti.
  %return LibIsSpecialSampleHit(sti,tid)

%endfunction %% LibIsSFcnSpecialSampleHit



%% DocFunction{Sample Time Functions}: LibGetSFcnTIDType =======================
%% Abstract:
%%   Returns the type of the specified S-Functions task identifier (sfcnTID).
%%
%%     "continuous" if the specified sfcnTID is continuous.
%%     "discrete"   if the specified sfcnTID is discrete.
%%     "triggered"  if the specified sfcnTID is triggered.
%%     "constant"   if the specified sfcnTID is constant
%%
%%   The format of sfcnTID must follow be the same as for LibIsSFcnSampleHit
%%
%%   Note:
%%     This is useful primarily in the context of S-functions that specified an
%%     inherited sample time.
%%
%function LibGetSFcnTIDType(sfcnTID)

  %% See also:
  %%   LibGetNumSFcnSampleTimes
  %%   LibIsSFcnSingleRate
  %%   LibGetGlobalTIDFromLocalSFcnTID
  %%   LibIsSFcnSampleHit
  %%   LibIsSFcnSpecialSampleHit
  %%
  
  %if SIZE(TID,1) == 1
    %assign tid = TID
  %else
    %assign tid = LibGetGlobalTIDFromLocalSFcnTID(sfcnTID)
  %endif

  %if TYPE(tid) == "Number"
    %assign period = CompiledModel.SampleTime[tid].PeriodAndOffset[0]
    %assign offset = CompiledModel.SampleTime[tid].PeriodAndOffset[1]
    %if period == 0.0 && offset == 0.0
      %return "continuous"
    %elseif period > 0.0
      %return "discrete"
    %endif
  %elseif TYPE(tid) == "String" || TYPE(tid) == "Identifier"
    %return tid
  %endif

%endfunction %% LibGetSFcnTIDType

%% Function: LibOptionalMatrixWidth ============================================
%% Abstract:
%%   LibOptionalMatrixWidth returns a string that can be used for
%%   C declarations of 1-D arrays (1-D or 2-D RTW arrays).
%%   
%%   This functions returns
%%      ""             if the inputs are 0
%%      "[number]"     if non-zero inputs, where number is nRows*nCols
%%
%function LibOptionalMatrixWidth(nRows, nCols) void
  %if nRows == 1 && nCols == 1
    %return ""
  %elseif nCols == 1 && nRows > 1
    %return "[%<nRows>]"
  %elseif nRows == 1 && nCols > 1
    %return "[%<nCols>]"
  %elseif nCols > 1 && nRows > 1
    %return "[%<nRows*nCols>]"
  %else
    %<LibReportFatalError("Invalid matrix size (%<nRows> x %<nCols>)")>
  %endif
%endfunction %% LibOptionalMatrixWidth

%% Function: LibOptionalVectorWidth ============================================
%% Abstract:
%%   LibOptionalVectorWidth returns "[length]" if the length of the input
%%   vector is greater than one and returns "" otherwise.
%%
%function LibOptionalVectorWidth(length) void
  %if length == 1
    %return ""
  %elseif length > 1
      %return "[%<length>]"
  %else
    %<LibReportFatalError("Invalid vector length (%<length>) specified")>
  %endif
%endfunction %% LibOptionalVectorWidth



%% Function: LibBlockSetIsExpressionCompliant ==================================
%% Abstract:
%%   Specify that this block's TLC file is compliant with expression folding.
%%   To be called in BlockInstanceSetup function.
%%
%function LibBlockSetIsExpressionCompliant(block) void
  %<SETFIELD(block,"TLCExprCompliant", 1)>
%endfunction


%% Function: LibBlockSetIntegerDowncastUnnecessary ==================================
%% Abstract:
%%   Specify that this block does not need to enforce integer downcasts for its
%%   output expression
%%
%function LibBlockSetIntegerDowncastUnnecessary(block) void
  %<SETFIELD(block,"EnforceIntegerDowncast", 0)>
%endfunction


%% Function: LibBlockInputSignalAllowScalarExpandedExpr ========================
%% Abstract:
%%   Always allow the input signal to be an expression, even when any of the
%%   output signals are wide.  To be called in BlockInstanceSetup function.
%%
%function LibBlockInputSignalAllowScalarExpandedExpr(block,ipIdx) void
  %<SETFIELD(block.DataInputPort[ipIdx],"AllowScalarExpandedExpr",1)>
%endfunction


%% Function: SLibGet1DArrayIndexer =============================================
%% Abstract:
%%      If the variable (e.g. rtB.idname) is non-scalar 1-D vector, this 
%%      function returns 
%%            C: "[index_expression]" or 
%%          Ada: "(index_expression)"
%%      otherwise this function returns 
%%             ""
%%      for the scalar case (when width == 1)
%% 
%%      The arguments determine how to index a variable depending on whether it
%%      is a scalar or a vector and whether or not it is in a rolled loop.
%%
%% Arguments:
%%      width - width of variable.
%%      ucv   - user control index variable
%%      lcv   - loop control index variable (when rolling)
%%      offset - offset into the source vector
%%
%% Returns:
%%      ""                 If signal is scalar (width is one)
%%      "[ucv+offset]"     If ucv specified (i.e. ucv not equal to "")
%%      "[lcv]"            If lcv specified (i.e. lcv not equal to "", 
%%                         ucv equal to ""). 
%%      "[offset]"         otherwise (ucv equal to "" and lcv equal to "")
%%
%function SLibGet1DArrayIndexer(width, ucv, lcv, offset) void
  %%
  %assign offsetStr = ""
  %%
  
  %if TYPE(offset) == "Number"
    %if offset > 0
      %assign offsetStr = "+%<offset>"
    %endif
  %endif

  %% scalar case
  %if width == 1
    %return ""
  %endif
  %% vector case
  %if ucv != ""
    %return "[%<ucv>%<offsetStr>]"
  %elseif lcv != ""
    %return "[%<lcv>]"
  %else
    %% Handle the case of idx being an integer literal or string
    %return "[%<offset>]"
  %endif
  
%endfunction %% SLibGet1DArrayIndexer


%% Function: SLibGet2DArrayIndexer =============================================
%% Abstract:
%%   Generate the index string for accessing elements of a
%%   2-D Real-Time Workshop array.
%%   
%%   Note: use LibOptionalMatrixWidth to generate
%%         index string for declarations (it collapses
%%         degenerate arrays).
%%   
%%   Matrices (2-D arrays) are saved within a vector in column-major format.
%%   If the accessed vector (e.g. rtB.idname) is non-scalar, this 
%%   function returns 
%%          C: "[index_expression]" or 
%%        Ada: "(index_expression)"
%%   otherwise this function returns 
%%        ""
%%   for the scalar case (when width == nRows*nCols == 1)
%%
%%   The general case for column order indexing is:
%%       [rowIdx + nRows * colIdx]
%%
%%   This function goes further by allowing for the abstraction of
%%   user and loop control variables analogous to SLibGet1DArrayIndexer.
%%   
%%   The indexer string consists of a preceding delimiter, the row index
%%   summed with the product of the column index and the number of rows
%%   in the matrix, following by a close delimiter.  For row or column
%%   vectors, the result is the minimum amount of information necessary
%%   to correctly access the matrix.
%%   
%%   Note: commonhdrlib.tlc collapses degenerate arrays into the minimum
%%         declaration, i.e., 1x1 => scalar and Nx1 or 1xN => N.  This function
%%         generates an indexer with this knowledge.
%%
%%   Arguments:
%%        offset: Offset to the base of the vector (generally 0).
%%        nRows:  Number of rows in matrix
%%        rucv:   User control variable string for row
%%        rlcv:   Loop control variable string for row
%%        ridx:   Row index (must be an integer)
%%        nCols:  Number of columns in matrix
%%        cucv:   User control variable string for columns
%%        clcv:   Loop control variable string for columns
%%        cidx:   Column index (must be an integer)
%%
%%   Returns:
%%      1) "" if signal is scalar (nRows*nCols equals one).
%%      2) "[offset + rowIdx + nRows * colIdx]" if signal is a matrix 
%%           where rowIdx = 
%%             rucv   if rcuv != ""
%%             rlcv   if rucv == "" and rlcv != ""
%%             ridx   if rucv == "" and rlcv == ""
%%           where colIdx =
%%             cucv   if ccuv != ""
%%             clcv   if cucv == "" and clcv != ""
%%             cidx   if cucv == "" and clcv == ""
%%
%function SLibGet2DArrayIndexer(offset, nRows, rucv, rlcv, ridx, ...
  nCols, cucv, clcv, cidx) void

  %if rlcv != "" || clcv != ""
    %setcommandswitch "-v1"
    %<LibReportError("Usage of rlcv and clcv in SLibGet2DArrayIndexer " + ...
      "is reserved for future use with a Matrix roller")>
  %endif

  %if nRows*nCols == 1
    %return ""
  %elseif nRows > 1 && nCols > 1
    %%
    %% actual 2-D matrix case:
    %%   first, generate the row index 
    %%
    %assign rowIdxIsConst = 0
    %assign colIdxIsConst = 0

    %if rucv != ""
      %assign rowIdx = rucv
    %elseif rlcv != ""
      %assign rowIdx = rlcv
    %else
      %if ridx > 0
        %assign rowIdx = "%<ridx>"
        %assign rowIdxIsConst = 1  %% possible optimization exists
      %else
        %assign rowIdx = ""
      %endif
    %endif

    %%
    %% now generate the column index
    %%
    %if cucv != ""
        %assign colIdx = "%<nRows>*%<cucv>"
    %elseif clcv != ""
      %assign colIdx = "%<nRows>*%<clcv>"
    %else
      %if cidx > 0
        %assign colIdx = "%<nRows*cidx>"
        %assign colIdxIsConst = 1  %% possible optimization exists
      %else
        %assign colIdx = ""
      %endif
    %endif

    %%
    %% put row and column index calculation text together
    %%
    %if rowIdx != "" && colIdx != ""
      %if rowIdxIsConst == 1 && colIdxIsConst == 1
        %assign returnVal = ridx+nRows*cidx  %% avoid expression
      %else
        %assign returnVal = "%<rowIdx> + %<colIdx>"
      %endif
    %elseif rowIdx != ""
      %assign returnVal = rowIdx
    %elseif colIdx != ""
      %assign returnVal = colIdx
    %else
      %assign returnVal = "0" %% need to access first element
    %endif
  %else 
    %if nRows > 1
      %assign ucv = rucv
      %assign lcv = rlcv
      %assign idx = ridx
    %else %% nCols > 1
      %assign ucv = cucv
      %assign lcv = clcv
      %assign idx = cidx
    %endif
    %if ucv != ""
      %assign returnVal = ucv
    %elseif lcv != ""
      %assign returnVal = lcv
    %else
      %assign returnVal = idx
    %endif
  %endif

  %%
  %% Add array offset
  %%
  %if offset != 0
    %if TYPE(returnVal) == "Number"
      %assign returnVal = offset + returnVal
    %else
      %assign returnVal = "%<offset>+%<returnVal>"
    %endif
  %endif
  %assign returnVal = "[%<returnVal>]"
  
  %return returnVal

%endfunction %% end SLibGet2DArrayIndexer



%% Function: LibComputeNumBlocks ===============================================
%% Abstract:
%%   LibComputeNumBlocks computes the number of nonvirtual blocks in the 
%%   entire model.
%%
%function LibComputeNumBlocks() void
  %assign numBlocks = 0
  %foreach sysIdx = NumSystems
    %assign numBlocks = numBlocks + CompiledModel.System[sysIdx].NumBlocks
  %endforeach
  %return numBlocks
%endfunction %% LibComputeNumBlocks


%% Function: LibConvertZCDirection =============================================
%% Abstract:
%%   Convert Real-Time Workshop zero crossing direction to a SimStruct
%%   representation. 
%%
%%   Returns:
%%        "RISING_ZERO_CROSSING"  if direction is "Rising"
%%        "ANY_ZERO_CROSSING"     if direction is "Any"
%%        "FALLING_ZERO_CROSSING" if direction is "Falling"
%%
%function LibConvertZCDirection(direction) void
  %if direction == "Falling"
    %return "FALLING_ZERO_CROSSING"
  %elseif direction == "Any"
    %return "ANY_ZERO_CROSSING"
  %elseif direction == "Rising"
    %return "RISING_ZERO_CROSSING"
  %else
    %<LibReportFatalError("Invalid zc direction (%<direction>)")>
  %endif
%endfunction %%  LibConvertZCDirection


%% Function: LibBaseAddrOfVariable =============================================
%% Abstract:
%%   Determine the base address of a C variable (prefix with &).
%%
%function LibBaseAddrOfVariable(variable, nrows, ncols) void
  %if nrows < 1 || ncols < 1
    %<LibReportFatalError("Invalid size (%<nrows> by %<ncols>)")>
  %elseif nrows == 1 && ncols == 1      /% scalar %/
    %return "&%<variable>"
  %elseif nrows > 1 && ncols == 1       /% vector %/
    %return "&%<variable>[0]"
  %elseif nrows > 1 && ncols > 1        /% RTW matrix %/
    %return "&%<variable>[0]"
  %endif
%endfunction %% LibBaseAddrOfVariable


%% SLibGrBlockName =============================================================
%% Abstract:
%%   SLibGrBlockName return the Simulink block name for a given
%%   BlockHierarchyMap block index.
%%
%function SLibGrBlockName(grBlockIndex) void
  %if grBlockIndex[1] != -1
    %with CompiledModel.BlockHierarchyMap
      %if Subsystem[grBlockIndex[0]].MaskType == "Stateflow"
        %assign grBlock = Subsystem[grBlockIndex[0]]
      %else
        %assign grBlock = Subsystem[grBlockIndex[0]].Block[grBlockIndex[1]]
      %endif
    %endwith
    %return grBlock.Name
  %else
    %return "synthesized block"
  %endif
%endfunction %% SLibGrBlockName


%% SLibGrBlockPath =============================================================
%% Abstract:
%%   SLibGrBlockPath return the full Simulink block path for a given
%%   BlockHierarchyMap block index.
%%
%function SLibGrBlockPath(grBlockIndex) void
  %if grBlockIndex[1] != -1
    %with CompiledModel.BlockHierarchyMap
      %assign grSubSys = Subsystem[grBlockIndex[0]]      
      %assign grBlock  = grSubSys.Block[grBlockIndex[1]]
      %if grSubSys.SubsystemBlockIndex[0] == -1 %% root
        %return grSubSys.SLName + "/" + grBlock.SLName
      %elseif grSubSys.MaskType == "Stateflow"
        %return SLibGrBlockPath(grSubSys.SubsystemBlockIndex)
      %else
        %return SLibGrBlockPath(grSubSys.SubsystemBlockIndex) + ...
          "/" + grBlock.SLName
      %endif
    %endwith
  %else
    %return "synthesized block"
  %endif
%endfunction %% SLibGrBlockPath


%% SLibMangledGrBlockPath ======================================================
%% Abstract:
%%   SLibMangledGrBlockPath return the Simulink block name for a given
%%   BlockHierarchyMap block index.
%%
%function SLibMangledGrBlockPath(grBlockIndex) void
  %if grBlockIndex[1] != -1
    %with CompiledModel.BlockHierarchyMap
      %assign grSubSys = Subsystem[grBlockIndex[0]]
      %assign grBlock  = grSubSys.Block[grBlockIndex[1]]
      %assign sysName  = SYSNAME(grBlock.Name)
      %if grSubSys.SubsystemBlockIndex[0] == -1
        %return grSubSys.SLName + "/" + sysName[1]
      %elseif grSubSys.MaskType == "Stateflow"
        %return SLibMangledGrBlockPath(grSubSys.SubsystemBlockIndex)
      %else
        %return SLibMangledGrBlockPath(grSubSys.SubsystemBlockIndex) + ...
          "/" + sysName[1]
      %endif
    %endwith
  %else
    %return "synthesized_block"
  %endif
%endfunction %% SLibGrBlockName


%% DocFunction{BlkPathAndErrFcns}: LibGetBlockName =============================
%% Abstract:
%%   LibGetBlockName returns the short block path name string for a block record
%%   excluding carriage returns and other special characters which may be
%%   present in the name.
%%
%function LibGetBlockName(block) void
  %if ISFIELD(block, "GrSrc") && block.GrSrc[1] != -1
    %return SLibGrBlockName(block.GrSrc)
  %else
    %return block.Name
  %endif
%endfunction


%% DocFunction{BlkPathAndErrFcns}: LibGetBlockPath =============================
%% Abstract:
%%   LibGetBlockPath returns the full block path name string for a block record
%%   including carriage returns and other special characters which may be
%%   present in the name.  Currently, the only other special string sequences
%%   defined are '/*' and '*/'.
%%
%%   The full block path name string is useful when accessing blocks from
%%   MATLAB.  For example, the full block name can be used with hilite_system()
%%   via FEVAL to match the Simulink path name exactly. 
%%
%%   Use LibGetFormattedBlockPath to get a block path suitable for placing
%%   in a comment or error message.
%%
%function LibGetBlockPath(block) void
  %if ISFIELD(block, "GrSrc") && block.GrSrc[1] != -1
    %return SLibGrBlockPath(block.GrSrc)
  %elseif ISFIELD(block, "SLName")
    %return LibUnmangledPathName(block.SLName)
  %else
    %return LibUnmangledPathName(block.Name)
  %endif
%endfunction


%% DocFunction{BlkPathAndErrFcns}: LibGetFormattedBlockPath ====================
%% Abstract:
%%   LibGetFormattedBlockPath returns the full path name string of a block
%%   without any special characters. The string returned from this function 
%%   is suitable for placing the block name, in comments or generated code, on
%%   a single line.
%%
%%   Currently, the special characters are carriage returns, '/*', and '*/'.
%%   A carriage return is converted to a space, '/*' is converted to '/+', 
%%   and '*/' is converted to '+/'.  Note that a '/' in  the name is 
%%   automatically converted to a '//' to distinguish it from a path separator.
%%
%%   Use LibGetBlockPath to get the block path needed by Matlab functions
%%   used in reference blocks in your model .
%%
%function LibGetFormattedBlockPath(block) void
  %if ISFIELD(block, "GrSrc") && block.GrSrc[1] != -1
    %return SLibMangledGrBlockPath(block.GrSrc)
  %else
    %return LibMangledPathName(block.Name)
  %endif
%endfunction


%% Function: LibUnmangledPathName =============================================
%% Abstract:
%%   This is an internal function that is called by LibGetBlockPath. 
%%   You should use LibGetBlockPath if possible.
%%   
%%   A block path can contain new-lines and troublesome character sequences 
%%   such as /* and */. This function constructs the actual block path when
%%   passed SLName. The function LibMangledPathName transforms the path
%%   (mangles it) such that there are no new lines or troublesome characters.
%%
%function LibUnmangledPathName(name) void
  %if Accelerator
    %% Accelerator encodes names, return its name.
    %return name
  %endif
  %assign sysName = SYSNAME(name)
  %if sysName[0] == ""
    %return name
  %elseif sysName[0] == "Root"
    %return CompiledModel.Name + "/" + sysName[1]
  %else
    %assign idNum = IDNUM(sysName[0])
    %assign subsystemNum = idNum[1] - 1
    %assign ssRef = Subsystem[subsystemNum]
    %if EXISTS("ssRef.SLName")
      %return LibUnmangledPathName(ssRef.SLName) + "/" + sysName[1]
    %else
      %return LibUnmangledPathName(ssRef.Name) + "/" + sysName[1]
    %endif
  %endif
%endfunction %% LibUnmangledPathName


%% Function: LibMangledPathName ===============================================
%% Abstract:
%%   This is an internal function that is called by LibGetFormattedBlockPath.
%%   You should use LibGetFormattedBlockPath if possible.
%%
%function LibMangledPathName(name) void
  %% Can't issue a warning yet ... should be using LibGetFormattedBlockPath.
  %if Accelerator
    %% Accelerator encodes names, return its name.
    %return name
  %endif
  %assign sysName = SYSNAME(name)
  %if sysName[0] == ""
    %return name
  %elseif sysName[0] == "Root"
    %return CompiledModel.Name + "/" + sysName[1]
  %else
    %assign idNum = IDNUM(sysName[0])
    %assign subsystemNum = idNum[1] - 1
    %return LibMangledPathName(Subsystem[subsystemNum].Name) + "/" + sysName[1]
  %endif
%endfunction %% LibMangledPathName


%% Function: LibBlockSFunctionFileExists =======================================
%% Abstract:
%%   LibBlockSFunctionFileExists determines if the TLC file for an 
%%   S-function exists.  Because FILE_EXISTS can be very slow especially
%%   over a network, the existence of the file is cached in a global variable.
%%   Subsequent calls for the same S-Function will execute much quicker.
%%
%function LibBlockSFunctionFileExists(sfuncName) void
    %%
    %% check cache to see if file existence has already been checked
    %%
%% ????? is sfuncName guaranteed to be a usable name for a TLC variable ?????
    %%
    %if ISFIELD(GblInlinedTLCFileAccessed,sfuncName)
        %assign fileExists = 1
    %elseif FILE_EXISTS(GENERATE_FILENAME(sfuncName))
        %assign fileExists = 1
        %<SETFIELD(GblInlinedTLCFileAccessed,sfuncName,1)>\
    %else
        %assign fileExists = 0
    %endif
    %%
    %return fileExists
    %%
%endfunction %% LibBlockSFunctionFileExists


%% Function: LibBlockFunctionExists ============================================
%% Abstract:
%%   LibBlockFunctionExists determines if a given block function (method) 
%%   exists. For S-function blocks, it first checks to see if the
%%   corresponding TLC file exists and then it checks to see if the
%%   function exists.
%%
%function LibBlockFunctionExists(block, fcn) void
  %if block.Type == "S-Function"
    %assign sfuncName = block.ParamSettings.FunctionName
    %%
    %assign fileExists = LibBlockSFunctionFileExists(sfuncName)
    %%
    %if fileExists
      %return GENERATE_TYPE_FUNCTION_EXISTS(block, fcn, sfuncName)
    %else
      %return 0
    %endif
  %else
    %return GENERATE_FUNCTION_EXISTS(block, fcn)
  %endif
%endfunction


%% Function: LibIsValidCVariable ===============================================
%% Abstract:
%%   For a string s, LibIsValidCVariable(s) returns one for alphanumeric
%%   variables starting with [_a-zA-Z] and zero otherwise.
%%
%function LibIsValidCVariable(s) void
  %return FEVAL("iscvar", s)
%endfunction

%% Function: LibSFunctionLevel =================================================
%% Abstract:
%%   Determine the S-function version level {Level1, Level2, RTWLevel2}
%%
%function LibSFunctionLevel() void
  %if EXISTS("ParamSettings.RTWGenerated")
    %return "RTWLevel2"
  %elseif EXISTS("SFcnParamSettings")
    %% For backwards compatibility with R11
    %if EXISTS("SFcnParamSettings.RTWGenerated")
      %return "RTWLevel2"
    %endif
  %elseif ParamSettings.FunctionLevel == 1
    %return "Level1"
  %else
    %return "Level2"
  %endif
%endfunction


%% Function: LibParentMaskBlockName ============================================
%% Abstract:
%%   Returns the name of the parent subsystem (mask) block.
%%
%function LibParentMaskBlockName(block) void
  %if Accelerator
    %% Accelerator encodes names, return its name.
    %return block.Name
  %endif
  %if EXISTS("block.SLName")
    %assign name = block.SLName
  %else
    %assign name = block.Name
  %endif
  %assign sysName = SYSNAME(name)
  %if sysName[0] != "Root"
    %assign sysId = sysName[0]
    %assign idIdx = %<IDNUM(sysId)>[1] - 1
    %return CompiledModel.Subsystem[idIdx].Name
  %else
    %return name
  %endif
%endfunction


%% Function: LibAddToCompiledModel =============================================
%% Abstract:
%%   Adds an identifier name/value pair to the global
%%   CompiledModel record.  An error is reported if the identifier already
%%   exists.
%%
%function LibAddToCompiledModel(name, value) void
  %if ISFIELD(CompiledModel, name)
    %<LibReportFatalError("LibAddToCompiledModel, %<name> already exists")>
  %endif
  %addtorecord CompiledModel %<name> value
%endfunction


%% Function: LibAddIdentifier ==================================================
%% Abstract:
%%   Adds an identifier/value pair to a specified scope.
%%   
%%   Adding a duplicate identifier (i.e. same name as one that already
%%   exists in rec) with a different value than that in rec will result
%%   in an error.
%%   
%%   Adding a duplicate identifier with equal value has no effect.
%%
%function LibAddIdentifier(rec, name, value) void
  %if ISFIELD(rec, name)
    %%
    %% name already exists in rec, therefore, exit if value is
    %% different, otherwise, ignore
    %%
    %if !ISEQUAL(rec.%<name>, value)
      %%
      %% Trying to modify a name (note that if it's the same we'll
      %% just ignore the request)
      %%
      %assign oldValue = rec.%<name>
      %assign warnTxt = "Modifying %<name> from %<oldValue> to %<value>"
      %<LibReportWarning(warnTxt)>
      %openfile errTxt


      Adding %<name> would change the current record value.

      %if EXISTS("Type")
        Current Type: %<Type>
      %endif
      %if EXISTS("Name")
        Current Name: %<Name>
      %endif
      %closefile errTxt
      %<LibReportFatalError(errTxt)>
    %endif
  %else
    %%
    %% adding name is safe
    %%
    %addtorecord rec %<name> value
  %endif
%endfunction


%% Function: LibAddToFile ======================================================
%% Abstract:
%%   Used to create additional source files.
%%   Adds the buffer to the file, if the file is not already "opened", it
%%   will be created and added to.  During code generation, any files created
%%   with this function will be created on disk.
%%   Note: Should also call LibAddToModelSources() or LibCacheIncludes() as
%%   desired to get file into the build process.
%%
%function LibAddToFile(file, buffer) void
  %assign existingFile = 0
  %% scan for existing name
  %foreach idx = CompiledModel.NumFiles
    %if CompiledModel.Files.Name[idx] == file
      %assign existingFile = 1
      %assign fileIdx = idx
      %break
    %endif
  %endforeach
  %if existingFile
    %% Add buffer to file
    %assign contents    = "::CompiledModel.Files.File[%<fileIdx>]"
    %assign %<contents> = %<contents> + buffer
  %else
    %if CompiledModel.NumFiles == 0
      %% Create record to hold all files
      %assign tmpVar = Files { Name []; File [] }
      %assign ::CompiledModel = CompiledModel + Files
      %undef Files
      %undef tmpVar
    %endif
    %% Start file and buffer
    %assign ::CompiledModel.Files.Name = CompiledModel.Files.Name + file
    %assign ::CompiledModel.Files.File = CompiledModel.Files.File + buffer
    %assign ::CompiledModel.NumFiles   = CompiledModel.NumFiles   + 1
  %endif
%endfunction


%% Function: SLibCrudeParseSafeExpression ======================================
%%
%function SLibCrudeParseSafeExpression(blockName, in, checkSideEffects) void

  %assign eRetValNeedsParen = 1
  %assign eRetValHasSideEffect = 2
  %assign eRetValMismatchedDelimiters = 4
  %%
  %assert TYPE(in) == "String"
  %%
  %assign retVal = NEEDS_PAREN(in)
  %%
  %if checkSideEffects && (retVal & eRetValHasSideEffect)
    
    %<LibReportFatalError("Block: %<blockName>.  Expression '%<in>' has a side effect.")>

  %endif
  %%
  %if retVal & eRetValMismatchedDelimiters

    %<LibReportFatalError("Block: %<blockName>.  Expression '%<in>' has a [] or () mismatch.")>

  %endif
  %%
  %if !(retVal & eRetValNeedsParen)
    %%
    %return in
  %else
    %<LibReportWarning("Block: %<blockName>.  Expression '%<in>' does not protect precedence of operators with parentheses.")>
    %return "(%<in>)"
  %endif
  %%
%endfunction %% SLibCrudeParseSafeExpression(in)


%% Function: SLibProcessSafeExpression ======================================
%%
%%   This function converts negative numeric inputs into
%%   precedence immune expressions.
%%
%%   Input 
%%       Type must be a string or a non-complex numeric type.
%%
%%   Output
%%       If the input is numeric and its value is negative, then
%%         the output is a string that wraps the input value in
%%         parentheses to make it a "precedence immune expression"
%%       Otherwise
%%         the output is identical to the input.
%%       
%function SLibProcessSafeExpression(blockName, in, checkSideEffects) void
  %%
  %switch TYPE(in)
      %%
    %case "String"
      %%
      %assign in = SLibCrudeParseSafeExpression(blockName, in, checkSideEffects)
      %%
      %% Fall Thru is Desired Here
      %%
    %case "Unsigned"
      %%
      %return in
      %%
      %break
      %%
    %case "Real"
    %case "Number"
    %case "Real32"
      %%
      %if in >= 0
        %%
        %return in
      %else
        %return "(%<in>)"
      %endif
      %%
      %break
      %%
    %default
      %<LibReportFatalError("Block: %<blockName>.  Input required to be precedence immune expression, but had unsupported type.")>
  %endswitch
  %%
%endfunction %% SLibProcessSafeExpression

%% Function: LibCallEventSystem ================================================
%% Abstract:
%%     This function is used by blocks that post events to call the subsystem
%%     for an event
%%
%function LibCallEventSystem(block, eventIdx) Output
  %assign sysIdx      = block.ModelEventSystemsToCall[eventIdx*2]
  %assign callSiteIdx = block.ModelEventSystemsToCall[eventIdx*2 + 1]
  %if sysIdx >= 0
    %assign ss = CompiledModel.System[sysIdx]
    %if !LibSystemFcnIsEmpty(ss, "Output")
      %<LibGenSystemFcnCall(ss, "Output", callSiteIdx)>\
    %endif
  %endif
%endfunction



%% DocFunction{Code Configuration Functions}: LibAddToModelSources =============
%% Abstract:
%%   This function serves two purposes:
%%     1) To notify the Real-Time Workshop build process that it must
%%        build with the specified source file, and
%%     2) To update the
%%          'SOURCES: file1.c file2.c ...' 
%%        comment in the generated code.
%%
%%   For inlined S-functions, LibAddToModelSources is generally called from 
%%   BlockTypeSetup. This function adds a file name to the list of sources 
%%   needed to build this model. This functions returns 1 if the filename passed
%%   in was a duplicate (i.e. it was already in the sources list) and 0 if it 
%%   was not a duplicate.
%%
%%   As an S-function author, we recommend using the SFunctionModules
%%   block parameter instead of this function. See Writing S-functions.
%%
%function LibAddToModelSources(newFile) void
    %assign duplicate = 0
    %% scan for duplicates
    %foreach idx = ::CompiledModel.NumSources
      %if (::CompiledModel.Sources[idx] == "%<newFile>")
	%assign duplicate = 1
	%break
      %endif
    %endforeach
    %if (!duplicate)
      %assign ::CompiledModel.Sources = ::CompiledModel.Sources + "%<newFile>"
      %assign ::CompiledModel.NumSources = ::CompiledModel.NumSources + 1
    %endif
    %return (duplicate)
%endfunction %% LibAddToModelSources

  
%% Function: SLibGenSourcesComment =============================================
%% Abstract:
%%   Called by the model-wide TLC code to generate the 
%%     '  * SOURCES: file1.c file2.c ...'
%%   comment.
%%
%function SLibGenSourcesComment() void
  %assign sources = "  * SOURCES: "
  %assign srcStr  = ""
  %foreach idx = ::CompiledModel.NumSources
    %assign mdlSrc  = ::CompiledModel.Sources[idx]
    %if (SIZE(srcStr, 1) + SIZE(mdlSrc, 1)) > 70
      %assign sources = sources + "\n  * SOURCES: "
      %assign srcStr  = ""
    %endif
    %assign srcStr = srcStr + "%<mdlSrc>.c "
    %assign sources = sources + "%<mdlSrc>.c "
  %endforeach
  %return(sources)
%endfunction %% SLibGenSourcesComment



%% Function: SLibCreateBuildSourcesTxtFile =====================================
%% Abstract:
%%   Create modelsources.txt, a list of module sources cached by 
%%   LibAddToModelSources
%% 
%function SLibCreateBuildSourcesTxtFile() void
  %assign sources = ""
  %foreach idx = ::CompiledModel.NumSources
    %assign sources = sources + " " + ::CompiledModel.Sources[idx] + "." + ::LangFileExt + " "
  %endforeach
  %openfile fid = "modelsources.txt"
  %<sources>
  %closefile fid
%endfunction %% SLibCreateBuildSourcesTxtFile

%% Function: SLibComparePriority ====================================
%% Abstract:
%%  Compare priority of tid1 and tid2.
%%  -1: tid1 or tid2 is not assigned a priority,
%%      comparing failed. 
%%   0: tid1 has priority as tid2, this only 
%%      happens if tid1==tid2.
%%   1: tid1 has higher priority than tid2
%%   2: tid1 has lower priority than tid2
%%
%function SLibComparePriority(tid1, tid2)

  %assert TYPE(tid1) == "Number" && TYPE(tid2) == "Number"
  
  %if tid1 == -2 || tid2 == -2
    %% either of the tids is constant,
    %return 0
  %endif
  
  %if tid1 < 0 || tid2 < 0 || ...
    !ISFIELD(SampleTime[tid1], "Priority") || ...
    !ISFIELD(SampleTime[tid2], "Priority")
    
    %assign retVal = -1
  %else
    %assign priority1 = CompiledModel.SampleTime[tid1].Priority
    %assign priority2 = CompiledModel.SampleTime[tid2].Priority

    %if priority1 > priority2
      %assign retVal = PositivePriority == "yes" ? 1 : 2
    %elseif priority1 < priority2
      %assign retVal = PositivePriority == "yes" ? 2 : 1
    %else
      %assert tid1==tid2
      %assign retVal = 0
    %endif
  %endif
  
  %return retVal 
%endfunction %% SLibComparePriority

%% Function: SLibIsAsyncTaskOnlyModel =======================
%%
%%     Return true if the model has only Async task block. 
%% Code for async task is empty. In this case don't need register
%% rtOneStep function. 
%%
%%    The all the followings must be true if a model is an 
%% AsyncTaskOnly model:
%%    1. Model is a single sync rate model. 
%%    2. No async task need absolute time, or
%%       Async task that need absolute time manage own
%%       absolute time.
%%    3. Blocks in root subsystem must be
%%         fcn-call subsystem block, or
%%         block is an async top caller, or 
%%         blocks output code is white space
%function SLibIsAsyncTaskOnlyModel()
  %assign retVal = TLC_TRUE %% assume
  
  %if ISFIELD(CompiledModel, "IsAsyncTaskOnlyModel")
    %return IsAsyncTaskOnlyModel
  %endif 
  
  %if  NumAsynchronousSampleTimes > 0 && ...
    NumSynchronousSampleTimes <= 1
    %foreach idx = NumAsynchronousSampleTimes
      %assign tid = idx + NumSynchronousSampleTimes
      %if SampleTime[tid].NeedAbsoluteTime == "yes" && ...
	SampleTime[tid].TimeSource == "BaseRate"
	%assign retVal = TLC_FALSE
      %endif
    %endforeach
  %else
    %assign retVal = TLC_FALSE
  %endif
    
  %if retVal
    %assign rootSystem = System[NumSystems-1]
    %with rootSystem
      %foreach blk_Idx = NumBlocks
	%with Block[blk_Idx]
	  %if Type == "SubSystem" && ...
	    NumControlInputPorts == 1 && ...
	    ControlInputPort.Type == "function-call"
	    %continue
	  %elseif ISEQUAL(TID, "constant") || ...
	    ISFIELD(Block[blk_Idx], "IsAsyncTopCaller")
	    %continue
	  %else
	    %openfile tmpBuf
	    %<SLibGenerateNonExprOutput(Block[blk_Idx],rootSystem)>
	    %closefile tmpBuf
	    %if WHITE_SPACE(tmpBuf)
	      %continue
	    %else
	      %assign retVal = TLC_FALSE
	      %break
	    %endif
	  %endif
	%endwith
      %endforeach
    %endwith
  %endif
  
  %addtorecord CompiledModel IsAsyncTaskOnlyModel retVal
  %return retVal
%endfunction

%endif %% _UTILLIB_
%% [EOF] utillib.tlc
