Project restructuring (fixes macOS builds) (#198)
- Create `Include/` folder for all main projects - Fix some issues here and there (found while moving things) - All includes are now in `Tactility/` subfolder and must be included with that prefix. This fixes issues with clashing POSIX headers (e.g. `<semaphore.h>` versus Tactility's `Semaphore.h`)
This commit is contained in:
committed by
GitHub
parent
7856827ecf
commit
c87200a80d
@@ -1,4 +1,4 @@
|
||||
#include "Bundle.h"
|
||||
#include "Tactility/Bundle.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* @brief key-value storage for general purpose.
|
||||
* Maps strings on a fixed set of data types.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* A dictionary that maps keys (strings) onto several atomary types.
|
||||
*/
|
||||
class Bundle {
|
||||
|
||||
private:
|
||||
|
||||
typedef uint32_t Hash;
|
||||
|
||||
enum class Type {
|
||||
Bool,
|
||||
Int32,
|
||||
String,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Type type;
|
||||
union {
|
||||
bool value_bool;
|
||||
int32_t value_int32;
|
||||
};
|
||||
std::string value_string;
|
||||
} Value;
|
||||
|
||||
std::unordered_map<std::string, Value> entries;
|
||||
|
||||
public:
|
||||
|
||||
Bundle() = default;
|
||||
|
||||
Bundle(const Bundle& bundle) {
|
||||
this->entries = bundle.entries;
|
||||
}
|
||||
|
||||
bool getBool(const std::string& key) const;
|
||||
int32_t getInt32(const std::string& key) const;
|
||||
std::string getString(const std::string& key) const;
|
||||
|
||||
bool hasBool(const std::string& key) const;
|
||||
bool hasInt32(const std::string& key) const;
|
||||
bool hasString(const std::string& key) const;
|
||||
|
||||
bool optBool(const std::string& key, bool& out) const;
|
||||
bool optInt32(const std::string& key, int32_t& out) const;
|
||||
bool optString(const std::string& key, std::string& out) const;
|
||||
|
||||
void putBool(const std::string& key, bool value);
|
||||
void putInt32(const std::string& key, int32_t value);
|
||||
void putString(const std::string& key, const std::string& value);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "Check.h"
|
||||
#include "Tactility/Check.h"
|
||||
|
||||
#include "Log.h"
|
||||
#include "RtosCompatTask.h"
|
||||
#include "Tactility/Log.h"
|
||||
#include "Tactility/RtosCompatTask.h"
|
||||
|
||||
#define TAG "kernel"
|
||||
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* @file check.h
|
||||
*
|
||||
* Tactility crash and check functions.
|
||||
*
|
||||
* The main problem with crashing is that you can't do anything without disturbing registers,
|
||||
* and if you disturb registers, you won't be able to see the correct register values in the debugger.
|
||||
*
|
||||
* Current solution works around it by passing the message through r12 and doing some magic with registers in crash function.
|
||||
* r0-r10 are stored in the ram2 on crash routine start and restored at the end.
|
||||
* The only register that is going to be lost is r11.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Log.h"
|
||||
#include <cassert>
|
||||
#include "CoreDefines.h"
|
||||
|
||||
#define TT_NORETURN [[noreturn]]
|
||||
|
||||
/** Crash system */
|
||||
namespace tt {
|
||||
/**
|
||||
* Don't call this directly. Use tt_crash() as it will trace info.
|
||||
*/
|
||||
TT_NORETURN void _crash();
|
||||
}
|
||||
|
||||
/** Crash system with message. */
|
||||
#define tt_crash(...) TT_ARG_CAT(_tt_crash,TT_ARGCOUNT(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
#define _tt_crash0() do { \
|
||||
TT_LOG_E("crash", "at %s:%d", __FILE__, __LINE__); \
|
||||
tt::_crash(); \
|
||||
} while (0)
|
||||
|
||||
#define _tt_crash1(message) do { \
|
||||
TT_LOG_E("crash", "%s\n\tat %s:%d", message, __FILE__, __LINE__); \
|
||||
tt::_crash(); \
|
||||
} while (0)
|
||||
|
||||
/** Halt the system
|
||||
* @param[in] optional message (const char*)
|
||||
*/
|
||||
#define tt_halt(...) M_APPLY(__tt_halt, M_IF_EMPTY(__VA_ARGS__)((NULL), (__VA_ARGS__)))
|
||||
|
||||
/** Check condition and crash if check failed */
|
||||
#define tt_check_internal(__e, __m) \
|
||||
do { \
|
||||
if (!(__e)) { \
|
||||
TT_LOG_E("check", "%s", #__e); \
|
||||
if (__m) { \
|
||||
tt_crash_internal(#__m); \
|
||||
} else { \
|
||||
tt_crash_internal(""); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/** Check condition and crash if failed
|
||||
*
|
||||
* @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(); }
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreExtraDefines.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#else
|
||||
#include "portmacro.h"
|
||||
#endif
|
||||
|
||||
#define TT_RETURNS_NONNULL __attribute__((returns_nonnull))
|
||||
|
||||
#define TT_WARN_UNUSED __attribute__((warn_unused_result))
|
||||
|
||||
#define TT_UNUSED __attribute__((unused))
|
||||
|
||||
#define TT_WEAK __attribute__((weak))
|
||||
|
||||
#define TT_PACKED __attribute__((packed))
|
||||
|
||||
#define TT_PLACE_IN_SECTION(x) __attribute__((section(x)))
|
||||
|
||||
#define TT_ALIGN(n) __attribute__((aligned(n)))
|
||||
|
||||
// Used by portENABLE_INTERRUPTS and portDISABLE_INTERRUPTS?
|
||||
#ifdef ESP_PLATFORM
|
||||
#define TT_IS_IRQ_MODE() (xPortInIsrContext() == pdTRUE)
|
||||
#else
|
||||
#define TT_IS_IRQ_MODE() false
|
||||
#endif
|
||||
|
||||
#define TT_IS_ISR() (TT_IS_IRQ_MODE())
|
||||
|
||||
#define TT_CHECK_RETURN __attribute__((__warn_unused_result__))
|
||||
|
||||
// region Variable arguments support
|
||||
|
||||
// Adapted from https://stackoverflow.com/a/78848701/3848666
|
||||
#define TT_ARG_IGNORE(X)
|
||||
#define TT_ARG_CAT(X,Y) _TT_ARG_CAT(X,Y)
|
||||
#define _TT_ARG_CAT(X,Y) X ## Y
|
||||
#define TT_ARGCOUNT(...) _TT_ARGCOUNT ## __VA_OPT__(1(__VA_ARGS__) TT_ARG_IGNORE) (0)
|
||||
#define _TT_ARGCOUNT1(X,...) _TT_ARGCOUNT ## __VA_OPT__(2(__VA_ARGS__) TT_ARG_IGNORE) (1)
|
||||
#define _TT_ARGCOUNT2(X,...) _TT_ARGCOUNT ## __VA_OPT__(3(__VA_ARGS__) TT_ARG_IGNORE) (2)
|
||||
#define _TT_ARGCOUNT3(X,...) _TT_ARGCOUNT ## __VA_OPT__(4(__VA_ARGS__) TT_ARG_IGNORE) (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
|
||||
@@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define TT_STRINGIFY(x) #x
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <kernel/Kernel.h>
|
||||
#include "Dispatcher.h"
|
||||
#include "Check.h"
|
||||
#include "Tactility/Dispatcher.h"
|
||||
|
||||
#include "Tactility/Check.h"
|
||||
#include "Tactility/kernel/Kernel.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* @file Dispatcher.h
|
||||
*
|
||||
* Dispatcher is a thread-safe code execution queue.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "MessageQueue.h"
|
||||
#include "Mutex.h"
|
||||
#include "EventFlag.h"
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
Function function;
|
||||
std::shared_ptr<void> context; // Can't use unique_ptr with void, so we use shared_ptr
|
||||
|
||||
DispatcherMessage(Function function, std::shared_ptr<void> context) :
|
||||
function(function),
|
||||
context(std::move(context))
|
||||
{}
|
||||
|
||||
~DispatcherMessage() = default;
|
||||
};
|
||||
|
||||
Mutex mutex;
|
||||
std::queue<std::shared_ptr<DispatcherMessage>> queue;
|
||||
EventFlag eventFlag;
|
||||
|
||||
public:
|
||||
|
||||
explicit Dispatcher() = default;
|
||||
~Dispatcher();
|
||||
|
||||
/**
|
||||
* 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 1 or more dispatched function (if any) until the queue is empty.
|
||||
* @warning The timeout is only the wait time before consuming the message! It is not a limit to the total execution time when calling this method.
|
||||
* @param[in] timeout the ticks to wait for a message
|
||||
* @return the amount of messages that were consumed
|
||||
*/
|
||||
uint32_t consume(TickType_t timeout = portMAX_DELAY);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "DispatcherThread.h"
|
||||
#include "Tactility/DispatcherThread.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#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(Dispatcher::Function function, std::shared_ptr<void> context);
|
||||
|
||||
/** Start the thread (blocking). */
|
||||
void start();
|
||||
|
||||
/** Stop the thread (blocking). */
|
||||
void stop();
|
||||
|
||||
/** Internal method */
|
||||
void _threadMain();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "EventFlag.h"
|
||||
#include "Tactility/EventFlag.h"
|
||||
|
||||
#include "Check.h"
|
||||
#include "CoreDefines.h"
|
||||
#include "Tactility/Check.h"
|
||||
#include "Tactility/CoreDefines.h"
|
||||
|
||||
#define TT_EVENT_FLAG_MAX_BITS_EVENT_GROUPS 24U
|
||||
#define TT_EVENT_FLAG_INVALID_BITS (~((1UL << TT_EVENT_FLAG_MAX_BITS_EVENT_GROUPS) - 1U))
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RtosCompatEventGroups.h"
|
||||
#include <memory>
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* Wrapper for FreeRTOS xEventGroup.
|
||||
*/
|
||||
class EventFlag {
|
||||
private:
|
||||
|
||||
struct EventGroupHandleDeleter {
|
||||
void operator()(EventGroupHandle_t handleToDelete) {
|
||||
vEventGroupDelete(handleToDelete);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<std::remove_pointer_t<EventGroupHandle_t>, EventGroupHandleDeleter> handle;
|
||||
|
||||
public:
|
||||
|
||||
EventFlag();
|
||||
~EventFlag();
|
||||
|
||||
enum Flag {
|
||||
WaitAny = 0x00000000U, ///< Wait for any flag (default).
|
||||
WaitAll = 0x00000001U, ///< Wait for all flags.
|
||||
NoClear = 0x00000002U, ///< Do not clear flags which have been specified to wait for.
|
||||
|
||||
Error = 0x80000000U, ///< Error indicator.
|
||||
ErrorUnknown = 0xFFFFFFFFU, ///< TtStatusError (-1).
|
||||
ErrorTimeout = 0xFFFFFFFEU, ///< TtStatusErrorTimeout (-2).
|
||||
ErrorResource = 0xFFFFFFFDU, ///< TtStatusErrorResource (-3).
|
||||
ErrorParameter = 0xFFFFFFFCU, ///< TtStatusErrorParameter (-4).
|
||||
ErrorISR = 0xFFFFFFFAU, ///< TtStatusErrorISR (-6).
|
||||
};
|
||||
|
||||
uint32_t set(uint32_t flags) const;
|
||||
uint32_t clear(uint32_t flags) const;
|
||||
uint32_t get() const;
|
||||
uint32_t wait(
|
||||
uint32_t flags,
|
||||
uint32_t options = WaitAny,
|
||||
uint32_t timeout = portMAX_DELAY
|
||||
) const;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Lockable.h"
|
||||
#include "Tactility/Lockable.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Check.h"
|
||||
#include "RtosCompat.h"
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
namespace tt {
|
||||
|
||||
class ScopedLockableUsage;
|
||||
|
||||
/** Represents a lock/mutex */
|
||||
class Lockable {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Lockable() = default;
|
||||
|
||||
virtual bool lock(TickType_t timeout) const = 0;
|
||||
|
||||
bool lock() const { return lock(portMAX_DELAY); }
|
||||
|
||||
virtual bool unlock() const = 0;
|
||||
|
||||
void withLock(TickType_t timeout, const std::function<void()>& onLockAcquired) const {
|
||||
if (lock(timeout)) {
|
||||
onLockAcquired();
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void withLock(TickType_t timeout, const std::function<void()>& onLockAcquired, const std::function<void()>& onLockFailure) const {
|
||||
if (lock(timeout)) {
|
||||
onLockAcquired();
|
||||
unlock();
|
||||
} else {
|
||||
onLockFailure();
|
||||
}
|
||||
}
|
||||
|
||||
void withLock(const std::function<void()>& onLockAcquired) const { withLock(portMAX_DELAY, onLockAcquired); }
|
||||
|
||||
void withLock(const std::function<void()>& onLockAcquired, const std::function<void()>& onLockFailed) const { withLock(portMAX_DELAY, onLockAcquired, onLockFailed); }
|
||||
|
||||
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;
|
||||
|
||||
public:
|
||||
|
||||
using Lockable::lock;
|
||||
|
||||
explicit ScopedLockableUsage(const Lockable& lockable) : lockable(lockable) {}
|
||||
|
||||
~ScopedLockableUsage() final {
|
||||
lockable.unlock(); // We don't care whether it succeeded or not
|
||||
}
|
||||
|
||||
bool lock(TickType_t timeout) const override {
|
||||
return lockable.lock(timeout);
|
||||
}
|
||||
|
||||
bool unlock() const override {
|
||||
return lockable.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "Mutex.h"
|
||||
#include "Tactility/Mutex.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
@@ -49,7 +50,7 @@ std::unique_ptr<std::array<LogEntry, TT_LOG_ENTRY_COUNT>> copyLogEntries(std::si
|
||||
|
||||
#ifndef ESP_PLATFORM
|
||||
|
||||
#include "Log.h"
|
||||
#include "Tactility/Log.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <sys/time.h>
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "LogMessages.h"
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <esp_log.h>
|
||||
#else
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#if not defined(ESP_PLATFORM) or (defined(CONFIG_SPIRAM_USE_MALLOC) && CONFIG_SPIRAM_USE_MALLOC == 1)
|
||||
#define TT_LOG_ENTRY_COUNT 200
|
||||
#define TT_LOG_MESSAGE_SIZE 128
|
||||
#else
|
||||
#define TT_LOG_ENTRY_COUNT 50
|
||||
#define TT_LOG_MESSAGE_SIZE 50
|
||||
#endif
|
||||
|
||||
namespace tt {
|
||||
|
||||
/** Used for log output filtering */
|
||||
enum class LogLevel {
|
||||
None, /*!< No log output */
|
||||
Error, /*!< Critical errors, software module can not recover on its own */
|
||||
Warning, /*!< Error conditions from which recovery measures have been taken */
|
||||
Info, /*!< Information messages which describe normal flow of events */
|
||||
Debug, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
|
||||
Verbose /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
|
||||
};
|
||||
|
||||
struct LogEntry {
|
||||
LogLevel level = LogLevel::None;
|
||||
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.
|
||||
*/
|
||||
std::unique_ptr<std::array<LogEntry, TT_LOG_ENTRY_COUNT>> copyLogEntries(std::size_t& outIndex);
|
||||
|
||||
} // namespace tt
|
||||
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#define TT_LOG_E(tag, format, ...) \
|
||||
ESP_LOGE(tag, format, ##__VA_ARGS__)
|
||||
#define TT_LOG_W(tag, format, ...) \
|
||||
ESP_LOGW(tag, format, ##__VA_ARGS__)
|
||||
#define TT_LOG_I(tag, format, ...) \
|
||||
ESP_LOGI(tag, format, ##__VA_ARGS__)
|
||||
#define TT_LOG_D(tag, format, ...) \
|
||||
ESP_LOGD(tag, format, ##__VA_ARGS__)
|
||||
#define TT_LOG_V(tag, format, ...) \
|
||||
ESP_LOGV(tag, format, ##__VA_ARGS__)
|
||||
|
||||
#else
|
||||
|
||||
namespace tt {
|
||||
|
||||
void log(LogLevel level, const char* tag, const char* format, ...);
|
||||
|
||||
} // namespace
|
||||
|
||||
#define TT_LOG_E(tag, format, ...) \
|
||||
tt::log(tt::LogLevel::Error, tag, format, ##__VA_ARGS__)
|
||||
#define TT_LOG_W(tag, format, ...) \
|
||||
tt::log(tt::LogLevel::Warning, tag, format, ##__VA_ARGS__)
|
||||
#define TT_LOG_I(tag, format, ...) \
|
||||
tt::log(tt::LogLevel::Info, tag, format, ##__VA_ARGS__)
|
||||
#define TT_LOG_D(tag, format, ...) \
|
||||
tt::log(tt::LogLevel::Debug, tag, format, ##__VA_ARGS__)
|
||||
#define TT_LOG_V(tag, format, ...) \
|
||||
tt::log(tt::LogLevel::Trace, tag, format, ##__VA_ARGS__)
|
||||
|
||||
#endif // ESP_PLATFORM
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* 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"
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "MessageQueue.h"
|
||||
#include "Check.h"
|
||||
#include "kernel/Kernel.h"
|
||||
#include "Tactility/MessageQueue.h"
|
||||
#include "Tactility/Check.h"
|
||||
#include "Tactility/kernel/Kernel.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* @file MessageQueue.h
|
||||
*
|
||||
* MessageQueue is a wrapper for FreeRTOS xQueue functionality.
|
||||
* There is no additional thread-safety on top of the xQueue functionality,
|
||||
* so make sure you create a lock if needed.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
#endif
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* Message Queue implementation.
|
||||
* Calls can be done from ISR/IRQ mode unless otherwise specified.
|
||||
*/
|
||||
class MessageQueue {
|
||||
private:
|
||||
|
||||
struct QueueHandleDeleter {
|
||||
void operator()(QueueHandle_t handleToDelete) {
|
||||
vQueueDelete(handleToDelete);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<std::remove_pointer_t<QueueHandle_t>, QueueHandleDeleter> handle;
|
||||
|
||||
public:
|
||||
/** Allocate message queue
|
||||
* @param[in] capacity Maximum messages in queue
|
||||
* @param[in] messageSize The size in bytes of a single message
|
||||
*/
|
||||
MessageQueue(uint32_t capacity, uint32_t messageSize);
|
||||
|
||||
~MessageQueue();
|
||||
|
||||
/** 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] timeout
|
||||
* @return success result
|
||||
*/
|
||||
bool put(const void* message, TickType_t timeout);
|
||||
|
||||
/** Get message from queue
|
||||
* @param[out] message A pointer to an already allocated message object
|
||||
* @param[in] timeout
|
||||
* @return success result
|
||||
*/
|
||||
bool get(void* message, TickType_t timeout);
|
||||
|
||||
/**
|
||||
* @return The maximum amount of messages that can be in the queue at any given time.
|
||||
*/
|
||||
uint32_t getCapacity() const;
|
||||
|
||||
/**
|
||||
* @return The size of a single message in bytes
|
||||
*/
|
||||
uint32_t getMessageSize() const;
|
||||
|
||||
/**
|
||||
* @return How many messages are currently in the queue.
|
||||
*/
|
||||
uint32_t getCount() const;
|
||||
|
||||
/**
|
||||
* @return How many messages can be added to the queue before the put() method starts blocking.
|
||||
*/
|
||||
uint32_t getSpace() const;
|
||||
|
||||
/** Reset queue (cannot be called in ISR/IRQ mode)
|
||||
* @return success result
|
||||
*/
|
||||
bool reset();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "Mutex.h"
|
||||
#include "Tactility/Mutex.h"
|
||||
|
||||
#include "Check.h"
|
||||
#include "CoreDefines.h"
|
||||
#include "Log.h"
|
||||
#include "Tactility/Check.h"
|
||||
#include "Tactility/CoreDefines.h"
|
||||
#include "Tactility/Log.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
* @file mutex.h
|
||||
* Mutex
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Thread.h"
|
||||
#include "RtosCompatSemaphore.h"
|
||||
#include "Check.h"
|
||||
#include "Lockable.h"
|
||||
#include <memory>
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* Wrapper for FreeRTOS xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex
|
||||
* Cannot be used in IRQ mode (within ISR context)
|
||||
*/
|
||||
class Mutex final : public Lockable {
|
||||
|
||||
public:
|
||||
|
||||
enum class Type {
|
||||
Normal,
|
||||
Recursive,
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
struct SemaphoreHandleDeleter {
|
||||
void operator()(QueueHandle_t handleToDelete) {
|
||||
assert(!TT_IS_IRQ_MODE());
|
||||
vSemaphoreDelete(handleToDelete);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<std::remove_pointer_t<QueueHandle_t>, SemaphoreHandleDeleter> handle;
|
||||
Type type;
|
||||
|
||||
public:
|
||||
|
||||
using Lockable::lock;
|
||||
|
||||
explicit Mutex(Type type = Type::Normal);
|
||||
~Mutex() final = default;
|
||||
|
||||
/** 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 final;
|
||||
|
||||
/** Attempt to unlock the mutex.
|
||||
* @return success result
|
||||
*/
|
||||
bool unlock() const final;
|
||||
|
||||
/** @return the owner of the thread */
|
||||
ThreadId getOwner() const;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "PubSub.h"
|
||||
#include "Check.h"
|
||||
#include "Tactility/PubSub.h"
|
||||
#include "Tactility/Check.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* @file pubsub.h
|
||||
* PubSub
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Mutex.h"
|
||||
#include <list>
|
||||
|
||||
namespace tt {
|
||||
|
||||
/** PubSub Callback type */
|
||||
typedef void (*PubSubCallback)(const void* message, void* context);
|
||||
|
||||
/** Publish and subscribe to messages in a thread-safe manner. */
|
||||
class PubSub {
|
||||
|
||||
private:
|
||||
|
||||
struct Subscription {
|
||||
uint64_t id;
|
||||
PubSubCallback callback;
|
||||
void* callbackParameter;
|
||||
};
|
||||
|
||||
typedef std::list<Subscription> Subscriptions;
|
||||
uint64_t lastId = 0;
|
||||
Subscriptions items;
|
||||
Mutex mutex;
|
||||
|
||||
public:
|
||||
|
||||
typedef void* SubscriptionHandle;
|
||||
|
||||
PubSub() = default;
|
||||
|
||||
~PubSub() {
|
||||
tt_check(items.empty());
|
||||
}
|
||||
|
||||
/** Start receiving messages at the specified handle (Threadsafe, Re-entrable)
|
||||
* @param[in] callback
|
||||
* @param[in] callbackParameter the data to pass to the callback
|
||||
* @return subscription instance
|
||||
*/
|
||||
SubscriptionHandle subscribe(PubSubCallback callback, void* callbackParameter);
|
||||
|
||||
/** Stop receiving messages at the specified handle (Threadsafe, Re-entrable.)
|
||||
* No use of `tt_pubsub_subscription` allowed after call of this method
|
||||
* @param[in] subscription
|
||||
*/
|
||||
void unsubscribe(SubscriptionHandle subscription);
|
||||
|
||||
/** Publish message to all subscribers (Threadsafe, Re-entrable.)
|
||||
* @param[in] message message pointer to publish - it is passed as-is to the callback
|
||||
*/
|
||||
void publish(void* message);
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Compatibility includes for FreeRTOS.
|
||||
* Custom FreeRTOS from ESP-IDF prefixes paths with "freertos/",
|
||||
* but this isn't the normal behaviour for the regular FreeRTOS project.
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#endif
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* See explanation in RtosCompat.h
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#include "event_groups.h"
|
||||
#endif
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* See explanation in RtosCompat.h
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#endif
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* See explanation in RtosCompat.h
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#endif
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* See explanation in RtosCompat.h
|
||||
*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/timers.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#include "timers.h"
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "Semaphore.h"
|
||||
#include "Check.h"
|
||||
#include "CoreDefines.h"
|
||||
#include "Tactility/Semaphore.h"
|
||||
#include "Tactility/Check.h"
|
||||
#include "Tactility/CoreDefines.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Lockable.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#include "semphr.h"
|
||||
#endif
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* Wrapper for xSemaphoreCreateBinary (max count == 1) and xSemaphoreCreateCounting (max count > 1)
|
||||
* Can be used from IRQ/ISR mode, but cannot be created/destroyed from such a context.
|
||||
*/
|
||||
class Semaphore final : public Lockable {
|
||||
|
||||
private:
|
||||
|
||||
struct SemaphoreHandleDeleter {
|
||||
void operator()(QueueHandle_t handleToDelete) {
|
||||
assert(!TT_IS_IRQ_MODE());
|
||||
vSemaphoreDelete(handleToDelete);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<std::remove_pointer_t<QueueHandle_t>, SemaphoreHandleDeleter> handle;
|
||||
|
||||
public:
|
||||
|
||||
using Lockable::lock;
|
||||
|
||||
/**
|
||||
* Cannot be called from IRQ/ISR mode.
|
||||
* @param[in] maxAvailable The maximum count
|
||||
* @param[in] initialAvailable The initial count
|
||||
*/
|
||||
Semaphore(uint32_t maxAvailable, uint32_t initialAvailable);
|
||||
|
||||
/**
|
||||
* Cannot be called from IRQ/ISR mode.
|
||||
* @param[in] maxAvailable The maximum count
|
||||
*/
|
||||
explicit Semaphore(uint32_t maxAvailable) : Semaphore(maxAvailable, maxAvailable) {};
|
||||
|
||||
/** Cannot be called from IRQ/ISR mode. */
|
||||
~Semaphore() override;
|
||||
|
||||
Semaphore(Semaphore& other) : handle(std::move(other.handle)) {}
|
||||
|
||||
/** Acquire semaphore */
|
||||
bool acquire(TickType_t timeout) const;
|
||||
|
||||
/** Release semaphore */
|
||||
bool release() const;
|
||||
|
||||
bool lock(TickType_t timeout) const override { return acquire(timeout); }
|
||||
|
||||
bool unlock() const override { return release(); }
|
||||
|
||||
/** @return return the amount of times this semaphore can be acquired/locked */
|
||||
uint32_t getAvailable() const;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "StreamBuffer.h"
|
||||
#include "Tactility/StreamBuffer.h"
|
||||
|
||||
#include "Check.h"
|
||||
#include "CoreDefines.h"
|
||||
#include "Tactility/Check.h"
|
||||
#include "Tactility/CoreDefines.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/stream_buffer.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#include "stream_buffer.h"
|
||||
#endif
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* Stream buffers are used to send a continuous stream of data from one task or
|
||||
* interrupt to another. Their implementation is light weight, making them
|
||||
* particularly suited for interrupt to task and core to core communication
|
||||
* scenarios.
|
||||
*
|
||||
* **NOTE**: Stream buffer implementation assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader).
|
||||
*/
|
||||
class StreamBuffer {
|
||||
|
||||
private:
|
||||
|
||||
struct StreamBufferHandleDeleter {
|
||||
void operator()(StreamBufferHandle_t handleToDelete) {
|
||||
vStreamBufferDelete(handleToDelete);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<std::remove_pointer_t<StreamBufferHandle_t>, StreamBufferHandleDeleter> handle;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Stream buffer implementation assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader).
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
StreamBuffer(size_t size, size_t triggerLevel);
|
||||
|
||||
~StreamBuffer() = default;
|
||||
|
||||
/**
|
||||
* @brief Set trigger level for stream buffer.
|
||||
* A stream buffer's trigger level is 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.
|
||||
*
|
||||
* @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).
|
||||
*/
|
||||
bool setTriggerLevel(size_t triggerLevel) const;
|
||||
|
||||
/**
|
||||
* @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[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 portMAX_DELAY will cause the task to wait indefinitely.
|
||||
* Ignored if called from ISR.
|
||||
* @return The number of bytes actually written to the stream buffer.
|
||||
*/
|
||||
size_t send(
|
||||
const void* data,
|
||||
size_t length,
|
||||
uint32_t timeout
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Receives bytes from a stream buffer.
|
||||
* Wakes up task waiting for space to become available if called from ISR.
|
||||
*
|
||||
* @param[in] data A pointer to the buffer into which the received bytes will be
|
||||
* copied.
|
||||
* @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 portMAX_DELAY will cause the task to wait indefinitely.
|
||||
* Ignored if called from ISR.
|
||||
* @return The number of bytes read from the stream buffer, if any.
|
||||
*/
|
||||
size_t receive(
|
||||
void* data,
|
||||
size_t length,
|
||||
uint32_t timeout
|
||||
) const;
|
||||
|
||||
/**
|
||||
* @brief Queries a stream buffer to see how much data it contains, which is equal to
|
||||
* the number of bytes that can be read from the stream buffer before the stream
|
||||
* buffer would be empty.
|
||||
*
|
||||
* @return The number of bytes that can be read from the stream buffer before
|
||||
* the stream buffer would be empty.
|
||||
*/
|
||||
size_t getAvailableReadBytes() const;
|
||||
|
||||
/**
|
||||
* @brief Queries a stream buffer to see how much free space it contains, which is
|
||||
* equal to the amount of data that can be sent to the stream buffer before it
|
||||
* is full.
|
||||
*
|
||||
* @return The number of bytes that can be written to the stream buffer before
|
||||
* the stream buffer would be full.
|
||||
*/
|
||||
size_t getAvailableWriteBytes() const;
|
||||
|
||||
/**
|
||||
* @brief Queries a stream buffer to see if it is full.
|
||||
*
|
||||
* @return true if the stream buffer is full.
|
||||
* @return false if the stream buffer is not full.
|
||||
*/
|
||||
bool isFull() const;
|
||||
|
||||
/**
|
||||
* @brief Queries a stream buffer to see if it is empty.
|
||||
*
|
||||
* @param stream_buffer The stream buffer instance.
|
||||
* @return true if the stream buffer is empty.
|
||||
* @return false if the stream buffer is not empty.
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
/**
|
||||
* @brief Resets a stream buffer to its initial, empty, state. Any data that was
|
||||
* in the stream buffer is discarded. A stream buffer can only be reset if there
|
||||
* are no tasks blocked waiting to either send to or receive from the stream buffer.
|
||||
*
|
||||
* @return TtStatusOk if the stream buffer is reset.
|
||||
* @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.
|
||||
*/
|
||||
bool reset() const;
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "StringUtils.h"
|
||||
#include "Tactility/StringUtils.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace tt::string {
|
||||
|
||||
/**
|
||||
* Given a filesystem path as input, try and get the parent path.
|
||||
* @param[in] path input path
|
||||
* @param[out] output an output buffer that is allocated to at least the size of "current"
|
||||
* @return true when successful
|
||||
*/
|
||||
bool getPathParent(const std::string& path, std::string& output);
|
||||
|
||||
/**
|
||||
* Given a filesystem path as input, get the last segment of a path
|
||||
* @param[in] path input path
|
||||
*/
|
||||
std::string getLastPathSegment(const std::string& path);
|
||||
|
||||
/**
|
||||
* Splits the provided input into separate pieces with delimiter as separator text.
|
||||
* When the input string is empty, the output list will be empty too.
|
||||
*
|
||||
* @param input the input to split up
|
||||
* @param delimiter a non-empty string to recognize as separator
|
||||
*/
|
||||
std::vector<std::string> split(const std::string& input, const std::string& delimiter);
|
||||
|
||||
/**
|
||||
* Join a set of tokens into a single string, given a delimiter (separator).
|
||||
* If the input is an empty list, the result will be an empty string.
|
||||
* The delimeter is only placed inbetween tokens and not appended at the end of the resulting string.
|
||||
*
|
||||
* @param input the tokens to join together
|
||||
* @param delimiter the separator to join with
|
||||
*/
|
||||
std::string join(const std::vector<std::string>& input, const std::string& delimiter);
|
||||
|
||||
/**
|
||||
* Returns the lowercase value of a string.
|
||||
* @param[in] the string with lower and/or uppercase characters
|
||||
* @return a string with only lowercase characters
|
||||
*/
|
||||
template <typename T>
|
||||
std::basic_string<T> lowercase(const std::basic_string<T>& input) {
|
||||
std::basic_string<T> output = input;
|
||||
std::transform(
|
||||
output.begin(),
|
||||
output.end(),
|
||||
output.begin(),
|
||||
[](const T character) { return static_cast<T>(std::tolower(character)); }
|
||||
);
|
||||
return std::move(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the first part of a file name right up (and excluding) the first period character.
|
||||
*/
|
||||
std::string removeFileExtension(const std::string& input);
|
||||
|
||||
} // namespace
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "Check.h"
|
||||
#include "CoreDefines.h"
|
||||
#include "CoreExtraDefines.h"
|
||||
#include "EventFlag.h"
|
||||
#include "kernel/Kernel.h"
|
||||
#include "kernel/critical/Critical.h"
|
||||
#include "Log.h"
|
||||
#include "Mutex.h"
|
||||
#include "Thread.h"
|
||||
@@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define TT_CONFIG_THREAD_MAX_PRIORITIES 10
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "Thread.h"
|
||||
#include "Tactility/Thread.h"
|
||||
|
||||
#include "Check.h"
|
||||
#include "CoreDefines.h"
|
||||
#include "EventFlag.h"
|
||||
#include "kernel/Kernel.h"
|
||||
#include "Log.h"
|
||||
#include "TactilityCoreConfig.h"
|
||||
#include "Tactility/Check.h"
|
||||
#include "Tactility/CoreDefines.h"
|
||||
#include "Tactility/EventFlag.h"
|
||||
#include "Tactility/kernel/Kernel.h"
|
||||
#include "Tactility/Log.h"
|
||||
#include "Tactility/TactilityCoreConfig.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreDefines.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "RtosCompatTask.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
typedef TaskHandle_t ThreadId;
|
||||
|
||||
class Thread {
|
||||
|
||||
public:
|
||||
|
||||
enum class State{
|
||||
Stopped,
|
||||
Starting,
|
||||
Running,
|
||||
};
|
||||
|
||||
/** ThreadPriority */
|
||||
enum class Priority : UBaseType_t {
|
||||
None = 0U, /**< Uninitialized, choose system default */
|
||||
Idle = 1U,
|
||||
Lower = 2U,
|
||||
Low = 3U,
|
||||
Normal = 4U,
|
||||
High = 5U,
|
||||
Higher = 6U,
|
||||
Critical = 7U
|
||||
};
|
||||
|
||||
|
||||
/** ThreadCallback Your callback to run in new thread
|
||||
* @warning never use osThreadExit in Thread
|
||||
*/
|
||||
typedef int32_t (*Callback)(void* context);
|
||||
|
||||
/** Write to stdout callback
|
||||
* @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[in] state new thread state
|
||||
* @param[in] context callback context
|
||||
*/
|
||||
typedef void (*StateCallback)(State state, void* context);
|
||||
|
||||
private:
|
||||
|
||||
static void mainBody(void* context);
|
||||
|
||||
TaskHandle_t taskHandle = nullptr;
|
||||
State state = State::Stopped;
|
||||
Callback callback = nullptr;
|
||||
void* callbackContext = nullptr;
|
||||
int32_t callbackResult = 0;
|
||||
StateCallback stateCallback = nullptr;
|
||||
void* stateCallbackContext = nullptr;
|
||||
std::string name = {};
|
||||
Priority priority = Priority::Normal;
|
||||
configSTACK_DEPTH_TYPE stackSize = 0;
|
||||
portBASE_TYPE affinity = -1;
|
||||
|
||||
void setState(Thread::State state);
|
||||
|
||||
public:
|
||||
|
||||
Thread() = default;
|
||||
|
||||
/** Allocate Thread, shortcut version
|
||||
* @param[in] name the name of the thread
|
||||
* @param[in] stackSize in bytes
|
||||
* @param[in] callback
|
||||
* @param[in] callbackContext
|
||||
* @param[in] affinity Which CPU core to pin this task to, -1 means unpinned (only works on ESP32)
|
||||
*/
|
||||
Thread(
|
||||
std::string name,
|
||||
configSTACK_DEPTH_TYPE stackSize,
|
||||
Callback callback,
|
||||
_Nullable void* callbackContext,
|
||||
portBASE_TYPE affinity = -1
|
||||
);
|
||||
|
||||
~Thread();
|
||||
|
||||
/** Set Thread name
|
||||
* @param[in] name string
|
||||
*/
|
||||
void setName(std::string name);
|
||||
|
||||
/** Set Thread stack size
|
||||
* @param[in] stackSize stack size in bytes
|
||||
*/
|
||||
void setStackSize(size_t stackSize);
|
||||
|
||||
/** Set Thread 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[in] priority ThreadPriority value
|
||||
*/
|
||||
void setPriority(Priority priority);
|
||||
|
||||
|
||||
/** Set Thread state change callback
|
||||
* @param[in] callback state change callback
|
||||
* @param[in] callbackContext pointer to context
|
||||
*/
|
||||
void setStateCallback(StateCallback callback, _Nullable void* callbackContext = nullptr);
|
||||
|
||||
/** Get Thread state
|
||||
* @return thread state from ThreadState
|
||||
*/
|
||||
State getState() const;
|
||||
|
||||
/** Start Thread */
|
||||
void start();
|
||||
|
||||
/** Join Thread
|
||||
* @warning make sure you manually interrupt any logic in your thread (e.g. by an EventFlag or boolean+Mutex)
|
||||
* @param[in] timeout the maximum amount of time to wait
|
||||
* @param[in] pollInterval the amount of ticks to wait before we check again if the thread is finished
|
||||
* @return success result
|
||||
*/
|
||||
bool join(TickType_t timeout = portMAX_DELAY, TickType_t pollInterval = 10);
|
||||
|
||||
/** Get FreeRTOS ThreadId for Thread instance
|
||||
* @return ThreadId or nullptr
|
||||
*/
|
||||
ThreadId getId() const;
|
||||
|
||||
/**
|
||||
* @warning crashes when state is not "stopped"
|
||||
* @return thread return code
|
||||
*/
|
||||
int32_t getReturnCode() const;
|
||||
|
||||
/** Suspend thread
|
||||
* @param[in] threadId thread id
|
||||
*/
|
||||
static void suspend(ThreadId threadId);
|
||||
|
||||
/** Resume thread
|
||||
* @param[in] threadId thread id
|
||||
*/
|
||||
static void resume(ThreadId threadId);
|
||||
|
||||
/** Get thread suspended state
|
||||
* @param[in] threadId thread id
|
||||
* @return true if thread is suspended
|
||||
*/
|
||||
static bool isSuspended(ThreadId threadId);
|
||||
|
||||
/**
|
||||
* @brief Get thread stack watermark
|
||||
* @param[in] threadId
|
||||
* @return uint32_t
|
||||
*/
|
||||
static uint32_t getStackSpace(ThreadId threadId);
|
||||
|
||||
/** @return pointer to Thread instance or nullptr if this thread doesn't belong to Tactility */
|
||||
static Thread* getCurrent();
|
||||
|
||||
static uint32_t setFlags(ThreadId threadId, uint32_t flags);
|
||||
|
||||
static uint32_t clearFlags(uint32_t flags);
|
||||
|
||||
static uint32_t getFlags();
|
||||
|
||||
static uint32_t awaitFlags(uint32_t flags, uint32_t options, uint32_t timeout);
|
||||
};
|
||||
|
||||
#define THREAD_PRIORITY_APP Thread::PriorityNormal
|
||||
#define THREAD_PRIORITY_SERVICE Thread::Priority::High
|
||||
#define THREAD_PRIORITY_RENDER Thread::Priority::Higher
|
||||
#define THREAD_PRIORITY_ISR Thread::Priority::Critical
|
||||
|
||||
} // namespace
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "Timer.h"
|
||||
#include "Tactility/Timer.h"
|
||||
|
||||
#include "Tactility/Check.h"
|
||||
#include "Tactility/RtosCompat.h"
|
||||
|
||||
#include <utility>
|
||||
#include "Check.h"
|
||||
#include "RtosCompat.h"
|
||||
|
||||
namespace tt {
|
||||
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RtosCompatTimers.h"
|
||||
#include "Thread.h"
|
||||
#include <memory>
|
||||
|
||||
namespace tt {
|
||||
|
||||
class Timer {
|
||||
|
||||
public:
|
||||
|
||||
typedef void (*Callback)(std::shared_ptr<void> context);
|
||||
typedef void (*PendingCallback)(void* context, uint32_t arg);
|
||||
|
||||
private:
|
||||
|
||||
struct TimerHandleDeleter {
|
||||
void operator()(TimerHandle_t handleToDelete) {
|
||||
xTimerDelete(handleToDelete, portMAX_DELAY);
|
||||
}
|
||||
};
|
||||
|
||||
Callback callback;
|
||||
std::shared_ptr<void> callbackContext;
|
||||
std::unique_ptr<std::remove_pointer_t<TimerHandle_t>, TimerHandleDeleter> handle;
|
||||
|
||||
static void onCallback(TimerHandle_t hTimer);
|
||||
|
||||
public:
|
||||
|
||||
enum class Type {
|
||||
Once = 0, ///< One-shot timer.
|
||||
Periodic = 1 ///< Repeating timer.
|
||||
};
|
||||
|
||||
enum class Priority{
|
||||
Normal, /**< Lower then other threads */
|
||||
Elevated, /**< Same as other threads */
|
||||
};
|
||||
|
||||
/**
|
||||
* @param[in] type The timer type
|
||||
* @param[in] callback The callback function
|
||||
* @param callbackContext The callback context
|
||||
*/
|
||||
Timer(Type type, Callback callback, std::shared_ptr<void> callbackContext = nullptr);
|
||||
|
||||
~Timer();
|
||||
|
||||
/** Start timer
|
||||
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
||||
* @param[in] interval The interval in ticks
|
||||
* @return success result
|
||||
*/
|
||||
bool start(TickType_t interval);
|
||||
|
||||
/** Restart timer with previous timeout value
|
||||
* @warning This is asynchronous call, real operation will happen as soon as timer service process this request.
|
||||
* @param[in] interval The interval in ticks
|
||||
* @return success result
|
||||
*/
|
||||
bool restart(TickType_t interval);
|
||||
|
||||
/** Stop timer
|
||||
* @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.
|
||||
* @return true when running
|
||||
*/
|
||||
bool isRunning();
|
||||
|
||||
/** Get timer expire time
|
||||
* @return expire tick
|
||||
*/
|
||||
TickType_t getExpireTime();
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @return true on success
|
||||
*/
|
||||
bool setPendingCallback(PendingCallback callback, void* callbackContext, uint32_t callbackArg, TickType_t timeout);
|
||||
|
||||
/** Set Timer thread priority
|
||||
* @param[in] priority The priority
|
||||
*/
|
||||
void setThreadPriority(Thread::Priority priority);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "Crypt.h"
|
||||
#include "Tactility/crypt/Crypt.h"
|
||||
|
||||
#include "Check.h"
|
||||
#include "Log.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "Tactility/Check.h"
|
||||
#include "Tactility/Log.h"
|
||||
|
||||
#include <mbedtls/aes.h>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/** @file secure.h
|
||||
*
|
||||
* @brief Hardware-bound encryption methods.
|
||||
* @warning Enable secure boot and flash encryption to increase security.
|
||||
*
|
||||
* Offers AES 256 CBC encryption with built-in key.
|
||||
* The key is built from data including:
|
||||
* - the internal factory MAC address
|
||||
* - random data stored in NVS
|
||||
*
|
||||
* It's important to use flash encryption to avoid an attacker to get
|
||||
* access to your encrypted data. If flash encryption is disabled,
|
||||
* someone can fetch the key from the partitions.
|
||||
*
|
||||
* See:
|
||||
* https://docs.espressif.com/projects/esp-idf/en/latest/esp32/security/secure-boot-v2.html
|
||||
* https://docs.espressif.com/projects/esp-idf/en/latest/esp32/security/flash-encryption.html
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace tt::crypt {
|
||||
|
||||
/**
|
||||
* @brief Fills the IV with zeros and then creates an IV based on the input data.
|
||||
* @param[in] data input data
|
||||
* @param[in] dataLength input data length
|
||||
* @param[out] iv output IV
|
||||
*/
|
||||
void getIv(const void* data, size_t dataLength, uint8_t iv[16]);
|
||||
|
||||
/**
|
||||
* @brief Encrypt data.
|
||||
*
|
||||
* Important: Use flash encryption to increase security.
|
||||
* Important: input and output data must be aligned to 16 bytes.
|
||||
*
|
||||
* @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* inData, uint8_t* outData, size_t dataLength);
|
||||
|
||||
/**
|
||||
* @brief Decrypt data.
|
||||
*
|
||||
* Important: Use flash encryption to increase security.
|
||||
* Important: input and output data must be aligned to 16 bytes.
|
||||
*
|
||||
* @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* inData, uint8_t* outData, size_t dataLength);
|
||||
|
||||
} // namespace
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Hash.h"
|
||||
#include "Tactility/crypt/Hash.h"
|
||||
|
||||
namespace tt::crypt {
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace tt::crypt {
|
||||
|
||||
/**
|
||||
* Implementation of DJB2 hashing algorithm.
|
||||
* @param[in] str the string to calculate the hash for
|
||||
* @return the hash
|
||||
*/
|
||||
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);
|
||||
|
||||
} // namespace
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "File.h"
|
||||
#include "Tactility/file/File.h"
|
||||
|
||||
namespace tt::file {
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "TactilityCore.h"
|
||||
#include <cstdio>
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "kernel/Kernel.h"
|
||||
#include "CoreDefines.h"
|
||||
#include "RtosCompatTask.h"
|
||||
#include "Tactility/kernel/Kernel.h"
|
||||
#include "Tactility/CoreDefines.h"
|
||||
#include "Tactility/RtosCompatTask.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#else
|
||||
#include "FreeRTOS.h"
|
||||
#endif
|
||||
|
||||
namespace tt::kernel {
|
||||
|
||||
/** Recognized platform types */
|
||||
typedef enum {
|
||||
PlatformEsp,
|
||||
PlatformSimulator
|
||||
} Platform;
|
||||
|
||||
/** Check if kernel is running
|
||||
* @return true if the FreeRTOS kernel is running, false otherwise
|
||||
*/
|
||||
bool isRunning();
|
||||
|
||||
/** Lock kernel, pause process scheduling
|
||||
* @warning don't call from ISR context
|
||||
* @return true on success
|
||||
*/
|
||||
bool lock();
|
||||
|
||||
/** Unlock kernel, resume process scheduling
|
||||
* @warning don't call from ISR context
|
||||
* @return true on success
|
||||
*/
|
||||
bool unlock();
|
||||
|
||||
/** Restore kernel lock state
|
||||
* @warning don't call from ISR context
|
||||
* @param[in] lock The lock state
|
||||
* @return true on success
|
||||
*/
|
||||
bool restoreLock(bool lock);
|
||||
|
||||
/** Get kernel systick frequency
|
||||
* @return systick counts per second
|
||||
*/
|
||||
uint32_t getTickFrequency();
|
||||
|
||||
TickType_t getTicks();
|
||||
|
||||
/** Delay execution
|
||||
* @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
|
||||
*/
|
||||
void delayTicks(TickType_t ticks);
|
||||
|
||||
/** Delay until tick
|
||||
* @warning don't call from ISR context
|
||||
* @param[in] ticks The tick until which kerel should delay task execution
|
||||
* @return true on success
|
||||
*/
|
||||
bool delayUntilTick(TickType_t tick);
|
||||
|
||||
/** Convert milliseconds to ticks
|
||||
*
|
||||
* @param[in] milliSeconds time in milliseconds
|
||||
* @return time in ticks
|
||||
*/
|
||||
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 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
|
||||
*/
|
||||
void delayMicros(uint32_t microSeconds);
|
||||
|
||||
/** @return the platform that Tactility currently is running on. */
|
||||
Platform getPlatform();
|
||||
|
||||
} // namespace
|
||||
@@ -1,6 +1,6 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#include "PanicHandler.h"
|
||||
#include "Tactility/kernel/PanicHandler.h"
|
||||
|
||||
#include <esp_debug_helpers.h>
|
||||
#include <esp_attr.h>
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#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
|
||||
uint32_t sp = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Callstack-related crash data. */
|
||||
struct CrashData {
|
||||
bool callstackCorrupted = false;
|
||||
uint8_t callstackLength = 0;
|
||||
CallstackFrame callstack[CRASH_DATA_CALLSTACK_LIMIT];
|
||||
};
|
||||
|
||||
/** @return the crash data */
|
||||
const CrashData& getRtcCrashData();
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "Critical.h"
|
||||
#include "CoreDefines.h"
|
||||
#include "RtosCompatTask.h"
|
||||
#include "Tactility/kernel/critical/Critical.h"
|
||||
|
||||
#include "Tactility/CoreDefines.h"
|
||||
#include "Tactility/RtosCompatTask.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
static portMUX_TYPE critical_mutex;
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace tt::kernel::critical {
|
||||
|
||||
struct CriticalInfo {
|
||||
uint32_t isrm;
|
||||
bool fromIsr;
|
||||
bool kernelRunning;
|
||||
};
|
||||
|
||||
/** Enter a critical section
|
||||
* @return info on the status
|
||||
*/
|
||||
CriticalInfo enter();
|
||||
|
||||
/**
|
||||
* Exit a critical section
|
||||
* @param[in] info the info from when the critical section was started
|
||||
*/
|
||||
void exit(CriticalInfo info);
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user