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