From e156a8d62bbee29b784a5a09fe541227385d512c Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Sun, 30 Jun 2013 21:51:41 +0800 Subject: Move logtrace to utilites --- components/logtrace/SConscript | 9 - components/logtrace/log_file.c | 115 -------- components/logtrace/log_trace.c | 427 ------------------------------ components/logtrace/log_trace.h | 151 ----------- components/utilities/SConscript | 15 ++ components/utilities/logtrace/SConscript | 9 + components/utilities/logtrace/log_file.c | 115 ++++++++ components/utilities/logtrace/log_trace.c | 427 ++++++++++++++++++++++++++++++ components/utilities/logtrace/log_trace.h | 151 +++++++++++ 9 files changed, 717 insertions(+), 702 deletions(-) delete mode 100644 components/logtrace/SConscript delete mode 100644 components/logtrace/log_file.c delete mode 100644 components/logtrace/log_trace.c delete mode 100644 components/logtrace/log_trace.h create mode 100644 components/utilities/SConscript create mode 100644 components/utilities/logtrace/SConscript create mode 100644 components/utilities/logtrace/log_file.c create mode 100644 components/utilities/logtrace/log_trace.c create mode 100644 components/utilities/logtrace/log_trace.h (limited to 'components') diff --git a/components/logtrace/SConscript b/components/logtrace/SConscript deleted file mode 100644 index 4a70005a41..0000000000 --- a/components/logtrace/SConscript +++ /dev/null @@ -1,9 +0,0 @@ -from building import * - -cwd = GetCurrentDir() -src = Glob('*.c') -CPPPATH = [cwd] - -group = DefineGroup('Utilities', src, depend = ['RT_USING_LOGTRACE'], CPPPATH = CPPPATH) - -Return('group') diff --git a/components/logtrace/log_file.c b/components/logtrace/log_file.c deleted file mode 100644 index c5815536b2..0000000000 --- a/components/logtrace/log_file.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * File : log_file.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2013, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * Bernard the first version - * 2013-06-26 Grissiom refactor - */ - -#ifdef RT_USING_DFS - -#include -#include -#include - -struct file_device -{ - struct rt_device parent; - - int fd; - char *filename; -}; - -/* file device for log trace */ -static struct file_device _file_device; - -/* common device interface */ -rt_err_t fdevice_open(rt_device_t dev, rt_uint16_t oflag) -{ - int fd; - struct file_device *file = (struct file_device *)dev; - if (file->fd >= 0) return -RT_EBUSY; - - fd = open(file->filename, O_RDONLY, 0); - if (fd >= 0) - { - close(fd); - - /* file exists */ - fd = open(file->filename, O_WRONLY | O_APPEND, 0); - } - else - { - /* file not exists */ - fd = open(file->filename, O_WRONLY | O_CREAT, 0); - } - - file->fd = fd; - return RT_EOK; -} - -rt_err_t fdevice_close(rt_device_t dev) -{ - rt_err_t result; - - struct file_device *file = (struct file_device *)dev; - if (file->fd < 0) return -RT_EBUSY; - - result = close(file->fd); - if (result == 0) - { - file->fd = -1; - } - - return result; -} - -rt_size_t fdevice_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - struct file_device *file = (struct file_device *)dev; - if (file->fd < 0) return 0; - - return write(file->fd, buffer, size); -} - -void log_trace_file_init(const char *filename) -{ - rt_device_t device; - - device = rt_device_find("logfile"); - if (device == RT_NULL) - { - rt_memset(&_file_device, 0x00, sizeof(_file_device)); - - _file_device.parent.type = RT_Device_Class_Char; - - _file_device.parent.init = RT_NULL; - _file_device.parent.open = fdevice_open; - _file_device.parent.close = fdevice_close; - _file_device.parent.write = fdevice_write; - - rt_device_register(&_file_device.parent, "logfile", O_RDWR); - } - - _file_device.filename = rt_strdup(filename); - _file_device.fd = -1; -} - -#endif // RT_USING_DFS diff --git a/components/logtrace/log_trace.c b/components/logtrace/log_trace.c deleted file mode 100644 index 7b17874445..0000000000 --- a/components/logtrace/log_trace.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * File : log_trace.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2013, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * Bernard the first version - * 2013-06-26 Grissiom refactor - */ - -#include -#include -#include -#include "log_trace.h" - -#ifdef RT_USING_FINSH -#include -#else -#define FINSH_FUNCTION_EXPORT(...) -#define FINSH_FUNCTION_EXPORT_ALIAS(...) -#endif - -/* log pseudo device */ -static struct rt_device _log_device; - -static rt_device_t _traceout_device = RT_NULL; - -/* define a default lg session. The name is empty. */ -static struct log_trace_session _def_session = {{0}, LOG_TRACE_LEVEL_INFO}; -static struct log_trace_session *_the_sessions[LOG_TRACE_MAX_SESSION] = {&_def_session}; -/* there is a default session at least */ -static rt_uint16_t _the_sess_nr = 1; - -rt_inline int _idname_len(log_trace_idnum_t id) -{ - /* little endian */ - if ((id & 0x000000FF) == 0) - return 0; - if ((id & 0x0000FF00) == 0) - return 1; - if ((id & 0x00FF0000) == 0) - return 2; - if ((id & 0xFF000000) == 0) - return 3; -#ifndef LOG_TRACE_USE_LONGNAME - return 4; -#else - { - rt_uint32_t id2 = id >> 32; - if ((id2 & 0x000000FF) == 0) - return 4; - if ((id2 & 0x0000FF00) == 0) - return 5; - if ((id2 & 0x00FF0000) == 0) - return 6; - if ((id2 & 0xFF000000) == 0) - return 7; - return 8; - } -#endif -} - -/* lookup the session according to name. - * - * @param len is the length of the name - * @return the pointer to the named session. RT_NULL when there is no such a - * session. - */ -static struct log_trace_session* _lg_lookup_session(log_trace_idnum_t num) -{ - static struct log_trace_session *_cache = &_def_session; - rt_uint16_t first, last; - - if (_cache->id.num == num) - return _cache; - - first = 0; - last = _the_sess_nr; - do { - unsigned int i = (first + last)/2; - if (_the_sessions[i]->id.num == num) - { - /* there is no need to protect the _cache because write a pointer - * is atomic. So we cannot get a invalid pointer. The worst thing - * could happen is there is an interrupt in the read/modify/write - * process and we wrote the old one to _cache. But it doesn't harm - * a lot because it will be flushed in the next time. */ - _cache = _the_sessions[i]; - return _the_sessions[i]; - } - else if (_the_sessions[i]->id.num > num) - { - last = i; - } - else // _the_sessions[i]->id.num < num - { - first = i; - } - } while (first != last-1); - - return RT_NULL; -} - -rt_err_t log_trace_register_session(struct log_trace_session *session) -{ - unsigned int lvl, i; - - if (_the_sess_nr == LOG_TRACE_MAX_SESSION) - return -RT_EFULL; - - if (session == RT_NULL) - return RT_EOK; - - lvl = rt_hw_interrupt_disable(); - /* inserting the sessions in ascending order. - * - * this might take relatively long time. But since the register should only - * happen when initialize the whole system, this should not be a matter. */ - for (i = 0; i < _the_sess_nr; i++) - { - if (_the_sessions[i]->id.num > session->id.num) - { - rt_memmove(_the_sessions+i, _the_sessions+i+1, _the_sess_nr-i); - _the_sessions[i] = session; - break; - } - else if (_the_sessions[i]->id.num == session->id.num) - { - rt_kprintf("registering session 0x%p twice\n", session); - rt_hw_interrupt_enable(lvl); - return -RT_ERROR; - } - } - if (i == _the_sess_nr) - _the_sessions[i] = session; - _the_sess_nr++; - rt_hw_interrupt_enable(lvl); - - return RT_EOK; -} - -struct log_trace_session* log_trace_session_find(const char *name) -{ - union log_trace_id *idp; - - RT_ASSERT(name); - idp = (union log_trace_id*)name; - return _lg_lookup_session(idp->num); -} - -void log_trace_set_level(rt_uint8_t level) -{ - _def_session.lvl = level; -} -FINSH_FUNCTION_EXPORT_ALIAS(log_trace_set_level, log_level, set the filter level of log trace); - -void log_trace_session_set_level(struct log_trace_session *sess, rt_uint8_t level) -{ - RT_ASSERT(sess); - sess->lvl = level; -} - -/* parse the level info in fmt - * - * @param flen the length of the format. - * @param lvlp the pointer to level. It will store the level in the memory the - * lvlp points to. The default value is LOG_TRACE_LEVEL_DEFAULT. - * @return the number of char it scaned. - */ -static rt_size_t _lg_parse_lvl(const char *fmt, rt_size_t flen, int *lvlp) -{ - RT_ASSERT(fmt); - RT_ASSERT(lvlp); - - /* setup default value */ - *lvlp = LOG_TRACE_LEVEL_DEFAULT; - - if (flen < 3) - { - return 0; - } - - if (fmt[0] == '<' && fmt[2] == '>') - { - *lvlp = fmt[1] - '0'; - return 3; - } - return 0; -} - -/* parse the header in fmt - * - * @param flen the length of the format. - * @param sessp the pointer of pointer to the session. It will store the - * session pointer in the memory the sessp points to. When failed to - * find the session, it will be setted to the default session. - * @return the number of char it scaned, i.e., the length of header. - */ -static rt_size_t _lg_parse_session( - const char *fmt, rt_size_t flen, struct log_trace_session **sessp) -{ - unsigned int i; - struct log_trace_session *tmpsess; - union log_trace_id id; - - RT_ASSERT(fmt); - RT_ASSERT(sessp); - - /* setup default value */ - *sessp = &_def_session; - - /* no name space left */ - if (flen < sizeof(id) + 2) - return 0; - - if (fmt[0] != '[') - return 0; - - id.num = 0; - /* skip '[' and convert the string to id number. */ - for (i = 1; fmt[i] != ']'; i++) - { - if (i - 1 == sizeof(id)) - return 0; - id.name[i-1] = fmt[i]; - } - tmpsess = _lg_lookup_session(id.num); - if (tmpsess != RT_NULL) - { - *sessp = tmpsess; - /* only count the header length when we found the session. So - * the wrong [name] will be printed out. */ - return i + 1; - } - - return 0; -} - -static void _lg_fmtout( - struct log_trace_session *session, const char *fmt, va_list argptr) -{ - /* 1 for ']' */ - static char _trace_buf[1+LOG_TRACE_BUFSZ]; - char *ptr; - rt_size_t length; - - RT_ASSERT(session); - RT_ASSERT(fmt); - - rt_snprintf(_trace_buf, sizeof(_trace_buf), "[%08x][", rt_tick_get()); - if (_traceout_device != RT_NULL) - { - rt_device_write(_traceout_device, -1, _trace_buf, 11); - rt_device_write(_traceout_device, -1, - session->id.name, _idname_len(session->id.num)); - } - - _trace_buf[0] = ']'; - ptr = &_trace_buf[1]; - length = vsnprintf(ptr, LOG_TRACE_BUFSZ, fmt, argptr); - - if (length >= LOG_TRACE_BUFSZ) - length = LOG_TRACE_BUFSZ - 1; - - if (_traceout_device != RT_NULL) - { - rt_device_write(_traceout_device, -1, _trace_buf, length + 1); - } -} - -void log_trace(const char *fmt, ...) -{ - va_list args; - int level; - struct log_trace_session *session; - - RT_ASSERT(fmt); - - fmt += _lg_parse_lvl(fmt, strlen(fmt), &level); - fmt += _lg_parse_session(fmt, strlen(fmt), &session); - - /* filter by level */ - if (level > session->lvl) - return; - - va_start(args, fmt); - _lg_fmtout(session, fmt, args); - va_end(args); -} -FINSH_FUNCTION_EXPORT(log_trace, log trace); - -void log_session(struct log_trace_session *session, const char *fmt, ...) -{ - va_list args; - int level; - - RT_ASSERT(session); - RT_ASSERT(fmt); - - fmt += _lg_parse_lvl(fmt, strlen(fmt), &level); - if (level > session->lvl) - return; - - va_start(args, fmt); - _lg_fmtout(session, fmt, args); - va_end(args); -} - -void log_trace_flush(void) -{ - rt_device_control(_traceout_device, LOG_TRACE_CTRL_FLUSH, RT_NULL); -} -FINSH_FUNCTION_EXPORT_ALIAS(log_trace_flush, log_flush, flush log on the buffer); - -/* RT-Thread common device interface */ -static rt_size_t _log_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - char c; - int level; - rt_size_t head_len; - const char *ptr = buffer; - struct log_trace_session *session; - - head_len = _lg_parse_lvl(ptr, size, &level); - head_len += _lg_parse_session(ptr+head_len, size-head_len, &session); - - /* filter by level */ - if (level > session->lvl) - return size; - - if (_traceout_device != RT_NULL) - { - c = '['; - rt_device_write(_traceout_device, -1, &c, 1); - rt_device_write(_traceout_device, -1, session->id.name, _idname_len(session->id.num)); - c = ']'; - rt_device_write(_traceout_device, -1, &c, 1); - rt_device_write(_traceout_device, -1, ((char*)buffer)+head_len, size - head_len); - } - - return size; -} - -static rt_err_t _log_control(rt_device_t dev, rt_uint8_t cmd, void *arg) -{ - if (_traceout_device == RT_NULL) return -RT_ERROR; - - return rt_device_control(_traceout_device, cmd, arg); -} - -void log_trace_init(void) -{ - rt_memset(&_log_device, 0x00, sizeof(_log_device)); - - _log_device.type = RT_Device_Class_Char; - _log_device.init = RT_NULL; - _log_device.open = RT_NULL; - _log_device.close = RT_NULL; - _log_device.read = RT_NULL; - _log_device.write = _log_write; - _log_device.control = _log_control; - - /* no indication and complete callback */ - _log_device.rx_indicate = RT_NULL; - _log_device.tx_complete = RT_NULL; - - rt_device_register(&_log_device, "log", RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR); - return ; -} - -rt_device_t log_trace_get_device(void) -{ - return _traceout_device; -} - -rt_err_t log_trace_set_device(const char *device_name) -{ - struct rt_device *output_device; - - /* find out output device */ - output_device = rt_device_find(device_name); - if (output_device != RT_NULL) - { - rt_err_t result; - - /* open device */ - result = rt_device_open(output_device, RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR); - if (result != RT_EOK) - { - rt_kprintf("Open trace device failed.\n"); - return -RT_ERROR; - } - } - - /* set trace out device */ - if (_traceout_device != RT_NULL) - rt_device_close(_traceout_device); - _traceout_device = output_device; - - return RT_EOK; -} -FINSH_FUNCTION_EXPORT_ALIAS(log_trace_set_device, log_device, set device of log trace); - -#ifdef RT_USING_DFS -void log_trace_set_file(const char *filename) -{ - log_trace_file_init(filename); - log_trace_set_device("logfile"); -} -FINSH_FUNCTION_EXPORT_ALIAS(log_trace_set_file, log_file, set output filename of log trace); -#endif // RT_USING_DFS - diff --git a/components/logtrace/log_trace.h b/components/logtrace/log_trace.h deleted file mode 100644 index d5a028f553..0000000000 --- a/components/logtrace/log_trace.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * File : log_trace.h - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2013, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * Bernard the first version - * 2013-06-26 Grissiom refactor - */ - -#ifndef __LOG_TRACE_H__ -#define __LOG_TRACE_H__ - -#include - -#define LOG_TRACE_LEVEL_MASK 0x0f -#define LOG_TRACE_LEVEL_NOTRACE 0x00 -#define LOG_TRACE_LEVEL_ERROR 0x01 -#define LOG_TRACE_LEVEL_WARNING 0x02 -#define LOG_TRACE_LEVEL_INFO 0x03 -#define LOG_TRACE_LEVEL_DEBUG 0x04 -#define LOG_TRACE_LEVEL_ALL 0x0f - -#ifndef LOG_TRACE_LEVEL_DEFAULT -#define LOG_TRACE_LEVEL_DEFAULT LOG_TRACE_LEVEL_INFO -#endif - -#define LOG_TRACE_ERROR "<1>" -#define LOG_TRACE_WARNING "<2>" -#define LOG_TRACE_INFO "<3>" -#define LOG_TRACE_DEBUG "<4>" - -#define LOG_TRACE_OPT_NOTS 0x10 /* no timestamp */ -#define LOG_TRACE_OPT_LN 0x20 /* terminate the current line */ - -#define LOG_TRACE_CTRL_FLUSH 0x10 -#define LOG_TRACE_CTRL_RESET 0x11 -#define LOG_TRACE_CTRL_DUMP 0x12 - -//#define LOG_TRACE_USE_LONGNAME - -#ifndef LOG_TRACE_BUFSZ -#define LOG_TRACE_BUFSZ RT_CONSOLEBUF_SIZE -#endif - -/** maximum number of sessions that can be registered to the log_trace system - */ -#ifndef LOG_TRACE_MAX_SESSION -#define LOG_TRACE_MAX_SESSION 16 -#endif - -#ifdef LOG_TRACE_USE_LONGNAME -typedef rt_uint64_t log_trace_idnum_t; -#else -typedef rt_uint32_t log_trace_idnum_t; -#endif - -/* use a integer to represent a string to avoid strcmp. Even 4 chars - * should be enough for most of the cases. - * NOTE: take care when converting the name string to id number, you - * can trapped in endianness. - */ -union log_trace_id { - char name[sizeof(log_trace_idnum_t)]; - log_trace_idnum_t num; -}; - -struct log_trace_session -{ - union log_trace_id id; - rt_uint8_t lvl; -}; - -/** initialize the log_trace system */ -void log_trace_init(void); - -/** register a session. - * - * @return RT_EOK on success. -RT_EFULL if there is no space for registration. - */ -rt_err_t log_trace_register_session(struct log_trace_session *session); - -/** find a session with name - * - * The name is not enclosed by parenthesis([]). - * - * @return RT_NULL if there is no such a session. - */ -struct log_trace_session* log_trace_session_find(const char *name); - -/** set the log level of the default session. */ -void log_trace_set_level(rt_uint8_t level); - -/** set the log level of the session */ -void log_trace_session_set_level( - struct log_trace_session *session, rt_uint8_t level); - -/** log according to the format - * - * the format of log_trace is: "[name]log messages". It will output - * "[systick][name]log messages" When there is no session named name, the - * default session will be used. - * - * We have keep the level tag before the name tag because we don't print put - * the level tag to the output and it's easier to implement if we place the - * level tag in the very beginning. - */ -void log_trace(const char *fmt, ...); - -/** log into session. - * - * the format of log_trace is: "log messages". It will output - * "[systick][name]log messages". The name is the name of the session. It is - * faster than bare log_trace. - */ -void log_session(struct log_trace_session *session, const char *fmt, ...); - -/* here comes the global part. All sessions share the some output backend. */ - -/** get the backend device */ -rt_device_t log_trace_get_device(void); - -/** set the backend device */ -rt_err_t log_trace_set_device(const char *device_name); - -void log_trace_flush(void); - -/** set the backend to file */ -void log_trace_set_file(const char *filename); - -/* log trace for NAND Flash */ -void log_trace_nand_init(const char *nand_device); -void log_trace_file_init(const char *filename); - -#endif - diff --git a/components/utilities/SConscript b/components/utilities/SConscript new file mode 100644 index 0000000000..4c815c49b8 --- /dev/null +++ b/components/utilities/SConscript @@ -0,0 +1,15 @@ +# RT-Thread building script for bridge + +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/components/utilities/logtrace/SConscript b/components/utilities/logtrace/SConscript new file mode 100644 index 0000000000..4a70005a41 --- /dev/null +++ b/components/utilities/logtrace/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('Utilities', src, depend = ['RT_USING_LOGTRACE'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/utilities/logtrace/log_file.c b/components/utilities/logtrace/log_file.c new file mode 100644 index 0000000000..c5815536b2 --- /dev/null +++ b/components/utilities/logtrace/log_file.c @@ -0,0 +1,115 @@ +/* + * File : log_file.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * Bernard the first version + * 2013-06-26 Grissiom refactor + */ + +#ifdef RT_USING_DFS + +#include +#include +#include + +struct file_device +{ + struct rt_device parent; + + int fd; + char *filename; +}; + +/* file device for log trace */ +static struct file_device _file_device; + +/* common device interface */ +rt_err_t fdevice_open(rt_device_t dev, rt_uint16_t oflag) +{ + int fd; + struct file_device *file = (struct file_device *)dev; + if (file->fd >= 0) return -RT_EBUSY; + + fd = open(file->filename, O_RDONLY, 0); + if (fd >= 0) + { + close(fd); + + /* file exists */ + fd = open(file->filename, O_WRONLY | O_APPEND, 0); + } + else + { + /* file not exists */ + fd = open(file->filename, O_WRONLY | O_CREAT, 0); + } + + file->fd = fd; + return RT_EOK; +} + +rt_err_t fdevice_close(rt_device_t dev) +{ + rt_err_t result; + + struct file_device *file = (struct file_device *)dev; + if (file->fd < 0) return -RT_EBUSY; + + result = close(file->fd); + if (result == 0) + { + file->fd = -1; + } + + return result; +} + +rt_size_t fdevice_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + struct file_device *file = (struct file_device *)dev; + if (file->fd < 0) return 0; + + return write(file->fd, buffer, size); +} + +void log_trace_file_init(const char *filename) +{ + rt_device_t device; + + device = rt_device_find("logfile"); + if (device == RT_NULL) + { + rt_memset(&_file_device, 0x00, sizeof(_file_device)); + + _file_device.parent.type = RT_Device_Class_Char; + + _file_device.parent.init = RT_NULL; + _file_device.parent.open = fdevice_open; + _file_device.parent.close = fdevice_close; + _file_device.parent.write = fdevice_write; + + rt_device_register(&_file_device.parent, "logfile", O_RDWR); + } + + _file_device.filename = rt_strdup(filename); + _file_device.fd = -1; +} + +#endif // RT_USING_DFS diff --git a/components/utilities/logtrace/log_trace.c b/components/utilities/logtrace/log_trace.c new file mode 100644 index 0000000000..7b17874445 --- /dev/null +++ b/components/utilities/logtrace/log_trace.c @@ -0,0 +1,427 @@ +/* + * File : log_trace.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * Bernard the first version + * 2013-06-26 Grissiom refactor + */ + +#include +#include +#include +#include "log_trace.h" + +#ifdef RT_USING_FINSH +#include +#else +#define FINSH_FUNCTION_EXPORT(...) +#define FINSH_FUNCTION_EXPORT_ALIAS(...) +#endif + +/* log pseudo device */ +static struct rt_device _log_device; + +static rt_device_t _traceout_device = RT_NULL; + +/* define a default lg session. The name is empty. */ +static struct log_trace_session _def_session = {{0}, LOG_TRACE_LEVEL_INFO}; +static struct log_trace_session *_the_sessions[LOG_TRACE_MAX_SESSION] = {&_def_session}; +/* there is a default session at least */ +static rt_uint16_t _the_sess_nr = 1; + +rt_inline int _idname_len(log_trace_idnum_t id) +{ + /* little endian */ + if ((id & 0x000000FF) == 0) + return 0; + if ((id & 0x0000FF00) == 0) + return 1; + if ((id & 0x00FF0000) == 0) + return 2; + if ((id & 0xFF000000) == 0) + return 3; +#ifndef LOG_TRACE_USE_LONGNAME + return 4; +#else + { + rt_uint32_t id2 = id >> 32; + if ((id2 & 0x000000FF) == 0) + return 4; + if ((id2 & 0x0000FF00) == 0) + return 5; + if ((id2 & 0x00FF0000) == 0) + return 6; + if ((id2 & 0xFF000000) == 0) + return 7; + return 8; + } +#endif +} + +/* lookup the session according to name. + * + * @param len is the length of the name + * @return the pointer to the named session. RT_NULL when there is no such a + * session. + */ +static struct log_trace_session* _lg_lookup_session(log_trace_idnum_t num) +{ + static struct log_trace_session *_cache = &_def_session; + rt_uint16_t first, last; + + if (_cache->id.num == num) + return _cache; + + first = 0; + last = _the_sess_nr; + do { + unsigned int i = (first + last)/2; + if (_the_sessions[i]->id.num == num) + { + /* there is no need to protect the _cache because write a pointer + * is atomic. So we cannot get a invalid pointer. The worst thing + * could happen is there is an interrupt in the read/modify/write + * process and we wrote the old one to _cache. But it doesn't harm + * a lot because it will be flushed in the next time. */ + _cache = _the_sessions[i]; + return _the_sessions[i]; + } + else if (_the_sessions[i]->id.num > num) + { + last = i; + } + else // _the_sessions[i]->id.num < num + { + first = i; + } + } while (first != last-1); + + return RT_NULL; +} + +rt_err_t log_trace_register_session(struct log_trace_session *session) +{ + unsigned int lvl, i; + + if (_the_sess_nr == LOG_TRACE_MAX_SESSION) + return -RT_EFULL; + + if (session == RT_NULL) + return RT_EOK; + + lvl = rt_hw_interrupt_disable(); + /* inserting the sessions in ascending order. + * + * this might take relatively long time. But since the register should only + * happen when initialize the whole system, this should not be a matter. */ + for (i = 0; i < _the_sess_nr; i++) + { + if (_the_sessions[i]->id.num > session->id.num) + { + rt_memmove(_the_sessions+i, _the_sessions+i+1, _the_sess_nr-i); + _the_sessions[i] = session; + break; + } + else if (_the_sessions[i]->id.num == session->id.num) + { + rt_kprintf("registering session 0x%p twice\n", session); + rt_hw_interrupt_enable(lvl); + return -RT_ERROR; + } + } + if (i == _the_sess_nr) + _the_sessions[i] = session; + _the_sess_nr++; + rt_hw_interrupt_enable(lvl); + + return RT_EOK; +} + +struct log_trace_session* log_trace_session_find(const char *name) +{ + union log_trace_id *idp; + + RT_ASSERT(name); + idp = (union log_trace_id*)name; + return _lg_lookup_session(idp->num); +} + +void log_trace_set_level(rt_uint8_t level) +{ + _def_session.lvl = level; +} +FINSH_FUNCTION_EXPORT_ALIAS(log_trace_set_level, log_level, set the filter level of log trace); + +void log_trace_session_set_level(struct log_trace_session *sess, rt_uint8_t level) +{ + RT_ASSERT(sess); + sess->lvl = level; +} + +/* parse the level info in fmt + * + * @param flen the length of the format. + * @param lvlp the pointer to level. It will store the level in the memory the + * lvlp points to. The default value is LOG_TRACE_LEVEL_DEFAULT. + * @return the number of char it scaned. + */ +static rt_size_t _lg_parse_lvl(const char *fmt, rt_size_t flen, int *lvlp) +{ + RT_ASSERT(fmt); + RT_ASSERT(lvlp); + + /* setup default value */ + *lvlp = LOG_TRACE_LEVEL_DEFAULT; + + if (flen < 3) + { + return 0; + } + + if (fmt[0] == '<' && fmt[2] == '>') + { + *lvlp = fmt[1] - '0'; + return 3; + } + return 0; +} + +/* parse the header in fmt + * + * @param flen the length of the format. + * @param sessp the pointer of pointer to the session. It will store the + * session pointer in the memory the sessp points to. When failed to + * find the session, it will be setted to the default session. + * @return the number of char it scaned, i.e., the length of header. + */ +static rt_size_t _lg_parse_session( + const char *fmt, rt_size_t flen, struct log_trace_session **sessp) +{ + unsigned int i; + struct log_trace_session *tmpsess; + union log_trace_id id; + + RT_ASSERT(fmt); + RT_ASSERT(sessp); + + /* setup default value */ + *sessp = &_def_session; + + /* no name space left */ + if (flen < sizeof(id) + 2) + return 0; + + if (fmt[0] != '[') + return 0; + + id.num = 0; + /* skip '[' and convert the string to id number. */ + for (i = 1; fmt[i] != ']'; i++) + { + if (i - 1 == sizeof(id)) + return 0; + id.name[i-1] = fmt[i]; + } + tmpsess = _lg_lookup_session(id.num); + if (tmpsess != RT_NULL) + { + *sessp = tmpsess; + /* only count the header length when we found the session. So + * the wrong [name] will be printed out. */ + return i + 1; + } + + return 0; +} + +static void _lg_fmtout( + struct log_trace_session *session, const char *fmt, va_list argptr) +{ + /* 1 for ']' */ + static char _trace_buf[1+LOG_TRACE_BUFSZ]; + char *ptr; + rt_size_t length; + + RT_ASSERT(session); + RT_ASSERT(fmt); + + rt_snprintf(_trace_buf, sizeof(_trace_buf), "[%08x][", rt_tick_get()); + if (_traceout_device != RT_NULL) + { + rt_device_write(_traceout_device, -1, _trace_buf, 11); + rt_device_write(_traceout_device, -1, + session->id.name, _idname_len(session->id.num)); + } + + _trace_buf[0] = ']'; + ptr = &_trace_buf[1]; + length = vsnprintf(ptr, LOG_TRACE_BUFSZ, fmt, argptr); + + if (length >= LOG_TRACE_BUFSZ) + length = LOG_TRACE_BUFSZ - 1; + + if (_traceout_device != RT_NULL) + { + rt_device_write(_traceout_device, -1, _trace_buf, length + 1); + } +} + +void log_trace(const char *fmt, ...) +{ + va_list args; + int level; + struct log_trace_session *session; + + RT_ASSERT(fmt); + + fmt += _lg_parse_lvl(fmt, strlen(fmt), &level); + fmt += _lg_parse_session(fmt, strlen(fmt), &session); + + /* filter by level */ + if (level > session->lvl) + return; + + va_start(args, fmt); + _lg_fmtout(session, fmt, args); + va_end(args); +} +FINSH_FUNCTION_EXPORT(log_trace, log trace); + +void log_session(struct log_trace_session *session, const char *fmt, ...) +{ + va_list args; + int level; + + RT_ASSERT(session); + RT_ASSERT(fmt); + + fmt += _lg_parse_lvl(fmt, strlen(fmt), &level); + if (level > session->lvl) + return; + + va_start(args, fmt); + _lg_fmtout(session, fmt, args); + va_end(args); +} + +void log_trace_flush(void) +{ + rt_device_control(_traceout_device, LOG_TRACE_CTRL_FLUSH, RT_NULL); +} +FINSH_FUNCTION_EXPORT_ALIAS(log_trace_flush, log_flush, flush log on the buffer); + +/* RT-Thread common device interface */ +static rt_size_t _log_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + char c; + int level; + rt_size_t head_len; + const char *ptr = buffer; + struct log_trace_session *session; + + head_len = _lg_parse_lvl(ptr, size, &level); + head_len += _lg_parse_session(ptr+head_len, size-head_len, &session); + + /* filter by level */ + if (level > session->lvl) + return size; + + if (_traceout_device != RT_NULL) + { + c = '['; + rt_device_write(_traceout_device, -1, &c, 1); + rt_device_write(_traceout_device, -1, session->id.name, _idname_len(session->id.num)); + c = ']'; + rt_device_write(_traceout_device, -1, &c, 1); + rt_device_write(_traceout_device, -1, ((char*)buffer)+head_len, size - head_len); + } + + return size; +} + +static rt_err_t _log_control(rt_device_t dev, rt_uint8_t cmd, void *arg) +{ + if (_traceout_device == RT_NULL) return -RT_ERROR; + + return rt_device_control(_traceout_device, cmd, arg); +} + +void log_trace_init(void) +{ + rt_memset(&_log_device, 0x00, sizeof(_log_device)); + + _log_device.type = RT_Device_Class_Char; + _log_device.init = RT_NULL; + _log_device.open = RT_NULL; + _log_device.close = RT_NULL; + _log_device.read = RT_NULL; + _log_device.write = _log_write; + _log_device.control = _log_control; + + /* no indication and complete callback */ + _log_device.rx_indicate = RT_NULL; + _log_device.tx_complete = RT_NULL; + + rt_device_register(&_log_device, "log", RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR); + return ; +} + +rt_device_t log_trace_get_device(void) +{ + return _traceout_device; +} + +rt_err_t log_trace_set_device(const char *device_name) +{ + struct rt_device *output_device; + + /* find out output device */ + output_device = rt_device_find(device_name); + if (output_device != RT_NULL) + { + rt_err_t result; + + /* open device */ + result = rt_device_open(output_device, RT_DEVICE_FLAG_STREAM | RT_DEVICE_FLAG_RDWR); + if (result != RT_EOK) + { + rt_kprintf("Open trace device failed.\n"); + return -RT_ERROR; + } + } + + /* set trace out device */ + if (_traceout_device != RT_NULL) + rt_device_close(_traceout_device); + _traceout_device = output_device; + + return RT_EOK; +} +FINSH_FUNCTION_EXPORT_ALIAS(log_trace_set_device, log_device, set device of log trace); + +#ifdef RT_USING_DFS +void log_trace_set_file(const char *filename) +{ + log_trace_file_init(filename); + log_trace_set_device("logfile"); +} +FINSH_FUNCTION_EXPORT_ALIAS(log_trace_set_file, log_file, set output filename of log trace); +#endif // RT_USING_DFS + diff --git a/components/utilities/logtrace/log_trace.h b/components/utilities/logtrace/log_trace.h new file mode 100644 index 0000000000..d5a028f553 --- /dev/null +++ b/components/utilities/logtrace/log_trace.h @@ -0,0 +1,151 @@ +/* + * File : log_trace.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * Bernard the first version + * 2013-06-26 Grissiom refactor + */ + +#ifndef __LOG_TRACE_H__ +#define __LOG_TRACE_H__ + +#include + +#define LOG_TRACE_LEVEL_MASK 0x0f +#define LOG_TRACE_LEVEL_NOTRACE 0x00 +#define LOG_TRACE_LEVEL_ERROR 0x01 +#define LOG_TRACE_LEVEL_WARNING 0x02 +#define LOG_TRACE_LEVEL_INFO 0x03 +#define LOG_TRACE_LEVEL_DEBUG 0x04 +#define LOG_TRACE_LEVEL_ALL 0x0f + +#ifndef LOG_TRACE_LEVEL_DEFAULT +#define LOG_TRACE_LEVEL_DEFAULT LOG_TRACE_LEVEL_INFO +#endif + +#define LOG_TRACE_ERROR "<1>" +#define LOG_TRACE_WARNING "<2>" +#define LOG_TRACE_INFO "<3>" +#define LOG_TRACE_DEBUG "<4>" + +#define LOG_TRACE_OPT_NOTS 0x10 /* no timestamp */ +#define LOG_TRACE_OPT_LN 0x20 /* terminate the current line */ + +#define LOG_TRACE_CTRL_FLUSH 0x10 +#define LOG_TRACE_CTRL_RESET 0x11 +#define LOG_TRACE_CTRL_DUMP 0x12 + +//#define LOG_TRACE_USE_LONGNAME + +#ifndef LOG_TRACE_BUFSZ +#define LOG_TRACE_BUFSZ RT_CONSOLEBUF_SIZE +#endif + +/** maximum number of sessions that can be registered to the log_trace system + */ +#ifndef LOG_TRACE_MAX_SESSION +#define LOG_TRACE_MAX_SESSION 16 +#endif + +#ifdef LOG_TRACE_USE_LONGNAME +typedef rt_uint64_t log_trace_idnum_t; +#else +typedef rt_uint32_t log_trace_idnum_t; +#endif + +/* use a integer to represent a string to avoid strcmp. Even 4 chars + * should be enough for most of the cases. + * NOTE: take care when converting the name string to id number, you + * can trapped in endianness. + */ +union log_trace_id { + char name[sizeof(log_trace_idnum_t)]; + log_trace_idnum_t num; +}; + +struct log_trace_session +{ + union log_trace_id id; + rt_uint8_t lvl; +}; + +/** initialize the log_trace system */ +void log_trace_init(void); + +/** register a session. + * + * @return RT_EOK on success. -RT_EFULL if there is no space for registration. + */ +rt_err_t log_trace_register_session(struct log_trace_session *session); + +/** find a session with name + * + * The name is not enclosed by parenthesis([]). + * + * @return RT_NULL if there is no such a session. + */ +struct log_trace_session* log_trace_session_find(const char *name); + +/** set the log level of the default session. */ +void log_trace_set_level(rt_uint8_t level); + +/** set the log level of the session */ +void log_trace_session_set_level( + struct log_trace_session *session, rt_uint8_t level); + +/** log according to the format + * + * the format of log_trace is: "[name]log messages". It will output + * "[systick][name]log messages" When there is no session named name, the + * default session will be used. + * + * We have keep the level tag before the name tag because we don't print put + * the level tag to the output and it's easier to implement if we place the + * level tag in the very beginning. + */ +void log_trace(const char *fmt, ...); + +/** log into session. + * + * the format of log_trace is: "log messages". It will output + * "[systick][name]log messages". The name is the name of the session. It is + * faster than bare log_trace. + */ +void log_session(struct log_trace_session *session, const char *fmt, ...); + +/* here comes the global part. All sessions share the some output backend. */ + +/** get the backend device */ +rt_device_t log_trace_get_device(void); + +/** set the backend device */ +rt_err_t log_trace_set_device(const char *device_name); + +void log_trace_flush(void); + +/** set the backend to file */ +void log_trace_set_file(const char *filename); + +/* log trace for NAND Flash */ +void log_trace_nand_init(const char *nand_device); +void log_trace_file_init(const char *filename); + +#endif + -- cgit v1.3.1