diff --git a/include/kapi.h b/include/kapi.h index 07a10fe5..72dc36f0 100644 --- a/include/kapi.h +++ b/include/kapi.h @@ -29,7 +29,7 @@ extern "C" { #define task_fn_t pros::task_fn_t #define mutex_t pros::mutex_t #define sem_t pros::c::sem_t -#define queue_t pros::c::queue_t +#define queue_t pros::queue_t #endif #define KDBG_FILENO 3 diff --git a/include/pros/apix.h b/include/pros/apix.h index 165c0541..f0510137 100644 --- a/include/pros/apix.h +++ b/include/pros/apix.h @@ -50,7 +50,6 @@ extern "C" { /// \name RTOS Facilities ///@{ -typedef void* queue_t; typedef void* sem_t; /** @@ -418,225 +417,6 @@ bool sem_post(sem_t sem); */ uint32_t sem_get_count(sem_t sem); -/** - * Creates a queue. - * - * \param length - * The maximum number of items that the queue can contain. - * \param item_size - * The number of bytes each item in the queue will require. - * - * \return A handle to a newly created queue, or NULL if the queue cannot be - * created. - * - * \b Example: - * \code - * void opcontrol(void) { - * queue_t queue = queue_create(10, sizeof(int)); - * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - * queue_prepend(queue, item, 1000); - * queue_append(queue, item, 1000); - * printf("queue length: %d", queue_get_length(queue)); - * } - * \endcode - */ -queue_t queue_create(uint32_t length, uint32_t item_size); - -/** - * Posts an item to the front of a queue. The item is queued by copy, not by - * reference. - * - * \param queue - * The queue handle - * \param item - * A pointer to the item that will be placed on the queue. - * \param timeout - * Time to wait for space to become available. A timeout of 0 can be used - * to attempt to post without blocking. TIMEOUT_MAX can be used to block - * indefinitely. - * - * \return True if the item was preprended, false otherwise. - * - * \b Example: - * \code - * void opcontrol(void) { - * queue_t queue = queue_create(10, sizeof(int)); - * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - * queue_prepend(queue, item, 1000); - * queue_append(queue, item, 1000); - * printf("queue length: %d", queue_get_length(queue)); - * } - */ -bool queue_prepend(queue_t queue, const void* item, uint32_t timeout); - -/** - * Posts an item to the end of a queue. The item is queued by copy, not by - * reference. - * - * \param queue - * The queue handle - * \param item - * A pointer to the item that will be placed on the queue. - * \param timeout - * Time to wait for space to become available. A timeout of 0 can be used - * to attempt to post without blocking. TIMEOUT_MAX can be used to block - * indefinitely. - * - * \return True if the item was preprended, false otherwise. - * - * \b Example: - * \code - * void opcontrol(void) { - * queue_t queue = queue_create(10, sizeof(int)); - * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - * queue_prepend(queue, item, 1000); - * queue_append(queue, item, 1000); - * printf("queue length: %d", queue_get_length(queue)); - * } - * \endcode - */ -bool queue_append(queue_t queue, const void* item, uint32_t timeout); - -/** - * Receive an item from a queue without removing the item from the queue. - * - * \param queue - * The queue handle - * \param buffer - * Pointer to a buffer to which the received item will be copied - * \param timeout - * The maximum amount of time the task should block waiting for an item to receive should the queue be empty at - * the time of the call. TIMEOUT_MAX can be used to block indefinitely. - * - * \return True if an item was copied into the buffer, false otherwise. - * - * \b Example: - * \code - * void opcontrol(void) { - * queue_t queue = queue_create(10, sizeof(int)); - * char* item = "Hello! this is a test"; - * queue_prepend(queue, item, 1000); - * queue_append(queue, item, 1000); - * char* recv = malloc(sizeof("Hello! this is a test")); - * queue_peek(queue, recv, 1000); - * printf("Queue: %s", recv); - * free(recv); - * } - * \endcode - */ -bool queue_peek(queue_t queue, void* const buffer, uint32_t timeout); - -/** - * Receive an item from the queue. - * - * \param queue - * The queue handle - * \param buffer - * Pointer to a buffer to which the received item will be copied - * \param timeout - * The maximum amount of time the task should block - * waiting for an item to receive should the queue be empty at the time - * of the call. queue_recv() will return immediately if timeout - * is zero and the queue is empty. - * - * \return True if an item was copied into the buffer, false otherwise. - * - * \b Example: - * \code - * void opcontrol(void) { - * queue_t queue = queue_create(10, sizeof(int)); - * char* item = "Hello! this is a test"; - * queue_prepend(queue, item, 1000); - * queue_append(queue, item, 1000); - * char* recv = malloc(sizeof("Hello! this is a test")); - * queue_recv(queue, recv, 1000); - * printf("Queue: %s", recv); - * free(recv); - * } - * \endcode - */ -bool queue_recv(queue_t queue, void* const buffer, uint32_t timeout); - -/** - * Return the number of messages stored in a queue. - * - * \param queue - * The queue handle. - * - * \return The number of messages available in the queue. - * - * \b Example: - * \code - * void opcontrol(void) { - * queue_t queue = queue_create(10, sizeof(int)); - * - * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - * queue_prepend(queue, item, 1000); - * queue_append(queue, item, 1000); - * printf("queue waiting: %d", queue_get_waiting(queue)); - * } - * \endcode - */ -uint32_t queue_get_waiting(const queue_t queue); - -/** - * Return the number of spaces left in a queue. - * - * \param queue - * The queue handle. - * - * \return The number of spaces available in the queue. - * - * \b Example: - * \code - * void opcontrol(void) { - * queue_t queue = queue_create(10, sizeof(int)); - * - * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - * queue_prepend(queue, item, 1000); - * queue_append(queue, item, 1000); - * printf("queue available: %d", queue_get_available(queue)); - * } - * \endcode - */ -uint32_t queue_get_available(const queue_t queue); - -/** - * Delete a queue. - * - * \param queue - * Queue handle to delete - * - * \b Example: - * \code - * void opcontrol(void) { - * queue_t queue = queue_create(10, sizeof(int)); - * queue_delete(queue); - * } - * \endcode - */ -void queue_delete(queue_t queue); - -/** - * Resets a queue to an empty state - * - * \param queue - * Queue handle to reset - * - * \b Example: - * \code - * void opcontrol(void) { - * queue_t queue = queue_create(10, sizeof(int)); - * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - * queue_prepend(queue, item, 1000); - * queue_append(queue, item, 1000); - * queue_reset(queue); - * } - * \endcode - */ -void queue_reset(queue_t queue); - -///@} /// \name Device Registration ///@{ diff --git a/include/pros/rtos.h b/include/pros/rtos.h index d6b9be48..85df6055 100644 --- a/include/pros/rtos.h +++ b/include/pros/rtos.h @@ -171,6 +171,9 @@ typedef enum { /// @} Name: Simple enum names +typedef void* queue_t; + + /// \name Typedefs /** @@ -822,6 +825,226 @@ uint32_t task_notify_take(bool clear_on_exit, uint32_t timeout); */ bool task_notify_clear(task_t task); +/** + * Creates a queue. + * + * \param length + * The maximum number of items that the queue can contain. + * \param item_size + * The number of bytes each item in the queue will require. + * + * \return A handle to a newly created queue, or NULL if the queue cannot be + * created. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue length: %d", queue_get_length(queue)); + * } + * \endcode + */ +queue_t queue_create(uint32_t length, uint32_t item_size); + +/** + * Posts an item to the front of a queue. The item is queued by copy, not by + * reference. + * + * \param queue + * The queue handle + * \param item + * A pointer to the item that will be placed on the queue. + * \param timeout + * Time to wait for space to become available. A timeout of 0 can be used + * to attempt to post without blocking. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the item was preprended, false otherwise. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue length: %d", queue_get_length(queue)); + * } + */ +bool queue_prepend(queue_t queue, const void* item, uint32_t timeout); + +/** + * Posts an item to the end of a queue. The item is queued by copy, not by + * reference. + * + * \param queue + * The queue handle + * \param item + * A pointer to the item that will be placed on the queue. + * \param timeout + * Time to wait for space to become available. A timeout of 0 can be used + * to attempt to post without blocking. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the item was preprended, false otherwise. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue length: %d", queue_get_length(queue)); + * } + * \endcode + */ +bool queue_append(queue_t queue, const void* item, uint32_t timeout); + +/** + * Receive an item from a queue without removing the item from the queue. + * + * \param queue + * The queue handle + * \param buffer + * Pointer to a buffer to which the received item will be copied + * \param timeout + * The maximum amount of time the task should block waiting for an item to receive should the queue be empty at + * the time of the call. TIMEOUT_MAX can be used to block indefinitely. + * + * \return True if an item was copied into the buffer, false otherwise. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * char* item = "Hello! this is a test"; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * char* recv = malloc(sizeof("Hello! this is a test")); + * queue_peek(queue, recv, 1000); + * printf("Queue: %s", recv); + * free(recv); + * } + * \endcode + */ +bool queue_peek(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Receive an item from the queue. + * + * \param queue + * The queue handle + * \param buffer + * Pointer to a buffer to which the received item will be copied + * \param timeout + * The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. queue_recv() will return immediately if timeout + * is zero and the queue is empty. + * + * \return True if an item was copied into the buffer, false otherwise. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * char* item = "Hello! this is a test"; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * char* recv = malloc(sizeof("Hello! this is a test")); + * queue_recv(queue, recv, 1000); + * printf("Queue: %s", recv); + * free(recv); + * } + * \endcode + */ +bool queue_recv(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Return the number of messages stored in a queue. + * + * \param queue + * The queue handle. + * + * \return The number of messages available in the queue. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue waiting: %d", queue_get_waiting(queue)); + * } + * \endcode + */ +uint32_t queue_get_waiting(const queue_t queue); + +/** + * Return the number of spaces left in a queue. + * + * \param queue + * The queue handle. + * + * \return The number of spaces available in the queue. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue available: %d", queue_get_available(queue)); + * } + * \endcode + */ +uint32_t queue_get_available(const queue_t queue); + +/** + * Delete a queue. + * + * \param queue + * Queue handle to delete + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * queue_delete(queue); + * } + * \endcode + */ +void queue_delete(queue_t queue); + +/** + * Resets a queue to an empty state + * + * \param queue + * Queue handle to reset + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * queue_reset(queue); + * } + * \endcode + */ +void queue_reset(queue_t queue); + +///@} + /** * Creates a mutex. * diff --git a/include/pros/rtos.hpp b/include/pros/rtos.hpp index f02495c2..99ac1294 100644 --- a/include/pros/rtos.hpp +++ b/include/pros/rtos.hpp @@ -820,6 +820,60 @@ struct Clock { static time_point now(); }; +template +requires std::is_trivially_copyable_v +class Queue { + queue_t queue; + + public: + explicit Queue(uint32_t length) : queue(pros::c::queue_create(length, sizeof(T))) {}; + + Queue() = delete; + + Queue(const Queue&) = default; + Queue(Queue&&) = delete; + + Queue& operator=(const Queue&) = default; + Queue& operator=(Queue&&) = delete; + + ~Queue() { + pros::c::queue_delete(queue); + } + + bool prepend(T* item, uint32_t timeout = TIMEOUT_MAX) { + return pros::c::queue_prepend(queue, item, timeout); + } + + bool append(T* item, uint32_t timeout = TIMEOUT_MAX) { + return pros::c::queue_append(queue, item, timeout); + } + + bool send(T* item, uint32_t timeout = TIMEOUT_MAX) { + return pros::c::queue_append(queue, item, timeout); // same as append + } + + bool peek(T* buffer, uint32_t timeout = TIMEOUT_MAX) { + return pros::c::queue_peek(queue, buffer, timeout); + } + + bool receive(T* buffer, uint32_t timeout = TIMEOUT_MAX) { + return pros::c::queue_recv(queue, buffer, timeout); + } + + uint32_t get_waiting() { + return pros::c::queue_get_waiting(queue); + } + + uint32_t get_available() { + return pros::c::queue_get_available(queue); + } + + void reset() { + pros::c::queue_reset(queue); + } + +}; + class Mutex { std::shared_ptr> mutex; diff --git a/src/system/unwind.c b/src/system/unwind.c index 9ac6c180..7eeafc7b 100644 --- a/src/system/unwind.c +++ b/src/system/unwind.c @@ -67,7 +67,7 @@ static inline void print_phase2_vrs(struct phase2_vrs* vrs) { "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc"}; for (size_t i = 0; i < 16; i++) { fprintf(stderr, "%3s: 0x%08x ", registers[i], vrs->core.r[i]); - if (i % 8 == 7) printf("\n"); + if (i % 4 == 3) printf("\n"); } fputs("\n", stderr); } @@ -148,6 +148,12 @@ void report_data_abort(uint32_t _sp) { fprintf(stderr, "CURRENT TASK: %.32s\n", pxCurrentTCB->pcTaskName); } + struct mallinfo info = mallinfo(); + fprintf(stderr, "HEAP USED: %d bytes\n", info.uordblks); + if (pxCurrentTCB) { + fprintf(stderr, "STACK REMAINING AT ABORT: %lu bytes\n", vrs.core.r[R_SP] - (uint32_t)pxCurrentTCB->pxStack); + } + fputs("REGISTERS AT ABORT\n", stderr); print_phase2_vrs(&vrs); @@ -155,12 +161,6 @@ void report_data_abort(uint32_t _sp) { fprintf(stderr, "\t%p\n", (void*)vrs.core.r[R_PC]); __gnu_Unwind_Backtrace(trace_fn, NULL, &vrs); fputs("END OF TRACE\n", stderr); - - struct mallinfo info = mallinfo(); - fprintf(stderr, "HEAP USED: %d bytes\n", info.uordblks); - if (pxCurrentTCB) { - fprintf(stderr, "STACK REMAINING AT ABORT: %lu bytes\n", vrs.core.r[R_SP] - (uint32_t)pxCurrentTCB->pxStack); - } } /******************************************************************************/