1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * Bernard the first version
9 * 2013-06-26 Grissiom refactor
10 */
11 #include <rtthread.h>
12 #include <log_trace.h>
13
14 #ifdef RT_USING_DFS
15
16 #include <dfs_posix.h>
17
18 struct file_device
19 {
20 struct rt_device parent;
21
22 int fd;
23 char *filename;
24 };
25
26 /* file device for log trace */
27 static struct file_device _file_device;
28
29 /* common device interface */
fdevice_open(rt_device_t dev,rt_uint16_t oflag)30 static rt_err_t fdevice_open(rt_device_t dev, rt_uint16_t oflag)
31 {
32 int fd;
33 struct file_device *fdev = (struct file_device *)dev;
34
35 if (fdev->fd >= 0)
36 return -RT_EBUSY;
37
38 /* test and open */
39 fd = open(fdev->filename, O_RDONLY, 0);
40 if (fd >= 0)
41 {
42 close(fd);
43 fd = open(fdev->filename, O_WRONLY | O_APPEND, 0);
44 }
45 else
46 {
47 /* file not exists */
48 fd = open(fdev->filename, O_WRONLY | O_CREAT, 0);
49 }
50 fdev->fd = fd;
51
52 return RT_EOK;
53 }
54
fdevice_close(rt_device_t dev)55 static rt_err_t fdevice_close(rt_device_t dev)
56 {
57 rt_err_t result;
58 struct file_device *fdev = (struct file_device *)dev;
59
60 if (fdev->fd < 0)
61 return -RT_EBUSY;
62
63 result = close(fdev->fd);
64 if (result == 0)
65 {
66 fdev->fd = -1;
67 }
68
69 return result;
70 }
71
fdevice_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)72 static rt_size_t fdevice_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
73 {
74 struct file_device *fdev = (struct file_device *)dev;
75
76 if (fdev->fd < 0)
77 return 0;
78
79 return write(fdev->fd, buffer, size);
80 }
81
fdevice_control(rt_device_t dev,int cmd,void * arg)82 static rt_err_t fdevice_control(rt_device_t dev, int cmd, void *arg)
83 {
84 struct file_device *fdev = (struct file_device *)dev;
85
86 if (fdev->fd < 0)
87 return 0;
88
89 switch (cmd)
90 {
91 case LOG_TRACE_CTRL_FLUSH:
92 if (fsync(fdev->fd) != 0)
93 return RT_ERROR;
94 break;
95 default:
96 break;
97 }
98 return RT_EOK;
99 }
100
101 #ifdef RT_USING_DEVICE_OPS
102 const static struct rt_device_ops log_trace_ops =
103 {
104 RT_NULL,
105 fdevice_open,
106 fdevice_close,
107 RT_NULL,
108 fdevice_write,
109 fdevice_control
110 };
111 #endif
112
log_trace_file_init(const char * filename)113 void log_trace_file_init(const char *filename)
114 {
115 rt_device_t device;
116
117 device = rt_device_find("logfile");
118 if (device == RT_NULL)
119 {
120 rt_memset(&_file_device, 0x00, sizeof(_file_device));
121
122 _file_device.parent.type = RT_Device_Class_Char;
123
124 #ifdef RT_USING_DEVICE_OPS
125 _file_device.parent.ops = &log_trace_ops;
126 #else
127 _file_device.parent.init = RT_NULL;
128 _file_device.parent.open = fdevice_open;
129 _file_device.parent.close = fdevice_close;
130 _file_device.parent.write = fdevice_write;
131 _file_device.parent.control = fdevice_control;
132 #endif
133
134 rt_device_register(&_file_device.parent, "logfile", O_RDWR);
135 }
136
137 _file_device.filename = rt_strdup(filename);
138 _file_device.fd = -1;
139 }
140
log_trace_set_file(const char * filename)141 void log_trace_set_file(const char *filename)
142 {
143 log_trace_file_init(filename);
144 log_trace_set_device("logfile");
145 }
146 #ifdef RT_USING_FINSH
147 #include <finsh.h>
148 FINSH_FUNCTION_EXPORT_ALIAS(log_trace_set_file, log_file, set output filename of log trace);
149 #endif
150
151 #endif /* RT_USING_DFS */
152