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