|
LibJuno 1.0.1
LibJuno is a lightweight C11 library designed specifically for embedded systems.
|
#include "juno/app/app_api.h"#include "juno/log/log_api.h"#include "juno/sb/broker_api.h"#include "juno/time/time_api.h"#include "engine_app/engine_app.h"#include "juno/macros.h"#include "juno/status.h"#include "system_manager_app/system_manager_app.h"#include <stdarg.h>#include <stddef.h>#include <stdio.h>#include <time.h>
Functions | |
| static JUNO_STATUS_T | LogDebug (const JUNO_LOG_ROOT_T *ptJunoLog, const char *pcMsg,...) |
| static JUNO_STATUS_T | LogInfo (const JUNO_LOG_ROOT_T *ptJunoLog, const char *pcMsg,...) |
| static JUNO_STATUS_T | LogWarning (const JUNO_LOG_ROOT_T *ptJunoLog, const char *pcMsg,...) |
| static JUNO_STATUS_T | LogError (const JUNO_LOG_ROOT_T *ptJunoLog, const char *pcMsg,...) |
| static JUNO_TIMESTAMP_RESULT_T | Now (const JUNO_TIME_ROOT_T *ptTime) |
| Get the current time as specified by the implementation. | |
| static JUNO_STATUS_T | SleepTo (const JUNO_TIME_ROOT_T *ptTime, JUNO_TIMESTAMP_T tTimeToWakeup) |
| Sleep this thread until a specific time. | |
| static JUNO_STATUS_T | Sleep (const JUNO_TIME_ROOT_T *ptTime, JUNO_TIMESTAMP_T tDuration) |
| Sleep this thread for a duration. | |
| void | FailureHandler (JUNO_STATUS_T tStatus, const char *pcMsg, JUNO_USER_DATA_T *pvUserData) |
| int | main (void) |
Variables | |
| static const JUNO_LOG_API_T | gtMyLoggerApi |
| static const JUNO_TIME_API_T | gtTimeApi = JunoTime_TimeApiInit(Now, SleepTo, Sleep) |
| void FailureHandler | ( | JUNO_STATUS_T | tStatus, |
| const char * | pcMsg, | ||
| JUNO_USER_DATA_T * | pvUserData | ||
| ) |
DOC
LibJuno utilizes a failure handler callback. This is a function that is automatically called by downstream code when a failure occurs. In an embedded system, you might not have a terminal or console log running. This enables developers to have a single implementation and methodology for handling failure within the software. The JUNO_FAIL... macros will automatically call the failure handler if one is provided.
|
static |
DOC The purpose of this tutorial is to show new users how to use LibJuno as a embedded software micro-framework. LibJuno is intended to provide developers and software architects the freedom to implement their software system according to their use case, instead of users conforming to our library.
This means users will need to define their own entry point. On systems with an OS, this would be a main function.
Additionally, users will need to implement project specific functions like logging and time management since LibJuno doesn't assume your OS or time use-case.
In this case, we are going to implement the logging functions using printf. A fixed size buffer is utilized with vsnprintf to ensure the logger doesn't see any memory overruns.
|
static |
|
static |
|
static |
| int main | ( | void | ) |
DOC
This example project assumes its running on a POSIX system. Therefore, we can use a main method as the entry point. Many microcontrollers have different architectures for their entry point so you'll need to consult with your architecture documentation on how to implement the entry point.
DOC
The core principle of dependency injection is "inversion of control". This is a fancy term for saying that modules don't allocate resources, up stream users do. This is done at the "composition root", or the spot in the code where all the dependencies get implemented. In this case, the main function is the composition root. Here we need to instantiate the time, logger, registry modules.
Applications in LibJuno are actually derived modules of JUNO_APP_ROOT_T. Here we will need to instantiate the engine, and system manager application modules.
DOC
Modules typically have an Init function that specifies the required fields to initialize a module. Modules also utilize a Verify function to verify they've been initialzed. Most modules will return a JUNO_STATUS_NULLPTR_ERROR if they have not been initalized and a function has been called on them.
DOC Notice how the broker, engine, and system manager take initialized modules as dependencies to their initialization. This is DI in action. For example, the engine app is provided with a logger, time, and broker instead of instantiating it itself.
DOC
For this example we are going to create a very simple "schedule table" or table of applications that will run in a specific order. This schedule table will run at best-effort. This means that when one application is done, the next will start.
DOC Since all applications have the same interface, we can run their init function in a for-loop and run the application OnProcess function in a while(true) loop.
|
static |
Get the current time as specified by the implementation.
DOC
In this example project we will need a timestamp, so we'll implement the Now function. We don't need Sleep or SleepTo so we'll provide mocks to those functions. LibJuno provides time math functions that we can utilize so we only need to provide implementations to these three time functions.
|
static |
Sleep this thread for a duration.
|
static |
Sleep this thread until a specific time.
|
static |
DOC
LibJuno utilizes a vtable, or a table of function pointers to the specific implementation, that is passed to the LibJuno module. This vtable is called an "API" in LibJuno nomenclature and it provides a standard interface to the capabilities. LibJuno is implemented as a set of capabilities, or software components that perform a set functionality. These capabilities are called "Modules" and can be extened through derivation. Additionally APIs can be extended through derivation. When a module or API is extended its called "derived".
Below is the API instantiation of the logger and time APIs for this project. We are providing our logging implementations and time implementations. You'll notice that the time API provides a helper macro to instantiate the API. Some APIs offer existing implementations, so a helper macro is used to inform users which functions they need to implement.
|
static |