2024-01-08 19:00:53 -05:00

940 lines
24 KiB
C++

/**
* \file pros/apix.h
* \ingroup apix
*
* PROS Extended API header
*
* Contains additional declarations for use by advaned users of PROS. These
* functions do not typically have as much error handling or require deeper
* knowledge of real time operating systems.
*
* This file should not be modified by users, since it gets replaced whenever
* a kernel upgrade occurs.
*
* \copyright (c) 2017-2023, Purdue University ACM SIGBots.
* All rights reserved.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* \defgroup apix Extended API
* \note Also included in the Extended API is [LVGL.](https://lvgl.io/)
*/
#ifndef _PROS_API_EXTENDED_H_
#define _PROS_API_EXTENDED_H_
#include "api.h"
#include "pros/device.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wall"
#pragma GCC diagnostic pop
#include "pros/serial.h"
#ifdef __cplusplus
#include "pros/serial.hpp"
namespace pros::c {
extern "C" {
#endif
/**
* \ingroup apix
*/
/**
* \addtogroup apix
* @{
*/
/// \name RTOS Facilities
///@{
typedef void* queue_t;
typedef void* sem_t;
/**
* Unblocks a task in the Blocked state (e.g. waiting for a delay, on a
* semaphore, etc.).
*
* \param task
* The task to unblock
*
* \return True if the task was unblocked, false otherwise
*
* \b Example:
* \code
* task_t task = task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
* task_delay(1000);
* // in another task somewhere else, this will abort the task_delay bove:
* task_abort_delay(task);
* \endcode
*/
bool task_abort_delay(task_t task);
/**
* Notify a task when a target task is being deleted.
*
* \param target_task
* The task being watched for deletion
* \param task_to_notify
* The task to notify when target_task is deleted
* \param value
* The value to supply to task_notify_ext
* \param notify_action
* The action to supply to task_notify_ext
*
* \b Example:
* \code
* task_t task_to_delete = task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
* task_t task_to_notify = task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn2");
*
* task_notify_ext(task_to_notify, 0, NOTIFY_ACTION_INCREMENT, NULL);
*
* task_notify_when_deleting(task_to_delete, task_get_current(), 0, NOTIFY_ACTION_NONE);
* task_delete(task_to_delete);
* \endcode
*/
void task_notify_when_deleting(task_t target_task, task_t task_to_notify, uint32_t value,
notify_action_e_t notify_action);
/**
* Creates a recursive mutex which can be locked recursively by the owner.
*
* \return A newly created recursive mutex.
*
* \b Example:
* \code
* mutex_t mutex = mutex_recursive_create();
*
* void task_fn(void* param) {
* while(1) {
* mutex_recursive_take(mutex, 1000);
* // critical section
* mutex_recursive_give(mutex);
* task_delay(1000);
* }
* }
* task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
*
* \endcode
*/
mutex_t mutex_recursive_create(void);
/**
* Takes a recursive mutex.
*
* \param mutex
* A mutex handle created by mutex_recursive_create
* \param wait_time
* Amount of time to wait before timing out
*
* \return 1 if the mutex was obtained, 0 otherwise
*
* \b Example:
* \code
* mutex_t mutex = mutex_recursive_create();
*
* void task_fn(void* param) {
* while(1) {
* mutex_recursive_take(mutex, 1000);
* // critical section
* mutex_recursive_give(mutex);
* task_delay(1000);
* }
* }
* task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
*
* \endcode
*/
bool mutex_recursive_take(mutex_t mutex, uint32_t timeout);
/**
* Gives a recursive mutex.
*
* \param mutex
* A mutex handle created by mutex_recursive_create
*
* \return 1 if the mutex was obtained, 0 otherwise
*
* \b Example:
* \code
* mutex_t mutex = mutex_recursive_create();
*
* void task_fn(void* param) {
* while(1) {
* mutex_recursive_take(mutex, 1000);
* // critical section
* mutex_recursive_give(mutex);
* task_delay(1000);
* }
* }
* task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
*
* \endcode
*/
bool mutex_recursive_give(mutex_t mutex);
/**
* Returns a handle to the current owner of a mutex.
*
* \param mutex
* A mutex handle
*
* \return A handle to the current task that owns the mutex, or NULL if the
* mutex isn't owned.
*
* \b Example:
* \code
* mutex_t mutex = mutex_create();
*
* void task_fn(void* param) {
* while(1) {
* mutex_take(mutex, 1000);
* // critical section
* mutex_give(mutex);
* task_delay(1000);
* }
* }
* task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
*
* void opcontrol(void) {
* while (1) {
* if (joystick_get_digital(1, 7, JOY_UP)) {
* task_t owner = mutex_get_owner(mutex);
* if (owner != NULL) {
* printf("Mutex is owned by task %s", task_get_name(owner));
* } else {
* printf("Mutex is not owned");
* }
* }
* task_delay(20);
* }
* }
* \endcode
*/
task_t mutex_get_owner(mutex_t mutex);
/**
* Creates a counting sempahore.
*
* \param max_count
* The maximum count value that can be reached.
* \param init_count
* The initial count value assigned to the new semaphore.
*
* \return A newly created semaphore. If an error occurred, NULL will be
* returned and errno can be checked for hints as to why sem_create failed.
*
* \b Example:
* \code
* // Binary semaphore acts as a mutex
* sem_t sem = sem_create(1, 0);
*
* void task_fn(void* param) {
* while(1) {
* sem_take(sem, 1000);
* // critical section
* sem_give(sem);
* task_delay(1000);
* }
* }
* task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
*
* \endcode
*/
sem_t sem_create(uint32_t max_count, uint32_t init_count);
/**
* Deletes a semaphore (or binary semaphore)
*
* \param sem
* Semaphore to delete
*
* \b Example:
* \code
* // Binary semaphore acts as a mutex
* sem_t sem = sem_create(1, 0);
*
* void task_fn(void* param) {
* while(1) {
* sem_take(sem, 1000);
* // critical section
* sem_give(sem);
* task_delay(1000);
* }
* }
* task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
*
* void opcontrol(void) {
* while (1) {
* if (joystick_get_digital(1, 7, JOY_UP)) {
* // honestly this is a bad example because you should never
* // delete a semaphore like this
* sem_delete(sem);
* }
* task_delay(20);
* }
* }
*
* \endcode
*/
void sem_delete(sem_t sem);
/**
* Creates a binary semaphore.
*
* \return A newly created semaphore.
*
* \b Example:
* \code
* // Binary semaphore acts as a mutex
* sem_t sem = sem_binary_create();
*
* void task_fn(void* param) {
* while(1) {
* sem_take(sem, 1000);
* // critical section
* sem_give(sem);
* task_delay(1000);
* }
* }
* task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
*
* \endcode
*/
sem_t sem_binary_create(void);
/**
* Waits for the semaphore's value to be greater than 0. If the value is already
* greater than 0, this function immediately returns.
*
* \param sem
* Semaphore to wait on
* \param timeout
* Time to wait before the semaphore's becomes available. A timeout of 0
* can be used to poll the sempahore. TIMEOUT_MAX can be used to block
* indefinitely.
*
* \return True if the semaphore was successfully take, false otherwise. If
* false is returned, then errno is set with a hint about why the sempahore
* couldn't be taken.
*
* \b Example:
* \code
* // Binary semaphore acts as a mutex
* sem_t sem = sem_create(1, 0);
*
* void task_fn(void* param) {
* while(1) {
* if(!sem_wait(sem, 1000)) {
* printf("Failed to take semaphore");
* task_delay(1000);
* continue;
* }
* // critical section
* sem_give(sem);
* task_delay(1000);
* }
* }
* task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
*
* void opcontrol(void) {
* while (1) {
* if (sem_wait(sem, 0))) {
* printf("Semaphore is available");
* }
* task_delay(20);
* }
* }
* \endcode
*/
bool sem_wait(sem_t sem, uint32_t timeout);
/**
* Increments a semaphore's value.
*
* \param sem
* Semaphore to post
*
* \return True if the value was incremented, false otherwise. If false is
* returned, then errno is set with a hint about why the semaphore couldn't be
* taken.
*
* \b Example:
* \code
* // Binary semaphore acts as a mutex
* sem_t sem = sem_create(1, 0);
*
* void task_fn(void* param) {
* while(1) {
* sem_post(sem); // increments, mimicking to "claim"
* // critical section
* sem_give(sem);
* task_delay(1000);
* }
* }
* task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT,
* TASK_STACK_DEPTH_DEFAULT, "task_fn");
*
* \endcode
*/
bool sem_post(sem_t sem);
/**
* Returns the current value of the semaphore.
*
* \param sem
* A semaphore handle
*
* \return The current value of the semaphore (e.g. the number of resources
* available)
*
* \b Example of sem_get_count:
* \code
* // Binary semaphore acts as a mutex
* sem_t sem = sem_create(1, 0);
* printf("semaphore count: %d", sem_get_count(sem));
* // semaphore count: 0
* sem_take(sem, 1000);
* printf("semaphore count: %d", sem_get_count(sem));
* // semaphore count: 1
* sem_give(sem);
* printf("semaphore count: %d", sem_get_count(sem));
* // semaphore count: 0
*
* \endcode
*/
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
///@{
/**
* Registers a device in the given zero-indexed port
*
* Registers a device of the given type in the given port into the registry, if
* that type of device is detected to be plugged in to that port.
*
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - The given value is not within the range of V5 ports (0-20), or a
* a different device than specified is plugged in.
* EADDRINUSE - The port is already registered to another device.
*
* \param port
* The port number to register the device
* \param device
* The type of device to register
*
* \return 1 upon success, PROS_ERR upon failure
*
* \b Example:
* \code
* void opcontrol(void) {
* registry_bind_port(1, E_DEVICE_MOTOR);
* }
* \endcode
*/
int registry_bind_port(uint8_t port, v5_device_e_t device_type);
/**
* Deregisters a devices from the given zero-indexed port
*
* Removes the device registed in the given port, if there is one.
*
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - The given value is not within the range of V5 ports (0-20).
*
* \param port
* The port number to deregister
*
* \return 1 upon success, PROS_ERR upon failure
*
* \b Example:
* \code
* void opcontrol(void) {
* registry_bind_port(1, E_DEVICE_MOTOR);
* registry_unbind_port(1);
* }
* \endcode
*/
int registry_unbind_port(uint8_t port);
/**
* Returns the type of device registered to the zero-indexed port.
*
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - The given value is not within the range of V5 ports (0-20).
*
* \param port
* The V5 port number from 0-20
*
* \return The type of device that is registered into the port (NOT what is
* plugged in)
*
* \b Example:
* \code
* void opcontrol(void) {
* registry_bind_port(1, E_DEVICE_MOTOR);
* printf("port 1 is registered to a motor: %d", registry_get_bound_type(1) == E_DEVICE_MOTOR);
* }
* \endcode
*/
v5_device_e_t registry_get_bound_type(uint8_t port);
/**
* Returns the type of the device plugged into the zero-indexed port.
*
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - The given value is not within the range of V5 ports (0-20).
*
* \param port
* The V5 port number from 0-20
*
* \return The type of device that is plugged into the port (NOT what is
* registered)
*
* \b Example:
* \code
* void opcontrol(void) {
* registry_bind_port(1, E_DEVICE_MOTOR);
* printf("port 1 is registered to a motor: %d", registry_get_plugged_type(1) == E_DEVICE_MOTOR);
* }
* \endcode
*/
v5_device_e_t registry_get_plugged_type(uint8_t port);
///@}
/// \name Filesystem
///@{
/**
* Control settings of the serial driver.
*
* \param action
* An action to perform on the serial driver. See the SERCTL_* macros for
* details on the different actions.
* \param extra_arg
* An argument to pass in based on the action
*
* \b Example:
* \code
* void opcontrol(void) {
* serctl(SERCTL_SET_BAUDRATE, (void*) 9600);
* }
*/
int32_t serctl(const uint32_t action, void* const extra_arg);
/*
* Control settings of the microSD card driver.
*
* \param action
* An action to perform on the microSD card driver. See the USDCTL_* macros
* for details on the different actions.
* \param extra_arg
* An argument to pass in based on the action
*/
// Not yet implemented
// int32_t usdctl(const uint32_t action, void* const extra_arg);
/**
* Control settings of the way the file's driver treats the file
*
* \param file
* A valid file descriptor number
* \param action
* An action to perform on the file's driver. See the *CTL_* macros for
* details on the different actions. Note that the action passed in must
* match the correct driver (e.g. don't perform a SERCTL_* action on a
* microSD card file)
* \param extra_arg
* An argument to pass in based on the action
*
* \b Example:
* \code
* void opcontrol(void) {
* int32_t fd = open("serial", O_RDWR);
* fdctl(fd, SERCTL_SET_BAUDRATE, (void*) 9600);
* }
* \endcode
*/
int32_t fdctl(int file, const uint32_t action, void* const extra_arg);
/**
* Sets the reverse flag for the motor.
*
* This will invert its movements and the values returned for its position.
*
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - The given value is not within the range of V5 ports (1-21).
* ENODEV - The port cannot be configured as a motor
*
* \param port
* The V5 port number from 1-21
* \param reverse
* True reverses the motor, false is default
*
* \return 1 if the operation was successful or PROS_ERR if the operation
* failed, setting errno.
*
* \b Example
* \code
* void autonomous() {
* motor_set_reversed(1, true);
* printf("Is this motor reversed? %d\n", motor_is_reversed(1));
* }
* \endcode
*/
int32_t motor_set_reversed(int8_t port, const bool reverse);
/**
* Gets the operation direction of the motor as set by the user.
*
* This function uses the following values of errno when an error state is
* reached:
* ENXIO - The given value is not within the range of V5 ports (1-21).
* ENODEV - The port cannot be configured as a motor
*
* \param port
* The V5 port number from 1-21
*
* \return 1 if the motor has been reversed and 0 if the motor was not reversed,
* or PROS_ERR if the operation failed, setting errno.
*
* \b Example
* \code
* void initialize() {
* printf("Is the motor reversed? %d\n", motor_is_reversed(1));
* // Prints "Is the motor reversed? 0"
* }
* \endcode
*/
int32_t motor_is_reversed(int8_t port);
/**
* Action macro to pass into serctl or fdctl that activates the stream
* identifier.
*
* When used with serctl, the extra argument must be the little endian
* representation of the stream identifier (e.g. "sout" -> 0x74756f73)
*
*/
#define SERCTL_ACTIVATE 10
/**
* Action macro to pass into serctl or fdctl that deactivates the stream
* identifier.
*
* When used with serctl, the extra argument must be the little endian
* representation of the stream identifier (e.g. "sout" -> 0x74756f73)
*
*/
#define SERCTL_DEACTIVATE 11
/**
* Action macro to pass into fdctl that enables blocking writes for the file
*
* The extra argument is not used with this action, provide any value (e.g.
* NULL) instead
*
*/
#define SERCTL_BLKWRITE 12
/**
* Action macro to pass into fdctl that makes writes non-blocking for the file
*
* The extra argument is not used with this action, provide any value (e.g.
* NULL) instead
*
*/
#define SERCTL_NOBLKWRITE 13
/**
* Action macro to pass into serctl that enables advanced stream multiplexing
* capabilities
*
* The extra argument is not used with this action, provide any value (e.g.
* NULL) instead
*
*/
#define SERCTL_ENABLE_COBS 14
/**
* Action macro to pass into serctl that disables advanced stream multiplexing
* capabilities
*
* The extra argument is not used with this action, provide any value (e.g.
* NULL) instead
*
*/
#define SERCTL_DISABLE_COBS 15
/**
* Action macro to check if there is data available from the Generic Serial
* Device
*
*/
#define DEVCTL_FIONREAD 16
/**
* Action macro to check if there is space available in the Generic Serial
* Device's output buffer
*
*/
#define DEVCTL_FIONWRITE 18
/**
* Action macro to set the Generic Serial Device's baudrate.
*
* The extra argument is the baudrate.
*/
#define DEVCTL_SET_BAUDRATE 17
///@}
///@}
#ifdef __cplusplus
}
}
#endif
#endif // _PROS_API_EXTENDED_H_