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