]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lib.git/blob - rpp/src/rpp/sdr.c
Add SPI into RPP layer
[pes-rpp/rpp-lib.git] / rpp / src / rpp / sdr.c
1 /* Copyright (C) 2013, 2014, 2015 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         stop_tasks = FALSE;
71 }
72
73
74
75 /// Show log task --------------------------------------------------------------
76 // Semaphore to order the show task to start flushing the log
77 static xSemaphoreHandle show_semaphore;
78
79 // Flag to check if log show task is flushing the log
80 static boolean_t show_flushing = FALSE;
81
82 // Show log task
83 void rpp_sdr_showtask(void *p)
84 {
85         uint8_t *current;
86         uint8_t byte;
87
88         while (!stop_tasks) {
89
90                 // Wait semaphore to start
91                 if (xSemaphoreTake(show_semaphore, 1) != pdTRUE)
92                         // This will wake up each tick to check if
93                         // deletion of this task was requested.
94                         continue;
95                 current = memory_start;
96
97                 // Iterate until the end of the log
98                 while (show_flushing &&
99                            (current != memory_current) &&
100                            (current < memory_end)) { // Just in case
101
102                         // Print characters in this memory location.
103                         // Ignores non-printable characters except \r and \n
104                         byte = *current;
105                         if ((byte == '\r') || (byte == '\n') || isprint(byte))
106                                 rpp_sci_putc(byte);
107                         current++;
108                 }
109
110                 // If user waited to finish
111                 if (show_flushing) {
112                         rpp_sci_printf((const char *)"%s", newline);
113                         rpp_sci_printf((const char *)"%s", prompt);
114                         show_flushing = FALSE;
115                 }
116         }
117
118         // Delete myself
119         tasks_running--;
120         vTaskDelete(NULL);
121 }
122
123
124
125 /// Command processor task -----------------------------------------------------
126 #define BUF_SIZE 80
127
128 // Buffer to store incomming command
129 static char in_buffer[BUF_SIZE];
130
131 // SCI log command processor task
132 void rpp_sdr_cmdproc(void *p)
133 {
134         rpp_sci_printf((const char *)
135                                    "Log control: %dkB available.\r\n",
136                                    (rpp_sdr_available() / 1024)
137                                    );
138         rpp_sci_printf((const char *)
139                                    "===========================================================\r\n"
140                                    );
141         rpp_sci_printf((const char *)"%s", prompt);
142
143         uint8_t input = 0;
144         uint8_t buff_index = 0;
145         boolean_t flush = FALSE;
146         while (!stop_tasks) {
147
148                 // Get one character from the user
149                 if (rpp_sci_read_nb(1, &input) != SUCCESS) {
150                         if (!stop_tasks)
151                                 vTaskDelay(50 / portTICK_RATE_MS);
152                         continue;
153                 }
154
155                 // Stop flushing if one character is received
156                 if (show_flushing) {
157                         rpp_sdr_show(FALSE);
158                         vTaskDelay(100 / portTICK_RATE_MS);
159                         rpp_sci_printf("%s", newline);
160                         rpp_sci_printf("%s", prompt);
161                         continue;
162                 }
163
164                 // Backspace and Delete
165                 if (input == 8 || input == 127) {
166                         if (buff_index > 0) {
167                                 buff_index--;
168                                 echo('\b');
169                                 echo(' ' );
170                                 echo('\b');
171                         }
172
173                         // Line feed or Carriage return
174                 }
175                 else if (input == 10 || input == 13) {
176                         flush = TRUE;
177                         echo('\r');
178                         echo('\n');
179
180                         // If is any printable character
181                 }
182                 else if (isprint(input)) {
183
184                         // Store character and increment buffer index
185                         in_buffer[buff_index] = input;
186                         buff_index++;
187                         echo(input);
188
189                         // Check if buffer is full and force flush
190                         if (buff_index == BUF_SIZE - 1)
191                                 flush = TRUE;
192                 }
193                 // All other character are ignored
194
195                 // Flush buffer
196                 if (flush) {
197
198                         // Terminate string
199                         in_buffer[buff_index] = '\0';
200
201
202                         // Re-prompt
203                         if (buff_index == 0) {
204                                 rpp_sci_printf((const char *)"%s", newline);
205                                 rpp_sci_printf((const char *)"%s", prompt);
206
207                         }
208                         // Help command
209                         else if (strncmp(in_buffer, "help", BUF_SIZE) == 0) {
210
211                                 rpp_sci_printf((const char *)
212                                                            "Available commands:\r\n"
213                                                            );
214                                 rpp_sci_printf((const char *)
215                                                            "\tlog       - Show the log.\r\n"
216                                                            );
217                                 rpp_sci_printf((const char *)
218                                                            "\tclear     - Clear the log.\r\n"
219                                                            );
220                                 rpp_sci_printf((const char *)
221                                                            "\tavailable - Display amount of memory left.\r\n"
222                                                            );
223                                 rpp_sci_printf((const char *)
224                                                            "\texit      - Exit this command processor.\r\n"
225                                                            );
226
227                                 rpp_sci_printf((const char *)"%s", newline);
228                                 rpp_sci_printf((const char *)"%s", prompt);
229                         }
230                         // Log command
231                         else if (strncmp(in_buffer, "log", BUF_SIZE) == 0)
232                                 rpp_sdr_show(TRUE);
233
234                         // Clear command
235                         else if (strncmp(in_buffer, "clear", BUF_SIZE) == 0) {
236                                 rpp_sdr_clear();
237                                 rpp_sci_printf((const char *)"Done.\r\n");
238                                 rpp_sci_printf((const char *)"%s", newline);
239                                 rpp_sci_printf((const char *)"%s", prompt);
240
241                         }
242                         // Available command
243                         else if (strncmp(in_buffer, "available", BUF_SIZE) == 0) {
244                                 rpp_sci_printf(
245                                         (const char *)"%d kB of %d kB available.\r\n",
246                                         rpp_sdr_available() / 1024,
247                                         memory_size / 1024
248                                         );
249                                 rpp_sci_printf((const char *)"%s", newline);
250                                 rpp_sci_printf((const char *)"%s", prompt);
251
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                         }
260                         // Unknown command, print buffer back
261                         else {
262                                 rpp_sci_printf(
263                                         (const char *)"ERROR: Unknown command \"%s\"\r\n",
264                                         (char *)&in_buffer);
265                                 rpp_sci_printf((const char *)"%s", prompt);
266                         }
267
268                         // Reset variables
269                         rpp_sci_flush(TRUE);
270                         buff_index = 0;
271                         flush = FALSE;
272                 }
273         }
274
275         // Delete myself
276         tasks_running--;
277         vTaskDelete(NULL);
278 }
279
280
281
282 /// Public API -----------------------------------------------------------------
283 // Flag to check if SDR module is initialized
284 static boolean_t initialized = FALSE;
285
286 // Memory for Simulation only
287 #ifdef FREERTOS_POSIX
288 static uint8_t memory_simulation[1024*1024]; // Allocate 1MB for test
289 #endif
290
291 // Initialize SDR module
292 int8_t rpp_sdr_init()
293 {
294         if (initialized)
295                 return FAILURE;
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         // No change, ignore
342         if (log_enabled == enable)
343                 return FAILURE;
344
345         // Shut down is requested
346         if (log_enabled && !enable) {
347                 // Stop show task if running
348                 rpp_sdr_show(FALSE);
349                 // Delete tasks
350                 wait_tasks_to_finish();
351                 // Disable logging
352                 log_enabled = FALSE;
353
354                 // Startup is requested
355         }
356         else {
357                 if (xTaskCreate(rpp_sdr_showtask,
358                                                 "rpp_sdr_showtask",
359                                                 256, NULL, 2, &show_handle) != pdPASS)
360                         return FAILURE;
361                 tasks_running++;
362
363                 if (xTaskCreate(rpp_sdr_cmdproc,
364                                                 "rpp_sdr_cmdproc",
365                                                 512, NULL, 2, &cmdproc_handle) != pdPASS) {
366                         wait_tasks_to_finish();
367                         return FAILURE;
368                 }
369                 tasks_running++;
370
371                 log_enabled = TRUE;
372         }
373
374         return SUCCESS;
375 }
376
377
378 // Memory available
379 uint32_t rpp_sdr_available()
380 {
381         return (uint32_t)(memory_end - memory_current + 1);
382 }
383
384
385 // Store something to the log, if logging is enabled
386 int32_t rpp_sdr_printf(const char *format, ...)
387 {
388         if (!log_enabled)
389                 return FAILURE;
390
391         // Don't even try if memory is full
392         if (memory_current == memory_end)
393                 return FAILURE;
394
395         /// Format user string
396         char str[MAX_BUFFER_LEN];
397         int length = -1;
398
399         va_list argList;
400         va_start(argList, format);
401
402         length = vsnprintf(str, sizeof(str), format, argList);
403
404         va_end(argList);
405
406         if (length < 1)
407                 return length;
408
409
410         /// Format header
411         // uint32_t max value is 4294967295 (10 digits) + [] + ' ' + '\0' = 14
412         char hdr[14];
413         int hdr_length = -1;
414         hdr_length = sprintf(hdr, (const char *)"[%10d] ", xTaskGetTickCount());
415
416         if (hdr_length < 1)
417                 return hdr_length;
418
419
420         /// Write header
421         uint32_t cnt = 0;
422         int i = 0;
423         xSemaphoreTake(memory_mutex, portMAX_DELAY);
424         while ((memory_current != memory_end) && (i < hdr_length)) {
425
426                 *memory_current = hdr[i];
427
428                 memory_current++;
429                 cnt++;
430                 i++;
431         }
432
433
434         /// Write user string
435         i = 0;
436         if (length > sizeof(str))
437                 length = sizeof(str);
438         while ((memory_current != memory_end) && (i < length)) {
439
440                 *memory_current = str[i];
441
442                 memory_current++;
443                 cnt++;
444                 i++;
445         }
446
447         /// Write trailer
448         static const char trl[2] = {'\r', '\n'};
449         i = 0;
450         while ((memory_current != memory_end) && (i < sizeof(trl))) {
451
452                 *memory_current = trl[i];
453
454                 memory_current++;
455                 cnt++;
456                 i++;
457         }
458
459         xSemaphoreGive(memory_mutex);
460         return cnt;
461 }
462
463
464 // Clears log. Will also stop the show task
465 int8_t rpp_sdr_clear()
466 {
467         if (!log_enabled)
468                 return FAILURE;
469
470         // Stop log show flushing if running
471         if (show_flushing)
472                 rpp_sdr_show(FALSE);
473
474         // Check if log is already empty
475         if (memory_current == memory_start)
476                 return FAILURE;
477
478         // Reset memory pointer
479         memory_current = memory_start;
480
481         return SUCCESS;
482 }
483
484
485 // Starts/Stops the task that sends the log to the SCI
486 int8_t rpp_sdr_show(boolean_t start)
487 {
488         if (!log_enabled)
489                 return FAILURE;
490
491         // No change, ignore
492         if (start == show_flushing)
493                 return FAILURE;
494
495         // Log flush stop requested
496         if (show_flushing && !start)
497                 show_flushing = FALSE;
498
499         // Log flush start requested
500         else {
501                 show_flushing = TRUE;
502                 xSemaphoreGive(show_semaphore);
503         }
504
505         return SUCCESS;
506 }