initial
This commit is contained in:
commit
ef391b9720
6 changed files with 382 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.vscode
|
9
library.properties
Normal file
9
library.properties
Normal file
|
@ -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
|
134
src/esp32/esp32_queue.c
Normal file
134
src/esp32/esp32_queue.c
Normal file
|
@ -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
|
202
src/esp32/esp32_queue.h
Normal file
202
src/esp32/esp32_queue.h
Normal file
|
@ -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
|
23
src/jmutex.h
Normal file
23
src/jmutex.h
Normal file
|
@ -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
|
13
src/jqueue.h
Normal file
13
src/jqueue.h
Normal file
|
@ -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
|
Loading…
Reference in a new issue