1    /*
     2     * Copyright (c) 2014-2017, 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    @InstanceInitStatic     /* Construct/Destruct CAN becalled at runtime */
   143    
   144    module Mailbox 
   145    {
   146        /*!
   147         *  ======== BasicView ========
   148         *  @_nodoc
   149         */
   150        metaonly struct BasicView {
   151            String label;
   152            SizeT  msgSize;
   153            UInt   numMsgs;
   154        }
   155        
   156        /*!
   157         *  ======== DetailedView ========
   158         *  @_nodoc
   159         */
   160        metaonly struct DetailedView {
   161            String label;
   162            SizeT  msgSize;
   163            UInt   numMsgs;
   164            UInt   curNumMsgs;
   165            UInt   freeSlots;
   166            String pendQueue[];
   167            String postQueue[];
   168        }
   169    
   170        /*!
   171         *  ======== rovViewInfo ========
   172         *  @_nodoc
   173         */
   174        @Facet
   175        metaonly config ViewInfo.Instance rovViewInfo = 
   176            ViewInfo.create({
   177                viewMap: [
   178                [
   179                    'Basic',
   180                    {
   181                        type: ViewInfo.INSTANCE,
   182                        viewInitFxn: 'viewInitBasic',
   183                        structName: 'BasicView'
   184                    }
   185                ],
   186                [
   187                    'Detailed',
   188                    {
   189                        type: ViewInfo.INSTANCE,
   190                        viewInitFxn: 'viewInitDetailed',
   191                        structName: 'DetailedView'
   192                    }
   193                ]
   194                ]
   195            });
   196    
   197        /*!
   198         *  ======== MbxElem ========
   199         *  The header used to save each Mailbox message
   200         *
   201         *  Mailbox messages are stored in a queue that requires a header in
   202         *  front of each message.  This structure defines that header and its
   203         *  size must be factored into the total data size requirements for a
   204         *  mailbox instance.
   205         */
   206        struct MbxElem {
   207            Queue.Elem elem;
   208        };
   209    
   210        /*!
   211         *  ======== A_invalidBufSize ========
   212         *  Assert raised when the bufSize parameter is too small
   213         *
   214         *  This assert is raised when bufSize is too small to handle
   215         *  (size of messages + sizeof(MbxElem)) * number of messages.
   216         *  See {@link ti.sysbios.knl.MailBox#buf} for more information on the buf
   217         *  parameter.
   218         */
   219        config xdc.runtime.Assert.Id A_invalidBufSize =
   220            {msg: "Mailbox_create's bufSize parameter is invalid (too small)"};
   221    
   222    instance:
   223    
   224        /*!
   225         *  ======== create ========
   226         *  Create a mailbox
   227         *
   228         *  Mailbox_create creates a mailbox object which is initialized to contain
   229         *  numMsgs messages of size msgSize.
   230         *
   231         *  @param(msgSize)         size of message
   232         *  @param(numMsgs)         length of mailbox
   233         */
   234        create(SizeT msgSize, UInt numMsgs);
   235    
   236        /*!
   237         *  ======== heap ========
   238         *  The IHeap instance used for dynamic creates
   239         *
   240         *  This heap is used only for dynamic instances is ignored  for static 
   241         *  instances.
   242         */
   243        config xdc.runtime.IHeap.Handle heap = null;
   244    
   245        /*!
   246         *  ======== sectionName ========
   247         *  Section name for the buffer managed by the instance
   248         *
   249         *  The default section is the 'dataSection' in the platform.
   250         */
   251        metaonly config String sectionName = null;
   252        
   253        /*!
   254         *  ======== readerEvent ========
   255         *  Mailbox not empty event if using Events. Default is null
   256         *
   257         *  Posted whenever a mailbox is written to.
   258         *  Reader task pends on this event. 
   259         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents 
   260         *  Semaphore.supportsEvents} has to be 
   261         *  set to true for Mailbox to support Events.
   262         */
   263        config Event.Handle readerEvent = null;
   264    
   265        /*!
   266         *  ======== readerEventId ========
   267         *  Mailbox not empty event Id if using Events. Default is 1
   268         *
   269         *  Posted whenever a mailbox is written to.
   270         *  Reader task pends on this eventId.
   271         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
   272         *  Semaphore.supportsEvents} has to be 
   273         *  set to true for Mailbox to support Events.
   274         */
   275        config UInt readerEventId = 1;
   276    
   277        /*!
   278         *  ======== writerEvent ========
   279         *  Mailbox not full event if using Events. Default is null
   280         *
   281         *  Posted whenever a mailbox is read from.
   282         *  Writer task pends on this event.
   283         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
   284         *  Semaphore.supportsEvents} has to be 
   285         *  set to true for Mailbox to support Events.
   286         */
   287        config Event.Handle writerEvent = null;
   288    
   289        /*!
   290         *  ======== writerEventId ========
   291         *  Mailbox not full event Id if using Events
   292         *
   293         *  Posted whenever a mailbox is read from.
   294         *  Writer task pends on this eventId.
   295         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents 
   296         *  Semaphore.supportsEvents} has to be 
   297         *  set to true for Mailbox to support Events.
   298         */
   299        config UInt writerEventId = 1;
   300    
   301        /*!
   302         *  ======== buf ========
   303         *  The address of the buffer used for creating messages
   304         *
   305         *  This property is only used for dynamically created Mailboxes.
   306         *  If set to 'null', the messages will be allocated from the heap
   307         *  during runtime, otherwise the user may set this to a buffer of their
   308         *  creation to be used for allocating the messages.
   309         *  
   310         *  The module will split the buf into
   311         *  {@link ti.sysbios.knl.Mailbox#numMsgs} number of blocks (one block per
   312         *  Mailbox message).
   313         *
   314         *  Please note that if the buffer is user supplied, then it is the user's
   315         *  responsibility to ensure that it is aligned properly and is also large
   316         *  enough to contain {@link ti.sysbios.knl.Mailbox#numMsgs} number of
   317         *  blocks.  The size of each block is defined as follows:
   318         *  @p(code)
   319         *      sizeof(Mailbox_MbxElem) + msgSize
   320         *  @p
   321         *
   322         *  Since the buffer must be a aligned properly, it may be necessary to
   323         *  'round up' the total size of the buffer to the next multiple of the
   324         *  alignment for odd sized messages.
   325         *
   326         *  Also note that if {@link ti.sysbios.BIOS#runtimeCreatesEnabled
   327         *  BIOS.runtimeCreatesEnabled} is set to false, then the user is required
   328         *  to provide this buffer when constructing the Mailbox object. If 'buf'
   329         *  is not set, then Mailbox_construct() will fail.
   330         *
   331         *  @see #MbxElem
   332         */
   333        config Ptr buf = null;
   334    
   335        /*!
   336         *  ======== bufSize ========
   337         *  The size of the buffer that 'buf' references
   338         *
   339         *  This property is only used for dynamically created Mailboxes.
   340         */
   341        config UInt bufSize = 0;
   342    
   343        /*!
   344         *  ======== getMsgSize ========
   345         *  Get the message size
   346         */
   347        SizeT getMsgSize();
   348    
   349        /*!
   350         *  ======== getNumFreeMsgs ========
   351         *  Get the number messages available for use
   352         */
   353        Int getNumFreeMsgs();
   354    
   355        /*!
   356         *  ======== getNumPendingMsgs ========
   357         *  Get the number of messages that are ready to be read
   358         */
   359        Int getNumPendingMsgs();
   360    
   361        /*!
   362         *  ======== pend ========
   363         *  Wait for a message from mailbox
   364         *
   365         *  If the mailbox is not empty, Mailbox_pend copies the first message into
   366         *  msg and returns TRUE. Otherwise, Mailbox_pend suspends the execution of
   367         *  the current task until Mailbox_post is called or the timeout expires. 
   368         *
   369         *  A timeout value of 
   370         *  {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes 
   371         *  the task to wait indefinitely  for a message. 
   372         *
   373         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   374         *  causes Mailbox_pend to return immediately. 
   375         *
   376         *  The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   377         *  should be passed to Mailbox_pend() to retrieve a message after
   378         *  Event_pend() is called outside of Mailbox_pend to wait on an incoming
   379         *  message.
   380         *
   381         *  Mailbox_pend's return value indicates whether the mailbox was signaled
   382         *  successfully.
   383         *
   384         *  @a(Event Object Note)
   385         *  If the Mailbox object has been configured with an embedded readerEvent
   386         *  Event object, then prior to returnig from this function, the Event
   387         *  object's state is updated to reflect whether messages are available
   388         *  in the Mailbox after the current message is removed.
   389         *  If there are no more messages available, then the readerEventId is
   390         *  cleared in the Event object. If more messages are available,
   391         *  then the readerEventId is set in the Event object.
   392         *
   393         *  @param(msg)     message pointer
   394         *  @param(timeout) maximum duration in system clock ticks
   395         *  @b(returns)     TRUE if successful, FALSE if timeout
   396         *
   397         *  @a(WARNING)
   398         *  Be careful with the 'msg' parameter!  The size of the buffer that 'msg'
   399         *  points to must match the 'msgSize' that was specified
   400         *  when the mailbox was created.  This function does a blind copy of the
   401         *  message from the mailbox to the destination pointer, so the destination
   402         *  buffer must be big enough to handle this copy.
   403         */
   404        Bool pend(Ptr msg, UInt32 timeout);
   405    
   406        /*!
   407         *  ======== post ========
   408         *  Post a message to mailbox
   409         *
   410         *  Mailbox_post checks to see if there are any free message slots before
   411         *  copying msg into the mailbox. Mailbox_post readies the first task 
   412         *  (if any) waiting on the mailbox. If the mailbox is full and a timeout 
   413         *  is specified  the task remains suspended until Mailbox_pend is called 
   414         *  or the timeout expires.
   415         *
   416         *  A timeout value of 
   417         *  {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes 
   418         *  the task to wait indefinitely for a free slot.
   419         *
   420         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   421         *  causes  Mailbox_post to return immediately.
   422         *
   423         *  The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   424         *  should be passed to Mailbox_post() to post a message after
   425         *  Event_pend() is called outside of Mailbox_post to wait on an 
   426         *  available message buffer.
   427         *
   428         *  Mailbox_post's return value indicates whether the msg was 
   429         *  copied or not.
   430         *
   431         *  @a(Event Object Note)
   432         *  If the Mailbox object has been configured with an embedded writerEvent
   433         *  Event object, then prior to returnig from this function, the Event
   434         *  object's state is updated to reflect whether more messages can be
   435         *  posted to the Mailbox after the current message has been posted.
   436         *  If no more room is available, then the writerEventId is
   437         *  cleared in the Event object. If more room is available,
   438         *  then the writerEventId is set in the Event object.
   439         *
   440         *  @param(msg)     message pointer
   441         *  @param(timeout) maximum duration in system clock ticks
   442         *  @b(returns)     TRUE if successful, FALSE if timeout
   443         *
   444         *  @a(NOTE)
   445         *  The operation of adding a message to the mailbox and signalling
   446         *  the task (if any) waiting on the mailbox is not atomic. This can
   447         *  result in a priority inversion with respect to message delivery.
   448         *  This can for example affect the order of message delivery for 2
   449         *  tasks with different priorities. The lower priority task's message
   450         *  may be delivered first while the higher priority task's message
   451         *  may not unblock the task waiting on the mailbox until the lower
   452         *  priority task resumes and completes its Mailbox_post() call.
   453         */
   454        Bool post(Ptr msg, UInt32 timeout);
   455    
   456    internal:
   457    
   458        Void cleanQue(Queue.Handle obj);
   459        
   460        /*
   461         *  ======== postInit ========
   462         *  finish initializing static and dynamic instances
   463         */
   464        Int postInit(Object *obj, SizeT blockSize);
   465        
   466        config UInt maxTypeAlign;
   467    
   468        /* -------- Internal Structures -------- */
   469        struct Instance_State {
   470            xdc.runtime.IHeap.Handle    heap;
   471            SizeT                       msgSize;
   472            UInt                        numMsgs;
   473            Ptr                         buf;
   474            Queue.Object                dataQue;
   475            Queue.Object                freeQue;
   476            Semaphore.Object            dataSem;
   477            Semaphore.Object            freeSem;
   478            UInt                        numFreeMsgs;
   479            Char                        allocBuf[];
   480        };
   481    }