Update docs and fix bugs (#149)
Improved the docs for the 3 main Tactility projects. I also fixed some inaccuracies and bugs in certain APIs as I went through the code.
This commit is contained in:
committed by
GitHub
parent
ff4287e2ce
commit
415096c3b2
@@ -10,6 +10,9 @@
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* A dictionary that maps keys (strings) onto several atomary types.
|
||||
*/
|
||||
class Bundle {
|
||||
|
||||
private:
|
||||
|
||||
@@ -40,9 +40,8 @@ namespace tt {
|
||||
tt::_crash(); \
|
||||
} while (0)
|
||||
|
||||
/** Halt system
|
||||
*
|
||||
* @param optional message (const char*)
|
||||
/** Halt the system
|
||||
* @param[in] optional message (const char*)
|
||||
*/
|
||||
#define tt_halt(...) M_APPLY(__tt_halt, M_IF_EMPTY(__VA_ARGS__)((NULL), (__VA_ARGS__)))
|
||||
|
||||
@@ -61,8 +60,8 @@ namespace tt {
|
||||
|
||||
/** Check condition and crash if failed
|
||||
*
|
||||
* @param condition to check
|
||||
* @param optional message (const char*)
|
||||
* @param[in] condition to check
|
||||
* @param[in] optional message (const char*)
|
||||
*/
|
||||
|
||||
#define tt_check(x, ...) if (!(x)) { TT_LOG_E("check", "Failed: %s", #x); tt::_crash(); }
|
||||
@@ -89,10 +88,7 @@ namespace tt {
|
||||
#endif
|
||||
|
||||
/** Assert condition and crash if failed
|
||||
*
|
||||
* @warning only will do check if firmware compiled in debug mode
|
||||
*
|
||||
* @param condition to check
|
||||
* @param optional message (const char*)
|
||||
* @warning only will do check if firmware compiled in debug mode
|
||||
* @param[in] condition to check
|
||||
*/
|
||||
#define tt_assert(expression) assert(expression)
|
||||
|
||||
@@ -45,5 +45,3 @@
|
||||
#define _TT_ARGCOUNT4(X,...) _TT_ARGCOUNT ## __VA_OPT__(5(__VA_ARGS__) TT_ARG_IGNORE) (4)
|
||||
#define _TT_ARGCOUNT5(X,...) 5
|
||||
#define _TT_ARGCOUNT(X) X
|
||||
|
||||
// endregion
|
||||
@@ -1,5 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
/** Find the largest value
|
||||
* @param[in] a first value to compare
|
||||
* @param[in] b second value to compare
|
||||
* @return the largest value of a and b
|
||||
*/
|
||||
#define TT_MAX(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
@@ -7,6 +12,11 @@
|
||||
_a > _b ? _a : _b; \
|
||||
})
|
||||
|
||||
/** Find the smallest value
|
||||
* @param[in] a first value to compare
|
||||
* @param[in] b second value to compare
|
||||
* @return the smallest value of a and b
|
||||
*/
|
||||
#define TT_MIN(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
@@ -14,49 +24,12 @@
|
||||
_a < _b ? _a : _b; \
|
||||
})
|
||||
|
||||
/** @return the absolute value of the input */
|
||||
#define TT_ABS(a) ({ (a) < 0 ? -(a) : (a); })
|
||||
|
||||
#define TT_ROUND_UP_TO(a, b) \
|
||||
({ \
|
||||
__typeof__(a) _a = (a); \
|
||||
__typeof__(b) _b = (b); \
|
||||
_a / _b + !!(_a % _b); \
|
||||
})
|
||||
|
||||
/** Clamp a value between a min and a max.
|
||||
* @param[in] x value to clamp
|
||||
* @param[in] upper upper bounds for x
|
||||
* @param[in] lower lower bounds for x
|
||||
*/
|
||||
#define TT_CLAMP(x, upper, lower) (TT_MIN(upper, TT_MAX(x, lower)))
|
||||
|
||||
#define TT_COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
#define TT_SWAP(x, y) \
|
||||
do { \
|
||||
typeof(x) SWAP = x; \
|
||||
x = y; \
|
||||
y = SWAP; \
|
||||
} while (0)
|
||||
|
||||
#define TT_STRINGIFY(x) #x
|
||||
|
||||
#define TT_TOSTRING(x) TT_STRINGIFY(x)
|
||||
|
||||
#define TT_CONCATENATE(a, b) CONCATENATE_(a, b)
|
||||
#define TT_CONCATENATE_(a, b) a##b
|
||||
|
||||
#define TT_REVERSE_BYTES_U32(x) \
|
||||
((((x) & 0x000000FF) << 24) | (((x) & 0x0000FF00) << 8) | (((x) & 0x00FF0000) >> 8) | \
|
||||
(((x) & 0xFF000000) >> 24))
|
||||
|
||||
#define TT_BIT(x, n) (((x) >> (n)) & 1)
|
||||
|
||||
#define TT_BIT_SET(x, n) \
|
||||
({ \
|
||||
__typeof__(x) _x = (1); \
|
||||
(x) |= (_x << (n)); \
|
||||
})
|
||||
|
||||
#define TT_BIT_CLEAR(x, n) \
|
||||
({ \
|
||||
__typeof__(x) _x = (1); \
|
||||
(x) &= ~(_x << (n)); \
|
||||
})
|
||||
|
||||
#define TT_SW_MEMBARRIER() asm volatile("" : : : "memory")
|
||||
|
||||
@@ -18,8 +18,8 @@ Dispatcher::~Dispatcher() {
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
void Dispatcher::dispatch(Callback callback, std::shared_ptr<void> context) {
|
||||
auto message = std::make_shared<DispatcherMessage>(callback, std::move(context));
|
||||
void Dispatcher::dispatch(Function function, std::shared_ptr<void> context) {
|
||||
auto message = std::make_shared<DispatcherMessage>(function, std::move(context));
|
||||
// Mutate
|
||||
if (mutex.lock(1000 / portTICK_PERIOD_MS)) {
|
||||
queue.push(std::move(message));
|
||||
@@ -34,16 +34,16 @@ void Dispatcher::dispatch(Callback callback, std::shared_ptr<void> context) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Dispatcher::consume(uint32_t timeout_ticks) {
|
||||
uint32_t Dispatcher::consume(TickType_t timeout) {
|
||||
// Wait for signal and clear
|
||||
TickType_t start_ticks = kernel::getTicks();
|
||||
if (eventFlag.wait(WAIT_FLAG, TtFlagWaitAny, timeout_ticks) == WAIT_FLAG) {
|
||||
if (eventFlag.wait(WAIT_FLAG, TtFlagWaitAny, timeout) == WAIT_FLAG) {
|
||||
eventFlag.clear(WAIT_FLAG);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TickType_t ticks_remaining = TT_MAX(timeout_ticks - (kernel::getTicks() - start_ticks), 0);
|
||||
TickType_t ticks_remaining = TT_MAX(timeout - (kernel::getTicks() - start_ticks), 0);
|
||||
|
||||
TT_LOG_I(TAG, "Dispatcher continuing (%d ticks)", (int)ticks_remaining);
|
||||
|
||||
@@ -59,7 +59,7 @@ uint32_t Dispatcher::consume(uint32_t timeout_ticks) {
|
||||
processing = !queue.empty();
|
||||
// Don't keep lock as callback might be slow
|
||||
tt_check(mutex.unlock());
|
||||
item->callback(item->context);
|
||||
item->function(item->context);
|
||||
} else {
|
||||
processing = false;
|
||||
tt_check(mutex.unlock());
|
||||
|
||||
@@ -13,16 +13,24 @@
|
||||
|
||||
namespace tt {
|
||||
|
||||
typedef void (*Callback)(std::shared_ptr<void> data);
|
||||
|
||||
/**
|
||||
* A thread-safe way to defer code execution.
|
||||
* Generally, one task would dispatch the execution,
|
||||
* while the other thread consumes and executes the work.
|
||||
*/
|
||||
class Dispatcher {
|
||||
public:
|
||||
|
||||
typedef void (*Function)(std::shared_ptr<void> data);
|
||||
|
||||
private:
|
||||
struct DispatcherMessage {
|
||||
Callback callback;
|
||||
Function function;
|
||||
std::shared_ptr<void> context; // Can't use unique_ptr with void, so we use shared_ptr
|
||||
|
||||
DispatcherMessage(Callback callback, std::shared_ptr<void> context) :
|
||||
callback(callback),
|
||||
DispatcherMessage(Function function, std::shared_ptr<void> context) :
|
||||
function(function),
|
||||
context(std::move(context))
|
||||
{}
|
||||
|
||||
@@ -38,8 +46,19 @@ public:
|
||||
explicit Dispatcher();
|
||||
~Dispatcher();
|
||||
|
||||
void dispatch(Callback callback, std::shared_ptr<void> context);
|
||||
uint32_t consume(uint32_t timeout_ticks);
|
||||
/**
|
||||
* Queue a function to be consumed elsewhere.
|
||||
* @param[in] function the function to execute elsewhere
|
||||
* @param[in] context the data to pass onto the function
|
||||
*/
|
||||
void dispatch(Function function, std::shared_ptr<void> context);
|
||||
|
||||
/**
|
||||
* Consume a dispatched function (if any)
|
||||
* @param[in] timeout the ticks to wait for a message
|
||||
* @return the amount of messages that were consumed
|
||||
*/
|
||||
uint32_t consume(TickType_t timeout);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -29,8 +29,8 @@ void DispatcherThread::_threadMain() {
|
||||
} while (!interruptThread);
|
||||
}
|
||||
|
||||
void DispatcherThread::dispatch(Callback callback, std::shared_ptr<void> context) {
|
||||
dispatcher.dispatch(callback, std::move(context));
|
||||
void DispatcherThread::dispatch(Dispatcher::Function function, std::shared_ptr<void> context) {
|
||||
dispatcher.dispatch(function, std::move(context));
|
||||
}
|
||||
|
||||
void DispatcherThread::start() {
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
/**
|
||||
* Dispatch a message.
|
||||
*/
|
||||
void dispatch(Callback callback, std::shared_ptr<void> context);
|
||||
void dispatch(Dispatcher::Function function, std::shared_ptr<void> context);
|
||||
|
||||
/** Start the thread (blocking). */
|
||||
void start();
|
||||
|
||||
@@ -1,22 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "Check.h"
|
||||
#include "RtosCompat.h"
|
||||
#include <memory>
|
||||
|
||||
namespace tt {
|
||||
|
||||
class ScopedLockableUsage;
|
||||
|
||||
/** Represents a lock/mutex */
|
||||
class Lockable {
|
||||
public:
|
||||
virtual ~Lockable() = default;
|
||||
|
||||
virtual bool lock(uint32_t timeoutTicks) const = 0;
|
||||
virtual bool lock(TickType_t timeoutTicks) const = 0;
|
||||
|
||||
virtual bool unlock() const = 0;
|
||||
|
||||
std::unique_ptr<ScopedLockableUsage> scoped() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a lockable instance that is scoped to a specific lifecycle.
|
||||
* Once the ScopedLockableUsage is destroyed, unlock() is called automatically.
|
||||
*
|
||||
* In other words:
|
||||
* You have to lock() this object manually, but unlock() happens automatically on destruction.
|
||||
*/
|
||||
class ScopedLockableUsage final : public Lockable {
|
||||
|
||||
const Lockable& lockable;
|
||||
@@ -29,7 +39,7 @@ public:
|
||||
lockable.unlock(); // We don't care whether it succeeded or not
|
||||
}
|
||||
|
||||
bool lock(uint32_t timeout) const override {
|
||||
bool lock(TickType_t timeout) const override {
|
||||
return lockable.lock(timeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace tt {
|
||||
|
||||
/** Used for log output filtering */
|
||||
enum LogLevel {
|
||||
LogLevelNone, /*!< No log output */
|
||||
LogLevelError, /*!< Critical errors, software module can not recover on its own */
|
||||
@@ -26,6 +27,10 @@ struct LogEntry {
|
||||
char message[TT_LOG_MESSAGE_SIZE] = { 0 };
|
||||
};
|
||||
|
||||
/** Make a copy of the currently stored entries.
|
||||
* The array size is TT_LOG_ENTRY_COUNT
|
||||
* @param[out] outIndex the write index for the next log entry.
|
||||
*/
|
||||
LogEntry* copyLogEntries(unsigned int& outIndex);
|
||||
|
||||
} // namespace tt
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
namespace tt {
|
||||
|
||||
MessageQueue::MessageQueue(uint32_t capacity, uint32_t msg_size) {
|
||||
tt_assert((kernel::isIrq() == 0U) && (capacity > 0U) && (msg_size > 0U));
|
||||
tt_assert(!TT_IS_ISR() && (capacity > 0U) && (msg_size > 0U));
|
||||
queue_handle = xQueueCreate(capacity, msg_size);
|
||||
tt_check(queue_handle);
|
||||
}
|
||||
|
||||
MessageQueue::~MessageQueue() {
|
||||
tt_assert(kernel::isIrq() == 0U);
|
||||
tt_assert(!TT_IS_ISR());
|
||||
vQueueDelete(queue_handle);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ bool MessageQueue::put(const void* message, uint32_t timeout) {
|
||||
bool result = true;
|
||||
BaseType_t yield;
|
||||
|
||||
if (kernel::isIrq() != 0U) {
|
||||
if (TT_IS_ISR()) {
|
||||
if ((queue_handle == nullptr) || (message == nullptr) || (timeout != 0U)) {
|
||||
result = false;
|
||||
} else {
|
||||
@@ -45,7 +45,7 @@ bool MessageQueue::get(void* msg_ptr, uint32_t timeout_ticks) {
|
||||
BaseType_t yield;
|
||||
|
||||
|
||||
if (kernel::isIrq()) {
|
||||
if (TT_IS_ISR()) {
|
||||
if ((queue_handle == nullptr) || (msg_ptr == nullptr) || (timeout_ticks != 0U)) {
|
||||
result = false;
|
||||
} else {
|
||||
@@ -91,7 +91,7 @@ uint32_t MessageQueue::getCount() const {
|
||||
|
||||
if (queue_handle == nullptr) {
|
||||
count = 0U;
|
||||
} else if (kernel::isIrq() != 0U) {
|
||||
} else if (TT_IS_ISR()) {
|
||||
count = uxQueueMessagesWaitingFromISR(queue_handle);
|
||||
} else {
|
||||
count = uxQueueMessagesWaiting(queue_handle);
|
||||
@@ -108,7 +108,7 @@ uint32_t MessageQueue::getSpace() const {
|
||||
|
||||
if (mq == nullptr) {
|
||||
space = 0U;
|
||||
} else if (kernel::isIrq() != 0U) {
|
||||
} else if (TT_IS_ISR()) {
|
||||
isrm = taskENTER_CRITICAL_FROM_ISR();
|
||||
|
||||
/* space = pxQueue->uxLength - pxQueue->uxMessagesWaiting; */
|
||||
@@ -123,7 +123,7 @@ uint32_t MessageQueue::getSpace() const {
|
||||
}
|
||||
|
||||
bool MessageQueue::reset() {
|
||||
tt_check(!kernel::isIrq());
|
||||
tt_check(!TT_IS_ISR());
|
||||
if (queue_handle == nullptr) {
|
||||
return false;
|
||||
} else {
|
||||
|
||||
@@ -36,7 +36,8 @@ public:
|
||||
|
||||
~MessageQueue();
|
||||
|
||||
/** Put message into queue
|
||||
/** Post a message to the queue.
|
||||
* The message is queued by copy, not by reference.
|
||||
* @param[in] message A pointer to a message. The message will be copied into a buffer.
|
||||
* @param[in] timeoutTicks
|
||||
* @return success result
|
||||
@@ -44,7 +45,7 @@ public:
|
||||
bool put(const void* message, uint32_t timeoutTicks);
|
||||
|
||||
/** Get message from queue
|
||||
* @param message A pointer to an already allocated message object
|
||||
* @param[out] message A pointer to an already allocated message object
|
||||
* @param[in] timeoutTicks
|
||||
* @return success result
|
||||
*/
|
||||
|
||||
@@ -44,7 +44,7 @@ Mutex::~Mutex() {
|
||||
semaphore = nullptr; // If the mutex is used after release, this might help debugging
|
||||
}
|
||||
|
||||
TtStatus Mutex::acquire(uint32_t timeout) const {
|
||||
TtStatus Mutex::acquire(TickType_t timeout) const {
|
||||
tt_assert(!TT_IS_IRQ_MODE());
|
||||
tt_assert(semaphore);
|
||||
|
||||
@@ -114,7 +114,7 @@ void tt_mutex_free(Mutex* mutex) {
|
||||
delete mutex;
|
||||
}
|
||||
|
||||
TtStatus tt_mutex_acquire(Mutex* mutex, uint32_t timeout) {
|
||||
TtStatus tt_mutex_acquire(Mutex* mutex, TickType_t timeout) {
|
||||
return mutex-> acquire(timeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
|
||||
namespace tt {
|
||||
|
||||
class ScopedMutexUsage;
|
||||
|
||||
/**
|
||||
* Wrapper for FreeRTOS xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex
|
||||
* Can be used in IRQ mode (within ISR context)
|
||||
@@ -38,56 +36,64 @@ public:
|
||||
explicit Mutex(Type type = TypeNormal);
|
||||
~Mutex() override;
|
||||
|
||||
TtStatus acquire(uint32_t timeoutTicks) const;
|
||||
/** Attempt to lock the mutex. Blocks until timeout passes or lock is acquired.
|
||||
* @param[in] timeout
|
||||
* @return status result
|
||||
*/
|
||||
TtStatus acquire(TickType_t timeout) const;
|
||||
|
||||
/** Attempt to unlock the mutex.
|
||||
* @return status result
|
||||
*/
|
||||
TtStatus release() const;
|
||||
|
||||
bool lock(uint32_t timeoutTicks) const override { return acquire(timeoutTicks) == TtStatusOk; }
|
||||
/** Attempt to lock the mutex. Blocks until timeout passes or lock is acquired.
|
||||
* @param[in] timeout
|
||||
* @return success result
|
||||
*/
|
||||
bool lock(TickType_t timeout) const override { return acquire(timeout) == TtStatusOk; }
|
||||
|
||||
/** Attempt to unlock the mutex.
|
||||
* @return success result
|
||||
*/
|
||||
bool unlock() const override { return release() == TtStatusOk; }
|
||||
|
||||
/** @return the owner of the thread */
|
||||
ThreadId getOwner() const;
|
||||
};
|
||||
|
||||
/** Allocate Mutex
|
||||
*
|
||||
* @param[in] type The mutex type
|
||||
*
|
||||
* @return pointer to Mutex instance
|
||||
* @param[in] type The mutex type
|
||||
* @return pointer to Mutex instance
|
||||
*/
|
||||
|
||||
[[deprecated("use class")]]
|
||||
Mutex* tt_mutex_alloc(Mutex::Type type);
|
||||
|
||||
/** Free Mutex
|
||||
*
|
||||
* @param mutex The Mutex instance
|
||||
* @param[in] mutex The Mutex instance
|
||||
*/
|
||||
[[deprecated("use class")]]
|
||||
void tt_mutex_free(Mutex* mutex);
|
||||
|
||||
/** Acquire mutex
|
||||
*
|
||||
* @param mutex The Mutex instance
|
||||
* @param[in] timeout The timeout
|
||||
*
|
||||
* @return The status.
|
||||
* @param[in] mutex
|
||||
* @param[in] timeout
|
||||
* @return the status result
|
||||
*/
|
||||
[[deprecated("use class")]]
|
||||
TtStatus tt_mutex_acquire(Mutex* mutex, uint32_t timeout);
|
||||
TtStatus tt_mutex_acquire(Mutex* mutex, TickType_t timeout);
|
||||
|
||||
/** Release mutex
|
||||
*
|
||||
* @param mutex The Mutex instance
|
||||
*
|
||||
* @return The status.
|
||||
* @param[in] mutex The Mutex instance
|
||||
* @return the status result
|
||||
*/
|
||||
[[deprecated("use class")]]
|
||||
TtStatus tt_mutex_release(Mutex* mutex);
|
||||
|
||||
/** Get mutex owner thread id
|
||||
*
|
||||
* @param mutex The Mutex instance
|
||||
*
|
||||
* @return The thread identifier.
|
||||
* @param[in] mutex The Mutex instance
|
||||
* @return The thread identifier.
|
||||
*/
|
||||
[[deprecated("use class")]]
|
||||
ThreadId tt_mutex_get_owner(Mutex* mutex);
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
namespace tt {
|
||||
|
||||
PubSubSubscription* tt_pubsub_subscribe(std::shared_ptr<PubSub> pubsub, PubSubCallback callback, void* callback_context) {
|
||||
PubSubSubscription* tt_pubsub_subscribe(std::shared_ptr<PubSub> pubsub, PubSubCallback callback, void* callbackContext) {
|
||||
tt_check(pubsub->mutex.acquire(TtWaitForever) == TtStatusOk);
|
||||
PubSubSubscription subscription = {
|
||||
.id = (++pubsub->last_id),
|
||||
.callback = callback,
|
||||
.callback_context = callback_context
|
||||
.callback_context = callbackContext
|
||||
};
|
||||
pubsub->items.push_back(
|
||||
subscription
|
||||
|
||||
@@ -30,34 +30,27 @@ struct PubSub {
|
||||
};
|
||||
|
||||
/** Subscribe to PubSub
|
||||
*
|
||||
* Threadsafe, Reentrable
|
||||
*
|
||||
* @param pubsub pointer to PubSub instance
|
||||
* @param[in] callback The callback
|
||||
* @param callback_context The callback context
|
||||
*
|
||||
* @return pointer to PubSubSubscription instance
|
||||
* @param[in] pubsub pointer to PubSub instance
|
||||
* @param[in] callback
|
||||
* @param[in] callbackContext the data to pass to the callback
|
||||
* @return subscription instance
|
||||
*/
|
||||
PubSubSubscription*
|
||||
tt_pubsub_subscribe(std::shared_ptr<PubSub> pubsub, PubSubCallback callback, void* callback_context);
|
||||
tt_pubsub_subscribe(std::shared_ptr<PubSub> pubsub, PubSubCallback callback, void* callbackContext);
|
||||
|
||||
/** Unsubscribe from PubSub
|
||||
*
|
||||
* No use of `pubsub_subscription` allowed after call of this method
|
||||
* Threadsafe, Reentrable.
|
||||
*
|
||||
* @param pubsub pointer to PubSub instance
|
||||
* @param pubsub_subscription pointer to PubSubSubscription instance
|
||||
* No use of `tt_pubsub_subscription` allowed after call of this method
|
||||
* Threadsafe, Re-entrable.
|
||||
* @param[in] pubsub
|
||||
* @param[in] subscription
|
||||
*/
|
||||
void tt_pubsub_unsubscribe(std::shared_ptr<PubSub> pubsub, PubSubSubscription* pubsub_subscription);
|
||||
void tt_pubsub_unsubscribe(std::shared_ptr<PubSub> pubsub, PubSubSubscription* subscription);
|
||||
|
||||
/** Publish message to PubSub
|
||||
*
|
||||
* Threadsafe, Reentrable.
|
||||
*
|
||||
* @param pubsub pointer to PubSub instance
|
||||
* @param message message pointer to publish
|
||||
* @param[in] pubsub
|
||||
* @param[in] message message pointer to publish - it is passed as-is to the callback
|
||||
*/
|
||||
void tt_pubsub_publish(std::shared_ptr<PubSub> pubsub, void* message);
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ public:
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader).
|
||||
*
|
||||
* @param size The total number of bytes the stream buffer will be able to hold at any one time.
|
||||
* @param triggerLevel The number of bytes that must be in the stream buffer
|
||||
* @param[in] size The total number of bytes the stream buffer will be able to hold at any one time.
|
||||
* @param[in] triggerLevel The number of bytes that must be in the stream buffer
|
||||
* before a task that is blocked on the stream buffer to wait for data is moved out of the blocked state.
|
||||
* @return The stream buffer instance.
|
||||
*/
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
* stream buffer before a task that is blocked on the stream buffer to
|
||||
* wait for data is moved out of the blocked state.
|
||||
*
|
||||
* @param triggerLevel The new trigger level for the stream buffer.
|
||||
* @param[in] triggerLevel The new trigger level for the stream buffer.
|
||||
* @return true if trigger level can be be updated (new trigger level was less than or equal to the stream buffer's length).
|
||||
* @return false if trigger level can't be be updated (new trigger level was greater than the stream buffer's length).
|
||||
*/
|
||||
@@ -60,9 +60,9 @@ public:
|
||||
* @brief Sends bytes to a stream buffer. The bytes are copied into the stream buffer.
|
||||
* Wakes up task waiting for data to become available if called from ISR.
|
||||
*
|
||||
* @param data A pointer to the data that is to be copied into the stream buffer.
|
||||
* @param length The maximum number of bytes to copy from data into the stream buffer.
|
||||
* @param timeout The maximum amount of time the task should remain in the
|
||||
* @param[in] data A pointer to the data that is to be copied into the stream buffer.
|
||||
* @param[in] length The maximum number of bytes to copy from data into the stream buffer.
|
||||
* @param[in] timeout The maximum amount of time the task should remain in the
|
||||
* Blocked state to wait for space to become available if the stream buffer is full.
|
||||
* Will return immediately if timeout is zero.
|
||||
* Setting timeout to TtWaitForever will cause the task to wait indefinitely.
|
||||
@@ -79,10 +79,10 @@ public:
|
||||
* @brief Receives bytes from a stream buffer.
|
||||
* Wakes up task waiting for space to become available if called from ISR.
|
||||
*
|
||||
* @param data A pointer to the buffer into which the received bytes will be
|
||||
* @param[in] data A pointer to the buffer into which the received bytes will be
|
||||
* copied.
|
||||
* @param length The length of the buffer pointed to by the data parameter.
|
||||
* @param timeout The maximum amount of time the task should remain in the
|
||||
* @param[in] length The length of the buffer pointed to by the data parameter.
|
||||
* @param[in] timeout The maximum amount of time the task should remain in the
|
||||
* Blocked state to wait for data to become available if the stream buffer is empty.
|
||||
* Will return immediately if timeout is zero.
|
||||
* Setting timeout to TtWaitForever will cause the task to wait indefinitely.
|
||||
|
||||
@@ -7,13 +7,7 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#endif
|
||||
#include "RtosCompatTask.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
@@ -47,14 +41,14 @@ public:
|
||||
typedef int32_t (*Callback)(void* context);
|
||||
|
||||
/** Write to stdout callback
|
||||
* @param data pointer to data
|
||||
* @param size data size @warning your handler must consume everything
|
||||
* @param[in] data pointer to data
|
||||
* @param[in] size data size @warning your handler must consume everything
|
||||
*/
|
||||
typedef void (*StdoutWriteCallback)(const char* data, size_t size);
|
||||
|
||||
/** Thread state change callback called upon thread state change
|
||||
* @param state new thread state
|
||||
* @param context callback context
|
||||
* @param[in] state new thread state
|
||||
* @param[in] context callback context
|
||||
*/
|
||||
typedef void (*StateCallback)(State state, void* context);
|
||||
|
||||
@@ -85,11 +79,10 @@ public:
|
||||
Thread();
|
||||
|
||||
/** Allocate Thread, shortcut version
|
||||
|
||||
* @param name
|
||||
* @param stack_size
|
||||
* @param callback
|
||||
* @param context
|
||||
* @param[in] name
|
||||
* @param[in] stack_size
|
||||
* @param[in] callback
|
||||
* @param[in] callbackContext
|
||||
* @return Thread*
|
||||
*/
|
||||
Thread(
|
||||
@@ -102,8 +95,7 @@ public:
|
||||
~Thread();
|
||||
|
||||
/** Set Thread name
|
||||
*
|
||||
* @param name string
|
||||
* @param[in] name string
|
||||
*/
|
||||
void setName(const std::string& name);
|
||||
|
||||
@@ -118,75 +110,49 @@ public:
|
||||
bool isMarkedAsStatic() const;
|
||||
|
||||
/** Set Thread stack size
|
||||
*
|
||||
* @param thread Thread instance
|
||||
* @param stackSize stack size in bytes
|
||||
* @param[in] stackSize stack size in bytes
|
||||
*/
|
||||
void setStackSize(size_t stackSize);
|
||||
|
||||
/** Set Thread callback
|
||||
*
|
||||
* @param thread Thread instance
|
||||
* @param callback ThreadCallback, called upon thread run
|
||||
* @param callbackContext what to pass to the callback
|
||||
* @param[in] callback ThreadCallback, called upon thread run
|
||||
* @param[in] callbackContext what to pass to the callback
|
||||
*/
|
||||
void setCallback(Callback callback, _Nullable void* callbackContext = nullptr);
|
||||
|
||||
/** Set Thread priority
|
||||
*
|
||||
* @param thread Thread instance
|
||||
* @param priority ThreadPriority value
|
||||
* @param[in] priority ThreadPriority value
|
||||
*/
|
||||
void setPriority(Priority priority);
|
||||
|
||||
|
||||
/** Set Thread state change callback
|
||||
*
|
||||
* @param thread Thread instance
|
||||
* @param callback state change callback
|
||||
* @param context pointer to context
|
||||
* @param[in] callback state change callback
|
||||
* @param[in] callbackContext pointer to context
|
||||
*/
|
||||
void setStateCallback(StateCallback callback, _Nullable void* callbackContext = nullptr);
|
||||
|
||||
/** Get Thread state
|
||||
*
|
||||
* @param thread Thread instance
|
||||
*
|
||||
* @return thread state from ThreadState
|
||||
*/
|
||||
State getState() const;
|
||||
|
||||
/** Start Thread
|
||||
*
|
||||
* @param thread Thread instance
|
||||
*/
|
||||
void start();
|
||||
|
||||
/** Join Thread
|
||||
*
|
||||
* @warning Use this method only when CPU is not busy(Idle task receives
|
||||
* control), otherwise it will wait forever.
|
||||
*
|
||||
* @param thread Thread instance
|
||||
*
|
||||
* @warning Use this method only when CPU is not busy (Idle task receives control), otherwise it will wait forever.
|
||||
* @return success result
|
||||
*/
|
||||
bool join();
|
||||
|
||||
/** Get FreeRTOS ThreadId for Thread instance
|
||||
*
|
||||
* @param thread Thread instance
|
||||
*
|
||||
* @return ThreadId or nullptr
|
||||
*/
|
||||
ThreadId getId();
|
||||
|
||||
/** Get thread return code
|
||||
*
|
||||
* @param thread Thread instance
|
||||
*
|
||||
* @return return code
|
||||
*/
|
||||
/** @return thread return code */
|
||||
int32_t getReturnCode();
|
||||
|
||||
private:
|
||||
@@ -200,31 +166,17 @@ private:
|
||||
#define THREAD_PRIORITY_ISR (TT_CONFIG_THREAD_MAX_PRIORITIES - 1)
|
||||
|
||||
/** Set current thread priority
|
||||
*
|
||||
* @param priority ThreadPriority value
|
||||
* @param[in] priority ThreadPriority value
|
||||
*/
|
||||
void thread_set_current_priority(Thread::Priority priority);
|
||||
|
||||
/** Get current thread priority
|
||||
*
|
||||
* @return ThreadPriority value
|
||||
*/
|
||||
/** @return ThreadPriority value */
|
||||
Thread::Priority thread_get_current_priority();
|
||||
|
||||
/** Thread related methods that doesn't involve Thread directly */
|
||||
|
||||
/** Get FreeRTOS ThreadId for current thread
|
||||
*
|
||||
* @param thread Thread instance
|
||||
*
|
||||
* @return ThreadId or NULL
|
||||
*/
|
||||
/** @return FreeRTOS ThreadId or NULL */
|
||||
ThreadId thread_get_current_id();
|
||||
|
||||
/** Get Thread instance for current thread
|
||||
*
|
||||
* @return pointer to Thread or NULL if this thread doesn't belongs to Tactility
|
||||
*/
|
||||
/** @return pointer to Thread instance or NULL if this thread doesn't belongs to Tactility */
|
||||
Thread* thread_get_current();
|
||||
|
||||
/** Return control to scheduler */
|
||||
@@ -240,44 +192,38 @@ uint32_t thread_flags_wait(uint32_t flags, uint32_t options, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* @brief Get thread name
|
||||
*
|
||||
* @param thread_id
|
||||
* @param[in] threadId
|
||||
* @return const char* name or NULL
|
||||
*/
|
||||
const char* thread_get_name(ThreadId thread_id);
|
||||
const char* thread_get_name(ThreadId threadId);
|
||||
|
||||
/**
|
||||
* @brief Get thread stack watermark
|
||||
*
|
||||
* @param thread_id
|
||||
* @param[in] threadId
|
||||
* @return uint32_t
|
||||
*/
|
||||
uint32_t thread_get_stack_space(ThreadId thread_id);
|
||||
uint32_t thread_get_stack_space(ThreadId threadId);
|
||||
|
||||
/** Suspend thread
|
||||
*
|
||||
* @param thread_id thread id
|
||||
* @param[in] threadId thread id
|
||||
*/
|
||||
void thread_suspend(ThreadId thread_id);
|
||||
void thread_suspend(ThreadId threadId);
|
||||
|
||||
/** Resume thread
|
||||
*
|
||||
* @param thread_id thread id
|
||||
* @param[in] threadId thread id
|
||||
*/
|
||||
void thread_resume(ThreadId thread_id);
|
||||
void thread_resume(ThreadId threadId);
|
||||
|
||||
/** Get thread suspended state
|
||||
*
|
||||
* @param thread_id thread id
|
||||
* @param[in] threadId thread id
|
||||
* @return true if thread is suspended
|
||||
*/
|
||||
bool thread_is_suspended(ThreadId thread_id);
|
||||
bool thread_is_suspended(ThreadId threadId);
|
||||
|
||||
/** Check if the thread was created with static memory
|
||||
*
|
||||
* @param thread_id thread id
|
||||
* @param[in] threadId thread id
|
||||
* @return true if thread memory is static
|
||||
*/
|
||||
bool thread_mark_is_static(ThreadId thread_id);
|
||||
bool thread_mark_is_static(ThreadId threadId);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -16,7 +16,7 @@ static void timer_callback(TimerHandle_t hTimer) {
|
||||
}
|
||||
|
||||
Timer::Timer(Type type, Callback callback, std::shared_ptr<void> callbackContext) {
|
||||
tt_assert((kernel::isIrq() == 0U) && (callback != nullptr));
|
||||
tt_assert((!TT_IS_ISR()) && (callback != nullptr));
|
||||
|
||||
this->callback = callback;
|
||||
this->callbackContext = std::move(callbackContext);
|
||||
@@ -33,48 +33,49 @@ Timer::Timer(Type type, Callback callback, std::shared_ptr<void> callbackContext
|
||||
}
|
||||
|
||||
Timer::~Timer() {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
tt_check(xTimerDelete(timerHandle, portMAX_DELAY) == pdPASS);
|
||||
}
|
||||
|
||||
bool Timer::start(uint32_t intervalTicks) {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
tt_assert(intervalTicks < portMAX_DELAY);
|
||||
return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS;
|
||||
}
|
||||
|
||||
bool Timer::restart(uint32_t intervalTicks) {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
tt_assert(intervalTicks < portMAX_DELAY);
|
||||
return xTimerChangePeriod(timerHandle, intervalTicks, portMAX_DELAY) == pdPASS &&
|
||||
xTimerReset(timerHandle, portMAX_DELAY) == pdPASS;
|
||||
}
|
||||
|
||||
bool Timer::stop() {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
return xTimerStop(timerHandle, portMAX_DELAY) == pdPASS;
|
||||
}
|
||||
|
||||
bool Timer::isRunning() {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
return xTimerIsTimerActive(timerHandle) == pdTRUE;
|
||||
}
|
||||
|
||||
uint32_t Timer::getExpireTime() {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
return (uint32_t)xTimerGetExpiryTime(timerHandle);
|
||||
}
|
||||
|
||||
bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg) {
|
||||
if (kernel::isIrq()) {
|
||||
return xTimerPendFunctionCallFromISR(callback, callbackContext, arg, nullptr) == pdPASS;
|
||||
bool Timer::setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout) {
|
||||
if (TT_IS_ISR()) {
|
||||
assert(timeout == 0);
|
||||
return xTimerPendFunctionCallFromISR(callback, callbackContext, callbackArg, nullptr) == pdPASS;
|
||||
} else {
|
||||
return xTimerPendFunctionCall(callback, callbackContext, arg, TtWaitForever) == pdPASS;
|
||||
return xTimerPendFunctionCall(callback, callbackContext, callbackArg, timeout) == pdPASS;
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::setThreadPriority(ThreadPriority priority) {
|
||||
tt_assert(!kernel::isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
|
||||
TaskHandle_t task_handle = xTimerGetTimerDaemonTaskHandle();
|
||||
tt_assert(task_handle); // Don't call this method before timer task start
|
||||
|
||||
@@ -33,55 +33,44 @@ public:
|
||||
~Timer();
|
||||
|
||||
/** Start timer
|
||||
*
|
||||
* @warning This is asynchronous call, real operation will happen as soon as
|
||||
* timer service process this request.
|
||||
*
|
||||
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
||||
* @param[in] ticks The interval in ticks
|
||||
* @return success result
|
||||
*/
|
||||
bool start(uint32_t intervalTicks);
|
||||
|
||||
/** Restart timer with previous timeout value
|
||||
*
|
||||
* @warning This is asynchronous call, real operation will happen as soon as
|
||||
* timer service process this request.
|
||||
*
|
||||
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
||||
* @param[in] ticks The interval in ticks
|
||||
*
|
||||
* @return success result
|
||||
*/
|
||||
bool restart(uint32_t intervalTicks);
|
||||
|
||||
|
||||
/** Stop timer
|
||||
*
|
||||
* @warning This is asynchronous call, real operation will happen as soon as
|
||||
* timer service process this request.
|
||||
*
|
||||
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
||||
* @return success result
|
||||
*/
|
||||
bool stop();
|
||||
|
||||
/** Is timer running
|
||||
*
|
||||
* @warning This cal may and will return obsolete timer state if timer
|
||||
* commands are still in the queue. Please read FreeRTOS timer
|
||||
* documentation first.
|
||||
*
|
||||
* @warning This cal may and will return obsolete timer state if timer commands are still in the queue. Please read FreeRTOS timer documentation first.
|
||||
* @return true when running
|
||||
*/
|
||||
bool isRunning();
|
||||
|
||||
/** Get timer expire time
|
||||
*
|
||||
* @param instance The Timer instance
|
||||
*
|
||||
* @return expire tick
|
||||
*/
|
||||
uint32_t getExpireTime();
|
||||
|
||||
bool setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t arg);
|
||||
/**
|
||||
* Calls xTimerPendFunctionCall internally.
|
||||
* @param[in] callback the function to call
|
||||
* @param[in] callbackContext the first function argument
|
||||
* @param[in] callbackArg the second function argument
|
||||
* @param[in] timeout the function timeout (must set to 0 in ISR mode)
|
||||
*/
|
||||
bool setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout);
|
||||
|
||||
typedef enum {
|
||||
TimerThreadPriorityNormal, /**< Lower then other threads */
|
||||
@@ -89,7 +78,6 @@ public:
|
||||
} ThreadPriority;
|
||||
|
||||
/** Set Timer thread priority
|
||||
*
|
||||
* @param[in] priority The priority
|
||||
*/
|
||||
void setThreadPriority(ThreadPriority priority);
|
||||
|
||||
@@ -91,14 +91,14 @@ static void get_nvs_key(uint8_t key[32]) {
|
||||
|
||||
/**
|
||||
* Performs XOR on 2 memory regions and stores it in a third
|
||||
* @param[in] in_left input buffer for XOR
|
||||
* @param[in] in_right second input buffer for XOR
|
||||
* @param[in] inLeft input buffer for XOR
|
||||
* @param[in] inRight second input buffer for XOR
|
||||
* @param[out] out output buffer for result of XOR
|
||||
* @param[in] length data length (all buffers must be at least this size)
|
||||
*/
|
||||
static void xorKey(const uint8_t* in_left, const uint8_t* in_right, uint8_t* out, size_t length) {
|
||||
static void xorKey(const uint8_t* inLeft, const uint8_t* inRight, uint8_t* out, size_t length) {
|
||||
for (int i = 0; i < length; ++i) {
|
||||
out[i] = in_left[i] ^ in_right[i];
|
||||
out[i] = inLeft[i] ^ inRight[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,10 +112,10 @@ static void getKey(uint8_t key[32]) {
|
||||
TT_LOG_W(TAG, "An attacker with physical access to your ESP32 can decrypt your secure data.");
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
uint8_t hardware_key[32];
|
||||
uint8_t nvs_key[32];
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
get_hardware_key(hardware_key);
|
||||
get_nvs_key(nvs_key);
|
||||
xorKey(hardware_key, nvs_key, key, 32);
|
||||
@@ -125,10 +125,10 @@ static void getKey(uint8_t key[32]) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void getIv(const void* data, size_t data_length, uint8_t iv[16]) {
|
||||
void getIv(const void* data, size_t dataLength, uint8_t iv[16]) {
|
||||
memset((void*)iv, 0, 16);
|
||||
uint8_t* data_bytes = (uint8_t*)data;
|
||||
for (int i = 0; i < data_length; ++i) {
|
||||
auto* data_bytes = (uint8_t*)data;
|
||||
for (int i = 0; i < dataLength; ++i) {
|
||||
size_t safe_index = i % 16;
|
||||
iv[safe_index] %= data_bytes[i];
|
||||
}
|
||||
@@ -160,8 +160,8 @@ static int aes256CryptCbc(
|
||||
return result;
|
||||
}
|
||||
|
||||
int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length) {
|
||||
tt_check(length % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256");
|
||||
int encrypt(const uint8_t iv[16], uint8_t* inData, uint8_t* outData, size_t dataLength) {
|
||||
tt_check(dataLength % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256");
|
||||
uint8_t key[32];
|
||||
getKey(key);
|
||||
|
||||
@@ -169,11 +169,11 @@ int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t le
|
||||
uint8_t iv_copy[16];
|
||||
memcpy(iv_copy, iv, sizeof(iv_copy));
|
||||
|
||||
return aes256CryptCbc(key, MBEDTLS_AES_ENCRYPT, length, iv_copy, in_data, out_data);
|
||||
return aes256CryptCbc(key, MBEDTLS_AES_ENCRYPT, dataLength, iv_copy, inData, outData);
|
||||
}
|
||||
|
||||
int decrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length) {
|
||||
tt_check(length % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256");
|
||||
int decrypt(const uint8_t iv[16], uint8_t* inData, uint8_t* outData, size_t dataLength) {
|
||||
tt_check(dataLength % 16 == 0, "Length is not a multiple of 16 bytes (for AES 256");
|
||||
uint8_t key[32];
|
||||
getKey(key);
|
||||
|
||||
@@ -181,7 +181,7 @@ int decrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t le
|
||||
uint8_t iv_copy[16];
|
||||
memcpy(iv_copy, iv, sizeof(iv_copy));
|
||||
|
||||
return aes256CryptCbc(key, MBEDTLS_AES_DECRYPT, length, iv_copy, in_data, out_data);
|
||||
return aes256CryptCbc(key, MBEDTLS_AES_DECRYPT, dataLength, iv_copy, inData, outData);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -26,11 +26,11 @@ namespace tt::crypt {
|
||||
|
||||
/**
|
||||
* @brief Fills the IV with zeros and then creates an IV based on the input data.
|
||||
* @param data input data
|
||||
* @param data_length input data length
|
||||
* @param iv output IV
|
||||
* @param[in] data input data
|
||||
* @param[in] dataLength input data length
|
||||
* @param[out] iv output IV
|
||||
*/
|
||||
void getIv(const void* data, size_t data_length, uint8_t iv[16]);
|
||||
void getIv(const void* data, size_t dataLength, uint8_t iv[16]);
|
||||
|
||||
/**
|
||||
* @brief Encrypt data.
|
||||
@@ -38,13 +38,13 @@ void getIv(const void* data, size_t data_length, uint8_t iv[16]);
|
||||
* Important: Use flash encryption to increase security.
|
||||
* Important: input and output data must be aligned to 16 bytes.
|
||||
*
|
||||
* @param iv the AES IV
|
||||
* @param data_in input data
|
||||
* @param data_out output data
|
||||
* @param length data length, a multiple of 16
|
||||
* @param[in] iv the AES IV
|
||||
* @param[in] inData input data
|
||||
* @param[out] outData output data
|
||||
* @param[in] dataLength data length, a multiple of 16 (for both inData and outData)
|
||||
* @return the result of esp_aes_crypt_cbc() (MBEDTLS_ERR_*)
|
||||
*/
|
||||
int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length);
|
||||
int encrypt(const uint8_t iv[16], uint8_t* inData, uint8_t* outData, size_t dataLength);
|
||||
|
||||
/**
|
||||
* @brief Decrypt data.
|
||||
@@ -52,12 +52,12 @@ int encrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t le
|
||||
* Important: Use flash encryption to increase security.
|
||||
* Important: input and output data must be aligned to 16 bytes.
|
||||
*
|
||||
* @param iv AES IV
|
||||
* @param data_in input data
|
||||
* @param data_out output data
|
||||
* @param length data length, a multiple of 16
|
||||
* @param[in] iv AES IV
|
||||
* @param[in] inData input data
|
||||
* @param[out] outData output data
|
||||
* @param[in] dataLength data length, a multiple of 16 (for both inData and outData)
|
||||
* @return the result of esp_aes_crypt_cbc() (MBEDTLS_ERR_*)
|
||||
*/
|
||||
int decrypt(const uint8_t iv[16], uint8_t* in_data, uint8_t* out_data, size_t length);
|
||||
int decrypt(const uint8_t iv[16], uint8_t* inData, uint8_t* outData, size_t dataLength);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -15,6 +15,7 @@ uint32_t djb2(const char* str);
|
||||
/**
|
||||
* Implementation of DJB2 hashing algorithm.
|
||||
* @param[in] data the bytes to calculate the hash for
|
||||
* @param[in] length the size of data
|
||||
* @return the hash
|
||||
*/
|
||||
uint32_t djb2(const void* data, size_t length);
|
||||
|
||||
@@ -26,6 +26,11 @@ long getSize(FILE* file) {
|
||||
return file_size;
|
||||
}
|
||||
|
||||
/** Read a file.
|
||||
* @param[in] filepath
|
||||
* @param[out] outSize the amount of bytes that were read, excluding the sizePadding
|
||||
* @param[in] sizePadding optional padding to add at the end of the output data (the values are not set)
|
||||
*/
|
||||
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");
|
||||
|
||||
@@ -53,15 +58,19 @@ static std::unique_ptr<uint8_t[]> readBinaryInternal(const std::string& filepath
|
||||
if (bytes_read > 0) {
|
||||
buffer_offset += bytes_read;
|
||||
} else { // Something went wrong?
|
||||
data = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
outSize = buffer_offset;
|
||||
|
||||
fclose(file);
|
||||
return data;
|
||||
|
||||
if (buffer_offset == content_length) {
|
||||
outSize = buffer_offset;
|
||||
return data;
|
||||
} else {
|
||||
outSize = 0;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> readBinary(const std::string& filepath, size_t& outSize) {
|
||||
@@ -71,15 +80,11 @@ std::unique_ptr<uint8_t[]> readBinary(const std::string& filepath, size_t& outSi
|
||||
std::unique_ptr<uint8_t[]> readString(const std::string& filepath) {
|
||||
size_t size = 0;
|
||||
auto data = readBinaryInternal(filepath, size, 1);
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
} else if (size > 0) {
|
||||
if (data != nullptr) {
|
||||
data.get()[size] = 0; // Append null terminator
|
||||
return data;
|
||||
} else { // Empty file: return empty string
|
||||
auto value = std::make_unique<uint8_t[]>(1);
|
||||
value[0] = 0;
|
||||
return value;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,17 @@ namespace tt::file {
|
||||
|
||||
long getSize(FILE* file);
|
||||
|
||||
/** Read a file and return its data.
|
||||
* @param[in] filepath the path of the file
|
||||
* @param[out] size the amount of bytes that were read
|
||||
* @return null on error, or an array of bytes in case of success
|
||||
*/
|
||||
std::unique_ptr<uint8_t[]> readBinary(const std::string& filepath, size_t& outSize);
|
||||
|
||||
/** Read a file and return a null-terminated string that represents its content.
|
||||
* @param[in] filepath the path of the file
|
||||
* @return null on error, or an array of bytes in case of success. Empty string returns as a single 0 character.
|
||||
*/
|
||||
std::unique_ptr<uint8_t[]> readString(const std::string& filepath);
|
||||
|
||||
}
|
||||
|
||||
@@ -12,16 +12,12 @@
|
||||
|
||||
namespace tt::kernel {
|
||||
|
||||
bool isIrq() {
|
||||
return TT_IS_IRQ_MODE();
|
||||
}
|
||||
|
||||
bool isRunning() {
|
||||
return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING;
|
||||
}
|
||||
|
||||
int32_t lock() {
|
||||
tt_assert(!isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
|
||||
int32_t lock;
|
||||
|
||||
@@ -46,7 +42,7 @@ int32_t lock() {
|
||||
}
|
||||
|
||||
int32_t unlock() {
|
||||
tt_assert(!isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
|
||||
int32_t lock;
|
||||
|
||||
@@ -76,7 +72,7 @@ int32_t unlock() {
|
||||
}
|
||||
|
||||
int32_t restoreLock(int32_t lock) {
|
||||
tt_assert(!isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
|
||||
switch (xTaskGetSchedulerState()) {
|
||||
case taskSCHEDULER_SUSPENDED:
|
||||
@@ -112,7 +108,7 @@ uint32_t getTickFrequency() {
|
||||
}
|
||||
|
||||
void delayTicks(TickType_t ticks) {
|
||||
tt_assert(!isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
if (ticks == 0U) {
|
||||
taskYIELD();
|
||||
} else {
|
||||
@@ -121,7 +117,7 @@ void delayTicks(TickType_t ticks) {
|
||||
}
|
||||
|
||||
TtStatus delayUntilTick(TickType_t tick) {
|
||||
tt_assert(!isIrq());
|
||||
tt_assert(!TT_IS_ISR());
|
||||
|
||||
TickType_t tcnt, delay;
|
||||
TtStatus stat;
|
||||
@@ -150,7 +146,7 @@ TtStatus delayUntilTick(TickType_t tick) {
|
||||
TickType_t getTicks() {
|
||||
TickType_t ticks;
|
||||
|
||||
if (isIrq() != 0U) {
|
||||
if (TT_IS_ISR() != 0U) {
|
||||
ticks = xTaskGetTickCountFromISR();
|
||||
} else {
|
||||
ticks = xTaskGetTickCount();
|
||||
|
||||
@@ -10,87 +10,56 @@
|
||||
|
||||
namespace tt::kernel {
|
||||
|
||||
/** Recognized platform types */
|
||||
typedef enum {
|
||||
PlatformEsp,
|
||||
PlatformSimulator
|
||||
} Platform;
|
||||
|
||||
/** Check if CPU is in IRQ or kernel running and IRQ is masked
|
||||
*
|
||||
* Originally this primitive was born as a workaround for FreeRTOS kernel primitives shenanigans with PRIMASK.
|
||||
*
|
||||
* Meaningful use cases are:
|
||||
*
|
||||
* - When kernel is started and you want to ensure that you are not in IRQ or IRQ is not masked(like in critical section)
|
||||
* - When kernel is not started and you want to make sure that you are not in IRQ mode, ignoring PRIMASK.
|
||||
*
|
||||
* As you can see there will be edge case when kernel is not started and PRIMASK is not 0 that may cause some funky behavior.
|
||||
* Most likely it will happen after kernel primitives being used, but control not yet passed to kernel.
|
||||
* It's up to you to figure out if it is safe for your code or not.
|
||||
*
|
||||
* @return true if CPU is in IRQ or kernel running and IRQ is masked
|
||||
*/
|
||||
bool isIrq();
|
||||
|
||||
/** Check if kernel is running
|
||||
*
|
||||
* @return true if running, false otherwise
|
||||
* @return true if the FreeRTOS kernel is running, false otherwise
|
||||
*/
|
||||
bool isRunning();
|
||||
|
||||
/** Lock kernel, pause process scheduling
|
||||
*
|
||||
* @warning This should never be called in interrupt request context.
|
||||
*
|
||||
* @return previous lock state(0 - unlocked, 1 - locked)
|
||||
* @warning don't call from ISR context
|
||||
* @return previous lock state(0 - unlocked, 1 - locked)
|
||||
*/
|
||||
int32_t lock();
|
||||
|
||||
/** Unlock kernel, resume process scheduling
|
||||
*
|
||||
* @warning This should never be called in interrupt request context.
|
||||
*
|
||||
* @return previous lock state(0 - unlocked, 1 - locked)
|
||||
* @warning don't call from ISR context
|
||||
* @return previous lock state(0 - unlocked, 1 - locked)
|
||||
*/
|
||||
int32_t unlock();
|
||||
|
||||
/** Restore kernel lock state
|
||||
*
|
||||
* @warning This should never be called in interrupt request context.
|
||||
*
|
||||
* @param[in] lock The lock state
|
||||
*
|
||||
* @return new lock state or error
|
||||
* @warning don't call from ISR context
|
||||
* @param[in] lock The lock state
|
||||
* @return new lock state or error
|
||||
*/
|
||||
int32_t restoreLock(int32_t lock);
|
||||
|
||||
/** Get kernel systick frequency
|
||||
*
|
||||
* @return systick counts per second
|
||||
* @return systick counts per second
|
||||
*/
|
||||
uint32_t getTickFrequency();
|
||||
|
||||
TickType_t getTicks();
|
||||
|
||||
/** Delay execution
|
||||
*
|
||||
* @warning This should never be called in interrupt request context.
|
||||
*
|
||||
* @warning don't call from ISR context
|
||||
* Also keep in mind delay is aliased to scheduler timer intervals.
|
||||
*
|
||||
* @param[in] ticks The ticks count to pause
|
||||
* @param[in] ticks The ticks count to pause
|
||||
*/
|
||||
void delayTicks(TickType_t ticks);
|
||||
|
||||
/** Delay until tick
|
||||
*
|
||||
* @warning This should never be called in interrupt request context.
|
||||
*
|
||||
* @param[in] ticks The tick until which kerel should delay task execution
|
||||
*
|
||||
* @return The status.
|
||||
* @warning don't call from ISR context
|
||||
* @param[in] ticks The tick until which kerel should delay task execution
|
||||
* @return the status
|
||||
*/
|
||||
TtStatus delayUntilTick(uint32_t tick);
|
||||
TtStatus delayUntilTick(TickType_t tick);
|
||||
|
||||
/** Convert milliseconds to ticks
|
||||
*
|
||||
@@ -100,26 +69,22 @@ TtStatus delayUntilTick(uint32_t tick);
|
||||
TickType_t millisToTicks(uint32_t milliSeconds);
|
||||
|
||||
/** Delay in milliseconds
|
||||
*
|
||||
* This method uses kernel ticks on the inside, which causes delay to be aliased to scheduler timer intervals.
|
||||
* Real wait time will be between X+ milliseconds.
|
||||
* Special value: 0, will cause task yield.
|
||||
* Also if used when kernel is not running will fall back to `tt_delay_us`.
|
||||
*
|
||||
* @warning Cannot be used from ISR
|
||||
*
|
||||
* @param[in] milliSeconds milliseconds to wait
|
||||
* Also if used when kernel is not running will fall back to delayMicros()
|
||||
* @warning don't call from ISR context
|
||||
* @param[in] milliSeconds milliseconds to wait
|
||||
*/
|
||||
void delayMillis(uint32_t milliSeconds);
|
||||
|
||||
/** Delay in microseconds
|
||||
*
|
||||
* Implemented using Cortex DWT counter. Blocking and non aliased.
|
||||
*
|
||||
* @param[in] microSeconds microseconds to wait
|
||||
* @param[in] microSeconds microseconds to wait
|
||||
*/
|
||||
void delayMicros(uint32_t microSeconds);
|
||||
|
||||
/** @return the platform that Tactility currently is running on. */
|
||||
Platform getPlatform();
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "PanicHandler.h"
|
||||
|
||||
#include <esp_rom_sys.h>
|
||||
#include <esp_debug_helpers.h>
|
||||
#include <esp_attr.h>
|
||||
#include <esp_memory_utils.h>
|
||||
@@ -10,6 +9,10 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
/**
|
||||
* This static variable survives a crash reboot.
|
||||
* It is reset by the Boot app.
|
||||
*/
|
||||
static RTC_NOINIT_ATTR CrashData crashData;
|
||||
|
||||
void __real_esp_panic_handler(void* info);
|
||||
@@ -61,6 +64,6 @@ void __wrap_esp_panic_handler(void* info) {
|
||||
|
||||
}
|
||||
|
||||
const CrashData* getRtcCrashData() { return &crashData; }
|
||||
const CrashData& getRtcCrashData() { return crashData; }
|
||||
|
||||
#endif
|
||||
@@ -7,6 +7,7 @@
|
||||
#define CRASH_DATA_CALLSTACK_LIMIT 64
|
||||
#define CRASH_DATA_INCLUDES_SP false
|
||||
|
||||
/** Represents a single frame on the callstack. */
|
||||
struct CallstackFrame {
|
||||
uint32_t pc = 0;
|
||||
#if CRASH_DATA_INCLUDES_SP
|
||||
@@ -14,12 +15,14 @@ struct CallstackFrame {
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Callstack-related crash data. */
|
||||
struct CrashData {
|
||||
bool callstackCorrupted = false;
|
||||
uint8_t callstackLength = 0;
|
||||
CallstackFrame callstack[CRASH_DATA_CALLSTACK_LIMIT];
|
||||
};
|
||||
|
||||
const CrashData* getRtcCrashData();
|
||||
/** @return the crash data */
|
||||
const CrashData& getRtcCrashData();
|
||||
|
||||
#endif
|
||||
@@ -10,8 +10,15 @@ typedef struct {
|
||||
bool kernelRunning;
|
||||
} TtCriticalInfo;
|
||||
|
||||
/** Enter a critical section
|
||||
* @return info on the status
|
||||
*/
|
||||
TtCriticalInfo enter();
|
||||
|
||||
/**
|
||||
* Exit a critical section
|
||||
* @param[in] info the info from when the critical section was started
|
||||
*/
|
||||
void exit(TtCriticalInfo info);
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user