1    /* 
     2     * Copyright (c) 2009
     3     * Texas Instruments
     4     *
     5     *  All rights reserved.  Property of Texas Instruments
     6     *  Restricted rights to use, duplicate or disclose this code are
     7     *  granted through contract.
     8     * 
     9     * */
    10    /*
    11     *  ======== Mailbox.xdc ========
    12     *
    13     */
    14    package ti.sysbios.ipc;
    15    
    16    import xdc.rov.ViewInfo;
    17    
    18    import xdc.runtime.IHeap;
    19    import ti.sysbios.misc.Queue;
    20    import ti.sysbios.heaps.HeapBuf;
    21    
    22    /*!
    23     *  ======== Mailbox ========
    24     *  Mailbox Manager.
    25     *
    26     *  The Mailbox module makes available a set of functions that manipulate
    27     *  mailbox objects accessed through handles of type Mailbox_Handle.
    28     *
    29     *  {@link #pend()} is used to wait for a message from a mailbox. 
    30     *  The timeout parameter to Mailbox_pend allows the task to wait until a 
    31     *  timeout specified in terms of system clock ticks. 
    32     *  A timeout value of {@link ti.sysbios.BIOS#WAIT_FOREVER BIOS_WAIT_FOREVER}
    33     *  causes the task to wait indefinitely  for a message. 
    34     *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT BIOS_NO_WAIT} 
    35     *  causes Mailbox_pend to return immediately. 
    36     *  Mailbox_pend's return value indicates whether the mailbox was signaled 
    37     *  successfully.
    38     *
    39     *  When a Mailbox has been configured with a {@link #readerEvent} Event
    40     *  object and a task has returned from {@link Event#pend()} with the 
    41     *  corresponding {@link #readerEventId}, then BIOS_NO_WAIT
    42     *  should be passed to Mailbox_pend() to retrieve the message.
    43     *
    44     *  NOTE: Since only a single reader can pend on a {@link #readerEvent} Event object,
    45     *  a Mailbox configured with a {@link #readerEvent} Event object does not
    46     *  support multiple readers. 
    47     *
    48     *  {@link #post()} is used to send a message to a mailbox. 
    49     *  The timeout parameter to Mailbox_post specifies the amount of time the 
    50     *  calling task waits if the mailbox is full. 
    51     *
    52     *  When a Mailbox has been configured with a {@link #writerEvent} Event
    53     *  object and a task has returned from {@link Event#pend()} with the 
    54     *  corresponding {@link #writerEventId}, then BIOS_NO_WAIT
    55     *  should be passed to Mailbox_post() knowing that the message
    56     *  will be successfully posted.
    57     *
    58     *  NOTE: Since only a single writer can pend on a {@link #writerEvent} Event object,
    59     *  a Mailbox configured with a {@link #writerEvent} Event object does not
    60     *  support multiple writers.
    61     *
    62     *  @p(html)
    63     *  <h3> Calling Context </h3>
    64     *  <table border="1" cellpadding="3">
    65     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center"></colgroup>
    66     *
    67     *    <tr><th> Function        </th><th>  Hwi   </th><th>  Swi   </th><th>  Task  </th><th>  Main  </th><th>  Startup  </th></tr>
    68     *    <!--                                                                                                                 -->
    69     *    <tr><td> {@link #Params_init}       </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td></tr>
    70     *    <tr><td> {@link #construct}         </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    71     *    <tr><td> {@link #create}            </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    72     *    <tr><td> {@link #delete}            </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    73     *    <tr><td> {@link #destruct}          </td><td>   N    </td><td>   N    </td><td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
    74     *    <tr><td> {@link #getNumFreeMsgs}    </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td><td>   N    </td></tr>
    75     *    <tr><td> {@link #getNumPendingMsgs} </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td><td>   N    </td></tr>
    76     *    <tr><td> {@link #pend}              </td><td>   Y*   </td><td>   Y*   </td><td>   Y    </td><td>   N    </td><td>   N    </td></tr>
    77     *    <tr><td> {@link #post}              </td><td>   Y    </td><td>   Y    </td><td>   Y    </td><td>   N    </td><td>   N    </td></tr>
    78     *    <tr><td colspan="6"> Definitions: <br />
    79     *       <ul>
    80     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
    81     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
    82     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
    83     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
    84     *           <ul>
    85     *             <li> In your module startup after this module is started (e.g. Mailbox_Module_startupDone() returns TRUE). </li>
    86     *             <li> During xdc.runtime.Startup.lastFxns. </li>
    87     *             <li> During main().</li>
    88     *             <li> During BIOS.startupFxns.</li>
    89     *           </ul>
    90     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
    91     *           <ul>
    92     *             <li> During xdc.runtime.Startup.firstFxns.</li>
    93     *             <li> In your module startup before this module is started (e.g. Mailbox_Module_startupDone() returns FALSE).</li>
    94     *           </ul>
    95     *       <li> <b>*</b>: Yes but only for a timeout value of zero. </li>
    96     *       </ul>
    97     *    </td></tr>
    98     *
    99     *  </table>
   100     *  @p 
   101     */
   102    
   103    @InstanceFinalize
   104    @InstanceInitError
   105    
   106    module Mailbox 
   107    {
   108        metaonly struct BasicView {
   109            String label;
   110            SizeT  msgSize;
   111            UInt   numMsgs;
   112        }
   113        
   114        metaonly struct DetailedView {
   115            String label;
   116            SizeT  msgSize;
   117            UInt   numMsgs;
   118            UInt   curNumMsgs;
   119            UInt   freeSlots;
   120            String pendQueue[];
   121            String postQueue[];
   122        }
   123    
   124        @Facet
   125        metaonly config ViewInfo.Instance rovViewInfo = 
   126            ViewInfo.create({
   127                viewMap: [
   128                [
   129                    'Basic',
   130                    {
   131                        type: ViewInfo.INSTANCE,
   132                        viewInitFxn: 'viewInitBasic',
   133                        structName: 'BasicView'
   134                    }
   135                ],
   136                [
   137                    'Detailed',
   138                    {
   139                        type: ViewInfo.INSTANCE,
   140                        viewInitFxn: 'viewInitDetailed',
   141                        structName: 'DetailedView'
   142                    }
   143                ]
   144                ]
   145            });
   146    
   147        struct MbxElem {
   148            Queue.Elem      elem;
   149        };
   150    
   151        /*!
   152         *  Assert raised when the bufSize parameter is too small
   153         *  to handle (size of messages + sizeof(MbxElem)) * number of messages. See
   154         *  {@link ti.sysbios.ipc.MailBox#buf} for more information on the buf
   155         *  parameter.
   156         */
   157        config xdc.runtime.Assert.Id A_invalidBufSize =
   158            {msg: "Mailbox_create's bufSize parameter is invalid (too small)"};
   159    
   160    instance:
   161    
   162        /*!
   163         *  ======== create ========
   164         *  Create a mailbox
   165         *
   166         *  Mailbox_create creates a mailbox object which is initialized to contain
   167         *  numMsgs messages of size msgSize.
   168         *
   169         *  @param(msgSize)         size of message
   170         *  @param(numMsgs)         length of mailbox
   171         */
   172        create(SizeT msgSize, UInt numMsgs);
   173    
   174        /*!
   175         *  ======== heap ========
   176         * The IHeap instance used for dynamic creates. 
   177         *
   178         *  This heap is used only for dynamic instances is ignored  for static 
   179         *  instances.
   180         */
   181        config xdc.runtime.IHeap.Handle heap = null;
   182        
   183        /*!
   184         *  ======== sectionName ========
   185         *  Section name for the buffer managed by the instance.
   186         *
   187         *  The default section is the 'dataSection' in the platform.
   188         */
   189        metaonly config String sectionName = null;
   190        
   191        /*!
   192         *  ======== readerEvent ========
   193         *  Mailbox not empty event if using Events. Default is null.
   194         *
   195         *  Posted whenever a mailbox is written to.
   196         *  Reader task pends on this event. 
   197         *  Note that {@link ti.sysbios.ipc.Semaphore#supportsEvents Semaphore.supportsEvents} has to be 
   198         *  set to true for Mailbox to support Events.
   199         */
   200        config Event.Handle readerEvent = null;
   201    
   202        /*!
   203         *  ======== readerEventId ========
   204         *  Mailbox not empty event Id if using Events. Default is 1.
   205         *
   206         *  Posted whenever a mailbox is written to.
   207         *  Reader task pends on this eventId.
   208         *  Note that {@link ti.sysbios.ipc.Semaphore#supportsEvents Semaphore.supportsEvents} has to be 
   209         *  set to true for Mailbox to support Events.
   210         */
   211        config UInt readerEventId = 1;
   212    
   213        /*!
   214         *  ======== writerEvent ========
   215         *  Mailbox not full event if using Events. Default is null.
   216         *
   217         *  Posted whenever a mailbox is read from.
   218         *  Writer task pends on this event.
   219         *  Note that {@link ti.sysbios.ipc.Semaphore#supportsEvents Semaphore.supportsEvents} has to be 
   220         *  set to true for Mailbox to support Events.
   221         */
   222        config Event.Handle writerEvent = null;
   223    
   224        /*!
   225         *  ======== writerEventId ========
   226         *  Mailbox not full event Id if using Events. Default is 1.
   227         *
   228         *  Posted whenever a mailbox is read from.
   229         *  Writer task pends on this eventId.
   230         *  Note that {@link ti.sysbios.ipc.Semaphore#supportsEvents Semaphore.supportsEvents} has to be 
   231         *  set to true for Mailbox to support Events.
   232         */
   233        config UInt writerEventId = 1;
   234    
   235        /*!
   236         *  ======== buf ========
   237         *  The address of the buffer used for creating messages.
   238         *
   239         *  This property is only used for dynamically created Mailboxes.
   240         *  If set to 'null', the messages will be allocated from the heap
   241         *  during runtime, otherwise the user may set this to a buffer of their
   242         *  creation to be used for allocating the messages.  In either case, 
   243         *  the {@link ti.sysbios.ipc.Mailbox} module will use the
   244         *  {@link ti.sysbios.heaps.HeapBuf} module for handling the allocation of
   245         *  all messages.
   246         *  
   247         *  The {@link ti.sysbios.heaps.HeapBuf} module will split the buf into
   248         *  {@link ti.sysbios.ipc.Mailbox#numMsgs} number of blocks (one block per
   249         *  Mailbox message).  This {@link ti.sysbios.heaps.HeapBuf} instance is
   250         *  then used for managing the Mailbox messages.
   251         *
   252         *  Please note that if the buffer is user supplied, then it is the user's
   253         *  responsibility to ensure that it is aligned properly and is also large
   254         *  enough to contain {@link ti.sysbios.ipc.Mailbox#numMsgs} number of
   255         *  blocks.  The size of each block is defined as follows:
   256         *  @p(code)
   257         *  sizeof(Mailbox_MbxElem) + msgSize
   258         *  @p
   259         *
   260         *  Since the buffer must be a aligned properly, it may be necessary to
   261         *  'round up' the total size of the buffer to the next multiple of the
   262         *  alignment for odd sized messages.  Please refer to the alignment rules
   263         *  specified by the {@link ti.sysbios.heaps.HeapBuf} module's
   264         *  {@link ti.sysbios.heaps.HeapBuf#align} paremeter for more
   265         *  information on alignment.  If the buffer is not properly aligned, an
   266         *  Assert will be raised.
   267         *
   268         */
   269        config Ptr buf = null;
   270    
   271        /*!
   272         *  ======== bufSize ========
   273         *  The size of the buffer that 'buf' points to.
   274         *
   275         *  This property is only used for dynamically created Mailboxes.
   276         */
   277        config UInt bufSize = 0;
   278    
   279        /*!
   280         *  ======== getNumFreeMsgs ========
   281         *  Returns the number messages available for use for a Mailbox instance.
   282         */
   283        Int getNumFreeMsgs();
   284    
   285        /*!
   286         *  ======== getNumPendingMsgs ========
   287         *  Returns the number of messages that are ready to be read for a Mailbox
   288         *  instance.
   289         */
   290        Int getNumPendingMsgs();
   291    
   292        /*!
   293         *  ======== pend ========
   294         *  Wait for a message from mailbox
   295         *
   296         *  If the mailbox is not empty, Mailbox_pend copies the first message into
   297         *  msg and returns TRUE. Otherwise, Mailbox_pend suspends the execution of
   298         *  the current task until Mailbox_post is called or the timeout expires. 
   299         *
   300         *  A timeout value of 
   301         *  {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes 
   302         *  the task to wait indefinitely  for a message. 
   303         *
   304         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   305         *  causes Mailbox_pend to return immediately. 
   306         *
   307         *  The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   308         *  should be passed to Mailbox_pend() to retrieve a message after
   309         *  Event_pend() is called outside of Mailbox_pend to wait on an incoming
   310         *  message.
   311         *
   312         *  Mailbox_pend's return value indicates whether the mailbox was signaled
   313         *  successfully.
   314         *
   315         *  @param(msg)     message pointer
   316         *  @param(timeout) maximum duration in system clock ticks
   317         *  @b(returns)     TRUE if successful, FALSE if timeout
   318         */
   319        Bool pend(Ptr msg, UInt timeout);
   320    
   321        /*!
   322         *  ======== post ========
   323         *  Post a message to mailbox
   324         *
   325         *  Mailbox_post checks to see if there are any free message slots before
   326         *  copying msg into the mailbox. Mailbox_post readies the first task 
   327         *  (if any) waiting on the mailbox. If the mailbox is full and a timeout 
   328         *  is specified  the task remains suspended until Mailbox_pend is called 
   329         *  or the timeout expires.
   330         *
   331         *  A timeout value of 
   332         *  {@link ti.sysbios.BIOS#WAIT_FOREVER, BIOS_WAIT_FOREVER} causes 
   333         *  the task to wait indefinitely for a free slot.
   334         *
   335         *  A timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   336         *  causes  Mailbox_post to return immediatly.
   337         *
   338         *  The timeout value of {@link ti.sysbios.BIOS#NO_WAIT, BIOS_NO_WAIT} 
   339         *  should be passed to Mailbox_post() to post a message after
   340         *  Event_pend() is called outside of Mailbox_post to wait on an 
   341         *  available message buffer.
   342         *
   343         *  Mailbox_post's return value indicates whether the msg was 
   344         *  copied or not.
   345         *
   346         *  @param(msg)     message pointer
   347         *  @param(timeout) maximum duration in system clock ticks
   348         *  @b(returns)     TRUE if successful, FALSE if timeout
   349         */
   350        Bool post(Ptr msg, UInt timeout);
   351    
   352    internal:
   353    
   354        Void cleanQue(Queue.Handle obj);
   355    
   356        /* -------- Internal Structures -------- */
   357        struct Instance_State {
   358            xdc.runtime.IHeap.Handle        heap;
   359            SizeT                           msgSize;
   360            UInt                            numMsgs;
   361            Ptr                             buf;
   362            Queue.Object                    dataQue;
   363            HeapBuf.Object                  freeQue;
   364            Semaphore.Object                dataSem;
   365            Semaphore.Object                freeSem;
   366        };
   367    }
   368    /*
   369     *  @(#) ti.sysbios.ipc; 2, 0, 0, 0,348; 12-18-2009 15:12:59; /db/vtree/library/trees/avala/avala-m19x/src/
   370     */
   371