1    /* --COPYRIGHT--,BSD
     2     * Copyright (c) $(CPYYEAR), Texas Instruments Incorporated
     3     * All rights reserved.
     4     *
     5     * Redistribution and use in source and binary forms, with or without
     6     * modification, are permitted provided that the following conditions
     7     * are met:
     8     *
     9     * *  Redistributions of source code must retain the above copyright
    10     *    notice, this list of conditions and the following disclaimer.
    11     *
    12     * *  Redistributions in binary form must reproduce the above copyright
    13     *    notice, this list of conditions and the following disclaimer in the
    14     *    documentation and/or other materials provided with the distribution.
    15     *
    16     * *  Neither the name of Texas Instruments Incorporated nor the names of
    17     *    its contributors may be used to endorse or promote products derived
    18     *    from this software without specific prior written permission.
    19     *
    20     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    23     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    27     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    28     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    29     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    30     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31     * --/COPYRIGHT--*/
    32    
    33     
    34    /*
    35     *  ======== LoggerStreamer.xdc ========
    36     */
    37    import xdc.runtime.ILogger;
    38    import ti.uia.runtime.ILoggerSnapshot;
    39    import xdc.rov.ViewInfo;
    40    import xdc.runtime.Log;
    41    import xdc.runtime.Diags;
    42    import xdc.runtime.Types;
    43    import xdc.runtime.Log;
    44    import xdc.runtime.Error;
    45    
    46    /*!
    47     *  ======== LoggerStreamer ========
    48     *  This general purpose logger is useful in situations where the application
    49     *  wants to manage the buffers used to store and transmit events. This includes 
    50     *  managing the sending of the buffers to an instrumentation host (e.g. 
    51     *  System Analyzer in CCS).  The logger is named "LoggerStreamer" because it is
    52     *  designed to enable the application to send a stream of packets containing
    53     *  UIA event data to the instrumentation host.
    54     *
    55     *  The application is responsible for providing the buffers that LoggerStreamer
    56     *  uses. There are two ways to accomplish this.
    57     *  @p(blist)
    58     *      - Provide a prime callback function via the `{@link #primeFxn}`
    59     *        configuration parameter.
    60     *      - Call the `{@link #prime}` API once.
    61     *  @p
    62     *
    63     *  The logger stores the events in a UIAPacket event packet structure that
    64     *  allows them to be sent directly to System Analyzer (e.g. via UDP), enabling
    65     *  efficient streaming of the data from the target to the host.  The first 
    66     *  four 32-bit words contain a `{@link UIAPacket#Hdr}` structure. This struct
    67     *  is used by the host (e.g. System Analyzer in CCS) to help decode the 
    68     *  data (e.g. endianess, length of data, etc.). The `{@link UIAPacket#Hdr}`
    69     *  structure is initialized via the `{@link #initBuffer}` API. All buffers
    70     *  given to LoggerStreamer (via priming or exchange) must be initialized via
    71     *  `{@link #initBuffer}`.
    72     *
    73     *  The size of buffer -*- includes UIAPacket_Hdr?
    74     *  LoggerStreamer treats the buffer as a UInt32 array. So the application
    75     *  must guarantee the buffers are aligned on word addresses.  Alignment on
    76     *  cache line boundaries is recommended for best performance.
    77     *
    78     *  When the buffer is filled, LoggerStreamer will hand it off to the
    79     *  application using an application-provided exchange function (`{@link #exchangeFxn}`).  
    80     *  The exchange function must be of type `{@link #ExchangeFxnType}`.  
    81     *  The exchange function is called in the context of a log
    82     *  so generally the exchange function should be quick to execute.
    83     *
    84     *  The exchange function is called within the context of a Log call, so the exchange
    85     *  function should be design to fast. Since the exchange function is called
    86     *  within the context of the Log call, LoggerStreamer guarantees no Log
    87     *  records are dropped (i.e. LoggerStreamer is lossless).
    88     *
    89     *  LoggerStreamer was designed to have as minimal impact as possible on an
    90     *  application  when calling a Log function. There are several configuration 
    91     *  parameters that allow an application to get the optimal performance in 
    92     *  exchange for certain restrictions.
    93     *
    94     *  Interrupts are disabled during the duration of the log call including
    95     *  when the exchange function is called. LoggerStreamer will ignore any
    96     *  log events generated during the exchangeFxn (e.g. posting a semaphore).
    97     *
    98     *  @a(Examples)
    99     *  The following XDC configuration statements
   100     *  create a logger module, and assign it as the default logger for all
   101     *  modules.
   102     *
   103     *  @p(code)
   104     *  var Defaults = xdc.useModule('xdc.runtime.Defaults');
   105     *  var Diags = xdc.useModule('xdc.runtime.Diags');
   106     *  var LoggerStreamer = xdc.useModule('ti.uia.sysbios.LoggerStreamer');
   107     *
   108     *  LoggerStreamer.bufSize = 1024;
   109     *  LoggerStreamer.isTimestampEnabled = true;
   110     *  LoggerStreamer.primeFxn = '&prime';
   111     *  LoggerStreamer.exchangeFxn = '&exchange';
   112     *  Defaults.common$.logger = LoggerStreamer.create();
   113     *  @p
   114     *
   115     *  @a(Examples)
   116     *  The following C code demonstrates a basic prime and exchange example.
   117     *  A real implementation would send the buffer to an instrumentation
   118     *  host (e.g. System Analyzer in CCS) via a transport such as UDP.
   119     *
   120     *  @p(code)
   121     *  UInt32 buffer[2][BUFSIZE];
   122     
   123     *  Ptr prime()
   124     *  {
   125     *      LoggerStreamer_initBuffer(buffer[0], 0);
   126     *      LoggerStreamer_initBuffer(buffer[1], 0);
   127     *      return ((Ptr)(buffer[0]));
   128     *  }
   129     *
   130     *  Ptr exchange(Ptr *full)
   131     *  {
   132     *      count++;
   133     *      // Ping-pong between the two buffers
   134     *      return ((Ptr*)buffer[count & 1]);
   135     *  }
   136     *  @p
   137     */
   138    
   139    @ModuleStartup
   140    @Template("./LoggerStreamer.xdt")
   141    @CustomHeader
   142    module LoggerStreamer inherits ILoggerSnapshot {
   143    
   144        /*!
   145         *  ======== TransportType ========
   146         *  Used to specify the type of transport to use
   147         *
   148         *  This enum is used by the instrumentation host to determine what
   149         *  the transport is. It is not used by the target code.
   150         */
   151        enum TransportType {
   152            TransportType_UART = 0,
   153            TransportType_USB = 1, 
   154            TransportType_ETHERNET = 2, 
   155            TransportType_CUSTOM = 3
   156        };
   157        
   158        /*!
   159         *  @_nodoc
   160         *  ======== ModuleView ========
   161         */
   162        metaonly struct ModuleView {        
   163            Bool       isEnabled;
   164            Bool       isTimestampEnabled;
   165            Int        bufferSize;
   166            String     primeFunc;
   167            String     exchangeFunc;
   168            String     transportType;
   169            String     customTransport;
   170        }
   171    
   172        metaonly struct RecordView {
   173            Int     sequence;
   174            Long    timestampRaw;
   175            String  modName;
   176            String  text;
   177            Int     eventId;
   178            String  eventName;
   179            IArg    arg0;
   180            IArg    arg1;
   181            IArg    arg2;
   182            IArg    arg3;
   183            IArg    arg4;
   184            IArg    arg5;
   185            IArg    arg6;
   186            IArg    arg7;
   187        }
   188        
   189        /*!
   190         *  @_nodoc
   191         *  ======== rovViewInfo ========
   192         */    
   193        @Facet
   194        metaonly config ViewInfo.Instance rovViewInfo =
   195            ViewInfo.create({
   196                viewMap: [
   197                    ['Module',   
   198                        {
   199                            type: ViewInfo.MODULE,   
   200                            viewInitFxn: 'viewInitModule', 
   201                            structName: 'ModuleView'
   202                        }
   203                    ],
   204                    ['Records', 
   205                        {
   206                            type: xdc.rov.ViewInfo.MODULE_DATA,
   207                            viewInitFxn: 'viewInitRecords',
   208                            structName: 'RecordView'
   209                        }
   210                    ]
   211                ]
   212            });
   213        
   214        /*!
   215         *  ======== initBuffer ========
   216         *  Initializes the UIA packet header. 
   217         *
   218         *  This API is used to initialize a buffer before it is given to
   219         *  LoggerStreamer (via priming or exchange). The function initializes
   220         *  the UIAPacket portion of the buffer. 
   221         *
   222         *  @param(buffer)    Pointer to the buffer that LoggerStreamer will
   223         *                    fill with Log events. The first four 32-bit words
   224         *                    will contain the UIAPacket_Hdr structure.
   225         *
   226         *  @param(src)       Used to initialize the UIA source address. For 
   227         *                    a single core device, this will generally be 0.
   228         *                    For multi-core devices, it generally corresponds
   229         *                    to the DNUM (on C6xxxx deviecs) or the Ipc
   230         *                    MultiProc id. It must be unique for all cores and
   231         *                    match the configuration in the System Analyzer 
   232         *                    endpoint configuration.
   233         */
   234        @Macro Void initBuffer(Ptr buffer, UInt16 src);
   235    
   236        /*!
   237         *  ======== flush ========
   238         *  Force LoggerStreamer to call the exchange function
   239         * 
   240         *  This API makes LoggerStreamer call the application provided
   241         *  `{@link #exchangeFxn}` function if there are Log events present 
   242         *  in the buffer.
   243         *
   244         *  The call to the `{@link #exchangeFxn}` function is called in the 
   245         *  context of the flush call.     
   246         */
   247         Void flush();
   248             
   249             /*!
   250             *  ======== prime =========
   251             *  If PrimeFxn is not set the user must call prime with the first buffer.
   252             */
   253            Bool prime(Ptr buffer);
   254        
   255        /*!
   256         *  ======== ExchangeFxnType ========
   257         *  Typedef for the exchange function pointer. 
   258         */
   259        typedef Ptr (*ExchangeFxnType)(Ptr);
   260        
   261        /*!
   262         *  ======== PrimeFxnType ========
   263         *  Typedef for the exchange function pointer. 
   264         */
   265        typedef Ptr (*PrimeFxnType)(Void);
   266        
   267        /*!
   268         *  ======== bufSize ========
   269         *  LoggerStreamer buffer size in MAUs (Minimum Addressable Units e.g. Bytes)
   270         *  
   271         *  NOTE: the buffer size must contain an integer number of 32b words
   272         *  (e.g. if a MAU = 1 byte, then the buffer size must be a multiple of 4).
   273         *  The buffer size must also be at least maxEventSize + 64.
   274         */
   275        config SizeT bufSize = 1400;
   276        
   277        /*!
   278         *  ======== transportType ========
   279         *  Transport used to send the records to an instrumentation host
   280         *
   281         *  This parameter is used to specify the transport that the 
   282         *  `{@link #exchangeFxn}` function will use to send the buffer to
   283         *  an instrumentation host (e.g. System Analyzer in CCS).
   284         *
   285         *  This parameter is placed into the generated UIA XML file. The 
   286         *  instrumentation host can use the XML file to help it auto-detect as
   287         *  much as possible and act accordingly.
   288         *
   289         *  If the desired transport is not in the `{@link #TransportType}` enum,
   290         *  select `{@link #TransportType_CUSTOM}` and set the 
   291         *  `{@link #customTransportType}` string with the desired string.
   292         */
   293        metaonly config TransportType transportType = TransportType_ETHERNET;
   294        
   295        /*!
   296         *  ======== customTransportType ========
   297         *  Custom transport used to send the records to an instrumentation host
   298         *
   299         *  If the desired transport is not in the `{@link #TransportType}` enum,
   300         *  and `{@link #transportType}` is set to `{@link #TransportType_CUSTOM}`,
   301         *  this parameter must be filled in with the correct transport name.
   302         *
   303         *  If `{@link #transportType}` is NOT set to 
   304         *  `{@link #TransportType_CUSTOM}`, this parameter is ignored.
   305         */
   306        config String customTransportType = null;
   307        
   308        /*!
   309         *  ======== isTimestampEnabled ========
   310         *  Enable or disable logging the 64b local CPU timestamp
   311         *  at the start of each event
   312         *
   313         *  Having a timestamp allows an instrumentation host (e.g.
   314         *  System Analyzer) to display events with the correct system time.
   315         */
   316        config Bool isTimestampEnabled = false;    
   317        
   318        /*!
   319         * @_nodoc
   320         *  ======== isBadPacketDetectionEnabled ========
   321         *  Enable or disable checking that the event contents in the packet are 
   322         *  properly formatted with no data errors
   323         *
   324         *  If enabled, a breakpoint can be placed in the code to detect when 
   325         *  a bad packet is found.
   326         */
   327        config Bool isBadPacketDetectionEnabled = false;       
   328        /*!
   329         *  ======== supportLoggerDisable ========
   330         *  Allow LoggerStreamer to be enabled/disabled during runtime.
   331         */
   332        config Bool supportLoggerDisable = false;
   333        
   334        /*!
   335         *  ======== testForNullWrPtr ========
   336         *  Protect against log calls during the exchange function. 
   337         */
   338        config Bool testForNullWrPtr = true;
   339        
   340        /*!
   341         *  ======== primeFxn ========
   342         *  Function pointer to the prime function. 
   343         */
   344        config PrimeFxnType primeFxn = null;
   345        
   346        /*!
   347         *  ======== exchangeFxn ========
   348         *  Function pointer to the exchange function. 
   349         *
   350         *  exchange function must return a pointer to a buffer that is word aligned, initialized with 
   351         *  a UIA header and the correct size.  This is called in the context of a log
   352         *  so generally the exchange function should be quick to execute.
   353         */
   354        config ExchangeFxnType exchangeFxn = null;
   355        
   356       
   357        /*!
   358         *  ======== statusLogger ========
   359         *  This configuration option is not supported by this logger and should be left null.
   360         */
   361        config xdc.runtime.IFilterLogger.Handle statusLogger = null;
   362    
   363        /*!
   364         *  ======== level1Mask ========
   365         *  Mask of diags categories whose initial filtering level is Diags.LEVEL1
   366         *
   367         *  See '{@link #level4Mask}' for details.
   368         */
   369        config Diags.Mask level1Mask = 0;
   370    
   371        /*!
   372         *  ======== level2Mask ========
   373         *  Mask of diags categories whose initial filtering level is Diags.LEVEL2
   374         *
   375         *  See '{@link #level4Mask}' for details.
   376         */
   377        config Diags.Mask level2Mask = 0;
   378    
   379        /*!
   380         *  ======== level3Mask ========
   381         *  Mask of diags categories whose initial filtering level is Diags.LEVEL3
   382         *
   383         *  See '{@link #level4Mask}' for details.
   384         */
   385        config Diags.Mask level3Mask = 0;
   386    
   387        /*!
   388         *  ======== level4Mask ========
   389         *  Mask of diags categories whose initial filtering level is Diags.LEVEL4
   390         *
   391         *  If 'filterByLevel' is true, then all LoggerBuf instances will filter
   392         *  incoming events based on their event level.
   393         *
   394         *  The LoggerCircBuf module allows for specifying a different filter level for
   395         *  every Diags bit. These filtering levels are module wide; LoggerBuf does
   396         *  not support specifying the levels on a per-instance basis.
   397         *
   398         *  The setFilterLevel API can be used to change the filtering levels at
   399         *  runtime.
   400         *
   401         *  The default filtering levels are assigned using the 'level1Mask' -
   402         *  'level4Mask' config parameters. These are used to specify, for each of
   403         *  the four event levels, the set of bits which should filter at that
   404         *  level by default.
   405         *
   406         *  The default filtering configuration sets the filter level to
   407         *  Diags.LEVEL4 for all logging-related diags bits so that all events are
   408         *  logged by default.
   409         */
   410        config Diags.Mask level4Mask = Diags.ALL_LOGGING;
   411    
   412        /*!
   413         *  ======== moduleToRouteToStatusLogger ========
   414         *  This configuration option is not supported by this logger and should be left unconfigured.
   415         */
   416        metaonly config String moduleToRouteToStatusLogger;
   417    
   418        /*!
   419         *  ======== setModuleIdToRouteToStatusLogger ========
   420         *  This function is provided for compatibility with the ILoggerSnapshot interface only
   421         *  and simply returns when called.
   422         */
   423        @DirectCall
   424        Void setModuleIdToRouteToStatusLogger(Types.ModuleId mid);
   425        
   426        /*!
   427         * @_nodoc
   428         *  ======== L_test ========
   429         *  Event used to benchmark write0. 
   430         */
   431        config xdc.runtime.Log.Event L_test = {
   432            mask: xdc.runtime.Diags.USER1,    
   433            msg: "Test"
   434        };
   435    
   436        /*!
   437         * @_nodoc
   438         *  ======== E_badLevel ========
   439         *  Error raised if get or setFilterLevel receive a bad level value 
   440         */
   441        config Error.Id E_badLevel = {
   442             msg: "E_badLevel: Bad filter level value: %d"
   443        };   
   444        
   445        /*!
   446         * ======== maxEventSize ========
   447         * The maximum event size (in Maus) that can be written with a single event.
   448         * Must be less than or equal to bufSize - 64.
   449         *
   450         * The writeMemoryRange API checks to see if the event size required to write
   451         * the block of memory is larger than maxEventSize.  If so, it will split the
   452         * memory range up into a number of smaller blocks and log the blocks using 
   453         * separate events with a common snapshot ID in order to allow the events to be 
   454         * collated and the original memory block to be reconstructed on the host.
   455         */
   456        config SizeT maxEventSize = 512;
   457        
   458        /*!
   459         * @_nodoc    
   460         *  ======== validatePacket ========
   461         *  if isBadPacketDetectionEnabled is configured as true, this function is called prior
   462         *  to the exchange function being called.  
   463         * 
   464         *  Returns null if the packet is ok, else returns the address of a string
   465         *  that describes the error. 
   466         */
   467        @DirectCall
   468        Char* validatePacket(UInt32 *writePtr, UInt32 numBytesInPacket);   
   469            
   470    instance:
   471    
   472        /*!
   473         *  ======== create ========
   474         *  Create a `LoggerStreamer` logger
   475         */
   476        create();
   477    
   478        /*!
   479         *  ======== write0 ========
   480         *  Process a log event with 0 arguments and the calling address.
   481         *
   482         *  Same as `write4` except with 0 arguments rather than 4.
   483         *  @see #write4()
   484         */
   485        @DirectCall   
   486        override Void write0(xdc.runtime.Log.Event evt, 
   487                    xdc.runtime.Types.ModuleId mid);
   488        
   489        /*!
   490         *  ======== write1 ========
   491         *  Process a log event with 1 arguments and the calling address.
   492         *
   493         *  Same as `write4` except with 1 arguments rather than 4.
   494         *  @see #write4()
   495         */
   496        @DirectCall   
   497        override Void write1(xdc.runtime.Log.Event evt, 
   498                    xdc.runtime.Types.ModuleId mid, 
   499                    IArg a1);
   500                                
   501        /*!
   502         *  ======== write2 ========
   503         *  Process a log event with 2 arguments and the calling address.
   504         *
   505         *  Same as `write4` except with 2 arguments rather than 4.
   506         *  @see #write4()
   507         */
   508        @DirectCall   
   509        override Void write2(xdc.runtime.Log.Event evt, 
   510                    xdc.runtime.Types.ModuleId mid, 
   511                    IArg a1, IArg a2);
   512                                
   513        /*!
   514         *  ======== write4 ========
   515         *  Process a log event with 4 arguments and the calling address.
   516         *
   517         *  @see ILogger#write4()
   518         */@DirectCall   
   519        override Void write4(xdc.runtime.Log.Event evt, 
   520                    xdc.runtime.Types.ModuleId mid, 
   521                    IArg a1, IArg a2, IArg a3, IArg a4);
   522                                
   523        /*!
   524         *  ======== write8 ========
   525         *  Process a log event with 8 arguments and the calling address.
   526         *
   527         *  Same as `write4` except with 8 arguments rather than 4.
   528         *
   529         *  @see #write4()
   530         */
   531        @DirectCall   
   532        override Void write8(xdc.runtime.Log.Event evt, 
   533                    xdc.runtime.Types.ModuleId mid, 
   534                    IArg a1, IArg a2, IArg a3, IArg a4,
   535                    IArg a5, IArg a6, IArg a7, IArg a8);
   536    
   537        /*!
   538         *  ======== setFilterLevel ========
   539         *  Sets the level of detail that instances will log.
   540         *
   541         *  Events with the specified level or higher will be logged, events
   542         *  below the specified level will be dropped.
   543         *
   544         *  Events are filtered first by diags category, then by level. If an
   545         *  event's diags category is disabled in the module's diags mask, then it
   546         *  will be filtered out regardless of level. The event will not even be
   547         *  passed to the logger.
   548         *
   549         *  This API allows for setting the filtering level for more than one
   550         *  diags category at a time. The mask parameter can be a single category
   551         *  or multiple categories combined, and the level will be set for all of
   552         *  those categories.
   553         *
   554         *  @param(mask) The diags categories to set the level for
   555         *  @param(filterLevel) The new filtering level for the specified
   556         *                      categories
   557         */
   558        @DirectCall
   559        override Void setFilterLevel(Diags.Mask mask, Diags.EventLevel filterLevel);
   560    
   561        /*!
   562         *  ======== getFilterLevel ========
   563         *  Returns the mask of diags categories currently set to the specified
   564         *  level.
   565         *
   566         *  See '{@link #setFilterLevel}' for an explanation of level filtering.
   567         */
   568        @DirectCall
   569        override Diags.Mask getFilterLevel(Diags.EventLevel level);
   570    
   571     
   572        
   573    internal:
   574    
   575        /* Write size in bytes for generating event length */
   576        const Int WRITE0_SIZE_IN_BYTES = 8;
   577        const Int WRITE1_SIZE_IN_BYTES = 12;
   578        const Int WRITE2_SIZE_IN_BYTES = 16;
   579        const Int WRITE4_SIZE_IN_BYTES = 24;
   580        const Int WRITE8_SIZE_IN_BYTES = 40;
   581        /* Bytes added for timestamps; used for generating event length in bytes */
   582        const Int TIMESTAMP = 8;
   583        const Int NO_TIMESTAMP = 0;
   584    
   585        /*!
   586         *  ======== filterOutEvent ========
   587         */
   588        @DirectCall
   589        Bool filterOutEvent(Diags.Mask mask);
   590        
   591        /* 
   592         *  Interesting...I moved the enabled field to the end and performance 
   593         *  in the exchange case was slower by 4 cycles...
   594         */
   595        struct Module_State {
   596            Bool        enabled;       /* Enabled state */
   597            UInt32      *buffer;       /* Ptr to buffer */
   598            UInt32      *write;        /* Ptr to write location */
   599            UInt32      *end;
   600            Diags.Mask level1;
   601            Diags.Mask level2;
   602            Diags.Mask level3;
   603            Types.ModuleId moduleIdToRouteToStatusLogger;        
   604            SizeT maxEventSizeInBits32;
   605            Int  droppedEvents;        /* incremented by writeMemoryRange when event is too big to log or no buffers available */
   606        };
   607        
   608        struct Instance_State {
   609        };
   610    }