-
Notifications
You must be signed in to change notification settings - Fork 1
/
log.ic
228 lines (197 loc) · 6.95 KB
/
log.ic
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/**
* @file log.ic
* @brief Logging code.
* @author Andrew Krieger
* @date 4/25/2011
*
* This code lets us log events on our Handy Board.
* Events are stored as one byte IDs.
* Events are divided into the null event, normal events, and extended events.
* The null event is used as a placeholder. If you try to log it, it will be ignored.
* Normal events only store their one byte ID.
* Extended events store their ID and a one byte argument.
* Any event with ID >= EV_EXTENDED is considered extended.
* (Please don't make EV_NULL >= EV_EXTENDED, or this code will probably malfunction)
*/
//Link utility functions
#use "util.ic"
///the size of the log buffer
#define LOG_BUFFER_SZ 256
///The null event - used as an empty space
#define EV_NULL 0x00
///All events >= EV_EXTENDED are extended events
#define EV_EXTENDED 0x80
//Sample events - please overwrite
#define EV_SAMPLE_1 0x01
#define EV_SAMPLE_2 0x02
#define EV_SAMPLE_3 0x24
#define EV_SAMPLE_EXT_1 0x80
#define EV_SAMPLE_EXT_2 0xBE
///Circular buffer for events
persistent char log_buffer[LOG_BUFFER_SZ];
///Insertion point in circular buffer
persistent int log_buffer_ins;
/*
* Circular buffer functions.
* The buffer only has one index, used as both a read and write point.
* The first datum to be read is the one immediately after the index.
* When reading data, NULL bytes are skipped.
* When writing data, the id being overwritten is checked.
* If it's an extended event, so we also clear its argument byte to NULL.
* That way, the next read or write will happily ignore it.
* If it's a normal event, then we just overwrite it.
* Writing moves the insertion point forward.
* Reads are handled bu read_logs. It's ugly, but I don't see any reason
* to add a general-purose read function.
* See http://en.wikipedia.org/wiki/Circular_buffer for more information about circular buffers.
*/
/**
* @brief Clear the log buffer.
*
* Deletes all events currently in the buffer, and reinitializes the buffer.
* This is called at the end of init_log, so there usually isn't a reason
* to call it directly.
*/
void clear_log_buffer(void) {
int i;
for(i=0;i<LOG_BUFFER_SZ; ++i)
log_buffer[i] = EV_NULL;
log_buffer_ins = 0;
}
/**
* @brief Low level routine to write a byte to the log buffer.
* @param b The byte to write.
*
* Add a single byte to the log buffer.
* Doesn't handle writing extended events differently - just writes a byte.
* Does handle overwrites of extended events properly. So, if it overwrites
* an extended event, it will also overwrite its argument to EV_NULL.
*/
void add_to_log_buffer(int b) {
if(log_buffer[log_buffer_ins] >= EV_EXTENDED)
//extended event. Overwrite the argument byte with EV_NULL.
log_buffer[(log_buffer_ins + 1) % LOG_BUFFER_SZ] = EV_NULL;
log_buffer[log_buffer_ins] = b;
log_buffer_ins = (log_buffer_ins + 1) % LOG_BUFFER_SZ;
}
/**
* @brief Show logs on the LCD.
*
* Actually print the logs to the screen.
* This is meant to be used by @ref init_log; there's no reason
* to call this directly.
*/
/*
* Warning: heavy wizardry begins here
* Any time you see something like "i = (i+1) % LOG_BUFFER_SZ;",
* that is advancing i to the next spot in the circular buffer
*/
void read_logs(void) {
int n_events;
int curr_event;
int i;
int button;
int arg;
//Count number of actual events
n_events = 0;
for(i = (log_buffer_ins + 1) % LOG_BUFFER_SZ; i != log_buffer_ins; i = (i+1) % LOG_BUFFER_SZ) {
//Is this a real event (ie, not EV_NULL) ?
if(log_buffer[i] != EV_NULL) {
//Yes, count it
++n_events;
if(log_buffer[i] >= EV_EXTENDED) {
//Skip the argument byte if it's extended
i = (i+1) % LOG_BUFFER_SZ;
//Make sure to stop if we end on an extended argument
//Without this, a misformed event log can cause an infinite loop
if(i == log_buffer_ins)
break;
}
}
}
//catch the special case of an empty event log
if(n_events == 0) {
printf("No events in log\n");
while(!stop_button())
;
return;
}
//The curr_event counter is just for the user's convenience - the code doesn't use it
curr_event = 0;
//Find first event
i = (log_buffer_ins + 1) % LOG_BUFFER_SZ;
while(log_buffer[i] == EV_NULL)
i = (i+1) % LOG_BUFFER_SZ;
for(;;) {
//Is this an extended event?
if(log_buffer[i] >= EV_EXTENDED) {
//Yes; print it and its argument
//Format: "E:XX A:XX (DDD) "
arg = log_buffer[(i+1) % LOG_BUFFER_SZ];
printf("E:");
print_hex_byte(log_buffer[i]);
printf(" A:");
print_hex_byte(arg);
printf(" (%d) ", arg);
if(arg < 100) printf(" ");
if(arg < 10) printf(" ");
} else {
//No; only print the event
//Format: "E:XX "
printf("E:");
print_hex_byte(log_buffer[i]);
printf(" ");
}
//Display event number
printf("%d/%d\n", curr_event+1, n_events);
//Wait for a button press
button = press_button();
if(button == BUTTON_STOP)
//Stop reading logs
return;
//Otherwise user pressed start; go to next entry
//Update the current event counter - this is just for the user's benefit; this code doesn't use it
curr_event = (curr_event+1) % n_events;
//Actually go to the next event (or loop back to this one if it's the only one)
//Skip argument if this is extended
if(log_buffer[i] >= EV_EXTENDED)
i = (i+1) % LOG_BUFFER_SZ;
//Go to next event
i = (i+1) % LOG_BUFFER_SZ;
//Skip any null events
while(log_buffer[i] == EV_NULL)
i = (i+1) % LOG_BUFFER_SZ;
}
}
/**
* @brief Prompt the user to read the logs, then clear the buffer.
*
* Main entry point. Call this on Handy Board startup or reset.
* Optionally displays the logs to the user using @ref read_logs.
* Either way, resets logs at the end.
*/
void init_log(void) {
int choice;
printf("START to see logSTOP to skip\n");
choice = press_button();
if(choice == BUTTON_START)
read_logs();
//Reset the circular buffer
clear_log_buffer();
}
/**
* @brief Log an event, optionally with an argument.
* @param ev The event to log.
* @param arg The event's argument (ignored if it's not an extended event).
*
* The actual logging function.
* If the event is a normal (non-extended) event, the second argument is ignored.
* If it's an extended event, the second argument becomes the event argument.
*/
void log_event(int ev, int arg) {
if(ev == EV_NULL)
return;
add_to_log_buffer(ev);
if(ev >= EV_EXTENDED)
add_to_log_buffer(arg);
}