diff --git a/src/host.cmake b/src/host.cmake index 46e575627..10cafc7f9 100644 --- a/src/host.cmake +++ b/src/host.cmake @@ -34,6 +34,7 @@ include (${CMAKE_DIR}/no_hardware.cmake) pico_add_subdirectory(${HOST_DIR}/pico_rand) pico_add_subdirectory(${HOST_DIR}/pico_runtime) pico_add_subdirectory(${HOST_DIR}/pico_printf) + pico_add_subdirectory(${HOST_DIR}/pico_status_led) pico_add_subdirectory(${HOST_DIR}/pico_stdio) pico_add_subdirectory(${HOST_DIR}/pico_stdlib) pico_add_subdirectory(${HOST_DIR}/pico_time_adapter) diff --git a/src/host/pico_status_led/BUILD.bazel b/src/host/pico_status_led/BUILD.bazel new file mode 100644 index 000000000..8c4cf3252 --- /dev/null +++ b/src/host/pico_status_led/BUILD.bazel @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "pico_status_led", + srcs = ["status_led.c"], + hdrs = ["include/pico/status_led.h"], + includes = ["include"], + target_compatible_with = ["//bazel/constraint:host"], + deps = [ + "//src/host/hardware_gpio", + ], +) + diff --git a/src/host/pico_status_led/CMakeLists.txt b/src/host/pico_status_led/CMakeLists.txt new file mode 100644 index 000000000..fe6453327 --- /dev/null +++ b/src/host/pico_status_led/CMakeLists.txt @@ -0,0 +1,10 @@ +pico_add_library(pico_status_led) +target_sources(pico_status_led INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/status_led.c +) +target_include_directories(pico_status_led_headers SYSTEM INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/include +) +pico_mirrored_target_link_libraries(pico_status_led INTERFACE + hardware_gpio +) diff --git a/src/host/pico_status_led/include/pico/status_led.h b/src/host/pico_status_led/include/pico/status_led.h new file mode 100644 index 000000000..c4dc21e43 --- /dev/null +++ b/src/host/pico_status_led/include/pico/status_led.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2025 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** \file pico/status_led.h + * \defgroup pico_status_led pico_status_led + * + * \brief Enables access to the on-board status LED(s) + * + * Boards usually have access to one or two on-board status LEDs which are configured via the board header (PICO_DEFAULT_LED_PIN, CYW43_WL_GPIO_LED_PIN and/or PICO_DEFAULT_WS2812_PIN). + * This library hides the low-level details so you can use the status LEDs for all boards without changing your code. + * \note If your board has both a single-color LED and a colored LED, you can independently control the single-color LED with the `status_led_` APIs, and the colored LED with the `colored_status_led_` APIs + */ + +#ifndef _PICO_STATUS_LED_H +#define _PICO_STATUS_LED_H + +#include "pico.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// PICO_CONFIG: PICO_STATUS_LED_AVAILABLE, Indicate whether a single-color status LED is available, type=bool, default=1 if PICO_DEFAULT_LED_PIN or CYW43_WL_GPIO_LED_PIN is defined; may be set by the user to 0 to not use either even if they are available, group=pico_status_led +#ifndef PICO_STATUS_LED_AVAILABLE +#define PICO_STATUS_LED_AVAILABLE 1 +#endif + +// PICO_CONFIG: PICO_COLORED_STATUS_LED_AVAILABLE, Indicate whether a colored status LED is available, type=bool, default=1 if PICO_DEFAULT_WS2812_PIN is defined; may be set by the user to 0 to not use the colored status LED even if available, group=pico_status_led +#ifndef PICO_COLORED_STATUS_LED_AVAILABLE +#define PICO_COLORED_STATUS_LED_AVAILABLE 1 +#endif + +// PICO_CONFIG: PICO_STATUS_LED_VIA_COLORED_STATUS_LED, Indicate if the colored status LED should be used for both status_led and colored_status_led APIs, type=bool, default=1 if PICO_COLORED_STATUS_LED_AVAILABLE is 1 and PICO_STATUS_LED_AVAILABLE is 0, group=pico_status_led +#ifndef PICO_STATUS_LED_VIA_COLORED_STATUS_LED +#define PICO_STATUS_LED_VIA_COLORED_STATUS_LED (PICO_COLORED_STATUS_LED_AVAILABLE && !PICO_STATUS_LED_AVAILABLE) +#endif + +// PICO_CONFIG: PICO_COLORED_STATUS_LED_USES_WRGB, Indicate if the colored status LED supports WRGB, type=bool, default=0, group=pico_status_led +#ifndef PICO_COLORED_STATUS_LED_USES_WRGB +#define PICO_COLORED_STATUS_LED_USES_WRGB 0 +#endif + +/*! \brief Generate an RGB color value for /ref colored_status_led_set_on_with_color + * \ingroup pico_status_led + */ +#ifndef PICO_COLORED_STATUS_LED_COLOR_FROM_RGB +#define PICO_COLORED_STATUS_LED_COLOR_FROM_RGB(r, g, b) (((r) << 16) | ((g) << 8) | (b)) +#endif + +/*! \brief Generate an WRGB color value for \ref colored_status_led_set_on_with_color + * \ingroup pico_status_led + * + * \note If your hardware does not support a white pixel, the white component is ignored + */ +#ifndef PICO_COLORED_STATUS_LED_COLOR_FROM_WRGB +#define PICO_COLORED_STATUS_LED_COLOR_FROM_WRGB(w, r, g, b) (((w) << 24) | ((r) << 16) | ((g) << 8) | (b)) +#endif + +// PICO_CONFIG: PICO_DEFAULT_COLORED_STATUS_LED_ON_COLOR, the default pixel color value of the colored status LED when it is on, type=int, group=pico_status_led +#ifndef PICO_DEFAULT_COLORED_STATUS_LED_ON_COLOR +#if PICO_COLORED_STATUS_LED_USES_WRGB +#define PICO_DEFAULT_COLORED_STATUS_LED_ON_COLOR PICO_COLORED_STATUS_LED_COLOR_FROM_WRGB(0xaa, 0, 0, 0) +#else +#define PICO_DEFAULT_COLORED_STATUS_LED_ON_COLOR PICO_COLORED_STATUS_LED_COLOR_FROM_RGB(0xaa, 0xaa, 0xaa) +#endif +#endif + +struct async_context; + +/*! \brief Initialize the status LED(s) + * \ingroup pico_status_led + * + * Initialize the status LED(s) and the resources they need before use. On some devices (e.g. Pico W, Pico 2 W) accessing + * the status LED requires talking to the WiFi chip, which requires an \ref async_context. + * This method will create an async_context for you. + * + * However an application should only use a single \ref async_context instance to talk to the WiFi chip. + * If the application already has an async context (e.g. created by cyw43_arch_init) you should use \ref + * status_led_init_with_context instead and pass it the \ref async_context already created by your application + * + * \note You must call this function (or \ref status_led_init_with_context) before using any other pico_status_led functions. + * + * \return Returns true if the LED was initialized successfully, otherwise false on failure + * \sa status_led_init_with_context + */ +bool status_led_init(void); + +/*! \brief Initialise the status LED(s) + * \ingroup pico_status_led + * + * Initialize the status LED(s) and the resources they need before use. + * + * \note You must call this function (or \ref status_led_init) before using any other pico_status_led functions. + * + * \param context An \ref async_context used to communicate with the status LED (e.g. on Pico W or Pico 2 W) + * \return Returns true if the LED was initialized successfully, otherwise false on failure + * \sa status_led_init_with_context + */ +bool status_led_init_with_context(struct async_context *context); + +/*! \brief Determine if the `colored_status_led_` APIs are supported (i.e. if there is a colored status LED, and its + * use isn't disabled via \ref PICO_COLORED_STATUS_LED_AVAILABLE being set to 0 + * \ingroup pico_status_led + * \return true if the colored status LED API is available and expected to produce visible results + * \sa PICO_COLORED_STATUS_LED_AVAILABLE + */ +static inline bool colored_status_led_supported(void) { + return PICO_COLORED_STATUS_LED_AVAILABLE; +} + +/*! \brief Determine if the colored status LED is being used for the single-color `status_led_` APIs + * \ingroup pico_status_led + * \return true if the colored status LED is being used for the single-color `status_led_` API + * \sa PICO_STATUS_LED_VIA_COLORED_STATUS_LED + */ +static inline bool status_led_via_colored_status_led(void) { + return PICO_STATUS_LED_VIA_COLORED_STATUS_LED; +} + +/*! \brief Determine if the single-color `status_led_` APIs are supported (i.e. if there is a regular LED, and its + * use isn't disabled via \ref PICO_STATUS_LED_AVAILABLE being set to 0, or if the colored status LED is being used for + * the single-color `status_led_` APIs + * \ingroup pico_status_led + * \return true if the single-color status LED API is available and expected to produce visible results + * \sa PICO_STATUS_LED_AVAILABLE + * \sa PICO_STATUS_LED_VIA_COLORED_STATUS_LED + */ +static inline bool status_led_supported(void) { + if (status_led_via_colored_status_led()) { + return colored_status_led_supported(); + } + return PICO_STATUS_LED_AVAILABLE; +} + +/*! \brief Set the colored status LED on or off + * \ingroup pico_status_led + * + * \note If your hardware does not support a colored status LED (PICO_DEFAULT_WS2812_PIN), this function does nothing and returns false. + * + * \param led_on true to turn the colored LED on. Pass false to turn the colored LED off + * \return true if the colored status LED could be set, otherwise false + */ +bool colored_status_led_set_state(bool led_on); + +/*! \brief Get the state of the colored status LED + * \ingroup pico_status_led + * + * \note If your hardware does not support a colored status LED (PICO_DEFAULT_WS2812_PIN), this function returns false. + * + * \return true if the colored status LED is on, or false if the colored status LED is off + */ +bool colored_status_led_get_state(void); + +/*! \brief Ensure the colored status LED is on, with the specified color + * \ingroup pico_status_led + * + * \note If your hardware does not support a colored status LED (PICO_DEFAULT_WS2812_PIN), this function does nothing and returns false. + * + * \param color The color to use for the colored status LED when it is on, in 0xWWRRGGBB format + * \return true if the colored status LED could be set, otherwise false on failure + */ +bool colored_status_led_set_on_with_color(uint32_t color); + +/*! \brief Get the color used for the status LED value when it is on + * \ingroup pico_status_led + * + * \note If your hardware does not support a colored status LED (PICO_DEFAULT_WS2812_PIN), this function always returns 0x0. + * +* \return The color used for the colored status LED when it is on, in 0xWWRRGGBB format +*/ +uint32_t colored_status_led_get_on_color(void); + +/*! \brief Set the status LED on or off +* \ingroup pico_status_led +* +* \note If your hardware does not support a status LED, this function does nothing and returns false. +* +* \param led_on true to turn the LED on. Pass false to turn the LED off +* \return true if the status LED could be set, otherwise false +*/ +bool status_led_set_state(bool led_on); + +/*! \brief Get the state of the status LED + * \ingroup pico_status_led + * + * \note If your hardware does not support a status LED, this function always returns false. + * + * \return true if the status LED is on, or false if the status LED is off + */ +bool status_led_get_state(); + +/*! \brief De-initialize the status LED(s) + * \ingroup pico_status_led + * + * De-initializes the status LED(s) when they are no longer needed. + */ +void status_led_deinit(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/host/pico_status_led/status_led.c b/src/host/pico_status_led/status_led.c new file mode 100644 index 000000000..b5d079798 --- /dev/null +++ b/src/host/pico_status_led/status_led.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "pico/status_led.h" + +static bool status_led_on; +static uint32_t colored_status_led_on_color = PICO_DEFAULT_COLORED_STATUS_LED_ON_COLOR; +static bool colored_status_led_on; + +bool status_led_set_state(bool led_on) { + bool success = false; + if (status_led_supported()) { + success = true; + } + if (success) status_led_on = led_on; + return success; +} + +bool status_led_get_state(void) { + return status_led_on; +} + +bool colored_status_led_set_on_with_color(uint32_t color) { + colored_status_led_on_color = color; + return colored_status_led_set_state(true); +} + +uint32_t colored_status_led_get_on_color(void) { + return colored_status_led_on_color; +} + +bool colored_status_led_set_state(bool led_on) { + bool success = false; + if (colored_status_led_supported()) { + success = true; + } + if (success) colored_status_led_on = led_on; + return success; +} + +bool colored_status_led_get_state(void) { + return colored_status_led_on; +} + +bool status_led_init(void) { + return true; +} + +bool status_led_init_with_context(__unused struct async_context *context) { + return true; +} + +void status_led_deinit(void) { +}