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 metaonlystruct BasicView {
150 String label;
151 SizeT msgSize;
152 UInt numMsgs;
153 }
154
155 /*!
156 * ======== DetailedView ========
157 * @_nodoc 158 */
159 metaonlystruct 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 metaonlyconfig 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 metaonlyconfig 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 }