Skip to content

Commit 9227cad

Browse files
add pico_status_led (#2501)
Co-authored-by: graham sanderson <[email protected]>
1 parent bb66fdf commit 9227cad

File tree

12 files changed

+546
-9
lines changed

12 files changed

+546
-9
lines changed

docs/index.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
* \cond pico_multicore \defgroup pico_multicore pico_multicore \endcond
6565
* \cond pico_rand \defgroup pico_rand pico_rand \endcond
6666
* \cond pico_sha256 \defgroup pico_sha256 pico_sha256 \endcond
67+
* \cond pico_status_led \defgroup pico_status_led pico_status_led \endcond
6768
* \cond pico_stdlib \defgroup pico_stdlib pico_stdlib \endcond
6869
* \cond pico_sync \defgroup pico_sync pico_sync \endcond
6970
* \cond pico_time \defgroup pico_time pico_time \endcond

src/cmake/rp2_common.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ if (NOT PICO_BARE_METAL)
140140
pico_add_subdirectory(rp2_common/pico_standard_link)
141141

142142
pico_add_subdirectory(rp2_common/pico_fix)
143+
pico_add_subdirectory(rp2_common/pico_status_led)
143144

144145
# at the end as it includes a lot of other stuff
145146
pico_add_subdirectory(rp2_common/pico_runtime_init)

src/rp2_common/pico_cyw43_driver/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ if (EXISTS ${PICO_CYW43_DRIVER_PATH}/${CYW43_DRIVER_TEST_FILE})
4141
target_sources(pico_cyw43_driver INTERFACE
4242
cyw43_driver.c)
4343
target_include_directories(pico_cyw43_driver_headers SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
44-
pico_mirrored_target_link_libraries(pico_cyw43_driver INTERFACE cyw43_driver)
44+
pico_mirrored_target_link_libraries(pico_cyw43_driver INTERFACE cyw43_driver pico_unique_id)
4545

4646
# cyw43_driver_picow is cyw43_driver plus Pico W specific bus implementation
4747
pico_add_library(cyw43_driver_picow NOFLAG)

src/rp2_common/pico_cyw43_driver/cyw43_driver.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,20 +275,20 @@ void cyw43_delay_us(uint32_t us) {
275275
}
276276

277277
#if !CYW43_LWIP
278-
static void no_lwip_fail() {
278+
static void no_lwip_fail(void) {
279279
panic("cyw43 has no ethernet interface");
280280
}
281-
void __attribute__((weak)) cyw43_cb_tcpip_init(cyw43_t *self, int itf) {
281+
void __attribute__((weak)) cyw43_cb_tcpip_init(__unused cyw43_t *self, __unused int itf) {
282282
}
283-
void __attribute__((weak)) cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
283+
void __attribute__((weak)) cyw43_cb_tcpip_deinit(__unused cyw43_t *self, __unused int itf) {
284284
}
285-
void __attribute__((weak)) cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {
285+
void __attribute__((weak)) cyw43_cb_tcpip_set_link_up(__unused cyw43_t *self, __unused int itf) {
286286
no_lwip_fail();
287287
}
288-
void __attribute__((weak)) cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {
288+
void __attribute__((weak)) cyw43_cb_tcpip_set_link_down(__unused cyw43_t *self, __unused int itf) {
289289
no_lwip_fail();
290290
}
291-
void __attribute__((weak)) cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
291+
void __attribute__((weak)) cyw43_cb_process_ethernet(__unused void *cb_data, __unused int itf, __unused size_t len, __unused const uint8_t *buf) {
292292
no_lwip_fail();
293293
}
294294
#endif

src/rp2_common/pico_cyw43_driver/include/cyw43_configport.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ void cyw43_post_poll_hook(void);
211211
#define CYW43_PRINTF(...) (void)0
212212
#endif
213213

214+
// PICO_CONFIG: CYW43_LWIP_DEFAULT, Sets the default value of CYW43_LWIP if it's undefined. CYW43_LWIP defines if cyw43-driver uses LwIP. The default behavior - if it's not defined anywhere - is to set it to 1 and cyw43-driver will use lwIP requiring you to provide an lwipopts.h header file. You can set CYW43_LWIP_DEFAULT to change the default to 0 and avoid using lwIP if CYW43_LWIP is undefined, type=bool, group=pico_cyw43_driver
215+
#if !defined CYW43_LWIP && defined CYW43_LWIP_DEFAULT
216+
#define CYW43_LWIP CYW43_LWIP_DEFAULT
217+
#endif
218+
214219
#ifdef __cplusplus
215220
}
216221
#endif

src/rp2_common/pico_lwip/lwip_freertos.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ static void tcpip_init_done(void *param) {
2525
}
2626

2727
bool lwip_freertos_init(async_context_t *context) {
28-
assert(!lwip_context);
29-
lwip_context = context;
28+
assert(!lwip_context || lwip_context == context);
3029
static bool done_lwip_init;
3130
if (!done_lwip_init) {
31+
lwip_context = context;
3232
done_lwip_init = true;
3333
SemaphoreHandle_t init_sem = xSemaphoreCreateBinary();
3434
tcpip_task_blocker = xSemaphoreCreateBinary();
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
load("//bazel:defs.bzl", "compatible_with_rp2", "pico_generate_pio_header")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
cc_library(
6+
name = "pico_status_led",
7+
srcs = ["status_led.c"],
8+
hdrs = ["include/pico/status_led.h"],
9+
includes = ["include"],
10+
target_compatible_with = compatible_with_rp2(),
11+
deps = [
12+
"//src/rp2_common/hardware_gpio",
13+
"//src/rp2_common/hardware_pio",
14+
] + select({
15+
"//bazel/constraint:is_pico_w": [
16+
"//src/rp2_common/pico_cyw43_driver",
17+
],
18+
"//bazel/constraint:is_pico2_w": [
19+
"//src/rp2_common/pico_cyw43_driver"
20+
],
21+
"//conditions:default": [],
22+
}),
23+
)
24+
25+
pico_generate_pio_header(
26+
name = "ws2812",
27+
srcs = ["ws2812.pio"],
28+
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
pico_add_library(pico_status_led)
2+
target_sources(pico_status_led INTERFACE
3+
${CMAKE_CURRENT_LIST_DIR}/status_led.c
4+
)
5+
target_include_directories(pico_status_led_headers SYSTEM INTERFACE
6+
${CMAKE_CURRENT_LIST_DIR}/include
7+
)
8+
pico_mirrored_target_link_libraries(pico_status_led INTERFACE
9+
hardware_gpio
10+
hardware_pio
11+
)
12+
if (PICO_CYW43_SUPPORTED)
13+
pico_mirrored_target_link_libraries(pico_status_led INTERFACE
14+
pico_cyw43_driver cyw43_driver_picow pico_async_context_threadsafe_background
15+
)
16+
target_compile_definitions(pico_status_led INTERFACE
17+
CYW43_LWIP_DEFAULT=0 # Disable LwIP by default. Can be overridden if LwIP is needed.
18+
)
19+
endif()
20+
pico_generate_pio_header(pico_status_led ${CMAKE_CURRENT_LIST_DIR}/ws2812.pio)
21+
22+
get_target_property(OUT pico_status_led LINK_LIBRARIES)
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/*
2+
* Copyright (c) 2025 Raspberry Pi (Trading) Ltd.
3+
*
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
/** \file pico/status_led.h
8+
* \defgroup pico_status_led pico_status_led
9+
*
10+
* \brief Enables access to the on-board status LED(s)
11+
*
12+
* Boards usually have access to an on-board status LEDs which are configured via the board header (\see PICO_DEFAULT_LED_PIN and \see PICO_DEFAULT_WS2812_PIN)
13+
* This library hides the details so you can use the status LEDs for all boards without changing your code.
14+
*/
15+
16+
#ifndef _PICO_STATUS_LED_H
17+
#define _PICO_STATUS_LED_H
18+
19+
#include "hardware/gpio.h"
20+
21+
#if defined(CYW43_WL_GPIO_LED_PIN)
22+
#include "cyw43.h"
23+
#endif
24+
25+
struct async_context;
26+
27+
#ifdef __cplusplus
28+
extern "C" {
29+
#endif
30+
31+
// PICO_CONFIG: PICO_STATUS_LED_AVAILABLE, Indicate whether a non-colored 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
32+
#ifndef PICO_STATUS_LED_AVAILABLE
33+
#if defined(PICO_DEFAULT_LED_PIN) || defined(CYW43_WL_GPIO_LED_PIN)
34+
#define PICO_STATUS_LED_AVAILABLE 1
35+
#else
36+
#define PICO_STATUS_LED_AVAILABLE 0
37+
#endif
38+
#endif
39+
40+
// 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
41+
#ifndef PICO_COLORED_STATUS_LED_AVAILABLE
42+
#ifdef PICO_DEFAULT_WS2812_PIN
43+
#define PICO_COLORED_STATUS_LED_AVAILABLE 1
44+
#else
45+
#define PICO_COLORED_STATUS_LED_AVAILABLE 0
46+
#endif
47+
#endif
48+
49+
// 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
50+
#ifndef PICO_STATUS_LED_VIA_COLORED_STATUS_LED
51+
#define PICO_STATUS_LED_VIA_COLORED_STATUS_LED (PICO_COLORED_STATUS_LED_AVAILABLE && !PICO_STATUS_LED_AVAILABLE)
52+
#endif
53+
54+
// PICO_CONFIG: PICO_COLORED_STATUS_LED_USES_WRGB, Indicate if the colored status LED supports WRGB, type=bool, default=0, group=pico_status_led
55+
#ifndef PICO_COLORED_STATUS_LED_USES_WRGB
56+
#define PICO_COLORED_STATUS_LED_USES_WRGB 0
57+
#endif
58+
59+
/*! \brief Generate an RGB color value for /ref colored_status_led_set_on_with_color
60+
* \ingroup pico_status_led
61+
*/
62+
#ifndef PICO_COLORED_STATUS_LED_COLOR_FROM_RGB
63+
#define PICO_COLORED_STATUS_LED_COLOR_FROM_RGB(r, g, b) (((r) << 16) | ((g) << 8) | (b))
64+
#endif
65+
66+
/*! \brief Generate an WRGB color value for \ref colored_status_led_set_on_with_color
67+
* \ingroup pico_status_led
68+
*
69+
* \note: If your hardware does not support a white pixel, the white component is ignored
70+
*/
71+
#ifndef PICO_COLORED_STATUS_LED_COLOR_FROM_WRGB
72+
#define PICO_COLORED_STATUS_LED_COLOR_FROM_WRGB(w, r, g, b) (((w) << 24) | ((r) << 16) | ((g) << 8) | (b))
73+
#endif
74+
75+
// 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
76+
#ifndef PICO_DEFAULT_COLORED_STATUS_LED_ON_COLOR
77+
#if PICO_COLORED_STATUS_LED_USES_WRGB
78+
#define PICO_DEFAULT_COLORED_STATUS_LED_ON_COLOR PICO_COLORED_STATUS_LED_COLOR_FROM_WRGB(0xaa, 0, 0, 0)
79+
#else
80+
#define PICO_DEFAULT_COLORED_STATUS_LED_ON_COLOR PICO_COLORED_STATUS_LED_COLOR_FROM_RGB(0xaa, 0xaa, 0xaa)
81+
#endif
82+
#endif
83+
84+
/*! \brief Initialize the status LED(s)
85+
* \ingroup pico_status_led
86+
*
87+
* Initialize the status LED(s) and the resources they need before use. On some devices (e.g. Pico W, Pico 2 W) accessing
88+
* the status LED requires talking to the WiFi chip, which requires an \ref async_context.
89+
* This method will create an async_context for you.
90+
*
91+
* However an application should only use a single \ref async_context instance to talk to the WiFi chip.
92+
* If the application already has an async context (e.g. created by cyw43_arch_init) you should use \ref
93+
* status_led_init_with_context instead and pass it the \ref async_context already created by your application
94+
*
95+
* \note: You must call this function (or \ref status_led_init_with_context) before using any other pico_status_led functions.
96+
*
97+
* \return Returns true if the LED was initialized successfully, otherwise false on failure
98+
* \sa status_led_init_with_context
99+
*/
100+
bool status_led_init(void);
101+
102+
/*! \brief Initialise the status LED(s)
103+
* \ingroup pico_status_led
104+
*
105+
* Initialize the status LED(s) and the resources they need before use.
106+
*
107+
* \note: You must call this function (or \ref status_led_init) before using any other pico_status_led functions.
108+
*
109+
* \param context An \ref async_context used to communicate with the status LED (e.g. on Pico W or Pico 2 W)
110+
* \return Returns true if the LED was initialized successfully, otherwise false on failure
111+
* \sa status_led_init_with_context
112+
*/
113+
bool status_led_init_with_context(struct async_context *context);
114+
115+
/*! \brief Determine if the `colored_status_led_` APIs are supported (i.e. if there is a colored status LED, and its
116+
* use isn't disabled via \ref PICO_COLORED_STATUS_LED_AVAILABLE being set to 0
117+
* \ingroup pico_status_led
118+
* \return true if the colored status LED API is available and expected to produce visible results
119+
* \sa PICO_COLORED_STATUS_LED_AVAILABLE
120+
*/
121+
static inline bool colored_status_led_supported(void) {
122+
return PICO_COLORED_STATUS_LED_AVAILABLE;
123+
}
124+
125+
/*! \brief Determine if the colored status LED is being used for the non-colored `status_led_` APIs
126+
* \ingroup pico_status_led
127+
* \return true if the olored status LED is being used for the non-colored `status_led_` API
128+
* \sa PICO_STATUS_LED_VIA_COLORED_STATUS_LED
129+
*/
130+
static inline bool status_led_via_colored_status_led(void) {
131+
return PICO_STATUS_LED_VIA_COLORED_STATUS_LED;
132+
}
133+
134+
/*! \brief Determine if the non-colored `status_led_` APIs are supported (i.e. if there is a regular LED, and its
135+
* use isn't disabled via \ref PICO_STATUS_LED_AVAILABLE being set to 0, or if the colored status LED is being used for
136+
* \ingroup pico_status_led
137+
* \return true if the non-colored status LED API is available and expected to produce visible results
138+
* \sa PICO_STATUS_LED_AVAILABLE
139+
* \sa PICO_STATUS_LED_VIA_COLORED_STATUS_LED
140+
*/
141+
static inline bool status_led_supported(void) {
142+
if (status_led_via_colored_status_led()) {
143+
return colored_status_led_supported();
144+
}
145+
return PICO_STATUS_LED_AVAILABLE;
146+
}
147+
148+
/*! \brief Set the colored status LED on or off
149+
* \ingroup pico_status_led
150+
*
151+
* \note: If your hardware does not support a colored status LED (\see PICO_DEFAULT_WS2812_PIN), this function does nothing and returns false.
152+
*
153+
* \param led_on true to turn the colored LED on. Pass false to turn the colored LED off
154+
* \return true if the colored status LED could be set, otherwise false
155+
*/
156+
bool colored_status_led_set_state(bool led_on);
157+
158+
/*! \brief Get the state of the colored status LED
159+
* \ingroup pico_status_led
160+
*
161+
* \note: If your hardware does not support a colored status LED (\see PICO_DEFAULT_WS2812_PIN), this function returns false.
162+
*
163+
* \return true if the colored status LED is on, or false if the colored status LED is off
164+
*/
165+
bool colored_status_led_get_state(void);
166+
167+
/*! \brief Ensure the colored status LED is on, with the specified color
168+
* \ingroup pico_status_led
169+
*
170+
* \note: If your hardware does not support a colored status LED (\see PICO_DEFAULT_WS2812_PIN), this function does nothing and returns false.
171+
*
172+
* \param color The color to use for the colored status LED when it is on, in 0xWWRRGGBB format
173+
* \return true if the coloured status LED could be set, otherwise false on failure
174+
*/
175+
bool colored_status_led_set_on_with_color(uint32_t color);
176+
177+
/*! \brief Get the color used for the status LED value when it is on
178+
* \ingroup pico_status_led
179+
*
180+
* \note: If your hardware does not support a colored status LED (\see PICO_DEFAULT_WS2812_PIN), this function always returns 0x0.
181+
*
182+
* \return The color used for the colored status LED when it is on, in 0xWWRRGGBB format
183+
*/
184+
uint32_t colored_status_led_get_on_color(void);
185+
186+
/*! \brief Set the status LED on or off
187+
* \ingroup pico_status_led
188+
*
189+
* \note: If your hardware does not support a status LED (\see PICO_DEFAULT_LED_PIN), this function does nothing and returns false.
190+
*
191+
* \param led_on true to turn the LED on. Pass false to turn the LED off
192+
* \return true if the status LED could be set, otherwise false
193+
*/
194+
static inline bool status_led_set_state(bool led_on) {
195+
if (status_led_via_colored_status_led()) {
196+
return colored_status_led_set_state(led_on);
197+
} else if (status_led_supported()) {
198+
#if defined(PICO_DEFAULT_LED_PIN)
199+
#if PICO_DEFAULT_LED_PIN_INVERTED
200+
gpio_put(PICO_DEFAULT_LED_PIN, !led_on);
201+
#else
202+
gpio_put(PICO_DEFAULT_LED_PIN, led_on);
203+
#endif
204+
return true;
205+
#elif defined(CYW43_WL_GPIO_LED_PIN)
206+
cyw43_gpio_set(&cyw43_state, CYW43_WL_GPIO_LED_PIN, led_on);
207+
return true;
208+
#endif
209+
}
210+
return false;
211+
}
212+
213+
/*! \brief Get the state of the status LED
214+
* \ingroup pico_status_led
215+
*
216+
* \note: If your hardware does not support a status LED (\see PICO_DEFAULT_LED_PIN), this function always returns false.
217+
*
218+
* \return true if the status LED is on, or false if the status LED is off
219+
*/
220+
static inline bool status_led_get_state() {
221+
if (status_led_via_colored_status_led()) {
222+
return colored_status_led_get_state();
223+
} else if (status_led_supported()) {
224+
#if defined(PICO_DEFAULT_LED_PIN)
225+
#if PICO_DEFAULT_LED_PIN_INVERTED
226+
return !gpio_get(PICO_DEFAULT_LED_PIN);
227+
#else
228+
return gpio_get(PICO_DEFAULT_LED_PIN);
229+
#endif
230+
#elif defined CYW43_WL_GPIO_LED_PIN
231+
bool value = false;
232+
cyw43_gpio_get(&cyw43_state, CYW43_WL_GPIO_LED_PIN, &value);
233+
return value;
234+
#endif
235+
}
236+
return false;
237+
}
238+
239+
/*! \brief De-initialize the status LED(s)
240+
* \ingroup pico_status_led
241+
*
242+
* De-initializes the status LED(s) when they are no longer needed.
243+
*/
244+
void status_led_deinit();
245+
246+
#ifdef __cplusplus
247+
}
248+
#endif
249+
250+
#endif

0 commit comments

Comments
 (0)