Skip to content

Commit

Permalink
Enabled UART log reader task to print UART logs to console
Browse files Browse the repository at this point in the history
  • Loading branch information
danieldegrasse committed Aug 14, 2020
1 parent 1ab3b7c commit 4061a6f
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 16 deletions.
31 changes: 20 additions & 11 deletions commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "cli.h"
#include "sd_card.h"
#include "uart_log_reader_task.h"
#include "uart_logger_task.h"

/* Board-specific functions */
Expand Down Expand Up @@ -41,6 +42,7 @@ static int sdpwr(CLIContext *ctx, char **argv, int argc);
static int sdwrite(CLIContext *ctx, char **argv, int argc);
static int logfile_size(CLIContext *ctx, char **argv, int argc);
static int connect_log(CLIContext *ctx, char **argv, int argc);
static int disconnect_log(CLIContext *ctx, char **argv, int argc);

/**
* Declaration of commands. Syntax is as follows:
Expand All @@ -63,6 +65,8 @@ const CmdEntry COMMANDS[] = {
{"sdwrite", sdwrite, "Writes provided string to the SD card"},
{"filesize", logfile_size, "Gets the size of the log file in bytes"},
{"connect_log", connect_log, "Connects to the UART console being logged"},
{"disconnect_log", disconnect_log,
"Disconnects from the UART console being logged"},
// Add more entries here.
{NULL, NULL, NULL}};

Expand Down Expand Up @@ -266,17 +270,22 @@ static int logfile_size(CLIContext *ctx, char **argv, int argc) {
* @return 0 on success, or another value on failure
*/
static int connect_log(CLIContext *ctx, char **argv, int argc) {
char c;
enable_log_forwarding();
while (1)
{
dequeue_logger_data(&c);
// temporary. Just a way to get out of loop.
cli_printf(ctx, "%c", c);
if (c == 'x') {
break;
}
start_log_reader(ctx);
return 0;
}

/**
* Disconnects from the UART device being logged, so it's data no longer will
* print to the CLI.
* @param ctx: CLI context to print to
* @param argv list of arguments
* @param argc argument count
* @return 0 on success, or another value on failure
*/
static int disconnect_log(CLIContext *ctx, char **argv, int argc) {
if (stop_log_reader() != 0) {
cli_printf(ctx, "Cannot stop log reader from this terminal\r\n");
return 255;
}
disable_log_forwarding();
return 0;
}
2 changes: 2 additions & 0 deletions sd_logger.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "sd_card.h"
#include "uart_console_task.h"
#include "uart_logger_task.h"
#include "uart_log_reader_task.h"

/*
* ======== main ========
Expand All @@ -25,6 +26,7 @@ int main(void) {
Board_initUART(); // Done here since both the console and logger use it.
uart_console_prebios();
uart_logger_prebios();
uart_log_reader_prebios();
// Setup required pthread variables for the SD card.
sd_setup();
/* Start BIOS */
Expand Down
29 changes: 26 additions & 3 deletions sd_logger.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -510,17 +510,24 @@ var task0Params = new Task.Params();
task0Params.instance.name = "heartbeat";
task0Params.arg0 = 1000;
Program.global.heartbeat = Task.create("&heartBeatFxn", task0Params);
/* Uart console allows for commands to be issued to the MCU. */
/* UART console allows for commands to be issued to the MCU. */
var task1Params = new Task.Params();
task1Params.instance.name = "uart_console";
// Stack must be larger to hold CLI history buffer.
task1Params.stackSize = 2048;
Program.global.uart_console = Task.create("&uart_task_entry", task1Params);
/* Uart logger reads UART data and logs it to the SD card. */
/* UART logger reads UART data and logs it to the SD card. */
var task2Par = new Task.Params();
task2Par.instance.name = "uart_logger";
task2Par.stackSize = 2048;
Program.global.uart_logger = Task.create("&uart_logger_task_entry", task2Par);
/* UART log reader reads logs from the UART logger, and prints them to CLI */
var task3Par = new Task.Params();
task3Par.instance.name = "uart_log_reader";
task3Par.stackSize = 1024;
Program.global.uart_log_reader = Task.create("&uart_log_reader_task_entry",
task3Par);
/* ================= Required Modules for FatFS support ============ */
Expand All @@ -530,4 +537,20 @@ var Timestamp = xdc.useModule('xdc.runtime.Timestamp');
/* ================ Queue Creation ============================= */
// Create a queue to hold UART data.
var Queue = xdc.useModule('ti.sysbios.knl.Queue');
Program.global.uart_log_queue = Queue.create();
Program.global.uart_log_queue = Queue.create();
/* ================ Semaphore Creation ============================= */
var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
// Log reader sem signals when the log reader task should start or stop.
var semaphore0Params = new Semaphore.Params();
semaphore0Params.mode = Semaphore.Mode_COUNTING
Program.global.log_reader_sem = Semaphore.create(0, semaphore0Params);
// logger data avaliable sem signals when the UART logger has data enqueued.
var semaphore1Params = new Semaphore.Params();
semaphore1Params.mode = Semaphore.Mode_COUNTING
Program.global.logger_data_avail_sem = Semaphore.create(0, semaphore1Params);
// Shutdown semaphore lets uart log reader acknowledge shutdown request.
var semaphore2Params = new Semaphore.Params();
semaphore2Params.mode = Semaphore.Mode_COUNTING
Program.global.shutdown_ack_sem = Semaphore.create(0, semaphore2Params);
154 changes: 154 additions & 0 deletions uart_log_reader_task.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/**
* @file uart_log_reader_task.c
* This file implements a task (and functions to control it) based around
* reading data from the UART logger, and relaying it to a CLI context.
*/

/* XDCtools Header files */
#include <xdc/runtime/System.h>
#include <xdc/std.h>

/* BIOS Header files */
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Task.h>

/* Pthread support */
#include <ti/sysbios/posix/pthread.h>

#include "cli.h"
#include "uart_logger_task.h"

// Protects access to the CLI context global variable.
static pthread_mutex_t LOG_READER_CTX_MUTEX;
// Current context we will print to.
static CLIContext *CONTEXT;
/**
* This semaphore is used to signal this task to run. Statically created, see
* "Semaphore Creation" in .cfg file.
*/
extern Semaphore_Handle log_reader_sem;
// Also statically created. Lets task acknowledge shutdown.
extern Semaphore_Handle shutdown_ack_sem;

/**
* Must be called before BIOS starts. Sets up required data structures for
* the UART log reader task.
*/
void uart_log_reader_prebios(void) {
if (pthread_mutex_init(&LOG_READER_CTX_MUTEX, NULL) != 0) {
System_abort("Failed to create SD write mutex\n");
}
CONTEXT = NULL;
}

/**
* Starts the log reader with a given CLI context. If another log reader is
* running, this function will block until it terminates.
* @param context: CLI context the log reader must print to.
*/
void start_log_reader(CLIContext *context) {
// First, lock the mutex.
if (pthread_mutex_lock(&LOG_READER_CTX_MUTEX) != 0) {
System_abort("could not lock log reader mutex");
}
CONTEXT = context;
/*
* Now, post to the binary semaphore. The log reader task will see this
* signal and start writing to the set context.
*/
Semaphore_post(log_reader_sem);
/*
* Note: we purposely do NOT unlock the mutex here. This is how we keep
* other tasks from starting the log reader with their CLI context.
*/
}

/**
* Task entry for the UART log reader. Will wait for a semaphore to be
* signalled, and upon signaling will run until the semaphore is
* signalled again.
* The run loop of the log reader will read data from the UART logger, and
* echo this data to a selected CLI context.
* @param arg0: Unused
* @param arg1: Unused
*/
void uart_log_reader_task_entry(UArg arg0, UArg arg1) {
char uart_data;
while (1) {
// Wait for the semaphore to be signaled.
Semaphore_pend(log_reader_sem, BIOS_WAIT_FOREVER);
System_printf("Running Log reader\n");
System_flush();
cli_printf(CONTEXT, "We are running the task now\r\n");
// Enable log forwarding here.
enable_log_forwarding();
while (1) {
// If data is avaliable, read it and print to CLI.
if (logger_has_data()) {
dequeue_logger_data(&uart_data);
// Bypass cli_printf here, mostly for speed.
CONTEXT->cli_write(&uart_data, 1);
} else {
// Wait one second for logger data before trying again
/*
* We cannot wait forever because we need to be able to
* shutdown the logger in a timely manner, even if no new data
* has arrived from UART.
*/
wait_logger_data(1000);
}
/*
* Check to see if the semaphore was signaled again. If so, a task
* is requesting we exit.
*/
if (Semaphore_pend(log_reader_sem, BIOS_NO_WAIT) == TRUE) {
// Task requested exit. Disable log forwarding.
System_printf("Shutdown of log reader requested\n");
System_flush();
disable_log_forwarding();
// Clear the value of the global context.
CONTEXT = NULL;
// Post to shutdown ack sem to acknowledge exit.
Semaphore_post(shutdown_ack_sem);
break;
}
}
}
}

/**
* Stops the log reader. Must be called from the same task context that
* is currently running the log reader.
* @return 0 if the log reader stopped, or -1 if the task trying to stop the
* reader is not the one that started it.
*/
int stop_log_reader(void) {
if (CONTEXT == NULL) {
// No CLI context is running, so the log reader isn't either.
// Return 0, as the log reader is stopped (since it wasn't running)
return 0;
}
// First, signal the log reader semaphore. The log reader task will see it.
Semaphore_post(log_reader_sem);
/*
* Now, wait for the log reader task to post to the semaphore. this
* handshake ensures the log reader task has stopped.
*/
Semaphore_pend(shutdown_ack_sem, BIOS_WAIT_FOREVER);
System_printf("Got handshake signal from log reader task\n");
System_flush();
// Finally, drop the mutex.
if (pthread_mutex_unlock(&LOG_READER_CTX_MUTEX) != 0) {
/*
* The calling thread does not own the mutex, and was not the thread
* that started the log reader task. Post to the semaphore again to
* start the log reader task back up.
*/
System_printf("Calling thread did not own the mutex!\n");
System_flush();
Semaphore_post(log_reader_sem);
return -1;
}
return 0;
}
33 changes: 33 additions & 0 deletions uart_log_reader_task.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @file uart_log_reader_task.h
* This file implements a task (and functions to control it) based around
* reading data from the UART logger, and relaying it to a CLI context.
*/

#ifndef UART_LOG_READER_H
#define UART_LOG_READER_H

#include "cli.h"

/**
* Must be called before BIOS starts. Sets up required data structures for
* the UART log reader task.
*/
void uart_log_reader_prebios(void);

/**
* Starts the log reader with a given CLI context. If another log reader is
* running, this function will block until it terminates.
* @param context: CLI context the log reader must print to.
*/
void start_log_reader(CLIContext *context);

/**
* Stops the log reader. Must be called from the same task context that
* is currently running the log reader.
* @return 0 if the log reader stopped, or -1 if the task trying to stop the
* reader is not the one that started it.
*/
int stop_log_reader(void);

#endif
26 changes: 25 additions & 1 deletion uart_logger_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
/* BIOS Header files */
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Queue.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Task.h>

/* TI-RTOS Header files */
Expand All @@ -30,6 +31,12 @@
#define LOG_BAUD_RATE 115200
#define UART_LOGDEV Board_UART3

/*
* Statically allocated semaphore for data being in queue. See "Semaphore
* Creation" in .cfg file.
*/
extern Semaphore_Handle logger_data_avail_sem;

/*
* Statically allocated queue for received UART log data. Used for forward data
* when requested. See "Queue Creation" in cfg file.
Expand Down Expand Up @@ -115,6 +122,8 @@ void uart_logger_task_entry(UArg arg0, UArg arg1) {
Queue_put(uart_log_queue,
&(queue_elements[queue_idx].elem));
queue_idx++;
// Post to semaphore so any waiting tasks know we have data.
Semaphore_post(logger_data_avail_sem);
if (queue_idx >= MAX_QUEUE) {
// Wrap the queue element index back to 0.
queue_idx = 0;
Expand Down Expand Up @@ -159,9 +168,24 @@ void disable_log_forwarding(void) { FORWARD_UART_LOGS = false; }
void dequeue_logger_data(char *out) {
UART_Queue_Elem *elem;
/*
* Remove the element atomically
* Remove the element atomically
* (we expect other tasks to call this function)
*/
elem = Queue_get(uart_log_queue);
*out = elem->data;
}

/**
* Checks if the logger queue has data.
* @return true if data is present, or false otherwise.
*/
bool logger_has_data(void) { return !(Queue_empty(uart_log_queue)); }

/**
* Waits for data to be ready in the logger.
* @param timeout: How long to wait for data.
*/
void wait_logger_data(int timeout) {
// Pend on semaphore here.
Semaphore_pend(logger_data_avail_sem, timeout);
}
15 changes: 14 additions & 1 deletion uart_logger_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,17 @@ void disable_log_forwarding(void);
* queue element buffer will be exhausted and data WILL be lost.
* @param out: char of data returned from queue.
*/
void dequeue_logger_data(char *out);
void dequeue_logger_data(char *out);


/**
* Checks if the logger queue has data.
* @return true if data is present, or false otherwise.
*/
bool logger_has_data(void);

/**
* Waits for data to be ready in the logger.
* @param timeout: How long to wait for data.
*/
void wait_logger_data(int timeout);

0 comments on commit 4061a6f

Please sign in to comment.