1    /*
     2     * Copyright (c) 2013-2014, 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    /*
    34     *  ======== LoggerIdle.xdc ========
    35     */
    36    import xdc.runtime.ILogger;
    37    import xdc.runtime.Log;
    38    import xdc.rov.ViewInfo;
    39    
    40    /*!
    41     *  ======== LoggerIdle ========
    42     *  A logger which routes `Log` events to a users transport function.
    43     *
    44     *  This logger processes log events as they are generated, stores them in
    45     *  a buffer and during idle sends a section of the buffer to the user's
    46     *  transport function.  If you are seeing no log events or dropping too
    47     *  many events check that you are not logging too often and have enough idle
    48     *  time to send. LoggerIdle is compatable with StellarisWare and MWare
    49     *  devices. Example transports for UART (B92 and F28M35x) and USB (F28M35x)
    50     *  as well as initialization functions are included in the evmF28M35x.c files
    51     *  under the device folder in the ti.examples directory.
    52     *
    53     *  @a(Examples)
    54     *  Configuration example: The following XDC configuration statements
    55     *  create a logger module, and assign it as the default logger for all
    56     *  modules.
    57     *
    58     *  @p(code)
    59     *  var Defaults = xdc.useModule('xdc.runtime.Defaults');
    60     *  var Diags = xdc.useModule('xdc.runtime.Diags');
    61     *  var LoggerIdle = xdc.useModule('ti.uia.sysbios.LoggerIdle');
    62     *
    63     *  LoggerIdle.bufferSize = 60;
    64     *  LoggerIdle.timestamp = false;
    65     *  LoggerIdle.transportType = LoggerIdle.TransportType_UART;
    66     *  LoggerIdle.transportFxn = '&LoggerIdle_uartSend';
    67     *  var LoggerIdleParams = new LoggerIdle.Params();
    68     *  Defaults.common$.logger = LoggerIdle.create(LoggerIdleParams);
    69     *  @p
    70     */
    71    
    72    @Template("./LoggerIdle.xdt")
    73    module LoggerIdle inherits ILogger {
    74    
    75        /*!
    76         *  ======== TransportType ========
    77         *  Used to specify the type of transport to use
    78         *
    79         *  This enum is used by the instrumentation host to determine what
    80         *  the transport is. It is not used by the target code.
    81         */
    82        enum TransportType {
    83            TransportType_UART = 0,
    84            TransportType_USB = 1,
    85            TransportType_ETHERNET = 2,
    86            TransportType_CUSTOM = 3
    87        };
    88    
    89        /*!
    90         *  @_nodoc
    91         *  ======== ModuleView ========
    92         */
    93        metaonly struct ModuleView {
    94            Bool       isEnabled;
    95            Bool       isTimestampEnabled;
    96            Int        bufferSize;
    97            UInt       sequenceNumber;
    98            String     transportType;
    99            String     customTransport;
   100        }
   101    
   102        metaonly struct RecordView {
   103            Int     sequence;
   104            Long    timestampRaw;
   105            String  modName;
   106            String  text;
   107            Int     eventId;
   108            String  eventName;
   109            IArg    arg0;
   110            IArg    arg1;
   111            IArg    arg2;
   112            IArg    arg3;
   113            IArg    arg4;
   114            IArg    arg5;
   115            IArg    arg6;
   116            IArg    arg7;
   117        }
   118    
   119        /*!
   120         *  @_nodoc
   121         *  ======== rovViewInfo ========
   122         */
   123        @Facet
   124        metaonly config ViewInfo.Instance rovViewInfo =
   125            ViewInfo.create({
   126                viewMap: [
   127                    ['Module',
   128                        {
   129                            type: ViewInfo.MODULE,
   130                            viewInitFxn: 'viewInitModule',
   131                            structName: 'ModuleView'
   132                        }
   133                    ],
   134                    ['Records',
   135                        {
   136                            type: xdc.rov.ViewInfo.MODULE_DATA,
   137                            viewInitFxn: 'viewInitRecords',
   138                            structName: 'RecordView'
   139                        }
   140                    ]
   141                ]
   142            });
   143    
   144        /*!
   145         *  ======== RtaData ========
   146         *  Data added to the RTA MetaData file to support System Analyzer
   147         */
   148        @XmlDtd metaonly struct RtaData {
   149            Int instanceId;
   150        }
   151    
   152        /*!
   153         *  ======== LoggerFxn ========
   154         *  Typedef for the transport function pointer.
   155         */
   156        typedef Int (*LoggerFxn)(UChar *, Int);
   157    
   158        /*!
   159         *  ======== bufferSize ========
   160         *  LoggerIdle buffer size in 32-bit words.
   161         */
   162        config SizeT bufferSize = 256;
   163    
   164        /*!
   165         *  ======== isTimestampEnabled ========
   166         *  Enable or disable logging the 64b local CPU timestamp
   167         *  at the start of each event
   168         *
   169         *  Having a timestamp allows an instrumentation host (e.g.
   170         *  System Analyzer) to display events with the correct system time.
   171         */
   172        config Bool isTimestampEnabled = true;
   173    
   174        /*!
   175         *  ======== transportType ========
   176         *  Transport used to send the records to an instrumentation host
   177         *
   178         *  This parameter is used to specify the transport that the
   179         *  `{@link #transportFxn}` function will use to send the buffer to
   180         *  an instrumentation host (e.g. System Analyzer in CCS).
   181         *
   182         *  This parameter is placed into the generated UIA XML file. The
   183         *  instrumentation host can use the XML file to help it auto-detect as
   184         *  much as possible and act accordingly.
   185         *
   186         *  If the desired transport is not in the `{@link #TransportType}` enum,
   187         *  select `{@link #TransportType_CUSTOM}` and set the
   188         *  `{@link #customTransportType}` string with the desired string.
   189         */
   190        metaonly config TransportType transportType = TransportType_UART;
   191    
   192        /*!
   193         *  ======== customTransportType ========
   194         *  Custom transport used to send the records to an instrumentation host
   195         *
   196         *  If the desired transport is not in the `{@link #TransportType}` enum,
   197         *  and `{@link #transportType}` is set to `{@link #TransportType_CUSTOM}`,
   198         *  this parameter must be filled in with the correct transport name.
   199         *
   200         *  If `{@link #transportType}` is NOT set to
   201         *  `{@link #TransportType_CUSTOM}`, this parameter is ignored.
   202         */
   203        config String customTransportType = null;
   204    
   205        /*!
   206         *  ======== transportFxn ========
   207         *  User defined transport function responsible for transmitting the records
   208         */
   209        config LoggerFxn transportFxn = null;
   210    
   211        /*!
   212         *  @_nodoc
   213         *  ======== writeWhenFull ========
   214         *
   215         *  This configuration parameter has been deprecated.  The behavior
   216         *  is now to always allow wtites when the LoggerIdle buffer is full.
   217         *
   218         *  Allow Log writes to succeed even if the the LoggerIdle buffer is
   219         *  full.
   220         *
   221         *  LoggerIdle maintains a circular buffer where the Log events are
   222         *  written.  A write pointer indicates the location in the buffer
   223         *  where the next Log event can be written to, and a read pointer
   224         *  indicates the location of the next Log event to be sent to the
   225         *  user's transport function.  Log write calls cause the write pointer
   226         *  to advance, and when Log data is passed to the user's transport
   227         *  function in the idle loop, the read pointer advances. If the
   228         *  read pointer catches up the the write pointer, the buffer is
   229         *  'empty', and if the write pointer catches up the the read pointer,
   230         *  the buffer is full.
   231         *
   232         *  The LoggerIdle buffer will fill up, if the idle function to output
   233         *  the Log data cannot keep up with the Log writes. When this happens,
   234         *  if writeWhenFull is false, Log writes will not put any new data
   235         *  into the buffer until the LoggerIdle transportFxn has been called
   236         *  to empty some of the buffer.  As a result, the most recent Log
   237         *  events could be lost. This is a simple solution to dealing with a
   238         *  full buffer. Since Log event sizes vary, it avoids having to
   239         *  determine how much the read pointer must be adjusted to fit a new
   240         *  Log event. It also allows you to send a large chunk of the buffer
   241         *  to the transport function in one shot, since the data will not
   242         *  be overwritten by Log writes during the transfer. If Log events
   243         *  are infrequent or the idle time is sufficient to get the Log
   244         *  data out, then disabling writeWhenFull may be appropriate.
   245         *
   246         *  When this flag is set to true, if the LoggerIdle buffer is full,
   247         *  new Log data will be written over the oldest Log record(s) in the
   248         *  buffer.  The oldest Log records in the buffer will be lost when
   249         *  this happens.
   250         *
   251         *  The cost of enabling writeWhenFull is an increase in Log write
   252         *  times when the buffer is full, as the buffer's read pointer will
   253         *  need adjusting. There is also more overhead to get the Log data
   254         *  out through the transport function. When writeWhenFull is enabled,
   255         *  LoggerIdle's idle function will copy one Log record at a time into
   256         *  a temporary buffer, and send the temporary buffer to the user's
   257         *  transport function. This is to minimize interrupt latency, as the
   258         *  buffer's read pointer can now be modified by both the idle function
   259         *  and Log writes, and must be protected. The advantage, though, is
   260         *  that you will not lose the most recent Log data when the buffer is
   261         *  full.  If Log events are frequent and the idle time is insufficient
   262         *  to get the Log data out, then enabling writeWhenFull may be
   263         *  appropriate.
   264         */
   265        config Bool writeWhenFull = false;
   266    
   267        /*!
   268         *  @_nodoc
   269         *  ======== L_test ========
   270         *  Event used for benchmark tests
   271         */
   272        config xdc.runtime.Log.Event L_test = {
   273            mask: xdc.runtime.Diags.USER1,
   274            msg: "Test Event"
   275        };
   276    
   277        /*!
   278         *  ======== flush ========
   279         *  Call the transport function to empty out the LoggerIdle buffer.
   280         *
   281         *  This API is not intended for general use, but could be used for
   282         *  example, in an exception handler to recover the most recent Log
   283         *  data that was written after the last run of the idle loop.
   284         *
   285         *  NOTE:  Calling LoggerIdle_flush() when the idle task was in the
   286         *  middle of outputting data can result in lost data.  Since the idle
   287         *  function only outputs one Log record at a time, so at most one record
   288         *  could be lost.
   289         */
   290        Void flush();
   291    
   292        /*!
   293         *  @_nodoc
   294         *  ======== initDecoder ========
   295         *  Initialize the Java LoggerIdleDecoder for use in the LoggerIdle
   296         *  'Records' ROV view.
   297         */
   298        function initDecoder();
   299    
   300    instance:
   301        /*!
   302         *  ======== create ========
   303         *  Create a `LoggerIdle` logger
   304         *
   305         *  The logger instance will route all log events it receives to
   306         *  the Uart.
   307         */
   308        create();
   309    
   310        @DirectCall
   311        override Void write0(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid);
   312    
   313        @DirectCall
   314        override Void write1(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid,
   315                                IArg a1);
   316    
   317        @DirectCall
   318        override Void write2(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid,
   319                                IArg a1, IArg a2);
   320    
   321        @DirectCall
   322        override Void write4(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid,
   323                                IArg a1, IArg a2, IArg a3, IArg a4);
   324    
   325        @DirectCall
   326        override Void write8(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid,
   327                                IArg a1, IArg a2, IArg a3, IArg a4,
   328                                IArg a5, IArg a6, IArg a7, IArg a8);
   329    
   330    internal:
   331    
   332        /*!
   333         *  ======== idleWrite =========
   334         *  Idle function that calls the transport function.
   335         */
   336        Void idleWrite();
   337    
   338        /*!
   339         *  ======== idleWriteEvent =========
   340         *  Idle function that calls the transport function to write one
   341         *  Log event.
   342         */
   343        Void idleWriteEvent();
   344    
   345        Void write(Log.Event evt, xdc.runtime.Types.ModuleId mid,
   346                IArg numEventWords,
   347                IArg a1, IArg a2, IArg a3, IArg a4,
   348                IArg a5, IArg a6, IArg a7, IArg a8);
   349    
   350        struct Module_State {
   351            LoggerFxn loggerFxn;
   352            Bool enabled;          /* If the logger is enabled or not */
   353            Bool empty;         /* True if there is data in the buffer */
   354            UInt bufferSize;       /* Size of the buffer in words */
   355            UInt32 idleBuffer[];   /* Stores log events to be sent */
   356            UInt32 tempBuffer[];   /* For copying Event records into. */
   357            UInt32 *bufferRead;    /* Pointer to the first word to be read */
   358            UInt32 *bufferWrite;   /* Pointer to the next word to write to */
   359            UInt32 *bufferPad;     /* Pointer to the last word in the buffer when
   360                                      the buffer overflows into the 10 word pad */
   361            UInt32 *bufferEnd;     /* Pointer to begining of the buffer pad */
   362            UInt16  eventSequenceNum;  /* event sequence number */
   363        };
   364    
   365        struct Instance_State {
   366        };
   367    }