Initial UI setup
This commit is contained in:
45
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/I2CBus.h
Normal file
45
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/I2CBus.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ICommBus.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <expected>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class I2CBus : public ICommBus
|
||||
{
|
||||
public:
|
||||
using ReadBuf = std::span<uint8_t>;
|
||||
using WriteBuf = std::span<const uint8_t>;
|
||||
using Timeout = std::chrono::milliseconds;
|
||||
using ReturnType = std::expected<size_t, ReturnStatus>;
|
||||
|
||||
public:
|
||||
I2CBus() = default; // Default constructor
|
||||
virtual ~I2CBus() override = default; // Default destructor
|
||||
I2CBus(const I2CBus &) = delete; // Copy constructor
|
||||
I2CBus(I2CBus &&) = delete; // Move constructor
|
||||
I2CBus &operator=(const I2CBus &) = delete; // Copy assignment operator
|
||||
I2CBus &operator=(I2CBus &&) = delete; // Move assignment operator
|
||||
|
||||
virtual ReturnType write(uint8_t address, WriteBuf buf, Timeout timeout) const = 0; // Write data to I2C device
|
||||
virtual ReturnType read(uint8_t address, ReadBuf buf, Timeout timeout) const = 0; // Read data from I2C device
|
||||
virtual ReturnStatus isDeviceReady(uint8_t address) const = 0; // Check if I2C device is ready
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::comm
|
||||
62
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/I2CDevice.h
Normal file
62
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/I2CDevice.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "I2CBus.h"
|
||||
#include "ICommDevice.h"
|
||||
|
||||
namespace sdi_uToolBox::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class I2CDevice : public ICommDevice
|
||||
{
|
||||
public:
|
||||
I2CDevice() = delete; // Default constructor
|
||||
explicit I2CDevice(I2CBus &bus, uint8_t address); // Constructor
|
||||
virtual ~I2CDevice() override = default; // Default destructor
|
||||
I2CDevice(const I2CDevice &) = delete; // Copy constructor
|
||||
I2CDevice &operator=(const I2CDevice &) = delete; // Copy assignment operator
|
||||
I2CDevice(I2CDevice &&) = delete; // Move constructor
|
||||
I2CDevice &operator=(I2CDevice &&) = delete; // Move assignment operator
|
||||
|
||||
ReturnType write(WriteBuf buf, Timeout timeout) override; // Write data to device
|
||||
ReturnType read(ReadBuf buf, Timeout timeout) override; // Read data from device
|
||||
|
||||
protected:
|
||||
I2CBus &m_bus; // Reference to I2C bus
|
||||
uint8_t m_address; // I2C device address
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline I2CDevice::I2CDevice(I2CBus &bus, const uint8_t address)
|
||||
: m_bus(bus)
|
||||
, m_address(address)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to device */
|
||||
inline ICommDevice::ReturnType I2CDevice::write(const WriteBuf buf, const Timeout timeout)
|
||||
{
|
||||
return m_bus.write(m_address, buf, timeout);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from device */
|
||||
inline ICommDevice::ReturnType I2CDevice::read(const ReadBuf buf, const Timeout timeout)
|
||||
{
|
||||
return m_bus.read(m_address, buf, timeout);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::comm
|
||||
34
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/ICommBus.h
Normal file
34
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/ICommBus.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../defs.h"
|
||||
|
||||
namespace sdi_uToolBox::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class ICommBus
|
||||
{
|
||||
public:
|
||||
ICommBus() = default; // Default constructor
|
||||
virtual ~ICommBus() = default; // Default destructor
|
||||
ICommBus(const ICommBus &) = delete; // Copy constructor
|
||||
ICommBus &operator=(const ICommBus &) = delete; // Copy assignment operator
|
||||
ICommBus(ICommBus &&) = delete; // Move constructor
|
||||
ICommBus &operator=(ICommBus &&) = delete; // Move assignment operator
|
||||
|
||||
virtual ReturnStatus open() = 0; // Open communication bus
|
||||
virtual ReturnStatus close() = 0; // Close communication bus
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::comm
|
||||
46
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/ICommDevice.h
Normal file
46
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/ICommDevice.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../defs.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <expected>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class ICommDevice
|
||||
{
|
||||
public:
|
||||
using ReadBuf = std::span<uint8_t>;
|
||||
using WriteBuf = std::span<const uint8_t>;
|
||||
using Timeout = std::chrono::milliseconds;
|
||||
using ReturnType = std::expected<size_t, ReturnStatus>;
|
||||
|
||||
static constexpr auto INFINITE_DURATION = Timeout(-1);
|
||||
|
||||
public:
|
||||
ICommDevice() = default; // Default constructor
|
||||
virtual ~ICommDevice() = default; // Default destructor
|
||||
ICommDevice(const ICommDevice &) = delete; // Copy constructor
|
||||
ICommDevice &operator=(const ICommDevice &) = delete; // Copy assignment operator
|
||||
ICommDevice(ICommDevice &&) = delete; // Move constructor
|
||||
ICommDevice &operator=(ICommDevice &&) = delete; // Move assignment operator
|
||||
|
||||
virtual ReturnType write(WriteBuf buf, Timeout timeout = INFINITE_DURATION) = 0; // Write data to device
|
||||
virtual ReturnType read(ReadBuf buf, Timeout timeout = INFINITE_DURATION) = 0; // Read data from device
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::comm
|
||||
47
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/SerialBus.h
Normal file
47
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/SerialBus.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//{{copyright}}
|
||||
|
||||
//{{version}}
|
||||
|
||||
//{{license}}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ICommBus.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <expected>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class SerialBus : public ICommBus
|
||||
{
|
||||
public:
|
||||
using ReadBuf = std::span<uint8_t>;
|
||||
using WriteBuf = std::span<const uint8_t>;
|
||||
using Timeout = std::chrono::milliseconds;
|
||||
using ReturnType = std::expected<size_t, ReturnStatus>;
|
||||
|
||||
public:
|
||||
SerialBus() = default; // Default constructor
|
||||
virtual ~SerialBus() override = default; // Default destructor
|
||||
SerialBus(const SerialBus&) = delete; // Copy constructor
|
||||
SerialBus(SerialBus&&) = delete; // Move constructor
|
||||
SerialBus& operator=(const SerialBus&) = delete; // Copy assignment operator
|
||||
SerialBus& operator=(SerialBus&&) = delete; // Move assignment operator
|
||||
|
||||
virtual ReturnType write(WriteBuf buf, Timeout timeout) const = 0; // Write data to UART device
|
||||
virtual ReturnType read(ReadBuf buf, Timeout timeout) const = 0; // Read data from UART device
|
||||
virtual ReturnType readUntilIdle(ReadBuf buf, Timeout timeout) const; // Read data until IDLE event
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Read data until IDLE event */
|
||||
inline SerialBus::ReturnType SerialBus::readUntilIdle(ReadBuf buf, Timeout timeout) const
|
||||
{
|
||||
return std::unexpected(ReturnStatus::IncompatibleBaseType);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::comm
|
||||
51
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/UARTBus.h
Normal file
51
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/comm/UARTBus.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ICommBus.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <expected>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class UARTBus : public ICommBus
|
||||
{
|
||||
public:
|
||||
using ReadBuf = std::span<uint8_t>;
|
||||
using WriteBuf = std::span<const uint8_t>;
|
||||
using Timeout = std::chrono::milliseconds;
|
||||
using ReturnType = std::expected<size_t, ReturnStatus>;
|
||||
|
||||
public:
|
||||
UARTBus() = default; // Default constructor
|
||||
virtual ~UARTBus() override = default; // Default destructor
|
||||
UARTBus(const UARTBus &) = delete; // Copy constructor
|
||||
UARTBus(UARTBus &&) = delete; // Move constructor
|
||||
UARTBus &operator=(const UARTBus &) = delete; // Copy assignment operator
|
||||
UARTBus &operator=(UARTBus &&) = delete; // Move assignment operator
|
||||
|
||||
virtual ReturnType write(WriteBuf buf, Timeout timeout) const = 0; // Write data to UART device
|
||||
virtual ReturnType read(ReadBuf buf, Timeout timeout) const = 0; // Read data from UART device
|
||||
virtual ReturnType readUntilIdle(ReadBuf buf, Timeout timeout) const; // Read data until IDLE event
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Read data until IDLE event */
|
||||
inline UARTBus::ReturnType UARTBus::readUntilIdle(ReadBuf buf, Timeout timeout) const
|
||||
{
|
||||
return std::unexpected(ReturnStatus::IncompatibleBaseType);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::comm
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <FreeRTOSHeaders.h>
|
||||
#include <sdi_toolBox/dateTime/iPause.h>
|
||||
|
||||
namespace sdi_uToolBox::dateTime::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @brief FreeRTOS pause implementation.
|
||||
*
|
||||
* Implements IPause to provide a non-blocking pause using vTaskDelay
|
||||
* in FreeRTOS environments.
|
||||
*/
|
||||
class Pause : public sdi_toolBox::dateTime::IPause
|
||||
{
|
||||
public:
|
||||
Pause() = default; // Default constructor
|
||||
~Pause() = default; // Default destructor
|
||||
Pause(const Pause &obj) = default; // Copy constructor
|
||||
Pause(Pause &&obj) noexcept = default; // Move constructor
|
||||
Pause &operator=(const Pause &obj) = default; // Copy assignment operator
|
||||
Pause &operator=(Pause &&obj) noexcept = default; // Move assignment operator
|
||||
|
||||
explicit Pause(const Duration &duration); // Constructor
|
||||
|
||||
/**
|
||||
* @brief Pause execution for the specified duration using vTaskDelay.
|
||||
* @param duration Duration of the pause.
|
||||
*/
|
||||
void wait(const Duration &duration) const override;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline Pause::Pause(const Duration &duration)
|
||||
{
|
||||
wait(duration);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Pause execution for the specified duration */
|
||||
inline void Pause::wait(const Duration &duration) const
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(duration.count()));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::dateTime::FreeRTOS
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <FreeRTOSHeaders.h>
|
||||
#include <sdi_toolBox/dateTime/iTimer.h>
|
||||
|
||||
namespace sdi_uToolBox::dateTime::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @brief FreeRTOS timer implementation using the RTOS tick count.
|
||||
*
|
||||
* Implements ITimer for FreeRTOS environments, using xTaskGetTickCount()
|
||||
* to provide timing based on the RTOS tick counter.
|
||||
*/
|
||||
class Timer : public sdi_toolBox::dateTime::ITimer
|
||||
{
|
||||
public:
|
||||
Timer(); // Default constructor
|
||||
~Timer() = default; // Default destructor
|
||||
Timer(const Timer &obj) = default; // Copy constructor
|
||||
Timer(Timer &&obj) noexcept = default; // Move constructor
|
||||
Timer &operator=(const Timer &obj) = default; // Copy assignment operator
|
||||
Timer &operator=(Timer &&obj) noexcept = default; // Move assignment operator
|
||||
|
||||
/**
|
||||
* @brief Returns the current time point using the FreeRTOS tick count.
|
||||
* @return The current time point.
|
||||
*/
|
||||
[[nodiscard]] TimePoint now() const override;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Default constructor */
|
||||
inline Timer::Timer()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the current timepoint */
|
||||
inline Timer::TimePoint Timer::now() const
|
||||
{
|
||||
const auto ms = xTaskGetTickCount() * portTICK_PERIOD_MS;
|
||||
return TimePoint(Duration(ms));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::dateTime::FreeRTOS
|
||||
58
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/dateTime/pause.h
Normal file
58
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/dateTime/pause.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <STM32Headers.h>
|
||||
#include <sdi_toolBox/dateTime/iPause.h>
|
||||
|
||||
namespace sdi_uToolBox::dateTime
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @brief STM32 pause implementation.
|
||||
*
|
||||
* Implements IPause to provide a blocking pause using HAL_Delay
|
||||
* on STM32 platforms.
|
||||
*/
|
||||
class Pause : public sdi_toolBox::dateTime::IPause
|
||||
{
|
||||
public:
|
||||
Pause() = default; // Default constructor
|
||||
~Pause() = default; // Default destructor
|
||||
Pause(const Pause &obj) = default; // Copy constructor
|
||||
Pause(Pause &&obj) noexcept = default; // Move constructor
|
||||
Pause &operator=(const Pause &obj) = default; // Copy assignment operator
|
||||
Pause &operator=(Pause &&obj) noexcept = default; // Move assignment operator
|
||||
|
||||
explicit Pause(const Duration &duration); // Constructor
|
||||
|
||||
/**
|
||||
* @brief Pause execution for the specified duration using HAL_Delay.
|
||||
* @param duration Duration of the pause.
|
||||
*/
|
||||
void wait(const Duration &duration) const override;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline Pause::Pause(const Duration &duration)
|
||||
{
|
||||
wait(duration);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Pause execution for the specified duration */
|
||||
inline void Pause::wait(const Duration &duration) const
|
||||
{
|
||||
HAL_Delay(duration.count());
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::dateTime
|
||||
57
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/dateTime/timer.h
Normal file
57
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/dateTime/timer.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <STM32Headers.h>
|
||||
#include <sdi_toolBox/dateTime/iTimer.h>
|
||||
|
||||
namespace sdi_uToolBox::dateTime
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @brief STM32 timer implementation using HAL_GetTick().
|
||||
*
|
||||
* Implements ITimer for STM32 platforms, using HAL_GetTick() to
|
||||
* provide millisecond-precision timing since system startup.
|
||||
*/
|
||||
class Timer : public sdi_toolBox::dateTime::ITimer
|
||||
{
|
||||
public:
|
||||
Timer(); // Default constructor
|
||||
~Timer() = default; // Default destructor
|
||||
Timer(const Timer &obj) = default; // Copy constructor
|
||||
Timer(Timer &&obj) noexcept = default; // Move constructor
|
||||
Timer &operator=(const Timer &obj) = default; // Copy assignment operator
|
||||
Timer &operator=(Timer &&obj) noexcept = default; // Move assignment operator
|
||||
|
||||
/**
|
||||
* @brief Returns the current time point using HAL_GetTick().
|
||||
* @return The current time point.
|
||||
*/
|
||||
[[nodiscard]] TimePoint now() const override;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Default constructor */
|
||||
inline Timer::Timer()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get the current timepoint */
|
||||
inline Timer::TimePoint Timer::now() const
|
||||
{
|
||||
const auto ms = HAL_GetTick();
|
||||
return TimePoint(Duration(ms));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::dateTime
|
||||
26
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/defs.h
Normal file
26
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/defs.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//{{copyright}}
|
||||
|
||||
//{{version}}
|
||||
|
||||
//{{license}}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace sdi_uToolBox
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/* Return status enumeration */
|
||||
enum class ReturnStatus : uint8_t
|
||||
{
|
||||
Ok,
|
||||
Busy,
|
||||
Timeout,
|
||||
Error,
|
||||
IncompatibleBaseType,
|
||||
InvalidHandle,
|
||||
BufferOverflow,
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox
|
||||
154
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/FreeRTOS/mutex.h
Normal file
154
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/FreeRTOS/mutex.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <FreeRTOSHeaders.h>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
namespace sdi_uToolBox::generic::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class Mutex
|
||||
{
|
||||
public:
|
||||
Mutex(); // Constructor
|
||||
~Mutex(); // Destructor
|
||||
Mutex(const Mutex &other) = delete; // Copy constructor
|
||||
Mutex(Mutex &&other) = delete; // Move constructor
|
||||
Mutex &operator=(const Mutex &other) = delete; // Copy assignment
|
||||
Mutex &operator=(Mutex &&other) = delete; // Move assignment
|
||||
|
||||
void lock() const; // Locks the mutex, blocks if the mutex is not available
|
||||
void unlock() const; // Unlocks the mutex
|
||||
bool try_lock() const; // Tries to lock the mutex, returns if the mutex is not available
|
||||
bool try_lock_for(const std::chrono::milliseconds &duration) const; // Attempts to lock the mutex, returns if the mutex is not available
|
||||
|
||||
protected:
|
||||
SemaphoreHandle_t m_xSemaphore = nullptr;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline Mutex::Mutex()
|
||||
{
|
||||
m_xSemaphore = xSemaphoreCreateMutex();
|
||||
configASSERT(m_xSemaphore);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Destructor */
|
||||
inline Mutex::~Mutex()
|
||||
{
|
||||
if (!m_xSemaphore)
|
||||
vSemaphoreDelete(m_xSemaphore);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Locks the mutex, blocks if the mutex is not available */
|
||||
inline void Mutex::lock() const
|
||||
{
|
||||
if (xSemaphoreTake(m_xSemaphore, portMAX_DELAY) != pdTRUE)
|
||||
configASSERT(0);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Unlocks the mutex */
|
||||
inline void Mutex::unlock() const
|
||||
{
|
||||
xSemaphoreGive(m_xSemaphore);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Tries to lock the mutex, returns if the mutex is not available */
|
||||
inline bool Mutex::try_lock() const
|
||||
{
|
||||
return try_lock_for(std::chrono::milliseconds(0));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Attempts to lock the mutex, returns if the mutex has been unavailable for the specified time duration */
|
||||
inline bool Mutex::try_lock_for(const std::chrono::milliseconds &duration) const
|
||||
{
|
||||
const auto waitDelay = pdMS_TO_TICKS(duration.count());
|
||||
|
||||
if (xSemaphoreTakeRecursive(m_xSemaphore, waitDelay) == pdTRUE)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
class RecursiveMutex
|
||||
{
|
||||
public:
|
||||
RecursiveMutex(); // Constructor
|
||||
~RecursiveMutex(); // Destructor
|
||||
RecursiveMutex(const RecursiveMutex &other) = delete; // Copy constructor
|
||||
RecursiveMutex(RecursiveMutex &&other) = delete; // Move constructor
|
||||
RecursiveMutex &operator=(const RecursiveMutex &other) = delete; // Copy assignment
|
||||
RecursiveMutex &operator=(RecursiveMutex &&other) = delete; // Move assignment
|
||||
|
||||
void lock() const; // Locks the mutex, blocks if the mutex is not available
|
||||
void unlock() const; // Unlocks the mutex
|
||||
bool try_lock() const; // Tries to lock the mutex, returns if the mutex is not available
|
||||
bool try_lock_for(const std::chrono::milliseconds &duration) const; // Attempts to lock the mutex, returns if the mutex is not available
|
||||
|
||||
protected:
|
||||
SemaphoreHandle_t m_xSemaphore = nullptr;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline RecursiveMutex::RecursiveMutex()
|
||||
{
|
||||
m_xSemaphore = xSemaphoreCreateRecursiveMutex();
|
||||
configASSERT(m_xSemaphore);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Destructor */
|
||||
inline RecursiveMutex::~RecursiveMutex()
|
||||
{
|
||||
if (!m_xSemaphore)
|
||||
vSemaphoreDelete(m_xSemaphore);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Locks the mutex, blocks if the mutex is not available */
|
||||
inline void RecursiveMutex::lock() const
|
||||
{
|
||||
if (xSemaphoreTakeRecursive(m_xSemaphore, portMAX_DELAY) != pdTRUE)
|
||||
configASSERT(0);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Unlocks the mutex */
|
||||
inline void RecursiveMutex::unlock() const
|
||||
{
|
||||
xSemaphoreGiveRecursive(m_xSemaphore);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Tries to lock the mutex, returns if the mutex is not available */
|
||||
inline bool RecursiveMutex::try_lock() const
|
||||
{
|
||||
return try_lock_for(std::chrono::milliseconds(0));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Attempts to lock the mutex, returns if the mutex has been unavailable for the specified time duration */
|
||||
inline bool RecursiveMutex::try_lock_for(const std::chrono::milliseconds &duration) const
|
||||
{
|
||||
const auto waitDelay = pdMS_TO_TICKS(duration.count());
|
||||
|
||||
if (xSemaphoreTakeRecursive(m_xSemaphore, waitDelay) == pdTRUE)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::generic::FreeRTOS
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <FreeRTOSHeaders.h>
|
||||
#include <chrono>
|
||||
|
||||
namespace sdi_uToolBox::generic::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class Semaphore
|
||||
{
|
||||
using Timeout = std::chrono::milliseconds;
|
||||
|
||||
public:
|
||||
Semaphore() = delete; // Default constructor
|
||||
~Semaphore(); // Default destructor
|
||||
Semaphore(const Semaphore &other) = delete; // Copy constructor
|
||||
Semaphore(Semaphore &&other) = delete; // Move constructor
|
||||
Semaphore &operator=(const Semaphore &other) = delete; // Copy assignment
|
||||
Semaphore &operator=(Semaphore &&other) = delete; // Move assignment
|
||||
|
||||
explicit Semaphore(size_t maxCount = 1, size_t initialCount = 0); // Constructor
|
||||
|
||||
bool give() const; // Give/release the semaphore
|
||||
bool giveFromISR() const; // Give/release the semaphore from ISR
|
||||
bool take(Timeout timeout) const; // Take/acquire the semaphore with timeout
|
||||
bool take() const; // Take/acquire the semaphore without timeout (blocking)
|
||||
|
||||
protected:
|
||||
SemaphoreHandle_t m_xSemaphore = nullptr;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline Semaphore::Semaphore(const size_t maxCount, const size_t initialCount)
|
||||
{
|
||||
if (maxCount == 1)
|
||||
{
|
||||
// Binary semaphore
|
||||
m_xSemaphore = xSemaphoreCreateBinary();
|
||||
if (m_xSemaphore && initialCount > 0)
|
||||
xSemaphoreGive(m_xSemaphore);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Counting semaphore
|
||||
m_xSemaphore = xSemaphoreCreateCounting(maxCount, initialCount);
|
||||
}
|
||||
configASSERT(m_xSemaphore);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Default destructor */
|
||||
inline Semaphore::~Semaphore()
|
||||
{
|
||||
if (m_xSemaphore)
|
||||
vSemaphoreDelete(m_xSemaphore);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Give/release the semaphore */
|
||||
inline bool Semaphore::give() const
|
||||
{
|
||||
return xSemaphoreGive(m_xSemaphore) == pdTRUE;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Give/release the semaphore from ISR */
|
||||
inline bool Semaphore::giveFromISR() const
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
const bool result = xSemaphoreGiveFromISR(m_xSemaphore, &xHigherPriorityTaskWoken) == pdTRUE;
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // Request a context switch if needed
|
||||
return result;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Take/acquire the semaphore with timeout */
|
||||
inline bool Semaphore::take(const Timeout timeout) const
|
||||
{
|
||||
const TickType_t xTicksToWait = (timeout.count() == 0) ? 0 : pdMS_TO_TICKS(timeout.count());
|
||||
return xSemaphoreTake(m_xSemaphore, xTicksToWait) == pdTRUE;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Take/acquire the semaphore without timeout (blocking) */
|
||||
inline bool Semaphore::take() const
|
||||
{
|
||||
return xSemaphoreTake(m_xSemaphore, portMAX_DELAY) == pdTRUE;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Binary Semaphore helper class */
|
||||
class BinarySemaphore : public Semaphore
|
||||
{
|
||||
public:
|
||||
explicit BinarySemaphore(const bool initialState = false)
|
||||
: Semaphore(1, initialState ? 1 : 0)
|
||||
{
|
||||
}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
class CountingSemaphore : public Semaphore
|
||||
{
|
||||
/* Counting Semaphore helper class */
|
||||
public:
|
||||
explicit CountingSemaphore(const uint32_t maxCount, const uint32_t initialCount = 0)
|
||||
: Semaphore(maxCount, initialCount)
|
||||
{
|
||||
}
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::generic::FreeRTOS
|
||||
154
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/FreeRTOS/task.h
Normal file
154
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/FreeRTOS/task.h
Normal file
@@ -0,0 +1,154 @@
|
||||
//{{copyright}}
|
||||
|
||||
//{{version}}
|
||||
|
||||
//{{license}}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <FreeRTOSHeaders.h>
|
||||
#include <string>
|
||||
|
||||
namespace sdi_uToolBox::generic::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class Task
|
||||
{
|
||||
public:
|
||||
Task() = default; // Constructor
|
||||
virtual ~Task(); // Destructor
|
||||
Task(const Task &other) = delete; // Copy constructor
|
||||
Task(Task &&other) noexcept = delete; // Move constructor
|
||||
Task &operator=(const Task &other) = delete; // Copy assignment
|
||||
Task &operator=(Task &&other) noexcept = delete; // Move assignment
|
||||
|
||||
bool startTask(); // Create and start a FreeRTOS task
|
||||
void stopTask(); // Stop and destroy the task
|
||||
[[nodiscard]] bool isTaskRunning() const; // Return true if the task is running
|
||||
[[nodiscard]] TaskHandle_t getTaskHandle() const; // Return the task handle
|
||||
|
||||
protected:
|
||||
TaskHandle_t m_taskHandle = nullptr;
|
||||
|
||||
virtual void on_taskCreated(); // Function called after successful task creation (before execution)
|
||||
virtual void on_taskStarted(); // Function called after task starts
|
||||
virtual void on_taskStopped(); // Function called before task stops
|
||||
|
||||
private:
|
||||
virtual void processTask() = 0; // Task implementation
|
||||
[[nodiscard]] virtual std::string getTaskName() const; // Return a name for the task
|
||||
[[nodiscard]] virtual size_t getTaskStackSize() const; // Return stack size in words, not bytes
|
||||
[[nodiscard]] virtual size_t getTaskPriority() const; // Return priority at which the task is created
|
||||
|
||||
bool m_runningFlag = false;
|
||||
|
||||
static void taskCode(void *pThis); // Task implementation
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Destructor */
|
||||
inline Task::~Task()
|
||||
{
|
||||
stopTask();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Create and start a FreeRTOS task */
|
||||
inline bool Task::startTask()
|
||||
{
|
||||
if (isTaskRunning())
|
||||
return true;
|
||||
|
||||
const auto xReturned = xTaskCreate(taskCode, // Function that implements the task
|
||||
getTaskName().c_str(), // Text name for the task
|
||||
getTaskStackSize(), // Stack size in words, not bytes
|
||||
(void *)this, // Parameter passed into the task
|
||||
getTaskPriority(), // Priority at which the task is created
|
||||
&m_taskHandle); // Used to pass out the created task's handle
|
||||
|
||||
m_runningFlag = (xReturned == pdPASS);
|
||||
|
||||
if (m_runningFlag)
|
||||
on_taskCreated();
|
||||
|
||||
return m_runningFlag;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Stop and destroy the task */
|
||||
inline void Task::stopTask()
|
||||
{
|
||||
if (m_taskHandle)
|
||||
vTaskDelete(m_taskHandle);
|
||||
|
||||
m_taskHandle = nullptr;
|
||||
m_runningFlag = false;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return true if the task is running */
|
||||
inline bool Task::isTaskRunning() const
|
||||
{
|
||||
return m_runningFlag;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return the task handle */
|
||||
inline TaskHandle_t Task::getTaskHandle() const
|
||||
{
|
||||
return m_taskHandle;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Function called after successful task creation (before execution) */
|
||||
inline void Task::on_taskCreated()
|
||||
{
|
||||
// Nothing to do...
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Function called after task starts */
|
||||
inline void Task::on_taskStarted()
|
||||
{
|
||||
// Nothing to do...
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Function called after before stops */
|
||||
inline void Task::on_taskStopped()
|
||||
{
|
||||
// Nothing to do...
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return a name for the task */
|
||||
inline std::string Task::getTaskName() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return stack size in words, not bytes */
|
||||
inline size_t Task::getTaskStackSize() const
|
||||
{
|
||||
return configMINIMAL_STACK_SIZE;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return priority at which the task is created */
|
||||
inline size_t Task::getTaskPriority() const
|
||||
{
|
||||
return tskIDLE_PRIORITY + 1;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Task implementation */
|
||||
inline void Task::taskCode(void *pThis)
|
||||
{
|
||||
const auto task = static_cast<Task *>(pThis);
|
||||
|
||||
// At task starts
|
||||
if (task->m_runningFlag)
|
||||
task->on_taskStarted();
|
||||
|
||||
// Main task loop
|
||||
while (task->m_runningFlag)
|
||||
task->processTask();
|
||||
|
||||
// At task stops
|
||||
task->on_taskStopped();
|
||||
|
||||
task->stopTask();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::generic::FreeRTOS
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../defs.h"
|
||||
|
||||
#include <FreeRTOSHeaders.h>
|
||||
#include <algorithm>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::generic::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
/**
|
||||
* @class TaskInspector
|
||||
* @brief Utility class for inspecting FreeRTOS task statistics and runtime information.
|
||||
*
|
||||
* This class provides static methods to retrieve information about tasks,
|
||||
* such as their name, priority, runtime statistics, and stack usage.
|
||||
* It is designed for embedded systems and avoids dynamic memory allocation.
|
||||
*
|
||||
* @note Required FreeRTOSConfig.h options:
|
||||
* - configUSE_TRACE_FACILITY must be set to 1
|
||||
* - configUSE_RECURSIVE_MUTEXES must be set to 1
|
||||
*/
|
||||
class TaskInspector
|
||||
{
|
||||
static constexpr size_t MAX_TASKS = 16;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @struct TaskInfo
|
||||
* @brief Structure holding detailed information about a FreeRTOS task.
|
||||
*/
|
||||
struct TaskInfo
|
||||
{
|
||||
const char *taskName = nullptr; // Task name
|
||||
UBaseType_t currentPriority = 0; // Task current priority
|
||||
UBaseType_t basePriority = 0; // Task base priority
|
||||
uint32_t runTimeCounter = 0; // Total run time counter
|
||||
eTaskState currentState = eInvalid; // Task state
|
||||
UBaseType_t stackHighWaterMark = 0; // Stack high watermark
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct RuntimeStats
|
||||
* @brief Structure holding global runtime statistics for all tasks.
|
||||
*/
|
||||
struct RuntimeStats
|
||||
{
|
||||
uint32_t totalRunTime = 0; // Total run time of all tasks
|
||||
uint32_t numberOfTasks = 0; // Number of tasks
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct TaskRuntimeStat
|
||||
* @brief Structure holding runtime statistics for a single task.
|
||||
*/
|
||||
struct TaskRuntimeStat
|
||||
{
|
||||
const char *taskName = nullptr; // Task name
|
||||
uint32_t runTimeCounter = 0; // Total run time counter
|
||||
Real cpuUsage = 0.0f; // CPU usage percentage
|
||||
};
|
||||
|
||||
public:
|
||||
TaskInspector() = delete; // Default constructor
|
||||
~TaskInspector() = default; // Default destructor
|
||||
TaskInspector(const TaskInspector &obj) = delete; // Copy constructor
|
||||
TaskInspector(TaskInspector &&obj) noexcept = delete; // Move constructor
|
||||
TaskInspector &operator=(const TaskInspector &obj) = delete; // Copy assignment operator
|
||||
TaskInspector &operator=(TaskInspector &&obj) noexcept = delete; // Move assignment operator
|
||||
|
||||
/**
|
||||
* @brief Retrieves information about a specific task or the current task if no handle is provided.
|
||||
* @param taskHandle The handle of the task to inspect (optional).
|
||||
* @return TaskInfo structure with the task's information.
|
||||
*/
|
||||
[[nodiscard]] static TaskInfo getTaskInfo(TaskHandle_t taskHandle = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Retrieves global runtime statistics for all tasks.
|
||||
* @return RuntimeStats structure with the global runtime statistics.
|
||||
*/
|
||||
[[nodiscard]] static RuntimeStats GetRuntimeStats();
|
||||
|
||||
/**
|
||||
* @brief Retrieves the number of tasks currently running.
|
||||
* @return The number of tasks.
|
||||
*/
|
||||
[[nodiscard]] static size_t GetTaskCount();
|
||||
|
||||
/**
|
||||
* @brief Retrieves runtime statistics for all tasks.
|
||||
* @param statsArray A span to an array where task runtime statistics will be stored.
|
||||
* @return The number of tasks for which statistics were retrieved.
|
||||
*/
|
||||
[[nodiscard]] static size_t GetTasksRuntimeStats(std::span<TaskRuntimeStat> statsArray);
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Retrieves information about the current task */
|
||||
inline TaskInspector::TaskInfo TaskInspector::getTaskInfo(TaskHandle_t taskHandle)
|
||||
{
|
||||
#if (configUSE_RECURSIVE_MUTEXES != 1)
|
||||
# error "configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h"
|
||||
#endif
|
||||
#if (configUSE_TRACE_FACILITY != 1)
|
||||
# error "configUSE_TRACE_FACILITY must be set to 1 in FreeRTOSConfig.h"
|
||||
#endif
|
||||
|
||||
TaskInfo taskInfo;
|
||||
if (!taskHandle)
|
||||
{
|
||||
taskHandle = xTaskGetCurrentTaskHandle();
|
||||
if (!taskHandle)
|
||||
return taskInfo;
|
||||
}
|
||||
|
||||
// Get task info
|
||||
TaskStatus_t taskStatus;
|
||||
vTaskGetInfo(taskHandle, &taskStatus, pdTRUE, eInvalid);
|
||||
|
||||
// Fill task info structure
|
||||
taskInfo.taskName = taskStatus.pcTaskName;
|
||||
taskInfo.currentPriority = taskStatus.uxCurrentPriority;
|
||||
taskInfo.basePriority = taskStatus.uxBasePriority;
|
||||
taskInfo.runTimeCounter = taskStatus.ulRunTimeCounter;
|
||||
taskInfo.currentState = taskStatus.eCurrentState;
|
||||
taskInfo.stackHighWaterMark = taskStatus.usStackHighWaterMark;
|
||||
|
||||
return taskInfo;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Retrieves global runtime statistics for all tasks */
|
||||
inline TaskInspector::RuntimeStats TaskInspector::GetRuntimeStats()
|
||||
{
|
||||
#if (configUSE_TRACE_FACILITY != 1)
|
||||
# error "configUSE_TRACE_FACILITY must be set to 1 in FreeRTOSConfig.h"
|
||||
#endif
|
||||
|
||||
RuntimeStats stats;
|
||||
stats.numberOfTasks = uxTaskGetNumberOfTasks();
|
||||
uxTaskGetSystemState(nullptr, 0, &stats.totalRunTime);
|
||||
return stats;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Retrieves the number of tasks */
|
||||
inline size_t TaskInspector::GetTaskCount()
|
||||
{
|
||||
return uxTaskGetNumberOfTasks();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Retrieves runtime statistics for all tasks */
|
||||
inline size_t TaskInspector::GetTasksRuntimeStats(std::span<TaskRuntimeStat> statsArray)
|
||||
{
|
||||
#if (configUSE_TRACE_FACILITY != 1)
|
||||
# error "configUSE_TRACE_FACILITY must be set to 1 in FreeRTOSConfig.h"
|
||||
#endif
|
||||
|
||||
size_t numTasks = uxTaskGetNumberOfTasks();
|
||||
numTasks = std::min({ numTasks, statsArray.size(), MAX_TASKS });
|
||||
|
||||
TaskStatus_t statusArray[MAX_TASKS];
|
||||
uint32_t totalRunTime = 0;
|
||||
uxTaskGetSystemState(statusArray, numTasks, &totalRunTime);
|
||||
|
||||
for (size_t i = 0; i < numTasks; i++)
|
||||
{
|
||||
auto &stat = statsArray[i];
|
||||
stat.taskName = statusArray[i].pcTaskName;
|
||||
stat.runTimeCounter = statusArray[i].ulRunTimeCounter;
|
||||
stat.cpuUsage = (totalRunTime > 0) ? (100.0f * static_cast<Real>(stat.runTimeCounter) / static_cast<Real>(totalRunTime)) : 0.0f;
|
||||
}
|
||||
return numTasks;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::generic::FreeRTOS
|
||||
73
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/iGPIO.h
Normal file
73
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/iGPIO.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace sdi_uToolBox::generic
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class IGPIO
|
||||
{
|
||||
public:
|
||||
enum class PinType
|
||||
{
|
||||
Invalid,
|
||||
Input,
|
||||
ReversedInput,
|
||||
Output, // HIGH level to enable
|
||||
ReversedOutput, // LOW level to enable
|
||||
};
|
||||
|
||||
public:
|
||||
IGPIO() = default; // Constructor
|
||||
virtual ~IGPIO() = default; // Destructor
|
||||
IGPIO(const IGPIO &other) = delete; // Copy constructor
|
||||
IGPIO(IGPIO &&other) noexcept = delete; // Move constructor
|
||||
IGPIO &operator=(const IGPIO &other) = delete; // Copy assignment
|
||||
IGPIO &operator=(IGPIO &&other) noexcept = delete; // Move assignment
|
||||
|
||||
virtual void set(bool enable = true) const = 0; // Sets/Resets IO state
|
||||
void reset() const; // Resets IO state
|
||||
virtual bool get() const = 0; // Returns IO state
|
||||
virtual void toggle() const; // Flips IO state
|
||||
|
||||
using Callback = std::function<void()>;
|
||||
void setITCallback(const Callback &callback); // Defines the callback function for a possible interruption
|
||||
|
||||
protected:
|
||||
Callback m_itCallback = nullptr;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Resets IO state */
|
||||
inline void IGPIO::reset() const
|
||||
{
|
||||
set(false);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Flips IO state */
|
||||
inline void IGPIO::toggle() const
|
||||
{
|
||||
const auto newValue = !get();
|
||||
set(newValue);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Defines the callback function for a possible interruption */
|
||||
inline void IGPIO::setITCallback(const Callback &callback)
|
||||
{
|
||||
m_itCallback = callback;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::generic
|
||||
69
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/iI2CBus.h
Normal file
69
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/iI2CBus.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::generic
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class II2CBus
|
||||
{
|
||||
public:
|
||||
enum class I2CStatus
|
||||
{
|
||||
Ok,
|
||||
Timeout,
|
||||
Error,
|
||||
Busy,
|
||||
};
|
||||
|
||||
public:
|
||||
II2CBus() = default; // Constructor
|
||||
virtual ~II2CBus() = default; // Destructor
|
||||
II2CBus(const II2CBus &other) = delete; // Copy constructor
|
||||
II2CBus(II2CBus &&other) noexcept = delete; // Move constructor
|
||||
II2CBus &operator=(const II2CBus &other) = delete; // Copy assignment
|
||||
II2CBus &operator=(II2CBus &&other) noexcept = delete; // Move assignment
|
||||
|
||||
virtual I2CStatus read(const uint8_t chipAddress, const std::span<uint8_t> &buffer) = 0; // Read data from I2C device
|
||||
I2CStatus read(const uint8_t chipAddress, uint8_t &value); // Read data from I2C device
|
||||
virtual I2CStatus write(const uint8_t chipAddress, const std::span<const uint8_t> &buffer) = 0; // Write data to I2C device
|
||||
I2CStatus write(const uint8_t chipAddress, const uint8_t &value); // Write data to I2C device
|
||||
|
||||
// virtual I2CStatus readEeprom(const uint8_t chipAddress, const uint32_t memoryAddress, const std::span<uint8_t> &buffer) = 0; // Read data from I2C memory device
|
||||
// virtual I2CStatus writeEeprom(const uint8_t chipAddress, const uint32_t memoryAddress, const std::span<const uint8_t> &buffer) = 0; // Write data to I2C memory device
|
||||
|
||||
virtual I2CStatus isDeviceReady(const uint8_t chipAddress) = 0; // Check device readiness
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
inline II2CBus::I2CStatus II2CBus::read(const uint8_t chipAddress, uint8_t &value)
|
||||
{
|
||||
// Create a std::span pointing to the single byte 'value'
|
||||
std::span<uint8_t, 1> single_byte_span{ &value, 1 };
|
||||
|
||||
return read(chipAddress, single_byte_span);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
inline II2CBus::I2CStatus II2CBus::write(const uint8_t chipAddress, const uint8_t &value)
|
||||
{
|
||||
// Create a std::span pointing to the single byte 'value'
|
||||
std::span<const uint8_t, 1> single_byte_span{ &value, 1 };
|
||||
|
||||
return write(chipAddress, single_byte_span);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::generic
|
||||
47
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/iStream.h
Normal file
47
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/generic/iStream.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::generic
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class IStream
|
||||
{
|
||||
public:
|
||||
IStream() = default; // Constructor
|
||||
virtual ~IStream() = default; // Destructor
|
||||
IStream(const IStream &other) = delete; // Copy constructor
|
||||
IStream(IStream &&other) noexcept = delete; // Move constructor
|
||||
IStream &operator=(const IStream &other) = delete; // Copy assignment
|
||||
IStream &operator=(IStream &&other) noexcept = delete; // Move assignment
|
||||
|
||||
virtual size_t write(const std::span<const uint8_t> buffer) = 0; // Writes a block of data to the stream
|
||||
virtual size_t read(const std::span<uint8_t> buffer) = 0; // Reads a block of data from the stream
|
||||
virtual size_t read(const std::span<uint8_t> buffer, const std::chrono::milliseconds ms); // If available, wait for block of data from the stream
|
||||
|
||||
virtual bool isDataAvailable() const = 0; // Checks if the stream has data available for reading
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* If available, wait for block of data from the stream */
|
||||
inline size_t IStream::read(const std::span<uint8_t> buffer, const std::chrono::milliseconds ms)
|
||||
{
|
||||
return read(buffer);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::generic
|
||||
113
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/FreeRTOS/HIDBus.h
Normal file
113
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/FreeRTOS/HIDBus.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../generic/FreeRTOS/mutex.h"
|
||||
#include "../HIDBus.h"
|
||||
|
||||
namespace sdi_uToolBox::stm32::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
template<size_t QUEUE_SIZE>
|
||||
class HIDBus : public stm32::HIDBus<0>
|
||||
{
|
||||
public:
|
||||
HIDBus(); // Constructor
|
||||
~HIDBus() override = default; // Destructor
|
||||
HIDBus(const HIDBus &other) = delete; // Copy constructor
|
||||
HIDBus(HIDBus &&other) noexcept = delete; // Move constructor
|
||||
HIDBus &operator=(const HIDBus &other) = delete; // Copy assignment
|
||||
HIDBus &operator=(HIDBus &&other) noexcept = delete; // Move assignment
|
||||
|
||||
void onReceiveData(std::span<const uint8_t> buf) override;
|
||||
|
||||
size_t write(const std::span<const uint8_t> buffer) override;
|
||||
size_t read(const std::span<uint8_t> buffer) override; // Reads a block of data from the stream
|
||||
size_t read(const std::span<uint8_t> buffer, const std::chrono::milliseconds ms) override; // If available, wait for block of data from the stream
|
||||
bool isDataAvailable() const override; // Checks if the stream has data available for reading
|
||||
|
||||
protected:
|
||||
sdi_uToolBox::generic::FreeRTOS::Mutex m_mtx;
|
||||
QueueHandle_t m_uartRxQueue = nullptr;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
template<size_t QUEUE_SIZE>
|
||||
inline HIDBus<QUEUE_SIZE>::HIDBus()
|
||||
{
|
||||
// Initialization of FreeRTOS queue
|
||||
m_uartRxQueue = xQueueCreate(QUEUE_SIZE, sizeof(uint8_t));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Receive data from interuption */
|
||||
template<size_t QUEUE_SIZE>
|
||||
void HIDBus<QUEUE_SIZE>::onReceiveData(std::span<const uint8_t> buf)
|
||||
{
|
||||
auto xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
// Copy each bytes into the queue
|
||||
for (const auto byte : buf)
|
||||
{
|
||||
xQueueSendFromISR(m_uartRxQueue,
|
||||
&byte,
|
||||
&xHigherPriorityTaskWoken);
|
||||
|
||||
// If the data reception has woken up a higher priority task,
|
||||
// force a context switch immediately after the ISR
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
template<size_t QUEUE_SIZE>
|
||||
size_t HIDBus<QUEUE_SIZE>::write(const std::span<const uint8_t> buffer)
|
||||
{
|
||||
std::lock_guard lock(m_mtx);
|
||||
return stm32::HIDBus<0>::write(buffer);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Reads a block of data from the stream */
|
||||
template<size_t QUEUE_SIZE>
|
||||
inline size_t HIDBus<QUEUE_SIZE>::read(const std::span<uint8_t> buffer)
|
||||
{
|
||||
return read(buffer, std::chrono::milliseconds(0));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* If available, wait for block of data from the stream */
|
||||
template<size_t QUEUE_SIZE>
|
||||
inline size_t HIDBus<QUEUE_SIZE>::read(const std::span<uint8_t> buffer, const std::chrono::milliseconds ms)
|
||||
{
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
{
|
||||
uint8_t received_byte;
|
||||
if (xQueueReceive(m_uartRxQueue,
|
||||
&received_byte,
|
||||
pdMS_TO_TICKS(ms.count())) != pdPASS)
|
||||
return i;
|
||||
buffer[i] = received_byte;
|
||||
}
|
||||
return buffer.size();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Checks if the stream has data available for reading */
|
||||
template<size_t QUEUE_SIZE>
|
||||
inline bool HIDBus<QUEUE_SIZE>::isDataAvailable() const
|
||||
{
|
||||
const auto count = uxQueueMessagesWaiting(m_uartRxQueue);
|
||||
return count > 0;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::FreeRTOS
|
||||
131
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/GPIO.h
Normal file
131
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/GPIO.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../generic/iGPIO.h"
|
||||
|
||||
#include <STM32Headers.h>
|
||||
#include <array>
|
||||
|
||||
namespace sdi_uToolBox::stm32
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class GPIO : public sdi_uToolBox::generic::IGPIO
|
||||
{
|
||||
public:
|
||||
struct GpioDefs
|
||||
{
|
||||
GPIO_TypeDef *port = nullptr;
|
||||
uint16_t pin = 0;
|
||||
PinType type = PinType::Invalid;
|
||||
};
|
||||
|
||||
public:
|
||||
void configure(const GpioDefs &gpioDefs); // GPIO configuration
|
||||
[[nodiscard]] GPIO_TypeDef *getPort() const; // Returns IO port
|
||||
[[nodiscard]] uint16_t getPin() const; // Returns IO pin
|
||||
[[nodiscard]] PinType getType() const; // Returns IO type
|
||||
|
||||
void set(bool enable = true) const override; // Sets/Resets IO state
|
||||
[[nodiscard]] bool get() const override; // Returns IO state
|
||||
void toggle() const override; // Flips IO state
|
||||
|
||||
void enableEvent(bool enable = true); // Adds / remove GPIO handle in the indexed pin event handle list
|
||||
static void on_GpioIT(uint16_t pin); // Checks GPIO IT
|
||||
|
||||
protected:
|
||||
GpioDefs m_gpioDefs;
|
||||
|
||||
static inline std::array<GPIO *, 16> m_ITListHdl{}; // List of indexed pin IT handles
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* GPIO configuration */
|
||||
inline void GPIO::configure(const GpioDefs &gpioDefs)
|
||||
{
|
||||
m_gpioDefs = gpioDefs;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return IO port */
|
||||
inline GPIO_TypeDef *GPIO::getPort() const
|
||||
{
|
||||
return m_gpioDefs.port;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return IO pin */
|
||||
inline uint16_t GPIO::getPin() const
|
||||
{
|
||||
return m_gpioDefs.pin;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return IO type */
|
||||
inline GPIO::PinType GPIO::getType() const
|
||||
{
|
||||
return m_gpioDefs.type;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Set/Reset logical IO state */
|
||||
inline void GPIO::set(bool enable) const
|
||||
{
|
||||
if (m_gpioDefs.type == PinType::ReversedOutput)
|
||||
enable = !enable;
|
||||
|
||||
HAL_GPIO_WritePin(m_gpioDefs.port,
|
||||
m_gpioDefs.pin,
|
||||
(enable) ? GPIO_PIN_SET : GPIO_PIN_RESET);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return logical IO state */
|
||||
inline bool GPIO::get() const
|
||||
{
|
||||
const auto state = (GPIO_PIN_SET == HAL_GPIO_ReadPin(m_gpioDefs.port, m_gpioDefs.pin));
|
||||
|
||||
if (m_gpioDefs.type == PinType::ReversedOutput || m_gpioDefs.type == PinType::ReversedInput)
|
||||
return !state;
|
||||
|
||||
return state;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Flip IO state */
|
||||
inline void GPIO::toggle() const
|
||||
{
|
||||
HAL_GPIO_TogglePin(m_gpioDefs.port, m_gpioDefs.pin);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Add / remove GPIO handle in the indexed pin event handle list */
|
||||
inline void GPIO::enableEvent(bool enable)
|
||||
{
|
||||
const size_t pinIndex = __builtin_clz(m_gpioDefs.pin);
|
||||
if (pinIndex >= m_ITListHdl.size())
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
m_ITListHdl[pinIndex] = this;
|
||||
else
|
||||
m_ITListHdl[pinIndex] = nullptr;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check GPIO IT
|
||||
*/
|
||||
inline void GPIO::on_GpioIT(uint16_t pin)
|
||||
{
|
||||
const size_t pinIndex = __builtin_clz(pin);
|
||||
if (pinIndex < m_ITListHdl.size())
|
||||
{
|
||||
if (m_ITListHdl[pinIndex] && m_ITListHdl[pinIndex]->getPin() == pin)
|
||||
m_ITListHdl[pinIndex]->m_itCallback();
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32
|
||||
102
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/HIDBus.h
Normal file
102
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/HIDBus.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../generic/iStream.h"
|
||||
|
||||
#include <STM32Headers.h>
|
||||
|
||||
namespace sdi_uToolBox::stm32
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
template<size_t QUEUE_SIZE>
|
||||
class HIDBus : public sdi_uToolBox::generic::IStream
|
||||
{
|
||||
public:
|
||||
HIDBus() = default; // Constructor
|
||||
~HIDBus() override = default; // Destructor
|
||||
HIDBus(const HIDBus &other) = delete; // Copy constructor
|
||||
HIDBus(HIDBus &&HIDBus) noexcept = delete; // Move constructor
|
||||
HIDBus &operator=(const HIDBus &other) = delete; // Copy assignment
|
||||
HIDBus &operator=(HIDBus &&other) noexcept = delete; // Move assignment
|
||||
|
||||
void configure(USBD_HandleTypeDef *usbdHdl); // Bus configuration
|
||||
[[nodiscard]] USBD_HandleTypeDef *getBus() const; // Returns bus handle
|
||||
|
||||
virtual void onReceiveData(std::span<const uint8_t> buf); // Read data
|
||||
|
||||
size_t write(const std::span<const uint8_t> buffer) override;
|
||||
size_t read(const std::span<uint8_t> buffer) override;
|
||||
|
||||
bool isDataAvailable() const override;
|
||||
|
||||
protected:
|
||||
USBD_HandleTypeDef *m_usbdHdl = nullptr;
|
||||
|
||||
sdi_toolBox::generic::CircularBuffer<uint8_t, QUEUE_SIZE> m_rxBuffer;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Bus configuration */
|
||||
template<size_t QUEUE_SIZE>
|
||||
inline void HIDBus<QUEUE_SIZE>::configure(USBD_HandleTypeDef *usbdHdl)
|
||||
{
|
||||
m_usbdHdl = usbdHdl;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Returns bus handle */
|
||||
template<size_t QUEUE_SIZE>
|
||||
inline USBD_HandleTypeDef *HIDBus<QUEUE_SIZE>::getBus() const
|
||||
{
|
||||
return m_usbdHdl;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from IT and restart the reading process */
|
||||
template<size_t QUEUE_SIZE>
|
||||
inline void HIDBus<QUEUE_SIZE>::onReceiveData(const std::span<const uint8_t> buf)
|
||||
{
|
||||
for (const auto &c : buf)
|
||||
m_rxBuffer.push(c);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
template<size_t QUEUE_SIZE>
|
||||
size_t HIDBus<QUEUE_SIZE>::write(const std::span<const uint8_t> buffer)
|
||||
{
|
||||
USBD_CUSTOM_HID_SendReport(m_usbdHdl, const_cast<uint8_t*>(buffer.data()), buffer.size());
|
||||
|
||||
return 0;//TODO: correct return value
|
||||
}
|
||||
|
||||
template<size_t QUEUE_SIZE>
|
||||
size_t HIDBus<QUEUE_SIZE>::read(const std::span<uint8_t> buffer)
|
||||
{
|
||||
CriticalSection criticalSection;
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
{
|
||||
const auto data = m_rxBuffer.pop();
|
||||
if (!data)
|
||||
return i;
|
||||
buffer[i] = *data;
|
||||
}
|
||||
return buffer.size();
|
||||
}
|
||||
|
||||
template<size_t QUEUE_SIZE>
|
||||
bool HIDBus<QUEUE_SIZE>::isDataAvailable() const
|
||||
{
|
||||
CriticalSection criticalSection;
|
||||
return !m_rxBuffer.isEmpty();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32
|
||||
117
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/I2CBus.h
Normal file
117
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/I2CBus.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../generic/iI2CBus.h"
|
||||
|
||||
#include <STM32Headers.h>
|
||||
|
||||
namespace sdi_uToolBox::stm32
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class I2CBus : public sdi_uToolBox::generic::II2CBus
|
||||
{
|
||||
public:
|
||||
void configure(I2C_HandleTypeDef *i2cHdl, // Bus configuration
|
||||
const uint32_t delay = HAL_MAX_DELAY);
|
||||
[[nodiscard]] I2C_HandleTypeDef *getBus() const; // Returns bus handle
|
||||
[[nodiscard]] uint32_t getDelay() const; // Returns timeout delay
|
||||
|
||||
I2CStatus write(const uint8_t chipAddress, const std::span<const uint8_t> &buffer) override; // Write data to I2C device
|
||||
I2CStatus read(const uint8_t chipAddress, const std::span<uint8_t> &buffer) override; // Read data from I2C device
|
||||
|
||||
I2CStatus isDeviceReady(const uint8_t chipAddress) override; // Check device readiness
|
||||
|
||||
protected:
|
||||
I2C_HandleTypeDef *m_i2cHandle = nullptr;
|
||||
uint32_t m_delay = 0;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Bus configuration */
|
||||
inline void I2CBus::configure(I2C_HandleTypeDef *i2cHdl, const uint32_t delay)
|
||||
{
|
||||
m_i2cHandle = i2cHdl;
|
||||
m_delay = delay;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Returns bus handle */
|
||||
inline I2C_HandleTypeDef *I2CBus::getBus() const
|
||||
{
|
||||
return m_i2cHandle;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Return IO pin */
|
||||
inline uint32_t I2CBus::getDelay() const
|
||||
{
|
||||
return m_delay;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to I2C device */
|
||||
inline I2CBus::I2CStatus I2CBus::write(const uint8_t chipAddress, const std::span<const uint8_t> &buffer)
|
||||
{
|
||||
const auto ret = HAL_I2C_Master_Transmit(m_i2cHandle,
|
||||
chipAddress << 1,
|
||||
const_cast<uint8_t *>(buffer.data()),
|
||||
buffer.size(),
|
||||
m_delay);
|
||||
|
||||
if (ret == HAL_OK)
|
||||
return I2CStatus::Ok;
|
||||
else if (ret == HAL_BUSY)
|
||||
return I2CStatus::Busy;
|
||||
else if (ret == HAL_ERROR && m_i2cHandle->ErrorCode == HAL_I2C_ERROR_TIMEOUT)
|
||||
return I2CStatus::Timeout;
|
||||
else
|
||||
return I2CStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from I2C device */
|
||||
inline I2CBus::I2CStatus I2CBus::read(const uint8_t chipAddress, const std::span<uint8_t> &buffer)
|
||||
{
|
||||
const auto ret = HAL_I2C_Master_Receive(m_i2cHandle,
|
||||
chipAddress << 1,
|
||||
buffer.data(),
|
||||
buffer.size(),
|
||||
m_delay);
|
||||
|
||||
if (ret == HAL_OK)
|
||||
return I2CStatus::Ok;
|
||||
else if (ret == HAL_BUSY)
|
||||
return I2CStatus::Busy;
|
||||
else if (ret == HAL_ERROR && m_i2cHandle->ErrorCode == HAL_I2C_ERROR_TIMEOUT)
|
||||
return I2CStatus::Timeout;
|
||||
else
|
||||
return I2CStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check device readiness */
|
||||
inline I2CBus::I2CStatus I2CBus::isDeviceReady(const uint8_t chipAddress)
|
||||
{
|
||||
const auto ret = HAL_I2C_IsDeviceReady(m_i2cHandle,
|
||||
chipAddress << 1,
|
||||
5,
|
||||
m_delay);
|
||||
|
||||
if (ret == HAL_OK)
|
||||
return I2CStatus::Ok;
|
||||
else if (ret == HAL_BUSY)
|
||||
return I2CStatus::Busy;
|
||||
else if (ret == HAL_ERROR && m_i2cHandle->ErrorCode == HAL_I2C_ERROR_TIMEOUT)
|
||||
return I2CStatus::Timeout;
|
||||
else
|
||||
return I2CStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32
|
||||
83
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/UARTBus.h
Normal file
83
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/UARTBus.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../generic/iStream.h"
|
||||
|
||||
#include <STM32Headers.h>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
namespace sdi_uToolBox::stm32
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE>
|
||||
class UARTBus : public sdi_uToolBox::generic::IStream
|
||||
{
|
||||
public:
|
||||
UARTBus() = default; // Constructor
|
||||
~UARTBus() override = default; // Destructor
|
||||
UARTBus(const UARTBus &other) = delete; // Copy constructor
|
||||
UARTBus(UARTBus &&UARTBus) noexcept = delete; // Move constructor
|
||||
UARTBus &operator=(const UARTBus &other) = delete; // Copy assignment
|
||||
UARTBus &operator=(UARTBus &&other) noexcept = delete; // Move assignment
|
||||
|
||||
void configure(UART_HandleTypeDef *uartHdl); // Bus configuration
|
||||
[[nodiscard]] UART_HandleTypeDef *getBus() const; // Returns bus handle
|
||||
|
||||
void onReceiveData_fromISR(const size_t size); // Read data from IT and restart the reading process
|
||||
|
||||
protected:
|
||||
UART_HandleTypeDef *m_uartHdl = nullptr;
|
||||
std::array<uint8_t, UART_RX_BUFFER_SIZE> m_uartRXBuffer;
|
||||
std::array<uint8_t, UART_TX_BUFFER_SIZE> m_uartTXBuffer;
|
||||
|
||||
private:
|
||||
virtual void initDevice() = 0; // Device initialization
|
||||
virtual bool startReceiving() = 0; // Start specific receiving method (IT, DMA, ...)
|
||||
virtual void receiveData_fromISR(const uint8_t *buffer, const size_t size) = 0; // Receive data from interuption
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Bus configuration */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE>
|
||||
inline void UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::configure(UART_HandleTypeDef *uartHdl)
|
||||
{
|
||||
m_uartHdl = uartHdl;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Returns bus handle */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE>
|
||||
inline UART_HandleTypeDef *UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::getBus() const
|
||||
{
|
||||
return m_uartHdl;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from IT and restart the reading process */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE>
|
||||
inline void UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::onReceiveData_fromISR(const size_t size)
|
||||
{
|
||||
// Read data
|
||||
receiveData_fromISR(m_uartRXBuffer.data(), size);
|
||||
|
||||
// Restart receiving process
|
||||
if (!startReceiving())
|
||||
{
|
||||
// Quick fix in case of failure to start the receiving process
|
||||
initDevice();
|
||||
startReceiving();
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32
|
||||
140
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/UARTBusIT.h
Normal file
140
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/UARTBusIT.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UARTBus.h"
|
||||
#include "criticalSection.h"
|
||||
|
||||
#include <sdi_toolBox/generic/circularBuffer.h>
|
||||
|
||||
namespace sdi_uToolBox::stm32
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE, size_t QUEUE_SIZE>
|
||||
class UARTBusIT : public sdi_uToolBox::stm32::UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>
|
||||
{
|
||||
public:
|
||||
UARTBusIT() = default; // Constructor
|
||||
~UARTBusIT() override = default; // Destructor
|
||||
UARTBusIT(const UARTBusIT &other) = delete; // Copy constructor
|
||||
UARTBusIT(UARTBusIT &&other) noexcept = delete; // Move constructor
|
||||
UARTBusIT &operator=(const UARTBusIT &other) = delete; // Copy assignment
|
||||
UARTBusIT &operator=(UARTBusIT &&other) noexcept = delete; // Move assignment
|
||||
|
||||
size_t write(const std::span<const uint8_t> buffer) override; // Writes a block of data to the stream
|
||||
size_t read(const std::span<uint8_t> buffer) override; // Reads a block of data from the stream
|
||||
bool isDataAvailable() const override; // Checks if the stream has data available for reading
|
||||
|
||||
bool isTxReady(); // Returns true if the TX stream is ready and available
|
||||
void on_transmitComplete_fromISR(); // Interrupt-based transmission is over
|
||||
|
||||
protected:
|
||||
volatile bool m_txBufferIsEmpty = true;
|
||||
|
||||
sdi_toolBox::generic::CircularBuffer<uint8_t, QUEUE_SIZE> m_rxBuffer;
|
||||
|
||||
private:
|
||||
void initDevice() override; // Device initialization
|
||||
bool startReceiving() override; // Start specific receiving method (IT, DMA, ...)
|
||||
void receiveData_fromISR(const uint8_t *buffer, const size_t size) override; // Receive data from interuption
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Writes a block of data to the stream */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE, size_t QUEUE_SIZE>
|
||||
inline size_t UARTBusIT<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE, QUEUE_SIZE>::write(const std::span<const uint8_t> buffer)
|
||||
{
|
||||
if (!isTxReady())
|
||||
return 0;
|
||||
|
||||
if (UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::m_uartHdl->gState != HAL_UART_STATE_READY)
|
||||
return 0;
|
||||
|
||||
const auto len = std::min(buffer.size(), UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::m_uartTXBuffer.size());
|
||||
std::memcpy(UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::m_uartTXBuffer.data(),
|
||||
buffer.data(),
|
||||
len);
|
||||
|
||||
if (HAL_OK != HAL_UART_Transmit_IT(UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::m_uartHdl,
|
||||
UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::m_uartRXBuffer.data(),
|
||||
UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::m_uartRXBuffer.size()))
|
||||
return 0;
|
||||
|
||||
m_txBufferIsEmpty = false;
|
||||
return len;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Reads a block of data from the stream */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE, size_t QUEUE_SIZE>
|
||||
inline size_t UARTBusIT<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE, QUEUE_SIZE>::read(const std::span<uint8_t> buffer)
|
||||
{
|
||||
CriticalSection criticalSection;
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
{
|
||||
const auto data = m_rxBuffer.pop();
|
||||
if (!data)
|
||||
return i;
|
||||
buffer[i] = *data;
|
||||
}
|
||||
return buffer.size();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Checks if the stream has data available for reading */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE, size_t QUEUE_SIZE>
|
||||
inline bool UARTBusIT<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE, QUEUE_SIZE>::isDataAvailable() const
|
||||
{
|
||||
CriticalSection criticalSection;
|
||||
return !m_rxBuffer.isEmpty();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Returns true if the TX stream is ready and available */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE, size_t QUEUE_SIZE>
|
||||
inline bool UARTBusIT<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE, QUEUE_SIZE>::isTxReady()
|
||||
{
|
||||
return m_txBufferIsEmpty;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Interrupt-based transmission is over */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE, size_t QUEUE_SIZE>
|
||||
inline void UARTBusIT<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE, QUEUE_SIZE>::on_transmitComplete_fromISR()
|
||||
{
|
||||
m_txBufferIsEmpty = true;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Start specific receiving method (IT, DMA, ...) */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE, size_t QUEUE_SIZE>
|
||||
inline bool UARTBusIT<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE, QUEUE_SIZE>::startReceiving()
|
||||
{
|
||||
return (HAL_OK != HAL_UARTEx_ReceiveToIdle_IT(UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::m_uartHdl,
|
||||
UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::m_uartRXBuffer.data(),
|
||||
UARTBus<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE>::m_uartRXBuffer.size()));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Device initialization */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE, size_t QUEUE_SIZE>
|
||||
void UARTBusIT<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE, QUEUE_SIZE>::initDevice()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Receive data from interuption */
|
||||
template<size_t UART_RX_BUFFER_SIZE, size_t UART_TX_BUFFER_SIZE, size_t QUEUE_SIZE>
|
||||
inline void UARTBusIT<UART_RX_BUFFER_SIZE, UART_TX_BUFFER_SIZE, QUEUE_SIZE>::receiveData_fromISR(const uint8_t *buffer, const size_t size)
|
||||
{
|
||||
// Operations performed within an interrupt routine are considered atomic
|
||||
for (size_t i = 0; i < size; i++)
|
||||
m_rxBuffer.push(buffer[i]);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32
|
||||
@@ -0,0 +1,89 @@
|
||||
//{{copyright}}
|
||||
|
||||
//{{version}}
|
||||
|
||||
//{{license}}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../HIDBus.h"
|
||||
#include "../../../dateTime/FreeRTOS/timer.h"
|
||||
|
||||
#include <sdi_uToolBox/generic/FreeRTOS/mutex.h>
|
||||
#include <sdi_uToolBox/generic/FreeRTOS/semaphore.h>
|
||||
|
||||
namespace sdi_uToolBox::stm32::comm::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class HIDBus : public comm::HIDBus
|
||||
{
|
||||
public:
|
||||
using Mutex = generic::FreeRTOS::Mutex;
|
||||
using BinarySemaphore = generic::FreeRTOS::BinarySemaphore;
|
||||
|
||||
public:
|
||||
HIDBus(); // Default constructor
|
||||
virtual ~HIDBus() = default; // Default destructor
|
||||
HIDBus(const HIDBus &) = delete; // Copy constructor
|
||||
HIDBus(HIDBus &&) = delete; // Move constructor
|
||||
HIDBus &operator=(const HIDBus &) = delete; // Copy assignment operator
|
||||
HIDBus &operator=(HIDBus &&) = delete; // Move assignment operator
|
||||
|
||||
ReturnStatus open() override; // Open UART bus
|
||||
ReturnStatus close() override; // Close UART bus
|
||||
|
||||
ReturnType write(WriteBuf buf, Timeout timeout) const override; // Write data to UART device
|
||||
ReturnType read(ReadBuf buf, Timeout timeout) const override; // Read data from UART device
|
||||
|
||||
void rxCompleteCallback(std::span<const uint8_t> buf) override;
|
||||
|
||||
protected:
|
||||
mutable Mutex m_mtx;
|
||||
mutable BinarySemaphore m_semaphore{false};
|
||||
dateTime::FreeRTOS::Timer m_timer;
|
||||
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
inline HIDBus::HIDBus()
|
||||
{
|
||||
m_genericTimer = &m_timer;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Open UART bus */
|
||||
inline ReturnStatus HIDBus::open()
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return comm::HIDBus::open();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Close UART bus */
|
||||
inline ReturnStatus HIDBus::close()
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return comm::HIDBus::close();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to UART device */
|
||||
inline HIDBus::ReturnType HIDBus::write(const WriteBuf buf, const Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return comm::HIDBus::write(buf, timeout);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from UART device */
|
||||
inline HIDBus::ReturnType HIDBus::read(const ReadBuf buf, const Timeout timeout) const
|
||||
{
|
||||
if (!m_semaphore.take(timeout))
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return comm::HIDBus::read(buf, std::chrono::milliseconds(0));
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
inline void HIDBus::rxCompleteCallback(std::span<const uint8_t> buf)
|
||||
{
|
||||
comm::HIDBus::rxCompleteCallback(buf);
|
||||
(void)m_semaphore.giveFromISR();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::comm
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../I2CBus.h"
|
||||
|
||||
#include <sdi_uToolBox/generic/FreeRTOS/mutex.h>
|
||||
|
||||
namespace sdi_uToolBox::stm32::comm::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class I2CBus : public stm32::comm::I2CBus
|
||||
{
|
||||
public:
|
||||
using RecursiveMutex = generic::FreeRTOS::RecursiveMutex;
|
||||
|
||||
public:
|
||||
I2CBus() = default; // Default constructor
|
||||
virtual ~I2CBus() override = default; // Default destructor
|
||||
I2CBus(const I2CBus &) = delete; // Copy constructor
|
||||
I2CBus(I2CBus &&) = delete; // Move constructor
|
||||
I2CBus &operator=(const I2CBus &) = delete; // Copy assignment operator
|
||||
I2CBus &operator=(I2CBus &&) = delete; // Move assignment operator
|
||||
|
||||
ReturnStatus open() override; // Open I2C bus
|
||||
ReturnStatus close() override; // Close I2C bus
|
||||
|
||||
std::unique_lock<RecursiveMutex> getLock() const; // Get unique lock for the bus
|
||||
|
||||
ReturnType write(uint8_t address, WriteBuf buf, Timeout timeout) const override; // Write data to I2C device
|
||||
ReturnType read(uint8_t address, ReadBuf buf, Timeout timeout) const override; // Read data from I2C device
|
||||
ReturnStatus isDeviceReady(uint8_t address) const override; // Check if I2C device is ready
|
||||
|
||||
protected:
|
||||
mutable RecursiveMutex m_mtx; // Mutex for thread safety
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Open I2C bus */
|
||||
inline ReturnStatus I2CBus::open()
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return stm32::comm::I2CBus::open();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Close I2C bus */
|
||||
inline ReturnStatus I2CBus::close()
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return stm32::comm::I2CBus::close();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get unique lock for the bus */
|
||||
inline std::unique_lock<I2CBus::RecursiveMutex> I2CBus::getLock() const
|
||||
{
|
||||
return std::unique_lock(m_mtx);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to I2C device */
|
||||
inline I2CBus::ReturnType I2CBus::write(const uint8_t address, const WriteBuf buf, const Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return stm32::comm::I2CBus::write(address, buf, timeout);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from I2C device */
|
||||
inline I2CBus::ReturnType I2CBus::read(const uint8_t address, const ReadBuf buf, const Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return stm32::comm::I2CBus::read(address, buf, timeout);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check if I2C device is ready */
|
||||
inline ReturnStatus I2CBus::isDeviceReady(const uint8_t address) const
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return stm32::comm::I2CBus::isDeviceReady(address);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::comm::FreeRTOS
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../UARTBus.h"
|
||||
|
||||
#include <sdi_uToolBox/generic/FreeRTOS/mutex.h>
|
||||
|
||||
namespace sdi_uToolBox::stm32::comm::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class UARTBus : public stm32::comm::UARTBus
|
||||
{
|
||||
public:
|
||||
using Mutex = generic::FreeRTOS::Mutex;
|
||||
|
||||
public:
|
||||
UARTBus() = default; // Default constructor
|
||||
virtual ~UARTBus() override = default; // Default destructor
|
||||
UARTBus(const UARTBus &) = delete; // Copy constructor
|
||||
UARTBus(UARTBus &&) = delete; // Move constructor
|
||||
UARTBus &operator=(const UARTBus &) = delete; // Copy assignment operator
|
||||
UARTBus &operator=(UARTBus &&) = delete; // Move assignment operator
|
||||
|
||||
ReturnStatus open() override; // Open UART bus
|
||||
ReturnStatus close() override; // Close UART bus
|
||||
|
||||
ReturnType write(WriteBuf buf, Timeout timeout) const override; // Write data to UART device
|
||||
ReturnType read(ReadBuf buf, Timeout timeout) const override; // Read data from UART device
|
||||
|
||||
protected:
|
||||
mutable Mutex m_mtx; // Mutex for thread safety
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Open UART bus */
|
||||
inline ReturnStatus UARTBus::open()
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return stm32::comm::UARTBus::open();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Close UART bus */
|
||||
inline ReturnStatus UARTBus::close()
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return stm32::comm::UARTBus::close();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to UART device */
|
||||
inline UARTBus::ReturnType UARTBus::write(const WriteBuf buf, const Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return stm32::comm::UARTBus::write(buf, timeout);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from UART device */
|
||||
inline UARTBus::ReturnType UARTBus::read(const ReadBuf buf, const Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_mtx);
|
||||
return stm32::comm::UARTBus::read(buf, timeout);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::comm::FreeRTOS
|
||||
@@ -0,0 +1,283 @@
|
||||
//{{copyright}}
|
||||
|
||||
//{{version}}
|
||||
|
||||
//{{license}}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../UARTBus.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <sdi_uToolBox/generic/FreeRTOS/mutex.h>
|
||||
#include <sdi_uToolBox/generic/FreeRTOS/semaphore.h>
|
||||
|
||||
namespace sdi_uToolBox::stm32::comm::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
class UARTBusDMA : public stm32::comm::UARTBus
|
||||
, public UARTBusCallback
|
||||
{
|
||||
public:
|
||||
using Mutex = generic::FreeRTOS::Mutex;
|
||||
using BinarySemaphore = generic::FreeRTOS::BinarySemaphore;
|
||||
|
||||
public:
|
||||
UARTBusDMA() = default; // Default constructor
|
||||
virtual ~UARTBusDMA(); // Default destructor
|
||||
UARTBusDMA(const UARTBusDMA &) = delete; // Copy constructor
|
||||
UARTBusDMA(UARTBusDMA &&) = delete; // Move constructor
|
||||
UARTBusDMA &operator=(const UARTBusDMA &) = delete; // Copy assignment operator
|
||||
UARTBusDMA &operator=(UARTBusDMA &&) = delete; // Move assignment operator
|
||||
|
||||
ReturnStatus configure(UART_HandleTypeDef *handle) override; // Configure UART bus with HAL handle
|
||||
|
||||
ReturnStatus open() override; // Open UART bus
|
||||
ReturnStatus close() override; // Close UART bus
|
||||
|
||||
ReturnType write(WriteBuf buf, Timeout timeout) const override; // Write data to UART device
|
||||
ReturnType read(ReadBuf buf, Timeout timeout) const override; // Read data from UART device
|
||||
ReturnType readUntilIdle(ReadBuf buf, Timeout timeout) const override; // Read data until IDLE event
|
||||
|
||||
// Callback to be called from ISR when TX, RX is complete or error occurs
|
||||
void txCompleteCallback() const override; // TX complete callback
|
||||
void rxCompleteCallback() const override; // RX complete callback
|
||||
void rxEventCallback(uint16_t size) const override; // IDLE line detected callback
|
||||
void errorCallback() const override; // Error callback
|
||||
|
||||
protected:
|
||||
mutable Mutex m_txMtx; // Mutex for TX thread safety
|
||||
mutable Mutex m_rxMtx; // Mutex for RX thread safety
|
||||
mutable BinarySemaphore m_txSemaphore{ false }; // Semaphore for TX completion
|
||||
mutable BinarySemaphore m_rxSemaphore{ false }; // Semaphore for RX completion
|
||||
|
||||
alignas(32) mutable std::array<uint8_t, TX_BUFFER_SIZE> m_txBuffer; // Transmit buffer aligned for DMA
|
||||
alignas(32) mutable std::array<uint8_t, RX_BUFFER_SIZE> m_rxBuffer; // Receive buffer aligned for DMA
|
||||
|
||||
mutable std::atomic<size_t> m_lastTxSize{ 0 };
|
||||
mutable std::atomic<size_t> m_lastRxSize{ 0 };
|
||||
mutable std::atomic<bool> m_txError{ false };
|
||||
mutable std::atomic<bool> m_rxError{ false };
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::~UARTBusDMA()
|
||||
{
|
||||
UARTBusCallbackRegistry::unregisterInstance(this);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline ReturnStatus UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::configure(UART_HandleTypeDef *handle)
|
||||
{
|
||||
const auto ret = UARTBus::configure(handle);
|
||||
if (ret != ReturnStatus::Ok)
|
||||
return ret;
|
||||
|
||||
UARTBusCallbackRegistry::registerInstance(handle, this);
|
||||
return ReturnStatus::Ok;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Open UART bus */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline ReturnStatus UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::open()
|
||||
{
|
||||
std::scoped_lock lock(m_txMtx, m_rxMtx);
|
||||
return UARTBus::open();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Close UART bus */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline ReturnStatus UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::close()
|
||||
{
|
||||
std::scoped_lock lock(m_txMtx, m_rxMtx);
|
||||
__HAL_UART_DISABLE_IT(m_uartHandle, UART_IT_IDLE); // Disable IDLE interrupt
|
||||
HAL_UART_DMAStop(m_uartHandle); // Abort ongoing DMA operations
|
||||
return UARTBus::close();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to UART device */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBus::ReturnType UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::write(const WriteBuf buf, const Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_txMtx);
|
||||
|
||||
if (!m_uartHandle)
|
||||
return std::unexpected(ReturnStatus::InvalidHandle);
|
||||
|
||||
if (buf.size() > TX_BUFFER_SIZE)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Copy data to internal buffer
|
||||
std::copy_n(buf.begin(), buf.size(), m_txBuffer.begin());
|
||||
|
||||
// Reset flags
|
||||
m_txError = false;
|
||||
m_lastTxSize = 0;
|
||||
|
||||
// Start transmission with DMA
|
||||
const auto ret = HAL_UART_Transmit_DMA(m_uartHandle,
|
||||
m_txBuffer.data(),
|
||||
buf.size());
|
||||
if (ret != HAL_OK)
|
||||
{
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
|
||||
// Wait for transmission to complete. The timeout is handled by the semaphore
|
||||
// The task will be unblocked when the semaphore is given in the DMA ISR
|
||||
if (!m_txSemaphore.take(timeout))
|
||||
{
|
||||
HAL_UART_AbortTransmit(m_uartHandle);
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
}
|
||||
if (m_txError)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
return m_lastTxSize; // Return number of bytes transmitted
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from UART device */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBus::ReturnType UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::read(const ReadBuf buf, const Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_rxMtx);
|
||||
|
||||
if (!m_uartHandle)
|
||||
return std::unexpected(ReturnStatus::InvalidHandle);
|
||||
|
||||
if (buf.size() > RX_BUFFER_SIZE)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Reset flags
|
||||
m_rxError = false;
|
||||
m_lastRxSize = 0;
|
||||
|
||||
// Start reception with DMA
|
||||
const auto ret = HAL_UART_Receive_DMA(m_uartHandle,
|
||||
m_rxBuffer.data(),
|
||||
buf.size());
|
||||
if (ret != HAL_OK)
|
||||
{
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
|
||||
// Wait for IDLE event or buffer full. The timeout is handled by the semaphore
|
||||
// The task will be unblocked when the semaphore is given in the DMA ISR
|
||||
if (!m_rxSemaphore.take(timeout))
|
||||
{
|
||||
HAL_UART_AbortReceive(m_uartHandle);
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
}
|
||||
if (m_rxError)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Copy received data to user buffer
|
||||
std::copy_n(m_rxBuffer.begin(), m_lastRxSize.load(), buf.begin());
|
||||
|
||||
return m_lastRxSize; // Return number of bytes received
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBus::ReturnType UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::readUntilIdle(ReadBuf buf, Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_rxMtx);
|
||||
|
||||
if (!m_uartHandle)
|
||||
return std::unexpected(ReturnStatus::InvalidHandle);
|
||||
|
||||
if (buf.size() > RX_BUFFER_SIZE)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Reset flags
|
||||
m_rxError = false;
|
||||
m_lastRxSize = 0;
|
||||
|
||||
// Start reception with DMA (buffer size is the maximum expected)
|
||||
if (m_uartHandle->RxState != HAL_UART_STATE_READY)
|
||||
HAL_UART_AbortReceive(m_uartHandle);
|
||||
|
||||
const auto ret = HAL_UARTEx_ReceiveToIdle_DMA(m_uartHandle,
|
||||
m_rxBuffer.data(),
|
||||
buf.size());
|
||||
|
||||
if (ret != HAL_OK)
|
||||
{
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
|
||||
// Wait for reception to complete or idled. The timeout is handled by the semaphore
|
||||
// The task will be unblocked when the semaphore is given in the ISR
|
||||
if (!m_rxSemaphore.take(timeout))
|
||||
{
|
||||
HAL_UART_AbortReceive(m_uartHandle);
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
}
|
||||
|
||||
if (m_rxError)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Copy received data to user buffer
|
||||
std::copy_n(m_rxBuffer.begin(), m_lastRxSize.load(), buf.begin());
|
||||
|
||||
return m_lastRxSize;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* TX complete callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::txCompleteCallback() const
|
||||
{
|
||||
m_lastTxSize = m_uartHandle->TxXferSize - m_uartHandle->TxXferCount;
|
||||
(void)m_txSemaphore.giveFromISR();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* RX complete callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::rxCompleteCallback() const
|
||||
{
|
||||
m_lastRxSize = m_uartHandle->RxXferSize - m_uartHandle->RxXferCount;
|
||||
(void)m_rxSemaphore.giveFromISR();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* IDLE line detected callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::rxEventCallback(const uint16_t size) const
|
||||
{
|
||||
if (m_uartHandle->RxState == HAL_UART_STATE_READY)
|
||||
{
|
||||
// Stop DMA transfer
|
||||
HAL_UART_AbortReceive(m_uartHandle);
|
||||
|
||||
// Calculate received bytes: total size - remaining count
|
||||
// m_lastRxSize = m_uartHandle->RxXferSize - __HAL_DMA_GET_COUNTER(m_uartHandle->hdmarx);
|
||||
m_lastRxSize = size;
|
||||
|
||||
(void)m_rxSemaphore.giveFromISR();
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Error callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusDMA<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::errorCallback() const
|
||||
{
|
||||
if (m_uartHandle->gState == HAL_UART_STATE_BUSY_TX)
|
||||
{
|
||||
m_txError = true;
|
||||
(void)m_txSemaphore.giveFromISR();
|
||||
}
|
||||
|
||||
if (m_uartHandle->RxState == HAL_UART_STATE_BUSY_RX)
|
||||
{
|
||||
m_rxError = true;
|
||||
(void)m_rxSemaphore.giveFromISR();
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::comm::FreeRTOS
|
||||
@@ -0,0 +1,280 @@
|
||||
//{{copyright}}
|
||||
|
||||
//{{version}}
|
||||
|
||||
//{{license}}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../UARTBus.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <sdi_uToolBox/generic/FreeRTOS/mutex.h>
|
||||
#include <sdi_uToolBox/generic/FreeRTOS/semaphore.h>
|
||||
|
||||
namespace sdi_uToolBox::stm32::comm::FreeRTOS
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
class UARTBusIT : public stm32::comm::UARTBus
|
||||
, public UARTBusCallback
|
||||
{
|
||||
public:
|
||||
using Mutex = generic::FreeRTOS::Mutex;
|
||||
using BinarySemaphore = generic::FreeRTOS::BinarySemaphore;
|
||||
|
||||
public:
|
||||
UARTBusIT() = default; // Default constructor
|
||||
virtual ~UARTBusIT(); // Default destructor
|
||||
UARTBusIT(const UARTBusIT &) = delete; // Copy constructor
|
||||
UARTBusIT(UARTBusIT &&) = delete; // Move constructor
|
||||
UARTBusIT &operator=(const UARTBusIT &) = delete; // Copy assignment operator
|
||||
UARTBusIT &operator=(UARTBusIT &&) = delete; // Move assignment operator
|
||||
|
||||
ReturnStatus configure(UART_HandleTypeDef *handle) override; // Configure UART bus with HAL handle
|
||||
|
||||
ReturnStatus open() override; // Open UART bus
|
||||
ReturnStatus close() override; // Close UART bus
|
||||
|
||||
ReturnType write(WriteBuf buf, Timeout timeout) const override; // Write data to UART device
|
||||
ReturnType read(ReadBuf buf, Timeout timeout) const override; // Read data from UART device
|
||||
ReturnType readUntilIdle(ReadBuf buf, Timeout timeout) const; // Read data until IDLE event
|
||||
|
||||
// Callback to be called from ISR when TX, RX is complete or error occurs
|
||||
void txCompleteCallback() const override; // TX complete callback
|
||||
void rxCompleteCallback() const override; // RX complete callback
|
||||
void rxEventCallback(uint16_t size) const override; // IDLE line detected callback
|
||||
void errorCallback() const override; // Error callback
|
||||
|
||||
protected:
|
||||
mutable Mutex m_txMtx; // Mutex for TX thread safety
|
||||
mutable Mutex m_rxMtx; // Mutex for RX thread safety
|
||||
mutable BinarySemaphore m_txSemaphore{ false }; // Semaphore for TX completion
|
||||
mutable BinarySemaphore m_rxSemaphore{ false }; // Semaphore for RX completion
|
||||
|
||||
mutable std::array<uint8_t, TX_BUFFER_SIZE> m_txBuffer;
|
||||
mutable std::array<uint8_t, RX_BUFFER_SIZE> m_rxBuffer;
|
||||
|
||||
mutable std::atomic<size_t> m_lastTxSize{ 0 };
|
||||
mutable std::atomic<size_t> m_lastRxSize{ 0 };
|
||||
mutable std::atomic<bool> m_txError{ false };
|
||||
mutable std::atomic<bool> m_rxError{ false };
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::~UARTBusIT()
|
||||
{
|
||||
UARTBusCallbackRegistry::unregisterInstance(this);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline ReturnStatus UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::configure(UART_HandleTypeDef *handle)
|
||||
{
|
||||
const auto ret = UARTBus::configure(handle);
|
||||
if (ret != ReturnStatus::Ok)
|
||||
return ret;
|
||||
|
||||
UARTBusCallbackRegistry::registerInstance(handle, this);
|
||||
return ReturnStatus::Ok;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Open UART bus */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline ReturnStatus UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::open()
|
||||
{
|
||||
std::scoped_lock lock(m_txMtx, m_rxMtx);
|
||||
return UARTBus::open();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Close UART bus */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline ReturnStatus UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::close()
|
||||
{
|
||||
std::scoped_lock lock(m_txMtx, m_rxMtx);
|
||||
__HAL_UART_DISABLE_IT(m_uartHandle, UART_IT_IDLE); // Disable IDLE interrupt
|
||||
return UARTBus::close();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to UART device */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBus::ReturnType UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::write(const WriteBuf buf, const Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_txMtx);
|
||||
|
||||
if (!m_uartHandle)
|
||||
return std::unexpected(ReturnStatus::InvalidHandle);
|
||||
|
||||
if (buf.size() > TX_BUFFER_SIZE)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Copy data to internal buffer
|
||||
std::copy_n(buf.begin(), buf.size(), m_txBuffer.begin());
|
||||
|
||||
// Reset flags
|
||||
m_txError = false;
|
||||
m_lastTxSize = 0;
|
||||
|
||||
// Start transmission with interrupt
|
||||
const auto ret = HAL_UART_Transmit_IT(m_uartHandle,
|
||||
m_txBuffer.data(),
|
||||
buf.size());
|
||||
if (ret != HAL_OK)
|
||||
{
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
|
||||
// Wait for transmission to complete. The timeout is handled by the semaphore
|
||||
// The task will be unblocked when the semaphore is given in the ISR
|
||||
if (!m_txSemaphore.take(timeout))
|
||||
{
|
||||
HAL_UART_AbortTransmit(m_uartHandle);
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
}
|
||||
if (m_txError)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
return m_lastTxSize; // Return number of bytes transmitted
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from UART device */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBus::ReturnType UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::read(const ReadBuf buf, const Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_rxMtx);
|
||||
|
||||
if (!m_uartHandle)
|
||||
return std::unexpected(ReturnStatus::InvalidHandle);
|
||||
|
||||
if (buf.size() > RX_BUFFER_SIZE)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Reset flags
|
||||
m_rxError = false;
|
||||
m_lastRxSize = 0;
|
||||
|
||||
// Start reception with interrupt
|
||||
const auto ret = HAL_UART_Receive_IT(m_uartHandle,
|
||||
m_rxBuffer.data(),
|
||||
buf.size());
|
||||
if (ret != HAL_OK)
|
||||
{
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
|
||||
// Wait for reception to complete. The timeout is handled by the semaphore
|
||||
// The task will be unblocked when the semaphore is given in the ISR
|
||||
if (!m_rxSemaphore.take(timeout))
|
||||
{
|
||||
HAL_UART_AbortReceive(m_uartHandle);
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
}
|
||||
|
||||
if (m_rxError)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Copy received data to user buffer
|
||||
std::copy_n(m_rxBuffer.begin(), m_lastRxSize.load(), buf.begin());
|
||||
|
||||
return m_lastRxSize; // Return number of bytes received
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBus::ReturnType UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::readUntilIdle(ReadBuf buf, Timeout timeout) const
|
||||
{
|
||||
std::scoped_lock lock(m_rxMtx);
|
||||
|
||||
if (!m_uartHandle)
|
||||
return std::unexpected(ReturnStatus::InvalidHandle);
|
||||
|
||||
if (buf.size() > RX_BUFFER_SIZE)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Reset flags
|
||||
m_rxError = false;
|
||||
m_lastRxSize = 0;
|
||||
|
||||
|
||||
// Start reception with interrupt
|
||||
const auto ret = HAL_UART_ReceiveToIdle_IT(m_uartHandle,
|
||||
m_rxBuffer.data(),
|
||||
buf.size());
|
||||
if (ret != HAL_OK)
|
||||
{
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
|
||||
// Wait for reception to complete or idled. The timeout is handled by the semaphore
|
||||
// The task will be unblocked when the semaphore is given in the ISR
|
||||
if (!m_rxSemaphore.take(timeout))
|
||||
{
|
||||
HAL_UART_AbortReceive(m_uartHandle);
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
}
|
||||
|
||||
if (m_rxError)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Copy received data to user buffer
|
||||
std::copy_n(m_rxBuffer.begin(), m_lastRxSize.load(), buf.begin());
|
||||
|
||||
return m_lastRxSize; // Return number of bytes received
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* TX complete callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::txCompleteCallback() const
|
||||
{
|
||||
m_lastTxSize = m_uartHandle->TxXferSize - m_uartHandle->TxXferCount;
|
||||
(void)m_txSemaphore.giveFromISR();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* RX complete callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::rxCompleteCallback() const
|
||||
{
|
||||
m_lastRxSize = m_uartHandle->RxXferSize - m_uartHandle->RxXferCount;
|
||||
(void)m_rxSemaphore.giveFromISR();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* IDLE line detected callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::rxEventCallback(const uint16_t size) const
|
||||
{
|
||||
if (m_uartHandle->RxState == HAL_UART_STATE_BUSY_RX)
|
||||
{
|
||||
// Stop IT transfer
|
||||
HAL_UART_AbortReceive_IT(m_uartHandle);
|
||||
|
||||
// Calculate received bytes
|
||||
//m_lastRxSize = m_uartHandle->RxXferSize - m_uartHandle->RxXferCount;
|
||||
m_lastRxSize = size;
|
||||
|
||||
(void)m_rxSemaphore.giveFromISR();
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Error callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::errorCallback() const
|
||||
{
|
||||
if (m_uartHandle->gState == HAL_UART_STATE_BUSY_TX)
|
||||
{
|
||||
m_txError = true;
|
||||
(void)m_txSemaphore.giveFromISR();
|
||||
}
|
||||
|
||||
if (m_uartHandle->RxState == HAL_UART_STATE_BUSY_RX)
|
||||
{
|
||||
m_rxError = true;
|
||||
(void)m_rxSemaphore.giveFromISR();
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::comm::FreeRTOS
|
||||
131
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/comm/HIDBus.h
Normal file
131
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/comm/HIDBus.h
Normal file
@@ -0,0 +1,131 @@
|
||||
//{{copyright}}
|
||||
|
||||
//{{version}}
|
||||
|
||||
//{{license}}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../comm/SerialBus.h"
|
||||
#include "../criticalSection.h"
|
||||
#include "../../dateTime/timer.h"
|
||||
|
||||
#include <STM32Headers.h>
|
||||
#include <chrono>
|
||||
#include <expected>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::stm32::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class HIDBus : public sdi_uToolBox::comm::SerialBus
|
||||
{
|
||||
public:
|
||||
using ReadBuf = std::span<uint8_t>;
|
||||
using WriteBuf = std::span<const uint8_t>;
|
||||
using Timeout = std::chrono::milliseconds;
|
||||
using ReturnType = std::expected<size_t, ReturnStatus>;
|
||||
|
||||
public:
|
||||
HIDBus(); // Default constructor
|
||||
virtual ~HIDBus() = default; // Default destructor
|
||||
HIDBus(const HIDBus &) = delete; // Copy constructor
|
||||
HIDBus(HIDBus &&) = delete; // Move constructor
|
||||
HIDBus &operator=(const HIDBus &) = delete; // Copy assignment operator
|
||||
HIDBus &operator=(HIDBus &&) = delete; // Move assignment operator
|
||||
|
||||
virtual ReturnStatus configure(USBD_HandleTypeDef *handle); // Configure UART bus with HAL handle
|
||||
|
||||
ReturnStatus open() override; // Open UART bus
|
||||
ReturnStatus close() override; // Close UART bus
|
||||
|
||||
ReturnType write(WriteBuf buf, Timeout timeout) const override; // Write data to UART device
|
||||
ReturnType read(ReadBuf buf, Timeout timeout) const override; // Read data from UART device
|
||||
|
||||
virtual void rxCompleteCallback(std::span<const uint8_t> buf);
|
||||
|
||||
protected:
|
||||
USBD_HandleTypeDef *m_hidHandle = nullptr; // HAL UART handle
|
||||
sdi_uToolBox::dateTime::Timer m_timer;
|
||||
sdi_toolBox::dateTime::ITimer* m_genericTimer = nullptr;
|
||||
|
||||
mutable std::span<const uint8_t> m_rxBuffer;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
inline HIDBus::HIDBus()
|
||||
{
|
||||
m_genericTimer = &m_timer;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Configure UART bus with HAL handle */
|
||||
inline ReturnStatus HIDBus::configure(USBD_HandleTypeDef *handle)
|
||||
{
|
||||
if (!handle)
|
||||
return ReturnStatus::InvalidHandle;
|
||||
|
||||
m_hidHandle = handle;
|
||||
return ReturnStatus::Ok;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Open UART bus */
|
||||
inline ReturnStatus HIDBus::open()
|
||||
{
|
||||
if (!m_hidHandle)
|
||||
return ReturnStatus::InvalidHandle;
|
||||
|
||||
return ReturnStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Close UART bus */
|
||||
inline ReturnStatus HIDBus::close()
|
||||
{
|
||||
if (!m_hidHandle)
|
||||
return ReturnStatus::InvalidHandle;
|
||||
|
||||
return ReturnStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to UART device */
|
||||
inline HIDBus::ReturnType HIDBus::write(const WriteBuf buf, const Timeout timeout) const
|
||||
{
|
||||
const auto ret = USBD_CUSTOM_HID_SendReport(m_hidHandle,
|
||||
const_cast<uint8_t *>(buf.data()),
|
||||
buf.size());
|
||||
|
||||
if (ret == USBD_OK)
|
||||
return buf.size();
|
||||
if (ret == USBD_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from UART device */
|
||||
inline HIDBus::ReturnType HIDBus::read(const ReadBuf buf, const Timeout timeout) const
|
||||
{
|
||||
m_genericTimer->reset();
|
||||
while (!m_genericTimer->isElapsed(timeout))
|
||||
{
|
||||
CriticalSection criticalSection;
|
||||
if (m_rxBuffer.empty())
|
||||
continue;
|
||||
|
||||
if (m_rxBuffer.size() > buf.size())
|
||||
return std::unexpected(ReturnStatus::BufferOverflow);
|
||||
|
||||
std::copy_n(m_rxBuffer.begin(), m_rxBuffer.size(), buf.begin());
|
||||
m_rxBuffer = {};
|
||||
|
||||
return m_rxBuffer.size();
|
||||
}
|
||||
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
inline void HIDBus::rxCompleteCallback(const std::span<const uint8_t> buf)
|
||||
{
|
||||
CriticalSection criticalSection;
|
||||
m_rxBuffer = buf;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::comm
|
||||
134
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/comm/I2CBus.h
Normal file
134
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/comm/I2CBus.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../comm/I2CBus.h"
|
||||
|
||||
#include <STM32Headers.h>
|
||||
#include <chrono>
|
||||
#include <expected>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::stm32::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class I2CBus : public sdi_uToolBox::comm::I2CBus
|
||||
{
|
||||
public:
|
||||
using ReadBuf = std::span<uint8_t>;
|
||||
using WriteBuf = std::span<const uint8_t>;
|
||||
using Timeout = std::chrono::milliseconds;
|
||||
using ReturnType = std::expected<size_t, ReturnStatus>;
|
||||
|
||||
public:
|
||||
I2CBus() = default; // Default constructor
|
||||
virtual ~I2CBus() = default; // Default destructor
|
||||
I2CBus(const I2CBus &) = delete; // Copy constructor
|
||||
I2CBus(I2CBus &&) = delete; // Move constructor
|
||||
I2CBus &operator=(const I2CBus &) = delete; // Copy assignment operator
|
||||
I2CBus &operator=(I2CBus &&) = delete; // Move assignment operator
|
||||
|
||||
ReturnStatus configure(I2C_HandleTypeDef *handle); // Configure I2C bus with HAL handle
|
||||
|
||||
ReturnStatus open() override; // Open I2C bus
|
||||
ReturnStatus close() override; // Close I2C bus
|
||||
|
||||
ReturnType write(uint8_t address, WriteBuf buf, Timeout timeout) const override; // Write data to I2C device
|
||||
ReturnType read(uint8_t address, ReadBuf buf, Timeout timeout) const override; // Read data from I2C device
|
||||
ReturnStatus isDeviceReady(uint8_t address) const override; // Check if I2C device is ready
|
||||
|
||||
protected:
|
||||
I2C_HandleTypeDef *m_i2cHandle = nullptr; // HAL I2C handle
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Configure I2C bus with HAL handle */
|
||||
inline ReturnStatus I2CBus::configure(I2C_HandleTypeDef *handle)
|
||||
{
|
||||
if (!handle)
|
||||
return ReturnStatus::InvalidHandle;
|
||||
|
||||
m_i2cHandle = handle;
|
||||
return ReturnStatus::Ok;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Open I2C bus */
|
||||
inline ReturnStatus I2CBus::open()
|
||||
{
|
||||
return ReturnStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Close I2C bus */
|
||||
inline ReturnStatus I2CBus::close()
|
||||
{
|
||||
return ReturnStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to I2C device */
|
||||
inline I2CBus::ReturnType I2CBus::write(const uint8_t address, const WriteBuf buf, const Timeout timeout) const
|
||||
{
|
||||
const auto ret = HAL_I2C_Master_Transmit(m_i2cHandle,
|
||||
address << 1,
|
||||
const_cast<uint8_t *>(buf.data()),
|
||||
buf.size(),
|
||||
timeout.count());
|
||||
|
||||
if (ret == HAL_OK)
|
||||
return buf.size();
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
if (ret == HAL_ERROR && m_i2cHandle->ErrorCode == HAL_I2C_ERROR_TIMEOUT)
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from I2C device */
|
||||
inline I2CBus::ReturnType I2CBus::read(const uint8_t address, const ReadBuf buf, const Timeout timeout) const
|
||||
{
|
||||
const auto ret = HAL_I2C_Master_Receive(m_i2cHandle,
|
||||
address << 1,
|
||||
buf.data(),
|
||||
buf.size(),
|
||||
timeout.count());
|
||||
|
||||
if (ret == HAL_OK)
|
||||
return buf.size();
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
if (ret == HAL_ERROR && m_i2cHandle->ErrorCode == HAL_I2C_ERROR_TIMEOUT)
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Check if I2C device is ready */
|
||||
inline ReturnStatus I2CBus::isDeviceReady(const uint8_t address) const
|
||||
{
|
||||
const auto ret = HAL_I2C_IsDeviceReady(m_i2cHandle,
|
||||
address << 1,
|
||||
5,
|
||||
100);
|
||||
|
||||
if (ret == HAL_OK)
|
||||
return ReturnStatus::Ok;
|
||||
if (ret == HAL_BUSY)
|
||||
return ReturnStatus::Busy;
|
||||
if (ret == HAL_ERROR && m_i2cHandle->ErrorCode == HAL_I2C_ERROR_TIMEOUT)
|
||||
return ReturnStatus::Timeout;
|
||||
|
||||
return ReturnStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::comm
|
||||
201
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/comm/UARTBus.h
Normal file
201
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/comm/UARTBus.h
Normal file
@@ -0,0 +1,201 @@
|
||||
//{{copyright}}
|
||||
|
||||
//{{version}}
|
||||
|
||||
//{{license}}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../comm/SerialBus.h"
|
||||
|
||||
#include <STM32Headers.h>
|
||||
#include <chrono>
|
||||
#include <expected>
|
||||
#include <span>
|
||||
|
||||
namespace sdi_uToolBox::stm32::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class UARTBus : public sdi_uToolBox::comm::SerialBus
|
||||
{
|
||||
public:
|
||||
using ReadBuf = std::span<uint8_t>;
|
||||
using WriteBuf = std::span<const uint8_t>;
|
||||
using Timeout = std::chrono::milliseconds;
|
||||
using ReturnType = std::expected<size_t, ReturnStatus>;
|
||||
|
||||
public:
|
||||
UARTBus() = default; // Default constructor
|
||||
virtual ~UARTBus() = default; // Default destructor
|
||||
UARTBus(const UARTBus &) = delete; // Copy constructor
|
||||
UARTBus(UARTBus &&) = delete; // Move constructor
|
||||
UARTBus &operator=(const UARTBus &) = delete; // Copy assignment operator
|
||||
UARTBus &operator=(UARTBus &&) = delete; // Move assignment operator
|
||||
|
||||
virtual ReturnStatus configure(UART_HandleTypeDef *handle); // Configure UART bus with HAL handle
|
||||
|
||||
ReturnStatus open() override; // Open UART bus
|
||||
ReturnStatus close() override; // Close UART bus
|
||||
|
||||
ReturnType write(WriteBuf buf, Timeout timeout) const override; // Write data to UART device
|
||||
ReturnType read(ReadBuf buf, Timeout timeout) const override; // Read data from UART device
|
||||
|
||||
protected:
|
||||
UART_HandleTypeDef *m_uartHandle = nullptr; // HAL UART handle
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Configure UART bus with HAL handle */
|
||||
inline ReturnStatus UARTBus::configure(UART_HandleTypeDef *handle)
|
||||
{
|
||||
if (!handle)
|
||||
return ReturnStatus::InvalidHandle;
|
||||
|
||||
m_uartHandle = handle;
|
||||
return ReturnStatus::Ok;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Open UART bus */
|
||||
inline ReturnStatus UARTBus::open()
|
||||
{
|
||||
if (!m_uartHandle)
|
||||
return ReturnStatus::InvalidHandle;
|
||||
|
||||
return ReturnStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Close UART bus */
|
||||
inline ReturnStatus UARTBus::close()
|
||||
{
|
||||
if (!m_uartHandle)
|
||||
return ReturnStatus::InvalidHandle;
|
||||
|
||||
// Abort ongoing operations
|
||||
HAL_UART_AbortTransmit(m_uartHandle);
|
||||
HAL_UART_AbortReceive(m_uartHandle);
|
||||
|
||||
return ReturnStatus::Error;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Write data to UART device */
|
||||
inline UARTBus::ReturnType UARTBus::write(const WriteBuf buf, const Timeout timeout) const
|
||||
{
|
||||
const auto ret = HAL_UART_Transmit(m_uartHandle,
|
||||
const_cast<uint8_t *>(buf.data()),
|
||||
buf.size(),
|
||||
timeout.count());
|
||||
|
||||
if (ret == HAL_OK)
|
||||
return buf.size();
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
if (ret == HAL_TIMEOUT)
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Read data from UART device */
|
||||
inline UARTBus::ReturnType UARTBus::read(const ReadBuf buf, const Timeout timeout) const
|
||||
{
|
||||
const auto ret = HAL_UART_Receive(m_uartHandle,
|
||||
buf.data(),
|
||||
buf.size(),
|
||||
timeout.count());
|
||||
|
||||
if (ret == HAL_OK)
|
||||
return buf.size();
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
if (ret == HAL_TIMEOUT)
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
class UARTBusCallback
|
||||
{
|
||||
friend class UARTBusCallbackRegistry;
|
||||
|
||||
public:
|
||||
UARTBusCallback() = default; // Default constructor
|
||||
virtual ~UARTBusCallback() = default; // Default destructor
|
||||
UARTBusCallback(const UARTBusCallback &) = default; // Copy constructor
|
||||
UARTBusCallback &operator=(const UARTBusCallback &) = default; // Copy assignment operator
|
||||
UARTBusCallback(UARTBusCallback &&) = default; // Move constructor
|
||||
UARTBusCallback &operator=(UARTBusCallback &&) = default; // Move assignment operator
|
||||
|
||||
virtual void txCompleteCallback() const = 0;
|
||||
virtual void rxCompleteCallback() const = 0;
|
||||
virtual void rxEventCallback(uint16_t size) const = 0;
|
||||
virtual void errorCallback() const = 0;
|
||||
|
||||
protected:
|
||||
struct RegistryEntry
|
||||
{
|
||||
const UART_HandleTypeDef *handle = nullptr;
|
||||
const UARTBusCallback *instance = nullptr;
|
||||
};
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
/* --- */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
class UARTBusCallbackRegistry
|
||||
{
|
||||
static constexpr size_t MAX_UART_INSTANCES = 4;
|
||||
|
||||
public:
|
||||
static bool registerInstance(const UART_HandleTypeDef *handle, const UARTBusCallback *instance); // Register instance with UART handle
|
||||
static void unregisterInstance(const UARTBusCallback *instance); // Unregister instance with UART handle
|
||||
static const UARTBusCallback *getInstance(const UART_HandleTypeDef *handle); // Get instance from UART handle
|
||||
|
||||
protected:
|
||||
static inline std::array<UARTBusCallback::RegistryEntry, MAX_UART_INSTANCES> s_registry;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
/* Register instance with UART handle */
|
||||
inline bool UARTBusCallbackRegistry::registerInstance(const UART_HandleTypeDef *handle, const UARTBusCallback *instance)
|
||||
{
|
||||
for (auto &entry : s_registry)
|
||||
{
|
||||
if (!entry.handle)
|
||||
{
|
||||
entry.handle = handle;
|
||||
entry.instance = instance;
|
||||
return true; // Successfully registered
|
||||
}
|
||||
}
|
||||
|
||||
return false; // Registry full
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Unregister instance with UART handle */
|
||||
inline void UARTBusCallbackRegistry::unregisterInstance(const UARTBusCallback *instance)
|
||||
{
|
||||
for (auto &entry : s_registry)
|
||||
{
|
||||
if (entry.instance == instance)
|
||||
{
|
||||
entry.handle = nullptr;
|
||||
entry.instance = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Get instance from UART handle */
|
||||
inline const UARTBusCallback *UARTBusCallbackRegistry::getInstance(const UART_HandleTypeDef *handle)
|
||||
{
|
||||
for (const auto &entry : s_registry)
|
||||
{
|
||||
if (entry.handle == handle)
|
||||
return entry.instance;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::comm
|
||||
@@ -0,0 +1,198 @@
|
||||
/* ---
|
||||
* FONCTIONNEMENT PAS TRES CLAIR, A REVOIR
|
||||
*/
|
||||
|
||||
//{{copyright}}
|
||||
|
||||
//{{version}}
|
||||
|
||||
//{{license}}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UARTBus.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace sdi_uToolBox::stm32::comm
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
class UARTBusIT : public stm32::comm::UARTBus
|
||||
{
|
||||
public:
|
||||
UARTBusIT() = default; // Default constructor
|
||||
virtual ~UARTBusIT() override = default; // Default destructor
|
||||
UARTBusIT(const UARTBusIT &) = delete; // Copy constructor
|
||||
UARTBusIT(UARTBusIT &&) = delete; // Move constructor
|
||||
UARTBusIT &operator=(const UARTBusIT &) = delete; // Copy assignment operator
|
||||
UARTBusIT &operator=(UARTBusIT &&) = delete; // Move assignment operator
|
||||
|
||||
ReturnType write(WriteBuf buf, Timeout timeout) const override; // Write data to UART device
|
||||
ReturnType read(ReadBuf buf, Timeout timeout) const override; // Read data from UART device
|
||||
|
||||
// Callback to be called from ISR when TX, RX is complete or error occurs
|
||||
void txCompleteCallback() const; // TX complete callback
|
||||
void rxCompleteCallback() const; // RX complete callback
|
||||
void errorCallback() const; // Error callback
|
||||
|
||||
protected:
|
||||
mutable std::array<uint8_t, TX_BUFFER_SIZE> m_txBuffer;
|
||||
mutable std::array<uint8_t, RX_BUFFER_SIZE> m_rxBuffer;
|
||||
|
||||
mutable std::atomic<bool> m_txComplete{ false };
|
||||
mutable std::atomic<bool> m_rxComplete{ false };
|
||||
mutable std::atomic<bool> m_txError{ false };
|
||||
mutable std::atomic<bool> m_rxError{ false };
|
||||
mutable std::atomic<size_t> m_lastTxSize{ 0 };
|
||||
mutable std::atomic<size_t> m_lastRxSize{ 0 };
|
||||
|
||||
static bool waitForFlag(const std::atomic<bool> &flag, Timeout timeout);
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBus::ReturnType UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::write(const WriteBuf buf, const Timeout timeout) const
|
||||
{
|
||||
if (!m_uartHandle)
|
||||
return std::unexpected(ReturnStatus::InvalidHandle);
|
||||
|
||||
if (buf.size() > TX_BUFFER_SIZE)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Copy data to internal buffer
|
||||
std::copy(buf.begin(), buf.end(), m_txBuffer.begin());
|
||||
|
||||
// Reset flags
|
||||
m_txComplete.store(false, std::memory_order_release);
|
||||
m_txError.store(false, std::memory_order_release);
|
||||
m_lastTxSize.store(0, std::memory_order_release);
|
||||
|
||||
// Start transmission with interrupt
|
||||
const auto ret = HAL_UART_Transmit_IT(m_uartHandle,
|
||||
const_cast<uint8_t *>(m_txBuffer.data()),
|
||||
buf.size());
|
||||
|
||||
if (ret != HAL_OK)
|
||||
{
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
|
||||
// Wait for transmission to complete
|
||||
if (!waitForFlag(m_txComplete, timeout))
|
||||
{
|
||||
HAL_UART_AbortTransmit(m_uartHandle);
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
}
|
||||
|
||||
// Check for errors
|
||||
if (m_txError.load(std::memory_order_acquire))
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
return m_lastTxSize.load(std::memory_order_acquire);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline UARTBus::ReturnType UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::read(ReadBuf buf, const Timeout timeout) const
|
||||
{
|
||||
if (!m_uartHandle)
|
||||
return std::unexpected(ReturnStatus::InvalidHandle);
|
||||
|
||||
if (buf.size() > RX_BUFFER_SIZE)
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Reset flags
|
||||
m_rxComplete.store(false, std::memory_order_release);
|
||||
m_rxError.store(false, std::memory_order_release);
|
||||
m_lastRxSize.store(0, std::memory_order_release);
|
||||
|
||||
// Start reception with interrupt
|
||||
const auto ret = HAL_UART_Receive_IT(m_uartHandle,
|
||||
m_rxBuffer.data(),
|
||||
buf.size());
|
||||
|
||||
if (ret != HAL_OK)
|
||||
{
|
||||
if (ret == HAL_BUSY)
|
||||
return std::unexpected(ReturnStatus::Busy);
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
}
|
||||
|
||||
// Wait for reception to complete
|
||||
if (!waitForFlag(m_rxComplete, timeout))
|
||||
{
|
||||
HAL_UART_AbortReceive(m_uartHandle);
|
||||
return std::unexpected(ReturnStatus::Timeout);
|
||||
}
|
||||
|
||||
// Check for errors
|
||||
if (m_rxError.load(std::memory_order_acquire))
|
||||
return std::unexpected(ReturnStatus::Error);
|
||||
|
||||
// Copy data from internal buffer to output buffer
|
||||
const size_t receivedSize = m_lastRxSize.load(std::memory_order_acquire);
|
||||
std::copy_n(m_rxBuffer.begin(), receivedSize, buf.begin());
|
||||
|
||||
return receivedSize;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* TX complete callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::txCompleteCallback() const
|
||||
{
|
||||
m_lastTxSize.store(m_uartHandle->TxXferSize - m_uartHandle->TxXferCount,
|
||||
std::memory_order_release);
|
||||
m_txComplete.store(true, std::memory_order_release);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* RX complete callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::rxCompleteCallback() const
|
||||
{
|
||||
m_lastRxSize.store(m_uartHandle->RxXferSize - m_uartHandle->RxXferCount,
|
||||
std::memory_order_release);
|
||||
m_rxComplete.store(true, std::memory_order_release);
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Error callback */
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline void UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::errorCallback() const
|
||||
{
|
||||
if (m_uartHandle->gState == HAL_UART_STATE_BUSY_TX ||
|
||||
m_uartHandle->gState == HAL_UART_STATE_BUSY_TX_RX)
|
||||
{
|
||||
m_txError.store(true, std::memory_order_release);
|
||||
m_txComplete.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
if (m_uartHandle->RxState == HAL_UART_STATE_BUSY_RX ||
|
||||
m_uartHandle->gState == HAL_UART_STATE_BUSY_TX_RX)
|
||||
{
|
||||
m_rxError.store(true, std::memory_order_release);
|
||||
m_rxComplete.store(true, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
template<size_t TX_BUFFER_SIZE, size_t RX_BUFFER_SIZE>
|
||||
inline bool UARTBusIT<TX_BUFFER_SIZE, RX_BUFFER_SIZE>::waitForFlag(const std::atomic<bool> &flag, Timeout timeout)
|
||||
{
|
||||
const auto startTime = std::chrono::steady_clock::now();
|
||||
|
||||
while (!flag.load(std::memory_order_acquire))
|
||||
{
|
||||
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - startTime);
|
||||
|
||||
if (elapsed >= timeout)
|
||||
return false;
|
||||
|
||||
// Small delay to avoid busy waiting consuming too much CPU
|
||||
for (volatile int i = 0; i < 1000; ++i)
|
||||
;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32::comm
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
{{copyright}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{version}}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{license}}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace sdi_uToolBox::stm32
|
||||
{
|
||||
//--------------------------------------------------------------
|
||||
class CriticalSection final
|
||||
{
|
||||
public:
|
||||
CriticalSection(); // Constructor
|
||||
~CriticalSection(); // Destructor
|
||||
CriticalSection(const CriticalSection &other) = delete; // Copy constructor
|
||||
CriticalSection(CriticalSection &&other) noexcept = delete; // Move constructor
|
||||
CriticalSection &operator=(const CriticalSection &other) = delete; // Copy assignment
|
||||
CriticalSection &operator=(CriticalSection &&other) noexcept = delete; // Move assignment
|
||||
|
||||
protected:
|
||||
uint32_t m_primask;
|
||||
};
|
||||
//--------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/* Constructor */
|
||||
inline CriticalSection::CriticalSection()
|
||||
{
|
||||
m_primask = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
/* Destructor */
|
||||
inline CriticalSection::~CriticalSection()
|
||||
{
|
||||
if ((m_primask & 0x01) == 0) // Only if interrupts were enabled
|
||||
__enable_irq();
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
} // namespace sdi_uToolBox::stm32
|
||||
20
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/defs.h
Normal file
20
sdi_toolBox_1.0.x/toolBox/sdi_uToolBox/stm32/defs.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <main.h>
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Set a real type for FPU usage if available
|
||||
#if defined(__FPU_PRESENT) && (__FPU_PRESENT == 1U)
|
||||
# if defined(__FPU_DP) && (__FPU_DP == 1U)
|
||||
// FPU with double precision support
|
||||
using Real = double;
|
||||
# else
|
||||
// FPU with single precision only
|
||||
using Real = float;
|
||||
# endif
|
||||
#else
|
||||
// No FPU present. Floating point will be emulated
|
||||
// (It is better to use a smaller type to be cheaper)
|
||||
using Real = float;
|
||||
#endif
|
||||
//--------------------------------------------------------------
|
||||
Reference in New Issue
Block a user