1    /*
     2     * Copyright (c) 2013, 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     */
    32    
    33    import xdc.rov.ViewInfo;
    34    import xdc.runtime.IHeap;
    35    import xdc.runtime.ILogger;
    36    import xdc.runtime.ITimestampClient;
    37    import xdc.runtime.Diags;
    38    import xdc.runtime.Log;
    39    import xdc.runtime.Assert;
    40    import xdc.runtime.Error;
    41    import xdc.runtime.Types;
    42    
    43    /*
    44     *  ======== LoggerBuf.xdc ========
    45     */
    46    
    47    /*!
    48     *  ======== LoggerBuf ========
    49     *  A logger which stores `Log` events in a buffer.
    50     *
    51     *  This module provides a logger which captures `{@link xdc.runtime.Log}` events to a
    52     *  buffer in realtime. The `Log` events stored in the buffer are
    53     *  unformatted; `Log` event formatting is deferred until some client reads
    54     *  the raw event data from the buffer. You can use
    55     *  `{@link #flush LoggerBuf_flush()}` to process the `Log` events stored
    56     *  in the buffer and stream the formatted output to stdout
    57     *  (via `{@link xdc.runtime.System#printf}`).  Alternatively, you can read a raw event
    58     *  (via `{@link #getNextEntry}`) and send it to another client that
    59     *  has the resources to format the event for display.
    60     *
    61     *  The implementation of this logger is fast with minimal stack usage
    62     *  making it appropriate for a realtime application.
    63     *  This logger writes all `Log` events to a circular buffer.  As a
    64     *  result, the execution time of all `Log` methods bound to this type
    65     *  of logger are deterministic (and quite short) because there are no
    66     *  additional memory allocation calls after the circular buffer was
    67     *  allocated.
    68     *
    69     *  If this logger is used in a preemptive environment, then an appropriate
    70     *  gate must be assigned to the module. For example, if events are generated
    71     *  from an interrupt context, then a gate that disables interrupts
    72     *  must be used.
    73     *
    74     *  @p(code)
    75     *  var LoggerBuf = xdc.useModule('xdc.runtime.LoggerBuf');
    76     *  LoggerBuf.common$.gate = ...some gate instance...
    77     *  @p
    78     *
    79     *  If the buffer type is circular, the log buffer of size
    80     *  `{@link #numEntries}` contains the last `numEntries` of `Log` events. If
    81     *  the buffer type is fixed, the log buffer contains the first
    82     *  `numEntries` events.
    83     *
    84     *  LoggerBuf supports routing of 'STATUS' events (errors and warnings) to a
    85     *  separate ILogger instance. This is helpful in preserving these critical
    86     *  events, which may otherwise be overwritten by lower priority events. This
    87     *  feature is disabled by default. See {@link #statusLogger}.
    88     *
    89     *  LoggerBuf implements the {@link xdc.runtime.IFilterLogger} interface and
    90     *  optionally supports filtering of events based on their detail level. This
    91     *  feature is disabled by default. See {@link xdc.runtime.IFilterLogger}.
    92     *
    93     *  @a(Examples)
    94     *  Configuration example: The following XDC configuration statements
    95     *  create a logger instance, assign it as the default logger for all
    96     *  modules, and enable `USER1` logging in all modules of the package
    97     *  `my.pkg`. See the `{@link xdc.runtime.Diags#setMaskMeta Diags.setMaskMeta()}` function
    98     *  for details on specifying the module names.
    99     *
   100     *  @p(code)
   101     *  var Defaults = xdc.useModule('xdc.runtime.Defaults');
   102     *  var Diags = xdc.useModule('xdc.runtime.Diags');
   103     *  var LoggerBuf = xdc.useModule('xdc.runtime.LoggerBuf');
   104     *
   105     *  LoggerBuf.enableFlush = true;
   106     *  var LoggerBufParams = new LoggerBuf.Params();
   107     *  LoggerBufParams.exitFlush = true;
   108     *  Defaults.common$.logger = LoggerBuf.create(LoggerBufParams);
   109     *  Diags.setMaskMeta("my.pkg.%", Diags.USER1, Diags.RUNTIME_ON);
   110     *  @p
   111     */
   112    
   113    @ModuleStartup      /* Initialize static instances */
   114    @InstanceFinalize   /* this mod has cleanup fxn when instances are deleted */
   115    @InstanceInitError  /* instance create can fail */
   116    @Gated
   117    
   118    module LoggerBuf inherits xdc.runtime.IFilterLogger {
   119    
   120        /*!
   121         *  ======== BufType ========
   122         *  Type of log buffer
   123         */
   124        enum BufType {
   125            BufType_CIRCULAR,  /*! The log buffer wraps, overwriting old entries */
   126            BufType_FIXED      /*! The log buffer halts collection when full */
   127        };
   128    
   129        metaonly struct BasicView {
   130            String label;
   131            Int lastSerial;
   132            Int numEntries;
   133            String type;
   134            Bool enabledFlag;
   135        };
   136    
   137        metaonly struct RecordView {
   138            Int     serial;
   139            Long    timestampRaw;
   140            UInt    core;
   141            String  modName;
   142            String  text;
   143            Int     eventId;
   144            String  eventName;
   145            IArg    arg0;
   146            IArg    arg1;
   147            IArg    arg2;
   148            IArg    arg3;
   149            IArg    arg4;
   150            IArg    arg5;
   151            IArg    arg6;
   152            IArg    arg7;
   153        }
   154    
   155        /*!
   156         *  ======== rovViewInfo ========
   157         *  @_nodoc
   158         */
   159        @Facet
   160        metaonly config xdc.rov.ViewInfo.Instance rovViewInfo =
   161            xdc.rov.ViewInfo.create({
   162                viewMap: [
   163                    ['Basic',
   164                        {
   165                            type: xdc.rov.ViewInfo.INSTANCE,
   166                            viewInitFxn: 'viewInitBasic',
   167                            structName: 'BasicView'
   168                        }
   169                    ],
   170                    ['Records',
   171                        {
   172                            type: xdc.rov.ViewInfo.INSTANCE_DATA,
   173                            viewInitFxn: 'viewInitRecords',
   174                            structName: 'RecordView'
   175                        }
   176                    ]
   177                ]
   178            });
   179    
   180        /*!
   181         *  ======== StopModeData ========
   182         *  Data added to the RTA MetaData file to support stop mode RTA
   183         */
   184        @XmlDtd metaonly struct StopModeData {
   185            String bufferSymbol;
   186            Int bufferSize;
   187        }
   188    
   189        /*!
   190         *  ======== E_badLevel ========
   191         *  Error raised if get or setFilterLevel receives a bad level value
   192         */
   193        config Error.Id E_badLevel =
   194            {msg: "E_badLevel: Bad filter level value: %d"};
   195    
   196        /*!
   197         *  ======== TimestampProxy ========
   198         *  User supplied time-stamp proxy
   199         *
   200         *  This proxy allows `LoggerBuf` to use a timestamp server different
   201         *  from the server used by `{@link xdc.runtime.Timestamp}`. However, if
   202         *  not supplied by a user, this proxy defaults to whichever timestamp
   203         *  server is used by `Timestamp`.
   204         */
   205        proxy TimestampProxy inherits ITimestampClient;
   206    
   207        /*!
   208         *  ======== enableFlush ========
   209         *  Flush all logs at system exit
   210         */
   211        config Bool enableFlush = false;
   212    
   213        /*!
   214         *  ======== statusLogger ========
   215         *  Route all 'STATUS' (error and warning) events to this logger.
   216         *
   217         *  If a statusLogger is specified, all LoggerBuf instances will check to
   218         *  determine if any of the events they receive are errors or warnings (if
   219         *  their diags mask includes the STATUS category), and will log these
   220         *  events to the statusLogger.
   221         *
   222         *  Error events are infrequent, but it's generally critical that they be
   223         *  seen. In a typical system, non-error events easily outnumber any error
   224         *  events, and the logger is likely to wrap, overwriting any error events.
   225         *  To protect these events from being overwritten and lost, they can be
   226         *  sent to their own separate logger to preserve them.
   227         *
   228         *  The default value is null, indicating that the STATUS events will just
   229         *  be logged by the logger they were sent to.
   230         */
   231        config ILogger.Handle statusLogger = null;
   232    
   233        /*!
   234         *  ======== level1Mask ========
   235         *  Mask of diags categories whose initial filtering level is Diags.LEVEL1
   236         *
   237         *  See '{@link #level4Mask}' for details.
   238         */
   239        config Diags.Mask level1Mask = 0;
   240    
   241        /*!
   242         *  ======== level2Mask ========
   243         *  Mask of diags categories whose initial filtering level is Diags.LEVEL2
   244         *
   245         *  See '{@link #level4Mask}' for details.
   246         */
   247        config Diags.Mask level2Mask = 0;
   248    
   249        /*!
   250         *  ======== level3Mask ========
   251         *  Mask of diags categories whose initial filtering level is Diags.LEVEL3
   252         *
   253         *  See '{@link #level4Mask}' for details.
   254         */
   255        config Diags.Mask level3Mask = 0;
   256    
   257        /*!
   258         *  ======== level4Mask ========
   259         *  Mask of diags categories whose initial filtering level is Diags.LEVEL4
   260         *
   261         *  If `{@link xdc.runtime.IFilterLogger.filterByLevel}` is `true`, then all
   262         *  `LoggerBuf` instances will filter incoming events based on their
   263         *  event level.
   264         *
   265         *  The `LoggerBuf` module allows for specifying a different filter level
   266         *  for every `Diags` bit. These filtering levels are module wide;
   267         *  `LoggerBuf` does not support specifying the levels on a per-instance
   268         *  basis.
   269         *
   270         *  The `{@link xdc.runtime.IFilterLogger.setFilterLevel}` function can be used to
   271         *  change the filtering levels at runtime.
   272         *
   273         *  The default filtering levels are assigned using the `level1Mask` -
   274         *  `level4Mask` config parameters. These are used to specify, for each of
   275         *  the four event levels, the set of bits which should filter at that
   276         *  level by default.
   277         *
   278         *  The default filtering configuration sets the filter level to
   279         *  `Diags.LEVEL4` for all logging-related diags bits so that all events
   280         *  are logged by default.
   281         */
   282        config Diags.Mask level4Mask = Diags.ALL_LOGGING;
   283    
   284        /*!
   285         *  ======== flushAll ========
   286         *  Flush logs of all instances that set `exitFlush` to true
   287         *
   288         *  The user is responsible for making sure that no `LoggerBuf` instances
   289         *  are created or deleted during the execution of this function.
   290         */
   291        Void flushAll();
   292    
   293        /*!
   294         *  ======== flushAllInternal ========
   295         *  @_nodoc
   296         */
   297        Void flushAllInternal(Int stat);
   298    
   299        /*!
   300         *  ======== initDecoder ========
   301         * @_nodoc
   302         *  Initialize the LoggerBufDecoder for use in the LoggerBuf 'Records' ROV
   303         *  view.
   304         */
   305        function initDecoder();
   306    
   307    instance:
   308        /*!
   309         *  ======== create ========
   310         *  Create a `LoggerBuf` logger
   311         *
   312         *  @see LoggerBuf#Params
   313         */
   314        create();
   315    
   316        /*!
   317         *  ======== numEntries ========
   318         *  Number of entries in buffer
   319         *
   320         *  Each entry is large enough to store one `Log` event containing up to
   321         *  4 optional arguments.  Events containing more than 4 arguments (such
   322         *  as those from `{@link xdc.runtime.Log#write5}`) use 2 entries.
   323         *
   324         *  `numEntries` must be a power of 2.
   325         */
   326        config Int numEntries = 64;
   327    
   328        /*!
   329         *  ======== bufType ========
   330         *  Log buffer type
   331         */
   332        config BufType bufType = BufType_CIRCULAR;
   333    
   334        /*!
   335         *  ======== exitFlush ========
   336         *  Flush log at system exit
   337         *
   338         *  Only used when module parameter `{@link #enableFlush}` is `true`.
   339         */
   340        config Bool exitFlush = false;
   341    
   342        /*!
   343         *  ======== bufSection ========
   344         *  Section name for the buffer managed by the static instance.
   345         *
   346         *  The default section is the 'dataSection' in the platform.
   347         */
   348        metaonly config String bufSection = null;
   349    
   350        /*!
   351         *  ======== bufHeap ========
   352         *  The heap that contains the `Log` buffer for dynamic instances.
   353         *
   354         *  The default value `null` means the buffer will be allocated from
   355         *  the `{@link xdc.runtime.Memory#defaultHeapInstance}` heap.
   356         */
   357        config IHeap.Handle bufHeap = null;
   358    
   359        /*!
   360         *  ======== reset ========
   361         *  Reset a log to empty state and enable it
   362         *
   363         *  @a(WARNING)  This method is not synchronized with other instance
   364         *  methods and, as a result, it must never be called when there is a
   365         *  chance that another instance method is currently in operation or
   366         *  when another method on this instance may preempt this call.
   367         */
   368        Void reset();
   369    
   370        /*!
   371         *  ======== flush ========
   372         *  Read, clear, and output the contents of the log
   373         *
   374         *  This method reads, clears, and "prints" each `Log` event (via
   375         *  `{@link xdc.runtime.System#printf}`) in the log.
   376         */
   377        Void flush();
   378    
   379        /*!
   380         *  ======== getNextEntry ========
   381         *  Fills the passed `{@link xdc.runtime.Log#EventRec}` with the next entry in the log.
   382         *
   383         *  This function is used to read and clear `Log` events from the
   384         *  buffer maintained by the `LoggerBuf` instance. The `Log` event can
   385         *  then be transmitted and displayed on a host.
   386         *
   387         *  A read pointer is maintained in the `LoggerBuf` instance and
   388         *  points to the next record to read.  Entries are not necessarily
   389         *  returned in chronological order, since buffers of type
   390         *  `{@link #BufType_CIRCULAR}` can wrap.
   391         *
   392         *  @param(evtRec) pointer to a supplied `EventRec` object where the next
   393         *                 entry in the log is copied to
   394         *
   395         *  @a(returns)
   396         *  This function reports the number of entries actually read. The only
   397         *  values that can be returned are:
   398         *  @p(blist)
   399         *      - 0   no more entries to read
   400         *      - 1 or 2 read a complete entry written by `write4` or `write8`
   401         *      - -1  cleared an incomplete/overwritten entry, more entries to read
   402         */
   403        Int getNextEntry(Log.EventRec *evtRec);
   404    
   405    internal:
   406    
   407        Bool filterOutEvent(Diags.Mask mask);
   408    
   409        /*
   410         *  ======== instanceStartup ========
   411         */
   412        Void instanceStartup(Object *obj);
   413    
   414        const Int8 FULL = -1;
   415        const Int8 WRAP = 0;
   416    
   417        const Int8 NEXT = 1;
   418    
   419        struct Entry {
   420            Types.Timestamp64 tstamp;
   421            Bits32 serial;
   422            Types.Event evt;
   423            IArg arg1;
   424            IArg arg2;
   425            IArg arg3;
   426            IArg arg4;
   427        };
   428    
   429        struct Module_State {
   430            Diags.Mask level1;
   431            Diags.Mask level2;
   432            Diags.Mask level3;
   433        };
   434    
   435        struct Instance_State {
   436            IHeap.Handle bufHeap;
   437            Entry entryArr[];
   438            Entry *curEntry;
   439            Entry *endEntry;
   440            Entry *readEntry;
   441            Bits32 serial;
   442            Int16 numEntries;
   443            Int8 advance;
   444            Bool enabled;
   445            Bool flush;
   446        };
   447    
   448    }