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         *  @a(WARNING)
   235         *  Be careful with the msgSize parameter!  The 'msg' pointer passed to
   236         *  {@link #pend()} must point to a buffer whose size matches this msgSize
   237         *  parameter.  {@link #pend()} does a blind copy of size 'msgSize' into
   238         *  the destination pointer, so the destination buffer must be big enough to
   239         *  handle this copy.
   240         *
   241         */
   242        create(SizeT msgSize, UInt numMsgs);
   243    
   244        /*!
   245         *  ======== heap ========
   246         *  The IHeap instance used for dynamic creates
   247         *
   248         *  This heap is used only for dynamic instances is ignored  for static 
   249         *  instances.
   250         */
   251        config xdc.runtime.IHeap.Handle heap = null;
   252    
   253        /*!
   254         *  ======== sectionName ========
   255         *  Section name for the buffer managed by the instance
   256         *
   257         *  The default section is the 'dataSection' in the platform.
   258         */
   259        metaonly config String sectionName = null;
   260        
   261        /*!
   262         *  ======== readerEvent ========
   263         *  Mailbox not empty event if using Events. Default is null
   264         *
   265         *  Posted whenever a mailbox is written to.
   266         *  Reader task pends on this event. 
   267         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents 
   268         *  Semaphore.supportsEvents} has to be 
   269         *  set to true for Mailbox to support Events.
   270         */
   271        config Event.Handle readerEvent = null;
   272    
   273        /*!
   274         *  ======== readerEventId ========
   275         *  Mailbox not empty event Id if using Events. Default is 1
   276         *
   277         *  Posted whenever a mailbox is written to.
   278         *  Reader task pends on this eventId.
   279         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
   280         *  Semaphore.supportsEvents} has to be 
   281         *  set to true for Mailbox to support Events.
   282         */
   283        config UInt readerEventId = 1;
   284    
   285        /*!
   286         *  ======== writerEvent ========
   287         *  Mailbox not full event if using Events. Default is null
   288         *
   289         *  Posted whenever a mailbox is read from.
   290         *  Writer task pends on this event.
   291         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents
   292         *  Semaphore.supportsEvents} has to be 
   293         *  set to true for Mailbox to support Events.
   294         */
   295        config Event.Handle writerEvent = null;
   296    
   297        /*!
   298         *  ======== writerEventId ========
   299         *  Mailbox not full event Id if using Events
   300         *
   301         *  Posted whenever a mailbox is read from.
   302         *  Writer task pends on this eventId.
   303         *  Note that {@link ti.sysbios.knl.Semaphore#supportsEvents 
   304         *  Semaphore.supportsEvents} has to be 
   305         *  set to true for Mailbox to support Events.
   306         */
   307        config UInt writerEventId = 1;
   308    
   309        /*!
   310         *  ======== buf ========
   311         *  The address of the buffer used for creating messages
   312         *
   313         *  This property is only used for dynamically created Mailboxes.
   314         *  If set to 'null', the messages will be allocated from the heap
   315         *  during runtime, otherwise the user may set this to a buffer of their
   316         *  creation to be used for allocating the messages.
   317         *  
   318         *  The module will split the buf into
   319         *  {@link ti.sysbios.knl.Mailbox#numMsgs} number of blocks (one block per
   320         *  Mailbox message).
   321         *
   322         *  Please note that if the buffer is user supplied, then it is the user's
   323         *  responsibility to ensure that it is aligned properly and is also large
   324         *  enough to contain {@link ti.sysbios.knl.Mailbox#numMsgs} number of
   325         *  blocks.  The size of each block is defined as follows:
   326         *  @p(code)
   327         *      sizeof(Mailbox_MbxElem) + msgSize
   328         *  @p
   329         *
   330         *  Since the buffer must be a aligned properly, it may be necessary to
   331         *  'round up' the total size of the buffer to the next multiple of the
   332         *  alignment for odd sized messages.
   333         *
   334         *  Also note that if {@link ti.sysbios.BIOS#runtimeCreatesEnabled
   335         *  BIOS.runtimeCreatesEnabled} is set to false, then the user is required
   336         *  to provide this buffer when constructing the Mailbox object. If 'buf'
   337         *  is not set, then Mailbox_construct() will fail.
   338         *
   339         *  @see #MbxElem
   340         */
   341        config Ptr buf = null;
   342    
   343        /*!
   344         *  ======== bufSize ========
   345         *  The size of the buffer that 'buf' references
   346         *
   347         *  This property is only used for dynamically created Mailboxes.
   348         */
   349        config UInt bufSize = 0;
   350    
   351        /*!
   352         *  ======== getMsgSize ========
   353         *  Get the message size
   354         */
   355        SizeT getMsgSize();
   356    
   357        /*!
   358         *  ======== getNumFreeMsgs ========
   359         *  Get the number messages available for use
   360         */
   361        Int getNumFreeMsgs();
   362    
   363        /*!
   364         *  ======== getNumPendingMsgs ========
   365         *  Get the number of messages that are ready to be read
   366         */
   367        Int getNumPendingMsgs();
   368    
   369        /*!
   370         *  ======== pend ========
   371         *  Wait for a message from mailbox
   372         *
   373         *  If the mailbox is not empty, Mailbox_pend copies the first message into
   374         *  msg and returns TRUE. Otherwise, Mailbox_pend suspends the execution of
   375         *  the current task until Mailbox_post is called or the timeout expires. 
   376         *
   377         *  A timeout value of 
   378         *  {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes 
   379         *  the task to wait indefinitely  for a message. 
   380         *
   381         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   382         *  causes Mailbox_pend to return immediately. 
   383         *
   384         *  The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   385         *  should be passed to Mailbox_pend() to retrieve a message after
   386         *  Event_pend() is called outside of Mailbox_pend to wait on an incoming
   387         *  message.
   388         *
   389         *  Mailbox_pend's return value indicates whether the mailbox was signaled
   390         *  successfully.
   391         *
   392         *  @param(msg)     message pointer
   393         *  @param(timeout) maximum duration in system clock ticks
   394         *  @b(returns)     TRUE if successful, FALSE if timeout
   395         *
   396         *  @a(WARNING)
   397         *  Be careful with the 'msg' parameter!  The size of the buffer that 'msg'
   398         *  points to must match the 'msgSize' that was specified
   399         *  when the mailbox was created.  This function does a blind copy of the
   400         *  message from the mailbox to the destination pointer, so he destination
   401         *  buffer must be big enough to handle this copy.
   402         */
   403        Bool pend(Ptr msg, UInt32 timeout);
   404    
   405        /*!
   406         *  ======== post ========
   407         *  Post a message to mailbox
   408         *
   409         *  Mailbox_post checks to see if there are any free message slots before
   410         *  copying msg into the mailbox. Mailbox_post readies the first task 
   411         *  (if any) waiting on the mailbox. If the mailbox is full and a timeout 
   412         *  is specified  the task remains suspended until Mailbox_pend is called 
   413         *  or the timeout expires.
   414         *
   415         *  A timeout value of 
   416         *  {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes 
   417         *  the task to wait indefinitely for a free slot.
   418         *
   419         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   420         *  causes  Mailbox_post to return immediately.
   421         *
   422         *  The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   423         *  should be passed to Mailbox_post() to post a message after
   424         *  Event_pend() is called outside of Mailbox_post to wait on an 
   425         *  available message buffer.
   426         *
   427         *  Mailbox_post's return value indicates whether the msg was 
   428         *  copied or not.
   429         *
   430         *  @param(msg)     message pointer
   431         *  @param(timeout) maximum duration in system clock ticks
   432         *  @b(returns)     TRUE if successful, FALSE if timeout
   433         *
   434         *  @a(NOTE)
   435         *  The operation of adding a message to the mailbox and signalling
   436         *  the task (if any) waiting on the mailbox is not atomic. This can
   437         *  result in a priority inversion with respect to message delivery.
   438         *  This can for example affect the order of message delivery for 2
   439         *  tasks with different priorities. The lower priority task's message
   440         *  may be delivered first while the higher priority task's message
   441         *  may not unblock the task waiting on the mailbox until the lower
   442         *  priority task resumes and completes its Mailbox_post() call.
   443         */
   444        Bool post(Ptr msg, UInt32 timeout);
   445    
   446    internal:
   447    
   448        Void cleanQue(Queue.Handle obj);
   449        
   450        /*
   451         *  ======== postInit ========
   452         *  finish initializing static and dynamic instances
   453         */
   454        Int postInit(Object *obj, SizeT blockSize);
   455        
   456        config UInt maxTypeAlign;
   457    
   458        /* -------- Internal Structures -------- */
   459        struct Instance_State {
   460            xdc.runtime.IHeap.Handle    heap;
   461            SizeT                       msgSize;
   462            UInt                        numMsgs;
   463            Ptr                         buf;
   464            Queue.Object                dataQue;
   465            Queue.Object                freeQue;
   466            Semaphore.Object            dataSem;
   467            Semaphore.Object            freeSem;
   468            UInt                        numFreeMsgs;
   469            Char                        allocBuf[];
   470        };
   471    }