Skip to content

Commit

Permalink
[Core]: Add support for CMSIS RTOS 2 Thread synchronization
Browse files Browse the repository at this point in the history
  • Loading branch information
ad3154 committed Mar 28, 2024
1 parent ab2e8a9 commit af62b24
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 2 deletions.
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ if(NOT CAN_STACK_DISABLE_THREADS AND NOT ARDUINO)
endif()
endif()

option(
USE_CMSIS_RTOS2_THREADING
"Set to ON to use ARM CMSIS RTOS2 thread syncronization. Replaces std::mutex and implements a CMSIS lock_guard."
OFF)
if(USE_CMSIS_RTOS2_THREADING)
message(
AUTHOR_WARNING
"Using CMSIS RTOS2 threading requires you to implement a hardware timebase (_gettimeofday) for the stack. Make sure you do this using a hardware timer!"
)
endif()

# A handy function to prepend text to all elements in a list (useful for
# subdirectories)
function(prepend var prefix)
Expand Down
2 changes: 1 addition & 1 deletion isobus/src/isobus_task_controller_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ namespace isobus

if (!initialized)
{
#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO && !defined USE_CMSIS_RTOS2_THREADING
if (spawnThread)
{
workerThread = new std::thread([this]() { worker_thread_function(); });
Expand Down
2 changes: 1 addition & 1 deletion isobus/src/isobus_virtual_terminal_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ namespace isobus
{
languageCommandInterface.initialize();
}
#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO && !defined USE_CMSIS_RTOS2_THREADING
if (spawnThread)
{
workerThread = new std::thread([this]() { worker_thread_function(); });
Expand Down
169 changes: 169 additions & 0 deletions utility/include/isobus/utility/thread_synchronization.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,175 @@ namespace isobus
/// @brief Disabled LOCK_GUARD macro since threads are disabled.
#define LOCK_GUARD(type, x)

#elif defined USE_CMSIS_RTOS2_THREADING

#include "cmsis_os.h"

namespace isobus
{
/// @brief A wrapper around a CMSIS RTOS 2 mutex.
/// @details See definition at https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS.html
class Mutex
{
public:
/// @brief Constructor for the CMSIS RTOS2 mutex wrapper
Mutex() :
handle(nullptr)
{
}

/// @brief Locks the mutex. Part of BasicLockable requirements.
void lock()
{
if (ready())
{
osStatus_t osRetVal = osMutexAcquire(handle, osWaitForever);

if (osOK != osRetVal)
{
while (true)
{
// If your code is stuck in here, that means you did something
// very wrong, like recursively locked this mutex, or tried to
// lock the mutex before the OS was initialized, or called this in
// an interrupt service routine.
// osRetVal may contain more information.
}
}
}
}

/// @brief Attempts to the mutex, and doesn't wait if it's not available.
/// @returns true if the mutex was successfully locked, false otherwise.
bool try_lock()
{
bool retVal = false;

if (ready())
{
osStatus_t osRetVal = osMutexAcquire(handle, 0);
retVal = (osOK == osRetVal);
}
return retVal;
}

/// @brief Unlocks the mutex. Part of BasicLockable requirements.
void unlock()
{
if (nullptr != handle)
{
osStatus_t osRetVal = osMutexRelease(handle);

if (osOK != osRetVal)
{
while (true)
{
// If your code is stuck in here, that means you
// either tried to release a mutex which is owned by a different thread,
// or the release failed due to some other OS reason.
// osRetVal may contain more information.
}
}
}
else
{
while (true)
{
// If your code is stuck in here, it's because you tried to unlock a
// mutex which doesn't exist. Don't do that.
// osRetVal may contain more information.
}
}
}

protected:
/// @brief Checks if the mutex is ready to be used. Initializes the mutex if it's not.
/// @returns true if the mutex is ready to be used, false otherwise.
virtual bool ready()
{
if (nullptr == handle)
{
const osMutexAttr_t attributes = {
nullptr,
#ifdef osCMSIS_FreeRTOS // FreeRTOS doesn't support robust mutexes
osMutexPrioInherit,
#else
osMutexPrioInherit | osMutexRobust,
#endif
nullptr,
0
};
handle = osMutexNew(&attributes);
}
return nullptr != handle;
}
osMutexId_t handle; ///< Mutex ID for reference by other functions or NULL in case of error or not yet initialized
};

/// @brief A wrapper around a CMSIS RTOS 2 recursive mutex.
/// @details See definition at https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS.html
class RecursiveMutex : public Mutex
{
protected:
/// @brief Checks if the mutex is ready to be used.
/// Initializes the mutex if it's not.
/// @returns true if the mutex is ready to be used, false otherwise.
bool ready() override
{
if (nullptr == handle)
{
const osMutexAttr_t attributes = {
nullptr,
#ifdef osCMSIS_FreeRTOS // FreeRTOS doesn't support robust mutexes
osMutexPrioInherit | osMutexRecursive,
#else
osMutexPrioInherit | osMutexRobust | osMutexRecursive,
#endif
nullptr,
0
};
handle = osMutexNew(&attributes);
}
return nullptr != handle;
}
};

template<class T>
/// @brief A class to automatically lock and unlock a mutex when the scope ends.
/// Meant for systems with no support for std::lock_guard.
class LockGuard
{
public:
/// @brief Constructor for the LockGuard class.
/// @param mutex The mutex to lock.
/// @details Locks the mutex when the scope starts.
/// Unlocks the mutex when the scope ends.
LockGuard(T *mutex) :
lockable(mutex)
{
lockable->lock();
}

/// @brief Destructor for the LockGuard class.
/// @details Unlocks the mutex when the scope ends.
~LockGuard()
{
lockable->unlock();
}

private:
T *lockable; ///< The mutex to lock and unlock.
};
} // namespace isobus

namespace std
{
using mutex = isobus::Mutex;
using recursive_mutex = isobus::RecursiveMutex;
} // namespace std

#define LOCK_GUARD(type, x) const LockGuard<type> x##Lock(&x)

#else

#include <mutex>
Expand Down

0 comments on commit af62b24

Please sign in to comment.