-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmbser_log.c
188 lines (152 loc) · 3.43 KB
/
mbser_log.c
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/**
* Log Interface based on mailbox serial channel
*
* Copyright 2013 Innofidei Inc.
*
* @file
* @brief
* log output system
*
* @author: jimmy.li <[email protected]>
* @date: 2013-04-10
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
#include <cyg/kernel/kapi.h>
#include <mf_comn.h>
#include <mf_mbserial.h>
#include <mf_thread.h>
#include <libmf.h>
/* TODO : when can print, free log buffer to save memory */
#define LOG_BUFSZ (4096)
static char *log_buf;
static mbserial_t channel;
static cyg_mutex_t lock;
static int can_print;
#define LOG_BUF_MASK (LOG_BUFSZ - 1)
#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
static unsigned log_start; /* index to log_buf: next char to be read */
static unsigned log_end; /* index to log_buf: most-recently-written-char + 1 */
static void flush_log_buf(void)
{
unsigned start, end, boundary;
for (;;) {
cyg_mutex_lock(&lock);
if (log_start == log_end) {
cyg_mutex_unlock(&lock);
//nothing to print
break;
}
start = log_start;
end = log_end;
log_start = log_end; /* flush */
/*
* the ranage between start and end may cross the buffer boundary, so find
* the boundary firstly, and then output two part buffer
*/
boundary = _ALIGN_UP(start, LOG_BUFSZ);
if (boundary < end) {
mf_mbserial_send(channel, (void *)(&LOG_BUF(start)), boundary - start);
mf_mbserial_send(channel, (void *)(&LOG_BUF(boundary)), end - boundary);
} else {
mf_mbserial_send(channel, (void *)(&LOG_BUF(start)), end - start);
}
cyg_mutex_unlock(&lock);
}
}
static void emit_log_char(char c)
{
LOG_BUF(log_end) = c;
log_end++;
if (log_end - log_start > LOG_BUFSZ)
log_start = log_end - LOG_BUFSZ;
}
static int cache_log_buf(const char *buf, int len)
{
int i;
cyg_mutex_lock(&lock);
for (i=0; i<len; i++) {
emit_log_char(buf[i]);
}
cyg_mutex_unlock(&lock);
return len;
}
/**
* @brief output log buffer
*
* @param[in] buf : log buffer
* @param[in] len : log buffer length
*
* @return : actual length sent
*/
MF_API int mf_LogSend(const char* buf, int len)
{
int ret = 0;
if (can_print) {
ret = mf_mbserial_send(channel, (void*)buf, len);
} else {
ret = cache_log_buf((const char*)buf, len);
}
return ret;
}
/**
* @brief format output
*
* @param[in] fmt : format string, like printf().
*
* @return : void
*/
MF_API void mf_LogPrintf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
mf_LogvPrintf(fmt, ap);
va_end(ap);
}
/**
* @brief format output
*
* @param[in] fmt : format string, like vprintf().
*
* @return : void
*/
MF_API void mf_LogvPrintf(const char *fmt, va_list ap)
{
int n;
char buf[128];
n = vsnprintf(buf, sizeof(buf), fmt, ap);
mf_LogSend(buf, n);
}
static int log_mbserial_notifier(struct mf_notifier_block *nb, unsigned long action, void *data, int len)
{
switch (action) {
case MBSERIAL_EVENT_STARTUP:
flush_log_buf();
can_print = 1;
break;
case MBSERIAL_EVENT_SHUTDOWN:
can_print = 0;
break;
default:
break;
}
return 0;
}
static struct mf_notifier_block log_notifier = {
.notifier_call = log_mbserial_notifier,
};
MF_SYSINIT int mf_log_init(mf_gd_t *gd)
{
cyg_mutex_init(&lock);
log_buf = (char*)malloc(LOG_BUFSZ);
if (log_buf == NULL)
return -1;
channel = mf_mbserial_get(gd->log_mbser_line, &log_notifier);
if (channel == MBSERIAL_INVALID)
return -1;
return 0;
}