1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
32
33 34 35
36 import xdc.runtime.ILogger;
37 import xdc.runtime.Log;
38 import xdc.rov.ViewInfo;
39
40 /*!
41 * ======== LoggerIdle ========
42 * A logger which routes `Log` events to a users transport function.
43 *
44 * This logger processes log events as they are generated, stores them in
45 * a buffer and durring idle sends a section of the buffer to the user's
46 * transport function. If you are seeing no log events or dropping too
47 * many events check that you are not logging too often and have enough idle
48 * time to send. LoggerIdle is compatable with StellarisWare and MWare
49 * devices. Example transports for UART (B92 and F28M35x) and USB (F28M35x)
50 * as well as initialization functions are included in the evmF28M35x.c files
51 * under the device folder in the ti.examples directory.
52 *
53 * @a(Examples)
54 * Configuration example: The following XDC configuration statements
55 * create a logger module, and assign it as the default logger for all
56 * modules.
57 *
58 * @p(code)
59 * var Defaults = xdc.useModule('xdc.runtime.Defaults');
60 * var Diags = xdc.useModule('xdc.runtime.Diags');
61 * var LoggerIdle = xdc.useModule('ti.uia.sysbios.LoggerIdle');
62 *
63 * LoggerIdle.bufferSize = 60;
64 * LoggerIdle.timestamp = false;
65 * LoggerIdle.transportType = LoggerIdle.TransportType_UART;
66 * LoggerIdle.transportFxn = '&LoggerIdle_uartSend';
67 * var LoggerIdleParams = new LoggerIdle.Params();
68 * Defaults.common$.logger = LoggerIdle.create(LoggerIdleParams);
69 * @p
70 */
71
72 module LoggerIdle inherits ILogger {
73
74 /*!
75 * ======== TransportType ========
76 * Used to specify the type of transport to use
77 *
78 * This enum is used by the instrumentation host to determine what
79 * the transport is. It is not used by the target code.
80 */
81 enum TransportType {
82 TransportType_UART = 0,
83 TransportType_USB = 1,
84 TransportType_ETHERNET = 2,
85 TransportType_CUSTOM = 3
86 };
87
88 /*!
89 * @_nodoc
90 * ======== ModuleView ========
91 */
92 metaonly struct ModuleView {
93 Bool isEnabled;
94 Bool isTimestampEnabled;
95 Int bufferSize;
96 UInt sequenceNumber;
97 String transportType;
98 String customTransport;
99 }
100
101 metaonly struct RecordView {
102 Int sequence;
103 Long timestampRaw;
104 String modName;
105 String text;
106 Int eventId;
107 String eventName;
108 IArg arg0;
109 IArg arg1;
110 IArg arg2;
111 IArg arg3;
112 IArg arg4;
113 IArg arg5;
114 IArg arg6;
115 IArg arg7;
116 }
117
118 /*!
119 * @_nodoc
120 * ======== rovViewInfo ========
121 */
122 @Facet
123 metaonly config ViewInfo.Instance rovViewInfo =
124 ViewInfo.create({
125 viewMap: [
126 ['Module',
127 {
128 type: ViewInfo.MODULE,
129 viewInitFxn: 'viewInitModule',
130 structName: 'ModuleView'
131 }
132 ],
133 ['Records',
134 {
135 type: xdc.rov.ViewInfo.MODULE_DATA,
136 viewInitFxn: 'viewInitRecords',
137 structName: 'RecordView'
138 }
139 ]
140 ]
141 });
142
143 /*!
144 * ======== LoggerFxn ========
145 * Typedef for the transport function pointer.
146 */
147 typedef Int (*LoggerFxn)(UChar *, Int);
148
149 /*!
150 * ======== bufferSize ========
151 * LoggerIdle buffer size in 32-bit words.
152 */
153 config SizeT bufferSize = 256;
154
155 /*!
156 * ======== isTimestampEnabled ========
157 * Enable or disable logging the 64b local CPU timestamp
158 * at the start of each event
159 *
160 * Having a timestamp allows an instrumentation host (e.g.
161 * System Analyzer) to display events with the correct system time.
162 */
163 config Bool isTimestampEnabled = true;
164
165 /*!
166 * ======== transportType ========
167 * Transport used to send the records to an instrumentation host
168 *
169 * This parameter is used to specify the transport that the
170 * `{@link #transportFxn}` function will use to send the buffer to
171 * an instrumentation host (e.g. System Analyzer in CCS).
172 *
173 * This parameter is placed into the generated UIA XML file. The
174 * instrumentation host can use the XML file to help it auto-detect as
175 * much as possible and act accordingly.
176 *
177 * If the desired transport is not in the `{@link #TransportType}` enum,
178 * select `{@link #TransportType_CUSTOM}` and set the
179 * `{@link #customTransportType}` string with the desired string.
180 */
181 metaonly config TransportType transportType = TransportType_UART;
182
183 /*!
184 * ======== customTransportType ========
185 * Custom transport used to send the records to an instrumentation host
186 *
187 * If the desired transport is not in the `{@link #TransportType}` enum,
188 * and `{@link #transportType}` is set to `{@link #TransportType_CUSTOM}`,
189 * this parameter must be filled in with the correct transport name.
190 *
191 * If `{@link #transportType}` is NOT set to
192 * `{@link #TransportType_CUSTOM}`, this parameter is ignored.
193 */
194 config String customTransportType = null;
195
196 /*!
197 * ======== transportFxn ========
198 * User defined transport function responsible for transmitting the records
199 */
200 config LoggerFxn transportFxn = null;
201
202 /*!
203 * ======== writeWhenFull ========
204 * Allow Log writes to succeed even if the the LoggerIdle buffer is
205 * full.
206 *
207 * LoggerIdle maintains a circular buffer where the Log events are
208 * written. A write pointer indicates the location in the buffer
209 * where the next Log event can be written to, and a read pointer
210 * indicates the location of the next Log event to be sent to the
211 * user's transport function. Log write calls cause the write pointer
212 * to advance, and when Log data is passed to the user's transport
213 * function in the idle loop, the read pointer advances. If the
214 * read pointer catches up the the write pointer, the buffer is
215 * 'empty', and if the write pointer catches up the the read pointer,
216 * the buffer is full.
217 *
218 * The LoggerIdle buffer will fill up, if the idle function to output
219 * the Log data cannot keep up with the Log writes. When this happens,
220 * if writeWhenFull is false, Log writes will not put any new data
221 * into the buffer until the LoggerIdle transportFxn has been called
222 * to empty some of the buffer. As a result, the most recent Log
223 * events could be lost. This is a simple solution to dealing with a
224 * full buffer. Since Log event sizes vary, it avoids having to
225 * determine how much the read pointer must be adjusted to fit a new
226 * Log event. It also allows you to send a large chunk of the buffer
227 * to the transport function in one shot, since the data will not
228 * be overwritten by Log writes during the transfer. If Log events
229 * are infrequent or the idle time is sufficient to get the Log
230 * data out, then disabling writeWhenFull may be appropriate.
231 *
232 * When this flag is set to true, if the LoggerIdle buffer is full,
233 * new Log data will be written over the oldest Log record(s) in the
234 * buffer. The oldest Log records in the buffer will be lost when
235 * this happens.
236 *
237 * The cost of enabling writeWhenFull is an increase in Log write
238 * times when the buffer is full, as the buffer's read pointer will
239 * need adjusting. There is also more overhead to get the Log data
240 * out through the transport function. When writeWhenFull is enabled,
241 * LoggerIdle's idle function will copy one Log record at a time into
242 * a temporary buffer, and send the temporary buffer to the user's
243 * transport function. This is to minimize interrupt latency, as the
244 * buffer's read pointer can now be modified by both the idle function
245 * and Log writes, and must be protected. The advantage, though, is
246 * that you will not lose the most recent Log data when the buffer is
247 * full. If Log events are frequent and the idle time is insufficient
248 * to get the Log data out, then enabling writeWhenFull may be
249 * appropriate.
250 */
251 config Bool writeWhenFull = false;
252
253 /*!
254 * @_nodoc
255 * ======== L_test ========
256 * Event used for benchmark tests
257 */
258 config xdc.runtime.Log.Event L_test = {
259 mask: xdc.runtime.Diags.USER1,
260 msg: "Test Event"
261 };
262
263 /*!
264 * ======== flush ========
265 * Call the transport function to empty out the LoggerIdle buffer.
266 *
267 * This API is not intended for general use, but could be used for
268 * example, in an exception handler to recover the most recent Log
269 * data that was written after the last run of the idle loop.
270 *
271 * NOTE: Calling LoggerIdle_flush() when the idle task was in the
272 * middle of outputting data can result in lost data (writeWhenFull
273 * is true), or duplicate data (writeWhenFull is false).
274 * In the case where writeWhenFull is true, the idle function only
275 * outputs one Log record at a time, so at most one record could
276 * be lost. If writeWhenFull is false, Log data could be output
277 * twice, since LoggerIdle's internal read pointers are adjusted
278 * after the data is output.
279 */
280 Void flush();
281
282 instance:
283 /*!
284 * ======== create ========
285 * Create a `LoggerIdle` logger
286 *
287 * The logger instance will route all log events it receives to
288 * the Uart.
289 */
290 create();
291
292 @DirectCall
293 override Void write0(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid);
294
295 @DirectCall
296 override Void write1(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid,
297 IArg a1);
298
299 @DirectCall
300 override Void write2(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid,
301 IArg a1, IArg a2);
302
303 @DirectCall
304 override Void write4(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid,
305 IArg a1, IArg a2, IArg a3, IArg a4);
306
307 @DirectCall
308 override Void write8(xdc.runtime.Log.Event evt, xdc.runtime.Types.ModuleId mid,
309 IArg a1, IArg a2, IArg a3, IArg a4,
310 IArg a5, IArg a6, IArg a7, IArg a8);
311
312 internal:
313
314 /*!
315 * ======== idleWrite =========
316 * Idle function that calls the transport function.
317 */
318 Void idleWrite();
319
320 /*!
321 * ======== idleWriteEvent =========
322 * Idle function that calls the transport function to write one
323 * Log event.
324 */
325 Void idleWriteEvent();
326
327 struct Module_State {
328 LoggerFxn loggerFxn;
329 Bool enabled;
330 Bool empty;
331 UInt idleSequence;
332 UInt bufferSize;
333 UInt32 idleBuffer[];
334 UInt32 tempBuffer[];
335 UInt32 *bufferRead;
336 UInt32 *bufferWrite;
337 UInt32 *bufferPad; 338
339 UInt32 *bufferEnd;
340 };
341
342 struct Instance_State {
343 };
344 }