From ef391b9720c8fb65568ff15cac698291213185b9 Mon Sep 17 00:00:00 2001 From: jusax23 Date: Sat, 9 Sep 2023 13:45:09 +0200 Subject: [PATCH] initial --- .gitignore | 1 + library.properties | 9 ++ src/esp32/esp32_queue.c | 134 ++++++++++++++++++++++++++ src/esp32/esp32_queue.h | 202 ++++++++++++++++++++++++++++++++++++++++ src/jmutex.h | 23 +++++ src/jqueue.h | 13 +++ 6 files changed, 382 insertions(+) create mode 100644 .gitignore create mode 100644 library.properties create mode 100644 src/esp32/esp32_queue.c create mode 100644 src/esp32/esp32_queue.h create mode 100644 src/jmutex.h create mode 100644 src/jqueue.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..600d2d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vscode \ No newline at end of file diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..689d954 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=jusdk +version=1.0.0 +author=jusax23 +maintainer=jusax23 +sentence=Arduino library for pico and esp32. +paragraph=Add compatible Features. +category= +url=https://jusax.de/git/jusax23/JuSDK +architectures=esp32,pico diff --git a/src/esp32/esp32_queue.c b/src/esp32/esp32_queue.c new file mode 100644 index 0000000..c05dd1f --- /dev/null +++ b/src/esp32/esp32_queue.c @@ -0,0 +1,134 @@ + +#ifdef defined(_POSIX_THREADS) +#include "esp32_queue.h" + +#include "Arduino.h" + +void queue_init(queue_t *q, uint element_size, uint element_count) { + mutex_init(&q->core); + q->cond = PTHREAD_COND_INITIALIZER; + q->data = (uint8_t *)calloc(element_count + 1, element_size); + q->element_count = (uint16_t)element_count; + q->element_size = (uint16_t)element_size; + q->wptr = 0; + q->rptr = 0; +} + +void queue_free(queue_t *q) { free(q->data); } + +static inline uint queue_get_level_unsafe(queue_t *q) { + int32_t rc = (int32_t)q->wptr - (int32_t)q->rptr; + if (rc < 0) { + rc += q->element_count + 1; + } + return (uint)rc; +} + +static inline uint queue_get_level(queue_t *q) { + mutex_enter_blocking(&q->core); + uint level = queue_get_level_unsafe(q); + mutex_exit(&q->core); + return level; +} + +static inline void *element_ptr(queue_t *q, uint index) { + assert(index <= q->element_count); + return q->data + index * q->element_size; +} + +static inline uint16_t inc_index(queue_t *q, uint16_t index) { + if (++index > + q->element_count) { // > because we have element_count + 1 elements + index = 0; + } + +#if PICO_QUEUE_MAX_LEVEL + uint16_t level = queue_get_level_unsafe(q); + if (level > q->max_level) { + q->max_level = level; + } +#endif + + return index; +} + +static bool queue_add_internal(queue_t *q, const void *data, bool block) { + mutex_enter_blocking(&q->core); + do { + if (queue_get_level_unsafe(q) != q->element_count) { + memcpy(element_ptr(q, q->wptr), data, q->element_size); + q->wptr = inc_index(q, q->wptr); + mutex_exit(&q->core); + pthread_cond_signal(&q->cond); + return true; + } + if (block) { + pthread_cond_wait(&q->cond, &q->core); + } else { + mutex_exit(&q->core); + return false; + } + } while (true); +} + +static bool queue_remove_internal(queue_t *q, void *data, bool block) { + mutex_enter_blocking(&q->core); + do { + if (queue_get_level_unsafe(q) != 0) { + memcpy(data, element_ptr(q, q->rptr), q->element_size); + q->rptr = inc_index(q, q->rptr); + mutex_exit(&q->core); + pthread_cond_signal(&q->cond); + return true; + } + if (block) { + pthread_cond_wait(&q->cond, &q->core); + } else { + mutex_exit(&q->core); + return false; + } + } while (true); +} + +static bool queue_peek_internal(queue_t *q, void *data, bool block) { + mutex_enter_blocking(&q->core); + do { + if (queue_get_level_unsafe(q) != 0) { + memcpy(data, element_ptr(q, q->rptr), q->element_size); + mutex_exit(&q->core); + pthread_cond_signal(&q->cond); + return true; + } + if (block) { + pthread_cond_wait(&q->cond, &q->core); + } else { + mutex_exit(&q->core); + return false; + } + } while (true); +} + +bool queue_try_add(queue_t *q, const void *data) { + return queue_add_internal(q, data, false); +} + +bool queue_try_remove(queue_t *q, void *data) { + return queue_remove_internal(q, data, false); +} + +bool queue_try_peek(queue_t *q, void *data) { + return queue_peek_internal(q, data, false); +} + +void queue_add_blocking(queue_t *q, const void *data) { + queue_add_internal(q, data, true); +} + +void queue_remove_blocking(queue_t *q, void *data) { + queue_remove_internal(q, data, true); +} + +void queue_peek_blocking(queue_t *q, void *data) { + queue_peek_internal(q, data, true); +} +#endif \ No newline at end of file diff --git a/src/esp32/esp32_queue.h b/src/esp32/esp32_queue.h new file mode 100644 index 0000000..256fcde --- /dev/null +++ b/src/esp32/esp32_queue.h @@ -0,0 +1,202 @@ +#if defined(_POSIX_THREADS) + +#ifndef ESP32_QUEUE_H +#define ESP32_QUEUE_H + +/* + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "../jmutex.h" +#include "Arduino.h" +#include "pthread.h" + +#ifndef PICO_QUEUE_MAX_LEVEL +#define PICO_QUEUE_MAX_LEVEL 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + mutex_t core; + pthread_cond_t cond; + uint8_t *data; + uint16_t wptr; + uint16_t rptr; + uint16_t element_size; + uint16_t element_count; +#if PICO_QUEUE_MAX_LEVEL + uint16_t max_level; +#endif +} queue_t; + +/*! \brief Initialise a queue + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \param element_size Size of each value in the queue + * \param element_count Maximum number of entries in the queue + */ +static inline void queue_init(queue_t *q, uint element_size, + uint element_count); + +/*! \brief Destroy the specified queue. + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * + * Does not deallocate the queue_t structure itself. + */ +void queue_free(queue_t *q); + +/*! \brief Unsafe check of level of the specified queue. + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \return Number of entries in the queue + * + * This does not use the mutex, so may return incorrect results if the + * mutex is not externally locked + */ +static inline uint queue_get_level_unsafe(queue_t *q); + +/*! \brief Check of level of the specified queue. + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \return Number of entries in the queue + */ +static inline uint queue_get_level(queue_t *q); + +#if PICO_QUEUE_MAX_LEVEL +/*! \brief Returns the highest level reached by the specified queue since it was + * created or since the max level was reset \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \return Maximum level of the queue + */ +static inline uint queue_get_max_level(queue_t *q) { return q->max_level; } +#endif + +#if PICO_QUEUE_MAX_LEVEL +/*! \brief Reset the highest level reached of the specified queue. + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + */ +static inline void queue_reset_max_level(queue_t *q) { + mutex_enter_blocking(&q->core); + q->max_level = queue_get_level_unsafe(q); + mutex_exit(&q->core); +} +#endif + +/*! \brief Check if queue is empty + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \return true if queue is empty, false otherwise + * + * This function is interrupt and multicore safe. + */ +static inline bool queue_is_empty(queue_t *q) { + return queue_get_level(q) == 0; +} + +/*! \brief Check if queue is full + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \return true if queue is full, false otherwise + * + * This function is interrupt and multicore safe. + */ +static inline bool queue_is_full(queue_t *q) { + return queue_get_level(q) == q->element_count; +} + +// nonblocking queue access functions: + +/*! \brief Non-blocking add value queue if not full + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \param data Pointer to value to be copied into the queue + * \return true if the value was added + * + * If the queue is full this function will return immediately with false, + * otherwise the data is copied into a new value added to the queue, and this + * function will return true. + */ +bool queue_try_add(queue_t *q, const void *data); + +/*! \brief Non-blocking removal of entry from the queue if non empty + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \param data Pointer to the location to receive the removed value + * \return true if a value was removed + * + * If the queue is not empty function will copy the removed value into the + * location provided and return immediately with true, otherwise the function + * will return immediately with false. + */ +bool queue_try_remove(queue_t *q, void *data); + +/*! \brief Non-blocking peek at the next item to be removed from the queue + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \param data Pointer to the location to receive the peeked value + * \return true if there was a value to peek + * + * If the queue is not empty this function will return immediately with true + * with the peeked entry copied into the location specified by the data + * parameter, otherwise the function will return false. + */ +bool queue_try_peek(queue_t *q, void *data); + +// blocking queue access functions: + +/*! \brief Blocking add of value to queue + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \param data Pointer to value to be copied into the queue + * + * If the queue is full this function will block, until a removal happens on the + * queue + */ +void queue_add_blocking(queue_t *q, const void *data); + +/*! \brief Blocking remove entry from queue + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \param data Pointer to the location to receive the removed value + * + * If the queue is empty this function will block until a value is added. + */ +void queue_remove_blocking(queue_t *q, void *data); + +/*! \brief Blocking peek at next value to be removed from queue + * \ingroup queue + * + * \param q Pointer to a queue_t structure, used as a handle + * \param data Pointer to the location to receive the peeked value + * + * If the queue is empty function will block until a value is added + */ +void queue_peek_blocking(queue_t *q, void *data); + +#ifdef __cplusplus +} + +#endif + +#endif +#endif \ No newline at end of file diff --git a/src/jmutex.h b/src/jmutex.h new file mode 100644 index 0000000..47fa164 --- /dev/null +++ b/src/jmutex.h @@ -0,0 +1,23 @@ +#ifndef _J_MUTEX_H +#define _J_MUTEX_H + +#if defined(ARDUINO_ARCH_RP2040) +#include "pico/mutex.h" + +void test(){ + +} + +#elif defined(ARDUINO_ARCH_ESP32) + +#include "pthread.h" + +typedef pthread_mutex_t mutex_t + +inline void mutex_init(mutex_t *mtx) { pthread_mutex_init(mtx, NULL); } +inline void mutex_enter_blocking(mutex_t *mtx) { pthread_mutex_lock(mtx); } +inline void mutex_exit(mutex_t *mtx) { pthread_mutex_unlock(mtx); } + +#endif + +#endif \ No newline at end of file diff --git a/src/jqueue.h b/src/jqueue.h new file mode 100644 index 0000000..279fcf4 --- /dev/null +++ b/src/jqueue.h @@ -0,0 +1,13 @@ +#ifndef _J_QUEUE_H +#define _J_QUEUE_H + +#if defined(ARDUINO_ARCH_RP2040) + +#include "pico/util/queue.h" + +#elif defined(ARDUINO_ARCH_ESP32) + +#include "esp32/esp32_queue.h" + +#endif +#endif \ No newline at end of file