From 29cd3cd731d27e8a56d2c29e6eb7df670bab0471 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 3 May 2025 14:36:06 -0700 Subject: [PATCH 01/41] rename v5_device_e_t to V5Device --- include/pros/{apix.h => apix.hpp} | 35 ++++++----- include/vdml/registry.h | 99 ------------------------------- include/vdml/registry.hpp | 48 +++++++++++++++ include/vdml/vdml.h | 14 ++--- src/devices/registry.c | 20 +++---- src/devices/vdml.c | 2 +- 6 files changed, 83 insertions(+), 135 deletions(-) rename include/pros/{apix.h => apix.hpp} (95%) delete mode 100644 include/vdml/registry.h create mode 100644 include/vdml/registry.hpp diff --git a/include/pros/apix.h b/include/pros/apix.hpp similarity index 95% rename from include/pros/apix.h rename to include/pros/apix.hpp index 9653353f..c430d073 100644 --- a/include/pros/apix.h +++ b/include/pros/apix.hpp @@ -570,22 +570,21 @@ void queue_reset(queue_t queue); * This list contains all current V5 Devices, and mirrors V5_DeviceType from the * api. */ -typedef enum v5_device_e { - E_DEVICE_NONE = 0, ///< No device is plugged into the port - E_DEVICE_MOTOR = 2, ///< A motor is plugged into the port - E_DEVICE_ROTATION = 4, ///< A rotation sensor is plugged into the port - E_DEVICE_IMU = 6, ///< An inertial sensor is plugged into the port - E_DEVICE_DISTANCE = 7, ///< A distance sensor is plugged into the port - E_DEVICE_RADIO = 8, ///< A radio is plugged into the port - E_DEVICE_VISION = 11, ///< A vision sensor is plugged into the port - E_DEVICE_ADI = 12, ///< This port is an ADI expander - E_DEVICE_OPTICAL = 16, ///< An optical sensor is plugged into the port - E_DEVICE_GPS = 20, ///< A GPS sensor is plugged into the port - E_DEVICE_AIVISION = 29, ///< An AI Vision sensor is plugged into the port - E_DEVICE_SERIAL = 129, ///< A serial device is plugged into the port - E_DEVICE_GENERIC __attribute__((deprecated("use E_DEVICE_SERIAL instead"))) = E_DEVICE_SERIAL, +enum class V5Device { + E_DEVICE_NONE = 0, ///< No device is plugged into the port + E_DEVICE_MOTOR = 2, ///< A motor is plugged into the port + E_DEVICE_ROTATION = 4, ///< A rotation sensor is plugged into the port + E_DEVICE_IMU = 6, ///< An inertial sensor is plugged into the port + E_DEVICE_DISTANCE = 7, ///< A distance sensor is plugged into the port + E_DEVICE_RADIO = 8, ///< A radio is plugged into the port + E_DEVICE_VISION = 11, ///< A vision sensor is plugged into the port + E_DEVICE_ADI = 12, ///< This port is an ADI expander + E_DEVICE_OPTICAL = 16, ///< An optical sensor is plugged into the port + E_DEVICE_GPS = 20, ///< A GPS sensor is plugged into the port + E_DEVICE_AIVISION = 29, ///< An AI Vision sensor is plugged into the port + E_DEVICE_SERIAL = 129, ///< A serial device is plugged into the port E_DEVICE_UNDEFINED = 255 ///< The device type is not defined, or is not a valid device -} v5_device_e_t; +}; /** * Registers a device in the given zero-indexed port @@ -613,7 +612,7 @@ typedef enum v5_device_e { * } * \endcode */ -int registry_bind_port(uint8_t port, v5_device_e_t device_type); +int registry_bind_port(uint8_t port, V5Device device_type); /** * Deregisters a devices from the given zero-indexed port @@ -660,7 +659,7 @@ int registry_unbind_port(uint8_t port); * } * \endcode */ -v5_device_e_t registry_get_bound_type(uint8_t port); +V5Device registry_get_bound_type(uint8_t port); /** * Returns the type of the device plugged into the zero-indexed port. @@ -683,7 +682,7 @@ v5_device_e_t registry_get_bound_type(uint8_t port); * } * \endcode */ -v5_device_e_t registry_get_plugged_type(uint8_t port); +V5Device registry_get_plugged_type(uint8_t port); ///@} diff --git a/include/vdml/registry.h b/include/vdml/registry.h deleted file mode 100644 index 9856fa7f..00000000 --- a/include/vdml/registry.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * \file vdml/registry.h - * - * This file contains the standard header info for the VDML (Vex Data Management - * Layer) registry. - * - * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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/. - */ - -#pragma once - -#include "pros/apix.h" -#include "v5_api_patched.h" -#include "vdml/vdml.h" - -#ifdef __cplusplus - #define v5_device_e_t pros::c::v5_device_e_t -extern "C" { -#endif - -typedef struct { - v5_device_e_t device_type; - V5_DeviceT device_info; - uint8_t pad[128]; // 16 bytes in adi_data_s_t times 8 ADI Ports = 128 -} v5_smart_device_s_t; - -/* - * Detects the devices that are plugged in. - * - * Pulls the type names of plugged-in devices and stores them in the buffer - * registry_types. - */ -void registry_update_types(); - -/* - * Returns the information on the device registered to the 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 (1-21). - * - * \param port - * The V5 port number from 1-21 - * - * \return A struct containing the device type and the info needed for api - * functions - */ -v5_smart_device_s_t* registry_get_device(uint8_t port); - -/* - * Returns the information on the device registered to the 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 (1-21). - * - * \param port - * The V5 port number from 0-32 - * - * \return A struct containing the device type and the info needed for api - * functions - */ -v5_smart_device_s_t* registry_get_device_internal(uint8_t port); - -/* - * Checks whether there is a discrepancy between the binding of the port and - * what is actually plugged in. - * - * If a device is plugged in but not registered, registers the port. - * If a device is not plugged in and a device is registered, warns the user. - * If one type of device is registered but another is plugged in, warns 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). - * - * \param port - * The V5 port number from 1-21 - * \param expected_t - * The expected type (i.e., the type of function being called. If - * E_DEVICE_NONE, indicates that background processing is calling this, - * and a mismatch will only occur if there is an actual discrepancy - * between what is registered and what is plugged in. - * - * \return 0 if the device registered matches the device plugged and the - * expected device matches both of those or is E_DEVICE_NONE, 1 if the - * registered device is not plugged in, and 2 if there is a mismatch. PROS_ERR - * on exception. - */ -int32_t registry_validate_binding(uint8_t port, v5_device_e_t expected_t); - -#ifdef __cplusplus -} - #undef v5_device_e_t -#endif diff --git a/include/vdml/registry.hpp b/include/vdml/registry.hpp new file mode 100644 index 00000000..64109dee --- /dev/null +++ b/include/vdml/registry.hpp @@ -0,0 +1,48 @@ +/** + * \file vdml/registry.h + * + * This file contains the standard header info for the VDML (Vex Data Management + * Layer) registry. + * + * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. + * + * 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/. + */ + +#pragma once + +#include "pros/apix.h" +#include "v5_api_patched.h" + +typedef struct { + pros::c::V5Device device_type; + V5_DeviceT device_info; + uint8_t pad[128]; // 16 bytes in adi_data_s_t times 8 ADI Ports = 128 +} v5_smart_device_s_t; + +/* + * Detects the devices that are plugged in. + * + * Pulls the type names of plugged-in devices and stores them in the buffer + * registry_types. + */ +void registry_update_types(); + +/* + * Returns the information on the device registered to the 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 (1-21). + * + * \param port + * The V5 port number from 1-21 + * + * \return A struct containing the device type and the info needed for api + * functions + */ +v5_smart_device_s_t* registry_get_device(uint8_t port); + +v5_smart_device_s_t* registry_get_device_internal(uint8_t port); diff --git a/include/vdml/vdml.h b/include/vdml/vdml.h index c10006d5..2795eff1 100644 --- a/include/vdml/vdml.h +++ b/include/vdml/vdml.h @@ -19,7 +19,7 @@ #include #ifdef __cplusplus - #define v5_device_e_t pros::c::v5_device_e_t + #define V5Device pros::c::V5Device #endif #ifdef __cplusplus @@ -45,7 +45,7 @@ extern "C" { * \param port * The V5 port number from 0-20 * \param device_type - * The v5_device_e_t that the port is configured as + * The V5Device that the port is configured as * \param error_code * The error code that return if error checking failed */ @@ -66,7 +66,7 @@ extern "C" { * \param port * The V5 port number from 0-20 * \param device_type - * The v5_device_e_t that the port is configured as + * The V5Device that the port is configured as */ #define claim_port_i(port, device_type) claim_port(port, device_type, PROS_ERR) @@ -77,7 +77,7 @@ extern "C" { * \param port * The V5 port number from 0-20 * \param device_type - * The v5_device_e_t that the port is configured as + * The V5Device that the port is configured as */ #define claim_port_f(port, device_type) claim_port(port, device_type, PROS_ERR_F) @@ -93,12 +93,12 @@ extern "C" { * \param port * The V5 port number from 0-20 * \param device_type - * The v5_device_e_t that the port is configured as + * The V5Device that the port is configured as * * \return 1 if the operation was successful or 0 if the operation * failed, setting errno. */ -int32_t claim_port_try(uint8_t port, v5_device_e_t type); +int32_t claim_port_try(uint8_t port, V5Device type); /** * Macro that release the mutex for the given port and sets errno to 0 if the @@ -241,5 +241,5 @@ int internal_port_mutex_give(uint8_t port); #ifdef __cplusplus } - #undef v5_device_e_t + #undef V5Device #endif diff --git a/src/devices/registry.c b/src/devices/registry.c index 69b0c29a..88ebb127 100644 --- a/src/devices/registry.c +++ b/src/devices/registry.c @@ -31,7 +31,7 @@ void registry_init() { kprint("[VDML][INFO]Initializing registry\n"); registry_update_types(); for (i = 0; i < NUM_V5_PORTS; i++) { - registry[i].device_type = (v5_device_e_t)registry_types[i]; + registry[i].device_type = (V5Device)registry_types[i]; registry[i].device_info = vexDeviceGetByIndex(i); if (registry[i].device_type != E_DEVICE_NONE) { kprintf("[VDML][INFO]Register device in port %d", i + 1); @@ -44,7 +44,7 @@ void registry_update_types() { vexDeviceGetStatus(registry_types); } -int registry_bind_port(uint8_t port, v5_device_e_t device_type) { +int registry_bind_port(uint8_t port, V5Device device_type) { if (!VALIDATE_PORT_NO(port)) { kprintf("[VDML][ERROR]Registration: Invalid port number %d\n", port + 1); errno = ENXIO; @@ -55,8 +55,8 @@ int registry_bind_port(uint8_t port, v5_device_e_t device_type) { errno = EADDRINUSE; return PROS_ERR; } - if ((v5_device_e_t)registry_types[port] != device_type - && (v5_device_e_t)registry_types[port] != E_DEVICE_NONE) { + if ((V5Device)registry_types[port] != device_type + && (V5Device)registry_types[port] != E_DEVICE_NONE) { kprintf("[VDML][ERROR]Registration: Device mismatch in port %d\n", port + 1); errno = EADDRINUSE; return PROS_ERR; @@ -95,7 +95,7 @@ v5_smart_device_s_t* registry_get_device_internal(uint8_t port) { return ®istry[port]; } -v5_device_e_t registry_get_bound_type(uint8_t port) { +V5Device registry_get_bound_type(uint8_t port) { if (!VALIDATE_PORT_NO(port)) { errno = ENXIO; return E_DEVICE_UNDEFINED; @@ -103,23 +103,23 @@ v5_device_e_t registry_get_bound_type(uint8_t port) { return registry[port].device_type; } -v5_device_e_t registry_get_plugged_type(uint8_t port) { +V5Device registry_get_plugged_type(uint8_t port) { if (!VALIDATE_PORT_NO(port)) { errno = ENXIO; return -1; } - return (v5_device_e_t)registry_types[port]; + return (V5Device)registry_types[port]; } -int32_t registry_validate_binding(uint8_t port, v5_device_e_t expected_t) { +int32_t registry_validate_binding(uint8_t port, V5Device expected_t) { if (!VALIDATE_PORT_NO(port)) { errno = ENXIO; return PROS_ERR; } // Get the registered and plugged types - v5_device_e_t registered_t = registry_get_bound_type(port); - v5_device_e_t actual_t = registry_get_plugged_type(port); + V5Device registered_t = registry_get_bound_type(port); + V5Device actual_t = registry_get_plugged_type(port); // Auto register the port if needed if (registered_t == E_DEVICE_NONE && actual_t != E_DEVICE_NONE) { diff --git a/src/devices/vdml.c b/src/devices/vdml.c index 083f15da..6f2b6b2a 100644 --- a/src/devices/vdml.c +++ b/src/devices/vdml.c @@ -28,7 +28,7 @@ int32_t port_errors; extern void registry_init(); extern void port_mutex_init(); -int32_t claim_port_try(uint8_t port, v5_device_e_t type) { +int32_t claim_port_try(uint8_t port, V5Device type) { if (!VALIDATE_PORT_NO(port)) { errno = ENXIO; return 0; From 915f005979902ba8f71462d4962049ed172f3e3e Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 3 May 2025 15:15:28 -0700 Subject: [PATCH 02/41] start removing old vdml and registry --- include/kapi.h | 2 +- include/pros/apix.hpp | 127 ------------------ include/vdml/port.h | 31 ----- include/vdml/registry.hpp | 48 ------- include/vdml/vdml.h | 245 ---------------------------------- src/devices/screen.cpp | 149 --------------------- src/devices/vdml.c | 268 -------------------------------------- src/devices/vdml.cpp | 3 + src/devices/vdml.hpp | 23 ++++ src/devices/vdml_usd.c | 53 -------- 10 files changed, 27 insertions(+), 922 deletions(-) delete mode 100644 include/vdml/port.h delete mode 100644 include/vdml/registry.hpp delete mode 100644 include/vdml/vdml.h delete mode 100644 src/devices/screen.cpp delete mode 100644 src/devices/vdml.c create mode 100644 src/devices/vdml.cpp create mode 100644 src/devices/vdml.hpp delete mode 100644 src/devices/vdml_usd.c diff --git a/include/kapi.h b/include/kapi.h index 0993339a..c86b3780 100644 --- a/include/kapi.h +++ b/include/kapi.h @@ -19,7 +19,7 @@ #pragma once #include "api.h" -#include "pros/apix.h" +#include "pros/apix.hpp" #include "rtos/FreeRTOS.h" #include "rtos/stream_buffer.h" diff --git a/include/pros/apix.hpp b/include/pros/apix.hpp index c430d073..00bc468d 100644 --- a/include/pros/apix.hpp +++ b/include/pros/apix.hpp @@ -559,133 +559,6 @@ void queue_reset(queue_t queue); ///@} -/// \name Device Registration -///@{ - -/** - * \enum v5_device_e - * \brief - * List of possible v5 devices - * - * This list contains all current V5 Devices, and mirrors V5_DeviceType from the - * api. - */ -enum class V5Device { - E_DEVICE_NONE = 0, ///< No device is plugged into the port - E_DEVICE_MOTOR = 2, ///< A motor is plugged into the port - E_DEVICE_ROTATION = 4, ///< A rotation sensor is plugged into the port - E_DEVICE_IMU = 6, ///< An inertial sensor is plugged into the port - E_DEVICE_DISTANCE = 7, ///< A distance sensor is plugged into the port - E_DEVICE_RADIO = 8, ///< A radio is plugged into the port - E_DEVICE_VISION = 11, ///< A vision sensor is plugged into the port - E_DEVICE_ADI = 12, ///< This port is an ADI expander - E_DEVICE_OPTICAL = 16, ///< An optical sensor is plugged into the port - E_DEVICE_GPS = 20, ///< A GPS sensor is plugged into the port - E_DEVICE_AIVISION = 29, ///< An AI Vision sensor is plugged into the port - E_DEVICE_SERIAL = 129, ///< A serial device is plugged into the port - E_DEVICE_UNDEFINED = 255 ///< The device type is not defined, or is not a valid device -}; - -/** - * 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, V5Device 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 - */ -V5Device 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 - */ -V5Device registry_get_plugged_type(uint8_t port); - -///@} - /// \name Startup options ///@{ diff --git a/include/vdml/port.h b/include/vdml/port.h deleted file mode 100644 index b6f102d2..00000000 --- a/include/vdml/port.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * \file devices/port.h - * - * This file contains the standard header info for port macros and bit masks, - * used mostly for the adi expander. - * - * \copyright Copyright (c) 2017-2024, 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/. - */ - -#define SMART_PORT_BITS 16 -#define SMART_PORT_MASK ((1 << SMART_PORT_BITS) - 1) - -/** - * Macro Description: Given a merged ports variable, it sets the smart port and adi port to the - * values inside the int32_t. - */ -#define get_ports(ports, smart_port, adi_port) \ - { \ - uint32_t uport = (uint32_t)ports; \ - smart_port = uport & SMART_PORT_MASK; \ - adi_port = uport >> SMART_PORT_BITS; \ - } - -static inline uint32_t merge_adi_ports(uint8_t smart_port, uint8_t adi_port) { - return (adi_port << SMART_PORT_BITS) | smart_port; -} diff --git a/include/vdml/registry.hpp b/include/vdml/registry.hpp deleted file mode 100644 index 64109dee..00000000 --- a/include/vdml/registry.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * \file vdml/registry.h - * - * This file contains the standard header info for the VDML (Vex Data Management - * Layer) registry. - * - * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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/. - */ - -#pragma once - -#include "pros/apix.h" -#include "v5_api_patched.h" - -typedef struct { - pros::c::V5Device device_type; - V5_DeviceT device_info; - uint8_t pad[128]; // 16 bytes in adi_data_s_t times 8 ADI Ports = 128 -} v5_smart_device_s_t; - -/* - * Detects the devices that are plugged in. - * - * Pulls the type names of plugged-in devices and stores them in the buffer - * registry_types. - */ -void registry_update_types(); - -/* - * Returns the information on the device registered to the 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 (1-21). - * - * \param port - * The V5 port number from 1-21 - * - * \return A struct containing the device type and the info needed for api - * functions - */ -v5_smart_device_s_t* registry_get_device(uint8_t port); - -v5_smart_device_s_t* registry_get_device_internal(uint8_t port); diff --git a/include/vdml/vdml.h b/include/vdml/vdml.h deleted file mode 100644 index 2795eff1..00000000 --- a/include/vdml/vdml.h +++ /dev/null @@ -1,245 +0,0 @@ -/** - * \file vdml/vdml.h - * - * This file contains all types and functions used throughout multiple VDML - * (Vex Data Management Layer) files. - * - * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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/. - */ - -#pragma once - -#include "vdml/registry.h" - -#include -#include - -#ifdef __cplusplus - #define V5Device pros::c::V5Device -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Macro, returns true if the port is in range of user configurable ports, - * false otherwise. - */ -#define VALIDATE_PORT_NO(PORT) ((PORT) >= 0 && (PORT) < NUM_V5_PORTS) - -#define VALIDATE_PORT_NO_INTERNAL(PORT) ((PORT) >= 0 && (PORT) < V5_MAX_DEVICE_PORTS) - -/** - * Macro that handles error checking, sanity checking, automatic registration, - * and mutex taking for all of the motor wrapper functions. - * If port is out of range, the calling function sets errno and returns. - * If a port isn't yet registered, it registered as a motor automatically. - * If a mutex cannot be taken, errno is set to EACCES (access denied) and - * returns. - * - * \param port - * The V5 port number from 0-20 - * \param device_type - * The V5Device that the port is configured as - * \param error_code - * The error code that return if error checking failed - */ -#define claim_port(port, device_type, error_code) \ - if (registry_validate_binding(port, device_type) != 0) { \ - return error_code; \ - } \ - v5_smart_device_s_t* device = registry_get_device(port); \ - if (!port_mutex_take(port)) { \ - errno = EACCES; \ - return error_code; \ - } - -/** - * Function like claim_port. This macro should only be used in functions - * that return int32_t or enums as PROS_ERR could be returned. - * - * \param port - * The V5 port number from 0-20 - * \param device_type - * The V5Device that the port is configured as - */ -#define claim_port_i(port, device_type) claim_port(port, device_type, PROS_ERR) - -/** - * Function like claim_port. This macro should only be used in functions - * that return double or float as PROS_ERR_F could be returned. - * - * \param port - * The V5 port number from 0-20 - * \param device_type - * The V5Device that the port is configured as - */ -#define claim_port_f(port, device_type) claim_port(port, device_type, PROS_ERR_F) - -/** - * A function that executes claim_port and allows you to execute a block of - * code if an error occurs. - * - * 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). - * EACCES - Another resource is currently trying to access the port. - * - * \param port - * The V5 port number from 0-20 - * \param device_type - * The V5Device that the port is configured as - * - * \return 1 if the operation was successful or 0 if the operation - * failed, setting errno. - */ -int32_t claim_port_try(uint8_t port, V5Device type); - -/** - * Macro that release the mutex for the given port and sets errno to 0 if the - * function is an accessor wrapper whos return value is PROS_ERR or PROS_ERR_F. - * - * \param port - * The V5 port number from 0-20 - * \param rtn - * The desired return value - * - * \return The rtn parameter - */ -#define return_port(port, rtn) \ - port_mutex_give(port); \ - return rtn; - -/** - * Bitmap to indicate if a port has had an error printed or not. - */ -extern int32_t port_errors; - -/** - * Sets the port's bit to 1, indicating there has already been an error on this - * port. - * - * \param port - * The V5 port number to set from 0-20 - */ -void vdml_set_port_error(uint8_t port); - -/** - * Sets the port's bit to 0, effectively resetting it. - * - * \param port - * The V5 port number to unset from 0-20 - */ -void vdml_unset_port_error(uint8_t port); - -/** - * Gets the error bit for the port, indicating whether or not there has been an - * error on this port. - * - * \param port - * The V5 port number to check from 0-20 - * - * \return True if the port's bit is set, false otherwise. - */ -bool vdml_get_port_error(uint8_t port); - -/** - * Claims the mutex for the given port. - * - * Reserves the mutex for this port. Any other tasks trying to access this port - * will block until the mutex is returned. If a higher-priortiy task attempts - * to claim this port, the task which has the port claimed will temporarily be - * raised to an equal priority until the mutex is given, reducing the impact of - * the delay. See FreeRTOS documentation for more details. - * - * This MUST be called before any call to the v5 api to maintain thread saftey. - * - * 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 to claim from 0-20 - * - * \return 1 if the mutex was successfully taken, 0 if not, -1 if port is - * invalid. - */ -int port_mutex_take(uint8_t port); - -/** - * Returns the mutex for the given port. - * - * Frees the mutex for this port, allowing other tasks to continue. - * - * WARNING: If a mutex was claimed by a task, this MUST be called immediately - * after the port is no longer needed by that task in order to prevent delays in - * other tasks. - * - * 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 to free from 0-20 - */ -int port_mutex_give(uint8_t port); - -/** - * Executes port_mutex_take() for all of the V5 Smart Ports. - */ -void port_mutex_take_all(); - -/** - * Executes port_mutex_give() for all of the V5 Smart Ports. - */ -void port_mutex_give_all(); - -/** - * Obtains a port mutex with bounds checking for V5_MAX_PORTS (32) not user - * exposed device ports (20). Intended for internal usage for protecting - * thread-safety on devices such as the controller and battery - * - * 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-32). - * - * \param port - * The V5 port number from 0-32 - * - * \return True if the mutex was successfully taken, false otherwise. If false - * is returned, then errno is set with a hint about why the the mutex - * couldn't be taken. - */ -int internal_port_mutex_take(uint8_t port); - -/** - * Returns a port mutex with bounds checking for V5_MAX_PORTS (32) not user - * exposed device ports (20). Intended for internal usage for protecting - * thread-safety on devices such as the controller and battery - * - * 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-32). - * - * \param port - * The V5 port number from 0-32 - * - * \return True if the mutex was successfully returned, false otherwise. If - * false is returned, then errno is set with a hint about why the mutex - * couldn't be returned. - */ -int internal_port_mutex_give(uint8_t port); - -#define V5_PORT_BATTERY 24 -#define V5_PORT_CONTROLLER_1 25 -#define V5_PORT_CONTROLLER_2 26 - -#ifdef __cplusplus -} - #undef V5Device -#endif diff --git a/src/devices/screen.cpp b/src/devices/screen.cpp deleted file mode 100644 index 3d8b2c8f..00000000 --- a/src/devices/screen.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/** - * \file screen.cpp - * - * \brief Brain screen display and touch functions. - * - * Contains user calls to the v5 screen for touching and displaying graphics. - * - * \copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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/. - */ - -#include "pros/screen.hpp" - -#include - -namespace pros { -namespace screen { - -std::uint32_t set_pen(pros::Color color) { - return pros::c::screen_set_pen((uint32_t)color); -} - -std::uint32_t set_eraser(pros::Color color) { - return pros::c::screen_set_eraser((uint32_t)color); -} - -std::uint32_t set_pen(std::uint32_t color) { - return pros::c::screen_set_pen(color); -} - -std::uint32_t set_eraser(std::uint32_t color) { - return pros::c::screen_set_eraser(color); -} - -std::uint32_t get_pen() { - return pros::c::screen_get_pen(); -} - -std::uint32_t get_eraser() { - return pros::c::screen_get_eraser(); -} - -std::uint32_t erase() { - return pros::c::screen_erase(); -} - -std::uint32_t scroll(const std::int16_t start_line, const std::int16_t lines) { - return pros::c::screen_scroll(start_line, lines); -} - -std::uint32_t scroll_area( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1, - std::int16_t lines -) { - return pros::c::screen_scroll_area(x0, y0, x1, y1, lines); -} - -std::uint32_t copy_area( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1, - uint32_t* buf, - const std::int32_t stride -) { - return pros::c::screen_copy_area(x0, y0, x1, y1, buf, stride); -} - -std::uint32_t draw_pixel(const std::int16_t x, const std::int16_t y) { - return pros::c::screen_draw_pixel(x, y); -} - -std::uint32_t erase_pixel(const std::int16_t x, const std::int16_t y) { - return pros::c::screen_erase_pixel(x, y); -} - -std::uint32_t draw_line( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -) { - return pros::c::screen_draw_line(x0, y0, x1, y1); -} - -std::uint32_t erase_line( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -) { - return pros::c::screen_erase_line(x0, y0, x1, y1); -} - -std::uint32_t draw_rect( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -) { - return pros::c::screen_draw_rect(x0, y0, x1, y1); -} - -std::uint32_t erase_rect( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -) { - return pros::c::screen_erase_rect(x0, y0, x1, y1); -} - -std::uint32_t fill_rect( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -) { - return pros::c::screen_fill_rect(x0, y0, x1, y1); -} - -std::uint32_t draw_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius) { - return pros::c::screen_draw_circle(x, y, radius); -} - -std::uint32_t erase_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius) { - return pros::c::screen_erase_circle(x, y, radius); -} - -std::uint32_t fill_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius) { - return pros::c::screen_fill_circle(x, y, radius); -} - -screen_touch_status_s_t touch_status() { - return pros::c::screen_touch_status(); -} - -std::uint32_t touch_callback(touch_event_cb_fn_t cb, last_touch_e_t event_type) { - return pros::c::screen_touch_callback(cb, event_type); -} - -} // namespace screen -} // namespace pros diff --git a/src/devices/vdml.c b/src/devices/vdml.c deleted file mode 100644 index 6f2b6b2a..00000000 --- a/src/devices/vdml.c +++ /dev/null @@ -1,268 +0,0 @@ -/** - * \file devices/vdml.c - * - * VDML - VEX Data Management Layer - * - * VDML ensures thread saftey for operations on smart devices by maintaining - * an array of RTOS Mutexes and implementing functions to take and give them. - * - * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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/. - */ - -#include "vdml/vdml.h" - -#include "kapi.h" -#include "vdml/registry.h" - -#include - -/** - * Bitmap to indicate if a port has had an error printed or not. - */ -int32_t port_errors; - -extern void registry_init(); -extern void port_mutex_init(); - -int32_t claim_port_try(uint8_t port, V5Device type) { - if (!VALIDATE_PORT_NO(port)) { - errno = ENXIO; - return 0; - } - if (registry_validate_binding(port, type) != 0) { - return 0; - } - if (!port_mutex_take(port)) { - errno = EACCES; - return 0; - } - return 1; -} - -/** - * We have V5_MAX_DEVICE_PORTS so that we can do thread safety on things like - * controllers, batteries which are sort of like smart devices internally to the - * V5 - */ -mutex_t port_mutexes[V5_MAX_DEVICE_PORTS]; // Mutexes for each port -static_sem_s_t port_mutex_bufs[V5_MAX_DEVICE_PORTS]; // Stack mem for rtos - -/** - * Shorcut to initialize all of VDML (mutexes and register) - */ -void vdml_initialize() { - port_mutex_init(); - registry_init(); -} - -/** - * Initializes the mutexes for the motor ports. - * - * Initializes a static array of FreeRTOS mutexes to protect against race - * conditions. For example, we don't want the Background processing task to run - * at the same time that we set a motor, because bad information may be - * returned, or worse. - */ -void port_mutex_init() { - for (int i = 0; i < V5_MAX_DEVICE_PORTS; i++) { - port_mutexes[i] = mutex_create_static(&(port_mutex_bufs[i])); - } -} - -int port_mutex_take(uint8_t port) { - if (port >= V5_MAX_DEVICE_PORTS) { - errno = ENXIO; - return PROS_ERR; - } - return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING - || mutex_take(port_mutexes[port], TIMEOUT_MAX); -} - -int internal_port_mutex_take(uint8_t port) { - if (port >= V5_MAX_DEVICE_PORTS) { - errno = ENXIO; - return PROS_ERR; - } - return mutex_take(port_mutexes[port], TIMEOUT_MAX); -} - -static inline char* print_num(char* buff, int num) { - *buff++ = (num / 10) + '0'; - *buff++ = (num % 10) + '0'; - return buff; -} - -int port_mutex_give(uint8_t port) { - if (port >= V5_MAX_DEVICE_PORTS) { - errno = ENXIO; - return PROS_ERR; - } - return xTaskGetSchedulerState() != taskSCHEDULER_RUNNING || mutex_give(port_mutexes[port]); -} - -int internal_port_mutex_give(uint8_t port) { - if (port >= V5_MAX_DEVICE_PORTS) { - errno = ENXIO; - return PROS_ERR; - } - return mutex_give(port_mutexes[port]); -} - -void port_mutex_take_all() { - for (int i = 0; i < V5_MAX_DEVICE_PORTS; i++) { - port_mutex_take(i); - } -} - -void port_mutex_give_all() { - for (int i = 0; i < V5_MAX_DEVICE_PORTS; i++) { - port_mutex_give(i); - } -} - -void vdml_set_port_error(uint8_t port) { - if (VALIDATE_PORT_NO(port)) { - port_errors |= (1 << port); - } -} - -void vdml_unset_port_error(uint8_t port) { - if (VALIDATE_PORT_NO(port)) { - port_errors &= ~(1 << port); - } -} - -bool vdml_get_port_error(uint8_t port) { - if (VALIDATE_PORT_NO(port)) { - return (port_errors >> port) & 1; - } else { - return false; - } -} - -#if 0 -void vdml_reset_port_error() { - port_errors = 0; -} -#endif - -/** - * Background processing function for the VDML system. - * - * This function should be called by the system daemon approximately every - * 2 milliseconds. - * - * Updates the registry type array, detecting what devices are actually - * plugged in according to the system, then compares that with the registry - * records. - * - * On warnings, no operation is performed. - */ -void vdml_background_processing() { -// We're not removing this outright since we want to revisit the idea of logging -// the errors with devices in the future -#if 0 - static int32_t last_port_errors = 0; - static int cycle = 0; - cycle++; - if (cycle % 5000 == 0) { - vdml_reset_port_error(); - last_port_errors = 0; - } -#endif - - // Refresh actual device types. - registry_update_types(); - -#if 0 - // Validate the ports. Warn if mismatch. - uint8_t error_arr[NUM_V5_PORTS]; - int num_errors = 0; - int mismatch_errors = 0; - for (int i = 0; i < NUM_V5_PORTS; i++) { - error_arr[i] = registry_validate_binding(i, E_DEVICE_NONE); - if (error_arr[i] != 0) num_errors++; - if (error_arr[i] == 2) mismatch_errors++; - } - // Every 50 ms - if (cycle % 50 == 0) { - if (last_port_errors == port_errors) { - goto end_render_errors; - } - char line[50]; - char* line_ptr = line; - if (num_errors == 0) - line[0] = (char)0; - else if (num_errors <= 6) { - // If we have 1-6 total errors (unplugged + mismatch), we can - // display a line indicating the ports where these errors occur - strcpy(line_ptr, "PORTS"); - line_ptr += 5; // 5 is length of "PORTS" - if (mismatch_errors != 0) { - strcpy(line_ptr, " MISMATCHED: "); - line_ptr += 13; // 13 is length of previous string - for (int i = 0; i < NUM_V5_PORTS; i++) { - if (error_arr[i] == 2) { - line_ptr = print_num(line_ptr, i + 1); - *line_ptr++ = ','; - } - } - line_ptr--; - } - if (num_errors != mismatch_errors) { - strcpy(line_ptr, " UNPLUGGED: "); - line_ptr += 12; // 12 is length of previous string - for (int i = 0; i < NUM_V5_PORTS; i++) { - if (error_arr[i] == 1) { - line_ptr = print_num(line_ptr, i + 1); - *line_ptr++ = ','; - } - } - line_ptr--; - } - } else { - /* If we have > 6 errors, we display the following: - * PORT ERRORS: 1..... 6..... 11..... 16..... - * where each . represents a port. A '.' indicates - * there is no error on that port, a 'U' indicates - * the registry expected a device there but there isn't - * one, and a 'M' indicates the plugged in devices doesn't - * match what we expect. The numbers are just a visual reference - * to aid in determining what ports have errors. - */ - strcpy(line_ptr, "PORT ERRORS:"); - line_ptr += 12; // 12 is length of previous string - for (int i = 0; i < NUM_V5_PORTS; i++) { - if (i % 5 == 0) { - *line_ptr++ = ' '; - line_ptr = print_num(line_ptr, i + 1); - } - switch (error_arr[i]) { - case 0: - *line_ptr++ = '.'; - break; - case 1: - *line_ptr++ = 'U'; - break; - case 2: - *line_ptr++ = 'M'; - break; - // Should never happen - default: - *line_ptr++ = '?'; - break; - } - } - } - // Null terminate the string - *line_ptr = '\0'; - - end_render_errors: - last_port_errors = port_errors; - } -#endif -} diff --git a/src/devices/vdml.cpp b/src/devices/vdml.cpp new file mode 100644 index 00000000..748a7c8a --- /dev/null +++ b/src/devices/vdml.cpp @@ -0,0 +1,3 @@ +#include "src/devices/vdml.hpp" + +std::array port_mutex_array; \ No newline at end of file diff --git a/src/devices/vdml.hpp b/src/devices/vdml.hpp new file mode 100644 index 00000000..7e52f6ab --- /dev/null +++ b/src/devices/vdml.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "pros/rtos.hpp" +#include "v5_apitypes_patched.h" + +#include + +extern std::array port_mutex_array; + +enum class V5Device { + None, ///< No device is plugged into the port + Motor, ///< A motor is plugged into the port + Rotation, ///< A rotation sensor is plugged into the port + Imu, ///< An inertial sensor is plugged into the port + Distance, ///< A distance sensor is plugged into the port + Radio, ///< A radio is plugged into the port + Vision, ///< A vision sensor is plugged into the port + Adi, ///< This port is an ADI expander + Optical, ///< An optical sensor is plugged into the port + Gps, ///< A GPS sensor is plugged into the port + AiVision, ///< An AI Vision sensor is plugged into the port + Serial, ///< A serial device is plugged into the port +}; diff --git a/src/devices/vdml_usd.c b/src/devices/vdml_usd.c deleted file mode 100644 index 65c1cc33..00000000 --- a/src/devices/vdml_usd.c +++ /dev/null @@ -1,53 +0,0 @@ -/** - * \file devices/usd.c - * - * Contains functions for interacting with the SD card. - * - * \copyright Copyright (c) 2017-2024, 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/. - */ - -#include "pros/error.h" -#include "v5_api_patched.h" - -#include -#include - -int32_t usd_is_installed(void) { - return vexFileDriveStatus(0); -} - -static const int FRESULTMAP[] = { - 0, - EIO, - EINVAL, - EBUSY, - ENOENT, - ENOENT, - EINVAL, - EACCES, // FR_DENIED - EEXIST, - EINVAL, - EROFS, - ENXIO, - ENOBUFS, - ENXIO, - EIO, - EACCES, // FR_LOCKED - ENOBUFS, - ENFILE, - EINVAL -}; - -int32_t usd_list_files(const char* path, char* buffer, int32_t len) { - FRESULT result = vexFileDirectoryGet(path, buffer, len); - if (result != F_OK) { - errno = FRESULTMAP[result]; - return PROS_ERR; - } - return PROS_SUCCESS; -} From 6dcae1b3c03f1204497e41ab707835805f1d3597 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 3 May 2025 15:16:23 -0700 Subject: [PATCH 03/41] remove screen API --- src/devices/screen.c | 509 ------------------------------------------- 1 file changed, 509 deletions(-) delete mode 100644 src/devices/screen.c diff --git a/src/devices/screen.c b/src/devices/screen.c deleted file mode 100644 index 7311076c..00000000 --- a/src/devices/screen.c +++ /dev/null @@ -1,509 +0,0 @@ -/** - * \file screen.c - * - * \brief Brain screen display and touch functions. - * - * Contains user calls to the v5 screen for touching and displaying graphics. - * - * \copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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/. - */ - -#include "pros/screen.h" - -#include "common/linkedlist.h" -#include "kapi.h" -#include "v5_api_patched.h" // vexDisplay* - -#include -#include -#include - -/******************************************************************************/ -/** Screen Graphical Display Functions **/ -/** **/ -/** These functions allow programmers to display shapes on the v5 screen **/ -/******************************************************************************/ - -static mutex_t _screen_mutex = NULL; - -typedef struct touch_event_position_data_s { - int16_t x; - int16_t y; -} touch_event_position_data_s_t; - -uint32_t screen_set_pen(uint32_t color) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayForegroundColor(color); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_set_eraser(uint32_t color) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayBackgroundColor(color); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_get_pen(void) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - uint32_t color = vexDisplayForegroundColorGet(); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } - return color; -} - -uint32_t screen_get_eraser(void) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - uint32_t color = vexDisplayBackgroundColorGet(); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } - return color; -} - -uint32_t screen_erase(void) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayErase(); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_scroll(int16_t start_line, int16_t lines) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayScroll(start_line, lines); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_scroll_area(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t lines) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayScrollRect(x0, y0, x1, y1, lines); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t -screen_copy_area(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint32_t* buf, int32_t stride) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayCopyRect(x0, y0, x1, y1, buf, stride); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_draw_pixel(int16_t x, int16_t y) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayPixelSet(x, y); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_erase_pixel(int16_t x, int16_t y) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayPixelClear(x, y); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_draw_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayLineDraw(x0, y0, x1, y1); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_erase_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayLineClear(x0, y0, x1, y1); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_draw_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayRectDraw(x0, y0, x1, y1); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_erase_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayRectClear(x0, y0, x1, y1); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_fill_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayRectFill(x0, y0, x1, y1); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_draw_circle(int16_t x, int16_t y, int16_t radius) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayCircleDraw(x, y, radius); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_erase_circle(int16_t x, int16_t y, int16_t radius) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayCircleClear(x, y, radius); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_fill_circle(int16_t x, int16_t y, int16_t radius) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - vexDisplayCircleFill(x, y, radius); - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -/******************************************************************************/ -/** Screen Text Display Functions **/ -/** **/ -/** These functions allow programmers to display text on the v5 screen **/ -/******************************************************************************/ - -uint32_t screen_print(text_format_e_t txt_fmt, const int16_t line, const char* text, ...) { - va_list args; - va_start(args, text); - if (screen_vprintf((uint8_t)txt_fmt, line, text, args) == PROS_ERR) { - return PROS_ERR; - } - va_end(args); - return 1; -} - -uint32_t screen_print_at(text_format_e_t txt_fmt, int16_t x, int16_t y, const char* text, ...) { - va_list args; - va_start(args, text); - if (screen_vprintf_at((uint8_t)txt_fmt, x, y, text, args) == PROS_ERR) { - return PROS_ERR; - } - va_end(args); - return 1; -} - -uint32_t -screen_vprintf(text_format_e_t txt_fmt, const int16_t line, const char* text, va_list args) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - char* out; - vasprintf(&out, text, args); - va_list empty; - switch (txt_fmt) { - case E_TEXT_SMALL: - case E_TEXT_MEDIUM: { - vexDisplayVString(line, out, empty); - break; - } - case E_TEXT_LARGE: { - vexDisplayVBigString(line, out, empty); - break; - } - case E_TEXT_MEDIUM_CENTER: { - vexDisplayVCenteredString(line, out, empty); - break; - } - case E_TEXT_LARGE_CENTER: { - vexDisplayVBigCenteredString(line, out, empty); - break; - } - default: { - vexDisplayVString(line, out, empty); - break; - } - } - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -uint32_t screen_vprintf_at( - text_format_e_t txt_fmt, - const int16_t x, - const int16_t y, - const char* text, - va_list args -) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - char* out; - vasprintf(&out, text, args); - va_list empty; - switch (txt_fmt) { - case E_TEXT_SMALL: { - vexDisplayVSmallStringAt(x, y, out, empty); - break; - } - case E_TEXT_MEDIUM: - case E_TEXT_MEDIUM_CENTER: { - vexDisplayVStringAt(x, y, out, empty); - break; - } - case E_TEXT_LARGE: - case E_TEXT_LARGE_CENTER: { - vexDisplayVBigStringAt(x, y, out, empty); - break; - } - default: { - vexDisplayVStringAt(x, y, out, empty); - break; - } - } - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -/******************************************************************************/ -/** Screen Touch Functions **/ -/** **/ -/** These functions allow programmers to access **/ -/** information about screen touches **/ -/******************************************************************************/ - -static const screen_touch_status_s_t PROS_SCREEN_ERR = - {.touch_status = E_TOUCH_ERROR, .x = -1, .y = -1, .press_count = -1, .release_count = -1}; - -screen_touch_status_s_t screen_touch_status(void) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_SCREEN_ERR; - } - V5_TouchStatus v5_touch_status; - screen_touch_status_s_t rtv; - vexTouchDataGet(&v5_touch_status); - rtv.touch_status = (last_touch_e_t)v5_touch_status.lastEvent; - rtv.x = v5_touch_status.lastXpos; - rtv.y = v5_touch_status.lastYpos; - rtv.press_count = v5_touch_status.pressCount; - rtv.release_count = v5_touch_status.releaseCount; - if (!mutex_give(_screen_mutex)) { - errno = EACCES; - return PROS_SCREEN_ERR; - } - return rtv; -} - -static linked_list_s_t* _touch_event_release_handler_list = NULL; -static linked_list_s_t* _touch_event_press_handler_list = NULL; -static linked_list_s_t* _touch_event_press_auto_handler_list = NULL; - -static void _set_up_touch_callback_storage() { - _touch_event_release_handler_list = linked_list_init(); - _touch_event_press_handler_list = linked_list_init(); - _touch_event_press_auto_handler_list = linked_list_init(); -} - -uint32_t screen_touch_callback(touch_event_cb_fn_t cb, last_touch_e_t event_type) { - if (!mutex_take(_screen_mutex, TIMEOUT_MAX)) { - errno = EACCES; - return PROS_ERR; - } - switch (event_type) { - case E_TOUCH_RELEASED: - linked_list_prepend_func(_touch_event_release_handler_list, (generic_fn_t)cb); - break; - case E_TOUCH_PRESSED: - linked_list_prepend_func(_touch_event_press_handler_list, (generic_fn_t)cb); - break; - case E_TOUCH_HELD: - linked_list_prepend_func(_touch_event_press_auto_handler_list, (generic_fn_t)cb); - break; - case E_TOUCH_ERROR: - return PROS_ERR; - break; - } - if (!mutex_give(_screen_mutex)) { - return PROS_ERR; - } else { - return 1; - } -} - -static task_stack_t touch_handle_task_stack[TASK_STACK_DEPTH_DEFAULT]; -static static_task_s_t touch_handle_task_buffer; -static task_t touch_handle_task; - -static void _handle_cb(ll_node_s_t* current, void* extra_data) { - (current->payload.func)(); -} - -static inline bool _touch_status_equivalent(V5_TouchStatus x, V5_TouchStatus y) { - return (x.lastEvent == y.lastEvent) && (x.lastXpos == y.lastXpos) && (x.lastYpos == y.lastYpos); -} - -void _touch_handle_task(void* ignore) { - V5_TouchStatus last, current; - while (true) { - mutex_take(_screen_mutex, TIMEOUT_MAX); - vexTouchDataGet(¤t); - mutex_give(_screen_mutex); - if (!_touch_status_equivalent(current, last)) { - switch (current.lastEvent) { - case E_TOUCH_RELEASED: - linked_list_foreach(_touch_event_release_handler_list, _handle_cb, NULL); - break; - case E_TOUCH_PRESSED: - linked_list_foreach(_touch_event_press_handler_list, _handle_cb, NULL); - break; - case E_TOUCH_HELD: - linked_list_foreach(_touch_event_press_auto_handler_list, _handle_cb, NULL); - break; - } - last = current; - } - delay(10); - } -} - -// internal functions for different mechanisms - -void display_fatal_error(const char* text) { - // in fatal error state, cannot rely on integrity of the RTOS - char s[50]; - strncpy(s, text, 50); - vexDisplayForegroundColor(COLOR_RED); - vexDisplayRectFill(0, 0, 480, 19); - vexDisplayRectFill(0, 0, 27, 240); - vexDisplayRectFill(453, 0, 480, 240); - vexDisplayRectFill(0, 179, 480, 240); - vexDisplayForegroundColor(0x1A1917); - vexDisplayRectFill(50, 190, 130, 230); - vexDisplayRectFill(200, 190, 280, 230); - vexDisplayRectFill(350, 190, 430, 230); - vexDisplayCenteredString(0, s); -} - -void graphical_context_daemon_initialize(void) { - _screen_mutex = mutex_create(); - _set_up_touch_callback_storage(); - touch_handle_task = task_create_static( - _touch_handle_task, - NULL, - TASK_PRIORITY_MIN + 2, - TASK_STACK_DEPTH_DEFAULT, - "PROS Graphics Touch Handler", - touch_handle_task_stack, - &touch_handle_task_buffer - ); -} From db9281f55a8e9eb188a09949ac7d0b331b7f9f39 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 3 May 2025 15:26:29 -0700 Subject: [PATCH 04/41] delete registry.c --- src/devices/registry.c | 152 ----------------------------------------- 1 file changed, 152 deletions(-) delete mode 100644 src/devices/registry.c diff --git a/src/devices/registry.c b/src/devices/registry.c deleted file mode 100644 index 88ebb127..00000000 --- a/src/devices/registry.c +++ /dev/null @@ -1,152 +0,0 @@ -/** - * \file devices/registry.c - * - * This file is the VDML (Vex Data Management Layer) Registry. It keeps track of - * what devices are in use on the V5. Therefore, in order to use V5 devices with - * PROS, they must be registered and deregistered using the registry. - * - * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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/. - */ - -#include "vdml/registry.h" - -#include "kapi.h" -#include "pros/apix.h" -#include "pros/misc.h" -#include "v5_api_patched.h" -#include "vdml/vdml.h" - -#include -#include - -static v5_smart_device_s_t registry[V5_MAX_DEVICE_PORTS]; -static V5_DeviceType registry_types[V5_MAX_DEVICE_PORTS]; - -void registry_init() { - int i; - kprint("[VDML][INFO]Initializing registry\n"); - registry_update_types(); - for (i = 0; i < NUM_V5_PORTS; i++) { - registry[i].device_type = (V5Device)registry_types[i]; - registry[i].device_info = vexDeviceGetByIndex(i); - if (registry[i].device_type != E_DEVICE_NONE) { - kprintf("[VDML][INFO]Register device in port %d", i + 1); - } - } - kprint("[VDML][INFO]Done initializing registry\n"); -} - -void registry_update_types() { - vexDeviceGetStatus(registry_types); -} - -int registry_bind_port(uint8_t port, V5Device device_type) { - if (!VALIDATE_PORT_NO(port)) { - kprintf("[VDML][ERROR]Registration: Invalid port number %d\n", port + 1); - errno = ENXIO; - return PROS_ERR; - } - if (registry[port].device_type != E_DEVICE_NONE) { - kprintf("[VDML][ERROR]Registration: Port already in use %d\n", port + 1); - errno = EADDRINUSE; - return PROS_ERR; - } - if ((V5Device)registry_types[port] != device_type - && (V5Device)registry_types[port] != E_DEVICE_NONE) { - kprintf("[VDML][ERROR]Registration: Device mismatch in port %d\n", port + 1); - errno = EADDRINUSE; - return PROS_ERR; - } - kprintf("[VDML][INFO]Registering device in port %d\n", port + 1); - v5_smart_device_s_t device; - device.device_type = device_type; - device.device_info = vexDeviceGetByIndex(port); - registry[port] = device; - return 1; -} - -int registry_unbind_port(uint8_t port) { - if (!VALIDATE_PORT_NO(port)) { - errno = ENXIO; - return PROS_ERR; - } - registry[port].device_type = E_DEVICE_NONE; - registry[port].device_info = NULL; - return 1; -} - -v5_smart_device_s_t* registry_get_device(uint8_t port) { - if (!VALIDATE_PORT_NO(port)) { - errno = ENXIO; - return NULL; - } - return ®istry[port]; -} - -v5_smart_device_s_t* registry_get_device_internal(uint8_t port) { - if (!VALIDATE_PORT_NO_INTERNAL(port)) { - errno = ENXIO; - return NULL; - } - return ®istry[port]; -} - -V5Device registry_get_bound_type(uint8_t port) { - if (!VALIDATE_PORT_NO(port)) { - errno = ENXIO; - return E_DEVICE_UNDEFINED; - } - return registry[port].device_type; -} - -V5Device registry_get_plugged_type(uint8_t port) { - if (!VALIDATE_PORT_NO(port)) { - errno = ENXIO; - return -1; - } - return (V5Device)registry_types[port]; -} - -int32_t registry_validate_binding(uint8_t port, V5Device expected_t) { - if (!VALIDATE_PORT_NO(port)) { - errno = ENXIO; - return PROS_ERR; - } - - // Get the registered and plugged types - V5Device registered_t = registry_get_bound_type(port); - V5Device actual_t = registry_get_plugged_type(port); - - // Auto register the port if needed - if (registered_t == E_DEVICE_NONE && actual_t != E_DEVICE_NONE) { - registry_bind_port(port, actual_t); - registered_t = registry_get_bound_type(port); - } - - if ((expected_t == registered_t || expected_t == E_DEVICE_NONE) && registered_t == actual_t) { - // All are same OR expected is none (bgp) AND reg = act. - // All good - vdml_unset_port_error(port); - return 0; - } else if (actual_t == E_DEVICE_NONE) { - // Warn about nothing plugged - if (!vdml_get_port_error(port)) { - kprintf("[VDML][WARNING] No device in port %d. Is it plugged in?\n", port + 1); - vdml_set_port_error(port); - } - errno = ENODEV; - return 1; - } else { - // Warn about a mismatch - if (!vdml_get_port_error(port)) { - kprintf("[VDML][WARNING] Device mismatch in port %d.\n", port + 1); - vdml_set_port_error(port); - } - errno = EADDRINUSE; - return 2; - } -} From 320b7a756758df03800b7ea312cdb0c1dfe701de Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 3 May 2025 15:28:53 -0700 Subject: [PATCH 05/41] remove screen header files --- include/pros/screen.h | 803 ---------------------------------------- include/pros/screen.hpp | 766 -------------------------------------- 2 files changed, 1569 deletions(-) delete mode 100644 include/pros/screen.h delete mode 100644 include/pros/screen.hpp diff --git a/include/pros/screen.h b/include/pros/screen.h deleted file mode 100644 index c95eb0c0..00000000 --- a/include/pros/screen.h +++ /dev/null @@ -1,803 +0,0 @@ -/** - * \file screen.h - * \ingroup c-screen - * - * Brain screen display and touch functions. - * - * Contains user calls to the v5 screen for touching and displaying graphics. - * - * \copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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 c-screen Simplified Brain Screen C API - * - */ - -#ifndef _PROS_SCREEN_H_ -#define _PROS_SCREEN_H_ - -#include -#include -#define _GNU_SOURCE -#include -#undef _GNU_SOURCE -#include "pros/colors.h" // c color macros - -#include - - -#ifdef __cplusplus -extern "C" { -namespace pros { -#endif - -/** - * \ingroup c-screen - */ - -/** - * \addtogroup c-screen - * @{ - */ - -/** - * \enum text_format_e_t - * Different font sizes that can be used in printing text. - */ -typedef enum { - /// Small text font size - E_TEXT_SMALL = 0, - /// Normal/Medium text font size - E_TEXT_MEDIUM, - /// Large text font size - E_TEXT_LARGE, - /// Medium centered text - E_TEXT_MEDIUM_CENTER, - /// Large centered text - E_TEXT_LARGE_CENTER -} text_format_e_t; - -/** - * \enum last_touch_e_t - * Enum indicating what the current touch status is for the touchscreen. - */ -typedef enum { - /// Last interaction with screen was a quick press - E_TOUCH_RELEASED = 0, - /// Last interaction with screen was a release - E_TOUCH_PRESSED, - /// User is holding screen down - E_TOUCH_HELD, - /// An error occured while taking/returning the mutex - E_TOUCH_ERROR -} last_touch_e_t; - -/** - * \struct screen_touch_status_s_t - * Struct representing screen touch status, screen last x, screen last y, press count, release - * count. - */ -typedef struct screen_touch_status_s { - last_touch_e_t touch_status; ///< Represents if the screen is being held, released, or pressed. - int16_t x; ///< Represents the x value of the location of the touch. - int16_t y; ///< Represents the y value of the location of the touch. - int32_t press_count; ///< Represents how many times the screen has be pressed. - int32_t - release_count; ///< Represents how many times the user released after a touch on the screen. -} screen_touch_status_s_t; - -#ifdef PROS_USE_SIMPLE_NAMES - #ifdef __cplusplus - #define TEXT_SMALL pros::E_TEXT_SMALL - #define TEXT_MEDIUM pros::E_TEXT_MEDIUM - #define TEXT_LARGE pros::E_TEXT_LARGE - #define TEXT_MEDIUM_CENTER pros::E_TEXT_MEDIUM_CENTER - #define TEXT_LARGE_CENTER pros::E_TEXT_LARGE_CENTER - #define TOUCH_RELEASED pros::E_TOUCH_RELEASED - #define TOUCH_PRESSED pros::E_TOUCH_PRESSED - #define TOUCH_HELD pros::E_TOUCH_HELD - #else - #define TEXT_SMALL E_TEXT_SMALL - #define TEXT_MEDIUM E_TEXT_MEDIUM - #define TEXT_LARGE E_TEXT_LARGE - #define TEXT_MEDIUM_CENTER E_TEXT_MEDIUM_CENTER - #define TEXT_LARGE_CENTER E_TEXT_LARGE_CENTER - #define TOUCH_RELEASED E_TOUCH_RELEASED - #define TOUCH_PRESSED E_TOUCH_PRESSED - #define TOUCH_HELD E_TOUCH_HELD - #endif -#endif - -typedef void (*touch_event_cb_fn_t)(); - -#ifdef __cplusplus -namespace c { -#endif - -/// \name Screen Graphical Display Functions -/// These functions allow programmers to display shapes on the v5 screen -///@{ - -/** - * Set the pen color for subsequent graphics operations - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param color The pen color to set (it is recommended to use values - * from the enum defined in colors.h) - * - * \return Returns 1 if the mutex was successfully returned, or PROS_ERR if - * there was an error either taking or returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * screen_set_pen(COLOR_RED); - * } - * - * void opcontrol() { - * int iter = 0; - * while(1){ - * // This should print in red. - * screen_print(TEXT_MEDIUM, 1, "%d", iter++); - * } - * } - * \endcode - */ -uint32_t screen_set_pen(uint32_t color); - -/** - * Set the eraser color for erasing and the current background. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param color The background color to set (it is recommended to use values - * from the enum defined in colors.h) - * - * \return Returns 1 if the mutex was successfully returned, or - * PROS_ERR if there was an error either taking or returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * screen_set_eraser(COLOR_RED); - * } - * - * void opcontrol() { - * while(1){ - * // This should turn the screen red. - * screen_erase(); - * } - * } - * \endcode - */ -uint32_t screen_set_eraser(uint32_t color); - -/** - * Get the current pen color. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \return The current pen color in the form of a value from the enum defined - * in colors.h, or PROS_ERR if there was an error taking or returning - * the screen mutex. - * - * \b Example - * \code - * void initialize() { - * screen_set_pen(COLOR_RED); - * } - * - * void opcontrol() { - * while(1){ - * // Should print number equivalent to COLOR_RED defined in colors.h. - * screen_print(TEXT_MEDIUM, 1, "%d", screen_get_pen()); - * } - * } - * \endcode - */ -uint32_t screen_get_pen(void); - -/** - * Get the current eraser color. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \return The current eraser color in the form of a value from the enum - * defined in colors.h, or PROS_ERR if there was an error taking or - * returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * screen_set_eraser(COLOR_RED); - * } - * - * void opcontrol() { - * while(1){ - * // Should print number equivalent to COLOR_RED defined in colors.h. - * screen_print(TEXT_MEDIUM, 1, "%d", screen_get_eraser()); - * } - * } - * \endcode - */ -uint32_t screen_get_eraser(void); - -/** - * Clear display with eraser color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * screen_set_eraser(COLOR_RED); - * } - * - * void opcontrol() { - * while(1){ - * // This should turn the screen red. - * screen_erase(); - * } - * } - * \endcode - */ -uint32_t screen_erase(void); - -/** - * Scroll lines on the display upwards. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param start_line The line from which scrolling will start - * \param lines The number of lines to scroll up - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * screen_print(TEXT_MEDIUM, 4, "Line Here"); - * // Scroll 3 lines - * screen_scroll(4, 3); - * } - * \endcode - */ -uint32_t screen_scroll(int16_t start_line, int16_t lines); - -/** - * Scroll lines within a region on the display - * - * This function behaves in the same way as `screen_scroll`, except that you - * specify a rectangular region within which to scroll lines instead of a start - * line. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first corner of the - * rectangular region - * \param x1, y1 The (x,y) coordinates of the second corner of the - * rectangular region - * \param lines The number of lines to scroll upwards - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * screen_print(TEXT_MEDIUM, 1, "Line Here"); - * // Scrolls area of screen upwards slightly. including line of text - * screen_scroll_area(0,0, 400, 200, 3); - * } - * \endcode - */ -uint32_t screen_scroll_area(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t lines); - -/** - * Copy a screen region (designated by a rectangle) from an off-screen buffer - * to the screen - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first corner of the - * rectangular region of the screen - * \param x1, y1 The (x,y) coordinates of the second corner of the - * rectangular region of the screen - * \param buf Off-screen buffer containing screen data - * \param stride Off-screen buffer width in pixels, such that image size - * is stride-padding - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * uint32_t* buf = malloc(sizeof(uint32_t) * 400 * 200); - * screen_print(TEXT_MEDIUM, 1, "Line Here"); - * // Copies area of the screen including text - * screen_copy_area(0, 0, 400, 200, (uint32_t*)buf, 400 + 1); - * // Equation for stride is x2 - x1 + 1 - * } - * \endcode - */ -uint32_t -screen_copy_area(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint32_t* buf, int32_t stride); - -/** - * Draw a single pixel on the screen using the current pen color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the pixel - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * int i = 0; - * void opcontrol() { - * while(i < 200){ - * screen_draw_pixel(100,i++); - * // Draws a line at x = 100 gradually down the screen, pixel by pixel - * delay(200); - * } - * } - * \endcode - */ -uint32_t screen_draw_pixel(int16_t x, int16_t y); - -/** - * Erase a pixel from the screen (Sets the location) - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the erased - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Color the Screen in Red - * screen_set_pen(COLOR_RED); - * screen_fill_rect(0,0,400,200); - * int i = 0; - * while(i < 200){ - * screen_erase_pixel(100,i++); - * // Erases a line at x = 100 gradually down the screen, pixel by pixel - * delay(200); - * } - * } - * \endcode - */ -uint32_t screen_erase_pixel(int16_t x, int16_t y); - -/** - * Draw a line on the screen using the current pen color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x, y) coordinates of the first point of the line - * \param x1, y1 The (x, y) coordinates of the second point of the line - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * screen_set_pen(COLOR_RED); - * // Draw line down the screen at x = 100 - * screen_draw_line(100,0,100,200); - * } - * \endcode - */ -uint32_t screen_draw_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1); - -/** - * Erase a line on the screen using the current eraser color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x, y) coordinates of the first point of the line - * \param x1, y1 The (x, y) coordinates of the second point of the line - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Color the Screen in Red - * screen_set_pen(COLOR_RED); - * screen_fill_rect(0,0,400,200); - * // Erase line down the screen at x = 100 - * screen_erase_line(100,0,100,200); - * } - * \endcode - */ -uint32_t screen_erase_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1); - -/** - * Draw a rectangle on the screen using the current pen color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first point of the rectangle - * \param x1, y1 The (x,y) coordinates of the second point of the rectangle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * screen_set_pen(COLOR_RED); - * screen_draw_rect(1,1,480,200); - * } - * \endcode - */ -uint32_t screen_draw_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1); - -/** - * Erase a rectangle on the screen using the current eraser color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first point of the rectangle - * \param x1, y1 The (x,y) coordinates of the second point of the rectangle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Draw Box Around Half the Screen in Red - * screen_set_eraser(COLOR_RED); - * screen_erase_rect(5,5,240,200); - * } - * \endcode - */ -uint32_t screen_erase_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1); - -/** - * Fill a rectangular region of the screen using the current pen - * color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first point of the rectangle - * \param x1, y1 The (x,y) coordinates of the second point of the rectangle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Fill Around Half the Screen in Red - * screen_set_pen(COLOR_RED); - * screen_fill_rect(5,5,240,200); - * } - * \endcode - */ -uint32_t screen_fill_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1); - -/** - * Draw a circle on the screen using the current pen color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the center of the circle - * \param r The radius of the circle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Draw a circle with radius of 100 in red - * screen_set_pen(COLOR_RED); - * screen_draw_circle(240, 200, 100); - * } - * \endcode - */ -uint32_t screen_draw_circle(int16_t x, int16_t y, int16_t radius); - -/** - * Erase a circle on the screen using the current eraser color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the center of the circle - * \param r The radius of the circle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * screen_set_pen(COLOR_RED); - * screen_fill_rect(5,5,240,200); - * // Erase a circle with radius of 100 in COLOR_BLUE - * screen_set_pen(COLOR_BLUE); - * screen_erase_circle(240, 200, 100); - * } - * \endcode - */ -uint32_t screen_erase_circle(int16_t x, int16_t y, int16_t radius); - -/** - * Fill a circular region of the screen using the current pen - * color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the center of the circle - * \param r The radius of the circle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * screen_set_pen(COLOR_RED); - * screen_fill_rect(5,5,240,200); - * // Fill a circlular area with radius of 100 in COLOR_BLUE - * screen_set_pen(COLOR_BLUE); - * screen_fill_circle(240, 200, 100); - * } - * \endcode - */ -uint32_t screen_fill_circle(int16_t x, int16_t y, int16_t radius); - -///@} - -/// \name Screen Text Display Functions -/// These functions allow programmers to display text on the v5 screen -///@{ - -/** - * Print a formatted string to the screen on the specified line - * - * Will default to a medium sized font by default if invalid txt_fmt is given. - * - * \param txt_fmt Text format enum that determines if the text is medium, large, medium_center, or - * large_center. (DOES NOT SUPPORT SMALL) \param line The line number on which to print \param text - * Format string \param ... Optional list of arguments for the format string - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * int i = 0; - * - * screen_set_pen(COLOR_BLUE); - * while(1){ - * // Will print seconds started since program started on line 3 - * screen_print(TEXT_MEDIUM, 3, "Seconds Passed: %3d", i++); - * delay(1000); - * } - * } - * \endcode - */ -uint32_t screen_print(text_format_e_t txt_fmt, const int16_t line, const char* text, ...); - -/** - * Print a formatted string to the screen at the specified point - * - * Will default to a medium sized font by default if invalid txt_fmt is given. - * - * Text formats medium_center and large_center will default to medium and large respectively. - * - * \param txt_fmt Text format enum that determines if the text is small, medium, or large. - * \param x The y coordinate of the top left corner of the string - * \param y The x coordinate of the top left corner of the string - * \param text Format string - * \param ... Optional list of arguments for the format string - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * int i = 0; - * - * screen_set_pen(COLOR_BLUE); - * while(1){ - * // Will print seconds started since program started. - * screen_print_at(TEXT_SMALL, 3, "Seconds Passed: %3d", i++); - * delay(1000); - * } - * } - * \endcode - */ -uint32_t -screen_print_at(text_format_e_t txt_fmt, const int16_t x, const int16_t y, const char* text, ...); - -/** - * Print a formatted string to the screen on the specified line - * - * Same as `display_printf` except that this uses a `va_list` instead of the - * ellipsis operator so this can be used by other functions. - * - * Will default to a medium sized font by default if invalid txt_fmt is given. - * Exposed mostly for writing libraries and custom functions. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param txt_fmt Text format enum that determines if the text is medium, large, medium_center, or - * large_center. (DOES NOT SUPPORT SMALL) \param line The line number on which to print \param text - * Format string \param args List of arguments for the format string - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * while taking or returning the screen mutex. - * - * - */ -uint32_t -screen_vprintf(text_format_e_t txt_fmt, const int16_t line, const char* text, va_list args); - -/** - * Print a formatted string to the screen at the specified coordinates - * - * Same as `display_printf_at` except that this uses a `va_list` instead of the - * ellipsis operator so this can be used by other functions. - * - * Will default to a medium sized font by default if invalid txt_fmt is given. - * - * Text formats medium_center and large_center will default to medium and large respectively. - * Exposed mostly for writing libraries and custom functions. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param txt_fmt Text format enum that determines if the text is small, medium, or large. - * \param x, y The (x,y) coordinates of the top left corner of the string - * \param text Format string - * \param args List of arguments for the format string - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * while taking or returning the screen mutex. - * - */ -uint32_t screen_vprintf_at( - text_format_e_t txt_fmt, - const int16_t x, - const int16_t y, - const char* text, - va_list args -); - -///@} - -/// \name Screen Touch Functions -/// These functions allow programmers to access information about screen touches -///@{ - -/** - * Gets the touch status of the last touch of the screen. - * - * \return The last_touch_e_t enum specifier that indicates the last touch status of the screen - * (E_TOUCH_EVENT_RELEASE, E_TOUCH_EVENT_PRESS, or E_TOUCH_EVENT_PRESS_AND_HOLD). This will be - * released by default if no action was taken. If an error occured, the screen_touch_status_s_t will - * have its last_touch_e_t enum specifier set to E_TOUCH_ERR, and other values set to -1. - * - * \b Example - * \code - * void opcontrol() { - * int i = 0; - * screen_touch_status_s_t status; - * while(1){ - * status = screen_touch_status(); - * - * // Will print various information about the last touch - * screen_print(TEXT_MEDIUM, 1, "Touch Status (Type): %d", status.touch_status); - * screen_print(TEXT_MEDIUM, 2, "Last X: %d", status.x); - * screen_print(TEXT_MEDIUM, 3, "Last Y: %d", status.y); - * screen_print(TEXT_MEDIUM, 4, "Press Count: %d", status.press_count); - * screen_print(TEXT_MEDIUM, 5, "Release Count: %d", status.release_count); - * delay(20); - * } - * } - * \endcode - */ -screen_touch_status_s_t screen_touch_status(void); - -/** - * Assigns a callback function to be called when a certain touch event happens. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param cb Function pointer to callback when event type happens - * \param event_type Touch event that will trigger the callback. - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * while taking or returning the screen mutex. - * - * \b Example - * \code - * touch_event_cb_fn_t changePixel(){ - * screen_touch_status_s_t status = screen_touch_status(); - * screen_draw_pixel(status.x,status.y); - * return NULL; - * } - * - * void opcontrol() { - * screen_touch_callback(changePixel(), TOUCH_PRESSED); - * while(1) delay(20); - * } - * \endcode - */ -uint32_t screen_touch_callback(touch_event_cb_fn_t cb, last_touch_e_t event_type); - -///@} - -///@} - -#ifdef __cplusplus -} // namespace c -} // namespace pros -} -#endif - -#endif diff --git a/include/pros/screen.hpp b/include/pros/screen.hpp deleted file mode 100644 index 776b2c18..00000000 --- a/include/pros/screen.hpp +++ /dev/null @@ -1,766 +0,0 @@ -/** - * \file screen.hpp - * \ingroup cpp-screen - * - * Brain screen display and touch functions. - * - * Contains user calls to the v5 screen for touching and displaying graphics. - * - * \copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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 cpp-screen Simplified Brain Screen C++ API - */ - -#ifndef _PROS_SCREEN_HPP_ -#define _PROS_SCREEN_HPP_ - -#include "pros/colors.hpp" -#include "pros/screen.h" - -#include -#include - - -namespace pros { -namespace screen { - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" - -namespace { -template -T convert_args(T arg) { - return arg; -} - -const char* convert_args(const std::string& arg) { - return arg.c_str(); -} -} // namespace - -#pragma GCC diagnostic pop - -/** - * \ingroup cpp-screen - */ - -/** - * \addtogroup cpp-screen - * @{ - */ - -/******************************************************************************/ -/** Screen Graphical Display Functions **/ -/** **/ -/** These functions allow programmers to display shapes on the v5 screen **/ -/******************************************************************************/ - -/** - * Set the pen color for subsequent graphics operations - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param color The pen color to set (it is recommended to use values - * from the enum defined in colors.hpp) - * - * \return Returns 1 if the mutex was successfully returned, or PROS_ERR if - * there was an error either taking or returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * pros::screen::set_pen(red); - * } - * - * void opcontrol() { - * int iter = 0; - * while(1){ - * // This should print in red. - * pros::screen::print(TEXT_MEDIUM, 1, "%d", iter++); - * } - * } - * - * \endcode - */ -std::uint32_t set_pen(pros::Color color); - -/** - * Set the pen color for subsequent graphics operations - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param color The pen color to set (in hex form) - * - * \return Returns 1 if the mutex was successfully returned, or PROS_ERR if - * there was an error either taking or returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * //set pen color to red - * pros::screen::set_pen(0x00FF0000); - * } - * - * void opcontrol() { - * int iter = 0; - * while(1){ - * // This should print in red. - * pros::screen::print(TEXT_MEDIUM, 1, "%d", iter++); - * } - * } - * - * \endcode - */ -std::uint32_t set_pen(std::uint32_t color); - -/** - * Set the eraser color for erasing and the current background. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param color The background color to set (it is recommended to use values - * from the enum defined in colors.hpp) - * - * \return Returns 1 if the mutex was successfully returned, or PROS_ERR - * if there was an error either taking or returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * //set eraser color to red - * set_eraser(red); - * } - * - * void opcontrol() { - * int iter = 0; - * while(1){ - * // This should print in red. - * pros::screen::print(TEXT_MEDIUM, 1, "%d", iter++); - * } - * } - * - * \endcode - */ -std::uint32_t set_eraser(pros::Color color); - -/** - * Set the eraser color for erasing and the current background. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param color The background color to set to set (in hex form) - * - * \return Returns 1 if the mutex was successfully returned, or PROS_ERR - * if there was an error either taking or returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * //set eraser color to red - * pros::screen::set_eraser(0x00FF0000); - * } - * - * void opcontrol() { - * while(1){ - * // This should turn the screen red. - * pros::screen::erase(); - * } - * } - * \endcode - */ -std::uint32_t set_eraser(std::uint32_t color); - -/** - * Get the current pen color. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \return The current pen color in the form of a value from the enum - * defined in colors.h, or PROS_ERR if there was an error taking or - * returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * pros::screen::set_pen(red); - * } - * - * void opcontrol() { - * while(1){ - * // Should print number equivalent to red defined in colors.hpp. - * pros::screen::print(TEXT_MEDIUM, 1, "%d", get_pen()); - * } - * } - * \endcode - */ -std::uint32_t get_pen(); - -/** - * Get the current eraser color. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \return The current eraser color in the form of a value from the enum - * defined in colors.h, or PROS_ERR if there was an error taking or - * returning the screen mutex. - * - * \b Example - * \code - * void initialize() { - * pros::screen::set_eraser(red); - * } - * - * void opcontrol() { - * while(1){ - * // Should print number equivalent to red defined in colors.h. - * pros::screen::print(TEXT_MEDIUM, 1, "%d", get_eraser()); - * } - * } - * \endcode - */ -std::uint32_t get_eraser(); - -/** - * Clear display with eraser color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * * \b Example - * \code - * void initialize() { - * pros::screen::set_eraser(red); - * } - * - * void opcontrol() { - * while(1){ - * // This should turn the screen red. - * pros::screen::erase(); - * } - * } - * \endcode - */ -std::uint32_t erase(); - -/** - * Scroll lines on the display upwards. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param start_line The line from which scrolling will start - * \param lines The number of lines to scroll up - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * pros::screen::print(TEXT_MEDIUM, 4, "Line Here"); - * // Scroll 3 lines - * pros::screen::scroll(4, 3); - * } - * \endcode - */ -std::uint32_t scroll(const std::int16_t start_line, const std::int16_t lines); - -/** - * Scroll lines within a region on the display - * - * This function behaves in the same way as `screen_scroll`, except that you - * specify a rectangular region within which to scroll lines instead of a start - * line. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first corner of the - * rectangular region - * \param x1, y1 The (x,y) coordinates of the second corner of the - * rectangular region - * \param lines The number of lines to scroll upwards - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * pros::screen::print(TEXT_MEDIUM, 1, "Line Here"); - * // Scrolls area of screen upwards slightly. including line of text - * pros::screen::scroll_area(0,0, 400, 200, 3); - * } - * \endcode - */ -std::uint32_t scroll_area( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1, - std::int16_t lines -); - -/** - * Copy a screen region (designated by a rectangle) from an off-screen buffer - * to the screen - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first corner of the - * rectangular region of the screen - * \param x1, y1 The (x,y) coordinates of the second corner of the - * rectangular region of the screen - * \param buf Off-screen buffer containing screen data - * \param stride Off-screen buffer width in pixels, such that image size - * is stride-padding - * - * \return 1 if there were no errors, or PROS_ERR if an error occured taking - * or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * uint32_t* buf = malloc(sizeof(uint32_t) * 400 * 200); - * pros::screen::print(TEXT_MEDIUM, 1, "Line Here"); - * // Copies area of the screen including text - * pros::screen::copy_area(0, 0, 400, 200, (uint32_t*)buf, 400 + 1); - * // Equation for stride is x2 - x1 + 1 - * } - * \endcode - */ -std::uint32_t copy_area( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1, - uint32_t* buf, - const std::int32_t stride -); - -/** - * Draw a single pixel on the screen using the current pen color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the pixel - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * int i = 0; - * void opcontrol() { - * while(i < 200){ - * pros::screen::draw_pixel(100,i++); - * // Draws a line at x = 100 gradually down the screen, pixel by pixel - * pros::delay(200); - * } - * } - * \endcode - */ -std::uint32_t draw_pixel(const std::int16_t x, const std::int16_t y); - -/** - * Erase a pixel from the screen (Sets the location) - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the erased - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Color the Screen in Red - * pros::screen::set_pen(red); - * pros::screen::fill_rect(0,0,400,200); - * int i = 0; - * while(i < 200){ - * pros::screen::erase_pixel(100,i++); - * // Erases a line at x = 100 gradually down the screen, pixel by pixel - * pros::delay(200); - * } - * } - * \endcode - */ -std::uint32_t erase_pixel(const std::int16_t x, const std::int16_t y); - -/** - * Draw a line on the screen using the current pen color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x, y) coordinates of the first point of the line - * \param x1, y1 The (x, y) coordinates of the second point of the line - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * pros::screen::set_pen(red); - * // Draw line down the screen at x = 100 - * pros::screen::draw_line(100,0,100,200); - * } - * \endcode - */ -std::uint32_t draw_line( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -); - -/** - * Erase a line on the screen using the current eraser color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x, y) coordinates of the first point of the line - * \param x1, y1 The (x, y) coordinates of the second point of the line - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Color the Screen in Red - * pros::screen::set_pen(red); - * pros::screen::fill_rect(0,0,400,200); - * // Erase line down the screen at x = 100 - * pros::screen::erase_line(100,0,100,200); - * } - * \endcode - */ -std::uint32_t erase_line( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -); - -/** - * Draw a rectangle on the screen using the current pen color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first point of the rectangle - * \param x1, y1 The (x,y) coordinates of the second point of the rectangle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * pros::screen::set_pen(red); - * pros::screen::draw_rect(1,1,480,200); - * } - * \endcode - */ -std::uint32_t draw_rect( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -); - -/** - * Erase a rectangle on the screen using the current eraser color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first point of the rectangle - * \param x1, y1 The (x,y) coordinates of the second point of the rectangle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Draw Box Around Half the Screen in Red - * pros::screen::set_eraser(red); - * pros::screen::erase_rect(5,5,240,200); - * } - * \endcode - */ -std::uint32_t erase_rect( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -); - -/** - * Fill a rectangular region of the screen using the current pen - * color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x0, y0 The (x,y) coordinates of the first point of the rectangle - * \param x1, y1 The (x,y) coordinates of the second point of the rectangle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Fill Around Half the Screen in Red - * pros::screen::set_pen(red); - * pros::screen::fill_rect(5,5,240,200); - * } - * \endcode - */ -std::uint32_t fill_rect( - const std::int16_t x0, - const std::int16_t y0, - const std::int16_t x1, - const std::int16_t y1 -); - -/** - * Draw a circle on the screen using the current pen color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the center of the circle - * \param r The radius of the circle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * // Draw a circle with radius of 100 in red - * pros::screen::set_pen(red); - * pros::screen::draw_circle(240, 200, 100); - * } - * \endcode - */ -std::uint32_t draw_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius); - -/** - * Erase a circle on the screen using the current eraser color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the center of the circle - * \param r The radius of the circle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * pros::screen::set_pen(red); - * pros::screen::fill_rect(5,5,240,200); - * // Erase a circle with radius of 100 in blue - * pros::screen::set_pen(blue); - * pros::screen::erase_circle(240, 200, 100); - * } - * \endcode - */ -std::uint32_t erase_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius); - -/** - * Fill a circular region of the screen using the current pen - * color - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param x, y The (x,y) coordinates of the center of the circle - * \param r The radius of the circle - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * taking or returning the screen mutex. - * - * \b Example - * \code - * void opcontrol() { - * pros::screen::set_pen(red); - * pros::screen::fill_rect(5,5,240,200); - * // Fill a circlular area with radius of 100 in blue - * pros::screen::set_pen(blue); - * pros::screen::fill_circle(240, 200, 100); - * } - * \endcode - */ -std::uint32_t fill_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius); - -/******************************************************************************/ -/** Screen Text Display Functions **/ -/** **/ -/** These functions allow programmers to display text on the v5 screen **/ -/******************************************************************************/ - -/** - * Print a formatted string to the screen, overwrite available for printing at location too. - * - * Will default to a medium sized font by default if invalid txt_fmt is given. - * - * \param txt_fmt Text format enum that determines if the text is medium, large, medium_center, or - * large_center. (DOES NOT SUPPORT SMALL) - * \param line The line number on which to print - * \param x The (x,y) coordinates of the top left corner of the string - * \param y The (x,y) coordinates of the top left corner of the string - * \param fmt Format string - * \param ... Optional list of arguments for the format string - * - * \b Example - * \code - * void opcontrol() { - * int i = 0; - * pros::screen::set_pen(blue); - * while(1){ - * // Will print seconds started since program started on line 3 - * pros::screen::print(pros::TEXT_MEDIUM, 3, "Seconds Passed: %3d", i++); - * pros::delay(1000); - * } - * } - */ -template -void -print(pros::text_format_e_t txt_fmt, const std::int16_t line, const char* text, Params... args) { - pros::c::screen_print(txt_fmt, line, text, convert_args(args)...); -} - -template -void print( - pros::text_format_e_t txt_fmt, - const std::int16_t x, - const std::int16_t y, - const char* text, - Params... args -) { - pros::c::screen_print_at(txt_fmt, x, y, text, convert_args(args)...); -} - -/******************************************************************************/ -/** Screen Touch Functions **/ -/** **/ -/** These functions allow programmers to access **/ -/** information about screen touches **/ -/******************************************************************************/ - -/** - * Gets the touch status of the last touch of the screen. - * - * \return The last_touch_e_t enum specifier that indicates the last touch status of the screen - * (E_TOUCH_EVENT_RELEASE, E_TOUCH_EVENT_PRESS, or E_TOUCH_EVENT_PRESS_AND_HOLD). This will be - * released by default if no action was taken. If an error occured, the screen_touch_status_s_t will - * have its last_touch_e_t enum specifier set to E_TOUCH_ERR, and other values set to -1. - * - * \b Example - * \code - * void opcontrol() { - * int i = 0; - * pros::screen_touch_status_s_t status; - * while(1){ - * status = pros::touch_status(); - * - * // Will print various information about the last touch - * pros::screen::print(TEXT_MEDIUM, 1, "Touch Status (Type): %d", status.touch_status); - * pros::screen::print(TEXT_MEDIUM, 2, "Last X: %d", status.x); - * pros::screen::print(TEXT_MEDIUM, 3, "Last Y: %d", status.y); - * pros::screen::print(TEXT_MEDIUM, 4, "Press Count: %d", status.press_count); - * pros::screen::print(TEXT_MEDIUM, 5, "Release Count: %d", status.release_count); - * pros::delay(20); - * } - * } - * \endcode - */ -screen_touch_status_s_t touch_status(); - -/** - * Assigns a callback function to be called when a certain touch event happens. - * - * This function uses the following values of errno when an error state is - * reached: - * EACCESS - Another resource is currently trying to access the screen mutex. - * - * \param cb Function pointer to callback when event type happens - * \param event_type Touch event that will trigger the callback. - * - * \return 1 if there were no errors, or PROS_ERR if an error occured - * while taking or returning the screen mutex. - * - * \b Example - * \code - * touch_event_cb_fn_t changePixel(){ - * pros::screen_touch_status_s_t status = pros::screen::touch_status(); - * pros::screen::draw_pixel(status.x,status.y); - * return NULL; - * } - * - * void opcontrol() { - * pros::screen::touch_callback(changePixel(), TOUCH_PRESSED); - * while(1) { - * pros::delay(20); - * } - * } - * \endcode - */ -std::uint32_t touch_callback(touch_event_cb_fn_t cb, last_touch_e_t event_type); - -} // namespace screen - -} // namespace pros - -extern __attribute__((weak)) void lvgl_init() {} - -///@} -#endif // header guard From c8568229b41096d9f473c899d7900f9f26932276 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 3 May 2025 15:30:15 -0700 Subject: [PATCH 06/41] remove color headers --- include/pros/colors.h | 204 ---------------------------------------- include/pros/colors.hpp | 189 ------------------------------------- 2 files changed, 393 deletions(-) delete mode 100644 include/pros/colors.h delete mode 100644 include/pros/colors.hpp diff --git a/include/pros/colors.h b/include/pros/colors.h deleted file mode 100644 index faed7f67..00000000 --- a/include/pros/colors.h +++ /dev/null @@ -1,204 +0,0 @@ -/** - * \file pros/colors.h - * - * Contains macro definitions of colors (as `uint32_t`) - * - * This file should not be modified by users, since it gets replaced whenever - * a kernel upgrade occurs. - * - * \copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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 c-colors Colors C API - */ - -/** - * \ingroup c-colors - * \note These functions can be used for dynamic device instantiation. - */ - -/** - * \addtogroup c-colors - * @{ - */ - -#ifndef _PROS_COLORS_H_ -#define _PROS_COLORS_H_ - -#define RGB2COLOR(R, G, B) ((R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff)) -#define COLOR2R(COLOR) ((COLOR >> 16) & 0xff) -#define COLOR2G(COLOR) ((COLOR >> 8) & 0xff) -#define COLOR2B(COLOR) (COLOR & 0xff) - -#ifdef __cplusplus -namespace pros { -namespace c { -#endif - -/** - * \enum color_e_t - * @brief - * Enum of possible colors - * - * Contains common colors, all members are self descriptive. - */ -typedef enum color_e { - COLOR_ALICE_BLUE = 0x00F0F8FF, - COLOR_ANTIQUE_WHITE = 0x00FAEBD7, - COLOR_AQUA = 0x0000FFFF, - COLOR_AQUAMARINE = 0x007FFFD4, - COLOR_AZURE = 0x00F0FFFF, - COLOR_BEIGE = 0x00F5F5DC, - COLOR_BISQUE = 0x00FFE4C4, - COLOR_BLACK = 0x00000000, - COLOR_BLANCHED_ALMOND = 0x00FFEBCD, - COLOR_BLUE = 0x000000FF, - COLOR_BLUE_VIOLET = 0x008A2BE2, - COLOR_BROWN = 0x00A52A2A, - COLOR_BURLY_WOOD = 0x00DEB887, - COLOR_CADET_BLUE = 0x005F9EA0, - COLOR_CHARTREUSE = 0x007FFF00, - COLOR_CHOCOLATE = 0x00D2691E, - COLOR_CORAL = 0x00FF7F50, - COLOR_CORNFLOWER_BLUE = 0x006495ED, - COLOR_CORNSILK = 0x00FFF8DC, - COLOR_CRIMSON = 0x00DC143C, - COLOR_CYAN = 0x0000FFFF, - COLOR_DARK_BLUE = 0x0000008B, - COLOR_DARK_CYAN = 0x00008B8B, - COLOR_DARK_GOLDENROD = 0x00B8860B, - COLOR_DARK_GRAY = 0x00A9A9A9, - COLOR_DARK_GREY = COLOR_DARK_GRAY, - COLOR_DARK_GREEN = 0x00006400, - COLOR_DARK_KHAKI = 0x00BDB76B, - COLOR_DARK_MAGENTA = 0x008B008B, - COLOR_DARK_OLIVE_GREEN = 0x00556B2F, - COLOR_DARK_ORANGE = 0x00FF8C00, - COLOR_DARK_ORCHID = 0x009932CC, - COLOR_DARK_RED = 0x008B0000, - COLOR_DARK_SALMON = 0x00E9967A, - COLOR_DARK_SEA_GREEN = 0x008FBC8F, - COLOR_DARK_SLATE_GRAY = 0x002F4F4F, - COLOR_DARK_SLATE_GREY = COLOR_DARK_SLATE_GRAY, - COLOR_DARK_TURQUOISE = 0x0000CED1, - COLOR_DARK_VIOLET = 0x009400D3, - COLOR_DEEP_PINK = 0x00FF1493, - COLOR_DEEP_SKY_BLUE = 0x0000BFFF, - COLOR_DIM_GRAY = 0x00696969, - COLOR_DIM_GREY = COLOR_DIM_GRAY, - COLOR_DODGER_BLUE = 0x001E90FF, - COLOR_FIRE_BRICK = 0x00B22222, - COLOR_FLORAL_WHITE = 0x00FFFAF0, - COLOR_FOREST_GREEN = 0x00228B22, - COLOR_FUCHSIA = 0x00FF00FF, - COLOR_GAINSBORO = 0x00DCDCDC, - COLOR_GHOST_WHITE = 0x00F8F8FF, - COLOR_GOLD = 0x00FFD700, - COLOR_GOLDENROD = 0x00DAA520, - COLOR_GRAY = 0x00808080, - COLOR_GREY = COLOR_GRAY, - COLOR_GREEN = 0x00008000, - COLOR_GREEN_YELLOW = 0x00ADFF2F, - COLOR_HONEYDEW = 0x00F0FFF0, - COLOR_HOT_PINK = 0x00FF69B4, - COLOR_INDIAN_RED = 0x00CD5C5C, - COLOR_INDIGO = 0x004B0082, - COLOR_IVORY = 0x00FFFFF0, - COLOR_KHAKI = 0x00F0E68C, - COLOR_LAVENDER = 0x00E6E6FA, - COLOR_LAVENDER_BLUSH = 0x00FFF0F5, - COLOR_LAWN_GREEN = 0x007CFC00, - COLOR_LEMON_CHIFFON = 0x00FFFACD, - COLOR_LIGHT_BLUE = 0x00ADD8E6, - COLOR_LIGHT_CORAL = 0x00F08080, - COLOR_LIGHT_CYAN = 0x00E0FFFF, - COLOR_LIGHT_GOLDENROD_YELLOW = 0x00FAFAD2, - COLOR_LIGHT_GREEN = 0x0090EE90, - COLOR_LIGHT_GRAY = 0x00D3D3D3, - COLOR_LIGHT_GREY = COLOR_LIGHT_GRAY, - COLOR_LIGHT_PINK = 0x00FFB6C1, - COLOR_LIGHT_SALMON = 0x00FFA07A, - COLOR_LIGHT_SEA_GREEN = 0x0020B2AA, - COLOR_LIGHT_SKY_BLUE = 0x0087CEFA, - COLOR_LIGHT_SLATE_GRAY = 0x00778899, - COLOR_LIGHT_SLATE_GREY = COLOR_LIGHT_SLATE_GRAY, - COLOR_LIGHT_STEEL_BLUE = 0x00B0C4DE, - COLOR_LIGHT_YELLOW = 0x00FFFFE0, - COLOR_LIME = 0x0000FF00, - COLOR_LIME_GREEN = 0x0032CD32, - COLOR_LINEN = 0x00FAF0E6, - COLOR_MAGENTA = 0x00FF00FF, - COLOR_MAROON = 0x00800000, - COLOR_MEDIUM_AQUAMARINE = 0x0066CDAA, - COLOR_MEDIUM_BLUE = 0x000000CD, - COLOR_MEDIUM_ORCHID = 0x00BA55D3, - COLOR_MEDIUM_PURPLE = 0x009370DB, - COLOR_MEDIUM_SEA_GREEN = 0x003CB371, - COLOR_MEDIUM_SLATE_BLUE = 0x007B68EE, - COLOR_MEDIUM_SPRING_GREEN = 0x0000FA9A, - COLOR_MEDIUM_TURQUOISE = 0x0048D1CC, - COLOR_MEDIUM_VIOLET_RED = 0x00C71585, - COLOR_MIDNIGHT_BLUE = 0x00191970, - COLOR_MINT_CREAM = 0x00F5FFFA, - COLOR_MISTY_ROSE = 0x00FFE4E1, - COLOR_MOCCASIN = 0x00FFE4B5, - COLOR_NAVAJO_WHITE = 0x00FFDEAD, - COLOR_NAVY = 0x00000080, - COLOR_OLD_LACE = 0x00FDF5E6, - COLOR_OLIVE = 0x00808000, - COLOR_OLIVE_DRAB = 0x006B8E23, - COLOR_ORANGE = 0x00FFA500, - COLOR_ORANGE_RED = 0x00FF4500, - COLOR_ORCHID = 0x00DA70D6, - COLOR_PALE_GOLDENROD = 0x00EEE8AA, - COLOR_PALE_GREEN = 0x0098FB98, - COLOR_PALE_TURQUOISE = 0x00AFEEEE, - COLOR_PALE_VIOLET_RED = 0x00DB7093, - COLOR_PAPAY_WHIP = 0x00FFEFD5, - COLOR_PEACH_PUFF = 0x00FFDAB9, - COLOR_PERU = 0x00CD853F, - COLOR_PINK = 0x00FFC0CB, - COLOR_PLUM = 0x00DDA0DD, - COLOR_POWDER_BLUE = 0x00B0E0E6, - COLOR_PURPLE = 0x00800080, - COLOR_RED = 0x00FF0000, - COLOR_ROSY_BROWN = 0x00BC8F8F, - COLOR_ROYAL_BLUE = 0x004169E1, - COLOR_SADDLE_BROWN = 0x008B4513, - COLOR_SALMON = 0x00FA8072, - COLOR_SANDY_BROWN = 0x00F4A460, - COLOR_SEA_GREEN = 0x002E8B57, - COLOR_SEASHELL = 0x00FFF5EE, - COLOR_SIENNA = 0x00A0522D, - COLOR_SILVER = 0x00C0C0C0, - COLOR_SKY_BLUE = 0x0087CEEB, - COLOR_SLATE_BLUE = 0x006A5ACD, - COLOR_SLATE_GRAY = 0x00708090, - COLOR_SLATE_GREY = COLOR_SLATE_GRAY, - COLOR_SNOW = 0x00FFFAFA, - COLOR_SPRING_GREEN = 0x0000FF7F, - COLOR_STEEL_BLUE = 0x004682B4, - COLOR_TAN = 0x00D2B48C, - COLOR_TEAL = 0x00008080, - COLOR_THISTLE = 0x00D8BFD8, - COLOR_TOMATO = 0x00FF6347, - COLOR_TURQUOISE = 0x0040E0D0, - COLOR_VIOLET = 0x00EE82EE, - COLOR_WHEAT = 0x00F5DEB3, - COLOR_WHITE = 0x00FFFFFF, - COLOR_WHITE_SMOKE = 0x00F5F5F5, - COLOR_YELLOW = 0x00FFFF00, - COLOR_YELLOW_GREEN = 0x009ACD32, -} color_e_t; - -///@} - -#ifdef __cplusplus -} // namespace c -} // namespace pros -#endif - -#endif // _PROS_COLORS_H_ diff --git a/include/pros/colors.hpp b/include/pros/colors.hpp deleted file mode 100644 index 89875f56..00000000 --- a/include/pros/colors.hpp +++ /dev/null @@ -1,189 +0,0 @@ -/** - * \file pros/colors.hpp - * - * Contains enum class definitions of colors - * - * This file should not be modified by users, since it gets replaced whenever - * a kernel upgrade occurs. - * - * \copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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 cpp-colors C++ Color API - */ -#ifndef _PROS_COLORS_HPP_ -#define _PROS_COLORS_HPP_ - -namespace pros { -/** - * \ingroup cpp-colors - */ - -/** - * \addtogroup cpp-colors - * @{ - */ - -/** - * \enum Color - * @brief - * Enum class of possible colors - * - * Contains common colors, all members are self descriptive. - */ -enum class Color { - alice_blue = 0x00F0F8FF, - antique_white = 0x00FAEBD7, - aqua = 0x0000FFFF, - aquamarine = 0x007FFFD4, - azure = 0x00F0FFFF, - beige = 0x00F5F5DC, - bisque = 0x00FFE4C4, - black = 0x00000000, - blanched_almond = 0x00FFEBCD, - blue = 0x000000FF, - blue_violet = 0x008A2BE2, - brown = 0x00A52A2A, - burly_wood = 0x00DEB887, - cadet_blue = 0x005F9EA0, - chartreuse = 0x007FFF00, - chocolate = 0x00D2691E, - coral = 0x00FF7F50, - cornflower_blue = 0x006495ED, - cornsilk = 0x00FFF8DC, - crimson = 0x00DC143C, - cyan = 0x0000FFFF, - dark_blue = 0x0000008B, - dark_cyan = 0x00008B8B, - dark_goldenrod = 0x00B8860B, - dark_gray = 0x00A9A9A9, - dark_grey = dark_gray, - dark_green = 0x00006400, - dark_khaki = 0x00BDB76B, - dark_magenta = 0x008B008B, - dark_olive_green = 0x00556B2F, - dark_orange = 0x00FF8C00, - dark_orchid = 0x009932CC, - dark_red = 0x008B0000, - dark_salmon = 0x00E9967A, - dark_sea_green = 0x008FBC8F, - dark_slate_gray = 0x002F4F4F, - dark_slate_grey = dark_slate_gray, - dark_turquoise = 0x0000CED1, - dark_violet = 0x009400D3, - deep_pink = 0x00FF1493, - deep_sky_blue = 0x0000BFFF, - dim_gray = 0x00696969, - dim_grey = dim_gray, - dodger_blue = 0x001E90FF, - fire_brick = 0x00B22222, - floral_white = 0x00FFFAF0, - forest_green = 0x00228B22, - fuchsia = 0x00FF00FF, - gainsboro = 0x00DCDCDC, - ghost_white = 0x00F8F8FF, - gold = 0x00FFD700, - goldenrod = 0x00DAA520, - gray = 0x00808080, - grey = gray, - green = 0x00008000, - green_yellow = 0x00ADFF2F, - honeydew = 0x00F0FFF0, - hot_pink = 0x00FF69B4, - indian_red = 0x00CD5C5C, - indigo = 0x004B0082, - ivory = 0x00FFFFF0, - khaki = 0x00F0E68C, - lavender = 0x00E6E6FA, - lavender_blush = 0x00FFF0F5, - lawn_green = 0x007CFC00, - lemon_chiffon = 0x00FFFACD, - light_blue = 0x00ADD8E6, - light_coral = 0x00F08080, - light_cyan = 0x00E0FFFF, - light_goldenrod_yellow = 0x00FAFAD2, - light_green = 0x0090EE90, - light_gray = 0x00D3D3D3, - light_grey = light_gray, - light_pink = 0x00FFB6C1, - light_salmon = 0x00FFA07A, - light_sea_green = 0x0020B2AA, - light_sky_blue = 0x0087CEFA, - light_slate_gray = 0x00778899, - light_slate_grey = light_slate_gray, - light_steel_blue = 0x00B0C4DE, - light_yellow = 0x00FFFFE0, - lime = 0x0000FF00, - lime_green = 0x0032CD32, - linen = 0x00FAF0E6, - magenta = 0x00FF00FF, - maroon = 0x00800000, - medium_aquamarine = 0x0066CDAA, - medium_blue = 0x000000CD, - medium_orchid = 0x00BA55D3, - medium_purple = 0x009370DB, - medium_sea_green = 0x003CB371, - medium_slate_blue = 0x007B68EE, - medium_spring_green = 0x0000FA9A, - medium_turquoise = 0x0048D1CC, - medium_violet_red = 0x00C71585, - midnight_blue = 0x00191970, - mint_cream = 0x00F5FFFA, - misty_rose = 0x00FFE4E1, - moccasin = 0x00FFE4B5, - navajo_white = 0x00FFDEAD, - navy = 0x00000080, - old_lace = 0x00FDF5E6, - olive = 0x00808000, - olive_drab = 0x006B8E23, - orange = 0x00FFA500, - orange_red = 0x00FF4500, - orchid = 0x00DA70D6, - pale_goldenrod = 0x00EEE8AA, - pale_green = 0x0098FB98, - pale_turquoise = 0x00AFEEEE, - pale_violet_red = 0x00DB7093, - papay_whip = 0x00FFEFD5, - peach_puff = 0x00FFDAB9, - peru = 0x00CD853F, - pink = 0x00FFC0CB, - plum = 0x00DDA0DD, - powder_blue = 0x00B0E0E6, - purple = 0x00800080, - red = 0x00FF0000, - rosy_brown = 0x00BC8F8F, - royal_blue = 0x004169E1, - saddle_brown = 0x008B4513, - salmon = 0x00FA8072, - sandy_brown = 0x00F4A460, - sea_green = 0x002E8B57, - seashell = 0x00FFF5EE, - sienna = 0x00A0522D, - silver = 0x00C0C0C0, - sky_blue = 0x0087CEEB, - slate_blue = 0x006A5ACD, - slate_gray = 0x00708090, - slate_grey = slate_gray, - snow = 0x00FFFAFA, - spring_green = 0x0000FF7F, - steel_blue = 0x004682B4, - tan = 0x00D2B48C, - teal = 0x00008080, - thistle = 0x00D8BFD8, - tomato = 0x00FF6347, - turquoise = 0x0040E0D0, - violet = 0x00EE82EE, - wheat = 0x00F5DEB3, - white = 0x00FFFFFF, - white_smoke = 0x00F5F5F5, - yellow = 0x00FFFF00, - yellow_green = 0x009ACD32, -}; -} // namespace pros - -///@} - -#endif //_PROS_COLORS_HPP_ From 40df79a56d183ec81e569eee0eab865d9eefe227 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 3 May 2025 15:31:21 -0700 Subject: [PATCH 07/41] remove errors.h --- include/pros/error.h | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 include/pros/error.h diff --git a/include/pros/error.h b/include/pros/error.h deleted file mode 100644 index e1d03b6b..00000000 --- a/include/pros/error.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * \file pros/error.h - * - * Contains macro definitions for return types, mostly errors - * - * This file should not be modified by users, since it gets replaced whenever - * a kernel upgrade occurs. - * - * \copyright Copyright (c) 2017-2024, Purdue University ACM SIGBots. - * - * 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/. - */ -#ifndef _PROS_ERROR_H_ -#define _PROS_ERROR_H_ - -#include "limits.h" - -// Different Byte Size Errors - -/// @brief -/// Return This on Byte Sized Return Error -#define PROS_ERR_BYTE (INT8_MAX) - -/// @brief -/// Return This on 2 Byte Sized Return Error -#define PROS_ERR_2_BYTE (INT16_MAX) - -/// @brief -/// Return This on 4 Byte Sized Return Error -#define PROS_ERR (INT32_MAX) - -/// @brief -/// Return This on 8 Byte Sized Return Error -#define PROS_ERR_F (INFINITY) - -/// @brief -/// Return This on Success (1) -#define PROS_SUCCESS (1) - -#endif From 77ce640953b028e66e9cb900d39d1c7b97bd3918 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 3 May 2025 23:20:41 -0700 Subject: [PATCH 08/41] reimplement battery API --- include/common/result.hpp | 14 ++++++++ include/pros/devices/battery.hpp | 15 ++++++++ include/pros/devices/devices.hpp | 30 ++++++++++++++++ src/devices/battery.c | 55 ---------------------------- src/devices/battery.cpp | 62 ++++++++++++++++++-------------- 5 files changed, 95 insertions(+), 81 deletions(-) create mode 100644 include/pros/devices/battery.hpp create mode 100644 include/pros/devices/devices.hpp delete mode 100644 src/devices/battery.c diff --git a/include/common/result.hpp b/include/common/result.hpp index 799c0c5b..bdc9f3a3 100644 --- a/include/common/result.hpp +++ b/include/common/result.hpp @@ -41,6 +41,20 @@ class ResultError { std::optional runtime_data; }; +/** + * @brief Unknown Error + * + */ +class UnknownError : public ResultError { + public: + template + requires std::convertible_to + UnknownError(T&& message) + : message(std::forward(message)) {} + + std::string message; +}; + /** * @brief Trait to define a "sentinel" value for types indicating an error state. * @tparam T Type to provide a sentinel value for. diff --git a/include/pros/devices/battery.hpp b/include/pros/devices/battery.hpp new file mode 100644 index 00000000..ea98e19d --- /dev/null +++ b/include/pros/devices/battery.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "common/result.hpp" + +namespace zest { + +class Battery { + public: + static Result get_capacity(); + static Result get_current(); + static Result get_temperature(); + static Result get_voltage(); +}; + +} // namespace zest \ No newline at end of file diff --git a/include/pros/devices/devices.hpp b/include/pros/devices/devices.hpp new file mode 100644 index 00000000..b039ad0e --- /dev/null +++ b/include/pros/devices/devices.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "common/result.hpp" + +namespace zest { + +enum class DeviceType { + Battery, +}; + +/** + * @brief V5 Port Mismatch Error + * + */ +class V5PortMismatchError : public ResultError { + public: + /** + * @brief Construct a new V5 Port Mismatch Error object + * + * @param expected the device expected to be on the port + * @param actual the device that is actually on the port + */ + V5PortMismatchError(DeviceType expected, DeviceType actual) + : expected(expected), + actual(actual) {} + + DeviceType expected; + DeviceType actual; +}; +} // namespace zest \ No newline at end of file diff --git a/src/devices/battery.c b/src/devices/battery.c deleted file mode 100644 index 7fc29fba..00000000 --- a/src/devices/battery.c +++ /dev/null @@ -1,55 +0,0 @@ -/** - * \file devices/battery.c - * - * Contains functions for interacting with the V5 Battery. - * - * \copyright Copyright (c) 2017-2024, 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/. - */ - -#include "v5_api_patched.h" -#include "vdml/vdml.h" - -int32_t battery_get_voltage(void) { - if (!internal_port_mutex_take(V5_PORT_BATTERY)) { - errno = EACCES; - return PROS_ERR; - } - double rtn = vexBatteryVoltageGet(); - internal_port_mutex_give(V5_PORT_BATTERY); - return rtn; -} - -int32_t battery_get_current(void) { - if (!internal_port_mutex_take(V5_PORT_BATTERY)) { - errno = EACCES; - return PROS_ERR; - } - double rtn = vexBatteryCurrentGet(); - internal_port_mutex_give(V5_PORT_BATTERY); - return rtn; -} - -double battery_get_temperature(void) { - if (!internal_port_mutex_take(V5_PORT_BATTERY)) { - errno = EACCES; - return PROS_ERR_F; - } - double rtn = vexBatteryTemperatureGet(); - internal_port_mutex_give(V5_PORT_BATTERY); - return rtn; -} - -double battery_get_capacity(void) { - if (!internal_port_mutex_take(V5_PORT_BATTERY)) { - errno = EACCES; - return PROS_ERR_F; - } - double rtn = vexBatteryCapacityGet(); - internal_port_mutex_give(V5_PORT_BATTERY); - return rtn; -} diff --git a/src/devices/battery.cpp b/src/devices/battery.cpp index a7217064..c6047a55 100644 --- a/src/devices/battery.cpp +++ b/src/devices/battery.cpp @@ -1,36 +1,46 @@ -/** - * \file devices/battery.cpp - * - * Contains functions for interacting with the V5 Battery. - * - * \copyright Copyright (c) 2017-2024, 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/. - */ +#include "pros/devices/battery.hpp" -#include "pros/misc.h" +#include "src/devices/vdml.hpp" +#include "v5_api_patched.h" -namespace pros { -namespace battery { -using namespace pros::c; +#include -double get_capacity(void) { - return battery_get_capacity(); +constexpr uint8_t PORT = 25; + +namespace zest { +Result Battery::get_capacity() { + std::lock_guard lock(port_mutex_array.at(PORT)); + if (auto res = vexBatteryCapacityGet(); res == std::numeric_limits::max()) { + return UnknownError("An unknown error has occurred"); + } else { + return res; + } } -int32_t get_current(void) { - return battery_get_current(); +Result Battery::get_current() { + std::lock_guard lock(port_mutex_array.at(PORT)); + if (auto res = vexBatteryCurrentGet(); res == std::numeric_limits::max()) { + return UnknownError("An unknown error has occurred"); + } else { + return res; + } } -double get_temperature(void) { - return battery_get_temperature(); +Result Battery::get_temperature() { + std::lock_guard lock(port_mutex_array.at(PORT)); + if (auto res = vexBatteryTemperatureGet(); res == std::numeric_limits::max()) { + return UnknownError("An unknown error has occurred"); + } else { + return res; + } } -int32_t get_voltage(void) { - return battery_get_voltage(); +Result Battery::get_voltage() { + std::lock_guard lock(port_mutex_array.at(PORT)); + if (auto res = vexBatteryVoltageGet(); res == std::numeric_limits::max()) { + return UnknownError("An unknown error has occurred"); + } else { + return res; + } } -} // namespace battery -} // namespace pros +} // namespace zest \ No newline at end of file From dcf2329096ae45fae44066b0fd2464503812b946 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Thu, 8 May 2025 09:08:05 -0700 Subject: [PATCH 09/41] start work on Port class --- include/api.h | 4 ---- src/devices/vdml.cpp | 3 --- src/devices/vdml.hpp | 23 ----------------------- src/system/dev/ser_driver.c | 2 ++ src/system/startup.cpp | 2 -- 5 files changed, 2 insertions(+), 32 deletions(-) delete mode 100644 src/devices/vdml.cpp delete mode 100644 src/devices/vdml.hpp diff --git a/include/api.h b/include/api.h index 090a9301..9bd126c8 100644 --- a/include/api.h +++ b/include/api.h @@ -39,16 +39,12 @@ #include #endif /* __cplusplus */ -#include "pros/colors.h" -#include "pros/error.h" #include "pros/misc.h" #include "pros/rtos.h" #ifdef __cplusplus - #include "pros/colors.hpp" #include "pros/misc.hpp" #include "pros/rtos.hpp" - #include "pros/screen.hpp" #endif #endif // _PROS_API_H_ diff --git a/src/devices/vdml.cpp b/src/devices/vdml.cpp deleted file mode 100644 index 748a7c8a..00000000 --- a/src/devices/vdml.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "src/devices/vdml.hpp" - -std::array port_mutex_array; \ No newline at end of file diff --git a/src/devices/vdml.hpp b/src/devices/vdml.hpp deleted file mode 100644 index 7e52f6ab..00000000 --- a/src/devices/vdml.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "pros/rtos.hpp" -#include "v5_apitypes_patched.h" - -#include - -extern std::array port_mutex_array; - -enum class V5Device { - None, ///< No device is plugged into the port - Motor, ///< A motor is plugged into the port - Rotation, ///< A rotation sensor is plugged into the port - Imu, ///< An inertial sensor is plugged into the port - Distance, ///< A distance sensor is plugged into the port - Radio, ///< A radio is plugged into the port - Vision, ///< A vision sensor is plugged into the port - Adi, ///< This port is an ADI expander - Optical, ///< An optical sensor is plugged into the port - Gps, ///< A GPS sensor is plugged into the port - AiVision, ///< An AI Vision sensor is plugged into the port - Serial, ///< A serial device is plugged into the port -}; diff --git a/src/system/dev/ser_driver.c b/src/system/dev/ser_driver.c index eac72ce2..277b8891 100644 --- a/src/system/dev/ser_driver.c +++ b/src/system/dev/ser_driver.c @@ -23,6 +23,8 @@ #include +#define PROS_ERR INT32_MAX + #define VEX_SERIAL_BUFFER_SIZE 2047 // ser_file_arg is 2 words (64 bits). The first word is the stream_id diff --git a/src/system/startup.cpp b/src/system/startup.cpp index 1ea4979d..de423957 100644 --- a/src/system/startup.cpp +++ b/src/system/startup.cpp @@ -32,7 +32,6 @@ void graphical_context_daemon_initialize(); void display_initialize() {} void rtos_sched_start(); -void vdml_initialize(); // libc initialization void __libc_init_array(); @@ -54,7 +53,6 @@ vcodesig vexCodeSig = {V5_SIG_MAGIC, V5_SIG_TYPE_USER, V5_SIG_OWNER_PARTNER, V5_ static void pros_init() { rtos_initialize(); vfs_initialize(); - vdml_initialize(); graphical_context_daemon_initialize(); display_initialize(); // Note: system_daemon_initialize must be called last, per design requirements. From e91f58b8894510dd542e29a56226f7647f8e1cc6 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 9 May 2025 08:45:49 -0700 Subject: [PATCH 10/41] add port types --- include/pros/devices/port.hpp | 103 ++++++++++++++++++++++++++++++++++ src/devices/port.cpp | 18 ++++++ 2 files changed, 121 insertions(+) create mode 100644 include/pros/devices/port.hpp create mode 100644 src/devices/port.cpp diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp new file mode 100644 index 00000000..852c4e09 --- /dev/null +++ b/include/pros/devices/port.hpp @@ -0,0 +1,103 @@ +#pragma once + +#include "pros/rtos.hpp" + +#include + +namespace zest { + +class SmartPort { + public: + static constexpr SmartPort from_number(uint8_t number) { + return SmartPort(number - 1); + } + + static constexpr SmartPort from_index(uint8_t index) { + return SmartPort(index); + } + + constexpr uint8_t as_number() { + return m_index - 1; + } + + constexpr uint8_t as_index() { + return m_index; + } + + private: + constexpr SmartPort(uint8_t index) + : m_index(index) {} + + uint8_t m_index; +}; + +namespace ports { + +constexpr auto PORT_1 = SmartPort::from_number(1); +constexpr auto PORT_2 = SmartPort::from_number(2); +constexpr auto PORT_3 = SmartPort::from_number(3); +constexpr auto PORT_4 = SmartPort::from_number(4); +constexpr auto PORT_5 = SmartPort::from_number(5); +constexpr auto PORT_6 = SmartPort::from_number(6); +constexpr auto PORT_7 = SmartPort::from_number(7); +constexpr auto PORT_8 = SmartPort::from_number(8); +constexpr auto PORT_9 = SmartPort::from_number(9); +constexpr auto PORT_10 = SmartPort::from_number(10); +constexpr auto PORT_11 = SmartPort::from_number(11); +constexpr auto PORT_12 = SmartPort::from_number(12); +constexpr auto PORT_13 = SmartPort::from_number(13); +constexpr auto PORT_14 = SmartPort::from_number(14); +constexpr auto PORT_15 = SmartPort::from_number(15); +constexpr auto PORT_16 = SmartPort::from_number(16); +constexpr auto PORT_17 = SmartPort::from_number(17); +constexpr auto PORT_18 = SmartPort::from_number(18); +constexpr auto PORT_19 = SmartPort::from_number(19); +constexpr auto PORT_20 = SmartPort::from_number(20); +constexpr auto PORT_21 = SmartPort::from_number(21); + +} // namespace ports + +class AdiPort { + public: + static constexpr AdiPort from_char(char port) { + return AdiPort(port); + } + + constexpr char as_char() { + return m_port; + } + + constexpr uint8_t as_index() { + return static_cast(m_port) - 65; + } + + private: + constexpr AdiPort(char port) { + // convert lowercase to uppercase if needed + if (port >= 97) { + port -= 32; + } + m_port = port; + } + + char m_port; +}; + +namespace ports { + +constexpr auto PORT_A = AdiPort::from_char('A'); +constexpr auto PORT_B = AdiPort::from_char('B'); +constexpr auto PORT_C = AdiPort::from_char('C'); +constexpr auto PORT_D = AdiPort::from_char('D'); +constexpr auto PORT_E = AdiPort::from_char('E'); +constexpr auto PORT_F = AdiPort::from_char('F'); +constexpr auto PORT_G = AdiPort::from_char('G'); +constexpr auto PORT_H = AdiPort::from_char('H'); + +} // namespace ports + +template +pros::RecursiveMutex& get_port_mutex(T&&) { + throw("can't get mutex for non-port object!"); +} +} // namespace zest \ No newline at end of file diff --git a/src/devices/port.cpp b/src/devices/port.cpp new file mode 100644 index 00000000..63ccfe10 --- /dev/null +++ b/src/devices/port.cpp @@ -0,0 +1,18 @@ +#include "pros/devices/port.hpp" + +#include "pros/rtos.hpp" +#include "v5_apitypes_patched.h" + +namespace zest { +template<> +pros::RecursiveMutex& get_port_mutex(SmartPort&& port) { + static std::array array; + return array.at(port.as_index()); +} + +template<> +pros::RecursiveMutex& get_port_mutex(AdiPort&& port) { + static std::array array; + return array.at(port.as_index()); +} +} // namespace zest \ No newline at end of file From cff2a5b9aa1bbe65403bcea1274e85ff29d180af Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 9 May 2025 09:04:22 -0700 Subject: [PATCH 11/41] fix battery.cpp build --- src/devices/battery.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/devices/battery.cpp b/src/devices/battery.cpp index c6047a55..1abbec47 100644 --- a/src/devices/battery.cpp +++ b/src/devices/battery.cpp @@ -1,15 +1,15 @@ #include "pros/devices/battery.hpp" -#include "src/devices/vdml.hpp" +#include "pros/devices/port.hpp" #include "v5_api_patched.h" #include -constexpr uint8_t PORT = 25; +constexpr auto BATTERY_PORT = zest::SmartPort::from_index(25); namespace zest { Result Battery::get_capacity() { - std::lock_guard lock(port_mutex_array.at(PORT)); + std::lock_guard lock(get_port_mutex(BATTERY_PORT)); if (auto res = vexBatteryCapacityGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { @@ -18,7 +18,7 @@ Result Battery::get_capacity() { } Result Battery::get_current() { - std::lock_guard lock(port_mutex_array.at(PORT)); + std::lock_guard lock(get_port_mutex(BATTERY_PORT)); if (auto res = vexBatteryCurrentGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { @@ -27,7 +27,7 @@ Result Battery::get_current() { } Result Battery::get_temperature() { - std::lock_guard lock(port_mutex_array.at(PORT)); + std::lock_guard lock(get_port_mutex(BATTERY_PORT)); if (auto res = vexBatteryTemperatureGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { @@ -36,7 +36,7 @@ Result Battery::get_temperature() { } Result Battery::get_voltage() { - std::lock_guard lock(port_mutex_array.at(PORT)); + std::lock_guard lock(get_port_mutex(BATTERY_PORT)); if (auto res = vexBatteryVoltageGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { From e9db49970b3d89a6bf000529e0b6355f14b6dc33 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 13:20:53 -0700 Subject: [PATCH 12/41] port bugfixes --- include/pros/devices/port.hpp | 83 +++++++++++++++++------------------ src/devices/port.cpp | 18 -------- 2 files changed, 40 insertions(+), 61 deletions(-) delete mode 100644 src/devices/port.cpp diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index 852c4e09..e3ce0f78 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -1,38 +1,34 @@ #pragma once -#include "pros/rtos.hpp" - -#include +#include namespace zest { - class SmartPort { public: - static constexpr SmartPort from_number(uint8_t number) { - return SmartPort(number - 1); + static constexpr SmartPort from_number(uint8_t port_number) { + return SmartPort(port_number - 1); } - static constexpr SmartPort from_index(uint8_t index) { - return SmartPort(index); + static constexpr SmartPort from_index(uint8_t port_index) { + return SmartPort(port_index); } - constexpr uint8_t as_number() { - return m_index - 1; + constexpr uint8_t as_number() const { + return m_index + 1; } - constexpr uint8_t as_index() { + constexpr uint8_t as_index() const { return m_index; } private: - constexpr SmartPort(uint8_t index) - : m_index(index) {} + constexpr SmartPort(int port_index) + : m_index(port_index) {} uint8_t m_index; }; namespace ports { - constexpr auto PORT_1 = SmartPort::from_number(1); constexpr auto PORT_2 = SmartPort::from_number(2); constexpr auto PORT_3 = SmartPort::from_number(3); @@ -54,50 +50,51 @@ constexpr auto PORT_18 = SmartPort::from_number(18); constexpr auto PORT_19 = SmartPort::from_number(19); constexpr auto PORT_20 = SmartPort::from_number(20); constexpr auto PORT_21 = SmartPort::from_number(21); - } // namespace ports class AdiPort { public: - static constexpr AdiPort from_char(char port) { - return AdiPort(port); + static constexpr AdiPort from_letter(char port) { + // if the index is provided as a character + if (port >= '0' && port <= '9') { + return AdiPort(port - '0'); + } + // convert to uppercase if needed + if (port >= 'a' && port <= 'z') { + port -= ('a' - 'A'); + } + // 'A' has index 0, 'B' has index 1, etc + return AdiPort(port - 'A'); } - constexpr char as_char() { - return m_port; + static constexpr AdiPort from_index(uint8_t index) { + return AdiPort(index); } - constexpr uint8_t as_index() { - return static_cast(m_port) - 65; + constexpr char as_letter() const { + return m_index; } - private: - constexpr AdiPort(char port) { - // convert lowercase to uppercase if needed - if (port >= 97) { - port -= 32; - } - m_port = port; + constexpr uint8_t as_index() const { + return m_index; } - char m_port; + private: + uint8_t m_index; + + constexpr AdiPort(uint8_t index) + : m_index(index) {} }; namespace ports { - -constexpr auto PORT_A = AdiPort::from_char('A'); -constexpr auto PORT_B = AdiPort::from_char('B'); -constexpr auto PORT_C = AdiPort::from_char('C'); -constexpr auto PORT_D = AdiPort::from_char('D'); -constexpr auto PORT_E = AdiPort::from_char('E'); -constexpr auto PORT_F = AdiPort::from_char('F'); -constexpr auto PORT_G = AdiPort::from_char('G'); -constexpr auto PORT_H = AdiPort::from_char('H'); +constexpr auto PORT_A = AdiPort::from_letter('A'); +constexpr auto PORT_B = AdiPort::from_letter('B'); +constexpr auto PORT_C = AdiPort::from_letter('C'); +constexpr auto PORT_D = AdiPort::from_letter('D'); +constexpr auto PORT_E = AdiPort::from_letter('E'); +constexpr auto PORT_F = AdiPort::from_letter('F'); +constexpr auto PORT_G = AdiPort::from_letter('G'); +constexpr auto PORT_H = AdiPort::from_letter('H'); } // namespace ports - -template -pros::RecursiveMutex& get_port_mutex(T&&) { - throw("can't get mutex for non-port object!"); -} } // namespace zest \ No newline at end of file diff --git a/src/devices/port.cpp b/src/devices/port.cpp deleted file mode 100644 index 63ccfe10..00000000 --- a/src/devices/port.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "pros/devices/port.hpp" - -#include "pros/rtos.hpp" -#include "v5_apitypes_patched.h" - -namespace zest { -template<> -pros::RecursiveMutex& get_port_mutex(SmartPort&& port) { - static std::array array; - return array.at(port.as_index()); -} - -template<> -pros::RecursiveMutex& get_port_mutex(AdiPort&& port) { - static std::array array; - return array.at(port.as_index()); -} -} // namespace zest \ No newline at end of file From 8147465808557e44f6619b28e1c562ec30aeb1b6 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 13:53:30 -0700 Subject: [PATCH 13/41] document SmartPort class --- include/pros/devices/port.hpp | 44 ++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index e3ce0f78..d9b44620 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -3,26 +3,68 @@ #include namespace zest { + +/** + * @brief Smart Port class. Represents a Smart Port on the V5 brain. + * + * @details Smart Ports may be represented as a 1-indexed number or a 0-indexed number. While the + * user expects a 1-indexed number (matching the labels on the brain), treating it as an index makes + * development easier. This class abstracts that away so we don't have to worry about it. + * + */ class SmartPort { public: + /** + * @brief Construct a Smart Port from its number + * + * @note the smart port labelled "1" on the brain has a port number of 1 + * + * @param port_number the port number, 1-indexed + * @return constexpr SmartPort + */ static constexpr SmartPort from_number(uint8_t port_number) { return SmartPort(port_number - 1); } + /** + * @brief Construct a Smart Port from its index + * + * @note the smart port labelled "1" on the brain has a port index of 0 + * + * @param port_index the port index, 0-indexed + * @return constexpr SmartPort + */ static constexpr SmartPort from_index(uint8_t port_index) { return SmartPort(port_index); } + /** + * @brief Get the Smart Port as a number (1-indexed) + * + * @return constexpr uint8_t + */ constexpr uint8_t as_number() const { return m_index + 1; } + /** + * @brief Get the Smart Port as an index (0-indexed) + * + * @return constexpr uint8_t + */ constexpr uint8_t as_index() const { return m_index; } private: - constexpr SmartPort(int port_index) + /** + * @brief construct a Smart Port from an index + * + * This constructor is private to enforce the use of the `from_number` and `from_index` member + * functions. Having this construct be public defeats the purpose of this class, which is to + * prevent bugs by abstracting the port index. + */ + explicit constexpr SmartPort(uint8_t port_index) : m_index(port_index) {} uint8_t m_index; From 7c42ce06d55b6cd44a5d21842bf77041d764a3fc Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 14:02:19 -0700 Subject: [PATCH 14/41] improve SmartPort documentation --- include/pros/devices/port.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index d9b44620..0805cf5e 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -7,10 +7,9 @@ namespace zest { /** * @brief Smart Port class. Represents a Smart Port on the V5 brain. * - * @details Smart Ports may be represented as a 1-indexed number or a 0-indexed number. While the + * Smart Ports may be represented as a 1-indexed number or a 0-indexed number. While the * user expects a 1-indexed number (matching the labels on the brain), treating it as an index makes * development easier. This class abstracts that away so we don't have to worry about it. - * */ class SmartPort { public: @@ -71,6 +70,13 @@ class SmartPort { }; namespace ports { +/* + * Physical smart ports have a number from 1 to 21 (inclusive). While compile-time error checking + * could prevent an invalid port being constructed, the error messages that would be produced + * wouldn't be very concise. + * However, if the user tried constructing a device on the imaginary port 42, the project wouldn't + * compile since PORT_42 isn't declared. This error message is much clearer. + */ constexpr auto PORT_1 = SmartPort::from_number(1); constexpr auto PORT_2 = SmartPort::from_number(2); constexpr auto PORT_3 = SmartPort::from_number(3); From 9f613f5e345a885eee396c6469578946faeab46a Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 14:21:43 -0700 Subject: [PATCH 15/41] document AdiPort class --- include/pros/devices/port.hpp | 79 +++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index 0805cf5e..7d6967d3 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -14,7 +14,7 @@ namespace zest { class SmartPort { public: /** - * @brief Construct a Smart Port from its number + * @brief Create a Smart Port using its number * * @note the smart port labelled "1" on the brain has a port number of 1 * @@ -26,7 +26,7 @@ class SmartPort { } /** - * @brief Construct a Smart Port from its index + * @brief Create a Smart Port using its index * * @note the smart port labelled "1" on the brain has a port index of 0 * @@ -100,11 +100,23 @@ constexpr auto PORT_20 = SmartPort::from_number(20); constexpr auto PORT_21 = SmartPort::from_number(21); } // namespace ports +/** + * @brief ADI Port class. Represents an ADI Port on a the brain or on a 3-wire expander. + * + * ADI Ports may be represented as a 0-indexed number, or a char (e.g 'a' or 'C'). This class + * provides an interface so the developer doesn't have to worry about conversions. + */ class AdiPort { public: - static constexpr AdiPort from_letter(char port) { + /** + * @brief Create an ADI Port using its character + * + * @param port can be lowercase, uppercase, or even an index + * @return constexpr AdiPort + */ + static constexpr AdiPort from_char(char port) { // if the index is provided as a character - if (port >= '0' && port <= '9') { + if (port >= '0' && port <= '8') { return AdiPort(port - '0'); } // convert to uppercase if needed @@ -115,34 +127,65 @@ class AdiPort { return AdiPort(port - 'A'); } + /** + * @brief Create an ADI Port using its index + * + * @param index the port as an index (e.g 'A' has an index of 0) + * @return constexpr AdiPort + */ static constexpr AdiPort from_index(uint8_t index) { return AdiPort(index); } - constexpr char as_letter() const { - return m_index; + /** + * @brief Get the ADI Port as a char + * + * @note the returned char will be uppercase + * + * @return constexpr char + */ + constexpr char as_char() const { + // convert index to an uppercase letter + return m_index + 'A'; } + /** + * @brief Get the ADI Port as an index + * + * @return constexpr uint8_t + */ constexpr uint8_t as_index() const { return m_index; } private: - uint8_t m_index; - - constexpr AdiPort(uint8_t index) + /** + * @brief construct an ADI Port from an index + * + * This constructor is private to enforce the use of the `from_char` and `from_index` member + * functions. Having this construct be public defeats the purpose of this class, which is to + * prevent bugs by abstracting the port index. + */ + explicit constexpr AdiPort(uint8_t index) : m_index(index) {} + + uint8_t m_index; }; namespace ports { -constexpr auto PORT_A = AdiPort::from_letter('A'); -constexpr auto PORT_B = AdiPort::from_letter('B'); -constexpr auto PORT_C = AdiPort::from_letter('C'); -constexpr auto PORT_D = AdiPort::from_letter('D'); -constexpr auto PORT_E = AdiPort::from_letter('E'); -constexpr auto PORT_F = AdiPort::from_letter('F'); -constexpr auto PORT_G = AdiPort::from_letter('G'); -constexpr auto PORT_H = AdiPort::from_letter('H'); - +/* + * ADI ports have a char from 'A' to 'H'. While compile-time error checking could prevent an invalid + * port being constructed, the error messages that would be produced wouldn't be very concise. + * However, if the user tried constructing a device on the imaginary port I, the project wouldn't + * compile since PORT_I isn't declared. This error message is much clearer. + */ +constexpr auto PORT_A = AdiPort::from_char('A'); +constexpr auto PORT_B = AdiPort::from_char('B'); +constexpr auto PORT_C = AdiPort::from_char('C'); +constexpr auto PORT_D = AdiPort::from_char('D'); +constexpr auto PORT_E = AdiPort::from_char('E'); +constexpr auto PORT_F = AdiPort::from_char('F'); +constexpr auto PORT_G = AdiPort::from_char('G'); +constexpr auto PORT_H = AdiPort::from_char('H'); } // namespace ports } // namespace zest \ No newline at end of file From dfe13ffc9e2ecc9156246576612d8a6687624f4b Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 15:36:47 -0700 Subject: [PATCH 16/41] add mutex array to SmartPort class --- include/pros/devices/port.hpp | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index 7d6967d3..3d4ae86b 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -1,5 +1,8 @@ #pragma once +#include "pros/rtos.hpp" + +#include #include namespace zest { @@ -55,7 +58,51 @@ class SmartPort { return m_index; } + constexpr bool is_physical() const { + return m_index <= 20; + } + + constexpr bool is_virtual() const { + return m_index >= 21 && m_index <= 31; + } + + constexpr bool is_valid() const { + return m_index <= 31; + } + + /** + * @brief Get the mutex for the given port + * + * @todo decide whether this should go in a source file + * + * @return pros::RecursiveMutex& + */ + pros::RecursiveMutex& get_mutex() const { + if (this->is_valid()) { + return m_mutexes.at(m_index); + } else { + return *m_mutexes.end(); + } + } + private: + /** + * @brief array of recursive mutexes, with 33 elements. + * + * The mutexes in this array are used to ensure thread-safety when using devices. + * + * The decision to use recursive mutexes was made so device drivers could be made simpler, and + * performance is not a concern in this scenario. + * + * There are 22 physical smart ports, and 10 virtual smart ports, for a total of 32. + * Virtual smart ports are used by the VEX SDK to represent devices like the battery or a + * controller. + * + * This array has 33 elements instead of 32 as you may expect. The 33rd mutex is used for + * invalid ports. + */ + static std::array m_mutexes; + /** * @brief construct a Smart Port from an index * From 189f2c10d520a0866b485ee28612d1fb81c3a328 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 15:38:42 -0700 Subject: [PATCH 17/41] improve SmartPort::get_mutex documentation --- include/pros/devices/port.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index 3d4ae86b..04ee60be 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -73,7 +73,7 @@ class SmartPort { /** * @brief Get the mutex for the given port * - * @todo decide whether this should go in a source file + * @note if the port is not valid (index > 31), a reference to a reserved mutex is returned. * * @return pros::RecursiveMutex& */ @@ -81,7 +81,7 @@ class SmartPort { if (this->is_valid()) { return m_mutexes.at(m_index); } else { - return *m_mutexes.end(); + return m_mutexes.at(32); } } From ad4bda455548b04b889248a0a4ff3145d757c026 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 16:25:36 -0700 Subject: [PATCH 18/41] add ADI expander support to AdiPort class --- include/pros/devices/port.hpp | 37 ++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index 04ee60be..a992e98f 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace zest { @@ -145,6 +146,7 @@ constexpr auto PORT_18 = SmartPort::from_number(18); constexpr auto PORT_19 = SmartPort::from_number(19); constexpr auto PORT_20 = SmartPort::from_number(20); constexpr auto PORT_21 = SmartPort::from_number(21); +constexpr auto INVALID_SMART_PORT = SmartPort::from_index(std::numeric_limits::max()); } // namespace ports /** @@ -155,6 +157,19 @@ constexpr auto PORT_21 = SmartPort::from_number(21); */ class AdiPort { public: + // the default constructor is explicitly deleted to enforce the use of from_char and from_index + AdiPort(SmartPort, uint8_t) = delete; + + /** + * @brief Construct an ADI Port on an ADI expander + * + * @param expander_port the port of the ADI expander + * @param adi_port the ADI port. Can be lowercase or lowercase + */ + constexpr AdiPort(SmartPort expander_port, AdiPort adi_port) + : m_expander_port(expander_port), + m_index(adi_port.as_index()) {} + /** * @brief Create an ADI Port using its character * @@ -205,7 +220,25 @@ class AdiPort { return m_index; } + /** + * @brief Get the mutex for the given port + * + * @note if the expander port is not valid, a reference to a reserved mutex is returned. + * + * @return pros::RecursiveMutex& + */ + pros::RecursiveMutex& get_mutex() const { + if (m_expander_port.as_number() > 22) { + return ports::INVALID_SMART_PORT.get_mutex(); + } else { + return m_expander_port.get_mutex(); + } + } + private: + // the integrated ADI ports on the brain are represented by the virtual port 22 + static constexpr auto INTEGRATED_PORT = SmartPort::from_number(22); + /** * @brief construct an ADI Port from an index * @@ -214,8 +247,10 @@ class AdiPort { * prevent bugs by abstracting the port index. */ explicit constexpr AdiPort(uint8_t index) - : m_index(index) {} + : m_expander_port(INTEGRATED_PORT), + m_index(index) {} + SmartPort m_expander_port; uint8_t m_index; }; From 083f5f3928a2824e473b1e7080d4887d8424da33 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 16:28:00 -0700 Subject: [PATCH 19/41] add get_expander_port function to AdiPort class --- include/pros/devices/port.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index a992e98f..c8eb7051 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -220,6 +220,15 @@ class AdiPort { return m_index; } + /** + * @brief Get the smart port of the ADI expander + * + * @return constexpr SmartPort + */ + constexpr SmartPort get_expander_port() const { + return m_expander_port; + } + /** * @brief Get the mutex for the given port * From 839a59071f4d57a8c8f27c01c5218a24ab5d797b Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 16:29:04 -0700 Subject: [PATCH 20/41] fix AdiPort::get_mutex bug --- include/pros/devices/port.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index c8eb7051..bb276e33 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -232,12 +232,13 @@ class AdiPort { /** * @brief Get the mutex for the given port * - * @note if the expander port is not valid, a reference to a reserved mutex is returned. + * @note if the expander port or ADI port is not valid, a reference to a reserved mutex is + * returned. * * @return pros::RecursiveMutex& */ pros::RecursiveMutex& get_mutex() const { - if (m_expander_port.as_number() > 22) { + if (m_expander_port.as_number() > 22 || m_index > 7) { return ports::INVALID_SMART_PORT.get_mutex(); } else { return m_expander_port.get_mutex(); From e6933b1a283f420032349134a68002088b286638 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Fri, 16 May 2025 16:34:27 -0700 Subject: [PATCH 21/41] further SmartPort documentation --- include/pros/devices/port.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index bb276e33..20f10fe3 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -59,14 +59,32 @@ class SmartPort { return m_index; } + /** + * @brief whether the smart port represents a physical or virtual smart port + * + * @return true the smart port is physical + * @return false the smart port is virtual or invalid + */ constexpr bool is_physical() const { return m_index <= 20; } + /** + * @brief whether the smart port represents a physical or virtual smart port + * + * @return true the smart port is virtual + * @return false the smart port is physical or invalid + */ constexpr bool is_virtual() const { return m_index >= 21 && m_index <= 31; } + /** + * @brief whether the smart port is valid or not + * + * @return true the smart port is valid + * @return false the smart port is invalid + */ constexpr bool is_valid() const { return m_index <= 31; } From 41f4b6dd0809ff5313bd97e6a93fec81849dfb3d Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 17 May 2025 19:03:30 -0700 Subject: [PATCH 22/41] simplify port.hpp --- include/pros/devices/port.hpp | 65 +++++------------------------------ 1 file changed, 8 insertions(+), 57 deletions(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index 20f10fe3..c4447966 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -4,7 +4,6 @@ #include #include -#include namespace zest { @@ -135,38 +134,6 @@ class SmartPort { uint8_t m_index; }; -namespace ports { -/* - * Physical smart ports have a number from 1 to 21 (inclusive). While compile-time error checking - * could prevent an invalid port being constructed, the error messages that would be produced - * wouldn't be very concise. - * However, if the user tried constructing a device on the imaginary port 42, the project wouldn't - * compile since PORT_42 isn't declared. This error message is much clearer. - */ -constexpr auto PORT_1 = SmartPort::from_number(1); -constexpr auto PORT_2 = SmartPort::from_number(2); -constexpr auto PORT_3 = SmartPort::from_number(3); -constexpr auto PORT_4 = SmartPort::from_number(4); -constexpr auto PORT_5 = SmartPort::from_number(5); -constexpr auto PORT_6 = SmartPort::from_number(6); -constexpr auto PORT_7 = SmartPort::from_number(7); -constexpr auto PORT_8 = SmartPort::from_number(8); -constexpr auto PORT_9 = SmartPort::from_number(9); -constexpr auto PORT_10 = SmartPort::from_number(10); -constexpr auto PORT_11 = SmartPort::from_number(11); -constexpr auto PORT_12 = SmartPort::from_number(12); -constexpr auto PORT_13 = SmartPort::from_number(13); -constexpr auto PORT_14 = SmartPort::from_number(14); -constexpr auto PORT_15 = SmartPort::from_number(15); -constexpr auto PORT_16 = SmartPort::from_number(16); -constexpr auto PORT_17 = SmartPort::from_number(17); -constexpr auto PORT_18 = SmartPort::from_number(18); -constexpr auto PORT_19 = SmartPort::from_number(19); -constexpr auto PORT_20 = SmartPort::from_number(20); -constexpr auto PORT_21 = SmartPort::from_number(21); -constexpr auto INVALID_SMART_PORT = SmartPort::from_index(std::numeric_limits::max()); -} // namespace ports - /** * @brief ADI Port class. Represents an ADI Port on a the brain or on a 3-wire expander. * @@ -185,7 +152,7 @@ class AdiPort { * @param adi_port the ADI port. Can be lowercase or lowercase */ constexpr AdiPort(SmartPort expander_port, AdiPort adi_port) - : m_expander_port(expander_port), + : m_host_port(expander_port), m_index(adi_port.as_index()) {} /** @@ -244,7 +211,7 @@ class AdiPort { * @return constexpr SmartPort */ constexpr SmartPort get_expander_port() const { - return m_expander_port; + return m_host_port; } /** @@ -256,10 +223,11 @@ class AdiPort { * @return pros::RecursiveMutex& */ pros::RecursiveMutex& get_mutex() const { - if (m_expander_port.as_number() > 22 || m_index > 7) { - return ports::INVALID_SMART_PORT.get_mutex(); + if (m_host_port.as_number() > 22 || m_index > 7) { + // return a reference to the invalid port mutex + return SmartPort::from_number(33).get_mutex(); } else { - return m_expander_port.get_mutex(); + return m_host_port.get_mutex(); } } @@ -275,27 +243,10 @@ class AdiPort { * prevent bugs by abstracting the port index. */ explicit constexpr AdiPort(uint8_t index) - : m_expander_port(INTEGRATED_PORT), + : m_host_port(INTEGRATED_PORT), m_index(index) {} - SmartPort m_expander_port; + SmartPort m_host_port; uint8_t m_index; }; - -namespace ports { -/* - * ADI ports have a char from 'A' to 'H'. While compile-time error checking could prevent an invalid - * port being constructed, the error messages that would be produced wouldn't be very concise. - * However, if the user tried constructing a device on the imaginary port I, the project wouldn't - * compile since PORT_I isn't declared. This error message is much clearer. - */ -constexpr auto PORT_A = AdiPort::from_char('A'); -constexpr auto PORT_B = AdiPort::from_char('B'); -constexpr auto PORT_C = AdiPort::from_char('C'); -constexpr auto PORT_D = AdiPort::from_char('D'); -constexpr auto PORT_E = AdiPort::from_char('E'); -constexpr auto PORT_F = AdiPort::from_char('F'); -constexpr auto PORT_G = AdiPort::from_char('G'); -constexpr auto PORT_H = AdiPort::from_char('H'); -} // namespace ports } // namespace zest \ No newline at end of file From 84ce58e32ab8643171312cf8ef23eb1df18848c3 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 17 May 2025 20:52:51 -0700 Subject: [PATCH 23/41] add AdiExpander and Brain class --- include/pros/devices/adi_expander.hpp | 32 ++++++++++++++++++++++++ include/pros/devices/brain.hpp | 36 +++++++++++++++++++++++++++ include/pros/devices/port.hpp | 25 +++++++++++++++++++ src/devices/battery.cpp | 15 +++++------ 4 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 include/pros/devices/adi_expander.hpp create mode 100644 include/pros/devices/brain.hpp diff --git a/include/pros/devices/adi_expander.hpp b/include/pros/devices/adi_expander.hpp new file mode 100644 index 00000000..eac579a7 --- /dev/null +++ b/include/pros/devices/adi_expander.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "port.hpp" +#include "pros/devices/port.hpp" + +namespace zest { +class AdiExpander { + public: + constexpr AdiExpander(SmartPort port) + : port_a(port, AdiPort::from_char('A')), + port_b(port, AdiPort::from_char('B')), + port_c(port, AdiPort::from_char('C')), + port_d(port, AdiPort::from_char('D')), + port_e(port, AdiPort::from_char('E')), + port_f(port, AdiPort::from_char('F')), + port_g(port, AdiPort::from_char('G')), + port_h(port, AdiPort::from_char('H')), + smart_port(port) {} + + const AdiPort port_a; + const AdiPort port_b; + const AdiPort port_c; + const AdiPort port_d; + const AdiPort port_e; + const AdiPort port_f; + const AdiPort port_g; + const AdiPort port_h; + const AdiPort port_invalid = AdiPort::make_invalid(); + + const SmartPort smart_port; +}; +}; // namespace zest \ No newline at end of file diff --git a/include/pros/devices/brain.hpp b/include/pros/devices/brain.hpp new file mode 100644 index 00000000..3ee2e65c --- /dev/null +++ b/include/pros/devices/brain.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "pros/devices/adi_expander.hpp" + +namespace zest { +class Brain { + public: + static constexpr SmartPort port_1 = SmartPort::from_number(1); + static constexpr SmartPort port_2 = SmartPort::from_number(2); + static constexpr SmartPort port_3 = SmartPort::from_number(3); + static constexpr SmartPort port_4 = SmartPort::from_number(4); + static constexpr SmartPort port_5 = SmartPort::from_number(5); + static constexpr SmartPort port_6 = SmartPort::from_number(6); + static constexpr SmartPort port_7 = SmartPort::from_number(7); + static constexpr SmartPort port_8 = SmartPort::from_number(8); + static constexpr SmartPort port_9 = SmartPort::from_number(9); + static constexpr SmartPort port_10 = SmartPort::from_number(10); + static constexpr SmartPort port_11 = SmartPort::from_number(11); + static constexpr SmartPort port_12 = SmartPort::from_number(12); + static constexpr SmartPort port_13 = SmartPort::from_number(13); + static constexpr SmartPort port_14 = SmartPort::from_number(14); + static constexpr SmartPort port_15 = SmartPort::from_number(15); + static constexpr SmartPort port_16 = SmartPort::from_number(16); + static constexpr SmartPort port_17 = SmartPort::from_number(17); + static constexpr SmartPort port_18 = SmartPort::from_number(18); + static constexpr SmartPort port_19 = SmartPort::from_number(19); + static constexpr SmartPort port_20 = SmartPort::from_number(20); + static constexpr SmartPort port_21 = SmartPort::from_number(21); + + static constexpr SmartPort integrated_adi_port = SmartPort::from_number(22); + static constexpr SmartPort battery_port = SmartPort::from_number(25); + static constexpr SmartPort port_invalid = SmartPort::make_invalid(); + + static constexpr AdiExpander adi = AdiExpander(integrated_adi_port); +}; +}; // namespace zest \ No newline at end of file diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index c4447966..1e7a3400 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace zest { @@ -16,6 +17,18 @@ namespace zest { */ class SmartPort { public: + /** + * @brief Create an invalid Smart Port + * + * Users may want to create a device on an invalid port for testing. This function provides an + * idiomatic way to create an invalid port. + * + * @return constexpr SmartPort + */ + static constexpr SmartPort make_invalid() { + return SmartPort(std::numeric_limits::max()); + } + /** * @brief Create a Smart Port using its number * @@ -145,6 +158,18 @@ class AdiPort { // the default constructor is explicitly deleted to enforce the use of from_char and from_index AdiPort(SmartPort, uint8_t) = delete; + /** + * @brief Create an invalid ADI Port + * + * Users may want to create a device on an invalid port for testing. This function provides an + * idiomatic way to create an invalid port. + * + * @return constexpr SmartPort + */ + static constexpr AdiPort make_invalid() { + return AdiPort(std::numeric_limits::max()); + } + /** * @brief Construct an ADI Port on an ADI expander * diff --git a/src/devices/battery.cpp b/src/devices/battery.cpp index 1abbec47..d2bfe17c 100644 --- a/src/devices/battery.cpp +++ b/src/devices/battery.cpp @@ -1,15 +1,16 @@ #include "pros/devices/battery.hpp" -#include "pros/devices/port.hpp" +#include "pros/devices/brain.hpp" #include "v5_api_patched.h" #include -constexpr auto BATTERY_PORT = zest::SmartPort::from_index(25); - namespace zest { + +static Brain brain; + Result Battery::get_capacity() { - std::lock_guard lock(get_port_mutex(BATTERY_PORT)); + std::lock_guard lock(brain.battery_port.get_mutex()); if (auto res = vexBatteryCapacityGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { @@ -18,7 +19,7 @@ Result Battery::get_capacity() { } Result Battery::get_current() { - std::lock_guard lock(get_port_mutex(BATTERY_PORT)); + std::lock_guard lock(brain.battery_port.get_mutex()); if (auto res = vexBatteryCurrentGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { @@ -27,7 +28,7 @@ Result Battery::get_current() { } Result Battery::get_temperature() { - std::lock_guard lock(get_port_mutex(BATTERY_PORT)); + std::lock_guard lock(brain.battery_port.get_mutex()); if (auto res = vexBatteryTemperatureGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { @@ -36,7 +37,7 @@ Result Battery::get_temperature() { } Result Battery::get_voltage() { - std::lock_guard lock(get_port_mutex(BATTERY_PORT)); + std::lock_guard lock(brain.battery_port.get_mutex()); if (auto res = vexBatteryVoltageGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { From 450519c3716cc3c8aea85a9a33f6d200d3ca5fc9 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 17 May 2025 21:22:48 -0700 Subject: [PATCH 24/41] add port.cpp --- include/pros/devices/port.hpp | 16 ++++++---------- src/devices/port.cpp | 13 +++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 src/devices/port.cpp diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index 1e7a3400..c4698c2b 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -88,7 +88,7 @@ class SmartPort { * @return false the smart port is physical or invalid */ constexpr bool is_virtual() const { - return m_index >= 21 && m_index <= 31; + return m_index >= 21 && is_valid(); } /** @@ -98,7 +98,7 @@ class SmartPort { * @return false the smart port is invalid */ constexpr bool is_valid() const { - return m_index <= 31; + return m_index < MAX_SMART_PORTS; } /** @@ -108,13 +108,9 @@ class SmartPort { * * @return pros::RecursiveMutex& */ - pros::RecursiveMutex& get_mutex() const { - if (this->is_valid()) { - return m_mutexes.at(m_index); - } else { - return m_mutexes.at(32); - } - } + pros::RecursiveMutex& get_mutex() const; + + static constexpr uint8_t MAX_SMART_PORTS = 32; /**< the maximum number of smart ports */ private: /** @@ -132,7 +128,7 @@ class SmartPort { * This array has 33 elements instead of 32 as you may expect. The 33rd mutex is used for * invalid ports. */ - static std::array m_mutexes; + static std::array m_mutexes; /** * @brief construct a Smart Port from an index diff --git a/src/devices/port.cpp b/src/devices/port.cpp new file mode 100644 index 00000000..8edf5622 --- /dev/null +++ b/src/devices/port.cpp @@ -0,0 +1,13 @@ +#include "pros/devices/port.hpp" + +namespace zest { +std::array SmartPort::m_mutexes; + +pros::RecursiveMutex& SmartPort::get_mutex() const { + if (this->is_valid()) { + return m_mutexes.at(m_index); + } else { + return m_mutexes.back(); + } +} +}; // namespace zest \ No newline at end of file From d1f7f2c76b2fd4b8ece258f6ce1ac191aedb7d0c Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 17 May 2025 21:49:25 -0700 Subject: [PATCH 25/41] fix build errors --- src/system/startup.cpp | 5 +- .../{system_daemon.c => system_daemon.cpp} | 74 ++++++++++--------- .../{user_functions.c => user_functions.cpp} | 0 3 files changed, 43 insertions(+), 36 deletions(-) rename src/system/{system_daemon.c => system_daemon.cpp} (76%) rename src/system/{user_functions.c => user_functions.cpp} (100%) diff --git a/src/system/startup.cpp b/src/system/startup.cpp index de423957..b8580733 100644 --- a/src/system/startup.cpp +++ b/src/system/startup.cpp @@ -25,8 +25,6 @@ extern "C" { // Initialization routines provided elsewhere void rtos_initialize(); void vfs_initialize(); -void system_daemon_initialize(); -void graphical_context_daemon_initialize(); [[gnu::weak]] void display_initialize() {} @@ -40,6 +38,8 @@ void __libc_init_array(); void vexTasksRun(); } // extern "C" +void system_daemon_initialize(); + // this goes in the first 32-byte chunk of the user program // which is why the entrypoint is offset from 0x3800000 by 0x20 // only the first 16 bytes of this chunk is used however @@ -53,7 +53,6 @@ vcodesig vexCodeSig = {V5_SIG_MAGIC, V5_SIG_TYPE_USER, V5_SIG_OWNER_PARTNER, V5_ static void pros_init() { rtos_initialize(); vfs_initialize(); - graphical_context_daemon_initialize(); display_initialize(); // Note: system_daemon_initialize must be called last, per design requirements. system_daemon_initialize(); diff --git a/src/system/system_daemon.c b/src/system/system_daemon.cpp similarity index 76% rename from src/system/system_daemon.c rename to src/system/system_daemon.cpp index fb8acedc..a948f1aa 100644 --- a/src/system/system_daemon.c +++ b/src/system/system_daemon.cpp @@ -12,29 +12,41 @@ */ #include "kapi.h" +#include "pros/devices/port.hpp" #include "system/optimizers.h" #include "system/user_functions.h" // IWYU pragma: keep -extern void vdml_background_processing(); +extern "C" { +void vexTasksRun(); +void ser_output_flush(); +} + +void port_mutex_take_all() { + for (int i = 0; i < zest::SmartPort::MAX_SMART_PORTS; i++) { + zest::SmartPort::from_index(i).get_mutex().take(); + } +} + +void port_mutex_give_all() { + for (int i = 0; i < zest::SmartPort::MAX_SMART_PORTS; i++) { + zest::SmartPort::from_index(i).get_mutex().give(); + } +} -extern void port_mutex_take_all(); -extern void port_mutex_give_all(); +static void _disabled_task(void*); +static void _autonomous_task(void*); +static void _opcontrol_task(void*); +static void _competition_initialize_task(void*); +static void _initialize_task(void*); +static void _system_daemon_task(void*); static task_stack_t competition_task_stack[TASK_STACK_DEPTH_DEFAULT]; static static_task_s_t competition_task_buffer; -static task_t competition_task; +static pros::task_t competition_task; static task_stack_t system_daemon_task_stack[TASK_STACK_DEPTH_DEFAULT]; static static_task_s_t system_daemon_task_buffer; -static task_t system_daemon_task; - -static void _disabled_task(void* ign); -static void _autonomous_task(void* ign); -static void _opcontrol_task(void* ign); -static void _competition_initialize_task(void* ign); - -static void _initialize_task(void* ign); -static void _system_daemon_task(void* ign); +static pros::task_t system_daemon_task; enum state_task { E_OPCONTROL_TASK = 0, @@ -43,18 +55,15 @@ enum state_task { E_COMP_INIT_TASK }; -char task_names[4][32] = { +static const char task_names[4][32] = { "User Operator Control (PROS)", "User Autonomous (PROS)", "User Disabled (PROS)", "User Comp. Init. (PROS)" }; -task_fn_t task_fns[4] = - {_opcontrol_task, _autonomous_task, _disabled_task, _competition_initialize_task}; -extern void ser_output_flush(void); - -void vexTasksRun(); +static task_fn_t task_fns[4] = + {_opcontrol_task, _autonomous_task, _disabled_task, _competition_initialize_task}; // does the basic background operations that need to occur every 2ms static inline void do_background_operations() { @@ -63,12 +72,11 @@ static inline void do_background_operations() { rtos_suspend_all(); vexTasksRun(); rtos_resume_all(); - vdml_background_processing(); port_mutex_give_all(); } -static void _system_daemon_task(void* ign) { - uint32_t time = millis(); +static void _system_daemon_task(void*) { + uint32_t time = pros::millis(); // Initialize status to an invalid state to force an update the first loop uint32_t status = (uint32_t)(1 << 8); uint32_t task_state; @@ -78,7 +86,7 @@ static void _system_daemon_task(void* ign) { // Take all port mutexes to prevent user code from attempting to access VDML during this time. // User code could be running if a task is created from a global ctor port_mutex_take_all(); - task_delay(2); + pros::c::task_delay(2); port_mutex_give_all(); // start up user initialize task. once the user initialize function completes, @@ -94,18 +102,18 @@ static void _system_daemon_task(void* ign) { &competition_task_buffer ); - time = millis(); - while (!task_notify_take(true, 2)) { + time = pros::millis(); + while (!pros::c::task_notify_take(true, 2)) { // wait for initialize to finish do_background_operations(); } while (1) { do_background_operations(); - if (unlikely(status != competition_get_status())) { + if (unlikely(status != pros::c::competition_get_status())) { // Have a new competition status, need to clean up whatever's running uint32_t old_status = status; - status = competition_get_status(); + status = pros::c::competition_get_status(); enum state_task state = E_OPCONTROL_TASK; if ((status & COMPETITION_DISABLED) && (old_status & COMPETITION_DISABLED)) { // Don't restart the disabled task even if other bits have changed (e.g. auton bit) @@ -124,13 +132,13 @@ static void _system_daemon_task(void* ign) { state = E_AUTON_TASK; } - task_state = task_get_state(competition_task); + task_state = pros::c::task_get_state(competition_task); // delete the task only if it's in normal operation (e.g. not deleted) // The valid task states AREN'T deleted, invalid, or running (running // means it's the current task, which will never be the case) - if (task_state == E_TASK_STATE_READY || task_state == E_TASK_STATE_BLOCKED - || task_state == E_TASK_STATE_SUSPENDED) { - task_delete(competition_task); + if (task_state == pros::E_TASK_STATE_READY || task_state == pros::E_TASK_STATE_BLOCKED + || task_state == pros::E_TASK_STATE_SUSPENDED) { + pros::c::task_delete(competition_task); } competition_task = task_create_static( @@ -144,7 +152,7 @@ static void _system_daemon_task(void* ign) { ); } - task_delay_until(&time, 2); + pros::c::task_delay_until(&time, 2); } } @@ -165,7 +173,7 @@ void system_daemon_initialize() { #define FUNC(NAME) \ static void _##NAME##_task(void* ign) { \ user_##NAME(); \ - task_notify(system_daemon_task); \ + pros::c::task_notify(system_daemon_task); \ } #include "system/user_functions/c_list.h" #undef FUNC diff --git a/src/system/user_functions.c b/src/system/user_functions.cpp similarity index 100% rename from src/system/user_functions.c rename to src/system/user_functions.cpp From 50d2f27d85372f24033046aa7beb6b136bb8751f Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sat, 17 May 2025 22:13:24 -0700 Subject: [PATCH 26/41] define AdiPort::get_mutex out of line --- include/pros/devices/port.hpp | 9 +-------- src/devices/port.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index c4698c2b..a3c90395 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -243,14 +243,7 @@ class AdiPort { * * @return pros::RecursiveMutex& */ - pros::RecursiveMutex& get_mutex() const { - if (m_host_port.as_number() > 22 || m_index > 7) { - // return a reference to the invalid port mutex - return SmartPort::from_number(33).get_mutex(); - } else { - return m_host_port.get_mutex(); - } - } + pros::RecursiveMutex& get_mutex() const; private: // the integrated ADI ports on the brain are represented by the virtual port 22 diff --git a/src/devices/port.cpp b/src/devices/port.cpp index 8edf5622..3735528f 100644 --- a/src/devices/port.cpp +++ b/src/devices/port.cpp @@ -10,4 +10,13 @@ pros::RecursiveMutex& SmartPort::get_mutex() const { return m_mutexes.back(); } } + +pros::RecursiveMutex& AdiPort::get_mutex() const { + if (m_host_port.as_number() > 22 || m_index > 7) { + // return a reference to the invalid port mutex + return SmartPort::from_number(33).get_mutex(); + } else { + return m_host_port.get_mutex(); + } +} }; // namespace zest \ No newline at end of file From 3412f5466b62bf5e5a13661e8087edbaed484276 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sun, 18 May 2025 17:23:31 -0700 Subject: [PATCH 27/41] restructure ports --- include/pros/devices/adi_expander.hpp | 39 ++--- include/pros/devices/brain.hpp | 54 ++++--- include/pros/devices/port.hpp | 221 ++++---------------------- src/devices/battery.cpp | 8 +- src/devices/brain.cpp | 38 +++++ src/devices/port.cpp | 22 --- src/system/system_daemon.cpp | 38 +++-- 7 files changed, 145 insertions(+), 275 deletions(-) create mode 100644 src/devices/brain.cpp delete mode 100644 src/devices/port.cpp diff --git a/include/pros/devices/adi_expander.hpp b/include/pros/devices/adi_expander.hpp index eac579a7..c7fcf5c5 100644 --- a/include/pros/devices/adi_expander.hpp +++ b/include/pros/devices/adi_expander.hpp @@ -6,27 +6,28 @@ namespace zest { class AdiExpander { public: - constexpr AdiExpander(SmartPort port) - : port_a(port, AdiPort::from_char('A')), - port_b(port, AdiPort::from_char('B')), - port_c(port, AdiPort::from_char('C')), - port_d(port, AdiPort::from_char('D')), - port_e(port, AdiPort::from_char('E')), - port_f(port, AdiPort::from_char('F')), - port_g(port, AdiPort::from_char('G')), - port_h(port, AdiPort::from_char('H')), + AdiExpander(SmartPort& port) + : port_a(port, 'A'), + port_b(port, 'B'), + port_c(port, 'C'), + port_d(port, 'D'), + port_e(port, 'E'), + port_f(port, 'F'), + port_g(port, 'G'), + port_h(port, 'H'), + port_invalid(port, 'J'), smart_port(port) {} - const AdiPort port_a; - const AdiPort port_b; - const AdiPort port_c; - const AdiPort port_d; - const AdiPort port_e; - const AdiPort port_f; - const AdiPort port_g; - const AdiPort port_h; - const AdiPort port_invalid = AdiPort::make_invalid(); + AdiPort port_a; + AdiPort port_b; + AdiPort port_c; + AdiPort port_d; + AdiPort port_e; + AdiPort port_f; + AdiPort port_g; + AdiPort port_h; + AdiPort port_invalid; - const SmartPort smart_port; + SmartPort& smart_port; }; }; // namespace zest \ No newline at end of file diff --git a/include/pros/devices/brain.hpp b/include/pros/devices/brain.hpp index 3ee2e65c..ab04658a 100644 --- a/include/pros/devices/brain.hpp +++ b/include/pros/devices/brain.hpp @@ -5,32 +5,36 @@ namespace zest { class Brain { public: - static constexpr SmartPort port_1 = SmartPort::from_number(1); - static constexpr SmartPort port_2 = SmartPort::from_number(2); - static constexpr SmartPort port_3 = SmartPort::from_number(3); - static constexpr SmartPort port_4 = SmartPort::from_number(4); - static constexpr SmartPort port_5 = SmartPort::from_number(5); - static constexpr SmartPort port_6 = SmartPort::from_number(6); - static constexpr SmartPort port_7 = SmartPort::from_number(7); - static constexpr SmartPort port_8 = SmartPort::from_number(8); - static constexpr SmartPort port_9 = SmartPort::from_number(9); - static constexpr SmartPort port_10 = SmartPort::from_number(10); - static constexpr SmartPort port_11 = SmartPort::from_number(11); - static constexpr SmartPort port_12 = SmartPort::from_number(12); - static constexpr SmartPort port_13 = SmartPort::from_number(13); - static constexpr SmartPort port_14 = SmartPort::from_number(14); - static constexpr SmartPort port_15 = SmartPort::from_number(15); - static constexpr SmartPort port_16 = SmartPort::from_number(16); - static constexpr SmartPort port_17 = SmartPort::from_number(17); - static constexpr SmartPort port_18 = SmartPort::from_number(18); - static constexpr SmartPort port_19 = SmartPort::from_number(19); - static constexpr SmartPort port_20 = SmartPort::from_number(20); - static constexpr SmartPort port_21 = SmartPort::from_number(21); + // port collections + static std::array ports; + static AdiExpander adi; - static constexpr SmartPort integrated_adi_port = SmartPort::from_number(22); - static constexpr SmartPort battery_port = SmartPort::from_number(25); - static constexpr SmartPort port_invalid = SmartPort::make_invalid(); + // physical smart ports + static SmartPort& port_1; + static SmartPort& port_2; + static SmartPort& port_3; + static SmartPort& port_4; + static SmartPort& port_5; + static SmartPort& port_6; + static SmartPort& port_7; + static SmartPort& port_8; + static SmartPort& port_9; + static SmartPort& port_10; + static SmartPort& port_11; + static SmartPort& port_12; + static SmartPort& port_13; + static SmartPort& port_14; + static SmartPort& port_15; + static SmartPort& port_16; + static SmartPort& port_17; + static SmartPort& port_18; + static SmartPort& port_19; + static SmartPort& port_20; + static SmartPort& port_21; - static constexpr AdiExpander adi = AdiExpander(integrated_adi_port); + // virtual smart ports + static SmartPort& integrated_adi_port; + static SmartPort& battery_port; + static SmartPort& invalid_port; }; }; // namespace zest \ No newline at end of file diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index a3c90395..d7edfb68 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -2,64 +2,30 @@ #include "pros/rtos.hpp" -#include #include -#include namespace zest { +// forward-declare friend classes +class Brain; +class AdiExpander; + /** * @brief Smart Port class. Represents a Smart Port on the V5 brain. * - * Smart Ports may be represented as a 1-indexed number or a 0-indexed number. While the - * user expects a 1-indexed number (matching the labels on the brain), treating it as an index makes - * development easier. This class abstracts that away so we don't have to worry about it. */ class SmartPort { - public: - /** - * @brief Create an invalid Smart Port - * - * Users may want to create a device on an invalid port for testing. This function provides an - * idiomatic way to create an invalid port. - * - * @return constexpr SmartPort - */ - static constexpr SmartPort make_invalid() { - return SmartPort(std::numeric_limits::max()); - } - - /** - * @brief Create a Smart Port using its number - * - * @note the smart port labelled "1" on the brain has a port number of 1 - * - * @param port_number the port number, 1-indexed - * @return constexpr SmartPort - */ - static constexpr SmartPort from_number(uint8_t port_number) { - return SmartPort(port_number - 1); - } - - /** - * @brief Create a Smart Port using its index - * - * @note the smart port labelled "1" on the brain has a port index of 0 - * - * @param port_index the port index, 0-indexed - * @return constexpr SmartPort - */ - static constexpr SmartPort from_index(uint8_t port_index) { - return SmartPort(port_index); - } + // SmartPort instances can only be constructed by the Brain class + friend class Brain; + public: /** * @brief Get the Smart Port as a number (1-indexed) * * @return constexpr uint8_t */ - constexpr uint8_t as_number() const { - return m_index + 1; + uint8_t as_number() const { + return m_number; } /** @@ -67,80 +33,21 @@ class SmartPort { * * @return constexpr uint8_t */ - constexpr uint8_t as_index() const { - return m_index; + uint8_t as_index() const { + return m_number - 1; } - /** - * @brief whether the smart port represents a physical or virtual smart port - * - * @return true the smart port is physical - * @return false the smart port is virtual or invalid - */ - constexpr bool is_physical() const { - return m_index <= 20; - } - - /** - * @brief whether the smart port represents a physical or virtual smart port - * - * @return true the smart port is virtual - * @return false the smart port is physical or invalid - */ - constexpr bool is_virtual() const { - return m_index >= 21 && is_valid(); - } - - /** - * @brief whether the smart port is valid or not - * - * @return true the smart port is valid - * @return false the smart port is invalid - */ - constexpr bool is_valid() const { - return m_index < MAX_SMART_PORTS; - } - - /** - * @brief Get the mutex for the given port - * - * @note if the port is not valid (index > 31), a reference to a reserved mutex is returned. - * - * @return pros::RecursiveMutex& - */ - pros::RecursiveMutex& get_mutex() const; - - static constexpr uint8_t MAX_SMART_PORTS = 32; /**< the maximum number of smart ports */ + pros::RecursiveMutex mutex; private: - /** - * @brief array of recursive mutexes, with 33 elements. - * - * The mutexes in this array are used to ensure thread-safety when using devices. - * - * The decision to use recursive mutexes was made so device drivers could be made simpler, and - * performance is not a concern in this scenario. - * - * There are 22 physical smart ports, and 10 virtual smart ports, for a total of 32. - * Virtual smart ports are used by the VEX SDK to represent devices like the battery or a - * controller. - * - * This array has 33 elements instead of 32 as you may expect. The 33rd mutex is used for - * invalid ports. - */ - static std::array m_mutexes; - /** * @brief construct a Smart Port from an index * - * This constructor is private to enforce the use of the `from_number` and `from_index` member - * functions. Having this construct be public defeats the purpose of this class, which is to - * prevent bugs by abstracting the port index. */ - explicit constexpr SmartPort(uint8_t port_index) - : m_index(port_index) {} + SmartPort(uint8_t port_number) + : m_number(port_number) {} - uint8_t m_index; + uint8_t m_number; }; /** @@ -150,61 +57,10 @@ class SmartPort { * provides an interface so the developer doesn't have to worry about conversions. */ class AdiPort { - public: - // the default constructor is explicitly deleted to enforce the use of from_char and from_index - AdiPort(SmartPort, uint8_t) = delete; - - /** - * @brief Create an invalid ADI Port - * - * Users may want to create a device on an invalid port for testing. This function provides an - * idiomatic way to create an invalid port. - * - * @return constexpr SmartPort - */ - static constexpr AdiPort make_invalid() { - return AdiPort(std::numeric_limits::max()); - } - - /** - * @brief Construct an ADI Port on an ADI expander - * - * @param expander_port the port of the ADI expander - * @param adi_port the ADI port. Can be lowercase or lowercase - */ - constexpr AdiPort(SmartPort expander_port, AdiPort adi_port) - : m_host_port(expander_port), - m_index(adi_port.as_index()) {} - - /** - * @brief Create an ADI Port using its character - * - * @param port can be lowercase, uppercase, or even an index - * @return constexpr AdiPort - */ - static constexpr AdiPort from_char(char port) { - // if the index is provided as a character - if (port >= '0' && port <= '8') { - return AdiPort(port - '0'); - } - // convert to uppercase if needed - if (port >= 'a' && port <= 'z') { - port -= ('a' - 'A'); - } - // 'A' has index 0, 'B' has index 1, etc - return AdiPort(port - 'A'); - } - - /** - * @brief Create an ADI Port using its index - * - * @param index the port as an index (e.g 'A' has an index of 0) - * @return constexpr AdiPort - */ - static constexpr AdiPort from_index(uint8_t index) { - return AdiPort(index); - } + // AdiPort instances can only be constructed by the AdiExpander class + friend AdiExpander; + public: /** * @brief Get the ADI Port as a char * @@ -212,7 +68,7 @@ class AdiPort { * * @return constexpr char */ - constexpr char as_char() const { + char as_char() const { // convert index to an uppercase letter return m_index + 'A'; } @@ -222,45 +78,24 @@ class AdiPort { * * @return constexpr uint8_t */ - constexpr uint8_t as_index() const { + uint8_t as_index() const { return m_index; } - /** - * @brief Get the smart port of the ADI expander - * - * @return constexpr SmartPort - */ - constexpr SmartPort get_expander_port() const { - return m_host_port; - } - - /** - * @brief Get the mutex for the given port - * - * @note if the expander port or ADI port is not valid, a reference to a reserved mutex is - * returned. - * - * @return pros::RecursiveMutex& - */ - pros::RecursiveMutex& get_mutex() const; + SmartPort& host_port; private: - // the integrated ADI ports on the brain are represented by the virtual port 22 - static constexpr auto INTEGRATED_PORT = SmartPort::from_number(22); - /** - * @brief construct an ADI Port from an index + * @brief Create an ADI Port using its character * - * This constructor is private to enforce the use of the `from_char` and `from_index` member - * functions. Having this construct be public defeats the purpose of this class, which is to - * prevent bugs by abstracting the port index. + * @param host_port the smart port of the ADI hub this adi port belongs to + * @param port must be uppercase, 'A' - 'H' + * @return constexpr AdiPort */ - explicit constexpr AdiPort(uint8_t index) - : m_host_port(INTEGRATED_PORT), - m_index(index) {} + constexpr AdiPort(SmartPort& host_port, char port) + : host_port(host_port), + m_index(port - 'A') {} - SmartPort m_host_port; uint8_t m_index; }; } // namespace zest \ No newline at end of file diff --git a/src/devices/battery.cpp b/src/devices/battery.cpp index d2bfe17c..2e43a85f 100644 --- a/src/devices/battery.cpp +++ b/src/devices/battery.cpp @@ -10,7 +10,7 @@ namespace zest { static Brain brain; Result Battery::get_capacity() { - std::lock_guard lock(brain.battery_port.get_mutex()); + std::lock_guard lock(brain.battery_port.mutex); if (auto res = vexBatteryCapacityGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { @@ -19,7 +19,7 @@ Result Battery::get_capacity() { } Result Battery::get_current() { - std::lock_guard lock(brain.battery_port.get_mutex()); + std::lock_guard lock(brain.battery_port.mutex); if (auto res = vexBatteryCurrentGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { @@ -28,7 +28,7 @@ Result Battery::get_current() { } Result Battery::get_temperature() { - std::lock_guard lock(brain.battery_port.get_mutex()); + std::lock_guard lock(brain.battery_port.mutex); if (auto res = vexBatteryTemperatureGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { @@ -37,7 +37,7 @@ Result Battery::get_temperature() { } Result Battery::get_voltage() { - std::lock_guard lock(brain.battery_port.get_mutex()); + std::lock_guard lock(brain.battery_port.mutex); if (auto res = vexBatteryVoltageGet(); res == std::numeric_limits::max()) { return UnknownError("An unknown error has occurred"); } else { diff --git a/src/devices/brain.cpp b/src/devices/brain.cpp new file mode 100644 index 00000000..f5be6078 --- /dev/null +++ b/src/devices/brain.cpp @@ -0,0 +1,38 @@ +#include "pros/devices/brain.hpp" + +namespace zest { +// collection of smart ports +std::array Brain::ports = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}; + +// adi ports integrated in the brain +AdiExpander Brain::adi = AdiExpander(battery_port); +// physical smart ports +SmartPort& Brain::port_1 = ports.at(0); +SmartPort& Brain::port_2 = ports.at(1); +SmartPort& Brain::port_3 = ports.at(2); +SmartPort& Brain::port_4 = ports.at(3); +SmartPort& Brain::port_5 = ports.at(4); +SmartPort& Brain::port_6 = ports.at(5); +SmartPort& Brain::port_7 = ports.at(6); +SmartPort& Brain::port_8 = ports.at(7); +SmartPort& Brain::port_9 = ports.at(8); +SmartPort& Brain::port_10 = ports.at(9); +SmartPort& Brain::port_11 = ports.at(10); +SmartPort& Brain::port_12 = ports.at(11); +SmartPort& Brain::port_13 = ports.at(12); +SmartPort& Brain::port_14 = ports.at(13); +SmartPort& Brain::port_15 = ports.at(14); +SmartPort& Brain::port_16 = ports.at(15); +SmartPort& Brain::port_17 = ports.at(16); +SmartPort& Brain::port_18 = ports.at(17); +SmartPort& Brain::port_19 = ports.at(18); +SmartPort& Brain::port_20 = ports.at(19); +SmartPort& Brain::port_21 = ports.at(20); + +// virtual smart ports +SmartPort& Brain::integrated_adi_port = ports.at(21); +SmartPort& Brain::battery_port = ports.at(24); +SmartPort& Brain::invalid_port = ports.at(32); +} // namespace zest \ No newline at end of file diff --git a/src/devices/port.cpp b/src/devices/port.cpp deleted file mode 100644 index 3735528f..00000000 --- a/src/devices/port.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "pros/devices/port.hpp" - -namespace zest { -std::array SmartPort::m_mutexes; - -pros::RecursiveMutex& SmartPort::get_mutex() const { - if (this->is_valid()) { - return m_mutexes.at(m_index); - } else { - return m_mutexes.back(); - } -} - -pros::RecursiveMutex& AdiPort::get_mutex() const { - if (m_host_port.as_number() > 22 || m_index > 7) { - // return a reference to the invalid port mutex - return SmartPort::from_number(33).get_mutex(); - } else { - return m_host_port.get_mutex(); - } -} -}; // namespace zest \ No newline at end of file diff --git a/src/system/system_daemon.cpp b/src/system/system_daemon.cpp index a948f1aa..89d7bcc6 100644 --- a/src/system/system_daemon.cpp +++ b/src/system/system_daemon.cpp @@ -12,25 +12,39 @@ */ #include "kapi.h" +#include "pros/devices/brain.hpp" #include "pros/devices/port.hpp" +#include "pros/rtos.hpp" #include "system/optimizers.h" #include "system/user_functions.h" // IWYU pragma: keep +#include + extern "C" { void vexTasksRun(); void ser_output_flush(); } -void port_mutex_take_all() { - for (int i = 0; i < zest::SmartPort::MAX_SMART_PORTS; i++) { - zest::SmartPort::from_index(i).get_mutex().take(); - } +template +static void lock_ports(std::index_sequence) { + std::lock(zest::Brain::ports[Is].mutex...); } -void port_mutex_give_all() { - for (int i = 0; i < zest::SmartPort::MAX_SMART_PORTS; i++) { - zest::SmartPort::from_index(i).get_mutex().give(); - } +template +static void unlock_ports(std::index_sequence) { + constexpr std::size_t N = sizeof...(Is); + // Unlock in reverse order (RAII best practice) + (zest::Brain::ports[N - 1 - Is].mutex.unlock(), ...); +} + +static void port_mutex_lock_all() { + constexpr auto num_ports = std::tuple_size::value; + lock_ports(std::make_index_sequence{}); +} + +static void port_mutex_unlock_all() { + constexpr auto num_ports = std::tuple_size::value; + unlock_ports(std::make_index_sequence{}); } static void _disabled_task(void*); @@ -67,12 +81,12 @@ static task_fn_t task_fns[4] = // does the basic background operations that need to occur every 2ms static inline void do_background_operations() { - port_mutex_take_all(); + port_mutex_lock_all(); ser_output_flush(); rtos_suspend_all(); vexTasksRun(); rtos_resume_all(); - port_mutex_give_all(); + port_mutex_unlock_all(); } static void _system_daemon_task(void*) { @@ -85,9 +99,9 @@ static void _system_daemon_task(void*) { // (discovered b/c VDML would crash and burn) // Take all port mutexes to prevent user code from attempting to access VDML during this time. // User code could be running if a task is created from a global ctor - port_mutex_take_all(); + port_mutex_lock_all(); pros::c::task_delay(2); - port_mutex_give_all(); + port_mutex_unlock_all(); // start up user initialize task. once the user initialize function completes, // the _initialize_task will notify us and we can go into normal competition From 54550044c5ba8c22c07e684ae36697b3d72484d9 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sun, 18 May 2025 22:10:40 -0700 Subject: [PATCH 28/41] delete SmartPort and AdiPort copy constructors --- include/pros/devices/port.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index d7edfb68..a4dbeaf2 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -37,6 +37,9 @@ class SmartPort { return m_number - 1; } + // users should always use a reference to a SmartPort + SmartPort(SmartPort& other) = delete; + pros::RecursiveMutex mutex; private: @@ -82,6 +85,9 @@ class AdiPort { return m_index; } + // users should always use a reference to an AdiPort + AdiPort(AdiPort& other) = delete; + SmartPort& host_port; private: @@ -92,7 +98,7 @@ class AdiPort { * @param port must be uppercase, 'A' - 'H' * @return constexpr AdiPort */ - constexpr AdiPort(SmartPort& host_port, char port) + AdiPort(SmartPort& host_port, char port) : host_port(host_port), m_index(port - 'A') {} From a9b9e29371ad1b2b2b454004aba2cc3464e3bfa9 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sun, 18 May 2025 22:27:45 -0700 Subject: [PATCH 29/41] document AdiExpander class --- include/pros/devices/adi_expander.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/pros/devices/adi_expander.hpp b/include/pros/devices/adi_expander.hpp index c7fcf5c5..45685587 100644 --- a/include/pros/devices/adi_expander.hpp +++ b/include/pros/devices/adi_expander.hpp @@ -4,8 +4,18 @@ #include "pros/devices/port.hpp" namespace zest { + +/** + * @brief ADI Expander class. Used to control access to ADI ports + * + */ class AdiExpander { public: + /** + * @brief Construct a new ADI Expander object + * + * @param port the smart port the ADI expander is connected to + */ AdiExpander(SmartPort& port) : port_a(port, 'A'), port_b(port, 'B'), From 98c1376b0f6d40c8fad0f05512363e55a23e9998 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sun, 18 May 2025 22:34:11 -0700 Subject: [PATCH 30/41] update STRUCTURE.md to reflect VDML refactor --- docs/STRUCTURE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/STRUCTURE.md b/docs/STRUCTURE.md index 48b2f919..579fa433 100644 --- a/docs/STRUCTURE.md +++ b/docs/STRUCTURE.md @@ -10,17 +10,17 @@ Looking at the file structure of a project like this can feel intimidating. This - `include` contains the header files - `include/common` headers used in various parts of the project - `include/pros` headers that are distributed to user projects + - `include/pros/devices` headers containing api for interacting with V5 devices - `include/rtos` headers for the scheduler (FreeRTOS) - `include/system` headers for low-level system functionality - `include/system/dev` headers for serial I/O and file management - `include/system/user_functions` a horrifying mess that should be destroyed - - `include/vdml` headers for the VEX Data Management Layer (VDML), a system to ensure thread-safety when interacting with VEX devices - `scripts` contains scripts used for building ZestCode and projects that use ZestCode - `src` contains the source files - `src/common` sources defining symbols used throughout the project - - `src/devices` implementations of VEX device abstractions. Files prefixed with `vdml_` indicate that the file makes use of the VDML + - `src/devices` implementations of VEX device abstractions - `src/rtos` sources, build scripts, and misc files of FreeRTOS - `src/system` sources for low-level system functionality - `src/system/dev` sources for serial I/O and file management From b23dce09606bd2674a49eca479b601cdabfebeed Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sun, 18 May 2025 23:00:51 -0700 Subject: [PATCH 31/41] document system_daemon mutex helper functions --- src/system/system_daemon.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/system/system_daemon.cpp b/src/system/system_daemon.cpp index 89d7bcc6..a02c9921 100644 --- a/src/system/system_daemon.cpp +++ b/src/system/system_daemon.cpp @@ -25,11 +25,25 @@ void vexTasksRun(); void ser_output_flush(); } +/** + * @brief lock a sequence of smart ports + * + * For whatever reason, std::lock only compiles if you pass the mutexes like this: + * std::lock(mutex_a, mutex_b, mutex_c); + * You can't pass it an array or iterator or lambda, so we have to use this helper function instead. + */ template static void lock_ports(std::index_sequence) { std::lock(zest::Brain::ports[Is].mutex...); } +/** + * @brief unlock a sequence of smart ports + * + * For whatever reason, std::unlock only compiles if you pass the mutexes like this: + * std::unlock(mutex_a, mutex_b, mutex_c); + * You can't pass it an array or iterator or lambda, so we have to use this helper function instead + */ template static void unlock_ports(std::index_sequence) { constexpr std::size_t N = sizeof...(Is); @@ -37,12 +51,22 @@ static void unlock_ports(std::index_sequence) { (zest::Brain::ports[N - 1 - Is].mutex.unlock(), ...); } +/** + * @brief lock all smart port mutexes + * + */ static void port_mutex_lock_all() { + // this looks weird because of how std::lock is implemented. See lock_ports for details. constexpr auto num_ports = std::tuple_size::value; lock_ports(std::make_index_sequence{}); } +/** + * @brief unlock all smart port mutexes + * + */ static void port_mutex_unlock_all() { + // this looks weird because of how std::unlock is implemented. See unlock_ports for details. constexpr auto num_ports = std::tuple_size::value; unlock_ports(std::make_index_sequence{}); } From 2e16c0bf8fb05c352278c8f738a198cda8916d04 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Sun, 18 May 2025 23:04:40 -0700 Subject: [PATCH 32/41] further document lock_ports helper function --- src/system/system_daemon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/system/system_daemon.cpp b/src/system/system_daemon.cpp index a02c9921..55cb590a 100644 --- a/src/system/system_daemon.cpp +++ b/src/system/system_daemon.cpp @@ -34,6 +34,7 @@ void ser_output_flush(); */ template static void lock_ports(std::index_sequence) { + // std::lock locks multiple mutexes without risk of a deadlock std::lock(zest::Brain::ports[Is].mutex...); } From 300d787e9da8b09e578ccdcc2254ee48d77aea4f Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Tue, 20 May 2025 11:20:37 -0700 Subject: [PATCH 33/41] try using constinit --- include/pros/devices/adi_expander.hpp | 3 +- include/pros/devices/brain.hpp | 60 +++++++++++++++------------ include/pros/devices/port.hpp | 12 +++--- src/devices/brain.cpp | 56 ++++++++++++------------- 4 files changed, 70 insertions(+), 61 deletions(-) diff --git a/include/pros/devices/adi_expander.hpp b/include/pros/devices/adi_expander.hpp index 45685587..8a241c35 100644 --- a/include/pros/devices/adi_expander.hpp +++ b/include/pros/devices/adi_expander.hpp @@ -16,7 +16,7 @@ class AdiExpander { * * @param port the smart port the ADI expander is connected to */ - AdiExpander(SmartPort& port) + consteval AdiExpander(SmartPort& port) : port_a(port, 'A'), port_b(port, 'B'), port_c(port, 'C'), @@ -36,6 +36,7 @@ class AdiExpander { AdiPort port_f; AdiPort port_g; AdiPort port_h; + // users may use port_invalid as a placeholder or temporary port AdiPort port_invalid; SmartPort& smart_port; diff --git a/include/pros/devices/brain.hpp b/include/pros/devices/brain.hpp index ab04658a..2e583f03 100644 --- a/include/pros/devices/brain.hpp +++ b/include/pros/devices/brain.hpp @@ -3,38 +3,46 @@ #include "pros/devices/adi_expander.hpp" namespace zest { +/** + * @brief + * + */ class Brain { public: // port collections - static std::array ports; - static AdiExpander adi; + // there are 21 physical smart ports, 11 virtual smart ports, and 1 reserved virtual smart port + // for invalid ports. Totals 33. + static constinit std::array ports; + static constinit AdiExpander adi; // physical smart ports - static SmartPort& port_1; - static SmartPort& port_2; - static SmartPort& port_3; - static SmartPort& port_4; - static SmartPort& port_5; - static SmartPort& port_6; - static SmartPort& port_7; - static SmartPort& port_8; - static SmartPort& port_9; - static SmartPort& port_10; - static SmartPort& port_11; - static SmartPort& port_12; - static SmartPort& port_13; - static SmartPort& port_14; - static SmartPort& port_15; - static SmartPort& port_16; - static SmartPort& port_17; - static SmartPort& port_18; - static SmartPort& port_19; - static SmartPort& port_20; - static SmartPort& port_21; + // these references are simply a QoL feature + static constinit SmartPort& port_1; + static constinit SmartPort& port_2; + static constinit SmartPort& port_3; + static constinit SmartPort& port_4; + static constinit SmartPort& port_5; + static constinit SmartPort& port_6; + static constinit SmartPort& port_7; + static constinit SmartPort& port_8; + static constinit SmartPort& port_9; + static constinit SmartPort& port_10; + static constinit SmartPort& port_11; + static constinit SmartPort& port_12; + static constinit SmartPort& port_13; + static constinit SmartPort& port_14; + static constinit SmartPort& port_15; + static constinit SmartPort& port_16; + static constinit SmartPort& port_17; + static constinit SmartPort& port_18; + static constinit SmartPort& port_19; + static constinit SmartPort& port_20; + static constinit SmartPort& port_21; // virtual smart ports - static SmartPort& integrated_adi_port; - static SmartPort& battery_port; - static SmartPort& invalid_port; + static constinit SmartPort& integrated_adi_port; + static constinit SmartPort& battery_port; + // users may use port_invalid as a placeholder or temporary port + static constinit SmartPort& invalid_port; }; }; // namespace zest \ No newline at end of file diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index a4dbeaf2..a51ce40f 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -24,7 +24,7 @@ class SmartPort { * * @return constexpr uint8_t */ - uint8_t as_number() const { + constexpr uint8_t as_number() const { return m_number; } @@ -33,7 +33,7 @@ class SmartPort { * * @return constexpr uint8_t */ - uint8_t as_index() const { + constexpr uint8_t as_index() const { return m_number - 1; } @@ -47,7 +47,7 @@ class SmartPort { * @brief construct a Smart Port from an index * */ - SmartPort(uint8_t port_number) + constexpr SmartPort(uint8_t port_number) : m_number(port_number) {} uint8_t m_number; @@ -71,7 +71,7 @@ class AdiPort { * * @return constexpr char */ - char as_char() const { + constexpr char as_char() const { // convert index to an uppercase letter return m_index + 'A'; } @@ -81,7 +81,7 @@ class AdiPort { * * @return constexpr uint8_t */ - uint8_t as_index() const { + constexpr uint8_t as_index() const { return m_index; } @@ -98,7 +98,7 @@ class AdiPort { * @param port must be uppercase, 'A' - 'H' * @return constexpr AdiPort */ - AdiPort(SmartPort& host_port, char port) + constexpr AdiPort(SmartPort& host_port, char port) : host_port(host_port), m_index(port - 'A') {} diff --git a/src/devices/brain.cpp b/src/devices/brain.cpp index f5be6078..e3451823 100644 --- a/src/devices/brain.cpp +++ b/src/devices/brain.cpp @@ -2,37 +2,37 @@ namespace zest { // collection of smart ports -std::array Brain::ports = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}; +constinit std::array Brain::ports = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}; // adi ports integrated in the brain -AdiExpander Brain::adi = AdiExpander(battery_port); +constinit AdiExpander Brain::adi = AdiExpander(battery_port); // physical smart ports -SmartPort& Brain::port_1 = ports.at(0); -SmartPort& Brain::port_2 = ports.at(1); -SmartPort& Brain::port_3 = ports.at(2); -SmartPort& Brain::port_4 = ports.at(3); -SmartPort& Brain::port_5 = ports.at(4); -SmartPort& Brain::port_6 = ports.at(5); -SmartPort& Brain::port_7 = ports.at(6); -SmartPort& Brain::port_8 = ports.at(7); -SmartPort& Brain::port_9 = ports.at(8); -SmartPort& Brain::port_10 = ports.at(9); -SmartPort& Brain::port_11 = ports.at(10); -SmartPort& Brain::port_12 = ports.at(11); -SmartPort& Brain::port_13 = ports.at(12); -SmartPort& Brain::port_14 = ports.at(13); -SmartPort& Brain::port_15 = ports.at(14); -SmartPort& Brain::port_16 = ports.at(15); -SmartPort& Brain::port_17 = ports.at(16); -SmartPort& Brain::port_18 = ports.at(17); -SmartPort& Brain::port_19 = ports.at(18); -SmartPort& Brain::port_20 = ports.at(19); -SmartPort& Brain::port_21 = ports.at(20); +constinit SmartPort& Brain::port_1 = ports.at(0); +constinit SmartPort& Brain::port_2 = ports.at(1); +constinit SmartPort& Brain::port_3 = ports.at(2); +constinit SmartPort& Brain::port_4 = ports.at(3); +constinit SmartPort& Brain::port_5 = ports.at(4); +constinit SmartPort& Brain::port_6 = ports.at(5); +constinit SmartPort& Brain::port_7 = ports.at(6); +constinit SmartPort& Brain::port_8 = ports.at(7); +constinit SmartPort& Brain::port_9 = ports.at(8); +constinit SmartPort& Brain::port_10 = ports.at(9); +constinit SmartPort& Brain::port_11 = ports.at(10); +constinit SmartPort& Brain::port_12 = ports.at(11); +constinit SmartPort& Brain::port_13 = ports.at(12); +constinit SmartPort& Brain::port_14 = ports.at(13); +constinit SmartPort& Brain::port_15 = ports.at(14); +constinit SmartPort& Brain::port_16 = ports.at(15); +constinit SmartPort& Brain::port_17 = ports.at(16); +constinit SmartPort& Brain::port_18 = ports.at(17); +constinit SmartPort& Brain::port_19 = ports.at(18); +constinit SmartPort& Brain::port_20 = ports.at(19); +constinit SmartPort& Brain::port_21 = ports.at(20); // virtual smart ports -SmartPort& Brain::integrated_adi_port = ports.at(21); -SmartPort& Brain::battery_port = ports.at(24); -SmartPort& Brain::invalid_port = ports.at(32); +constinit SmartPort& Brain::integrated_adi_port = ports.at(21); +constinit SmartPort& Brain::battery_port = ports.at(24); +constinit SmartPort& Brain::invalid_port = ports.at(32); } // namespace zest \ No newline at end of file From b89fb526225897525d166b70f6d633cc4e9a8468 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Tue, 20 May 2025 11:22:39 -0700 Subject: [PATCH 34/41] fix compiler errors --- include/pros/devices/brain.hpp | 4 +++- src/devices/brain.cpp | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/pros/devices/brain.hpp b/include/pros/devices/brain.hpp index 2e583f03..8a55e0e2 100644 --- a/include/pros/devices/brain.hpp +++ b/include/pros/devices/brain.hpp @@ -13,7 +13,6 @@ class Brain { // there are 21 physical smart ports, 11 virtual smart ports, and 1 reserved virtual smart port // for invalid ports. Totals 33. static constinit std::array ports; - static constinit AdiExpander adi; // physical smart ports // these references are simply a QoL feature @@ -44,5 +43,8 @@ class Brain { static constinit SmartPort& battery_port; // users may use port_invalid as a placeholder or temporary port static constinit SmartPort& invalid_port; + + // all adi ports on the brain + static constinit AdiExpander adi; }; }; // namespace zest \ No newline at end of file diff --git a/src/devices/brain.cpp b/src/devices/brain.cpp index e3451823..3022ab1a 100644 --- a/src/devices/brain.cpp +++ b/src/devices/brain.cpp @@ -6,8 +6,6 @@ constinit std::array Brain::ports = {1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}; -// adi ports integrated in the brain -constinit AdiExpander Brain::adi = AdiExpander(battery_port); // physical smart ports constinit SmartPort& Brain::port_1 = ports.at(0); constinit SmartPort& Brain::port_2 = ports.at(1); @@ -35,4 +33,7 @@ constinit SmartPort& Brain::port_21 = ports.at(20); constinit SmartPort& Brain::integrated_adi_port = ports.at(21); constinit SmartPort& Brain::battery_port = ports.at(24); constinit SmartPort& Brain::invalid_port = ports.at(32); + +// adi ports integrated in the brain +constinit AdiExpander Brain::adi = AdiExpander(integrated_adi_port); } // namespace zest \ No newline at end of file From e2c2785f053fd8f81655ad5c0a848fea7251c451 Mon Sep 17 00:00:00 2001 From: Liam Teale <111480281+SizzinSeal@users.noreply.github.com> Date: Tue, 20 May 2025 13:46:34 -0700 Subject: [PATCH 35/41] simplify port_mutex_lock_all Co-authored-by: ion098 <146852218+ion098@users.noreply.github.com> --- src/system/system_daemon.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/system/system_daemon.cpp b/src/system/system_daemon.cpp index 55cb590a..14d5507a 100644 --- a/src/system/system_daemon.cpp +++ b/src/system/system_daemon.cpp @@ -57,9 +57,9 @@ static void unlock_ports(std::index_sequence) { * */ static void port_mutex_lock_all() { - // this looks weird because of how std::lock is implemented. See lock_ports for details. - constexpr auto num_ports = std::tuple_size::value; - lock_ports(std::make_index_sequence{}); + [](std::index_sequence) { + std::lock(zest::Brain::ports[Is].mutex...); + }(std::make_index_sequence{}); } /** From 0c9e91335d0b26ae34e9f5bc389ecae71fa373ec Mon Sep 17 00:00:00 2001 From: Liam Teale <111480281+SizzinSeal@users.noreply.github.com> Date: Tue, 20 May 2025 13:47:04 -0700 Subject: [PATCH 36/41] simplify port_mutex_unlock_all Co-authored-by: ion098 <146852218+ion098@users.noreply.github.com> --- src/system/system_daemon.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/system/system_daemon.cpp b/src/system/system_daemon.cpp index 14d5507a..3b71db3d 100644 --- a/src/system/system_daemon.cpp +++ b/src/system/system_daemon.cpp @@ -67,9 +67,10 @@ static void port_mutex_lock_all() { * */ static void port_mutex_unlock_all() { - // this looks weird because of how std::unlock is implemented. See unlock_ports for details. - constexpr auto num_ports = std::tuple_size::value; - unlock_ports(std::make_index_sequence{}); + [](std::index_sequence) { + // unlock mutexes in reverse order of locking + (zest::Brain::ports[sizeof...(Is) - 1 - Is].mutex.unlock(), ...); + }(std::make_index_sequence{}); } static void _disabled_task(void*); From d68bb2ae58a9033059c58eb8f9e98b8045f6f433 Mon Sep 17 00:00:00 2001 From: Liam Teale <111480281+SizzinSeal@users.noreply.github.com> Date: Tue, 20 May 2025 13:47:24 -0700 Subject: [PATCH 37/41] remove unused helper functions Co-authored-by: ion098 <146852218+ion098@users.noreply.github.com> --- src/system/system_daemon.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/system/system_daemon.cpp b/src/system/system_daemon.cpp index 3b71db3d..d90c0145 100644 --- a/src/system/system_daemon.cpp +++ b/src/system/system_daemon.cpp @@ -25,32 +25,6 @@ void vexTasksRun(); void ser_output_flush(); } -/** - * @brief lock a sequence of smart ports - * - * For whatever reason, std::lock only compiles if you pass the mutexes like this: - * std::lock(mutex_a, mutex_b, mutex_c); - * You can't pass it an array or iterator or lambda, so we have to use this helper function instead. - */ -template -static void lock_ports(std::index_sequence) { - // std::lock locks multiple mutexes without risk of a deadlock - std::lock(zest::Brain::ports[Is].mutex...); -} - -/** - * @brief unlock a sequence of smart ports - * - * For whatever reason, std::unlock only compiles if you pass the mutexes like this: - * std::unlock(mutex_a, mutex_b, mutex_c); - * You can't pass it an array or iterator or lambda, so we have to use this helper function instead - */ -template -static void unlock_ports(std::index_sequence) { - constexpr std::size_t N = sizeof...(Is); - // Unlock in reverse order (RAII best practice) - (zest::Brain::ports[N - 1 - Is].mutex.unlock(), ...); -} /** * @brief lock all smart port mutexes From b5106001273c2bd49d9fc93b45d4d6814b1b7a8b Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Mon, 26 May 2025 13:23:23 -0700 Subject: [PATCH 38/41] further restructuring of port mutexes --- include/pros/devices/adi_expander.hpp | 4 +- include/pros/devices/battery.hpp | 38 ++++++++++-- include/pros/devices/brain.hpp | 86 +++++++++++++++++---------- include/pros/devices/port.hpp | 27 +++------ src/devices/battery.cpp | 43 ++++---------- src/devices/brain.cpp | 60 +++++++++---------- src/system/system_daemon.cpp | 37 +----------- 7 files changed, 140 insertions(+), 155 deletions(-) diff --git a/include/pros/devices/adi_expander.hpp b/include/pros/devices/adi_expander.hpp index 8a241c35..20fa42a5 100644 --- a/include/pros/devices/adi_expander.hpp +++ b/include/pros/devices/adi_expander.hpp @@ -16,7 +16,7 @@ class AdiExpander { * * @param port the smart port the ADI expander is connected to */ - consteval AdiExpander(SmartPort& port) + constexpr AdiExpander(SmartPort port) : port_a(port, 'A'), port_b(port, 'B'), port_c(port, 'C'), @@ -39,6 +39,6 @@ class AdiExpander { // users may use port_invalid as a placeholder or temporary port AdiPort port_invalid; - SmartPort& smart_port; + SmartPort smart_port; }; }; // namespace zest \ No newline at end of file diff --git a/include/pros/devices/battery.hpp b/include/pros/devices/battery.hpp index ea98e19d..7da0ef13 100644 --- a/include/pros/devices/battery.hpp +++ b/include/pros/devices/battery.hpp @@ -1,15 +1,41 @@ #pragma once -#include "common/result.hpp" - namespace zest { class Battery { public: - static Result get_capacity(); - static Result get_current(); - static Result get_temperature(); - static Result get_voltage(); + /** + * @brief Get the remaining capacity of the robot battery + * + * TODO: document how the returned value should be interpreted (e.g 0-1 or 0-100) + * + * @return double + */ + static double get_capacity(); + /** + * @brief Get the current drawn from the robot battery + * + * TODO: document how the returned value should be interpreted (e.g amps or milliamps) + * + * @return double + */ + static double get_current(); + /** + * @brief Get the temperature of the robot battery + * + * TODO: document how the returned value should be interpreted (e.g celsius or fahrenheit) + * + * @return double + */ + static double get_temperature(); + /** + * @brief Get the voltage of the robot battery + * + * TODO: document how the returned value should be interpreted (e.g celsius or fahrenheit) + * + * @return double + */ + static double get_voltage(); }; } // namespace zest \ No newline at end of file diff --git a/include/pros/devices/brain.hpp b/include/pros/devices/brain.hpp index 8a55e0e2..7b560d1f 100644 --- a/include/pros/devices/brain.hpp +++ b/include/pros/devices/brain.hpp @@ -1,6 +1,7 @@ #pragma once #include "pros/devices/adi_expander.hpp" +#include "pros/rtos.hpp" namespace zest { /** @@ -9,42 +10,65 @@ namespace zest { */ class Brain { public: - // port collections - // there are 21 physical smart ports, 11 virtual smart ports, and 1 reserved virtual smart port - // for invalid ports. Totals 33. - static constinit std::array ports; - // physical smart ports - // these references are simply a QoL feature - static constinit SmartPort& port_1; - static constinit SmartPort& port_2; - static constinit SmartPort& port_3; - static constinit SmartPort& port_4; - static constinit SmartPort& port_5; - static constinit SmartPort& port_6; - static constinit SmartPort& port_7; - static constinit SmartPort& port_8; - static constinit SmartPort& port_9; - static constinit SmartPort& port_10; - static constinit SmartPort& port_11; - static constinit SmartPort& port_12; - static constinit SmartPort& port_13; - static constinit SmartPort& port_14; - static constinit SmartPort& port_15; - static constinit SmartPort& port_16; - static constinit SmartPort& port_17; - static constinit SmartPort& port_18; - static constinit SmartPort& port_19; - static constinit SmartPort& port_20; - static constinit SmartPort& port_21; + static constexpr SmartPort PORT_1 = SmartPort(1); + static constexpr SmartPort PORT_2 = SmartPort(2); + static constexpr SmartPort PORT_3 = SmartPort(3); + static constexpr SmartPort PORT_4 = SmartPort(4); + static constexpr SmartPort PORT_5 = SmartPort(5); + static constexpr SmartPort PORT_6 = SmartPort(6); + static constexpr SmartPort PORT_7 = SmartPort(7); + static constexpr SmartPort PORT_8 = SmartPort(8); + static constexpr SmartPort PORT_9 = SmartPort(9); + static constexpr SmartPort PORT_10 = SmartPort(10); + static constexpr SmartPort PORT_11 = SmartPort(11); + static constexpr SmartPort PORT_12 = SmartPort(12); + static constexpr SmartPort PORT_13 = SmartPort(13); + static constexpr SmartPort PORT_14 = SmartPort(14); + static constexpr SmartPort PORT_15 = SmartPort(15); + static constexpr SmartPort PORT_16 = SmartPort(16); + static constexpr SmartPort PORT_17 = SmartPort(17); + static constexpr SmartPort PORT_18 = SmartPort(18); + static constexpr SmartPort PORT_19 = SmartPort(19); + static constexpr SmartPort PORT_20 = SmartPort(20); + static constexpr SmartPort PORT_21 = SmartPort(21); // virtual smart ports - static constinit SmartPort& integrated_adi_port; - static constinit SmartPort& battery_port; + static constexpr SmartPort INTEGRATED_ADI_PORT = SmartPort(22); + static constexpr SmartPort BATTERY_PORT = SmartPort(25); // users may use port_invalid as a placeholder or temporary port - static constinit SmartPort& invalid_port; + static constexpr SmartPort INVALID_PORT = SmartPort(33); // all adi ports on the brain - static constinit AdiExpander adi; + static constexpr AdiExpander adi = AdiExpander(INTEGRATED_ADI_PORT); + + // TODO: conditionally declare functions below, to prevent users accidentally calling them + // TODO: replace lock_all and unlock_all with a single function that returns an std::scoped_lock + + /** + * @brief Get the mutex of a smart port + * + * @warning this function should not be used by typical users + * + * @param smart_port the smart port to get the mutex of + * @return pros::RecursiveMutex& + */ + static pros::RecursiveMutex& get_smart_port_mutex(SmartPort smart_port); + + /** + * @brief lock all smart port mutexes + * + * uses std::lock to prevent deadlocks + */ + static void smart_port_mutex_lock_all(); + + /** + * @brief unlock all smart port mutexes + * + */ + static void smart_port_mutex_unlock_all(); + + private: + static constinit std::array m_mutexes; }; }; // namespace zest \ No newline at end of file diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index a51ce40f..d72f77ee 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -1,7 +1,5 @@ #pragma once -#include "pros/rtos.hpp" - #include namespace zest { @@ -37,11 +35,6 @@ class SmartPort { return m_number - 1; } - // users should always use a reference to a SmartPort - SmartPort(SmartPort& other) = delete; - - pros::RecursiveMutex mutex; - private: /** * @brief construct a Smart Port from an index @@ -65,15 +58,12 @@ class AdiPort { public: /** - * @brief Get the ADI Port as a char - * - * @note the returned char will be uppercase + * @brief Get the ADI Port as an uppercase letter * * @return constexpr char */ - constexpr char as_char() const { - // convert index to an uppercase letter - return m_index + 'A'; + constexpr char as_letter() const { + return m_letter; } /** @@ -82,13 +72,13 @@ class AdiPort { * @return constexpr uint8_t */ constexpr uint8_t as_index() const { - return m_index; + return m_letter - 'A'; } // users should always use a reference to an AdiPort AdiPort(AdiPort& other) = delete; - SmartPort& host_port; + SmartPort host_port; private: /** @@ -98,10 +88,11 @@ class AdiPort { * @param port must be uppercase, 'A' - 'H' * @return constexpr AdiPort */ - constexpr AdiPort(SmartPort& host_port, char port) + constexpr AdiPort(SmartPort host_port, char port) : host_port(host_port), - m_index(port - 'A') {} + m_letter(port) {} - uint8_t m_index; + char m_letter; }; + } // namespace zest \ No newline at end of file diff --git a/src/devices/battery.cpp b/src/devices/battery.cpp index 2e43a85f..8dc66f5b 100644 --- a/src/devices/battery.cpp +++ b/src/devices/battery.cpp @@ -6,42 +6,23 @@ #include namespace zest { - -static Brain brain; - -Result Battery::get_capacity() { - std::lock_guard lock(brain.battery_port.mutex); - if (auto res = vexBatteryCapacityGet(); res == std::numeric_limits::max()) { - return UnknownError("An unknown error has occurred"); - } else { - return res; - } +double Battery::get_capacity() { + std::lock_guard lock(Brain::get_smart_port_mutex(Brain::BATTERY_PORT)); + return vexBatteryCapacityGet(); } -Result Battery::get_current() { - std::lock_guard lock(brain.battery_port.mutex); - if (auto res = vexBatteryCurrentGet(); res == std::numeric_limits::max()) { - return UnknownError("An unknown error has occurred"); - } else { - return res; - } +double Battery::get_current() { + std::lock_guard lock(Brain::get_smart_port_mutex(Brain::BATTERY_PORT)); + return vexBatteryCurrentGet(); } -Result Battery::get_temperature() { - std::lock_guard lock(brain.battery_port.mutex); - if (auto res = vexBatteryTemperatureGet(); res == std::numeric_limits::max()) { - return UnknownError("An unknown error has occurred"); - } else { - return res; - } +double Battery::get_temperature() { + std::lock_guard lock(Brain::get_smart_port_mutex(Brain::BATTERY_PORT)); + return vexBatteryTemperatureGet(); } -Result Battery::get_voltage() { - std::lock_guard lock(brain.battery_port.mutex); - if (auto res = vexBatteryVoltageGet(); res == std::numeric_limits::max()) { - return UnknownError("An unknown error has occurred"); - } else { - return res; - } +double Battery::get_voltage() { + std::lock_guard lock(Brain::get_smart_port_mutex(Brain::BATTERY_PORT)); + return vexBatteryVoltageGet(); } } // namespace zest \ No newline at end of file diff --git a/src/devices/brain.cpp b/src/devices/brain.cpp index 3022ab1a..2fd47752 100644 --- a/src/devices/brain.cpp +++ b/src/devices/brain.cpp @@ -1,39 +1,35 @@ #include "pros/devices/brain.hpp" +#include + namespace zest { -// collection of smart ports -constinit std::array Brain::ports = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}; -// physical smart ports -constinit SmartPort& Brain::port_1 = ports.at(0); -constinit SmartPort& Brain::port_2 = ports.at(1); -constinit SmartPort& Brain::port_3 = ports.at(2); -constinit SmartPort& Brain::port_4 = ports.at(3); -constinit SmartPort& Brain::port_5 = ports.at(4); -constinit SmartPort& Brain::port_6 = ports.at(5); -constinit SmartPort& Brain::port_7 = ports.at(6); -constinit SmartPort& Brain::port_8 = ports.at(7); -constinit SmartPort& Brain::port_9 = ports.at(8); -constinit SmartPort& Brain::port_10 = ports.at(9); -constinit SmartPort& Brain::port_11 = ports.at(10); -constinit SmartPort& Brain::port_12 = ports.at(11); -constinit SmartPort& Brain::port_13 = ports.at(12); -constinit SmartPort& Brain::port_14 = ports.at(13); -constinit SmartPort& Brain::port_15 = ports.at(14); -constinit SmartPort& Brain::port_16 = ports.at(15); -constinit SmartPort& Brain::port_17 = ports.at(16); -constinit SmartPort& Brain::port_18 = ports.at(17); -constinit SmartPort& Brain::port_19 = ports.at(18); -constinit SmartPort& Brain::port_20 = ports.at(19); -constinit SmartPort& Brain::port_21 = ports.at(20); +pros::RecursiveMutex& Brain::get_smart_port_mutex(SmartPort smart_port) { + // If the port is invalid, return the invalid port mutex. + // Otherwise, return the respective mutex + if (smart_port.as_number() > 32) { + return m_mutexes.at(Brain::INVALID_PORT.as_index()); + } else { + return m_mutexes.at(smart_port.as_index()); + } +} + +void Brain::smart_port_mutex_lock_all() { + std::apply([&](auto&... args) { + std::lock(args...); + }, Brain::m_mutexes); +} + +void Brain::smart_port_mutex_unlock_all() { + for (auto& mutex : Brain::m_mutexes) { + mutex.unlock(); + } +} -// virtual smart ports -constinit SmartPort& Brain::integrated_adi_port = ports.at(21); -constinit SmartPort& Brain::battery_port = ports.at(24); -constinit SmartPort& Brain::invalid_port = ports.at(32); +// The VEX SDK has 32 virtual smart ports. +// 21 of these ports represent physical smart ports, +// the rest represent things like the battery, the controller, etc. +// This array has 33 mutexes. The extra mutex is used for invalid ports. +constinit std::array Brain::m_mutexes; -// adi ports integrated in the brain -constinit AdiExpander Brain::adi = AdiExpander(integrated_adi_port); } // namespace zest \ No newline at end of file diff --git a/src/system/system_daemon.cpp b/src/system/system_daemon.cpp index d90c0145..278a5bf0 100644 --- a/src/system/system_daemon.cpp +++ b/src/system/system_daemon.cpp @@ -13,40 +13,15 @@ #include "kapi.h" #include "pros/devices/brain.hpp" -#include "pros/devices/port.hpp" #include "pros/rtos.hpp" #include "system/optimizers.h" #include "system/user_functions.h" // IWYU pragma: keep -#include - extern "C" { void vexTasksRun(); void ser_output_flush(); } - -/** - * @brief lock all smart port mutexes - * - */ -static void port_mutex_lock_all() { - [](std::index_sequence) { - std::lock(zest::Brain::ports[Is].mutex...); - }(std::make_index_sequence{}); -} - -/** - * @brief unlock all smart port mutexes - * - */ -static void port_mutex_unlock_all() { - [](std::index_sequence) { - // unlock mutexes in reverse order of locking - (zest::Brain::ports[sizeof...(Is) - 1 - Is].mutex.unlock(), ...); - }(std::make_index_sequence{}); -} - static void _disabled_task(void*); static void _autonomous_task(void*); static void _opcontrol_task(void*); @@ -81,12 +56,12 @@ static task_fn_t task_fns[4] = // does the basic background operations that need to occur every 2ms static inline void do_background_operations() { - port_mutex_lock_all(); + zest::Brain::smart_port_mutex_lock_all(); ser_output_flush(); rtos_suspend_all(); vexTasksRun(); rtos_resume_all(); - port_mutex_unlock_all(); + zest::Brain::smart_port_mutex_unlock_all(); } static void _system_daemon_task(void*) { @@ -95,14 +70,6 @@ static void _system_daemon_task(void*) { uint32_t status = (uint32_t)(1 << 8); uint32_t task_state; - // XXX: Delay likely necessary for shared memory to get copied over - // (discovered b/c VDML would crash and burn) - // Take all port mutexes to prevent user code from attempting to access VDML during this time. - // User code could be running if a task is created from a global ctor - port_mutex_lock_all(); - pros::c::task_delay(2); - port_mutex_unlock_all(); - // start up user initialize task. once the user initialize function completes, // the _initialize_task will notify us and we can go into normal competition // monitoring mode From 5cdce86a8b5807c9074f805b7c0a31cd0be9f122 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Mon, 26 May 2025 13:24:02 -0700 Subject: [PATCH 39/41] remove VDML readme --- src/devices/README.md | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/devices/README.md diff --git a/src/devices/README.md b/src/devices/README.md deleted file mode 100644 index c04195a2..00000000 --- a/src/devices/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Devices - -These source files implement VDML - the VEX Data Mesh Layer, which controls the -V5 Smart Devices and other peripherals. From 910401ee97c2936a8e7d45bb978ab5444ac5882b Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Mon, 26 May 2025 13:26:40 -0700 Subject: [PATCH 40/41] fix AdiPort class docs --- include/pros/devices/port.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index d72f77ee..c4820452 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -37,7 +37,7 @@ class SmartPort { private: /** - * @brief construct a Smart Port from an index + * @brief construct a Smart Port from a number * */ constexpr SmartPort(uint8_t port_number) @@ -49,7 +49,7 @@ class SmartPort { /** * @brief ADI Port class. Represents an ADI Port on a the brain or on a 3-wire expander. * - * ADI Ports may be represented as a 0-indexed number, or a char (e.g 'a' or 'C'). This class + * ADI Ports may be represented as a 0-indexed number, or a letter (e.g 'A' or 'C'). This class * provides an interface so the developer doesn't have to worry about conversions. */ class AdiPort { From bfbda47c08b5dd2b46a3b0b6ccb3989170a60b63 Mon Sep 17 00:00:00 2001 From: Liam Teale Date: Mon, 26 May 2025 13:28:43 -0700 Subject: [PATCH 41/41] clarify AdiPort docs --- include/pros/devices/port.hpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/include/pros/devices/port.hpp b/include/pros/devices/port.hpp index c4820452..d015e6d9 100644 --- a/include/pros/devices/port.hpp +++ b/include/pros/devices/port.hpp @@ -54,11 +54,11 @@ class SmartPort { */ class AdiPort { // AdiPort instances can only be constructed by the AdiExpander class - friend AdiExpander; + friend class AdiExpander; public: /** - * @brief Get the ADI Port as an uppercase letter + * @brief Get the ADI Port as an uppercase letter ('A' to 'H') * * @return constexpr char */ @@ -67,7 +67,7 @@ class AdiPort { } /** - * @brief Get the ADI Port as an index + * @brief Get the ADI Port as a 0-indexed number (0-7) * * @return constexpr uint8_t */ @@ -75,9 +75,6 @@ class AdiPort { return m_letter - 'A'; } - // users should always use a reference to an AdiPort - AdiPort(AdiPort& other) = delete; - SmartPort host_port; private: