xref: /nrf52832-nimble/rt-thread/components/utilities/logtrace/log_trace.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  *                Bernard      the first version
9*10465441SEvalZero  * 2013-06-26     Grissiom     refactor
10*10465441SEvalZero  */
11*10465441SEvalZero 
12*10465441SEvalZero #include <rtthread.h>
13*10465441SEvalZero #include <rthw.h>
14*10465441SEvalZero #include <stdio.h>
15*10465441SEvalZero #include "log_trace.h"
16*10465441SEvalZero 
17*10465441SEvalZero #ifdef RT_USING_FINSH
18*10465441SEvalZero #include <finsh.h>
19*10465441SEvalZero #else
20*10465441SEvalZero #define FINSH_FUNCTION_EXPORT(...)
21*10465441SEvalZero #define FINSH_FUNCTION_EXPORT_ALIAS(...)
22*10465441SEvalZero #endif
23*10465441SEvalZero 
24*10465441SEvalZero /* log pseudo device */
25*10465441SEvalZero static struct rt_device _log_device;
26*10465441SEvalZero 
27*10465441SEvalZero static rt_device_t _traceout_device = RT_NULL;
28*10465441SEvalZero 
29*10465441SEvalZero /* define a default lg session. The name is empty. */
30*10465441SEvalZero static struct log_trace_session _def_session = {{"\0"}, LOG_TRACE_LEVEL_DEFAULT};
31*10465441SEvalZero static const struct log_trace_session *_the_sessions[LOG_TRACE_MAX_SESSION] = {&_def_session};
32*10465441SEvalZero /* there is a default session at least */
33*10465441SEvalZero static rt_uint16_t _the_sess_nr = 1;
34*10465441SEvalZero 
_idname_len(log_trace_idnum_t id)35*10465441SEvalZero rt_inline int _idname_len(log_trace_idnum_t id)
36*10465441SEvalZero {
37*10465441SEvalZero     /* little endian */
38*10465441SEvalZero     if ((id & 0x000000FF) == 0)
39*10465441SEvalZero         return 0;
40*10465441SEvalZero     if ((id & 0x0000FF00) == 0)
41*10465441SEvalZero         return 1;
42*10465441SEvalZero     if ((id & 0x00FF0000) == 0)
43*10465441SEvalZero         return 2;
44*10465441SEvalZero     if ((id & 0xFF000000) == 0)
45*10465441SEvalZero         return 3;
46*10465441SEvalZero #ifndef LOG_TRACE_USE_LONGNAME
47*10465441SEvalZero     return 4;
48*10465441SEvalZero #else
49*10465441SEvalZero     {
50*10465441SEvalZero         rt_uint32_t id2 = id >> 32;
51*10465441SEvalZero         if ((id2 & 0x000000FF) == 0)
52*10465441SEvalZero             return 4;
53*10465441SEvalZero         if ((id2 & 0x0000FF00) == 0)
54*10465441SEvalZero             return 5;
55*10465441SEvalZero         if ((id2 & 0x00FF0000) == 0)
56*10465441SEvalZero             return 6;
57*10465441SEvalZero         if ((id2 & 0xFF000000) == 0)
58*10465441SEvalZero             return 7;
59*10465441SEvalZero         return 8;
60*10465441SEvalZero     }
61*10465441SEvalZero #endif
62*10465441SEvalZero }
63*10465441SEvalZero 
64*10465441SEvalZero /* lookup the session according to name.
65*10465441SEvalZero  *
66*10465441SEvalZero  * @param len is the length of the name
67*10465441SEvalZero  * @return the pointer to the named session. RT_NULL when there is no such a
68*10465441SEvalZero  * session.
69*10465441SEvalZero  */
_lg_lookup_session(log_trace_idnum_t num)70*10465441SEvalZero static struct log_trace_session* _lg_lookup_session(log_trace_idnum_t num)
71*10465441SEvalZero {
72*10465441SEvalZero     static const struct log_trace_session *_cache = &_def_session;
73*10465441SEvalZero     rt_uint16_t first, last;
74*10465441SEvalZero 
75*10465441SEvalZero     if (_cache->id.num == num)
76*10465441SEvalZero         return (struct log_trace_session *)_cache;
77*10465441SEvalZero 
78*10465441SEvalZero     first = 0;
79*10465441SEvalZero     last  = _the_sess_nr;
80*10465441SEvalZero     do {
81*10465441SEvalZero         unsigned int i = (first + last)/2;
82*10465441SEvalZero 
83*10465441SEvalZero         RT_ASSERT(_the_sessions[i]);
84*10465441SEvalZero 
85*10465441SEvalZero         if (_the_sessions[i]->id.num == num)
86*10465441SEvalZero         {
87*10465441SEvalZero             /* there is no need to protect the _cache because write a pointer
88*10465441SEvalZero              * is atomic. So we cannot get a invalid pointer. The worst thing
89*10465441SEvalZero              * could happen is there is an interrupt in the read/modify/write
90*10465441SEvalZero              * process and we wrote the old one to _cache. But it doesn't harm
91*10465441SEvalZero              * a lot because it will be flushed in the next time. */
92*10465441SEvalZero             _cache = _the_sessions[i];
93*10465441SEvalZero             return (struct log_trace_session *)_the_sessions[i];
94*10465441SEvalZero         }
95*10465441SEvalZero         else if (_the_sessions[i]->id.num > num)
96*10465441SEvalZero         {
97*10465441SEvalZero             last = i;
98*10465441SEvalZero         }
99*10465441SEvalZero         else // _the_sessions[i]->id.num < num
100*10465441SEvalZero         {
101*10465441SEvalZero             first = i;
102*10465441SEvalZero         }
103*10465441SEvalZero     } while (first != last-1);
104*10465441SEvalZero 
105*10465441SEvalZero     return RT_NULL;
106*10465441SEvalZero }
107*10465441SEvalZero 
log_trace_register_session(const struct log_trace_session * session)108*10465441SEvalZero rt_err_t log_trace_register_session(const struct log_trace_session *session)
109*10465441SEvalZero {
110*10465441SEvalZero     unsigned int lvl, i;
111*10465441SEvalZero 
112*10465441SEvalZero     if (_the_sess_nr == LOG_TRACE_MAX_SESSION)
113*10465441SEvalZero         return -RT_EFULL;
114*10465441SEvalZero 
115*10465441SEvalZero     if (session == RT_NULL)
116*10465441SEvalZero         return RT_EOK;
117*10465441SEvalZero 
118*10465441SEvalZero     lvl = rt_hw_interrupt_disable();
119*10465441SEvalZero     /* inserting the sessions in ascending order.
120*10465441SEvalZero      *
121*10465441SEvalZero      * this might take relatively long time. But since the register should only
122*10465441SEvalZero      * happen when initialize the whole system, this should not be a matter. */
123*10465441SEvalZero     for (i = 0; i < _the_sess_nr; i++)
124*10465441SEvalZero     {
125*10465441SEvalZero         if (_the_sessions[i]->id.num > session->id.num)
126*10465441SEvalZero         {
127*10465441SEvalZero             rt_memmove(_the_sessions+i+1, _the_sessions+i,
128*10465441SEvalZero                        (_the_sess_nr-i)*sizeof(&_the_sessions[0]));
129*10465441SEvalZero             _the_sessions[i] = session;
130*10465441SEvalZero             break;
131*10465441SEvalZero         }
132*10465441SEvalZero         else if (_the_sessions[i]->id.num == session->id.num)
133*10465441SEvalZero         {
134*10465441SEvalZero             rt_kprintf("registering session 0x%p twice\n", session);
135*10465441SEvalZero             rt_hw_interrupt_enable(lvl);
136*10465441SEvalZero             return -RT_ERROR;
137*10465441SEvalZero         }
138*10465441SEvalZero     }
139*10465441SEvalZero     if (i == _the_sess_nr)
140*10465441SEvalZero         _the_sessions[i] = session;
141*10465441SEvalZero     _the_sess_nr++;
142*10465441SEvalZero     rt_hw_interrupt_enable(lvl);
143*10465441SEvalZero 
144*10465441SEvalZero     return RT_EOK;
145*10465441SEvalZero }
146*10465441SEvalZero 
log_trace_session_find(const char * name)147*10465441SEvalZero struct log_trace_session* log_trace_session_find(const char *name)
148*10465441SEvalZero {
149*10465441SEvalZero     union log_trace_id *idp;
150*10465441SEvalZero 
151*10465441SEvalZero     RT_ASSERT(name);
152*10465441SEvalZero     idp = (union log_trace_id*)name;
153*10465441SEvalZero     return _lg_lookup_session(idp->num);
154*10465441SEvalZero }
155*10465441SEvalZero 
log_trace_set_level(rt_uint8_t level)156*10465441SEvalZero void log_trace_set_level(rt_uint8_t level)
157*10465441SEvalZero {
158*10465441SEvalZero     _def_session.lvl = level;
159*10465441SEvalZero }
160*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(log_trace_set_level, log_level, set the filter level of log trace);
161*10465441SEvalZero 
log_trace_session_set_level(struct log_trace_session * sess,rt_uint8_t level)162*10465441SEvalZero void log_trace_session_set_level(struct log_trace_session *sess, rt_uint8_t level)
163*10465441SEvalZero {
164*10465441SEvalZero     RT_ASSERT(sess);
165*10465441SEvalZero     sess->lvl = level;
166*10465441SEvalZero }
167*10465441SEvalZero 
168*10465441SEvalZero /* parse the level info in fmt
169*10465441SEvalZero  *
170*10465441SEvalZero  * @param flen the length of the format.
171*10465441SEvalZero  * @param lvlp the pointer to level. It will store the level in the memory the
172*10465441SEvalZero  *        lvlp points to. The default value is LOG_TRACE_LEVEL_DEFAULT.
173*10465441SEvalZero  * @return the number of char it scaned.
174*10465441SEvalZero  */
_lg_parse_lvl(const char * fmt,rt_size_t flen,int * lvlp)175*10465441SEvalZero static rt_size_t _lg_parse_lvl(const char *fmt, rt_size_t flen, int *lvlp)
176*10465441SEvalZero {
177*10465441SEvalZero     RT_ASSERT(fmt);
178*10465441SEvalZero     RT_ASSERT(lvlp);
179*10465441SEvalZero 
180*10465441SEvalZero     /* setup default value */
181*10465441SEvalZero     *lvlp = LOG_TRACE_LEVEL_DEFAULT;
182*10465441SEvalZero 
183*10465441SEvalZero     if (flen < 3)
184*10465441SEvalZero     {
185*10465441SEvalZero         return 0;
186*10465441SEvalZero     }
187*10465441SEvalZero 
188*10465441SEvalZero     if (fmt[0] == '<' && fmt[2] == '>')
189*10465441SEvalZero     {
190*10465441SEvalZero         *lvlp = fmt[1] - '0';
191*10465441SEvalZero         return 3;
192*10465441SEvalZero     }
193*10465441SEvalZero     return 0;
194*10465441SEvalZero }
195*10465441SEvalZero 
196*10465441SEvalZero /* parse the header in fmt
197*10465441SEvalZero  *
198*10465441SEvalZero  * @param flen the length of the format.
199*10465441SEvalZero  * @param sessp the pointer of pointer to the session. It will store the
200*10465441SEvalZero  *        session pointer in the memory the sessp points to. When failed to
201*10465441SEvalZero  *        find the session, it will be setted to the default session.
202*10465441SEvalZero  * @return the number of char it scaned, i.e., the length of header.
203*10465441SEvalZero  */
_lg_parse_session(const char * fmt,rt_size_t flen,struct log_trace_session ** sessp)204*10465441SEvalZero static rt_size_t _lg_parse_session(
205*10465441SEvalZero         const char *fmt, rt_size_t flen, struct log_trace_session **sessp)
206*10465441SEvalZero {
207*10465441SEvalZero     unsigned int i;
208*10465441SEvalZero     struct log_trace_session *tmpsess;
209*10465441SEvalZero     union log_trace_id id;
210*10465441SEvalZero 
211*10465441SEvalZero     RT_ASSERT(fmt);
212*10465441SEvalZero     RT_ASSERT(sessp);
213*10465441SEvalZero 
214*10465441SEvalZero     /* setup default value */
215*10465441SEvalZero     *sessp = &_def_session;
216*10465441SEvalZero 
217*10465441SEvalZero     /* no name space left */
218*10465441SEvalZero     if (flen < sizeof(id) + 2)
219*10465441SEvalZero         return 0;
220*10465441SEvalZero 
221*10465441SEvalZero     if (fmt[0] != '[')
222*10465441SEvalZero         return 0;
223*10465441SEvalZero 
224*10465441SEvalZero     id.num = 0;
225*10465441SEvalZero     /* skip '[' and convert the string to id number. */
226*10465441SEvalZero     for (i = 1; fmt[i] != ']'; i++)
227*10465441SEvalZero     {
228*10465441SEvalZero         if (i - 1 == sizeof(id))
229*10465441SEvalZero             return 0;
230*10465441SEvalZero         id.name[i-1] = fmt[i];
231*10465441SEvalZero     }
232*10465441SEvalZero     tmpsess = _lg_lookup_session(id.num);
233*10465441SEvalZero     if (tmpsess != RT_NULL)
234*10465441SEvalZero     {
235*10465441SEvalZero         *sessp = tmpsess;
236*10465441SEvalZero         /* only count the header length when we found the session. So
237*10465441SEvalZero          * the wrong [name] will be printed out. */
238*10465441SEvalZero         return i + 1;
239*10465441SEvalZero     }
240*10465441SEvalZero 
241*10465441SEvalZero     return 0;
242*10465441SEvalZero }
243*10465441SEvalZero 
__logtrace_vfmtout(const struct log_trace_session * session,const char * fmt,va_list argptr)244*10465441SEvalZero void __logtrace_vfmtout(const struct log_trace_session *session,
245*10465441SEvalZero                         const char *fmt,
246*10465441SEvalZero                         va_list argptr)
247*10465441SEvalZero {
248*10465441SEvalZero     /* 1 for ']' */
249*10465441SEvalZero     static char _trace_buf[1+LOG_TRACE_BUFSZ];
250*10465441SEvalZero     char *ptr;
251*10465441SEvalZero     rt_size_t length;
252*10465441SEvalZero 
253*10465441SEvalZero     RT_ASSERT(session);
254*10465441SEvalZero     RT_ASSERT(fmt);
255*10465441SEvalZero 
256*10465441SEvalZero     /* it's default session */
257*10465441SEvalZero     if (session->id.name[0] == '\0')
258*10465441SEvalZero     {
259*10465441SEvalZero         rt_snprintf(_trace_buf, sizeof(_trace_buf), "[%08x]", rt_tick_get());
260*10465441SEvalZero         if (_traceout_device != RT_NULL)
261*10465441SEvalZero         {
262*10465441SEvalZero             rt_device_write(_traceout_device, -1, _trace_buf, 10);
263*10465441SEvalZero         }
264*10465441SEvalZero 
265*10465441SEvalZero         ptr = &_trace_buf[0];
266*10465441SEvalZero     }
267*10465441SEvalZero     else
268*10465441SEvalZero     {
269*10465441SEvalZero         rt_snprintf(_trace_buf, sizeof(_trace_buf), "[%08x][", rt_tick_get());
270*10465441SEvalZero         if (_traceout_device != RT_NULL)
271*10465441SEvalZero         {
272*10465441SEvalZero             rt_device_write(_traceout_device, -1, _trace_buf, 11);
273*10465441SEvalZero             rt_device_write(_traceout_device, -1,
274*10465441SEvalZero                     session->id.name, _idname_len(session->id.num));
275*10465441SEvalZero         }
276*10465441SEvalZero 
277*10465441SEvalZero         _trace_buf[0] = ']';
278*10465441SEvalZero         ptr = &_trace_buf[1];
279*10465441SEvalZero     }
280*10465441SEvalZero 
281*10465441SEvalZero     length = rt_vsnprintf(ptr, LOG_TRACE_BUFSZ, fmt, argptr);
282*10465441SEvalZero 
283*10465441SEvalZero     if (length >= LOG_TRACE_BUFSZ)
284*10465441SEvalZero         length = LOG_TRACE_BUFSZ - 1;
285*10465441SEvalZero 
286*10465441SEvalZero     if (_traceout_device != RT_NULL)
287*10465441SEvalZero     {
288*10465441SEvalZero         rt_device_write(_traceout_device, -1, _trace_buf, length + 1);
289*10465441SEvalZero     }
290*10465441SEvalZero }
291*10465441SEvalZero 
log_trace(const char * fmt,...)292*10465441SEvalZero void log_trace(const char *fmt, ...)
293*10465441SEvalZero {
294*10465441SEvalZero     va_list args;
295*10465441SEvalZero     int level;
296*10465441SEvalZero     struct log_trace_session *session;
297*10465441SEvalZero 
298*10465441SEvalZero     RT_ASSERT(fmt);
299*10465441SEvalZero 
300*10465441SEvalZero     fmt += _lg_parse_lvl(fmt, strlen(fmt), &level);
301*10465441SEvalZero     fmt += _lg_parse_session(fmt, strlen(fmt), &session);
302*10465441SEvalZero 
303*10465441SEvalZero     /* filter by level */
304*10465441SEvalZero     if (level > session->lvl)
305*10465441SEvalZero         return;
306*10465441SEvalZero 
307*10465441SEvalZero     va_start(args, fmt);
308*10465441SEvalZero     __logtrace_vfmtout(session, fmt, args);
309*10465441SEvalZero     va_end(args);
310*10465441SEvalZero }
311*10465441SEvalZero FINSH_FUNCTION_EXPORT(log_trace, log trace);
312*10465441SEvalZero 
log_session(const struct log_trace_session * session,const char * fmt,...)313*10465441SEvalZero void log_session(const struct log_trace_session *session, const char *fmt, ...)
314*10465441SEvalZero {
315*10465441SEvalZero     va_list args;
316*10465441SEvalZero     int level;
317*10465441SEvalZero 
318*10465441SEvalZero     RT_ASSERT(session);
319*10465441SEvalZero     RT_ASSERT(fmt);
320*10465441SEvalZero 
321*10465441SEvalZero     fmt += _lg_parse_lvl(fmt, strlen(fmt), &level);
322*10465441SEvalZero     if (level > session->lvl)
323*10465441SEvalZero         return;
324*10465441SEvalZero 
325*10465441SEvalZero     va_start(args, fmt);
326*10465441SEvalZero     __logtrace_vfmtout(session, fmt, args);
327*10465441SEvalZero     va_end(args);
328*10465441SEvalZero }
329*10465441SEvalZero 
log_trace_flush(void)330*10465441SEvalZero void log_trace_flush(void)
331*10465441SEvalZero {
332*10465441SEvalZero     rt_device_control(_traceout_device, LOG_TRACE_CTRL_FLUSH, RT_NULL);
333*10465441SEvalZero }
334*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(log_trace_flush, log_flush, flush log on the buffer);
335*10465441SEvalZero 
336*10465441SEvalZero /* RT-Thread common device interface */
_log_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)337*10465441SEvalZero static rt_size_t _log_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
338*10465441SEvalZero {
339*10465441SEvalZero     char c;
340*10465441SEvalZero     int level;
341*10465441SEvalZero     rt_size_t head_len;
342*10465441SEvalZero     const char *ptr = buffer;
343*10465441SEvalZero     struct log_trace_session *session;
344*10465441SEvalZero 
345*10465441SEvalZero     head_len = _lg_parse_lvl(ptr, size, &level);
346*10465441SEvalZero     head_len += _lg_parse_session(ptr+head_len, size-head_len, &session);
347*10465441SEvalZero 
348*10465441SEvalZero     /* filter by level */
349*10465441SEvalZero     if (level > session->lvl)
350*10465441SEvalZero         return size;
351*10465441SEvalZero 
352*10465441SEvalZero     if (_traceout_device != RT_NULL)
353*10465441SEvalZero     {
354*10465441SEvalZero         c = '[';
355*10465441SEvalZero         rt_device_write(_traceout_device, -1, &c, 1);
356*10465441SEvalZero         rt_device_write(_traceout_device, -1, session->id.name, _idname_len(session->id.num));
357*10465441SEvalZero         c = ']';
358*10465441SEvalZero         rt_device_write(_traceout_device, -1, &c, 1);
359*10465441SEvalZero         rt_device_write(_traceout_device, -1, ((char*)buffer)+head_len, size - head_len);
360*10465441SEvalZero     }
361*10465441SEvalZero 
362*10465441SEvalZero     return size;
363*10465441SEvalZero }
364*10465441SEvalZero 
_log_control(rt_device_t dev,int cmd,void * arg)365*10465441SEvalZero static rt_err_t _log_control(rt_device_t dev, int cmd, void *arg)
366*10465441SEvalZero {
367*10465441SEvalZero     if (_traceout_device == RT_NULL) return -RT_ERROR;
368*10465441SEvalZero 
369*10465441SEvalZero     return rt_device_control(_traceout_device, cmd, arg);
370*10465441SEvalZero }
371*10465441SEvalZero 
372*10465441SEvalZero #ifdef RT_USING_DEVICE_OPS
373*10465441SEvalZero const static struct rt_device_ops log_device_ops =
374*10465441SEvalZero {
375*10465441SEvalZero     RT_NULL,
376*10465441SEvalZero     RT_NULL,
377*10465441SEvalZero     RT_NULL,
378*10465441SEvalZero     RT_NULL,
379*10465441SEvalZero     _log_write,
380*10465441SEvalZero     _log_control
381*10465441SEvalZero };
382*10465441SEvalZero #endif
383*10465441SEvalZero 
log_trace_init(void)384*10465441SEvalZero int log_trace_init(void)
385*10465441SEvalZero {
386*10465441SEvalZero     rt_memset(&_log_device, 0x00, sizeof(_log_device));
387*10465441SEvalZero 
388*10465441SEvalZero     _log_device.type = RT_Device_Class_Char;
389*10465441SEvalZero #ifdef RT_USING_DEVICE_OPS
390*10465441SEvalZero     _log_device.ops     = &log_device_ops;
391*10465441SEvalZero #else
392*10465441SEvalZero     _log_device.init    = RT_NULL;
393*10465441SEvalZero     _log_device.open    = RT_NULL;
394*10465441SEvalZero     _log_device.close   = RT_NULL;
395*10465441SEvalZero     _log_device.read    = RT_NULL;
396*10465441SEvalZero     _log_device.write   = _log_write;
397*10465441SEvalZero     _log_device.control = _log_control;
398*10465441SEvalZero #endif
399*10465441SEvalZero 
400*10465441SEvalZero     /* no indication and complete callback */
401*10465441SEvalZero     _log_device.rx_indicate = RT_NULL;
402*10465441SEvalZero     _log_device.tx_complete = RT_NULL;
403*10465441SEvalZero 
404*10465441SEvalZero     rt_device_register(&_log_device, "log", RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR);
405*10465441SEvalZero 
406*10465441SEvalZero 	/* set console as default device */
407*10465441SEvalZero 	_traceout_device = rt_console_get_device();
408*10465441SEvalZero 
409*10465441SEvalZero     return 0;
410*10465441SEvalZero }
411*10465441SEvalZero INIT_DEVICE_EXPORT(log_trace_init);
412*10465441SEvalZero 
log_trace_get_device(void)413*10465441SEvalZero rt_device_t log_trace_get_device(void)
414*10465441SEvalZero {
415*10465441SEvalZero     return _traceout_device;
416*10465441SEvalZero }
417*10465441SEvalZero 
log_trace_set_device(const char * device_name)418*10465441SEvalZero rt_err_t log_trace_set_device(const char *device_name)
419*10465441SEvalZero {
420*10465441SEvalZero     struct rt_device *output_device;
421*10465441SEvalZero 
422*10465441SEvalZero     /* find out output device */
423*10465441SEvalZero     output_device = rt_device_find(device_name);
424*10465441SEvalZero     if (output_device != RT_NULL)
425*10465441SEvalZero     {
426*10465441SEvalZero         rt_err_t result;
427*10465441SEvalZero 
428*10465441SEvalZero         /* open device */
429*10465441SEvalZero         result = rt_device_open(output_device, RT_DEVICE_FLAG_STREAM | RT_DEVICE_OFLAG_RDWR);
430*10465441SEvalZero         if (result != RT_EOK)
431*10465441SEvalZero         {
432*10465441SEvalZero             rt_kprintf("Open trace device failed.\n");
433*10465441SEvalZero             return -RT_ERROR;
434*10465441SEvalZero         }
435*10465441SEvalZero     }
436*10465441SEvalZero 
437*10465441SEvalZero     /* set trace out device */
438*10465441SEvalZero     if (_traceout_device != RT_NULL)
439*10465441SEvalZero         rt_device_close(_traceout_device);
440*10465441SEvalZero     _traceout_device = output_device;
441*10465441SEvalZero 
442*10465441SEvalZero     return RT_EOK;
443*10465441SEvalZero }
444*10465441SEvalZero FINSH_FUNCTION_EXPORT_ALIAS(log_trace_set_device, log_device, set device of log trace);
445*10465441SEvalZero 
446