1 /*
2 * Copyright (c) 2011-2013, 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 * ======== SysMin.c ========
34 */
36 #include <xdc/runtime/Startup.h>
37 #include <xdc/runtime/Gate.h>
39 #ifdef SMP
40 #include <ti/sysbios/BIOS.h>
41 #include <ti/sysbios/hal/Core.h>
42 #include <ti/sysbios/hal/Hwi.h>
43 #endif
44 #include <ti/sysbios/knl/Clock.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <stdio.h>
50 #include "package/internal/SysMin.xdc.h"
52 /*
53 * ======== SysMin_Module_startup ========
54 */
55 Int SysMin_Module_startup(Int phase)
56 {
57 if (SysMin_bufSize != 0) {
58 memset(module->outbuf, 0, SysMin_bufSize);
59 }
61 #ifndef SMP
62 /* Initialize to TRUE so the first line get the timestamp */
63 module->getTime = TRUE;
64 #endif
66 return (Startup_DONE);
67 }
69 /*
70 * ======== SysMin_abort ========
71 */
72 Void SysMin_abort(CString str)
73 {
74 Char ch;
76 if (SysMin_bufSize != 0) {
77 if (str != NULL) {
78 while ((ch = *str++) != '\0') {
79 SysMin_putch(ch);
80 }
81 }
83 /* Only flush if configured to do so */
84 if (SysMin_flushAtExit) {
85 SysMin_flush();
86 }
87 }
88 }
90 /*
91 * ======== SysMin_exit ========
92 */
93 Void SysMin_exit(Int stat)
94 {
95 if ((SysMin_flushAtExit) && (SysMin_bufSize != 0)) {
96 SysMin_flush();
97 }
98 }
100 /*
101 * ======== SysMin_output ========
102 * Common output function to write a character
103 * into the circular buffer
104 */
105 static inline Void SysMin_output(Char ch)
106 {
107 module->outbuf[module->outidx++] = ch;
108 /* Last 8 bytes are used for writeIdx/readIdx fields */
109 if (module->outidx == SysMin_bufSize - 8) {
110 module->outidx = 0;
111 }
112 }
114 /*
115 * ======== SysMin_putch ========
116 * Custom implementation for using circular
117 * buffer without using flush
118 */
119 Void SysMin_putch(Char ch)
120 {
121 IArg key;
122 UInt i;
123 #ifndef SMP
124 static UInt coreId = 0;
125 #else
126 UInt coreId;
127 #endif
128 UInt lineIdx;
129 Char *lineBuf;
130 Int index;
131 UInt64 uSec;
132 static Bool configure = FALSE;
133 static UInt startIdx;
134 static UInt endIdx;
135 static UInt timeStampSecCharLen;
136 const UInt minSecCharLen = 4; /* for 1 us tick period */
137 const UInt maxuSecCharLen = 6; /* for 1 us tick period */
138 /* Max characters for seconds would be 10 assuming 1 sec tick period,
139 * so decimal point index will be 11, and maximum time stamp buffer
140 * length would be 18 accounting maxuSecCharLen and a trailing NULL */
141 const UInt decPtIdx = 11;
142 const UInt timeStampBufLen = 18;
143 const UInt leftSpaceIdx = 10;
144 Char timeStamp[18] = {" \0"};
146 /* Configure the trace timestamp format */
147 if (!configure) {
148 Int i = 0, mod = 10;
150 /* Find number of characters needes for seconds and sub-seconds,
151 * tick periods are specified in microseconds */
152 for (; i < maxuSecCharLen; i++) {
153 if (Clock_tickPeriod % mod) {
154 break;
155 }
156 mod = mod * 10;
157 }
158 timeStampSecCharLen = minSecCharLen + i;
159 startIdx = decPtIdx - timeStampSecCharLen;
160 endIdx = timeStampBufLen - (i + 1); /* Account for null character too */
161 configure = TRUE;
162 }
164 if (SysMin_bufSize != 0) {
166 #ifndef SMP
167 key = Gate_enterSystem();
168 #else
169 /* Disable only local interrupts to place chars in local line buffer */
170 key = (IArg)Core_hwiDisable();
171 coreId = Core_getId();
172 #endif
174 lineIdx = module->lineBuffers[coreId].lineidx;
175 lineBuf = module->lineBuffers[coreId].linebuf;
176 lineBuf[lineIdx++] = ch;
177 module->lineBuffers[coreId].lineidx = lineIdx;
179 #ifdef SMP
180 /* Copy line buffer to shared output buffer at EOL or when filled up */
181 if ((ch == '\n') || (lineIdx >= SysMin_LINEBUFSIZE)) {
182 Gate_enterSystem();
184 /* Tag core number */
185 SysMin_output('[');
186 SysMin_output(0x30 + coreId);
187 SysMin_output(']');
188 #else
189 if (module->getTime == TRUE) {
190 #endif
191 uSec = Clock_getTicks() * (UInt64)Clock_tickPeriod;
192 SysMin_output('[');
193 if (uSec) {
194 sprintf(timeStamp, "%17llu\0", uSec);
195 }
196 for (index = startIdx; index < endIdx; index++) {
197 if (index == decPtIdx) {
198 SysMin_output('.');
199 }
200 if (timeStamp[index] == ' ' && index >= leftSpaceIdx) {
201 SysMin_output('0');
202 }
203 else {
204 SysMin_output(timeStamp[index]);
205 }
206 }
207 SysMin_output(']');
208 SysMin_output(' ');
209 #ifdef SMP
210 for (i = 0; i < lineIdx; i++) {
211 SysMin_output(lineBuf[i]);
212 }
213 module->writeidx[0] = module->outidx;
214 module->lineBuffers[coreId].lineidx = 0;
216 Gate_leaveSystem(key);
217 }
218 else {
219 /* restore local interrupts */
220 Core_hwiRestore((UInt)key);
221 }
222 #else
223 module->getTime = FALSE;
224 }
226 /* Copy line buffer to shared output buffer at EOL or when filled up */
227 if ((ch == '\n') || (lineIdx >= SysMin_LINEBUFSIZE)) {
228 for (i = 0; i < lineIdx; i++) {
229 SysMin_output(lineBuf[i]);
230 }
231 module->lineBuffers[coreId].lineidx = 0;
232 module->getTime = TRUE;
233 module->writeidx[0] = module->outidx;
234 }
236 Gate_leaveSystem(key);
237 #endif
239 }
240 }
242 /*
243 * ======== SysMin_ready ========
244 */
245 Bool SysMin_ready()
246 {
247 return (SysMin_bufSize != 0);
248 }
250 /*
251 * ======== SysMin_flush ========
252 * Called during SysMin_exit, System_exit or System_flush.
253 */
254 Void SysMin_flush()
255 {
256 /* Using custom circular buffer implementation without resetting write ptr */
257 #if 0
258 IArg key;
260 key = Gate_enterSystem();
262 /*
263 * If a wrap occured, we need to flush the "end" of the internal buffer
264 * first to maintain fifo character output order.
265 */
266 if (module->wrapped == TRUE) {
267 SysMin_outputFunc(module->outbuf + module->outidx,
268 SysMin_bufSize - module->outidx);
269 }
271 SysMin_outputFunc(module->outbuf, module->outidx);
272 module->outidx = 0;
273 module->wrapped = FALSE;
275 Gate_leaveSystem(key);
276 #endif
277 }