5502879a5b
This is very much still work in progress and much more will change before the final 2.0.0 Some APIs have changed. New libraries have been added. LittleFS included. Co-authored-by: Seon Rozenblum <seonr@3sprockets.com> Co-authored-by: Me No Dev <me-no-dev@users.noreply.github.com> Co-authored-by: geeksville <kevinh@geeksville.com> Co-authored-by: Mike Dunston <m_dunston@comcast.net> Co-authored-by: Unexpected Maker <seon@unexpectedmaker.com> Co-authored-by: Seon Rozenblum <seonr@3sprockets.com> Co-authored-by: microDev <70126934+microDev1@users.noreply.github.com> Co-authored-by: tobozo <tobozo@users.noreply.github.com> Co-authored-by: bobobo1618 <bobobo1618@users.noreply.github.com> Co-authored-by: lorol <lorolouis@gmail.com> Co-authored-by: geeksville <kevinh@geeksville.com> Co-authored-by: Limor "Ladyada" Fried <limor@ladyada.net> Co-authored-by: Sweety <switi.mhaiske@espressif.com> Co-authored-by: Loick MAHIEUX <loick111@gmail.com> Co-authored-by: Larry Bernstone <lbernstone@gmail.com> Co-authored-by: Valerii Koval <valeros@users.noreply.github.com> Co-authored-by: 快乐的我531 <2302004040@qq.com> Co-authored-by: chegewara <imperiaonline4@gmail.com> Co-authored-by: Clemens Kirchgatterer <clemens@1541.org> Co-authored-by: Aron Rubin <aronrubin@gmail.com> Co-authored-by: Pete Lewis <601236+lewispg228@users.noreply.github.com>
307 lines
8.0 KiB
C++
307 lines
8.0 KiB
C++
/*
|
|
* FreeRTOS.cpp
|
|
*
|
|
* Created on: Feb 24, 2017
|
|
* Author: kolban
|
|
*/
|
|
#include <freertos/FreeRTOS.h> // Include the base FreeRTOS definitions
|
|
#include <freertos/task.h> // Include the task definitions
|
|
#include <freertos/semphr.h> // Include the semaphore definitions
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include "RTOS.h"
|
|
#include "sdkconfig.h"
|
|
#include "esp32-hal-log.h"
|
|
|
|
/**
|
|
* Sleep for the specified number of milliseconds.
|
|
* @param[in] ms The period in milliseconds for which to sleep.
|
|
*/
|
|
void FreeRTOS::sleep(uint32_t ms) {
|
|
::vTaskDelay(ms / portTICK_PERIOD_MS);
|
|
} // sleep
|
|
|
|
|
|
/**
|
|
* Start a new task.
|
|
* @param[in] task The function pointer to the function to be run in the task.
|
|
* @param[in] taskName A string identifier for the task.
|
|
* @param[in] param An optional parameter to be passed to the started task.
|
|
* @param[in] stackSize An optional paremeter supplying the size of the stack in which to run the task.
|
|
*/
|
|
void FreeRTOS::startTask(void task(void*), std::string taskName, void* param, uint32_t stackSize) {
|
|
::xTaskCreate(task, taskName.data(), stackSize, param, 5, NULL);
|
|
} // startTask
|
|
|
|
|
|
/**
|
|
* Delete the task.
|
|
* @param[in] pTask An optional handle to the task to be deleted. If not supplied the calling task will be deleted.
|
|
*/
|
|
void FreeRTOS::deleteTask(TaskHandle_t pTask) {
|
|
::vTaskDelete(pTask);
|
|
} // deleteTask
|
|
|
|
|
|
/**
|
|
* Get the time in milliseconds since the %FreeRTOS scheduler started.
|
|
* @return The time in milliseconds since the %FreeRTOS scheduler started.
|
|
*/
|
|
uint32_t FreeRTOS::getTimeSinceStart() {
|
|
return (uint32_t) (xTaskGetTickCount() * portTICK_PERIOD_MS);
|
|
} // getTimeSinceStart
|
|
|
|
|
|
/**
|
|
* @brief Wait for a semaphore to be released by trying to take it and
|
|
* then releasing it again.
|
|
* @param [in] owner A debug tag.
|
|
* @return The value associated with the semaphore.
|
|
*/
|
|
uint32_t FreeRTOS::Semaphore::wait(std::string owner) {
|
|
log_v(">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());
|
|
|
|
if (m_usePthreads) {
|
|
pthread_mutex_lock(&m_pthread_mutex);
|
|
} else {
|
|
xSemaphoreTake(m_semaphore, portMAX_DELAY);
|
|
}
|
|
|
|
if (m_usePthreads) {
|
|
pthread_mutex_unlock(&m_pthread_mutex);
|
|
} else {
|
|
xSemaphoreGive(m_semaphore);
|
|
}
|
|
|
|
log_v("<< wait: Semaphore released: %s", toString().c_str());
|
|
return m_value;
|
|
} // wait
|
|
|
|
/**
|
|
* @brief Wait for a semaphore to be released in a given period of time by trying to take it and
|
|
* then releasing it again. The value associated with the semaphore can be taken by value() call after return
|
|
* @param [in] owner A debug tag.
|
|
* @param [in] timeoutMs timeout to wait in ms.
|
|
* @return True if we took the semaphore within timeframe.
|
|
*/
|
|
bool FreeRTOS::Semaphore::timedWait(std::string owner, uint32_t timeoutMs) {
|
|
log_v(">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());
|
|
|
|
if (m_usePthreads && timeoutMs != portMAX_DELAY) {
|
|
assert(false); // We apparently don't have a timed wait for pthreads.
|
|
}
|
|
|
|
auto ret = pdTRUE;
|
|
|
|
if (m_usePthreads) {
|
|
pthread_mutex_lock(&m_pthread_mutex);
|
|
} else {
|
|
ret = xSemaphoreTake(m_semaphore, timeoutMs);
|
|
}
|
|
|
|
if (m_usePthreads) {
|
|
pthread_mutex_unlock(&m_pthread_mutex);
|
|
} else {
|
|
xSemaphoreGive(m_semaphore);
|
|
}
|
|
|
|
log_v("<< wait: Semaphore %s released: %d", toString().c_str(), ret);
|
|
return ret;
|
|
} // wait
|
|
|
|
|
|
FreeRTOS::Semaphore::Semaphore(std::string name) {
|
|
m_usePthreads = false; // Are we using pThreads or FreeRTOS?
|
|
if (m_usePthreads) {
|
|
pthread_mutex_init(&m_pthread_mutex, nullptr);
|
|
} else {
|
|
m_semaphore = xSemaphoreCreateBinary();
|
|
xSemaphoreGive(m_semaphore);
|
|
}
|
|
|
|
m_name = name;
|
|
m_owner = std::string("<N/A>");
|
|
m_value = 0;
|
|
}
|
|
|
|
|
|
FreeRTOS::Semaphore::~Semaphore() {
|
|
if (m_usePthreads) {
|
|
pthread_mutex_destroy(&m_pthread_mutex);
|
|
} else {
|
|
vSemaphoreDelete(m_semaphore);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Give a semaphore.
|
|
* The Semaphore is given.
|
|
*/
|
|
void FreeRTOS::Semaphore::give() {
|
|
log_v("Semaphore giving: %s", toString().c_str());
|
|
m_owner = std::string("<N/A>");
|
|
|
|
if (m_usePthreads) {
|
|
pthread_mutex_unlock(&m_pthread_mutex);
|
|
} else {
|
|
xSemaphoreGive(m_semaphore);
|
|
}
|
|
// #ifdef ARDUINO_ARCH_ESP32
|
|
// FreeRTOS::sleep(10);
|
|
// #endif
|
|
|
|
} // Semaphore::give
|
|
|
|
|
|
/**
|
|
* @brief Give a semaphore.
|
|
* The Semaphore is given with an associated value.
|
|
* @param [in] value The value to associate with the semaphore.
|
|
*/
|
|
void FreeRTOS::Semaphore::give(uint32_t value) {
|
|
m_value = value;
|
|
give();
|
|
} // give
|
|
|
|
|
|
/**
|
|
* @brief Give a semaphore from an ISR.
|
|
*/
|
|
void FreeRTOS::Semaphore::giveFromISR() {
|
|
BaseType_t higherPriorityTaskWoken;
|
|
if (m_usePthreads) {
|
|
assert(false);
|
|
} else {
|
|
xSemaphoreGiveFromISR(m_semaphore, &higherPriorityTaskWoken);
|
|
}
|
|
} // giveFromISR
|
|
|
|
|
|
/**
|
|
* @brief Take a semaphore.
|
|
* Take a semaphore and wait indefinitely.
|
|
* @param [in] owner The new owner (for debugging)
|
|
* @return True if we took the semaphore.
|
|
*/
|
|
bool FreeRTOS::Semaphore::take(std::string owner) {
|
|
log_v("Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
|
bool rc = false;
|
|
if (m_usePthreads) {
|
|
pthread_mutex_lock(&m_pthread_mutex);
|
|
} else {
|
|
rc = ::xSemaphoreTake(m_semaphore, portMAX_DELAY) == pdTRUE;
|
|
}
|
|
if (rc) {
|
|
m_owner = owner;
|
|
log_v("Semaphore taken: %s", toString().c_str());
|
|
} else {
|
|
log_e("Semaphore NOT taken: %s", toString().c_str());
|
|
}
|
|
return rc;
|
|
} // Semaphore::take
|
|
|
|
|
|
/**
|
|
* @brief Take a semaphore.
|
|
* Take a semaphore but return if we haven't obtained it in the given period of milliseconds.
|
|
* @param [in] timeoutMs Timeout in milliseconds.
|
|
* @param [in] owner The new owner (for debugging)
|
|
* @return True if we took the semaphore.
|
|
*/
|
|
bool FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) {
|
|
log_v("Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
|
|
bool rc = false;
|
|
if (m_usePthreads) {
|
|
assert(false); // We apparently don't have a timed wait for pthreads.
|
|
} else {
|
|
rc = ::xSemaphoreTake(m_semaphore, timeoutMs / portTICK_PERIOD_MS) == pdTRUE;
|
|
}
|
|
if (rc) {
|
|
m_owner = owner;
|
|
log_v("Semaphore taken: %s", toString().c_str());
|
|
} else {
|
|
log_e("Semaphore NOT taken: %s", toString().c_str());
|
|
}
|
|
return rc;
|
|
} // Semaphore::take
|
|
|
|
|
|
|
|
/**
|
|
* @brief Create a string representation of the semaphore.
|
|
* @return A string representation of the semaphore.
|
|
*/
|
|
std::string FreeRTOS::Semaphore::toString() {
|
|
char hex[9];
|
|
std::string res = "name: " + m_name + " (0x";
|
|
snprintf(hex, sizeof(hex), "%08x", (uint32_t)m_semaphore);
|
|
res += hex;
|
|
res += "), owner: " + m_owner;
|
|
return res;
|
|
} // toString
|
|
|
|
|
|
/**
|
|
* @brief Set the name of the semaphore.
|
|
* @param [in] name The name of the semaphore.
|
|
*/
|
|
void FreeRTOS::Semaphore::setName(std::string name) {
|
|
m_name = name;
|
|
} // setName
|
|
|
|
|
|
/**
|
|
* @brief Create a ring buffer.
|
|
* @param [in] length The amount of storage to allocate for the ring buffer.
|
|
* @param [in] type The type of buffer. One of RINGBUF_TYPE_NOSPLIT, RINGBUF_TYPE_ALLOWSPLIT, RINGBUF_TYPE_BYTEBUF.
|
|
*/
|
|
#ifdef ESP_IDF_VERSION_MAJOR
|
|
Ringbuffer::Ringbuffer(size_t length, RingbufferType_t type)
|
|
#else
|
|
Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type)
|
|
#endif
|
|
{
|
|
m_handle = ::xRingbufferCreate(length, type);
|
|
} // Ringbuffer
|
|
|
|
|
|
Ringbuffer::~Ringbuffer() {
|
|
::vRingbufferDelete(m_handle);
|
|
} // ~Ringbuffer
|
|
|
|
|
|
/**
|
|
* @brief Receive data from the buffer.
|
|
* @param [out] size On return, the size of data returned.
|
|
* @param [in] wait How long to wait.
|
|
* @return A pointer to the storage retrieved.
|
|
*/
|
|
void* Ringbuffer::receive(size_t* size, TickType_t wait) {
|
|
return ::xRingbufferReceive(m_handle, size, wait);
|
|
} // receive
|
|
|
|
|
|
/**
|
|
* @brief Return an item.
|
|
* @param [in] item The item to be returned/released.
|
|
*/
|
|
void Ringbuffer::returnItem(void* item) {
|
|
::vRingbufferReturnItem(m_handle, item);
|
|
} // returnItem
|
|
|
|
|
|
/**
|
|
* @brief Send data to the buffer.
|
|
* @param [in] data The data to place into the buffer.
|
|
* @param [in] length The length of data to place into the buffer.
|
|
* @param [in] wait How long to wait before giving up. The default is to wait indefinitely.
|
|
* @return
|
|
*/
|
|
bool Ringbuffer::send(void* data, size_t length, TickType_t wait) {
|
|
return ::xRingbufferSend(m_handle, data, length, wait) == pdTRUE;
|
|
} // send
|
|
|
|
|