1    /*
     2     * Copyright (c) 2012, 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    /*
    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
    50     *  includes managing the sending of the buffers to an instrumentation host
    51     *  (e.g. System Analyzer in CCS).  The logger is named "LoggerStreamer"
    52     *  because it is designed to enable the application to send a stream of
    53     *  packets containing UIA event data to the instrumentation host.
    54     *
    55     *  The application is responsible for providing the buffers that
    56     *  LoggerStreamer 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
    85     *  exchange function should be designed to be fast. Since the exchange
    86     *  function is called within the context of the Log call, LoggerStreamer
    87     *  guarantees no Log 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.
   270         *  Bytes)
   271         *
   272         *  NOTE: the buffer size must contain an integer number of 32b words
   273         *  (e.g. if a MAU = 1 byte, then the buffer size must be a multiple of 4).
   274         *  The buffer size must also be at least maxEventSize + 64.
   275         */
   276        config SizeT bufSize = 1400;
   277    
   278        /*!
   279         *  ======== transportType ========
   280         *  Transport used to send the records to an instrumentation host
   281         *
   282         *  This parameter is used to specify the transport that the
   283         *  `{@link #exchangeFxn}` function will use to send the buffer to
   284         *  an instrumentation host (e.g. System Analyzer in CCS).
   285         *
   286         *  This parameter is placed into the generated UIA XML file. The
   287         *  instrumentation host can use the XML file to help it auto-detect as
   288         *  much as possible and act accordingly.
   289         *
   290         *  If the desired transport is not in the `{@link #TransportType}` enum,
   291         *  select `{@link #TransportType_CUSTOM}` and set the
   292         *  `{@link #customTransportType}` string with the desired string.
   293         */
   294        metaonly config TransportType transportType = TransportType_ETHERNET;
   295    
   296        /*!
   297         *  ======== customTransportType ========
   298         *  Custom transport used to send the records to an instrumentation host
   299         *
   300         *  If the desired transport is not in the `{@link #TransportType}` enum,
   301         *  and `{@link #transportType}` is set to `{@link #TransportType_CUSTOM}`,
   302         *  this parameter must be filled in with the correct transport name.
   303         *
   304         *  If `{@link #transportType}` is NOT set to
   305         *  `{@link #TransportType_CUSTOM}`, this parameter is ignored.
   306         */
   307        config String customTransportType = null;
   308    
   309        /*!
   310         *  ======== isTimestampEnabled ========
   311         *  Enable or disable logging the 64b local CPU timestamp
   312         *  at the start of each event
   313         *
   314         *  Having a timestamp allows an instrumentation host (e.g.
   315         *  System Analyzer) to display events with the correct system time.
   316         */
   317        config Bool isTimestampEnabled = false;
   318    
   319        /*!
   320         * @_nodoc
   321         *  ======== isBadPacketDetectionEnabled ========
   322         *  Enable or disable checking that the event contents in the packet are
   323         *  properly formatted with no data errors
   324         *
   325         *  If enabled, a breakpoint can be placed in the code to detect when
   326         *  a bad packet is found.
   327         */
   328        config Bool isBadPacketDetectionEnabled = false;
   329        /*!
   330         *  ======== supportLoggerDisable ========
   331         *  Allow LoggerStreamer to be enabled/disabled during runtime.
   332         */
   333        config Bool supportLoggerDisable = false;
   334    
   335        /*!
   336         *  ======== testForNullWrPtr ========
   337         *  Protect against log calls during the exchange function.
   338         */
   339        config Bool testForNullWrPtr = true;
   340    
   341        /*!
   342         *  ======== primeFxn ========
   343         *  Function pointer to the prime function.
   344         */
   345        config PrimeFxnType primeFxn = null;
   346    
   347        /*!
   348         *  ======== exchangeFxn ========
   349         *  Function pointer to the exchange function.
   350         *
   351         *  exchange function must return a pointer to a buffer that is word
   352         *  aligned, initialized with a UIA header and the correct size.  This is
   353         *  called in the context of a log so generally the exchange function
   354         *  should be quick to execute.
   355         */
   356        config ExchangeFxnType exchangeFxn = null;
   357    
   358    
   359        /*!
   360         *  ======== statusLogger ========
   361         *  This configuration option is not supported by this logger and should
   362         *  be left null.
   363         */
   364        config xdc.runtime.IFilterLogger.Handle statusLogger = null;
   365    
   366        /*!
   367         *  ======== level1Mask ========
   368         *  Mask of diags categories whose initial filtering level is Diags.LEVEL1
   369         *
   370         *  See '{@link #level4Mask}' for details.
   371         */
   372        config Diags.Mask level1Mask = 0;
   373    
   374        /*!
   375         *  ======== level2Mask ========
   376         *  Mask of diags categories whose initial filtering level is Diags.LEVEL2
   377         *
   378         *  See '{@link #level4Mask}' for details.
   379         */
   380        config Diags.Mask level2Mask = 0;
   381    
   382        /*!
   383         *  ======== level3Mask ========
   384         *  Mask of diags categories whose initial filtering level is Diags.LEVEL3
   385         *
   386         *  See '{@link #level4Mask}' for details.
   387         */
   388        config Diags.Mask level3Mask = 0;
   389    
   390        /*!
   391         *  ======== level4Mask ========
   392         *  Mask of diags categories whose initial filtering level is Diags.LEVEL4
   393         *
   394         *  If 'filterByLevel' is true, then all LoggerBuf instances will filter
   395         *  incoming events based on their event level.
   396         *
   397         *  The LoggerCircBuf module allows for specifying a different filter level
   398         *  for every Diags bit. These filtering levels are module wide; LoggerBuf
   399         *  does not support specifying the levels on a per-instance basis.
   400         *
   401         *  The setFilterLevel API can be used to change the filtering levels at
   402         *  runtime.
   403         *
   404         *  The default filtering levels are assigned using the 'level1Mask' -
   405         *  'level4Mask' config parameters. These are used to specify, for each of
   406         *  the four event levels, the set of bits which should filter at that
   407         *  level by default.
   408         *
   409         *  The default filtering configuration sets the filter level to
   410         *  Diags.LEVEL4 for all logging-related diags bits so that all events are
   411         *  logged by default.
   412         */
   413        config Diags.Mask level4Mask = Diags.ALL_LOGGING;
   414    
   415        /*!
   416         *  ======== moduleToRouteToStatusLogger ========
   417         *  This configuration option is not supported by this logger and should
   418         *  be left unconfigured.
   419         */
   420        metaonly config String moduleToRouteToStatusLogger;
   421    
   422        /*!
   423         *  ======== setModuleIdToRouteToStatusLogger ========
   424         *  This function is provided for compatibility with the ILoggerSnapshot
   425         *  interface only and simply returns when called.
   426         */
   427        @DirectCall
   428        Void setModuleIdToRouteToStatusLogger(Types.ModuleId mid);
   429    
   430        /*!
   431         * @_nodoc
   432         *  ======== L_test ========
   433         *  Event used to benchmark write0.
   434         */
   435        config xdc.runtime.Log.Event L_test = {
   436            mask: xdc.runtime.Diags.USER1,
   437            msg: "Test"
   438        };
   439    
   440        /*!
   441         * @_nodoc
   442         *  ======== E_badLevel ========
   443         *  Error raised if get or setFilterLevel receive a bad level value
   444         */
   445        config Error.Id E_badLevel = {
   446             msg: "E_badLevel: Bad filter level value: %d"
   447        };
   448    
   449        /*!
   450         *  ======== maxEventSize ========
   451         *  The maximum event size (in Maus) that can be written with a single
   452         *  event. Must be less than or equal to bufSize - 64.
   453         *
   454         *  The writeMemoryRange API checks to see if the event size required to
   455         *  write the block of memory is larger than maxEventSize.  If so, it will
   456         *  split the memory range up into a number of smaller blocks and log the
   457         *  blocks using separate events with a common snapshot ID in order to
   458         *  allow the events to be collated and the original memory block to be
   459         *  reconstructed on the host.
   460         */
   461        config SizeT maxEventSize = 512;
   462    
   463        /*!
   464         * @_nodoc
   465         *  ======== validatePacket ========
   466         *  if isBadPacketDetectionEnabled is configured as true, this function is
   467         *  called prior to the exchange function being called.
   468         *
   469         *  Returns null if the packet is ok, else returns the address of a string
   470         *  that describes the error.
   471         */
   472        @DirectCall
   473        Char* validatePacket(UInt32 *writePtr, UInt32 numBytesInPacket);
   474    
   475    instance:
   476    
   477        /*!
   478         *  ======== create ========
   479         *  Create a `LoggerStreamer` logger
   480         */
   481        create();
   482    
   483        /*!
   484         *  ======== write0 ========
   485         *  Process a log event with 0 arguments and the calling address.
   486         *
   487         *  Same as `write4` except with 0 arguments rather than 4.
   488         *  @see #write4()
   489         */
   490        @DirectCall
   491        override Void write0(xdc.runtime.Log.Event evt,
   492                    xdc.runtime.Types.ModuleId mid);
   493    
   494        /*!
   495         *  ======== write1 ========
   496         *  Process a log event with 1 arguments and the calling address.
   497         *
   498         *  Same as `write4` except with 1 arguments rather than 4.
   499         *  @see #write4()
   500         */
   501        @DirectCall
   502        override Void write1(xdc.runtime.Log.Event evt,
   503                    xdc.runtime.Types.ModuleId mid,
   504                    IArg a1);
   505    
   506        /*!
   507         *  ======== write2 ========
   508         *  Process a log event with 2 arguments and the calling address.
   509         *
   510         *  Same as `write4` except with 2 arguments rather than 4.
   511         *  @see #write4()
   512         */
   513        @DirectCall
   514        override Void write2(xdc.runtime.Log.Event evt,
   515                    xdc.runtime.Types.ModuleId mid,
   516                    IArg a1, IArg a2);
   517    
   518        /*!
   519         *  ======== write4 ========
   520         *  Process a log event with 4 arguments and the calling address.
   521         *
   522         *  @see ILogger#write4()
   523         */@DirectCall
   524        override Void write4(xdc.runtime.Log.Event evt,
   525                    xdc.runtime.Types.ModuleId mid,
   526                    IArg a1, IArg a2, IArg a3, IArg a4);
   527    
   528        /*!
   529         *  ======== write8 ========
   530         *  Process a log event with 8 arguments and the calling address.
   531         *
   532         *  Same as `write4` except with 8 arguments rather than 4.
   533         *
   534         *  @see #write4()
   535         */
   536        @DirectCall
   537        override Void write8(xdc.runtime.Log.Event evt,
   538                    xdc.runtime.Types.ModuleId mid,
   539                    IArg a1, IArg a2, IArg a3, IArg a4,
   540                    IArg a5, IArg a6, IArg a7, IArg a8);
   541    
   542        /*!
   543         *  ======== setFilterLevel ========
   544         *  Sets the level of detail that instances will log.
   545         *
   546         *  Events with the specified level or higher will be logged, events
   547         *  below the specified level will be dropped.
   548         *
   549         *  Events are filtered first by diags category, then by level. If an
   550         *  event's diags category is disabled in the module's diags mask, then it
   551         *  will be filtered out regardless of level. The event will not even be
   552         *  passed to the logger.
   553         *
   554         *  This API allows for setting the filtering level for more than one
   555         *  diags category at a time. The mask parameter can be a single category
   556         *  or multiple categories combined, and the level will be set for all of
   557         *  those categories.
   558         *
   559         *  @param(mask) The diags categories to set the level for
   560         *  @param(filterLevel) The new filtering level for the specified
   561         *                      categories
   562         */
   563        @DirectCall
   564        override Void setFilterLevel(Diags.Mask mask, Diags.EventLevel filterLevel);
   565    
   566        /*!
   567         *  ======== getFilterLevel ========
   568         *  Returns the mask of diags categories currently set to the specified
   569         *  level.
   570         *
   571         *  See '{@link #setFilterLevel}' for an explanation of level filtering.
   572         */
   573        @DirectCall
   574        override Diags.Mask getFilterLevel(Diags.EventLevel level);
   575    
   576    
   577    
   578    internal:
   579    
   580        /* Write size in bytes for generating event length */
   581        const Int WRITE0_SIZE_IN_BYTES = 8;
   582        const Int WRITE1_SIZE_IN_BYTES = 12;
   583        const Int WRITE2_SIZE_IN_BYTES = 16;
   584        const Int WRITE4_SIZE_IN_BYTES = 24;
   585        const Int WRITE8_SIZE_IN_BYTES = 40;
   586        /* Bytes added for timestamps; used for generating event length in bytes */
   587        const Int TIMESTAMP = 8;
   588        const Int NO_TIMESTAMP = 0;
   589    
   590        /*!
   591         *  ======== filterOutEvent ========
   592         */
   593        @DirectCall
   594        Bool filterOutEvent(Diags.Mask mask);
   595    
   596        /*
   597         *  Interesting...I moved the enabled field to the end and performance
   598         *  in the exchange case was slower by 4 cycles...
   599         */
   600        struct Module_State {
   601            Bool        enabled;       /* Enabled state */
   602            UInt32      *buffer;       /* Ptr to buffer */
   603            UInt32      *write;        /* Ptr to write location */
   604            UInt32      *end;
   605            Diags.Mask level1;
   606            Diags.Mask level2;
   607            Diags.Mask level3;
   608            Types.ModuleId moduleIdToRouteToStatusLogger;
   609            SizeT maxEventSizeInBits32;
   610    
   611            /*
   612             *  incremented by writeMemoryRange when event is too big to log or
   613             *  no buffers available
   614             */
   615            Int  droppedEvents;
   616        };
   617    
   618        struct Instance_State {
   619        };
   620    }