]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lib.git/blob - rpp/src/rpp/sdr.c
Compile against the DRV library macro reduced to FREERTOS_POSIX
[pes-rpp/rpp-lib.git] / rpp / src / rpp / sdr.c
1 /* Copyright (C) 2013 Czech Technical University in Prague
2  *
3  * Authors:
4  *     - Carlos Jenkins <carlos@jenkins.co.cr>
5  *
6  * This document contains proprietary information belonging to Czech
7  * Technical University in Prague. Passing on and copying of this
8  * document, and communication of its contents is not permitted
9  * without prior written authorization.
10  *
11  * File : sdr.c
12  * Abstract:
13  *     SD-RAM logging RPP API implementation file.
14  *
15  * References:
16  *     sdr.h
17  *     RPP API documentation.
18  */
19
20
21 #include "rpp/rpp.h"
22 #include <stdio.h>  // vsnprintf()
23 #include <ctype.h>  // isprint()
24 #include <string.h> // strncmp()
25 #include <stdarg.h> // va_start, va_end
26
27 #ifndef FREERTOS_POSIX
28 #include "drv/drv.h"
29 #define echo(x) rpp_sci_putc(x)
30 #else
31 #define echo(x) (void)(x)
32 #endif
33
34 static const char* prompt  = "--> ";
35 static const char* newline = "\r\n";
36
37 // extern this semaphore to wait for cmdproc to exit
38 xSemaphoreHandle rpp_sdr_cmdproc_semaphore;
39
40
41 /// Memory management variables ------------------------------------------------
42 static xSemaphoreHandle memory_mutex;
43 static uint32_t memory_size    = 0;
44 static uint8_t* memory_start   = NULL;
45 static uint8_t* memory_end     = NULL;
46 static uint8_t* memory_current = NULL;
47
48
49
50 /// Tasks control --------------------------------------------------------------
51 // Task handle for command processor task
52 static xTaskHandle cmdproc_handle;
53
54 // Task handle for log show task
55 static xTaskHandle show_handle;
56
57 // Flag the request the tasks to stop
58 static boolean_t stop_tasks = FALSE;
59
60 // Number of tasks running
61 static uint8_t tasks_running = 0;
62
63 // Force context change to other tasks until all
64 // the tasks created by this module are deleted.
65 static void wait_tasks_to_finish()
66 {
67     stop_tasks = TRUE;
68     while(tasks_running > 0) {
69         taskYIELD();
70     }
71     stop_tasks = FALSE;
72 }
73
74
75
76 /// Show log task --------------------------------------------------------------
77 // Semaphore to order the show task to start flushing the log
78 static xSemaphoreHandle show_semaphore;
79
80 // Flag to check if log show task is flushing the log
81 static boolean_t show_flushing = FALSE;
82
83 // Show log task
84 void rpp_sdr_showtask(void *p)
85 {
86     uint8_t* current;
87     uint8_t byte;
88
89     while(!stop_tasks) {
90
91         // Wait semaphore to start
92         if(xSemaphoreTake(show_semaphore, 1) != pdTRUE) {
93             // This will wake up each tick to check if
94             // deletion of this task was requested.
95             continue;
96         }
97         current = memory_start;
98
99         // Iterate until the end of the log
100         while(show_flushing &&
101               (current != memory_current) &&
102               (current < memory_end)) { // Just in case
103
104             // Print characters in this memory location.
105             // Ignores non-printable characters except \r and \n
106             byte = *current;
107             if((byte == '\r') || (byte == '\n') || isprint(byte)) {
108                 rpp_sci_putc(byte);
109             }
110             current++;
111         }
112
113         // If user waited to finish
114         if(show_flushing) {
115             rpp_sci_printf((const char*)"%s", newline);
116             rpp_sci_printf((const char*)"%s", prompt);
117             show_flushing = FALSE;
118         }
119     }
120
121     // Delete myself
122     tasks_running--;
123     vTaskDelete(NULL);
124 }
125
126
127
128 /// Command processor task -----------------------------------------------------
129 #define BUF_SIZE 80
130
131 // Buffer to store incomming command
132 static char in_buffer[BUF_SIZE];
133
134 // SCI log command processor task
135 void rpp_sdr_cmdproc(void *p)
136 {
137     rpp_sci_printf((const char*)
138             "Log control: %dkB available.\r\n",
139             (rpp_sdr_available() / 1024)
140         );
141     rpp_sci_printf((const char*)
142             "===========================================================\r\n"
143         );
144     rpp_sci_printf((const char*)"%s", prompt);
145
146     uint8_t input = 0;
147     uint8_t buff_index = 0;
148     boolean_t flush = FALSE;
149     while(!stop_tasks) {
150
151         // Get one character from the user
152         if(rpp_sci_read_nb(1, &input) != SUCCESS) {
153             if(!stop_tasks) {
154                 vTaskDelay(50 / portTICK_RATE_MS);
155             }
156             continue;
157         }
158
159         // Stop flushing if one character is received
160         if(show_flushing) {
161             rpp_sdr_show(FALSE);
162             vTaskDelay(100 / portTICK_RATE_MS);
163             rpp_sci_printf("%s", newline);
164             rpp_sci_printf("%s", prompt);
165             continue;
166         }
167
168         // Backspace and Delete
169         if(input == 8 || input == 127) {
170             if(buff_index > 0) {
171                 buff_index--;
172                 echo('\b');
173                 echo(' ' );
174                 echo('\b');
175             }
176
177         // Line feed or Carriage return
178         } else if(input == 10 || input == 13) {
179             flush = TRUE;
180             echo('\r');
181             echo('\n');
182
183         // If is any printable character
184         } else if(isprint(input)) {
185
186             // Store character and increment buffer index
187             in_buffer[buff_index] = input;
188             buff_index++;
189             echo(input);
190
191             // Check if buffer is full and force flush
192             if(buff_index == BUF_SIZE - 1) {
193                 flush = TRUE;
194             }
195         }
196         // All other character are ignored
197
198         // Flush buffer
199         if(flush) {
200
201             // Terminate string
202             in_buffer[buff_index] = '\0';
203
204
205             // Re-prompt
206             if(buff_index == 0) {
207                 rpp_sci_printf((const char*)"%s", newline);
208                 rpp_sci_printf((const char*)"%s", prompt);
209
210             // Help command
211             } else if(strncmp(in_buffer, "help", BUF_SIZE) == 0) {
212
213                 rpp_sci_printf((const char*)
214                         "Available commands:\r\n"
215                     );
216                 rpp_sci_printf((const char*)
217                         "\tlog       - Show the log.\r\n"
218                     );
219                 rpp_sci_printf((const char*)
220                         "\tclear     - Clear the log.\r\n"
221                     );
222                 rpp_sci_printf((const char*)
223                         "\tavailable - Display amount of memory left.\r\n"
224                     );
225                 rpp_sci_printf((const char*)
226                         "\texit      - Exit this command processor.\r\n"
227                     );
228
229                 rpp_sci_printf((const char*)"%s", newline);
230                 rpp_sci_printf((const char*)"%s", prompt);
231
232             // Log command
233             } else if(strncmp(in_buffer, "log", BUF_SIZE) == 0) {
234                 rpp_sdr_show(TRUE);
235
236             // Clear command
237             } else if(strncmp(in_buffer, "clear", BUF_SIZE) == 0) {
238                 rpp_sdr_clear();
239                 rpp_sci_printf((const char*)"Done.\r\n");
240                 rpp_sci_printf((const char*)"%s", newline);
241                 rpp_sci_printf((const char*)"%s", prompt);
242
243             // Available command
244             } else if(strncmp(in_buffer, "available", BUF_SIZE) == 0) {
245                 rpp_sci_printf(
246                         (const char*)"%d kB of %d kB available.\r\n",
247                         rpp_sdr_available() / 1024,
248                         memory_size / 1024
249                     );
250                 rpp_sci_printf((const char*)"%s", newline);
251                 rpp_sci_printf((const char*)"%s", prompt);
252
253             // Exit command
254             } else if(strncmp(in_buffer, "exit", BUF_SIZE) == 0) {
255                 xSemaphoreGive(rpp_sdr_cmdproc_semaphore);
256                 tasks_running--;
257                 vTaskDelete(NULL);
258
259             // Unknown command, print buffer back
260             } else {
261                 rpp_sci_printf(
262                         (const char*)"ERROR: Unknown command \"%s\"\r\n",
263                         (char*)&in_buffer);
264                 rpp_sci_printf((const char*)"%s", prompt);
265             }
266
267             // Reset variables
268             rpp_sci_flush(TRUE);
269             buff_index = 0;
270             flush = FALSE;
271         }
272     }
273
274     // Delete myself
275     tasks_running--;
276     vTaskDelete(NULL);
277 }
278
279
280
281 /// Public API -----------------------------------------------------------------
282 // Flag to check if SDR module is initialized
283 static boolean_t initialized = FALSE;
284
285 // Memory for Simulation only
286 #ifdef FREERTOS_POSIX
287 static uint8_t memory_simulation[1024*1024]; // Allocate 1MB for test
288 #endif
289
290 // Initialize SDR module
291 int8_t rpp_sdr_init()
292 {
293     if(initialized) {
294         return FAILURE;
295     }
296     initialized = TRUE;
297
298     // Create memory write mutex
299     memory_mutex = xSemaphoreCreateMutex();
300
301     // Create log show semaphore
302     vSemaphoreCreateBinary(show_semaphore);
303     xSemaphoreTake(show_semaphore, 0);
304
305     // Create semaphore for outer applications to wait cmdproc to exit.
306     // Non static! The symbol should be exported, so use the full prefix.
307     vSemaphoreCreateBinary(rpp_sdr_cmdproc_semaphore);
308     xSemaphoreTake(rpp_sdr_cmdproc_semaphore, 0);
309
310     // Define memory bounds
311 #ifndef FREERTOS_POSIX
312     memory_size    = RPP_SDR_ADDR_END - RPP_SDR_ADDR_START + 1;
313     memory_start   = (uint8_t*)RPP_SDR_ADDR_START;
314     memory_end     = (uint8_t*)RPP_SDR_ADDR_END;
315 #else
316     memory_size    = sizeof(memory_simulation);
317     memory_start   = (uint8_t*)&memory_simulation;
318     memory_end     = (uint8_t*)(memory_start + memory_size - 1);
319 #endif
320     memory_current = memory_start;
321
322     // Low level init
323 #ifndef FREERTOS_POSIX
324     emif_SDRAMInit();
325 #endif
326
327     return SUCCESS;
328 }
329
330
331 // General flag to check if logging is enabled
332 static boolean_t log_enabled = FALSE;
333
334 // Enable/Disable logging
335 int8_t rpp_sdr_setup(boolean_t enable)
336 {
337     // Just in case user ignore everything
338     if(!initialized) {
339         return FAILURE;
340     }
341
342     // No change, ignore
343     if(log_enabled == enable) {
344         return FAILURE;
345     }
346
347     // Shut down is requested
348     if(log_enabled && !enable) {
349         // Stop show task if running
350         rpp_sdr_show(FALSE);
351         // Delete tasks
352         wait_tasks_to_finish();
353         // Disable logging
354         log_enabled = FALSE;
355
356     // Startup is requested
357     } else {
358         if(xTaskCreate(rpp_sdr_showtask,
359                     (const signed char*)"rpp_sdr_showtask",
360                     256, NULL, 2, &show_handle) != pdPASS) {
361             return FAILURE;
362         }
363         tasks_running++;
364
365         if(xTaskCreate(rpp_sdr_cmdproc ,
366                     (const signed char*)"rpp_sdr_cmdproc" ,
367                     512, NULL, 2, &cmdproc_handle) != pdPASS) {
368             wait_tasks_to_finish();
369             return FAILURE;
370         }
371         tasks_running++;
372
373         log_enabled = TRUE;
374     }
375
376     return SUCCESS;
377 }
378
379
380 // Memory available
381 uint32_t rpp_sdr_available()
382 {
383     return (uint32_t)(memory_end - memory_current + 1);
384 }
385
386
387 // Store something to the log, if logging is enabled
388 int32_t rpp_sdr_printf(const char* format, ...)
389 {
390     if(!log_enabled) {
391         return FAILURE;
392     }
393
394     // Don't even try if memory is full
395     if(memory_current == memory_end) {
396         return FAILURE;
397     }
398
399     /// Format user string
400     char str[MAX_BUFFER_LEN];
401     int length = -1;
402
403     va_list argList;
404     va_start(argList, format);
405
406     length = vsnprintf(str, sizeof(str), format, argList);
407
408     va_end(argList);
409
410     if(length < 1) {
411         return length;
412     }
413
414
415     /// Format header
416     // uint32_t max value is 4294967295 (10 digits) + [] + ' ' + '\0' = 14
417     char hdr[14];
418     int hdr_length = -1;
419     hdr_length = sprintf(hdr, (const char*)"[%10d] ", xTaskGetTickCount());
420
421     if(hdr_length < 1) {
422         return hdr_length;
423     }
424
425
426     /// Write header
427     uint32_t cnt = 0;
428     int i = 0;
429     xSemaphoreTake(memory_mutex, portMAX_DELAY);
430     while((memory_current != memory_end) && (i < hdr_length)) {
431
432         *memory_current = hdr[i];
433
434         memory_current++;
435         cnt++;
436         i++;
437     }
438
439
440     /// Write user string
441     i = 0;
442     if(length > sizeof(str)) {
443         length = sizeof(str);
444     }
445     while((memory_current != memory_end) && (i < length)) {
446
447         *memory_current = str[i];
448
449         memory_current++;
450         cnt++;
451         i++;
452     }
453
454     /// Write trailer
455     static const char trl[2] = {'\r', '\n'};
456     i = 0;
457     while((memory_current != memory_end) && (i < sizeof(trl))) {
458
459         *memory_current = trl[i];
460
461         memory_current++;
462         cnt++;
463         i++;
464     }
465
466     xSemaphoreGive(memory_mutex);
467     return cnt;
468 }
469
470
471 // Clears log. Will also stop the show task
472 int8_t rpp_sdr_clear()
473 {
474     if(!log_enabled) {
475         return FAILURE;
476     }
477
478     // Stop log show flushing if running
479     if(show_flushing) {
480         rpp_sdr_show(FALSE);
481     }
482
483     // Check if log is already empty
484     if(memory_current == memory_start) {
485         return FAILURE;
486     }
487
488     // Reset memory pointer
489     memory_current = memory_start;
490
491     return SUCCESS;
492 }
493
494
495 // Starts/Stops the task that sends the log to the SCI
496 int8_t rpp_sdr_show(boolean_t start)
497 {
498     if(!log_enabled) {
499         return FAILURE;
500     }
501
502     // No change, ignore
503     if(start == show_flushing) {
504         return FAILURE;
505     }
506
507     // Log flush stop requested
508     if(show_flushing && !start) {
509         show_flushing = FALSE;
510
511     // Log flush start requested
512     } else {
513         show_flushing = TRUE;
514         xSemaphoreGive(show_semaphore);
515     }
516
517     return SUCCESS;
518 }