Merge develop into main branch (#137)
* SdCard HAL refactored (#135) - Refactor SdCard HAL - introduce Lockable * Screenshot and FatFS improvements (#136) - Fix screenshots on ESP32 - Improve Screenshot service - Convert Screenshot app to class-based instead of structs - Screenshot app now automatically updates when task is finished - Enable FatFS long filename support * Re-use common log messages (#138) For consistency and binary size reduction * Toolbar spinner should get margin to the right * More TactilityC features (#139) * Rewrote Loader - Simplified Loader by removing custom threa - Created DispatcherThread - Move auto-starting apps to Boot app - Fixed Dispatcher bug where it could get stuck not processing new messages * Hide AP settings if the AP is not saved * Missing from previous commit * Replace LV_EVENT_CLICKED with LV_EVENT_SHORT_CLICKED * Refactored files app and created InputDialog (#140) - Changed Files app so that it has a View and State - Files app now allows for long-pressing on files to perform actions - Files app now has rename and delete actions - Created InputDialog app - Improved AlertDialog app layout
This commit is contained in:
committed by
GitHub
parent
9033daa6dd
commit
50bd6e8bf6
@@ -5,10 +5,12 @@
|
||||
|
||||
namespace tt {
|
||||
|
||||
[[deprecated("Using this is poor software design in most scenarios")]]
|
||||
typedef enum {
|
||||
TtWaitForever = 0xFFFFFFFFU,
|
||||
} TtWait;
|
||||
|
||||
[[deprecated("Define flags as needed")]]
|
||||
typedef enum {
|
||||
TtFlagWaitAny = 0x00000000U, ///< Wait for any flag (default).
|
||||
TtFlagWaitAll = 0x00000001U, ///< Wait for all flags.
|
||||
@@ -22,6 +24,7 @@ typedef enum {
|
||||
TtFlagErrorISR = 0xFFFFFFFAU, ///< TtStatusErrorISR (-6).
|
||||
} TtFlag;
|
||||
|
||||
[[deprecated("Use bool or specific type")]]
|
||||
typedef enum {
|
||||
TtStatusOk = 0, ///< Operation completed successfully.
|
||||
TtStatusError =
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <kernel/Kernel.h>
|
||||
#include "Dispatcher.h"
|
||||
#include "Check.h"
|
||||
|
||||
@@ -19,32 +20,59 @@ Dispatcher::~Dispatcher() {
|
||||
void Dispatcher::dispatch(Callback callback, std::shared_ptr<void> context) {
|
||||
auto message = std::make_shared<DispatcherMessage>(callback, std::move(context));
|
||||
// Mutate
|
||||
mutex.acquire(TtWaitForever);
|
||||
queue.push(std::move(message));
|
||||
if (queue.size() == BACKPRESSURE_WARNING_COUNT) {
|
||||
TT_LOG_W(TAG, "Backpressure: You're not consuming fast enough (100 queued)");
|
||||
if (mutex.lock(1000 / portTICK_PERIOD_MS)) {
|
||||
queue.push(std::move(message));
|
||||
TT_LOG_I(TAG, "dispatch");
|
||||
if (queue.size() == BACKPRESSURE_WARNING_COUNT) {
|
||||
TT_LOG_W(TAG, "Backpressure: You're not consuming fast enough (100 queued)");
|
||||
}
|
||||
mutex.unlock();
|
||||
// Signal
|
||||
eventFlag.set(1);
|
||||
} else {
|
||||
TT_LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
||||
}
|
||||
mutex.release();
|
||||
// Signal
|
||||
eventFlag.set(1);
|
||||
}
|
||||
|
||||
uint32_t Dispatcher::consume(uint32_t timeout_ticks) {
|
||||
// Wait for signal and clear
|
||||
eventFlag.wait(1, TtFlagWaitAny, timeout_ticks);
|
||||
eventFlag.clear(1);
|
||||
|
||||
// Mutate
|
||||
if (mutex.acquire(1 / portTICK_PERIOD_MS) == TtStatusOk) {
|
||||
auto item = queue.front();
|
||||
queue.pop();
|
||||
// Don't keep lock as callback might be slow
|
||||
tt_check(mutex.release() == TtStatusOk);
|
||||
|
||||
item->callback(item->context);
|
||||
TickType_t start_ticks = kernel::getTicks();
|
||||
if (eventFlag.wait(1, TtFlagWaitAny, timeout_ticks) == TtStatusErrorTimeout) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
TickType_t ticks_remaining = TT_MAX(timeout_ticks - (kernel::getTicks() - start_ticks), 0);
|
||||
|
||||
eventFlag.clear(1);
|
||||
|
||||
TT_LOG_I(TAG, "Dispatcher continuing");
|
||||
|
||||
// Mutate
|
||||
bool processing = true;
|
||||
uint32_t consumed = 0;
|
||||
do {
|
||||
if (mutex.lock(ticks_remaining / portTICK_PERIOD_MS)) {
|
||||
if (!queue.empty()) {
|
||||
TT_LOG_I(TAG, "Dispatcher popping from queue");
|
||||
auto item = queue.front();
|
||||
queue.pop();
|
||||
consumed++;
|
||||
processing = !queue.empty();
|
||||
// Don't keep lock as callback might be slow
|
||||
|
||||
tt_check(mutex.unlock());
|
||||
item->callback(item->context);
|
||||
} else {
|
||||
tt_check(mutex.unlock());
|
||||
}
|
||||
|
||||
} else {
|
||||
TT_LOG_E(TAG, LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
||||
}
|
||||
|
||||
} while (processing);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "DispatcherThread.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
int32_t dispatcherThreadMain(void* context) {
|
||||
auto* dispatcherThread = (DispatcherThread*)context;
|
||||
dispatcherThread->_threadMain();
|
||||
return 0;
|
||||
}
|
||||
|
||||
DispatcherThread::DispatcherThread(const std::string& threadName, size_t threadStackSize) {
|
||||
thread = std::make_unique<Thread>(
|
||||
threadName,
|
||||
threadStackSize,
|
||||
dispatcherThreadMain,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
DispatcherThread::~DispatcherThread() {
|
||||
if (thread->getState() != Thread::StateStopped) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void DispatcherThread::_threadMain() {
|
||||
do {
|
||||
dispatcher.consume(1000);
|
||||
} while (!interruptThread);
|
||||
}
|
||||
|
||||
void DispatcherThread::dispatch(Callback callback, std::shared_ptr<void> context) {
|
||||
dispatcher.dispatch(callback, std::move(context));
|
||||
}
|
||||
|
||||
void DispatcherThread::start() {
|
||||
interruptThread = false;
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void DispatcherThread::stop() {
|
||||
interruptThread = true;
|
||||
thread->join();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dispatcher.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
/** Starts a Thread to process dispatched messages */
|
||||
class DispatcherThread {
|
||||
|
||||
Dispatcher dispatcher;
|
||||
std::unique_ptr<Thread> thread;
|
||||
bool interruptThread = false;
|
||||
|
||||
public:
|
||||
|
||||
explicit DispatcherThread(const std::string& threadName, size_t threadStackSize = 4096);
|
||||
~DispatcherThread();
|
||||
|
||||
/**
|
||||
* Dispatch a message.
|
||||
*/
|
||||
void dispatch(Callback callback, std::shared_ptr<void> context);
|
||||
|
||||
/** Start the thread (blocking). */
|
||||
void start();
|
||||
|
||||
/** Stop the thread (blocking). */
|
||||
void stop();
|
||||
|
||||
/** Internal method */
|
||||
void _threadMain();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "Lockable.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
std::unique_ptr<ScopedLockableUsage> Lockable::scoped() const {
|
||||
auto* scoped = new ScopedLockableUsage(*this);
|
||||
return std::unique_ptr<ScopedLockableUsage>(scoped);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "Check.h"
|
||||
#include <memory>
|
||||
|
||||
namespace tt {
|
||||
|
||||
class ScopedLockableUsage;
|
||||
|
||||
class Lockable {
|
||||
public:
|
||||
virtual ~Lockable() = default;
|
||||
|
||||
virtual bool lock(uint32_t timeoutTicks) const = 0;
|
||||
virtual bool unlock() const = 0;
|
||||
|
||||
std::unique_ptr<ScopedLockableUsage> scoped() const;
|
||||
};
|
||||
|
||||
class ScopedLockableUsage final : public Lockable {
|
||||
|
||||
const Lockable& lockable;
|
||||
|
||||
public:
|
||||
|
||||
explicit ScopedLockableUsage(const Lockable& lockable) : lockable(lockable) {}
|
||||
|
||||
~ScopedLockableUsage() final {
|
||||
lockable.unlock(); // We don't care whether it succeeded or not
|
||||
}
|
||||
|
||||
bool lock(uint32_t timeout) const override {
|
||||
return lockable.lock(timeout);
|
||||
}
|
||||
|
||||
bool unlock() const override {
|
||||
return lockable.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "LogMessages.h"
|
||||
|
||||
#ifdef ESP_TARGET
|
||||
#include "esp_log.h"
|
||||
#else
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Contains common log messages.
|
||||
* This helps to keep the binary smaller.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// Mutex
|
||||
#define LOG_MESSAGE_MUTEX_LOCK_FAILED "Mutex acquisition timeout"
|
||||
#define LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT "Mutex acquisition timeout (%s)"
|
||||
|
||||
// SPI
|
||||
#define LOG_MESSAGE_SPI_INIT_START_FMT "SPI %d init"
|
||||
#define LOG_MESSAGE_SPI_INIT_FAILED_FMT "SPI %d init failed"
|
||||
|
||||
// I2C
|
||||
#define LOG_MESSAGE_I2C_INIT_START "I2C init"
|
||||
#define LOG_MESSAGE_I2C_INIT_CONFIG_FAILED "I2C config failed"
|
||||
#define LOG_MESSAGE_I2C_INIT_DRIVER_INSTALL_FAILED "I2C driver install failed"
|
||||
|
||||
// Power on
|
||||
#define LOG_MESSAGE_POWER_ON_START "Power on"
|
||||
#define LOG_MESSAGE_POWER_ON_FAILED "Power on failed"
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
namespace tt {
|
||||
|
||||
MessageQueue::MessageQueue(uint32_t msg_count, uint32_t msg_size) {
|
||||
tt_assert((kernel::isIrq() == 0U) && (msg_count > 0U) && (msg_size > 0U));
|
||||
queue_handle = xQueueCreate(msg_count, msg_size);
|
||||
MessageQueue::MessageQueue(uint32_t capacity, uint32_t msg_size) {
|
||||
tt_assert((kernel::isIrq() == 0U) && (capacity > 0U) && (msg_size > 0U));
|
||||
queue_handle = xQueueCreate(capacity, msg_size);
|
||||
tt_check(queue_handle);
|
||||
}
|
||||
|
||||
@@ -15,106 +15,75 @@ MessageQueue::~MessageQueue() {
|
||||
vQueueDelete(queue_handle);
|
||||
}
|
||||
|
||||
TtStatus MessageQueue::put(const void* msg_ptr, uint32_t timeout) {
|
||||
TtStatus stat;
|
||||
bool MessageQueue::put(const void* message, uint32_t timeout) {
|
||||
bool result = true;
|
||||
BaseType_t yield;
|
||||
|
||||
stat = TtStatusOk;
|
||||
|
||||
if (kernel::isIrq() != 0U) {
|
||||
if ((queue_handle == nullptr) || (msg_ptr == nullptr) || (timeout != 0U)) {
|
||||
stat = TtStatusErrorParameter;
|
||||
if ((queue_handle == nullptr) || (message == nullptr) || (timeout != 0U)) {
|
||||
result = false;
|
||||
} else {
|
||||
yield = pdFALSE;
|
||||
|
||||
if (xQueueSendToBackFromISR(queue_handle, msg_ptr, &yield) != pdTRUE) {
|
||||
stat = TtStatusErrorResource;
|
||||
if (xQueueSendToBackFromISR(queue_handle, message, &yield) != pdTRUE) {
|
||||
result = false;
|
||||
} else {
|
||||
portYIELD_FROM_ISR(yield);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((queue_handle == nullptr) || (msg_ptr == nullptr)) {
|
||||
stat = TtStatusErrorParameter;
|
||||
} else {
|
||||
if (xQueueSendToBack(queue_handle, msg_ptr, (TickType_t)timeout) != pdPASS) {
|
||||
if (timeout != 0U) {
|
||||
stat = TtStatusErrorTimeout;
|
||||
} else {
|
||||
stat = TtStatusErrorResource;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((queue_handle == nullptr) || (message == nullptr)) {
|
||||
result = false;
|
||||
} else if (xQueueSendToBack(queue_handle, message, (TickType_t)timeout) != pdPASS) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
/* Return execution status */
|
||||
return (stat);
|
||||
return result;
|
||||
}
|
||||
|
||||
TtStatus MessageQueue::get(void* msg_ptr, uint32_t timeout_ticks) {
|
||||
TtStatus stat;
|
||||
bool MessageQueue::get(void* msg_ptr, uint32_t timeout_ticks) {
|
||||
bool result = true;
|
||||
BaseType_t yield;
|
||||
|
||||
stat = TtStatusOk;
|
||||
|
||||
if (kernel::isIrq() != 0U) {
|
||||
if (kernel::isIrq()) {
|
||||
if ((queue_handle == nullptr) || (msg_ptr == nullptr) || (timeout_ticks != 0U)) {
|
||||
stat = TtStatusErrorParameter;
|
||||
result = false;
|
||||
} else {
|
||||
yield = pdFALSE;
|
||||
|
||||
if (xQueueReceiveFromISR(queue_handle, msg_ptr, &yield) != pdPASS) {
|
||||
stat = TtStatusErrorResource;
|
||||
result = false;
|
||||
} else {
|
||||
portYIELD_FROM_ISR(yield);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((queue_handle == nullptr) || (msg_ptr == nullptr)) {
|
||||
stat = TtStatusErrorParameter;
|
||||
} else {
|
||||
if (xQueueReceive(queue_handle, msg_ptr, (TickType_t)timeout_ticks) != pdPASS) {
|
||||
if (timeout_ticks != 0U) {
|
||||
stat = TtStatusErrorTimeout;
|
||||
} else {
|
||||
stat = TtStatusErrorResource;
|
||||
}
|
||||
}
|
||||
result = false;
|
||||
} else if (xQueueReceive(queue_handle, msg_ptr, (TickType_t)timeout_ticks) != pdPASS) {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return execution status */
|
||||
return (stat);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t MessageQueue::getCapacity() const {
|
||||
auto* mq = (StaticQueue_t*)(queue_handle);
|
||||
uint32_t capacity;
|
||||
|
||||
if (mq == nullptr) {
|
||||
capacity = 0U;
|
||||
return 0U;
|
||||
} else {
|
||||
/* capacity = pxQueue->uxLength */
|
||||
capacity = mq->uxDummy4[1];
|
||||
return mq->uxDummy4[1];
|
||||
}
|
||||
|
||||
/* Return maximum number of messages */
|
||||
return (capacity);
|
||||
}
|
||||
|
||||
uint32_t MessageQueue::getMessageSize() const {
|
||||
auto* mq = (StaticQueue_t*)(queue_handle);
|
||||
uint32_t size;
|
||||
|
||||
if (mq == nullptr) {
|
||||
size = 0U;
|
||||
return 0U;
|
||||
} else {
|
||||
/* size = pxQueue->uxItemSize */
|
||||
size = mq->uxDummy4[2];
|
||||
return mq->uxDummy4[2];
|
||||
}
|
||||
|
||||
/* Return maximum message size */
|
||||
return (size);
|
||||
}
|
||||
|
||||
uint32_t MessageQueue::getCount() const {
|
||||
@@ -129,7 +98,7 @@ uint32_t MessageQueue::getCount() const {
|
||||
}
|
||||
|
||||
/* Return number of queued messages */
|
||||
return ((uint32_t)count);
|
||||
return (uint32_t)count;
|
||||
}
|
||||
|
||||
uint32_t MessageQueue::getSpace() const {
|
||||
@@ -150,24 +119,17 @@ uint32_t MessageQueue::getSpace() const {
|
||||
space = (uint32_t)uxQueueSpacesAvailable((QueueHandle_t)mq);
|
||||
}
|
||||
|
||||
/* Return number of available slots */
|
||||
return (space);
|
||||
return space;
|
||||
}
|
||||
|
||||
TtStatus MessageQueue::reset() {
|
||||
TtStatus stat;
|
||||
|
||||
if (kernel::isIrq() != 0U) {
|
||||
stat = TtStatusErrorISR;
|
||||
} else if (queue_handle == nullptr) {
|
||||
stat = TtStatusErrorParameter;
|
||||
bool MessageQueue::reset() {
|
||||
tt_check(!kernel::isIrq());
|
||||
if (queue_handle == nullptr) {
|
||||
return false;
|
||||
} else {
|
||||
stat = TtStatusOk;
|
||||
(void)xQueueReset(queue_handle);
|
||||
xQueueReset(queue_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Return execution status */
|
||||
return (stat);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -19,81 +19,61 @@
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* Message Queue implementation.
|
||||
* Calls can be done from ISR/IRQ mode unless otherwise specified.
|
||||
*/
|
||||
class MessageQueue {
|
||||
private:
|
||||
QueueHandle_t queue_handle;
|
||||
|
||||
public:
|
||||
/** Allocate message queue
|
||||
*
|
||||
* @param[in] msg_count The message count
|
||||
* @param[in] msg_size The message size
|
||||
* @param[in] capacity Maximum messages in queue
|
||||
* @param[in] messageSize The size in bytes of a single message
|
||||
*/
|
||||
MessageQueue(uint32_t msg_count, uint32_t msg_size);
|
||||
MessageQueue(uint32_t capacity, uint32_t messageSize);
|
||||
|
||||
~MessageQueue();
|
||||
|
||||
/** Put message into queue
|
||||
*
|
||||
* @param instance pointer to MessageQueue instance
|
||||
* @param[in] msg_ptr The message pointer
|
||||
* @param[in] timeout The timeout
|
||||
* @param[in] msg_prio The message prio
|
||||
*
|
||||
* @return The status.
|
||||
* @param[in] message A pointer to a message. The message will be copied into a buffer.
|
||||
* @param[in] timeoutTicks
|
||||
* @return success result
|
||||
*/
|
||||
TtStatus put(const void* msg_ptr, uint32_t timeout);
|
||||
bool put(const void* message, uint32_t timeoutTicks);
|
||||
|
||||
/** Get message from queue
|
||||
*
|
||||
* @param instance pointer to MessageQueue instance
|
||||
* @param msg_ptr The message pointer
|
||||
* @param msg_prio The message prioority
|
||||
* @param[in] timeout_ticks The timeout
|
||||
*
|
||||
* @return The status.
|
||||
* @param message A pointer to an already allocated message object
|
||||
* @param[in] timeoutTicks
|
||||
* @return success result
|
||||
*/
|
||||
TtStatus get(void* msg_ptr, uint32_t timeout_ticks);
|
||||
bool get(void* message, uint32_t timeoutTicks);
|
||||
|
||||
/** Get queue capacity
|
||||
*
|
||||
* @param instance pointer to MessageQueue instance
|
||||
*
|
||||
* @return capacity in object count
|
||||
/**
|
||||
* @return The maximum amount of messages that can be in the queue at any given time.
|
||||
*/
|
||||
uint32_t getCapacity() const;
|
||||
|
||||
/** Get message size
|
||||
*
|
||||
* @param instance pointer to MessageQueue instance
|
||||
*
|
||||
* @return Message size in bytes
|
||||
/**
|
||||
* @return The size of a single message in bytes
|
||||
*/
|
||||
uint32_t getMessageSize() const;
|
||||
|
||||
/** Get message count in queue
|
||||
*
|
||||
* @param instance pointer to MessageQueue instance
|
||||
*
|
||||
* @return Message count
|
||||
/**
|
||||
* @return How many messages are currently in the queue.
|
||||
*/
|
||||
uint32_t getCount() const;
|
||||
|
||||
/** Get queue available space
|
||||
*
|
||||
* @param instance pointer to MessageQueue instance
|
||||
*
|
||||
* @return Message count
|
||||
/**
|
||||
* @return How many messages can be added to the queue before the put() method starts blocking.
|
||||
*/
|
||||
uint32_t getSpace() const;
|
||||
|
||||
/** Reset queue
|
||||
*
|
||||
* @param instance pointer to MessageQueue instance
|
||||
*
|
||||
* @return The status.
|
||||
/** Reset queue (cannot be called in ISR/IRQ mode)
|
||||
* @return success result
|
||||
*/
|
||||
TtStatus reset();
|
||||
bool reset();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -110,11 +110,6 @@ ThreadId Mutex::getOwner() const {
|
||||
return (ThreadId)xSemaphoreGetMutexHolder(semaphore);
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<ScopedMutexUsage> Mutex::scoped() const {
|
||||
return std::make_unique<ScopedMutexUsage>(*this);
|
||||
}
|
||||
|
||||
Mutex* tt_mutex_alloc(Mutex::Type type) {
|
||||
return new Mutex(type);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Thread.h"
|
||||
#include "RtosCompatSemaphore.h"
|
||||
#include "Check.h"
|
||||
#include "Lockable.h"
|
||||
#include <memory>
|
||||
|
||||
namespace tt {
|
||||
@@ -18,7 +19,7 @@ class ScopedMutexUsage;
|
||||
* Wrapper for FreeRTOS xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex
|
||||
* Can be used in IRQ mode (within ISR context)
|
||||
*/
|
||||
class Mutex {
|
||||
class Mutex : public Lockable {
|
||||
|
||||
public:
|
||||
|
||||
@@ -35,35 +36,15 @@ private:
|
||||
public:
|
||||
|
||||
explicit Mutex(Type type = TypeNormal);
|
||||
~Mutex();
|
||||
~Mutex() override;
|
||||
|
||||
TtStatus acquire(uint32_t timeout) const;
|
||||
TtStatus acquire(uint32_t timeoutTicks) const;
|
||||
TtStatus release() const;
|
||||
|
||||
bool lock(uint32_t timeoutTicks) const override { return acquire(timeoutTicks) == TtStatusOk; }
|
||||
bool unlock() const override { return release() == TtStatusOk; }
|
||||
|
||||
ThreadId getOwner() const;
|
||||
|
||||
std::unique_ptr<ScopedMutexUsage> scoped() const;
|
||||
};
|
||||
|
||||
class ScopedMutexUsage {
|
||||
|
||||
const Mutex& mutex;
|
||||
bool acquired = false;
|
||||
|
||||
public:
|
||||
|
||||
ScopedMutexUsage(const Mutex& mutex) : mutex(mutex) {}
|
||||
|
||||
~ScopedMutexUsage() {
|
||||
if (acquired) {
|
||||
tt_check(mutex.release() == TtStatusOk);
|
||||
}
|
||||
}
|
||||
|
||||
bool acquire(uint32_t timeout) {
|
||||
TtStatus result = mutex.acquire(timeout);
|
||||
acquired = (result == TtStatusOk);
|
||||
return acquired;
|
||||
}
|
||||
};
|
||||
|
||||
/** Allocate Mutex
|
||||
|
||||
@@ -28,49 +28,36 @@ Semaphore::~Semaphore() {
|
||||
vSemaphoreDelete(handle);
|
||||
}
|
||||
|
||||
TtStatus Semaphore::acquire(uint32_t timeout) const {
|
||||
bool Semaphore::acquire(uint32_t timeout) const {
|
||||
if (TT_IS_IRQ_MODE()) {
|
||||
if (timeout != 0U) {
|
||||
return TtStatusErrorParameter;
|
||||
return false;
|
||||
} else {
|
||||
BaseType_t yield = pdFALSE;
|
||||
|
||||
if (xSemaphoreTakeFromISR(handle, &yield) != pdPASS) {
|
||||
return TtStatusErrorResource;
|
||||
return false;
|
||||
} else {
|
||||
portYIELD_FROM_ISR(yield);
|
||||
return TtStatusOk;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (xSemaphoreTake(handle, (TickType_t)timeout) != pdPASS) {
|
||||
if (timeout != 0U) {
|
||||
return TtStatusErrorTimeout;
|
||||
} else {
|
||||
return TtStatusErrorResource;
|
||||
}
|
||||
} else {
|
||||
return TtStatusOk;
|
||||
}
|
||||
return xSemaphoreTake(handle, (TickType_t)timeout) == pdPASS;
|
||||
}
|
||||
}
|
||||
|
||||
TtStatus Semaphore::release() const {
|
||||
bool Semaphore::release() const {
|
||||
if (TT_IS_IRQ_MODE()) {
|
||||
BaseType_t yield = pdFALSE;
|
||||
|
||||
if (xSemaphoreGiveFromISR(handle, &yield) != pdTRUE) {
|
||||
return TtStatusErrorResource;
|
||||
return false;
|
||||
} else {
|
||||
portYIELD_FROM_ISR(yield);
|
||||
return TtStatusOk;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (xSemaphoreGive(handle) != pdPASS) {
|
||||
return TtStatusErrorResource;
|
||||
} else {
|
||||
return TtStatusOk;
|
||||
}
|
||||
return xSemaphoreGive(handle) == pdPASS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,37 +15,29 @@ namespace tt {
|
||||
|
||||
/**
|
||||
* Wrapper for xSemaphoreCreateBinary (max count == 1) and xSemaphoreCreateCounting (max count > 1)
|
||||
* Can be used in IRQ mode (within ISR context)
|
||||
* Can be used from IRQ/ISR mode, but cannot be created/destroyed from such a context.
|
||||
*/
|
||||
class Semaphore {
|
||||
private:
|
||||
SemaphoreHandle_t handle;
|
||||
public:
|
||||
/**
|
||||
* Cannot be called from IRQ/ISR mode.
|
||||
* @param[in] maxCount The maximum count
|
||||
* @param[in] initialCount The initial count
|
||||
*/
|
||||
Semaphore(uint32_t maxCount, uint32_t initialCount);
|
||||
|
||||
/**
|
||||
* @param instance The pointer to Semaphore instance
|
||||
*/
|
||||
/** Cannot be called from IRQ/ISR mode. */
|
||||
~Semaphore();
|
||||
|
||||
/** Acquire semaphore
|
||||
* @param[in] timeout The timeout
|
||||
* @return the status
|
||||
*/
|
||||
TtStatus acquire(uint32_t timeout) const;
|
||||
/** Acquire semaphore */
|
||||
bool acquire(uint32_t timeoutTicks) const;
|
||||
|
||||
/** Release semaphore
|
||||
* @return the status
|
||||
*/
|
||||
TtStatus release() const;
|
||||
/** Release semaphore */
|
||||
bool release() const;
|
||||
|
||||
/** Get semaphore count
|
||||
* @return semaphore count
|
||||
*/
|
||||
/** @return semaphore count */
|
||||
uint32_t getCount() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -66,12 +66,8 @@ bool StreamBuffer::isEmpty() const {
|
||||
return xStreamBufferIsEmpty(handle) == pdTRUE;
|
||||
};
|
||||
|
||||
TtStatus StreamBuffer::reset() const {
|
||||
if (xStreamBufferReset(handle) == pdPASS) {
|
||||
return TtStatusOk;
|
||||
} else {
|
||||
return TtStatusError;
|
||||
}
|
||||
bool StreamBuffer::reset() const {
|
||||
return xStreamBufferReset(handle) == pdPASS;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
* @return TtStatusError if there was a task blocked waiting to send to or read
|
||||
* from the stream buffer then the stream buffer is not reset.
|
||||
*/
|
||||
TtStatus reset() const;
|
||||
bool reset() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -13,17 +13,15 @@ int findLastIndex(const char* text, size_t from_index, char find) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool getPathParent(const char* path, char* output) {
|
||||
int index = findLastIndex(path, strlen(path) - 1, '/');
|
||||
bool getPathParent(const std::string& path, std::string& output) {
|
||||
int index = findLastIndex(path.c_str(), path.length() - 1, '/');
|
||||
if (index == -1) {
|
||||
return false;
|
||||
} else if (index == 0) {
|
||||
output[0] = '/';
|
||||
output[1] = 0x00;
|
||||
output = "/";
|
||||
return true;
|
||||
} else {
|
||||
memcpy(output, path, index);
|
||||
output[index] = 0x00;
|
||||
output = path.substr(0, index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ int findLastIndex(const char* text, size_t from_index, char find);
|
||||
* @param[out] output an output buffer that is allocated to at least the size of "current"
|
||||
* @return true when successful
|
||||
*/
|
||||
bool getPathParent(const char* path, char* output);
|
||||
bool getPathParent(const std::string& path, std::string& output);
|
||||
|
||||
/**
|
||||
* Given a filesystem path as input, get the last segment of a path
|
||||
|
||||
@@ -37,33 +37,22 @@ Timer::~Timer() {
|
||||
tt_check(xTimerDelete(timerHandle, portMAX_DELAY) == pdPASS);
|
||||
}
|
||||
|
||||
TtStatus Timer::start(uint32_t ticks) {
|
||||
bool Timer::start(uint32_t intervalTicks) {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_assert(ticks < portMAX_DELAY);
|
||||
|
||||
if (xTimerChangePeriod(timerHandle, ticks, portMAX_DELAY) == pdPASS) {
|
||||
return TtStatusOk;
|
||||
} else {
|
||||
return TtStatusErrorResource;
|
||||
}
|
||||
tt_assert(intervalTicks < portMAX_DELAY);
|
||||
return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS;
|
||||
}
|
||||
|
||||
TtStatus Timer::restart(uint32_t ticks) {
|
||||
bool Timer::restart(uint32_t intervalTicks) {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_assert(ticks < portMAX_DELAY);
|
||||
|
||||
if (xTimerChangePeriod(timerHandle, ticks, portMAX_DELAY) == pdPASS &&
|
||||
xTimerReset(timerHandle, portMAX_DELAY) == pdPASS) {
|
||||
return TtStatusOk;
|
||||
} else {
|
||||
return TtStatusErrorResource;
|
||||
}
|
||||
tt_assert(intervalTicks < portMAX_DELAY);
|
||||
return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS &&
|
||||
xTimerReset(timerHandle, portMAX_DELAY) == pdPASS;
|
||||
}
|
||||
|
||||
TtStatus Timer::stop() {
|
||||
bool Timer::stop() {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_check(xTimerStop(timerHandle, portMAX_DELAY) == pdPASS);
|
||||
return TtStatusOk;
|
||||
return xTimerStop(timerHandle, portMAX_DELAY) == pdPASS;
|
||||
}
|
||||
|
||||
bool Timer::isRunning() {
|
||||
@@ -76,17 +65,15 @@ uint32_t Timer::getExpireTime() {
|
||||
return (uint32_t)xTimerGetExpiryTime(timerHandle);
|
||||
}
|
||||
|
||||
void Timer::pendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg) {
|
||||
BaseType_t ret = pdFAIL;
|
||||
bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg) {
|
||||
if (kernel::isIrq()) {
|
||||
ret = xTimerPendFunctionCallFromISR(callback, callbackContext, arg, nullptr);
|
||||
return xTimerPendFunctionCallFromISR(callback, callbackContext, arg, nullptr) == pdPASS;
|
||||
} else {
|
||||
ret = xTimerPendFunctionCall(callback, callbackContext, arg, TtWaitForever);
|
||||
return xTimerPendFunctionCall(callback, callbackContext, arg, TtWaitForever) == pdPASS;
|
||||
}
|
||||
tt_assert(ret == pdPASS);
|
||||
}
|
||||
|
||||
void Timer::setThreadPriority(TimerThreadPriority priority) {
|
||||
void Timer::setThreadPriority(ThreadPriority priority) {
|
||||
tt_assert(!kernel::isIrq());
|
||||
|
||||
TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle();
|
||||
|
||||
@@ -15,7 +15,6 @@ public:
|
||||
typedef void (*Callback)(std::shared_ptr<void> context);
|
||||
typedef void (*PendingCallback)(void* context, uint32_t arg);
|
||||
|
||||
|
||||
Callback callback;
|
||||
std::shared_ptr<void> callbackContext;
|
||||
|
||||
@@ -39,9 +38,9 @@ public:
|
||||
* timer service process this request.
|
||||
*
|
||||
* @param[in] ticks The interval in ticks
|
||||
* @return The status.
|
||||
* @return success result
|
||||
*/
|
||||
TtStatus start(uint32_t ticks);
|
||||
bool start(uint32_t intervalTicks);
|
||||
|
||||
/** Restart timer with previous timeout value
|
||||
*
|
||||
@@ -50,9 +49,9 @@ public:
|
||||
*
|
||||
* @param[in] ticks The interval in ticks
|
||||
*
|
||||
* @return The status.
|
||||
* @return success result
|
||||
*/
|
||||
TtStatus restart(uint32_t ticks);
|
||||
bool restart(uint32_t intervalTicks);
|
||||
|
||||
|
||||
/** Stop timer
|
||||
@@ -60,9 +59,9 @@ public:
|
||||
* @warning This is asynchronous call, real operation will happen as soon as
|
||||
* timer service process this request.
|
||||
*
|
||||
* @return The status.
|
||||
* @return success result
|
||||
*/
|
||||
TtStatus stop();
|
||||
bool stop();
|
||||
|
||||
/** Is timer running
|
||||
*
|
||||
@@ -82,18 +81,18 @@ public:
|
||||
*/
|
||||
uint32_t getExpireTime();
|
||||
|
||||
void pendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg);
|
||||
bool setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg);
|
||||
|
||||
typedef enum {
|
||||
TimerThreadPriorityNormal, /**< Lower then other threads */
|
||||
TimerThreadPriorityElevated, /**< Same as other threads */
|
||||
} TimerThreadPriority;
|
||||
} ThreadPriority;
|
||||
|
||||
/** Set Timer thread priority
|
||||
*
|
||||
* @param[in] priority The priority
|
||||
*/
|
||||
void setThreadPriority(TimerThreadPriority priority);
|
||||
void setThreadPriority(ThreadPriority priority);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -26,17 +26,17 @@ long getSize(FILE* file) {
|
||||
return file_size;
|
||||
}
|
||||
|
||||
static std::unique_ptr<uint8_t[]> readBinaryInternal(const char* filepath, size_t& outSize, size_t sizePadding = 0) {
|
||||
FILE* file = fopen(filepath, "rb");
|
||||
static std::unique_ptr<uint8_t[]> readBinaryInternal(const std::string& filepath, size_t& outSize, size_t sizePadding = 0) {
|
||||
FILE* file = fopen(filepath.c_str(), "rb");
|
||||
|
||||
if (file == nullptr) {
|
||||
TT_LOG_E(TAG, "Failed to open %s", filepath);
|
||||
TT_LOG_E(TAG, "Failed to open %s", filepath.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
long content_length = getSize(file);
|
||||
if (content_length == -1) {
|
||||
TT_LOG_E(TAG, "Failed to determine content length for %s", filepath);
|
||||
TT_LOG_E(TAG, "Failed to determine content length for %s", filepath.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -64,11 +64,11 @@ static std::unique_ptr<uint8_t[]> readBinaryInternal(const char* filepath, size_
|
||||
return data;
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> readBinary(const char* filepath, size_t& outSize) {
|
||||
std::unique_ptr<uint8_t[]> readBinary(const std::string& filepath, size_t& outSize) {
|
||||
return readBinaryInternal(filepath, outSize);
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> readString(const char* filepath) {
|
||||
std::unique_ptr<uint8_t[]> readString(const std::string& filepath) {
|
||||
size_t size = 0;
|
||||
auto data = readBinaryInternal(filepath, size, 1);
|
||||
if (size > 0) {
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace tt::file {
|
||||
|
||||
long getSize(FILE* file);
|
||||
|
||||
std::unique_ptr<uint8_t[]> readBinary(const char* filepath, size_t& outSize);
|
||||
std::unique_ptr<uint8_t[]> readString(const char* filepath);
|
||||
std::unique_ptr<uint8_t[]> readBinary(const std::string& filepath, size_t& outSize);
|
||||
std::unique_ptr<uint8_t[]> readString(const std::string& filepath);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user