1    /*
     2     * Copyright (c) 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     *  ======== Mailbox.xdc ========
    34     *
    35     */
    36    package ti.sysbios.knl;
    37    
    38    import xdc.rov.ViewInfo;
    39    
    40    import xdc.runtime.IHeap;
    41    
    42    /*!
    43     *  ======== Mailbox ========
    44     *  Mailbox Manager
    45     *
    46     *  The Mailbox module makes available a set of functions that manipulate
    47     *  mailbox objects accessed through handles of type Mailbox_Handle.
    48     *
    49     *  {@link #pend()} is used to wait for a message from a mailbox. 
    50     *  The timeout parameter to Mailbox_pend allows the task to wait until a 
    51     *  timeout specified in terms of system clock ticks. 
    52     *  A timeout value of {@link ti.sysbios.BIOS#WAIT_FOREVER BIOS_WAIT_FOREVER}
    53     *  causes the task to wait indefinitely  for a message. 
    54     *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT BIOS_NO_WAIT} 
    55     *  causes Mailbox_pend to return immediately. 
    56     *  Mailbox_pend's return value indicates whether the mailbox was signaled 
    57     *  successfully.
    58     *
    59     *  When a Mailbox has been configured with a {@link #readerEvent} Event
    60     *  object and a task has returned from {@link Event#pend()} with the 
    61     *  corresponding {@link #readerEventId}, then BIOS_NO_WAIT
    62     *  should be passed to Mailbox_pend() to retrieve the message.
    63     *
    64     *  NOTE: Since only a single reader can pend on a {@link #readerEvent} 
    65     *  Event object,
    66     *  a Mailbox configured with a {@link #readerEvent} Event object does not
    67     *  support multiple readers. 
    68     *
    69     *  {@link #post()} is used to send a message to a mailbox. 
    70     *  The timeout parameter to Mailbox_post specifies the amount of time the 
    71     *  calling task waits if the mailbox is full. 
    72     *
    73     *  When a Mailbox has been configured with a {@link #writerEvent} Event
    74     *  object and a task has returned from {@link Event#pend()} with the 
    75     *  corresponding {@link #writerEventId}, then BIOS_NO_WAIT
    76     *  should be passed to Mailbox_post() knowing that the message
    77     *  will be successfully posted.
    78     *
    79     *  NOTE: Since only a single writer can pend on a {@link #writerEvent} 
    80     *  Event object,
    81     *  a Mailbox configured with a {@link #writerEvent} Event object does not
    82     *  support multiple writers.
    83     *
    84     *  @p(html)
    85     *  <h3> Calling Context </h3>
    86     *  <table border="1" cellpadding="3">
    87     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center">
    88     *    </colgroup>
    89     *
    90     *    <tr><th> Function        </th><th>  Hwi   </th><th>  Swi   </th>
    91     *    <th>  Task  </th><th>  Main  </th><th>  Startup  </th></tr>
    92     *    <!--                                                        -->
    93     *    <tr><td> {@link #Params_init}       </td><td>   Y    </td><td>   Y   </td>
    94     *    <td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    95     *    <tr><td> {@link #construct}         </td><td>   N    </td><td>   N   </td>
    96     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    97     *    <tr><td> {@link #create}            </td><td>   N    </td><td>   N   </td>
    98     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    99     *    <tr><td> {@link #delete}            </td><td>   N    </td><td>   N   </td>
   100     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   101     *    <tr><td> {@link #destruct}          </td><td>   N    </td><td>   N   </td>
   102     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   103     *    <tr><td> {@link #getNumFreeMsgs}    </td><td>   Y    </td><td>   Y   </td>
   104     *    <td>   Y    </td><td>   N    </td><td>   N    </td></tr>
   105     *    <tr><td> {@link #getNumPendingMsgs} </td><td>   Y    </td><td>   Y   </td>
   106     *    <td>   Y    </td><td>   N    </td><td>   N    </td></tr>
   107     *    <tr><td> {@link #pend}              </td><td>   N*   </td><td>   N*  </td>
   108     *    <td>   Y    </td><td>   N*   </td><td>   N    </td></tr>
   109     *    <tr><td> {@link #post}              </td><td>   N*   </td><td>   N*  </td>
   110     *    <td>   Y    </td><td>   N*   </td><td>   N    </td></tr>
   111     *    <tr><td colspan="6"> Definitions: (N* means OK to call iff the timeout
   112     *           parameter is set to '0'.)<br />
   113     *       <ul>
   114     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
   115     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
   116     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
   117     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
   118     *           <ul>
   119     *             <li> In your module startup after this module is started 
   120     *    (e.g. Mailbox_Module_startupDone() returns TRUE). </li>
   121     *             <li> During xdc.runtime.Startup.lastFxns. </li>
   122     *             <li> During main().</li>
   123     *             <li> During BIOS.startupFxns.</li>
   124     *           </ul>
   125     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
   126     *           <ul>
   127     *             <li> During xdc.runtime.Startup.firstFxns.</li>
   128     *             <li> In your module startup before this module is started 
   129     *    (e.g. Mailbox_Module_startupDone() returns FALSE).</li>
   130     *           </ul>
   131     *       </ul>
   132     *    </td></tr>
   133     *
   134     *  </table>
   135     *  @p 
   136     */
   137    
   138    @DirectCall
   139    @ModuleStartup     /* Instances require more initialization at startup */
   140    @InstanceFinalize
   141    @InstanceInitError
   142    
   143    module Mailbox 
   144    {
   145        /*!
   146         *  ======== BasicView ========
   147         *  @_nodoc
   148         */
   149        metaonly struct BasicView {
   150            String label;
   151            SizeT  msgSize;
   152            UInt   numMsgs;
   153        }
   154        
   155        /*!
   156         *  ======== DetailedView ========
   157         *  @_nodoc
   158         */
   159        metaonly struct DetailedView {
   160            String label;
   161            SizeT  msgSize;
   162            UInt   numMsgs;
   163            UInt   curNumMsgs;
   164            UInt   freeSlots;
   165            String pendQueue[];
   166            String postQueue[];
   167        }
   168    
   169        /*!
   170         *  ======== rovViewInfo ========
   171         *  @_nodoc
   172         */
   173        @Facet
   174        metaonly config ViewInfo.Instance rovViewInfo = 
   175            ViewInfo.create({
   176                viewMap: [
   177                [
   178                    'Basic',
   179                    {
   180                        type: ViewInfo.INSTANCE,
   181                        viewInitFxn: 'viewInitBasic',
   182                        structName: 'BasicView'
   183                    }
   184                ],
   185                [
   186                    'Detailed',
   187                    {
   188                        type: ViewInfo.INSTANCE,
   189                        viewInitFxn: 'viewInitDetailed',
   190                        structName: 'DetailedView'
   191                    }
   192                ]
   193                ]
   194            });
   195    
   196        /*!
   197         *  ======== MbxElem ========
   198         *  The header used to save each Mailbox message
   199         *
   200         *  Mailbox messages are stored in a queue that requires a header in
   201         *  front of each message.  This structure defines that header and its
   202         *  size must be factored into the total data size requirements for a
   203         *  mailbox instance.
   204         */
   205        struct MbxElem {
   206            Queue.Elem elem;
   207        };
   208    
   209        /*!
   210         *  ======== A_invalidBufSize ========
   211         *  Assert raised when the bufSize parameter is too small
   212         *
   213         *  This assert is raised when bufSize is too small to handle
   214         *  (size of messages + sizeof(MbxElem)) * number of messages.
   215         *  See {@link ti.sysbios.knl.MailBox#buf} for more information on the buf
   216         *  parameter.
   217         */
   218        config xdc.runtime.Assert.Id A_invalidBufSize =
   219            {msg: "Mailbox_create's bufSize parameter is invalid (too small)"};
   220    
   221    instance:
   222    
   223        /*!
   224         *  ======== create ========
   225         *  Create a mailbox
   226         *
   227         *  Mailbox_create creates a mailbox object which is initialized to contain
   228         *  numMsgs messages of size msgSize.
   229         *
   230         *  @param(msgSize)         size of message
   231         *  @param(numMsgs)         length of mailbox
   232         *
   233         *  @a(WARNING)
   234         *  Be careful with the msgSize parameter!  The 'msg' pointer passed to
   235         *  {@link #pend()} must point to a buffer whose size matches this msgSize
   236         *  parameter.  {@link #pend()} does a blind copy of size 'msgSize' into
   237         *  the destination pointer, so he destination buffer must be big enough to
   238         *  handle this copy.
   239         *
   240         */
   241        create(SizeT msgSize, UInt numMsgs);
   242    
   243        /*!
   244         *  ======== heap ========
   245         *  The IHeap instance used for dynamic creates
   246         *
   247         *  This heap is used only for dynamic instances is ignored  for static 
   248         *  instances.
   249         */
   250        config xdc.runtime.IHeap.Handle heap = null;
   251    
   252        /*!
   253         *  ======== sectionName ========
   254         *  Section name for the buffer managed by the instance
   255         *
   256         *  The default section is the 'dataSection' in the platform.
   257         */
   258        metaonly config String sectionName = null;
   259        
   260        /*!
   261         *  ======== readerEvent ========
   262         *  Mailbox not empty event if using Events. Default is null
   263         *
   264         *  Posted whenever a mailbox is written to.
   265         *  Reader task pends on this event. 
   266         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents 
   267         *  Semaphore.supportsEvents} has to be 
   268         *  set to true for Mailbox to support Events.
   269         */
   270        config Event.Handle readerEvent = null;
   271    
   272        /*!
   273         *  ======== readerEventId ========
   274         *  Mailbox not empty event Id if using Events. Default is 1
   275         *
   276         *  Posted whenever a mailbox is written to.
   277         *  Reader task pends on this eventId.
   278         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
   279         *  Semaphore.supportsEvents} has to be 
   280         *  set to true for Mailbox to support Events.
   281         */
   282        config UInt readerEventId = 1;
   283    
   284        /*!
   285         *  ======== writerEvent ========
   286         *  Mailbox not full event if using Events. Default is null
   287         *
   288         *  Posted whenever a mailbox is read from.
   289         *  Writer task pends on this event.
   290         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
   291         *  Semaphore.supportsEvents} has to be 
   292         *  set to true for Mailbox to support Events.
   293         */
   294        config Event.Handle writerEvent = null;
   295    
   296        /*!
   297         *  ======== writerEventId ========
   298         *  Mailbox not full event Id if using Events
   299         *
   300         *  Posted whenever a mailbox is read from.
   301         *  Writer task pends on this eventId.
   302         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents 
   303         *  Semaphore.supportsEvents} has to be 
   304         *  set to true for Mailbox to support Events.
   305         */
   306        config UInt writerEventId = 1;
   307    
   308        /*!
   309         *  ======== buf ========
   310         *  The address of the buffer used for creating messages
   311         *
   312         *  This property is only used for dynamically created Mailboxes.
   313         *  If set to 'null', the messages will be allocated from the heap
   314         *  during runtime, otherwise the user may set this to a buffer of their
   315         *  creation to be used for allocating the messages.
   316         *  
   317         *  The module will split the buf into
   318         *  {@link ti.sysbios.knl.Mailbox#numMsgs} number of blocks (one block per
   319         *  Mailbox message).
   320         *
   321         *  Please note that if the buffer is user supplied, then it is the user's
   322         *  responsibility to ensure that it is aligned properly and is also large
   323         *  enough to contain {@link ti.sysbios.knl.Mailbox#numMsgs} number of
   324         *  blocks.  The size of each block is defined as follows:
   325         *  @p(code)
   326         *      sizeof(Mailbox_MbxElem) + msgSize
   327         *  @p
   328         *
   329         *  Since the buffer must be a aligned properly, it may be necessary to
   330         *  'round up' the total size of the buffer to the next multiple of the
   331         *  alignment for odd sized messages.
   332         *
   333         *  @see #MbxElem
   334         */
   335        config Ptr buf = null;
   336    
   337        /*!
   338         *  ======== bufSize ========
   339         *  The size of the buffer that 'buf' references
   340         *
   341         *  This property is only used for dynamically created Mailboxes.
   342         */
   343        config UInt bufSize = 0;
   344    
   345        /*!
   346         *  ======== getMsgSize ========
   347         *  Get the message size
   348         */
   349        SizeT getMsgSize();
   350    
   351        /*!
   352         *  ======== getNumFreeMsgs ========
   353         *  Get the number messages available for use
   354         */
   355        Int getNumFreeMsgs();
   356    
   357        /*!
   358         *  ======== getNumPendingMsgs ========
   359         *  Get the number of messages that are ready to be read
   360         */
   361        Int getNumPendingMsgs();
   362    
   363        /*!
   364         *  ======== pend ========
   365         *  Wait for a message from mailbox
   366         *
   367         *  If the mailbox is not empty, Mailbox_pend copies the first message into
   368         *  msg and returns TRUE. Otherwise, Mailbox_pend suspends the execution of
   369         *  the current task until Mailbox_post is called or the timeout expires. 
   370         *
   371         *  A timeout value of 
   372         *  {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes 
   373         *  the task to wait indefinitely  for a message. 
   374         *
   375         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   376         *  causes Mailbox_pend to return immediately. 
   377         *
   378         *  The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   379         *  should be passed to Mailbox_pend() to retrieve a message after
   380         *  Event_pend() is called outside of Mailbox_pend to wait on an incoming
   381         *  message.
   382         *
   383         *  Mailbox_pend's return value indicates whether the mailbox was signaled
   384         *  successfully.
   385         *
   386         *  @param(msg)     message pointer
   387         *  @param(timeout) maximum duration in system clock ticks
   388         *  @b(returns)     TRUE if successful, FALSE if timeout
   389         *
   390         *  @a(WARNING)
   391         *  Be careful with the 'msg' parameter!  The size of the buffer that 'msg'
   392         *  points to must match the 'msgSize' that was specified
   393         *  when the mailbox was created.  This function does a blind copy of the
   394         *  message from the mailbox to the destination pointer, so he destination
   395         *  buffer must be big enough to handle this copy.
   396         */
   397        Bool pend(Ptr msg, UInt32 timeout);
   398    
   399        /*!
   400         *  ======== post ========
   401         *  Post a message to mailbox
   402         *
   403         *  Mailbox_post checks to see if there are any free message slots before
   404         *  copying msg into the mailbox. Mailbox_post readies the first task 
   405         *  (if any) waiting on the mailbox. If the mailbox is full and a timeout 
   406         *  is specified  the task remains suspended until Mailbox_pend is called 
   407         *  or the timeout expires.
   408         *
   409         *  A timeout value of 
   410         *  {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes 
   411         *  the task to wait indefinitely for a free slot.
   412         *
   413         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   414         *  causes  Mailbox_post to return immediately.
   415         *
   416         *  The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   417         *  should be passed to Mailbox_post() to post a message after
   418         *  Event_pend() is called outside of Mailbox_post to wait on an 
   419         *  available message buffer.
   420         *
   421         *  Mailbox_post's return value indicates whether the msg was 
   422         *  copied or not.
   423         *
   424         *  @param(msg)     message pointer
   425         *  @param(timeout) maximum duration in system clock ticks
   426         *  @b(returns)     TRUE if successful, FALSE if timeout
   427         */
   428        Bool post(Ptr msg, UInt32 timeout);
   429    
   430    internal:
   431    
   432        Void cleanQue(Queue.Handle obj);
   433        
   434        /*
   435         *  ======== postInit ========
   436         *  finish initializing static and dynamic instances
   437         */
   438        Int postInit(Object *obj, SizeT blockSize);
   439        
   440        config UInt maxTypeAlign;
   441    
   442        /* -------- Internal Structures -------- */
   443        struct Instance_State {
   444            xdc.runtime.IHeap.Handle    heap;
   445            SizeT                       msgSize;
   446            UInt                        numMsgs;
   447            Ptr                         buf;
   448            Queue.Object                dataQue;
   449            Queue.Object                freeQue;
   450            Semaphore.Object            dataSem;
   451            Semaphore.Object            freeSem;
   452            UInt                        numFreeMsgs;
   453            Char                        allocBuf[];
   454        };
   455    }