Line data Source code
1 : /* Copyright 2017 noseglasses <shinynoseglasses@gmail.com>
2 : *
3 : * This program is free software: you can redistribute it and/or modify
4 : * it under the terms of the GNU Lesser General Public License as published by
5 : * the Free Software Foundation, either version 3 of the License, or
6 : * (at your option) any later version.
7 : *
8 : * This program is distributed in the hope that it will be useful,
9 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 : * GNU Lesser General Public License for more details.
12 : *
13 : * You should have received a copy of the GNU Lesser General Public License
14 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 : */
16 :
17 : #include "papageno_char_strings.h"
18 :
19 : #include <stdio.h>
20 : #include <string.h>
21 :
22 : #ifdef __AVR__
23 :
24 : // The following has been taken from the tmk and qmk projects
25 :
26 : #include <stdint.h>
27 :
28 : #ifndef TIMER_PRESCALER
29 : # if F_CPU > 16000000
30 : # define TIMER_PRESCALER 256
31 : # elif F_CPU > 2000000
32 : # define TIMER_PRESCALER 64
33 : # elif F_CPU > 250000
34 : # define TIMER_PRESCALER 8
35 : # else
36 : # define TIMER_PRESCALER 1
37 : # endif
38 : #endif
39 : #define TIMER_RAW_FREQ (F_CPU/TIMER_PRESCALER)
40 : #define TIMER_RAW TCNT0
41 : #define TIMER_RAW_TOP (TIMER_RAW_FREQ/1000)
42 :
43 : #if (TIMER_RAW_TOP > 255)
44 : # error "Timer0 can't count 1ms at this clock freq. Use larger prescaler."
45 : #endif
46 :
47 : #define TIMER_DIFF(a, b, max) ((a) >= (b) ? (a) - (b) : (max) - (b) + (a))
48 : #define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX)
49 : #define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX)
50 : #define TIMER_DIFF_32(a, b) TIMER_DIFF(a, b, UINT32_MAX)
51 : #define TIMER_DIFF_RAW(a, b) TIMER_DIFF_8(a, b)
52 :
53 : static uint32_t current_time = 0;
54 :
55 : void timer_init(void) {current_time = 0;}
56 :
57 : void timer_clear(void) {current_time = 0;}
58 :
59 : uint16_t timer_read(void) { return current_time & 0xFFFF; }
60 : uint32_t timer_read32(void) { return current_time; }
61 : uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); }
62 : uint32_t timer_elapsed32(uint32_t last) { return TIMER_DIFF_32(timer_read32(), last); }
63 :
64 : void set_time(uint32_t t) { current_time = t; }
65 : void advance_time(uint32_t ms) { current_time += ms; }
66 :
67 : void wait_ms(uint32_t ms) {
68 : advance_time(ms);
69 : }
70 : #else
71 :
72 : #include <sys/timeb.h>
73 : #include <unistd.h>
74 : #endif
75 :
76 : int ppg_cs_exceptions = PPG_CS_Action_Exception_None;
77 :
78 : #ifdef __AVR__
79 : static uint32_t ppg_cs_timeout_ms = 0;
80 : static uint32_t ppg_cs_start_time_ms = 0;
81 : #else
82 : static long unsigned ppg_cs_timeout_ms = 0;
83 : static long unsigned ppg_cs_start_time_s = 0;
84 : static long unsigned ppg_cs_start_time_ms = 0;
85 : #endif
86 :
87 : static bool ppg_cs_test_success = true;
88 :
89 : static char ppg_cs_flush_buffer[256];
90 : static int ppg_cs_cur_flush_pos = 0;
91 :
92 : static PPG_CS_Action_Expectation ppg_cs_action_expectation_queue[256];
93 : static int ppg_cs_n_actions = 0;
94 :
95 : #define MMG_MAX_ACTION_NAMES 100
96 : static char *ppg_cs_action_names[MMG_MAX_ACTION_NAMES];
97 : static int ppg_cs_next_action_id = 0;
98 :
99 40 : void ppg_cs_init(void)
100 : {
101 40 : ppg_cs_exceptions = PPG_CS_Action_Exception_None;
102 :
103 40 : ppg_cs_timeout_ms = 0;
104 :
105 : #ifndef __AVR__
106 40 : ppg_cs_start_time_s = 0;
107 : #endif
108 40 : ppg_cs_start_time_ms = 0;
109 :
110 40 : ppg_cs_test_success = true;
111 :
112 40 : ppg_cs_cur_flush_pos = 0;
113 :
114 40 : ppg_cs_n_actions = 0;
115 :
116 40 : ppg_cs_next_action_id = 0;
117 40 : }
118 :
119 242 : int ppg_cs_register_action(char *action_name)
120 : {
121 242 : ppg_cs_action_names[ppg_cs_next_action_id] = action_name;
122 242 : return ppg_cs_next_action_id++;
123 : }
124 :
125 170 : char *ppg_cs_get_action_name(int action_id)
126 : {
127 170 : if( (action_id < 0)
128 170 : || (action_id >= ppg_cs_next_action_id)) {
129 0 : return NULL;
130 : }
131 :
132 170 : return ppg_cs_action_names[action_id];
133 : }
134 :
135 32 : static void ppg_cs_store_start_time(void)
136 : {
137 : #ifdef __AVR__
138 : ppg_cs_start_time_ms = timer_read32();
139 : #else
140 : struct timeb a_timeb;
141 :
142 32 : ftime(&a_timeb);
143 :
144 32 : ppg_cs_start_time_s = a_timeb.time;
145 32 : ppg_cs_start_time_ms = a_timeb.millitm;
146 : #endif
147 32 : }
148 :
149 2008 : static long unsigned ppg_cs_run_time_ms(void)
150 : {
151 : #ifdef __AVR__
152 : return timer_read32() - ppg_cs_start_time_ms;
153 : #else
154 : struct timeb a_timeb;
155 :
156 2008 : ftime(&a_timeb);
157 :
158 2008 : return (a_timeb.time - ppg_cs_start_time_s)*1000 + a_timeb.millitm - ppg_cs_start_time_ms;
159 : #endif
160 : }
161 :
162 107 : void ppg_cs_reset_testing_environment(void)
163 : {
164 107 : ppg_cs_exceptions = PPG_CS_Action_Exception_None;
165 107 : ppg_cs_cur_flush_pos = 0;
166 107 : ppg_cs_test_success = true;
167 107 : ppg_cs_n_actions = 0;
168 107 : }
169 :
170 327 : void ppg_cs_process_event_callback(
171 : PPG_Event *event,
172 : void *user_data)
173 : {
174 : // Ignore events that were considered
175 : //
176 327 : if(event->flags & PPG_Event_Considered) { return; }
177 :
178 104 : char the_char = (char)(uintptr_t)event->input;
179 :
180 104 : if((uintptr_t)event->flags & PPG_Event_Active) {
181 54 : the_char = toupper(the_char);
182 : }
183 :
184 104 : ppg_cs_flush_buffer[ppg_cs_cur_flush_pos] = the_char;
185 104 : ++ppg_cs_cur_flush_pos;
186 :
187 : // PPG_LOG("%c", the_char);
188 : }
189 :
190 0 : void ppg_cs_list_flush_buffer(void)
191 : {
192 0 : PPG_LOG("Flushed: \'%s\'\n", ppg_cs_flush_buffer);
193 0 : }
194 :
195 256 : void ppg_cs_flush_events(void)
196 : {
197 256 : ppg_event_buffer_iterate(
198 : ppg_cs_process_event_callback,
199 : NULL
200 : );
201 256 : }
202 :
203 170 : void ppg_cs_process_action(bool activation, void *user_data) {
204 :
205 170 : PPG_Count action_id = *((uintptr_t*)&user_data);
206 :
207 170 : PPG_LOG("***** Action: %s\n", ppg_cs_action_names[action_id]);
208 :
209 170 : ppg_cs_action_expectation_queue[ppg_cs_n_actions]
210 170 : = (PPG_CS_Action_Expectation) {
211 : .action_id = action_id,
212 : .activated = activation
213 : };
214 :
215 170 : ++ppg_cs_n_actions;
216 170 : }
217 :
218 621 : static void ppg_cs_break(void) {
219 :
220 621 : PPG_LOG("\n");
221 621 : }
222 :
223 2109 : void ppg_cs_separator(void) {
224 :
225 2109 : PPG_LOG("***************************************************************************\n");
226 2109 : }
227 :
228 : // inline
229 : // static int my_isalpha_lower(int c) {
230 : // return ((c >= 'a' && c <= 'z')); }
231 :
232 : inline
233 1572 : static int my_isalpha_upper(int c) {
234 1572 : return ((c >= 'A' && c <= 'Z')); }
235 :
236 786 : void ppg_cs_process_event(char the_char)
237 : {
238 786 : if(!isalpha(the_char)) { return; }
239 :
240 786 : char lower_char = tolower(the_char);
241 :
242 786 : PPG_LOG("\n");
243 786 : ppg_cs_separator();
244 786 : PPG_LOG("Sending char %c, active: %d\n", the_char, my_isalpha_upper(the_char));
245 786 : ppg_cs_separator();
246 :
247 2358 : PPG_Event event = {
248 786 : .input = (PPG_Input_Id)(uintptr_t)lower_char,
249 786 : .time = (PPG_Time)ppg_cs_run_time_ms(),
250 786 : .flags = (my_isalpha_upper(the_char)) ? PPG_Event_Active : PPG_Event_Flags_Empty
251 : };
252 :
253 786 : ppg_event_process(&event);
254 : }
255 :
256 1137 : bool ppg_cs_check_and_process_control_char(char c)
257 : {
258 1137 : bool is_control_char = true;
259 :
260 1137 : switch(c) {
261 : case PPG_CS_CC_Short_Delay:
262 : {
263 : #ifdef __AVR__
264 : wait_ms(ppg_cs_timeout_ms);
265 : PPG_LOG("Short delay: %lu\n", ppg_cs_timeout_ms);
266 : #else
267 0 : int microseconds = (int)((double)ppg_cs_timeout_ms*0.3*1000);
268 0 : PPG_LOG("Short delay: %d\n", microseconds);
269 0 : usleep(microseconds);
270 : #endif
271 : }
272 0 : break;
273 :
274 : case PPG_CS_CC_Long_Delay:
275 : {
276 : #ifdef __AVR__
277 : wait_ms(ppg_cs_timeout_ms*3);
278 : PPG_LOG("Long delay: %lu\n", ppg_cs_timeout_ms*3);
279 : #else
280 28 : int microseconds = (int)((double)ppg_cs_timeout_ms*3*1000);
281 28 : PPG_LOG("Long delay: %d\n", microseconds);
282 28 : usleep(microseconds);
283 : #endif
284 : }
285 28 : break;
286 : case PPG_CS_CC_Noop:
287 452 : break;
288 : default:
289 657 : is_control_char = false;
290 657 : break;
291 : }
292 :
293 1137 : return is_control_char;
294 : }
295 :
296 63 : void ppg_cs_process_string(char *string)
297 : {
298 63 : ppg_cs_break();
299 63 : ppg_cs_separator();
300 63 : PPG_LOG("Sending control string \"%s\"\n", string);
301 63 : ppg_cs_separator();
302 :
303 63 : int i = 0;
304 1015 : while(string[i] != '\0') {
305 :
306 889 : if(!ppg_cs_check_and_process_control_char(string[i])) {
307 528 : ppg_cs_process_event(string[i]);
308 : }
309 889 : ++i;
310 : }
311 63 : }
312 :
313 42 : void ppg_cs_process_on_off(char *string)
314 : {
315 42 : ppg_cs_break();
316 42 : ppg_cs_separator();
317 42 : PPG_LOG("Sending control string \"%s\" in on-off mode\n", string);
318 42 : ppg_cs_separator();
319 :
320 42 : int i = 0;
321 332 : while(string[i] != '\0') {
322 :
323 248 : if(!ppg_cs_check_and_process_control_char(string[i])) {
324 129 : ppg_cs_process_event(toupper(string[i]));
325 129 : ppg_cs_process_event(tolower(string[i]));
326 : }
327 248 : ++i;
328 : }
329 42 : }
330 :
331 1222 : void ppg_cs_time(PPG_Time *time)
332 : {
333 1222 : *time = ppg_cs_run_time_ms();
334 :
335 : // PPG_LOG("time [ms]: %ld\n", *time);
336 1222 : }
337 :
338 442 : void ppg_cs_time_difference(PPG_Time time1, PPG_Time time2, PPG_Time *delta)
339 : {
340 442 : *delta = time2 - time1;
341 442 : }
342 :
343 442 : int8_t ppg_cs_time_comparison(
344 : PPG_Time time1,
345 : PPG_Time time2)
346 : {
347 442 : if(time1 > time2) {
348 15 : return 1;
349 : }
350 :
351 427 : if(time1 == time2) {
352 0 : return 0;
353 : }
354 :
355 427 : return -1;
356 : }
357 :
358 41 : void ppg_cs_set_timeout_ms(long unsigned timeout_ms)
359 : {
360 41 : ppg_cs_timeout_ms = timeout_ms;
361 41 : ppg_global_set_timeout((PPG_Time)timeout_ms);
362 41 : }
363 :
364 0 : int ppg_cs_get_timeout_ms(void)
365 : {
366 0 : return ppg_cs_timeout_ms;
367 : }
368 :
369 32 : void ppg_cs_compile(void)
370 : {
371 : // Store the start time as a reference
372 : //
373 32 : ppg_cs_store_start_time();
374 :
375 32 : ppg_global_compile();
376 :
377 32 : PPG_PATTERN_PRINT_TREE
378 32 : }
379 :
380 298 : void ppg_cs_on_signal(
381 : uint8_t slot_id,
382 : void *user_data)
383 : {
384 : // PPG_LOG("Slot id: %d\n", slot_id);
385 :
386 298 : ppg_cs_break();
387 :
388 298 : switch(slot_id) {
389 : case PPG_On_Abort:
390 4 : PPG_LOG("# Registering abortion\n");
391 4 : ppg_cs_exceptions |= PPG_CS_Action_Exception_Aborted;
392 4 : ppg_cs_flush_events();
393 4 : break;
394 : case PPG_On_Timeout:
395 15 : PPG_LOG("# Registering timeout\n");
396 15 : ppg_cs_exceptions |= PPG_CS_Action_Exception_Timeout;
397 15 : ppg_cs_flush_events();
398 15 : break;
399 : case PPG_On_Match_Failed:
400 42 : PPG_LOG("# Registering match failed\n");
401 42 : ppg_cs_exceptions |= PPG_CS_Action_Exception_Match_Failed;
402 42 : break;
403 : case PPG_On_Flush_Events:
404 237 : PPG_LOG("# Registering flush events\n");
405 237 : ppg_cs_flush_events();
406 237 : break;
407 : }
408 298 : }
409 :
410 109 : void ppg_cs_check_test_results(uint8_t expected)
411 : {
412 109 : ppg_cs_break();
413 :
414 109 : if(ppg_cs_exceptions != (expected)) {
415 0 : PPG_LOG("! Exception state mismatch\n");
416 :
417 0 : ppg_cs_test_success = false;
418 : }
419 : else {
420 109 : PPG_LOG("Exception state verified\n");
421 : }
422 :
423 109 : PPG_LOG(" aborted: expected: %d, actual: %d\n",
424 : ((expected) & PPG_CS_Action_Exception_Aborted),
425 : (ppg_cs_exceptions & PPG_CS_Action_Exception_Aborted));
426 :
427 109 : PPG_LOG(" timeout: expected: %d, actual: %d\n",
428 : ((expected) & PPG_CS_Action_Exception_Timeout),
429 : (ppg_cs_exceptions & PPG_CS_Action_Exception_Timeout)
430 : );
431 :
432 109 : PPG_LOG(" match failed: expected: %d, actual: %d\n",
433 : ((expected) & PPG_CS_Action_Exception_Match_Failed),
434 : (ppg_cs_exceptions & PPG_CS_Action_Exception_Match_Failed)
435 : );
436 :
437 109 : ppg_token_list_all_active();
438 109 : }
439 :
440 109 : void ppg_cs_check_flushed(char *expected)
441 : {
442 109 : ppg_cs_flush_buffer[ppg_cs_cur_flush_pos] = '\0';
443 109 : ++ppg_cs_cur_flush_pos;
444 :
445 109 : if(strcmp(ppg_cs_flush_buffer, expected)) {
446 0 : PPG_LOG("! Flush buffer mismatch\n");
447 0 : PPG_LOG(" expected: \'%s\'\n", expected);
448 0 : PPG_LOG(" actual: \'%s\'\n", ppg_cs_flush_buffer);
449 :
450 0 : ppg_cs_test_success = false;
451 : }
452 : else {
453 109 : PPG_LOG("Flush buffer test successfully passed (\'%s\')\n", expected);
454 : }
455 109 : }
456 :
457 105 : void ppg_cs_output_test_info(char *file, int line)
458 : {
459 105 : PPG_LOG("Next test at %s: %d\n", file, line);
460 105 : }
461 :
462 109 : void ppg_cs_check_test_success(char *file, int line)
463 : {
464 109 : if(!ppg_cs_test_success) {
465 0 : PPG_LOG("! %s: %d\n", file, line);
466 0 : PPG_LOG("Test failed. Aborting.\n");
467 :
468 : #ifdef __AVR__
469 : printf("__PAPAGENO_TEST_FAILED__\n");
470 : #endif
471 0 : abort();
472 : }
473 : else {
474 109 : PPG_LOG("All assertions passed.\n");
475 : }
476 109 : }
477 :
478 109 : void ppg_cs_check_action_series(int n_actions,
479 : PPG_CS_Action_Expectation* expected)
480 : {
481 109 : ppg_cs_break();
482 :
483 109 : bool n_actions_ok = true;
484 109 : bool actions_test_success = true;
485 :
486 109 : if(n_actions < ppg_cs_n_actions) {
487 0 : PPG_LOG("! There occurred more actions than expected\n");
488 0 : n_actions_ok = false;
489 : }
490 109 : else if(n_actions > ppg_cs_n_actions) {
491 0 : PPG_LOG("! There occurred less actions than expected\n");
492 0 : n_actions_ok = false;
493 : }
494 : else {
495 279 : for(int i = 0; i < ppg_cs_n_actions; ++i) {
496 340 : if( (ppg_cs_action_expectation_queue[i].action_id
497 170 : != expected[i].action_id)
498 340 : || (ppg_cs_action_expectation_queue[i].activated
499 170 : != expected[i].activated))
500 : {
501 0 : PPG_LOG("! Action mismatch of action %d\n", i);
502 0 : PPG_LOG(" expected: %s, activated: %d\n",
503 : ppg_cs_get_action_name(expected[i].action_id),
504 : expected[i].activated
505 : );
506 0 : PPG_LOG(" actual: %s, activated: %d\n",
507 : ppg_cs_get_action_name(
508 : ppg_cs_action_expectation_queue[i].action_id),
509 : ppg_cs_action_expectation_queue[i].activated
510 : );
511 :
512 0 : actions_test_success = false;
513 : }
514 : }
515 : }
516 :
517 109 : actions_test_success = (actions_test_success && n_actions_ok);
518 :
519 109 : if(!n_actions_ok) {
520 0 : PPG_LOG("expected:\n");
521 :
522 0 : for(int i = 0; i < n_actions; ++i) {
523 0 : PPG_LOG(" %s, activated: %d\n",
524 : ppg_cs_get_action_name(expected[i].action_id),
525 : expected[i].activated
526 : );
527 : }
528 :
529 0 : PPG_LOG("occurred:\n");
530 :
531 0 : for(int i = 0; i < ppg_cs_n_actions; ++i) {
532 0 : PPG_LOG(" %s, activated: %d\n",
533 : ppg_cs_get_action_name(
534 : ppg_cs_action_expectation_queue[i].action_id),
535 : ppg_cs_action_expectation_queue[i].activated
536 : );
537 : }
538 : }
539 :
540 109 : if(actions_test_success) {
541 109 : PPG_LOG("Actions test successfully passed\n");
542 279 : for(int i = 0; i < n_actions; ++i) {
543 170 : PPG_LOG(" %s, activated: %d\n",
544 : ppg_cs_get_action_name(expected[i].action_id),
545 : expected[i].activated);
546 : }
547 : }
548 : else {
549 0 : ppg_cs_test_success = false;
550 : }
551 109 : }
552 :
553 8 : void ppg_cs_event_char_callback(
554 : PPG_Event *event,
555 : void *user_data)
556 : {
557 8 : char the_char = (char)(uintptr_t)event->input;
558 :
559 8 : if((uintptr_t)event->flags & PPG_Event_Active) {
560 4 : the_char = toupper(the_char);
561 : }
562 : else {
563 4 : the_char = tolower(the_char);
564 : }
565 :
566 8 : PPG_LOG("%c", the_char);
567 8 : }
568 :
569 8 : void ppg_cs_event_considered_callback(
570 : PPG_Event *event,
571 : void *user_data)
572 : {
573 : #if PPG_HAVE_LOGGING
574 8 : char c_char = 0;
575 :
576 8 : if(event->flags & PPG_Event_Considered) {
577 0 : c_char = '+';
578 : }
579 : else {
580 8 : c_char = '-';
581 : }
582 :
583 8 : PPG_LOG("%c", c_char);
584 : #endif
585 8 : }
586 :
587 109 : void ppg_cs_list_event_queue(void)
588 : {
589 109 : PPG_LOG("\nEvent queue:\n");
590 :
591 109 : PPG_LOG(" \'");
592 :
593 109 : ppg_event_buffer_iterate((PPG_Event_Processor_Fun)ppg_cs_event_char_callback,
594 : NULL);
595 :
596 109 : PPG_LOG("\'\n");
597 :
598 109 : PPG_LOG(" ");
599 :
600 109 : ppg_event_buffer_iterate((PPG_Event_Processor_Fun)ppg_cs_event_considered_callback,
601 : NULL);
602 109 : PPG_LOG("\n");
603 109 : }
|