C++ conversions (#111)

* Remove version from artifact name
* Target C++ 20 and higher
* Use cpp string
* Better crash implementation
* String utils in cpp style
* Replace parameter methods with start() method
* MutexType to Mutex::Type
* Kernel c to cpp style
* Cleanup event flag
* More cpp conversions
* Test fixes
* Updated ideas docs
This commit is contained in:
Ken Van Hoeylandt
2024-12-07 12:24:28 +01:00
committed by GitHub
parent d52fe52d96
commit 42e843b463
66 changed files with 272 additions and 258 deletions
+201
View File
@@ -0,0 +1,201 @@
#include "kernel/Kernel.h"
#include "Check.h"
#include "CoreDefines.h"
#include "CoreTypes.h"
#include "RtosCompatTask.h"
#ifdef ESP_PLATFORM
#include "rom/ets_sys.h"
#else
#include <unistd.h>
#endif
namespace tt::kernel {
bool isIrq() {
return TT_IS_IRQ_MODE();
}
bool isRunning() {
return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING;
}
int32_t lock() {
tt_assert(!isIrq());
int32_t lock;
switch (xTaskGetSchedulerState()) {
case taskSCHEDULER_SUSPENDED:
lock = 1;
break;
case taskSCHEDULER_RUNNING:
vTaskSuspendAll();
lock = 0;
break;
case taskSCHEDULER_NOT_STARTED:
default:
lock = (int32_t)TtStatusError;
break;
}
/* Return previous lock state */
return (lock);
}
int32_t unlock() {
tt_assert(!isIrq());
int32_t lock;
switch (xTaskGetSchedulerState()) {
case taskSCHEDULER_SUSPENDED:
lock = 1;
if (xTaskResumeAll() != pdTRUE) {
if (xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) {
lock = (int32_t)TtStatusError;
}
}
break;
case taskSCHEDULER_RUNNING:
lock = 0;
break;
case taskSCHEDULER_NOT_STARTED:
default:
lock = (int32_t)TtStatusError;
break;
}
/* Return previous lock state */
return (lock);
}
int32_t restoreLock(int32_t lock) {
tt_assert(!isIrq());
switch (xTaskGetSchedulerState()) {
case taskSCHEDULER_SUSPENDED:
case taskSCHEDULER_RUNNING:
if (lock == 1) {
vTaskSuspendAll();
} else {
if (lock != 0) {
lock = (int32_t)TtStatusError;
} else {
if (xTaskResumeAll() != pdTRUE) {
if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) {
lock = (int32_t)TtStatusError;
}
}
}
}
break;
case taskSCHEDULER_NOT_STARTED:
default:
lock = (int32_t)TtStatusError;
break;
}
/* Return new lock state */
return (lock);
}
uint32_t getTickFrequency() {
/* Return frequency in hertz */
return (configTICK_RATE_HZ);
}
void delayTicks(TickType_t ticks) {
tt_assert(!isIrq());
if (ticks == 0U) {
taskYIELD();
} else {
vTaskDelay(ticks);
}
}
TtStatus delayUntilTick(TickType_t tick) {
tt_assert(!isIrq());
TickType_t tcnt, delay;
TtStatus stat;
stat = TtStatusOk;
tcnt = xTaskGetTickCount();
/* Determine remaining number of tick to delay */
delay = (TickType_t)tick - tcnt;
/* Check if target tick has not expired */
if ((delay != 0U) && (0 == (delay >> (8 * sizeof(TickType_t) - 1)))) {
if (xTaskDelayUntil(&tcnt, delay) == pdFALSE) {
/* Did not delay */
stat = TtStatusError;
}
} else {
/* No delay or already expired */
stat = TtStatusErrorParameter;
}
/* Return execution status */
return (stat);
}
TickType_t getTicks() {
TickType_t ticks;
if (isIrq() != 0U) {
ticks = xTaskGetTickCountFromISR();
} else {
ticks = xTaskGetTickCount();
}
return ticks;
}
TickType_t millisToTicks(uint32_t milliseconds) {
#if configTICK_RATE_HZ == 1000
return (TickType_t)milliseconds;
#else
return (TickType_t)((float)configTICK_RATE_HZ) / 1000.0f * (float)milliseconds;
#endif
}
void delayMillis(uint32_t milliseconds) {
if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) {
if (milliseconds > 0 && milliseconds < portMAX_DELAY - 1) {
milliseconds += 1;
}
#if configTICK_RATE_HZ_RAW == 1000
tt_delay_tick(milliseconds);
#else
delayTicks(kernel::millisToTicks(milliseconds));
#endif
} else if (milliseconds > 0) {
kernel::delayMicros(milliseconds * 1000);
}
}
void delayMicros(uint32_t microseconds) {
#ifdef ESP_PLATFORM
ets_delay_us(microseconds);
#else
usleep(microseconds);
#endif
}
Platform getPlatform() {
#ifdef ESP_PLATFORM
return PlatformEsp;
#else
return PlatformSimulator;
#endif
}
} // namespace
+125
View File
@@ -0,0 +1,125 @@
#pragma once
#include "CoreTypes.h"
#ifdef ESP_PLATFORM
#include "freertos/FreeRTOS.h"
#else
#include "FreeRTOS.h"
#endif
namespace tt::kernel {
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
*/
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)
*/
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)
*/
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
*/
int32_t restoreLock(int32_t lock);
/** Get kernel systick frequency
*
* @return systick counts per second
*/
uint32_t getTickFrequency();
TickType_t getTicks();
/** Delay execution
*
* @warning This should never be called in interrupt request 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 This should never be called in interrupt request context.
*
* @param[in] ticks The tick until which kerel should delay task execution
*
* @return The status.
*/
TtStatus delayUntilTick(uint32_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 `tt_delay_us`.
*
* @warning Cannot be used from ISR
*
* @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);
Platform getPlatform();
} // namespace
@@ -0,0 +1,42 @@
#include "Critical.h"
#include "CoreDefines.h"
#include "RtosCompatTask.h"
#ifdef ESP_PLATFORM
static portMUX_TYPE critical_mutex;
#define TT_ENTER_CRITICAL() taskENTER_CRITICAL(&critical_mutex)
#else
#define TT_ENTER_CRITICAL() taskENTER_CRITICAL()
#endif
namespace tt::kernel::critical {
TtCriticalInfo enter() {
TtCriticalInfo info = {
.isrm = 0,
.fromIsr = TT_IS_ISR(),
.kernelRunning = (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
};
if (info.fromIsr) {
info.isrm = taskENTER_CRITICAL_FROM_ISR();
} else if (info.kernelRunning) {
TT_ENTER_CRITICAL();
} else {
portDISABLE_INTERRUPTS();
}
return info;
}
void exit(TtCriticalInfo info) {
if (info.fromIsr) {
taskEXIT_CRITICAL_FROM_ISR(info.isrm);
} else if (info.kernelRunning) {
TT_ENTER_CRITICAL();
} else {
portENABLE_INTERRUPTS();
}
}
}
@@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
#ifndef TT_CRITICAL_ENTER
#define TT_CRITICAL_ENTER() __TtCriticalInfo __tt_critical_info = __tt_critical_enter();
#endif
#ifndef TT_CRITICAL_EXIT
#define TT_CRITICAL_EXIT() __tt_critical_exit(__tt_critical_info);
#endif
namespace tt::kernel::critical {
typedef struct {
uint32_t isrm;
bool fromIsr;
bool kernelRunning;
} TtCriticalInfo;
TtCriticalInfo enter();
void exit(TtCriticalInfo info);
} // namespace