mirror of
https://git.intern.spaceteamaachen.de/ALPAKA/rtos2-utils.git
synced 2025-06-10 18:15:59 +00:00
Merge pull request 'libs-rework' (#6) from libs-rework into main
Reviewed-on: https://git.intern.spaceteamaachen.de/ALPAKA/rtos2-utils/pulls/6 Reviewed-by: dario <dario@noreply.git.intern.spaceteamaachen.de>
This commit is contained in:
commit
c5f2d8e533
4
.gitignore
vendored
4
.gitignore
vendored
@ -6,8 +6,8 @@
|
||||
*.launch
|
||||
|
||||
# Build artifacts
|
||||
Debug/
|
||||
Release/
|
||||
/Debug/
|
||||
/Release/
|
||||
|
||||
# Doxygen
|
||||
docs/html
|
||||
|
68
README.md
68
README.md
@ -1,74 +1,42 @@
|
||||
# STA RTOS Utilities
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
Library using CMSIS-RTOS2 functionality for RTOS projects.
|
||||
Library providing the software stack for use with the ALPAKA hardware design for RTOS projects.
|
||||
|
||||
Modules are enabled via defines set in `<sta/config.hpp>` header which must be provided by the application.
|
||||
Modules can be configured via defines set in `<sta/config.hpp>` header file which must be provided by the application.
|
||||
|
||||
|
||||
# Interface implementations
|
||||
# ALPAKA Modules
|
||||
|
||||
The library provides implementations for the following interfaces using CMSIS-RTOS2 functionality:
|
||||
* `Mutex`
|
||||
* `Signal`
|
||||
All enabled modules are initialized by calling the `startALPAKA` function from the default task.
|
||||
|
||||
The function `startupExtras` is called before any module initialization and can be used by the application
|
||||
to execute additional initialization steps before any task waiting for the startup system event will run.
|
||||
The function prototype can be found in the `<sta/rtos/startup.hpp>` header and can optionally be implemented
|
||||
anywhere in the application code.
|
||||
|
||||
|
||||
# Modules
|
||||
## Can Bus
|
||||
|
||||
## System Event
|
||||
|
||||
Provides an interface for common system events.
|
||||
TODO Add description
|
||||
|
||||
Configuration:
|
||||
* `#define STA_RTOS_SYSTEM_EVENT_ENABLE`: Enable module
|
||||
* `#define STA_RTOS_SYSTEM_EVENT_HANDLE <var_name>`: Override variable name of flag handle (default: systemEventHandle)
|
||||
|
||||
|
||||
Requirements:
|
||||
* RTOS: event flag
|
||||
|
||||
|
||||
## Watchdog
|
||||
|
||||
The watchdog task waits for signals sent either from the heartbeat timer or manually via `sta::notifyWatchdog`
|
||||
and forwards the event flags to the `sta::watchdogEventHandler` function implemented by the application.
|
||||
The watchdog task waits for signals sent either from its heartbeat timer or manually via `sta::notifyWatchdog`
|
||||
and passes the event flags to the `sta::watchdogEventHandler` function. This function must be implemented by the application.
|
||||
|
||||
Configuration:
|
||||
* `#define STA_RTOS_WATCHDOG_ENABLE`: Enable module
|
||||
* `#define STA_RTOS_WATCHDOG_TIMER_PERIOD <period_ticks>`: Set period in ticks of heartbeat timer (default: 1000)
|
||||
* `#define STA_RTOS_WATCHDOG_TIMER_HANDLE <var_name>`: Override variable name of heartbeat timer handle (default: heartbeatHandle)
|
||||
* `#define STA_RTOS_WATCHDOG_TIMER_CALLBACK <func_name>`: Override name of heartbeat timer callback function (default: heartbeatCallback)
|
||||
* `#define STA_RTOS_WATCHDOG_HANDLE <var_name>`: Override variable name of watchdog task handle (default: watchdogHandle)
|
||||
* `#define STA_RTOS_WATCHDOG_ENTRY_FUNCTION <func_name>`: Override name of watchdog task entry function (default: watchdogTask)
|
||||
|
||||
Requirements:
|
||||
* Uses the `System Event` module
|
||||
* RTOS: timer + task
|
||||
|
||||
|
||||
## Startup
|
||||
# STA-Core Interfaces
|
||||
|
||||
The entry function for the startup task must be called manually from the default task.
|
||||
|
||||
It provides all setup required by the enabled system tasks. If additional initialization is required by the
|
||||
application the function `void sta::startupExtras(void *)` declared in `<sta/rtos2/startup.hpp>` can be implemented.
|
||||
|
||||
Configuration:
|
||||
* `#define STA_RTOS_STARTUP_ENABLE`: Enable module
|
||||
* `#define STA_RTOS_STARTUP_ENTRY_FUNCTION <func_name>`: Override name of startup task entry function (default: startupTask)
|
||||
|
||||
Requirements:
|
||||
* Uses the `System Event` module
|
||||
* RTOS: task
|
||||
|
||||
|
||||
## Easy Config
|
||||
|
||||
Simplify configuration of modules. Intended for use in `<sta/config.hpp>`.
|
||||
|
||||
Configuration:
|
||||
* `#define STA_RTOS_SYSTEM_TASKS_ENABLE`: Enable all modules required for system tasks
|
||||
* `#define STA_RTOS_WATCHDOG_TIMER_NAME <name>`: Override handle and callback name for watchdog timer
|
||||
* `#define STA_RTOS_WATCHDOG_NAME <name>`: Override handle and entry function name for watchdog task
|
||||
The library provides implementations for the following interfaces using CMSIS-RTOS2 functionality:
|
||||
* `Mutex`
|
||||
* `Signal`
|
||||
|
@ -2,8 +2,8 @@
|
||||
* @file
|
||||
* @brief CAN driver message request types for use in C code.
|
||||
*/
|
||||
#ifndef STA_RTOS_SYSTEM_CAN_MSG_H
|
||||
#define STA_RTOS_SYSTEM_CAN_MSG_H
|
||||
#ifndef STA_RTOS_C_API_CAN_MSG_H
|
||||
#define STA_RTOS_C_API_CAN_MSG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -46,4 +46,4 @@ struct CanSysMsg
|
||||
};
|
||||
|
||||
|
||||
#endif // STA_RTOS_SYSTEM_CAN_MSG_H
|
||||
#endif // STA_RTOS_C_API_CAN_MSG_H
|
22
include/sta/rtos/c_api/startup.h
Normal file
22
include/sta/rtos/c_api/startup.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef STA_RTOS_C_API_STARTUP_H
|
||||
#define STA_RTOS_C_API_STARTUP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param arg Default task argument
|
||||
*/
|
||||
void startALPAKA(void * arg);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif // STA_RTOS_C_API_STARTUP_H
|
@ -1,82 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Helper for easy system task setup in `<sta/config.hpp>`.
|
||||
*/
|
||||
#ifndef STA_RTOS_EASY_CONFIG_HPP
|
||||
#define STA_RTOS_EASY_CONFIG_HPP
|
||||
|
||||
#include <sta/rtos/system/names.hpp>
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup STA_RTOS_EasyConfig Easy Config
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
* @brief Helpers for easy RTOS module setup.
|
||||
*
|
||||
* Use this header only inside the <sta/config.hpp> header of your application.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @brief Don't warn about use of <rtos2/easy_config.hpp> outside of <sta/config.hpp>.
|
||||
*
|
||||
* @ingroup STA_RTOS_EasyConfig
|
||||
*/
|
||||
# define STA_RTOS_EASY_CONFIG_NO_WARNING
|
||||
#endif // DOXYGEN
|
||||
|
||||
#if !defined(STA_CONFIG_HPP) && !defined(STA_RTOS_EASY_CONFIG_NO_WARNING)
|
||||
#warning "Intended for use in <sta/config.hpp>"
|
||||
#endif // !STA_CONFIG_HPP && !STA_RTOS_EASY_CONFIG_NO_WARNING
|
||||
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @brief Enable all system tasks and required features.
|
||||
*
|
||||
* @ingroup STA_RTOS_EasyConfig
|
||||
*/
|
||||
# define STA_RTOS_EASY_CONFIG_SYSTEM_TASKS_ENABLE
|
||||
#endif // DOXYGEN
|
||||
|
||||
#ifdef STA_RTOS_EASY_CONFIG_SYSTEM_TASKS_ENABLE
|
||||
// Enable system events used by system tasks
|
||||
# define STA_RTOS_SYSTEM_EVENT_ENABLE
|
||||
// Enable system tasks
|
||||
# define STA_RTOS_CAN_BUS_ENABLE
|
||||
# define STA_RTOS_STARTUP_ENABLE
|
||||
# define STA_RTOS_WATCHDOG_ENABLE
|
||||
#endif // STA_RTOS_EASY_CONFIG_SYSTEM_TASKS_ENABLE
|
||||
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @brief Common base name used for watchdog timer handle and callback names.
|
||||
*
|
||||
* @ingroup STA_RTOS_EasyConfig
|
||||
*/
|
||||
# define STA_RTOS_EASY_CONFIG_WATCHDOG_TIMER_NAME
|
||||
#endif // DOXYGEN
|
||||
|
||||
#ifdef STA_RTOS_EASY_CONFIG_WATCHDOG_TIMER_NAME
|
||||
# define STA_RTOS_WATCHDOG_TIMER_HANDLE STA_RTOS_MAKE_HANDLE_NAME(STA_RTOS_EASY_CONFIG_WATCHDOG_TIMER_NAME)
|
||||
# define STA_RTOS_WATCHDOG_TIMER_CALLBACK STA_RTOS_MAKE_CALLBACK_NAME(STA_RTOS_EASY_CONFIG_WATCHDOG_TIMER_NAME)
|
||||
#endif // STA_RTOS_EASY_CONFIG_WATCHDOG_TIMER_NAME
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @brief Common base name used for watchdog task handle and entry function names.
|
||||
*
|
||||
* @ingroup STA_RTOS_EasyConfig
|
||||
*/
|
||||
# define STA_RTOS_EASY_CONFIG_WATCHDOG_NAME
|
||||
#endif // DOXYGEN
|
||||
|
||||
#ifdef STA_RTOS_EASY_CONFIG_WATCHDOG_NAME
|
||||
# define STA_RTOS_WATCHDOG_HANDLE STA_RTOS_MAKE_HANDLE_NAME(STA_RTOS_EASY_CONFIG_WATCHDOG_NAME)
|
||||
# define STA_RTOS_WATCHDOG_ENTRY_FUNCTION STA_RTOS_MAKE_TASK_NAME(STA_RTOS_EASY_CONFIG_WATCHDOG_NAME)
|
||||
#endif // STA_RTOS_EASY_CONFIG_WATCHDOG_NAME
|
||||
|
||||
|
||||
#endif // STA_RTOS_EASY_CONFIG_HPP
|
35
include/sta/rtos/event.hpp
Normal file
35
include/sta/rtos/event.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief RTOS event implementation.
|
||||
*/
|
||||
|
||||
#ifndef STA_RTOS_EVENT_HPP
|
||||
#define STA_RTOS_EVENT_HPP
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
#include <sta/event.hpp>
|
||||
|
||||
namespace sta
|
||||
{
|
||||
/**
|
||||
* @brief Implementation of Event using CMSIS RTOS2.
|
||||
*
|
||||
* @ingroup STA_RTOS_API
|
||||
*/
|
||||
class RtosEvent : public Event
|
||||
{
|
||||
public:
|
||||
RtosEvent();
|
||||
~RtosEvent();
|
||||
|
||||
void set(uint32_t flags) override;
|
||||
void clear(uint32_t flags) override;
|
||||
uint32_t get() override;
|
||||
uint32_t wait(uint32_t flags, uint32_t timeout = osWaitForever) override;
|
||||
|
||||
private:
|
||||
osEventFlagsId_t event_id; /**< CMSIS RTOS2 Event Flag */
|
||||
};
|
||||
} // namespace sta
|
||||
|
||||
#endif // STA_RTOS_EVENT_HPP
|
@ -5,7 +5,7 @@
|
||||
# error "Internal header. Use <sta/rtos/handle.hpp> instead."
|
||||
#endif // !STA_RTOS_HANDLE_HPP
|
||||
|
||||
#include <sta/assert.hpp>
|
||||
#include <sta/debug/assert.hpp>
|
||||
|
||||
|
||||
namespace sta
|
||||
|
@ -5,7 +5,7 @@
|
||||
#ifndef STA_RTOS_MUTEX_HPP
|
||||
#define STA_RTOS_MUTEX_HPP
|
||||
|
||||
#include <sta/intf/mutex.hpp>
|
||||
#include <sta/mutex.hpp>
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#ifndef STA_RTOS_SIGNAL_HPP
|
||||
#define STA_RTOS_SIGNAL_HPP
|
||||
|
||||
#include <sta/intf/signal.hpp>
|
||||
#include <sta/signal.hpp>
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
|
@ -5,8 +5,6 @@
|
||||
#ifndef STA_RTOS_SYSTEM_CAN_BUS_HPP
|
||||
#define STA_RTOS_SYSTEM_CAN_BUS_HPP
|
||||
|
||||
#include <sta/rtos/system/names.hpp>
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup STA_RTOS_CanBus CAN driver
|
||||
@ -25,31 +23,13 @@
|
||||
# define STA_RTOS_CAN_BUS_ENABLE
|
||||
#endif // DOXYGEN
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_CAN_BUS_TASK_NAME
|
||||
* @brief Set name of CAN driver task.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_CAN_BUS_TASK_NAME
|
||||
# define STA_RTOS_CAN_BUS_TASK_NAME canBus
|
||||
#endif // !STA_RTOS_CAN_BUS_TASK_NAME
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_CAN_BUS_ENTRY_FUNCTION
|
||||
* @brief Set name of CAN driver task entry function.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_CAN_BUS_ENTRY_FUNCTION
|
||||
# define STA_RTOS_CAN_BUS_ENTRY_FUNCTION STA_RTOS_MAKE_ENTRY_NAME(STA_RTOS_CAN_BUS_TASK_NAME)
|
||||
#endif // !STA_RTOS_CAN_BUS_ENTRY_FUNCTION
|
||||
|
||||
|
||||
#include <sta/config.hpp>
|
||||
#ifdef STA_RTOS_CAN_BUS_ENABLE
|
||||
|
||||
#include <sta/rtos/system/can_msg.h>
|
||||
|
||||
#include <sta/can/controller.hpp>
|
||||
#include <sta/rtos/c_api/can_msg.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@ -121,13 +101,18 @@ namespace sta
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialize CAN bus.
|
||||
*/
|
||||
void initCanBus();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Extra initialization run at start of CAN bus task.
|
||||
* @brief Return CanController for use in CAN system task.
|
||||
*
|
||||
* May be overridden by application if required.
|
||||
* Implementation must be provided by application.
|
||||
*/
|
||||
void setupCanBus();
|
||||
extern CanController * getCanController();
|
||||
|
||||
|
||||
|
||||
|
@ -2,10 +2,8 @@
|
||||
* @file
|
||||
* @brief Implementation of system events.
|
||||
*/
|
||||
#ifndef STA_RTOS_SYSTEM_SYSTEM_EVENT_HPP
|
||||
#define STA_RTOS_SYSTEM_SYSTEM_EVENT_HPP
|
||||
|
||||
#include <sta/rtos/system/names.hpp>
|
||||
#ifndef STA_RTOS_SYSTEM_EVENTS_HPP
|
||||
#define STA_RTOS_SYSTEM_EVENTS_HPP
|
||||
|
||||
|
||||
/**
|
||||
@ -16,29 +14,6 @@
|
||||
* Check @ref STA_RTOS_BuildConfig for configuration options.
|
||||
*/
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @brief Enable module.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
# define STA_RTOS2_SYSTEM_EVENT_ENABLE
|
||||
#endif // DOXYGEN
|
||||
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_SYSTEM_EVENT_NAME
|
||||
* @brief Set name of system event flags.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_SYSTEM_EVENT_NAME
|
||||
# define STA_RTOS_SYSTEM_EVENT_NAME systemEvent
|
||||
#endif // !STA_RTOS_SYSTEM_EVENT_NAME
|
||||
|
||||
|
||||
#include <sta/config.hpp>
|
||||
#ifdef STA_RTOS_SYSTEM_EVENT_ENABLE
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@ -51,13 +26,19 @@
|
||||
*
|
||||
* @ingroup STA_RTOS_SysEvent
|
||||
*/
|
||||
#define STA_SYSTEM_EVENT_STARTUP 0x100000U
|
||||
#define STA_RTOS_SYSTEM_EVENTS_STARTUP 0x100000U
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
namespace rtos
|
||||
{
|
||||
/**
|
||||
* @brief Initialize system events.
|
||||
*/
|
||||
void initSystemEvents();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Signal system events.
|
||||
*
|
||||
@ -98,6 +79,4 @@ namespace sta
|
||||
} // namespace sta
|
||||
|
||||
|
||||
#endif // STA_RTOS_SYSTEM_EVENT_ENABLE
|
||||
|
||||
#endif // STA_RTOS_SYSTEM_SYSTEM_EVENT_HPP
|
||||
#endif // STA_RTOS_SYSTEM_EVENTS_HPP
|
@ -1,12 +0,0 @@
|
||||
#ifndef STA_RTOS_SYSTEM_NAMES_HPP
|
||||
#define STA_RTOS_SYSTEM_NAMES_HPP
|
||||
|
||||
|
||||
#define _STA_RTOS_CONCAT(a, b) a ## b
|
||||
|
||||
#define STA_RTOS_MAKE_HANDLE_NAME(name) _STA_RTOS_CONCAT(name, Handle)
|
||||
#define STA_RTOS_MAKE_CALLBACK_NAME(name) _STA_RTOS_CONCAT(name, Callback)
|
||||
#define STA_RTOS_MAKE_ENTRY_NAME(name) _STA_RTOS_CONCAT(name, Task)
|
||||
|
||||
|
||||
#endif // STA_RTOS_SYSTEM_NAMES_HPP
|
@ -5,8 +5,6 @@
|
||||
#ifndef STA_RTOS_SYSTEM_STARTUP_HPP
|
||||
#define STA_RTOS_SYSTEM_STARTUP_HPP
|
||||
|
||||
#include <sta/rtos/system/names.hpp>
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup STA_RTOS_Startup Startup task
|
||||
@ -17,41 +15,6 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @brief Enable module.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
# define STA_RTOS_STARTUP_ENABLE
|
||||
#endif // DOXYGEN
|
||||
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_STARTUP_TASK_NAME
|
||||
* @brief Set name of startup task.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_STARTUP_TASK_NAME
|
||||
# define STA_RTOS_STARTUP_TASK_NAME startup
|
||||
#endif // !STA_RTOS_STARTUP_TASK_NAME
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_STARTUP_ENTRY_FUNCTION
|
||||
* @brief Set name of startup task entry function.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_STARTUP_ENTRY_FUNCTION
|
||||
# define STA_RTOS_STARTUP_ENTRY_FUNCTION STA_RTOS_MAKE_ENTRY_NAME(STA_RTOS_STARTUP_TASK_NAME)
|
||||
#endif // !STA_RTOS_STARTUP_ENTRY_FUNCTION
|
||||
|
||||
|
||||
#include <sta/config.hpp>
|
||||
#ifdef STA_RTOS_STARTUP_ENABLE
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
namespace rtos
|
||||
@ -68,6 +31,4 @@ namespace sta
|
||||
} // namespace sta
|
||||
|
||||
|
||||
#endif // STA_RTOS_STARTUP_ENABLE
|
||||
|
||||
#endif // STA_RTOS_SYSTEM_STARTUP_HPP
|
||||
|
@ -5,8 +5,6 @@
|
||||
#ifndef STA_RTOS_SYSTEM_WATCHDOG_HPP
|
||||
#define STA_RTOS_SYSTEM_WATCHDOG_HPP
|
||||
|
||||
#include <sta/rtos/system/names.hpp>
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup STA_RTOS_Watchdog Watchdog task
|
||||
@ -27,71 +25,20 @@
|
||||
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_WATCHDOG_TIMER_PERIOD
|
||||
* @def STA_RTOS_SYSTEM_WATCHDOG_TIMER_PERIOD
|
||||
* @brief Set period in ticks of heartbeat timer.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_WATCHDOG_TIMER_PERIOD
|
||||
# define STA_RTOS_WATCHDOG_TIMER_PERIOD 1000
|
||||
#endif // !STA_RTOS_WATCHDOG_TIMER_PERIOD
|
||||
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_WATCHDOG_TIMER_NAME
|
||||
* @brief Set name of watchdog timer.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_WATCHDOG_TIMER_NAME
|
||||
# define STA_RTOS_WATCHDOG_TIMER_NAME heartbeat
|
||||
#endif // !STA_RTOS_WATCHDOG_TIMER_NAME
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_WATCHDOG_TIMER_HANDLE
|
||||
* @brief Set variable name of heartbeat timer handle.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_WATCHDOG_TIMER_HANDLE
|
||||
# define STA_RTOS_WATCHDOG_TIMER_HANDLE STA_RTOS_MAKE_HANDLE_NAME(STA_RTOS_WATCHDOG_TIMER_NAME)
|
||||
#endif // !STA_RTOS_WATCHDOG_TIMER_HANDLE
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_WATCHDOG_TIMER_CALLBACK
|
||||
* @brief Set name of heartbeat timer callback function.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_WATCHDOG_TIMER_CALLBACK
|
||||
# define STA_RTOS_WATCHDOG_TIMER_CALLBACK STA_RTOS_MAKE_CALLBACK_NAME(STA_RTOS_WATCHDOG_TIMER_NAME)
|
||||
#endif // !STA_RTOS_WATCHDOG_TIMER_CALLBACK
|
||||
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_WATCHDOG_TASK_NAME
|
||||
* @brief Set name of watchdog task.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_WATCHDOG_TASK_NAME
|
||||
# define STA_RTOS_WATCHDOG_TASK_NAME watchdog
|
||||
#endif // !STA_RTOS_WATCHDOG_TASK_NAME
|
||||
|
||||
/**
|
||||
* @def STA_RTOS_WATCHDOG_ENTRY_FUNCTION
|
||||
* @brief Set name of watchdog task entry function.
|
||||
*
|
||||
* @ingroup STA_RTOS_BuildConfig
|
||||
*/
|
||||
#ifndef STA_RTOS_WATCHDOG_ENTRY_FUNCTION
|
||||
# define STA_RTOS_WATCHDOG_ENTRY_FUNCTION STA_RTOS_MAKE_ENTRY_NAME(STA_RTOS_WATCHDOG_TASK_NAME)
|
||||
#endif // !STA_RTOS_WATCHDOG_ENTRY_FUNCTION
|
||||
#ifndef STA_RTOS_SYSTEM_WATCHDOG_TIMER_PERIOD
|
||||
# define STA_RTOS_SYSTEM_WATCHDOG_TIMER_PERIOD 1000
|
||||
#endif // !STA_RTOS_SYSTEM_WATCHDOG_TIMER_PERIOD
|
||||
|
||||
|
||||
#include <sta/config.hpp>
|
||||
#ifdef STA_RTOS_WATCHDOG_ENABLE
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
@ -111,11 +58,12 @@ namespace sta
|
||||
namespace rtos
|
||||
{
|
||||
/**
|
||||
* @brief Start heartbeat timer for watchdog.
|
||||
* @brief Initialize system watchdog.
|
||||
*
|
||||
* @ingroup STA_RTOS_Watchdog
|
||||
*/
|
||||
void startWatchdogTimer();
|
||||
void initWatchdog();
|
||||
|
||||
/**
|
||||
* @brief Send notification to watchdog task.
|
||||
*
|
||||
|
34
include/sta/rtos/timer.hpp
Normal file
34
include/sta/rtos/timer.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief RTOS timer implementation.
|
||||
*/
|
||||
|
||||
#ifndef STA_RTOS_TIMER_HPP
|
||||
#define STA_RTOS_TIMER_HPP
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
#include <sta/timer.hpp>
|
||||
|
||||
namespace sta
|
||||
{
|
||||
/**
|
||||
* @brief Implementation of Timer using CMSIS RTOS2.
|
||||
*
|
||||
* @ingroup STA_RTOS_API
|
||||
*/
|
||||
class RtosTimer : public Timer
|
||||
{
|
||||
public:
|
||||
RtosTimer(void (*callback)(void *arg), void *arg);
|
||||
~RtosTimer();
|
||||
|
||||
void start(uint32_t millis) override;
|
||||
void stop() override;
|
||||
|
||||
private:
|
||||
osTimerId_t timer_id_; /**< CMSIS RTOS2 Timer */
|
||||
osTimerAttr_t timer_attr_; /**< CMSIS RTOS2 Timer attributes */
|
||||
};
|
||||
} // namespace sta
|
||||
|
||||
#endif // STA_RTOS_TIMER_HPP
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"owner" : "sta",
|
||||
"name": "sta-rtos",
|
||||
"version": "0.1.0",
|
||||
"version": "1.0.0",
|
||||
"dependencies": [
|
||||
{
|
||||
"url": "git@gitlab.com:sta-git/alpaka/sta-core.git",
|
||||
|
20
src/debug/runtime_stats.c
Normal file
20
src/debug/runtime_stats.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <sta/config.hpp>
|
||||
#ifdef STA_RTOS_RUNTIME_STATS_TIM
|
||||
|
||||
#include <tim.h>
|
||||
|
||||
|
||||
void configureTimerForRunTimeStats()
|
||||
{
|
||||
// Start timer base
|
||||
HAL_TIM_Base_Start(&STA_RTOS_RUNTIME_STATS_TIM);
|
||||
// Reset timer
|
||||
__HAL_TIM_SET_COUNTER(&STA_RTOS_RUNTIME_STATS_TIM, 0);
|
||||
}
|
||||
|
||||
unsigned long getRunTimeCounterValue()
|
||||
{
|
||||
return __HAL_TIM_GET_COUNTER(&STA_RTOS_RUNTIME_STATS_TIM);
|
||||
}
|
||||
|
||||
#endif // STA_RTOS_RUNTIME_STATS_TIM
|
35
src/debug/stack_overflow.cpp
Normal file
35
src/debug/stack_overflow.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include <sta/config.hpp>
|
||||
#ifdef STA_RTOS_STACK_OVERFLOW_HOOK
|
||||
|
||||
#include <sta/assert.hpp>
|
||||
#include <sta/debug_serial.hpp>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
|
||||
extern "C" void vApplicationStackOverflowHook(xTaskHandle xTask, char * pcTaskName)
|
||||
{
|
||||
STA_DEBUG_PRINT("Stack overflow detected in task ");
|
||||
if (pcTaskName)
|
||||
{
|
||||
// Manually calculate string length
|
||||
// Limited to configMAX_TASK_NAME_LEN to avoid reading
|
||||
// garbage values in case TCB has been corrupted
|
||||
size_t len = 0;
|
||||
while (len < configMAX_TASK_NAME_LEN)
|
||||
{
|
||||
if (pcTaskName[len] == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
++len;
|
||||
}
|
||||
|
||||
STA_DEBUG_PRINTLN(pcTaskName, len);
|
||||
}
|
||||
STA_HALT();
|
||||
}
|
||||
|
||||
|
||||
#endif // STA_RTOS_STACK_OVERFLOW_HOOK
|
29
src/event.cpp
Normal file
29
src/event.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include <sta/rtos/event.hpp>
|
||||
|
||||
namespace sta {
|
||||
RtosEvent::RtosEvent() {
|
||||
osEventFlagsAttr_t attr = { 0 };
|
||||
event_id = osEventFlagsNew(&attr);
|
||||
}
|
||||
|
||||
RtosEvent::~RtosEvent() {
|
||||
osEventFlagsDelete(event_id);
|
||||
}
|
||||
|
||||
void RtosEvent::set(uint32_t flags) {
|
||||
osEventFlagsSet(event_id, flags);
|
||||
}
|
||||
|
||||
void RtosEvent::clear(uint32_t flags) {
|
||||
osEventFlagsClear(event_id, flags);
|
||||
}
|
||||
|
||||
uint32_t RtosEvent::get() {
|
||||
return osEventFlagsGet(event_id);
|
||||
}
|
||||
|
||||
uint32_t RtosEvent::wait(uint32_t flags, uint32_t timeout) {
|
||||
return osEventFlagsWait(event_id, flags, osFlagsWaitAny, timeout);
|
||||
}
|
||||
|
||||
} // namespace sta
|
310
src/heap_useNewlib_ST.c
Normal file
310
src/heap_useNewlib_ST.c
Normal file
@ -0,0 +1,310 @@
|
||||
/**
|
||||
* \file heap_useNewlib_ST.c
|
||||
* \brief Wrappers required to use newlib malloc-family within FreeRTOS.
|
||||
*
|
||||
* \par Overview
|
||||
* Route FreeRTOS memory management functions to newlib's malloc family.
|
||||
* Thus newlib and FreeRTOS share memory-management routines and memory pool,
|
||||
* and all newlib's internal memory-management requirements are supported.
|
||||
*
|
||||
* \author Dave Nadler
|
||||
* \date 20-August-2019
|
||||
* \version 27-Jun-2020 Correct "FreeRTOS.h" capitalization, commentary
|
||||
* \version 24-Jun-2020 commentary only
|
||||
* \version 11-Sep-2019 malloc accounting, comments, newlib version check
|
||||
*
|
||||
* \see http://www.nadler.com/embedded/newlibAndFreeRTOS.html
|
||||
* \see https://sourceware.org/newlib/libc.html#Reentrancy
|
||||
* \see https://sourceware.org/newlib/libc.html#malloc
|
||||
* \see https://sourceware.org/newlib/libc.html#index-_005f_005fenv_005flock
|
||||
* \see https://sourceware.org/newlib/libc.html#index-_005f_005fmalloc_005flock
|
||||
* \see https://sourceforge.net/p/freertos/feature-requests/72/
|
||||
* \see http://www.billgatliff.com/newlib.html
|
||||
* \see http://wiki.osdev.org/Porting_Newlib
|
||||
* \see http://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html
|
||||
*
|
||||
*
|
||||
* \copyright
|
||||
* (c) Dave Nadler 2017-2020, All Rights Reserved.
|
||||
* Web: http://www.nadler.com
|
||||
* email: drn@nadler.com
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Use or redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions, and the following disclaimer.
|
||||
*
|
||||
* - Use or redistributions of source code must retain ALL ORIGINAL COMMENTS, AND
|
||||
* ANY CHANGES MUST BE DOCUMENTED, INCLUDING:
|
||||
* - Reason for change (purpose)
|
||||
* - Functional change
|
||||
* - Date and author contact
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \author Henrik Stickann
|
||||
* \data 20-January-2023
|
||||
*
|
||||
* Changes:
|
||||
* * Add macro to only use implementation when requested by user
|
||||
*/
|
||||
#include <sta/config.hpp>
|
||||
#ifdef STA_RTOS_MALLOC_ENABLE
|
||||
|
||||
// Allow setting configISR_STACK_SIZE_WORDS via the STA_RTOS_ISR_STACK_SIZE_WORDS config macro
|
||||
#ifdef STA_RTOS_ISR_STACK_SIZE_WORDS
|
||||
# ifdef configISR_STACK_SIZE_WORDS
|
||||
# warning "STA_RTOS_ISR_STACK_SIZE_WORDS value overriden by configISR_STACK_SIZE_WORDS!"
|
||||
# else // configISR_STACK_SIZE_WORDS
|
||||
# define configISR_STACK_SIZE_WORDS STA_RTOS_ISR_STACK_SIZE_WORDS
|
||||
# endif // configISR_STACK_SIZE_WORDS
|
||||
#endif // STA_RTOS_ISR_STACK_SIZE_WORDS
|
||||
|
||||
|
||||
// ================================================================================================
|
||||
// ======================================= Configuration ========================================
|
||||
// These configuration symbols could be provided by from build...
|
||||
#define STM_VERSION // Replace sane LD symbols with STM CubeMX's poor standard exported LD symbols
|
||||
#define ISR_STACK_LENGTH_BYTES (configISR_STACK_SIZE_WORDS*4) // bytes to reserve for ISR (MSP) stack
|
||||
// ======================================= Configuration ========================================
|
||||
// ================================================================================================
|
||||
|
||||
|
||||
#include <stdlib.h> // maps to newlib...
|
||||
#include <malloc.h> // mallinfo...
|
||||
#include <errno.h> // ENOMEM
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "newlib.h"
|
||||
#if ((__NEWLIB__ == 2) && (__NEWLIB_MINOR__ < 5)) ||((__NEWLIB__ == 3) && (__NEWLIB_MINOR__ > 1))
|
||||
#warning "This wrapper was verified for newlib versions 2.5 - 3.1; please ensure newlib's external requirements for malloc-family are unchanged!"
|
||||
#endif
|
||||
|
||||
#include "FreeRTOS.h" // defines public interface we're implementing here
|
||||
#if !defined(configUSE_NEWLIB_REENTRANT) || (configUSE_NEWLIB_REENTRANT!=1)
|
||||
#warning "#define configUSE_NEWLIB_REENTRANT 1 // Required for thread-safety of newlib sprintf, dtoa, strtok, etc..."
|
||||
// If you're *REALLY* sure you don't need FreeRTOS's newlib reentrancy support, comment out the above warning...
|
||||
#endif
|
||||
#include "task.h"
|
||||
|
||||
// ================================================================================================
|
||||
// External routines required by newlib's malloc (sbrk/_sbrk, __malloc_lock/unlock)
|
||||
// ================================================================================================
|
||||
|
||||
// Simplistic sbrk implementations assume stack grows downwards from top of memory,
|
||||
// and heap grows upwards starting just after BSS.
|
||||
// FreeRTOS normally allocates task stacks from a pool placed within BSS or DATA.
|
||||
// Thus within a FreeRTOS task, stack pointer is always below end of BSS.
|
||||
// When using this module, stacks are allocated from malloc pool, still always prior
|
||||
// current unused heap area...
|
||||
|
||||
// Doesn't work with FreeRTOS: STM CubeMX 2018-2019 Incorrect Implementation
|
||||
#if 0
|
||||
caddr_t _sbrk(int incr)
|
||||
{
|
||||
extern char end asm("end"); // From linker: lowest unused RAM address, just beyond end of BSS.
|
||||
static char *heap_end;
|
||||
char *prev_heap_end;
|
||||
if (heap_end == 0) heap_end = &end;
|
||||
prev_heap_end = heap_end;
|
||||
if (heap_end + incr > stack_ptr) // Fails here: always true for FreeRTOS task stacks
|
||||
{
|
||||
errno = ENOMEM; // ...so first call inside a FreeRTOS task lands here
|
||||
return (caddr_t) -1;
|
||||
}
|
||||
heap_end += incr;
|
||||
return (caddr_t) prev_heap_end;
|
||||
}
|
||||
#endif
|
||||
|
||||
register char * stack_ptr asm("sp");
|
||||
|
||||
#ifdef STM_VERSION // Use STM CubeMX LD symbols for heap+stack area
|
||||
// To avoid modifying STM LD file (and then having CubeMX trash it), use available STM symbols
|
||||
// Unfortunately STM does not provide standardized markers for RAM suitable for heap!
|
||||
// STM CubeMX-generated LD files provide the following symbols:
|
||||
// end /* aligned first word beyond BSS */
|
||||
// _estack /* one word beyond end of "RAM" Ram type memory, for STM32F429 0x20030000 */
|
||||
// Kludge below uses CubeMX-generated symbols instead of sane LD definitions
|
||||
#define __HeapBase end
|
||||
#define __HeapLimit _estack // In K64F LD this is already adjusted for ISR stack space...
|
||||
static int heapBytesRemaining;
|
||||
// no DRN HEAP_SIZE symbol from LD... // that's (&__HeapLimit)-(&__HeapBase)
|
||||
uint32_t TotalHeapSize; // publish for diagnostic routines; filled in first _sbrk call.
|
||||
#else
|
||||
// Note: DRN's K64F LD provided: __StackTop (byte beyond end of memory), __StackLimit, HEAP_SIZE, STACK_SIZE
|
||||
// __HeapLimit was already adjusted to be below reserved stack area.
|
||||
extern char HEAP_SIZE; // make sure to define this symbol in linker LD command file
|
||||
static int heapBytesRemaining = (int)&HEAP_SIZE; // that's (&__HeapLimit)-(&__HeapBase)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MALLOCS_INSIDE_ISRs // STM code to avoid malloc within ISR (USB CDC stack)
|
||||
// We can't use vTaskSuspendAll() within an ISR.
|
||||
// STM's stunningly bad coding malpractice calls malloc within ISRs (for example, on USB connect function USBD_CDC_Init)
|
||||
// So, we must just suspend/resume interrupts, lengthening max interrupt response time, aarrggg...
|
||||
#define DRN_ENTER_CRITICAL_SECTION(_usis) { _usis = taskENTER_CRITICAL_FROM_ISR(); } // Disables interrupts (after saving prior state)
|
||||
#define DRN_EXIT_CRITICAL_SECTION(_usis) { taskEXIT_CRITICAL_FROM_ISR(_usis); } // Re-enables interrupts (unless already disabled prior taskENTER_CRITICAL)
|
||||
#else
|
||||
#define DRN_ENTER_CRITICAL_SECTION(_usis) vTaskSuspendAll(); // Note: safe to use before FreeRTOS scheduler started, but not in ISR
|
||||
#define DRN_EXIT_CRITICAL_SECTION(_usis) xTaskResumeAll(); // Note: safe to use before FreeRTOS scheduler started, but not in ISR
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
static int totalBytesProvidedBySBRK = 0;
|
||||
#endif
|
||||
extern char __HeapBase, __HeapLimit; // symbols from linker LD command file
|
||||
|
||||
// Use of vTaskSuspendAll() in _sbrk_r() is normally redundant, as newlib malloc family routines call
|
||||
// __malloc_lock before calling _sbrk_r(). Note vTaskSuspendAll/xTaskResumeAll support nesting.
|
||||
|
||||
//! _sbrk_r version supporting reentrant newlib (depends upon above symbols defined by linker control file).
|
||||
void * _sbrk_r(struct _reent *pReent, int incr) {
|
||||
#ifdef MALLOCS_INSIDE_ISRs // block interrupts during free-storage use
|
||||
UBaseType_t usis; // saved interrupt status
|
||||
#endif
|
||||
static char *currentHeapEnd = &__HeapBase;
|
||||
#ifdef STM_VERSION // Use STM CubeMX LD symbols for heap
|
||||
if(TotalHeapSize==0) {
|
||||
TotalHeapSize = heapBytesRemaining = (int)((&__HeapLimit)-(&__HeapBase))-ISR_STACK_LENGTH_BYTES;
|
||||
};
|
||||
#endif
|
||||
char* limit = (xTaskGetSchedulerState()==taskSCHEDULER_NOT_STARTED) ?
|
||||
stack_ptr : // Before scheduler is started, limit is stack pointer (risky!)
|
||||
&__HeapLimit-ISR_STACK_LENGTH_BYTES; // Once running, OK to reuse all remaining RAM except ISR stack (MSP) stack
|
||||
DRN_ENTER_CRITICAL_SECTION(usis);
|
||||
if (currentHeapEnd + incr > limit) {
|
||||
// Ooops, no more memory available...
|
||||
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
|
||||
{
|
||||
extern void vApplicationMallocFailedHook( void );
|
||||
DRN_EXIT_CRITICAL_SECTION(usis);
|
||||
vApplicationMallocFailedHook();
|
||||
}
|
||||
#elif defined(configHARD_STOP_ON_MALLOC_FAILURE)
|
||||
// If you want to alert debugger or halt...
|
||||
// WARNING: brkpt instruction may prevent watchdog operation...
|
||||
while(1) { __asm("bkpt #0"); }; // Stop in GUI as if at a breakpoint (if debugging, otherwise loop forever)
|
||||
#else
|
||||
// Default, if you prefer to believe your application will gracefully trap out-of-memory...
|
||||
pReent->_errno = ENOMEM; // newlib's thread-specific errno
|
||||
DRN_EXIT_CRITICAL_SECTION(usis);
|
||||
#endif
|
||||
return (char *)-1; // the malloc-family routine that called sbrk will return 0
|
||||
}
|
||||
// 'incr' of memory is available: update accounting and return it.
|
||||
char *previousHeapEnd = currentHeapEnd;
|
||||
currentHeapEnd += incr;
|
||||
heapBytesRemaining -= incr;
|
||||
#ifndef NDEBUG
|
||||
totalBytesProvidedBySBRK += incr;
|
||||
#endif
|
||||
DRN_EXIT_CRITICAL_SECTION(usis);
|
||||
return (char *) previousHeapEnd;
|
||||
}
|
||||
//! non-reentrant sbrk uses is actually reentrant by using current context
|
||||
// ... because the current _reent structure is pointed to by global _impure_ptr
|
||||
char * sbrk(int incr) { return _sbrk_r(_impure_ptr, incr); }
|
||||
//! _sbrk is a synonym for sbrk.
|
||||
char * _sbrk(int incr) { return sbrk(incr); };
|
||||
|
||||
#ifdef MALLOCS_INSIDE_ISRs // block interrupts during free-storage use
|
||||
static UBaseType_t malLock_uxSavedInterruptStatus;
|
||||
#endif
|
||||
void __malloc_lock(struct _reent *r) {
|
||||
(void)(r);
|
||||
#if defined(MALLOCS_INSIDE_ISRs)
|
||||
DRN_ENTER_CRITICAL_SECTION(malLock_uxSavedInterruptStatus);
|
||||
#else
|
||||
bool insideAnISR = xPortIsInsideInterrupt();
|
||||
configASSERT( !insideAnISR ); // Make damn sure no more mallocs inside ISRs!!
|
||||
vTaskSuspendAll();
|
||||
#endif
|
||||
};
|
||||
void __malloc_unlock(struct _reent *r) {
|
||||
(void)(r);
|
||||
#if defined(MALLOCS_INSIDE_ISRs)
|
||||
DRN_EXIT_CRITICAL_SECTION(malLock_uxSavedInterruptStatus);
|
||||
#else
|
||||
(void)xTaskResumeAll();
|
||||
#endif
|
||||
};
|
||||
|
||||
// newlib also requires implementing locks for the application's environment memory space,
|
||||
// accessed by newlib's setenv() and getenv() functions.
|
||||
// As these are trivial functions, momentarily suspend task switching (rather than semaphore).
|
||||
// Not required (and trimmed by linker) in applications not using environment variables.
|
||||
// ToDo: Move __env_lock/unlock to a separate newlib helper file.
|
||||
void __env_lock() { vTaskSuspendAll(); };
|
||||
void __env_unlock() { (void)xTaskResumeAll(); };
|
||||
|
||||
#if 1 // Provide malloc debug and accounting wrappers
|
||||
/// /brief Wrap malloc/malloc_r to help debug who requests memory and why.
|
||||
/// To use these, add linker options: -Xlinker --wrap=malloc -Xlinker --wrap=_malloc_r
|
||||
// Note: These functions are normally unused and stripped by linker.
|
||||
size_t TotalMallocdBytes;
|
||||
int MallocCallCnt;
|
||||
static bool inside_malloc;
|
||||
void *__wrap_malloc(size_t nbytes) {
|
||||
extern void * __real_malloc(size_t nbytes);
|
||||
MallocCallCnt++;
|
||||
TotalMallocdBytes += nbytes;
|
||||
inside_malloc = true;
|
||||
void *p = __real_malloc(nbytes); // will call malloc_r...
|
||||
inside_malloc = false;
|
||||
return p;
|
||||
};
|
||||
void *__wrap__malloc_r(void *reent, size_t nbytes) {
|
||||
(void)(reent);
|
||||
extern void * __real__malloc_r(size_t nbytes);
|
||||
if(!inside_malloc) {
|
||||
MallocCallCnt++;
|
||||
TotalMallocdBytes += nbytes;
|
||||
};
|
||||
void *p = __real__malloc_r(nbytes);
|
||||
return p;
|
||||
};
|
||||
#endif
|
||||
|
||||
// ================================================================================================
|
||||
// Implement FreeRTOS's memory API using newlib-provided malloc family.
|
||||
// ================================================================================================
|
||||
|
||||
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION {
|
||||
void *p = malloc(xSize);
|
||||
return p;
|
||||
}
|
||||
void vPortFree( void *pv ) PRIVILEGED_FUNCTION {
|
||||
free(pv);
|
||||
};
|
||||
|
||||
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION {
|
||||
struct mallinfo mi = mallinfo(); // available space now managed by newlib
|
||||
return mi.fordblks + heapBytesRemaining; // plus space not yet handed to newlib by sbrk
|
||||
}
|
||||
|
||||
// GetMinimumEverFree is not available in newlib's malloc implementation.
|
||||
// So, no implementation is provided: size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
//! No implementation needed, but stub provided in case application already calls vPortInitialiseBlocks
|
||||
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION {};
|
||||
|
||||
|
||||
#endif // STA_RTOS_MALLOC_ENABLE
|
@ -1,20 +0,0 @@
|
||||
#include <sta/config.hpp>
|
||||
#ifdef STA_RTOS_STM32_RUNTIME_TIM
|
||||
|
||||
#include <tim.h>
|
||||
|
||||
|
||||
void configureTimerForRunTimeStats()
|
||||
{
|
||||
// Start timer base
|
||||
HAL_TIM_Base_Start(&STA_RTOS_STM32_RUNTIME_TIM);
|
||||
// Reset timer
|
||||
__HAL_TIM_SET_COUNTER(&STA_RTOS_STM32_RUNTIME_TIM, 0);
|
||||
}
|
||||
|
||||
unsigned long getRunTimeCounterValue()
|
||||
{
|
||||
return __HAL_TIM_GET_COUNTER(&STA_RTOS_STM32_RUNTIME_TIM);
|
||||
}
|
||||
|
||||
#endif // STA_RTOS_STM32_RUNTIME_TIM
|
@ -6,61 +6,101 @@
|
||||
#ifdef STA_RTOS_CAN_BUS_ENABLE
|
||||
|
||||
#include <sta/assert.hpp>
|
||||
#include <sta/debug_serial.hpp>
|
||||
#include <sta/can/subscribable.hpp>
|
||||
#include <sta/debug_serial.hpp>
|
||||
#include <sta/lang.hpp>
|
||||
|
||||
#include <sta/MCP2518FD/controller.hpp>
|
||||
#include <sta/MCP2518FD/stm32/interrupt.hpp>
|
||||
|
||||
#include <sta/proto/isotp/transmitter.hpp>
|
||||
#include <sta/proto/isotp/receiver.hpp>
|
||||
|
||||
#include <sta/rtos/defs.hpp>
|
||||
#include <sta/rtos/system/can_bus.hpp>
|
||||
#include <sta/rtos/system/system_event.hpp>
|
||||
#include <sta/rtos/thread.hpp>
|
||||
|
||||
#include <sta/stm32/spi.hpp>
|
||||
|
||||
#include <spi.h>
|
||||
#include <sta/rtos/system/events.hpp>
|
||||
#include <sta/stm32/hal.hpp>
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
#include <FreeRTOS.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
#define STA_RTOS_MAKE_DATA_QUEUE_NAME(name) _STA_RTOS_CONCAT(name, DataQueue)
|
||||
#define STA_RTOS_MAKE_SYS_QUEUE_NAME(name) _STA_RTOS_CONCAT(name, SysQueue)
|
||||
namespace
|
||||
{
|
||||
StaticTask_t canBusCB;
|
||||
StaticQueue_t canBusDataQueueCB;
|
||||
StaticQueue_t canBusSysQueueCB;
|
||||
|
||||
osThreadId_t canBusTaskHandle = nullptr;
|
||||
osMessageQueueId_t canBusDataQueueHandle = nullptr;
|
||||
osMessageQueueId_t canBusSysQueueHandle = nullptr;
|
||||
|
||||
sta::CanController * canBusController = nullptr;
|
||||
|
||||
const size_t queueLength = 8;
|
||||
|
||||
// Static memory buffers
|
||||
CanDataMsg canBusDataQueueBuffer[queueLength];
|
||||
CanSysMsg canBusSysQueueBuffer[queueLength];
|
||||
uint32_t canBusStack[256];
|
||||
}
|
||||
|
||||
|
||||
#define STA_RTOS_CAN_BUS_THREAD STA_RTOS_MAKE_HANDLE_NAME(STA_RTOS_CAN_BUS_TASK_NAME)
|
||||
#define STA_RTOS_CAN_BUS_DATA_QUEUE STA_RTOS_MAKE_HANDLE_NAME(STA_RTOS_MAKE_DATA_QUEUE_NAME(STA_RTOS_CAN_BUS_TASK_NAME))
|
||||
#define STA_RTOS_CAN_BUS_SYS_QUEUE STA_RTOS_MAKE_HANDLE_NAME(STA_RTOS_MAKE_SYS_QUEUE_NAME(STA_RTOS_CAN_BUS_TASK_NAME))
|
||||
|
||||
|
||||
// Access handles from freertos.c
|
||||
extern osThreadId_t STA_RTOS_CAN_BUS_THREAD;
|
||||
extern osMessageQueueId_t STA_RTOS_CAN_BUS_DATA_QUEUE;
|
||||
extern osMessageQueueId_t STA_RTOS_CAN_BUS_SYS_QUEUE;
|
||||
extern "C" void canBusTask(void *);
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
namespace rtos
|
||||
{
|
||||
extern CanController * CanBusController;
|
||||
void initCanBus()
|
||||
{
|
||||
// Create thread using static allocation
|
||||
const osThreadAttr_t taskAttributes = {
|
||||
.name = "sysCanBus",
|
||||
.cb_mem = &canBusCB,
|
||||
.cb_size = sizeof(canBusCB),
|
||||
.stack_mem = &canBusStack[0],
|
||||
.stack_size = sizeof(canBusStack),
|
||||
.priority = (osPriority_t) osPriorityLow,
|
||||
};
|
||||
|
||||
canBusTaskHandle = osThreadNew(canBusTask, NULL, &taskAttributes);
|
||||
STA_ASSERT_MSG(canBusTaskHandle != nullptr, "System CAN task initialization failed");
|
||||
|
||||
|
||||
STA_WEAK
|
||||
void setupCanBus()
|
||||
{}
|
||||
// Create message queues using static allocation
|
||||
const osMessageQueueAttr_t dataQueueAttributes = {
|
||||
.name = "sysCanDataOut",
|
||||
.attr_bits = 0,
|
||||
.cb_mem = &canBusDataQueueCB,
|
||||
.cb_size = sizeof(canBusDataQueueCB),
|
||||
.mq_mem = &canBusDataQueueBuffer,
|
||||
.mq_size = sizeof(canBusDataQueueBuffer)
|
||||
};
|
||||
|
||||
canBusDataQueueHandle = osMessageQueueNew(queueLength, sizeof(CanDataMsg), &dataQueueAttributes);
|
||||
STA_ASSERT_MSG(canBusDataQueueHandle != nullptr, "System CAN data message queue initialization failed");
|
||||
|
||||
const osMessageQueueAttr_t sysQueueAttributes = {
|
||||
.name = "sysCanSysOut",
|
||||
.attr_bits = 0,
|
||||
.cb_mem = &canBusSysQueueCB,
|
||||
.cb_size = sizeof(canBusSysQueueCB),
|
||||
.mq_mem = &canBusSysQueueBuffer,
|
||||
.mq_size = sizeof(canBusSysQueueBuffer)
|
||||
};
|
||||
|
||||
canBusSysQueueHandle = osMessageQueueNew(queueLength, sizeof(CanSysMsg), &sysQueueAttributes);
|
||||
STA_ASSERT_MSG(canBusSysQueueHandle != nullptr, "System CAN system message queue initialization failed");
|
||||
|
||||
|
||||
// Get initialized CAN controller from application
|
||||
canBusController = getCanController();
|
||||
}
|
||||
|
||||
|
||||
void notifyCanBus(uint32_t flags)
|
||||
{
|
||||
// Send flags to thread
|
||||
osThreadFlagsSet(STA_RTOS_CAN_BUS_THREAD, flags);
|
||||
osThreadFlagsSet(canBusTaskHandle, flags);
|
||||
}
|
||||
|
||||
|
||||
@ -69,10 +109,10 @@ namespace sta
|
||||
STA_ASSERT((msg.header.sid & STA_CAN_SID_SYS_BITS) == 0);
|
||||
STA_ASSERT(msg.header.payloadLength <= sizeof(msg.payload));
|
||||
|
||||
if (osOK == osMessageQueuePut(STA_RTOS_CAN_BUS_DATA_QUEUE, &msg, 0, timeout))
|
||||
if (osOK == osMessageQueuePut(canBusDataQueueHandle, &msg, 0, timeout))
|
||||
{
|
||||
// Signal thread
|
||||
osThreadFlagsSet(STA_RTOS_CAN_BUS_THREAD, STA_RTOS_CAN_FLAG_DATA_QUEUED);
|
||||
osThreadFlagsSet(canBusTaskHandle, STA_RTOS_CAN_FLAG_DATA_QUEUED);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -85,10 +125,10 @@ namespace sta
|
||||
{
|
||||
STA_ASSERT((msg.header.sid & ~STA_CAN_SID_SYS_BITS) == 0);
|
||||
|
||||
if (osOK == osMessageQueuePut(STA_RTOS_CAN_BUS_SYS_QUEUE, &msg, 0, timeout))
|
||||
if (osOK == osMessageQueuePut(canBusSysQueueHandle, &msg, 0, timeout))
|
||||
{
|
||||
// Signal thread
|
||||
osThreadFlagsSet(STA_RTOS_CAN_BUS_THREAD, STA_RTOS_CAN_FLAG_SYS_QUEUED);
|
||||
osThreadFlagsSet(canBusTaskHandle, STA_RTOS_CAN_FLAG_SYS_QUEUED);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -100,70 +140,19 @@ namespace sta
|
||||
|
||||
bool getCanBusMsg(CanDataMsg * msg, uint32_t timeout)
|
||||
{
|
||||
return (osOK == osMessageQueueGet(STA_RTOS_CAN_BUS_DATA_QUEUE, msg, 0, timeout));
|
||||
return (osOK == osMessageQueueGet(canBusDataQueueHandle, msg, 0, timeout));
|
||||
}
|
||||
|
||||
bool getCanBusMsg(CanSysMsg * msg, uint32_t timeout)
|
||||
{
|
||||
return (osOK == osMessageQueueGet(STA_RTOS_CAN_BUS_SYS_QUEUE, msg, 0, timeout));
|
||||
return (osOK == osMessageQueueGet(canBusSysQueueHandle, msg, 0, timeout));
|
||||
}
|
||||
} // namespace rtos
|
||||
} // namespace sta
|
||||
|
||||
|
||||
using namespace sta;
|
||||
|
||||
|
||||
/**< ISOTP CAN transmitter */
|
||||
IsotpTransmitter gCanTx(rtos::CanBusController, HAL_GetTick);
|
||||
/**< ISOTP CAN receiver */
|
||||
IsotpReceiver gCanRx(rtos::CanBusController, HAL_GetTick);
|
||||
|
||||
|
||||
CanRxCallback filterCallbacks[STA_RTOS_CAN_BUS_MAX_FILTER];
|
||||
|
||||
|
||||
namespace debug
|
||||
{
|
||||
/**
|
||||
* @brief Display ISOTP TX/RX statistics.
|
||||
*/
|
||||
void showStatistics()
|
||||
{
|
||||
STA_DEBUG_PRINTLN();
|
||||
STA_DEBUG_PRINTLN("# ######################");
|
||||
STA_DEBUG_PRINTLN("# ## ISOTP statistics ##");
|
||||
STA_DEBUG_PRINTLN("# ######################");
|
||||
STA_DEBUG_PRINTLN("#");
|
||||
|
||||
STA_DEBUG_PRINTLN("# Transmitter");
|
||||
STA_DEBUG_PRINT("# messages: ");
|
||||
STA_DEBUG_PRINTLN(gCanTx.stats().messages);
|
||||
STA_DEBUG_PRINT("# blocks: ");
|
||||
STA_DEBUG_PRINTLN(gCanTx.stats().blocks);
|
||||
STA_DEBUG_PRINT("# frames: ");
|
||||
STA_DEBUG_PRINTLN(gCanTx.stats().frames);
|
||||
STA_DEBUG_PRINT("# timeouts: ");
|
||||
STA_DEBUG_PRINTLN(gCanTx.stats().timeouts);
|
||||
STA_DEBUG_PRINTLN("#");
|
||||
|
||||
STA_DEBUG_PRINTLN("# Receiver");
|
||||
STA_DEBUG_PRINT("# messages: ");
|
||||
STA_DEBUG_PRINTLN(gCanRx.stats().messages);
|
||||
STA_DEBUG_PRINT("# blocks: ");
|
||||
STA_DEBUG_PRINTLN(gCanRx.stats().blocks);
|
||||
STA_DEBUG_PRINT("# frames: ");
|
||||
STA_DEBUG_PRINTLN(gCanRx.stats().frames);
|
||||
STA_DEBUG_PRINT("# timeouts: ");
|
||||
STA_DEBUG_PRINTLN(gCanRx.stats().timeouts);
|
||||
STA_DEBUG_PRINT("# flow control errors: ");
|
||||
STA_DEBUG_PRINTLN(gCanRx.stats().flowErrors);
|
||||
STA_DEBUG_PRINT("# overflows: ");
|
||||
STA_DEBUG_PRINTLN(gCanRx.stats().overflows);
|
||||
STA_DEBUG_PRINTLN();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Output CAN frame ID to UART.
|
||||
*
|
||||
@ -200,213 +189,357 @@ namespace debug
|
||||
} // namespace debug
|
||||
|
||||
|
||||
namespace demo
|
||||
namespace dummy
|
||||
{
|
||||
extern void handleRxMessage(const uint8_t * buffer, uint16_t size);
|
||||
} // namespace demo
|
||||
|
||||
|
||||
/**
|
||||
* @brief Process received ISOTP messages.
|
||||
*
|
||||
* @param msg ISOTP message
|
||||
*/
|
||||
void handleRxMessage(const sta::IsotpMessage & msg)
|
||||
{
|
||||
STA_DEBUG_PRINTLN("[event] RX message");
|
||||
|
||||
debug::printFrameID(msg.frameID);
|
||||
|
||||
// TODO Forward message to other threads
|
||||
demo::handleRxMessage(msg.buffer, msg.size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Handle received data message CAN frames.
|
||||
*
|
||||
* @param header CAN frame header
|
||||
* @param payload Payload buffer
|
||||
*/
|
||||
void receiveDataCallback(const sta::CanRxHeader & header, const uint8_t * payload)
|
||||
{
|
||||
// Write frame payload to DebugSerial
|
||||
STA_DEBUG_PRINTLN("[event] RX data frame");
|
||||
debug::printPayloadHex(payload, header.payloadLength);
|
||||
|
||||
// Process RX frame
|
||||
auto handle = gCanRx.processFrame(header, payload);
|
||||
|
||||
if (handle != sta::IsotpReceiver::INVALID_HANDLE)
|
||||
void handleSysMessage(const sta::CanRxHeader & header, const uint8_t * payload)
|
||||
{
|
||||
// Get message if completed
|
||||
sta::IsotpMessage msg;
|
||||
if (gCanRx.getMessage(handle, &msg))
|
||||
{
|
||||
handleRxMessage(msg);
|
||||
}
|
||||
// Write frame payload to DebugSerial
|
||||
STA_DEBUG_PRINTLN("[event] RX sys frame");
|
||||
|
||||
// Handle FC responses
|
||||
gCanRx.processFC(handle);
|
||||
debug::printFrameID(header.id);
|
||||
debug::printPayloadHex(payload, header.payloadLength);
|
||||
|
||||
// TODO Forward message to other threads
|
||||
}
|
||||
|
||||
// Process TX frame
|
||||
gCanTx.processFrame(header, payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle received system message CAN frames.
|
||||
*
|
||||
* @param header CAN frame header
|
||||
* @param payload Payload buffer
|
||||
*/
|
||||
void receiveSysCallback(const sta::CanRxHeader & header, const uint8_t * payload)
|
||||
{
|
||||
// Write frame payload to DebugSerial
|
||||
STA_DEBUG_PRINTLN("[event] RX sys frame");
|
||||
|
||||
debug::printFrameID(header.id);
|
||||
debug::printPayloadHex(payload, header.payloadLength);
|
||||
|
||||
// TODO Forward message to other threads
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configure CAN filters.
|
||||
*/
|
||||
void setupCanSubscriptions()
|
||||
{
|
||||
// Make sure to receive all messages
|
||||
CanFilter filter;
|
||||
|
||||
// Clear previous subscriptions
|
||||
rtos::CanBusController->clearFilters();
|
||||
|
||||
|
||||
// All bits except [0:1] of the SID must be zero for system messages
|
||||
filter.obj = {0, 0};
|
||||
filter.mask = {~STA_CAN_SID_SYS_BITS, 0};
|
||||
filter.type = sta::CanFilterIdFormat::ANY;
|
||||
filter.fifo = 0;
|
||||
|
||||
filterCallbacks[0] = receiveSysCallback;
|
||||
rtos::CanBusController->configureFilter(0, filter, true);
|
||||
|
||||
|
||||
// TODO Limit which data messages are received
|
||||
// Bits [0:1] of the SID must be zero for data messages
|
||||
filter.obj = {0, 0};
|
||||
filter.mask = {STA_CAN_SID_SYS_BITS, 0};
|
||||
filter.type = sta::CanFilterIdFormat::ANY;
|
||||
filter.fifo = 1;
|
||||
filterCallbacks[1] = receiveDataCallback;
|
||||
rtos::CanBusController->configureFilter(1, filter, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Process received CAN messages.
|
||||
*/
|
||||
void processMessages()
|
||||
{
|
||||
for (auto fifo : rtos::CanBusController->getPendingRxFifos())
|
||||
void handleDataMessage(const sta::IsotpMessage & msg)
|
||||
{
|
||||
CanRxHeader header;
|
||||
uint8_t payload[STA_RTOS_CAN_BUS_MAX_PAYLOAD_SIZE];
|
||||
STA_ASSERT(msg.buffer != nullptr);
|
||||
STA_ASSERT(msg.size != 0);
|
||||
|
||||
if (rtos::CanBusController->receiveFrame(fifo, &header, payload))
|
||||
STA_DEBUG_PRINTLN("[event] RX data message");
|
||||
|
||||
debug::printFrameID(msg.frameID);
|
||||
|
||||
// TODO Forward message to other threads
|
||||
|
||||
// if (buffer[0] == DEMO_BMP_PACKET_ID)
|
||||
// {
|
||||
// BmpPacket packet;
|
||||
// if (unpack(buffer + 1, size - 1, &packet))
|
||||
// {
|
||||
// STA_DEBUG_PRINTLN();
|
||||
// STA_DEBUG_PRINTLN("# ############");
|
||||
// STA_DEBUG_PRINTLN("# ## BMP380 ##");
|
||||
// STA_DEBUG_PRINTLN("# ############");
|
||||
// STA_DEBUG_PRINTLN("#");
|
||||
//
|
||||
// STA_DEBUG_PRINT("# temperature: ");
|
||||
// STA_DEBUG_PRINT(packet.temperature);
|
||||
// STA_DEBUG_PRINTLN(" *C");
|
||||
// STA_DEBUG_PRINT("# pressure: ");
|
||||
// STA_DEBUG_PRINT(packet.pressure);
|
||||
// STA_DEBUG_PRINTLN(" Pa");
|
||||
// STA_DEBUG_PRINT("# altitude: ");
|
||||
// STA_DEBUG_PRINT(packet.altitude);
|
||||
// STA_DEBUG_PRINTLN(" m");
|
||||
// STA_DEBUG_PRINTLN();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// STA_DEBUG_PRINTLN("[error] BMP unpack failed");
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
{
|
||||
// debug::displayFrameUART(frame);
|
||||
STA_DEBUG_PRINT("ID: ");
|
||||
STA_DEBUG_PRINTLN(msg.buffer[0], sta::IntegerBase::HEX);
|
||||
STA_DEBUG_PRINT("size: ");
|
||||
STA_DEBUG_PRINTLN(msg.size);
|
||||
}
|
||||
}
|
||||
} // namespace dummy
|
||||
|
||||
// Forward frame to filter callback
|
||||
if (fifo <= STA_RTOS_CAN_BUS_MAX_FILTER && filterCallbacks[header.filter])
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
class AlpakaCanBus
|
||||
{
|
||||
public:
|
||||
using SysMsgHandler = void (*)(const CanRxHeader &, const uint8_t *);
|
||||
using DataMsgHandler = void (*)(const IsotpMessage &);
|
||||
|
||||
static const uint8_t FIFO_SYS = 0;
|
||||
static const uint8_t FIFO_DATA = 1;
|
||||
|
||||
public:
|
||||
AlpakaCanBus(CanController * controller, TimeMsFn timeMs, SysMsgHandler sysMsgHandler, DataMsgHandler dataMsgHandler);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send system message.
|
||||
*
|
||||
* @param msg Message
|
||||
*/
|
||||
void send(const CanSysMsg & msg);
|
||||
|
||||
/**
|
||||
* @brief Send data message.
|
||||
*
|
||||
* @param msg Message
|
||||
*/
|
||||
void send(const CanDataMsg & msg);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Process transmissions.
|
||||
*
|
||||
* Call regularly to advance transmission.
|
||||
*/
|
||||
void processTx();
|
||||
|
||||
/**
|
||||
* @brief Process received CAN messages.
|
||||
*/
|
||||
void processRx();
|
||||
|
||||
/**
|
||||
* @brief Display ISOTP TX/RX statistics.
|
||||
*/
|
||||
void showStatistics();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Configure CAN filters.
|
||||
*/
|
||||
void setupSubscriptions();
|
||||
|
||||
/**
|
||||
* @brief Handle received data message CAN frames.
|
||||
*
|
||||
* @param header CAN frame header
|
||||
* @param payload Payload buffer
|
||||
*/
|
||||
void receiveDataFrame(const CanRxHeader & header, const uint8_t * payload);
|
||||
|
||||
private:
|
||||
CanController * controller_;
|
||||
IsotpTransmitter tx_;
|
||||
IsotpReceiver rx_;
|
||||
SysMsgHandler handleSysMsg_;
|
||||
DataMsgHandler handleDataMsg_;
|
||||
};
|
||||
|
||||
|
||||
AlpakaCanBus::AlpakaCanBus(CanController * controller, TimeMsFn timeMs, SysMsgHandler sysMsgHandler, DataMsgHandler dataMsgHandler)
|
||||
: controller_{controller}, tx_{controller, timeMs}, rx_{controller, timeMs}, handleSysMsg_{sysMsgHandler}, handleDataMsg_{dataMsgHandler}
|
||||
{
|
||||
STA_ASSERT(handleSysMsg_ != nullptr);
|
||||
STA_ASSERT(handleDataMsg_ != nullptr);
|
||||
|
||||
setupSubscriptions();
|
||||
}
|
||||
|
||||
|
||||
void AlpakaCanBus::send(const CanSysMsg & msg)
|
||||
{
|
||||
CanTxHeader header;
|
||||
header.id.format = static_cast<CanIdFormat>(msg.header.format);
|
||||
header.id.sid = msg.header.sid & STA_CAN_SID_SYS_BITS;
|
||||
header.id.eid = msg.header.eid;
|
||||
header.payloadLength = msg.header.payloadLength;
|
||||
|
||||
controller_->sendFrame(header, msg.payload);
|
||||
}
|
||||
|
||||
void AlpakaCanBus::send(const CanDataMsg & msg)
|
||||
{
|
||||
CanFrameId frameID;
|
||||
frameID.format = static_cast<CanIdFormat>(msg.header.format);
|
||||
frameID.sid = msg.header.sid & ~STA_CAN_SID_SYS_BITS;
|
||||
frameID.eid = msg.header.eid;
|
||||
|
||||
// Start transmission via ISO-TP
|
||||
tx_.send(frameID, msg.payload, msg.header.payloadLength);
|
||||
}
|
||||
|
||||
|
||||
inline void AlpakaCanBus::processTx()
|
||||
{
|
||||
tx_.process();
|
||||
}
|
||||
|
||||
|
||||
void AlpakaCanBus::processRx()
|
||||
{
|
||||
for (auto fifo : controller_->getPendingRxFifos())
|
||||
{
|
||||
CanRxHeader header;
|
||||
uint8_t payload[STA_RTOS_CAN_BUS_MAX_PAYLOAD_SIZE];
|
||||
|
||||
if (controller_->receiveFrame(fifo, &header, payload))
|
||||
{
|
||||
filterCallbacks[header.filter](header, payload);
|
||||
// debug::displayFrameUART(frame);
|
||||
|
||||
// Forward frame to callback
|
||||
switch (fifo)
|
||||
{
|
||||
case FIFO_SYS:
|
||||
handleSysMsg_(header, payload);
|
||||
break;
|
||||
|
||||
case FIFO_DATA:
|
||||
receiveDataFrame(header, payload);
|
||||
break;
|
||||
|
||||
default:
|
||||
STA_ASSERT(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
/**
|
||||
* @brief CAN driver thread entry function.
|
||||
*/
|
||||
void canBusTask(void *)
|
||||
void AlpakaCanBus::showStatistics()
|
||||
{
|
||||
using namespace sta;
|
||||
STA_DEBUG_PRINTLN();
|
||||
STA_DEBUG_PRINTLN("# ######################");
|
||||
STA_DEBUG_PRINTLN("# ## ISOTP statistics ##");
|
||||
STA_DEBUG_PRINTLN("# ######################");
|
||||
STA_DEBUG_PRINTLN("#");
|
||||
|
||||
// Initialize CAN controller
|
||||
rtos::setupCanBus();
|
||||
const auto & txStats = tx_.stats();
|
||||
STA_DEBUG_PRINTLN("# Transmitter");
|
||||
STA_DEBUG_PRINT("# messages: ");
|
||||
STA_DEBUG_PRINTLN(txStats.messages);
|
||||
STA_DEBUG_PRINT("# blocks: ");
|
||||
STA_DEBUG_PRINTLN(txStats.blocks);
|
||||
STA_DEBUG_PRINT("# frames: ");
|
||||
STA_DEBUG_PRINTLN(txStats.frames);
|
||||
STA_DEBUG_PRINT("# timeouts: ");
|
||||
STA_DEBUG_PRINTLN(txStats.timeouts);
|
||||
STA_DEBUG_PRINTLN("#");
|
||||
|
||||
// Configure filters for
|
||||
setupCanSubscriptions();
|
||||
const auto & rxStats = rx_.stats();
|
||||
STA_DEBUG_PRINTLN("# Receiver");
|
||||
STA_DEBUG_PRINT("# messages: ");
|
||||
STA_DEBUG_PRINTLN(rxStats.messages);
|
||||
STA_DEBUG_PRINT("# blocks: ");
|
||||
STA_DEBUG_PRINTLN(rxStats.blocks);
|
||||
STA_DEBUG_PRINT("# frames: ");
|
||||
STA_DEBUG_PRINTLN(rxStats.frames);
|
||||
STA_DEBUG_PRINT("# timeouts: ");
|
||||
STA_DEBUG_PRINTLN(rxStats.timeouts);
|
||||
STA_DEBUG_PRINT("# flow control errors: ");
|
||||
STA_DEBUG_PRINTLN(rxStats.flowErrors);
|
||||
STA_DEBUG_PRINT("# overflows: ");
|
||||
STA_DEBUG_PRINTLN(rxStats.overflows);
|
||||
STA_DEBUG_PRINTLN();
|
||||
}
|
||||
|
||||
|
||||
rtos::waitForStartupEvent();
|
||||
void AlpakaCanBus::setupSubscriptions()
|
||||
{
|
||||
// Make sure to receive all messages
|
||||
CanFilter filter;
|
||||
|
||||
while (true)
|
||||
// Clear previous subscriptions
|
||||
controller_->clearFilters();
|
||||
|
||||
|
||||
// All bits except [0:1] of the SID must be zero for system messages
|
||||
filter.obj = {0, 0};
|
||||
filter.mask = {~STA_CAN_SID_SYS_BITS, 0};
|
||||
filter.type = sta::CanFilterIdFormat::ANY;
|
||||
filter.fifo = FIFO_SYS;
|
||||
controller_->configureFilter(FIFO_SYS, filter, true);
|
||||
|
||||
// TODO Limit which data messages are received
|
||||
// Bits [0:1] of the SID must be zero for data messages
|
||||
filter.obj = {0, 0};
|
||||
filter.mask = {STA_CAN_SID_SYS_BITS, 0};
|
||||
filter.type = sta::CanFilterIdFormat::ANY;
|
||||
filter.fifo = FIFO_DATA;
|
||||
controller_->configureFilter(FIFO_DATA, filter, true);
|
||||
}
|
||||
|
||||
void AlpakaCanBus::receiveDataFrame(const CanRxHeader & header, const uint8_t * payload)
|
||||
{
|
||||
// Write frame payload to DebugSerial
|
||||
STA_DEBUG_PRINTLN("[event] RX data frame");
|
||||
debug::printPayloadHex(payload, header.payloadLength);
|
||||
|
||||
// Process RX frame
|
||||
auto handle = rx_.processFrame(header, payload);
|
||||
|
||||
if (handle != IsotpReceiver::INVALID_HANDLE)
|
||||
{
|
||||
uint32_t flags = osThreadFlagsWait(STA_RTOS_THREAD_FLAGS_VALID_BITS, osFlagsWaitAny, 50);
|
||||
|
||||
if (flags != static_cast<uint32_t>(osErrorTimeout))
|
||||
// Get message if completed
|
||||
IsotpMessage msg;
|
||||
if (rx_.getMessage(handle, &msg))
|
||||
{
|
||||
STA_ASSERT_MSG((flags & osStatusReserved) == flags, "Unexpected error occurred in wait");
|
||||
handleDataMsg_(msg);
|
||||
}
|
||||
|
||||
if (flags & STA_RTOS_CAN_FLAG_SYS_QUEUED)
|
||||
// Handle FC responses
|
||||
rx_.processFC(handle);
|
||||
}
|
||||
|
||||
// Process TX frame
|
||||
tx_.processFrame(header, payload);
|
||||
}
|
||||
} // namespace sta
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief CAN driver thread entry function.
|
||||
*/
|
||||
void canBusTask(void *)
|
||||
{
|
||||
using namespace sta;
|
||||
|
||||
STA_ASSERT_MSG(canBusController != nullptr, "System CAN bus not initialized");
|
||||
|
||||
// Setup ISO-TP transceiver
|
||||
AlpakaCanBus canBus(canBusController, HAL_GetTick, dummy::handleSysMessage, dummy::handleDataMessage);
|
||||
|
||||
|
||||
rtos::waitForStartupEvent();
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint32_t flags = osThreadFlagsWait(STA_RTOS_THREAD_FLAGS_VALID_BITS, osFlagsWaitAny, 50);
|
||||
|
||||
if (flags != static_cast<uint32_t>(osErrorTimeout))
|
||||
{
|
||||
STA_ASSERT_MSG((flags & osStatusReserved) == flags, "Unexpected error occurred in wait");
|
||||
|
||||
if (flags & STA_RTOS_CAN_FLAG_SYS_QUEUED)
|
||||
{
|
||||
// Take messages from queue until empty
|
||||
CanSysMsg msg;
|
||||
while (rtos::getCanBusMsg(&msg, 0))
|
||||
{
|
||||
CanSysMsg msg;
|
||||
CanTxHeader header;
|
||||
|
||||
// Take messages from queue until empty
|
||||
while (rtos::getCanBusMsg(&msg, 0))
|
||||
{
|
||||
header.id.format = static_cast<CanIdFormat>(msg.header.format);
|
||||
header.id.sid = msg.header.sid & STA_CAN_SID_SYS_BITS;
|
||||
header.id.eid = msg.header.eid;
|
||||
header.payloadLength = msg.header.payloadLength;
|
||||
|
||||
debug::printPayloadHex(msg.payload, header.payloadLength);
|
||||
|
||||
rtos::CanBusController->sendFrame(header, msg.payload);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & STA_RTOS_CAN_FLAG_DATA_QUEUED)
|
||||
{
|
||||
CanDataMsg msg;
|
||||
CanFrameId frameID;
|
||||
|
||||
// Take messages from queue until empty
|
||||
while (rtos::getCanBusMsg(&msg, 0))
|
||||
{
|
||||
frameID.format = static_cast<CanIdFormat>(msg.header.format);
|
||||
frameID.sid = msg.header.sid & ~STA_CAN_SID_SYS_BITS;
|
||||
frameID.eid = msg.header.eid;
|
||||
|
||||
// Transmit via ISO-TP
|
||||
gCanTx.send(frameID, msg.payload, msg.header.payloadLength);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & STA_RTOS_CAN_FLAG_MSG_AVAIL)
|
||||
{
|
||||
STA_DEBUG_PRINTLN("[event] CAN INT");
|
||||
|
||||
processMessages();
|
||||
}
|
||||
|
||||
if (flags & STA_RTOS_CAN_FLAG_SHOW_STATS)
|
||||
{
|
||||
debug::showStatistics();
|
||||
canBus.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Process ISOTP transmissions
|
||||
gCanTx.process();
|
||||
if (flags & STA_RTOS_CAN_FLAG_DATA_QUEUED)
|
||||
{
|
||||
// Take messages from queue until empty
|
||||
CanDataMsg msg;
|
||||
while (rtos::getCanBusMsg(&msg, 0))
|
||||
{
|
||||
canBus.send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & STA_RTOS_CAN_FLAG_MSG_AVAIL)
|
||||
{
|
||||
STA_DEBUG_PRINTLN("[event] CAN INT");
|
||||
|
||||
canBus.processRx();
|
||||
}
|
||||
|
||||
if (flags & STA_RTOS_CAN_FLAG_SHOW_STATS)
|
||||
{
|
||||
canBus.showStatistics();
|
||||
}
|
||||
}
|
||||
|
||||
// Process ISOTP transmissions
|
||||
canBus.processTx();
|
||||
}
|
||||
}
|
||||
|
||||
|
61
src/system/events.cpp
Normal file
61
src/system/events.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include <sta/rtos/system/events.hpp>
|
||||
|
||||
#include <sta/debug/assert.hpp>
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
#include <FreeRTOS.h>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// Static memory for system events
|
||||
StaticEventGroup_t systemEventControlBlock;
|
||||
// Event handle
|
||||
osEventFlagsId_t systemEventsHandle = nullptr;
|
||||
}
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
namespace rtos
|
||||
{
|
||||
void initSystemEvents()
|
||||
{
|
||||
// Create event using static allocation
|
||||
const osEventFlagsAttr_t attributes = {
|
||||
.name = "systemEvent",
|
||||
.cb_mem = &systemEventControlBlock,
|
||||
.cb_size = sizeof(systemEventControlBlock),
|
||||
};
|
||||
|
||||
if (systemEventsHandle == nullptr)
|
||||
{
|
||||
systemEventsHandle = osEventFlagsNew(&attributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void signalSystemEvents(uint32_t flags)
|
||||
{
|
||||
STA_ASSERT_MSG(systemEventsHandle != nullptr, "System events not initialized");
|
||||
osEventFlagsSet(systemEventsHandle, flags);
|
||||
}
|
||||
|
||||
void waitForSystemEvents(uint32_t flags, uint32_t options, uint32_t timeout)
|
||||
{
|
||||
STA_ASSERT_MSG(systemEventsHandle != nullptr, "System events not initialized");
|
||||
osEventFlagsWait(systemEventsHandle, flags, options | osFlagsNoClear, timeout);
|
||||
}
|
||||
|
||||
|
||||
void signalStartupEvent()
|
||||
{
|
||||
signalSystemEvents(STA_RTOS_SYSTEM_EVENTS_STARTUP);
|
||||
}
|
||||
|
||||
void waitForStartupEvent()
|
||||
{
|
||||
waitForSystemEvents(STA_RTOS_SYSTEM_EVENTS_STARTUP, osFlagsWaitAll, osWaitForever);
|
||||
}
|
||||
} // namespace rtos
|
||||
} // namespace sta
|
@ -1,10 +1,13 @@
|
||||
#include <sta/rtos/system/startup.hpp>
|
||||
#ifdef STA_RTOS_STARTUP_ENABLE
|
||||
|
||||
#include <sta/rtos/c_api/startup.h>
|
||||
|
||||
#include <sta/debug/assert.hpp>
|
||||
#include <sta/lang.hpp>
|
||||
#include <sta/rtos/system/system_event.hpp>
|
||||
#include <sta/rtos/system/can_bus.hpp>
|
||||
#include <sta/rtos/system/events.hpp>
|
||||
#include <sta/rtos/system/watchdog.hpp>
|
||||
#include <sta/stm32/init.hpp>
|
||||
#include <sta/devices/stm32/init.hpp>
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
@ -17,33 +20,46 @@ namespace sta
|
||||
STA_WEAK
|
||||
void startupExtras(void *)
|
||||
{}
|
||||
|
||||
|
||||
void initSystem()
|
||||
{
|
||||
#ifdef STA_RTOS_SYSTEM_EVENTS_ENABLE
|
||||
initSystemEvents();
|
||||
#endif // STA_RTOS_SYSTEM_EVENTS_ENABLE
|
||||
|
||||
#ifdef STA_RTOS_WATCHDOG_ENABLE
|
||||
initWatchdog();
|
||||
#endif // STA_RTOS_WATCHDOG_ENABLE
|
||||
|
||||
#ifdef STA_RTOS_CAN_BUS_ENABLE
|
||||
initCanBus();
|
||||
#endif // STA_RTOS_CAN_BUS_ENABLE
|
||||
}
|
||||
} // namespace rtos
|
||||
} // namespace sta
|
||||
|
||||
|
||||
// Declare with C linkage
|
||||
extern "C"
|
||||
void startALPAKA(void * arg)
|
||||
{
|
||||
void STA_RTOS_STARTUP_ENTRY_FUNCTION(void * arg)
|
||||
STA_ASSERT_MSG(osKernelGetState() != osKernelInactive, "Cannot call startALPAKA() before osKernelInitialize()");
|
||||
|
||||
// Call further initialization code
|
||||
sta::rtos::startupExtras(arg);
|
||||
|
||||
// Initialize HAL
|
||||
sta::initHAL();
|
||||
|
||||
// Initialize RTOS system resources
|
||||
sta::rtos::initSystem();
|
||||
|
||||
// Wake threads
|
||||
sta::rtos::signalStartupEvent();
|
||||
|
||||
// Check if called from thread
|
||||
if (osThreadGetId() != nullptr)
|
||||
{
|
||||
// Call further initialization code
|
||||
sta::rtos::startupExtras(arg);
|
||||
|
||||
// Initialize HAL
|
||||
sta::initHAL();
|
||||
|
||||
#ifdef STA_RTOS_WATCHDOG_ENABLE
|
||||
// Start timers
|
||||
sta::rtos::startWatchdogTimer();
|
||||
#endif // STA_RTOS_WATCHDOG_ENABLE
|
||||
|
||||
// Wake threads
|
||||
sta::rtos::signalStartupEvent();
|
||||
|
||||
// Terminate thread
|
||||
// Terminate current thread
|
||||
osThreadExit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // STA_RTOS_STARTUP_ENABLE
|
||||
|
@ -1,43 +0,0 @@
|
||||
#include <sta/rtos/system/system_event.hpp>
|
||||
|
||||
#ifdef STA_RTOS_SYSTEM_EVENT_ENABLE
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
|
||||
#define STA_RTOS_SYSTEM_EVENT_HANDLE STA_RTOS_MAKE_HANDLE_NAME(STA_RTOS_SYSTEM_EVENT_NAME)
|
||||
|
||||
|
||||
// Access handle from freertos.c
|
||||
extern osEventFlagsId_t STA_RTOS_SYSTEM_EVENT_HANDLE;
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
namespace rtos
|
||||
{
|
||||
void signalSystemEvents(uint32_t flags)
|
||||
{
|
||||
osEventFlagsSet(STA_RTOS_SYSTEM_EVENT_HANDLE, flags);
|
||||
}
|
||||
|
||||
void waitForSystemEvents(uint32_t flags, uint32_t options, uint32_t timeout)
|
||||
{
|
||||
osEventFlagsWait(STA_RTOS_SYSTEM_EVENT_HANDLE, flags, options | osFlagsNoClear, timeout);
|
||||
}
|
||||
|
||||
|
||||
void signalStartupEvent()
|
||||
{
|
||||
signalSystemEvents(STA_SYSTEM_EVENT_STARTUP);
|
||||
}
|
||||
|
||||
void waitForStartupEvent()
|
||||
{
|
||||
waitForSystemEvents(STA_SYSTEM_EVENT_STARTUP, osFlagsWaitAll, osWaitForever);
|
||||
}
|
||||
} // namespace rtos
|
||||
} // namespace sta
|
||||
|
||||
|
||||
#endif // STA_RTOS_SYSTEM_EVENT_ENABLE
|
100
src/system/watchdog.cpp
Normal file
100
src/system/watchdog.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include <sta/rtos/system/watchdog.hpp>
|
||||
#ifdef STA_RTOS_WATCHDOG_ENABLE
|
||||
|
||||
#include <sta/debug/assert.hpp>
|
||||
#include <sta/lang.hpp>
|
||||
#include <sta/rtos/defs.hpp>
|
||||
#include <sta/rtos/system/events.hpp>
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
#include <FreeRTOS.h>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
StaticTask_t watchdogCB;
|
||||
StaticTimer_t watchdogTimerCB;
|
||||
|
||||
osThreadId_t watchdogTaskHandle = nullptr;
|
||||
osTimerId_t watchdogTimerHandle = nullptr;
|
||||
|
||||
// Static stack memory
|
||||
uint32_t stackBuffer[256];
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void watchdogTask(void * arg);
|
||||
void watchdogTimerCallback(void *);
|
||||
}
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
namespace rtos
|
||||
{
|
||||
void initWatchdog()
|
||||
{
|
||||
// Create thread using static allocation
|
||||
const osThreadAttr_t taskAttributes = {
|
||||
.name = "sysWatchdog",
|
||||
.cb_mem = &watchdogCB,
|
||||
.cb_size = sizeof(watchdogCB),
|
||||
.stack_mem = &stackBuffer[0],
|
||||
.stack_size = sizeof(stackBuffer),
|
||||
.priority = (osPriority_t) osPriorityLow,
|
||||
};
|
||||
|
||||
watchdogTaskHandle = osThreadNew(watchdogTask, NULL, &taskAttributes);
|
||||
STA_ASSERT_MSG(watchdogTaskHandle != nullptr, "System watchdog task initialization failed");
|
||||
|
||||
|
||||
// Create timer using static allocation
|
||||
const osTimerAttr_t timerAttributes = {
|
||||
.name = "sysWatchdogTimer",
|
||||
.attr_bits = 0, // Reserved, must be set to 0
|
||||
.cb_mem = &watchdogTimerCB,
|
||||
.cb_size = sizeof(watchdogTimerCB)
|
||||
};
|
||||
|
||||
watchdogTimerHandle = osTimerNew(watchdogTimerCallback, osTimerPeriodic, nullptr, &timerAttributes);
|
||||
STA_ASSERT_MSG(watchdogTimerHandle != nullptr, "System watchdog timer initialization failed");
|
||||
osTimerStart(watchdogTimerHandle, STA_RTOS_SYSTEM_WATCHDOG_TIMER_PERIOD);
|
||||
}
|
||||
|
||||
|
||||
void notifyWatchdog(uint32_t flags)
|
||||
{
|
||||
STA_ASSERT_MSG(watchdogTaskHandle != nullptr, "System watchdog not initialized");
|
||||
osThreadFlagsSet(watchdogTaskHandle, flags);
|
||||
}
|
||||
} // namespace rtos
|
||||
} // namespace sta
|
||||
|
||||
|
||||
|
||||
void watchdogTask(void * arg)
|
||||
{
|
||||
sta::rtos::waitForStartupEvent();
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Wait for any flag to be set
|
||||
uint32_t flags = osThreadFlagsWait(STA_RTOS_THREAD_FLAGS_VALID_BITS, osFlagsWaitAny, osWaitForever);
|
||||
|
||||
// Call event handler
|
||||
sta::rtos::watchdogEventHandler(arg, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void watchdogTimerCallback(void *)
|
||||
{
|
||||
// Notify watchdog task to send heartbeat message
|
||||
// Required because blocking in a timer callback is not allowed
|
||||
osThreadFlagsSet(watchdogTaskHandle, STA_WATCHDOG_FLAG_HEARTBEAT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // STA_RTOS_WATCHDOG_ENABLE
|
@ -1,18 +0,0 @@
|
||||
#ifndef STA_RTOS_SYSTEM_WATCHDOG_HANDLES_HPP
|
||||
#define STA_RTOS_SYSTEM_WATCHDOG_HANDLES_HPP
|
||||
|
||||
#include <sta/rtos/system/watchdog.hpp>
|
||||
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
|
||||
#define WATCHDOG_TASK_HANDLE STA_RTOS_MAKE_HANDLE_NAME(STA_RTOS_WATCHDOG_TASK_NAME)
|
||||
#define WATCHDOG_TIMER_HANDLE STA_RTOS_MAKE_HANDLE_NAME(STA_RTOS_WATCHDOG_TIMER_NAME)
|
||||
|
||||
|
||||
// Access handles from freertos.c
|
||||
extern osThreadId_t WATCHDOG_TASK_HANDLE;
|
||||
extern osTimerId_t WATCHDOG_TIMER_HANDLE;
|
||||
|
||||
|
||||
#endif // STA_RTOS_SYSTEM_WATCHDOG_HANDLES_HPP
|
@ -1,32 +0,0 @@
|
||||
#include <sta/rtos/system/watchdog.hpp>
|
||||
|
||||
#ifdef STA_RTOS_WATCHDOG_ENABLE
|
||||
|
||||
#include "handles.hpp"
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
namespace rtos
|
||||
{
|
||||
void startWatchdogTimer()
|
||||
{
|
||||
osTimerStart(WATCHDOG_TIMER_HANDLE, STA_RTOS_WATCHDOG_TIMER_PERIOD);
|
||||
}
|
||||
} // namespace rtos
|
||||
} // namespace sta
|
||||
|
||||
|
||||
// Declare with C linkage
|
||||
extern "C"
|
||||
{
|
||||
void STA_RTOS_WATCHDOG_TIMER_CALLBACK(void *)
|
||||
{
|
||||
// Notify watchdog task to send heartbeat message
|
||||
// Required because blocking in a timer callback is not allowed
|
||||
osThreadFlagsSet(WATCHDOG_TASK_HANDLE, STA_WATCHDOG_FLAG_HEARTBEAT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // STA_RTOS_WATCHDOG_ENABLE
|
@ -1,43 +0,0 @@
|
||||
#include <sta/rtos/system/watchdog.hpp>
|
||||
|
||||
#ifdef STA_RTOS_WATCHDOG_ENABLE
|
||||
|
||||
#include <sta/rtos/defs.hpp>
|
||||
#include <sta/rtos/system/system_event.hpp>
|
||||
|
||||
|
||||
#include "handles.hpp"
|
||||
|
||||
|
||||
namespace sta
|
||||
{
|
||||
namespace rtos
|
||||
{
|
||||
void notifyWatchdog(uint32_t flags)
|
||||
{
|
||||
osThreadFlagsSet(WATCHDOG_TASK_HANDLE, flags);
|
||||
}
|
||||
} // namespace rtos
|
||||
} // namespace sta
|
||||
|
||||
|
||||
// Declare with C linkage
|
||||
extern "C"
|
||||
{
|
||||
void STA_RTOS_WATCHDOG_ENTRY_FUNCTION(void * arg)
|
||||
{
|
||||
sta::rtos::waitForStartupEvent();
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Wait for any flag to be set
|
||||
uint32_t flags = osThreadFlagsWait(STA_RTOS_THREAD_FLAGS_VALID_BITS, osFlagsWaitAny, osWaitForever);
|
||||
|
||||
// Call event handler
|
||||
sta::rtos::watchdogEventHandler(arg, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // STA_RTOS_WATCHDOG_ENABLE
|
28
src/timer.cpp
Normal file
28
src/timer.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include <sta/rtos/timer.hpp>
|
||||
#include <sta/debug/debug.hpp>
|
||||
|
||||
namespace sta {
|
||||
RtosTimer::RtosTimer(void (*callback)(void *arg), void *arg) {
|
||||
timer_attr_.name = "Timer";
|
||||
timer_attr_.attr_bits = osTimerOnce;
|
||||
timer_attr_.cb_size = sizeof(osTimerAttr_t);
|
||||
|
||||
timer_id_ = osTimerNew(callback, osTimerOnce, arg, &timer_attr_);
|
||||
}
|
||||
|
||||
RtosTimer::~RtosTimer() {
|
||||
osTimerDelete(timer_id_);
|
||||
}
|
||||
|
||||
void RtosTimer::start(uint32_t millis) {
|
||||
osStatus_t status = osTimerStart(timer_id_, millis);
|
||||
|
||||
if (status != osOK) STA_DEBUG_PRINTLN("Timer start failed");
|
||||
}
|
||||
|
||||
void RtosTimer::stop() {
|
||||
osStatus_t status = osTimerStop(timer_id_);
|
||||
|
||||
if (status != osOK) STA_DEBUG_PRINTLN("Timer stop failed");
|
||||
}
|
||||
} // namespace sta
|
Loading…
x
Reference in New Issue
Block a user