Merge pull request #6960 from jepler/picow-server

Pico W: implement more things
This commit is contained in:
Jeff Epler 2022-09-30 11:15:37 -05:00 committed by GitHub
commit fcf7cfe838
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 203 additions and 28 deletions

View File

@ -213,6 +213,7 @@ exclude_patterns = ["**/build*",
"ports/nrf/peripherals", "ports/nrf/peripherals",
"ports/nrf/usb", "ports/nrf/usb",
"ports/raspberrypi/sdk", "ports/raspberrypi/sdk",
"ports/raspberrypi/lib",
"ports/stm/st_driver", "ports/stm/st_driver",
"ports/stm/packages", "ports/stm/packages",
"ports/stm/peripherals", "ports/stm/peripherals",

View File

@ -65,7 +65,7 @@ INC_CYW43 := \
-isystem sdk/src/rp2_common/pico_cyw43_arch/include/ \ -isystem sdk/src/rp2_common/pico_cyw43_arch/include/ \
-isystem sdk/src/rp2_common/pico_lwip/include/ \ -isystem sdk/src/rp2_common/pico_lwip/include/ \
CFLAGS_CYW43 := -DCYW43_LWIP=1 -DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_USE_SPI -DIGNORE_GPIO25 -DCYW43_LOGIC_DEBUG=0 CFLAGS_CYW43 := -DCYW43_LWIP=1 -DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_USE_SPI -DIGNORE_GPIO25 -DIGNORE_GPIO23 -DCYW43_LOGIC_DEBUG=0
SRC_SDK_CYW43 := \ SRC_SDK_CYW43 := \
src/common/pico_sync/sem.c \ src/common/pico_sync/sem.c \
src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.c \ src/rp2_common/cyw43_driver/cyw43_bus_pio_spi.c \
@ -110,21 +110,6 @@ $(BUILD)/cyw43_resource.o: lib/cyw43-driver/firmware/$(CYW43_FIRMWARE_BIN)
--redefine-sym _binary_lib_cyw43_driver_firmware_43439A0_7_95_49_00_combined_end=fw_43439A0_7_95_49_00_end \ --redefine-sym _binary_lib_cyw43_driver_firmware_43439A0_7_95_49_00_combined_end=fw_43439A0_7_95_49_00_end \
$< $@ $< $@
OBJ_CYW43 := $(BUILD)/cyw43_resource.o OBJ_CYW43 := $(BUILD)/cyw43_resource.o
# need to do the equivalent of this in cmake
### # cyw43_resource.o contains the WiFi and BT firmware as a binary blob
### add_custom_command(
### OUTPUT ${CYW43_FIRMWARE_OBJ}
### DEPENDS ${PICO_CYW43_DRIVER_PATH}/firmware/${CYW43_FIRMWARE_BIN}
### WORKING_DIRECTORY ${PICO_CYW43_DRIVER_PATH}/firmware
### COMMAND ${CMAKE_OBJCOPY} -I binary -O elf32-littlearm -B arm
### --readonly-text
### --rename-section .data=${RESOURCE_SECNAME},${RESOURCE_SECFLAGS}
### --redefine-sym _binary_${CYW43_FIRMWARE_BIN_}_start=${CYW43_FIRMWARE_PRETTY}_start
### --redefine-sym _binary_${CYW43_FIRMWARE_BIN_}_end=${CYW43_FIRMWARE_PRETTY}_end
### --redefine-sym _binary_${CYW43_FIRMWARE_BIN_}_size=${CYW43_FIRMWARE_PRETTY}_size
### ${CYW43_FIRMWARE_BIN} ${CYW43_FIRMWARE_OBJ}
### )
###
else else
INC_CYW43 := INC_CYW43 :=
CFLAGS_CYW43 := CFLAGS_CYW43 :=

View File

@ -32,6 +32,12 @@
#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Pin.h"
#include "bindings/cyw43/__init__.h" #include "bindings/cyw43/__init__.h"
//| class CywPin:
//| """A class that represents a GPIO pin attached to the wifi chip.
//|
//| Cannot be constructed at runtime, but may be the type of a pin object
//| in :py:mod:`board`. A `CywPin` can be used as a DigitalInOut, but not with other
//| peripherals such as `PWMOut`."""
const mp_obj_type_t cyw43_pin_type = { const mp_obj_type_t cyw43_pin_type = {
{ &mp_type_type }, { &mp_type_type },
.flags = MP_TYPE_FLAG_EXTENDED, .flags = MP_TYPE_FLAG_EXTENDED,
@ -42,6 +48,22 @@ const mp_obj_type_t cyw43_pin_type = {
) )
}; };
//| def set_power_management(value: int) -> None:
//| """Set the power management register
//|
//| According to Raspberry Pi documentation, the value 0xa11140
//| increases responsiveness at the cost of higher power usage.
//|
//| Besides this value, there appears to be no other public documentation
//| of the values that can be used.
//| """
STATIC mp_obj_t cyw43_set_power_management(const mp_obj_t value_in) {
mp_int_t value = mp_obj_get_int(value_in);
cyw43_wifi_pm(&cyw43_state, value);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(cyw43_set_power_management_obj, cyw43_set_power_management);
const mcu_pin_obj_t *validate_obj_is_pin_including_cyw43(mp_obj_t obj) { const mcu_pin_obj_t *validate_obj_is_pin_including_cyw43(mp_obj_t obj) {
if (!mp_obj_is_type(obj, &mcu_pin_type) && !mp_obj_is_type(obj, &cyw43_pin_type)) { if (!mp_obj_is_type(obj, &mcu_pin_type) && !mp_obj_is_type(obj, &cyw43_pin_type)) {
mp_raise_TypeError_varg(translate("Expected a %q or %q"), mcu_pin_type.name, cyw43_pin_type.name); mp_raise_TypeError_varg(translate("Expected a %q or %q"), mcu_pin_type.name, cyw43_pin_type.name);
@ -58,6 +80,7 @@ const mcu_pin_obj_t *validate_obj_is_free_pin_including_cyw43(mp_obj_t obj) {
STATIC const mp_rom_map_elem_t cyw43_module_globals_table[] = { STATIC const mp_rom_map_elem_t cyw43_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cyw43) }, { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cyw43) },
{ MP_ROM_QSTR(MP_QSTR_CywPin), MP_ROM_QSTR(MP_QSTR_CywPin) }, { MP_ROM_QSTR(MP_QSTR_CywPin), MP_ROM_QSTR(MP_QSTR_CywPin) },
{ MP_ROM_QSTR(MP_QSTR_set_power_management), &cyw43_set_power_management_obj },
}; };
STATIC MP_DEFINE_CONST_DICT(cyw43_module_globals, cyw43_module_globals_table); STATIC MP_DEFINE_CONST_DICT(cyw43_module_globals, cyw43_module_globals_table);

View File

@ -27,8 +27,8 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) },
{ MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_GPIO23) }, { MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_CYW1) },
{ MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_CYW1) },
{ MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO24) }, { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO24) },
{ MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) },

View File

@ -140,6 +140,11 @@ void common_hal_digitalio_digitalinout_set_value(
bool common_hal_digitalio_digitalinout_get_value( bool common_hal_digitalio_digitalinout_get_value(
digitalio_digitalinout_obj_t *self) { digitalio_digitalinout_obj_t *self) {
#if CIRCUITPY_CYW43
if (IS_CYW(self)) {
return cyw43_arch_gpio_get(self->pin->number);
}
#endif
return gpio_get(self->pin->number); return gpio_get(self->pin->number);
} }

View File

@ -173,7 +173,9 @@ const mp_rom_map_elem_t mcu_pin_global_dict_table[TOTAL_GPIO_COUNT] = {
{ MP_ROM_QSTR(MP_QSTR_GPIO20), MP_ROM_PTR(&pin_GPIO20) }, { MP_ROM_QSTR(MP_QSTR_GPIO20), MP_ROM_PTR(&pin_GPIO20) },
{ MP_ROM_QSTR(MP_QSTR_GPIO21), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_GPIO21), MP_ROM_PTR(&pin_GPIO21) },
{ MP_ROM_QSTR(MP_QSTR_GPIO22), MP_ROM_PTR(&pin_GPIO22) }, { MP_ROM_QSTR(MP_QSTR_GPIO22), MP_ROM_PTR(&pin_GPIO22) },
#if !defined(IGNORE_GPIO23)
{ MP_ROM_QSTR(MP_QSTR_GPIO23), MP_ROM_PTR(&pin_GPIO23) }, { MP_ROM_QSTR(MP_QSTR_GPIO23), MP_ROM_PTR(&pin_GPIO23) },
#endif
{ MP_ROM_QSTR(MP_QSTR_GPIO24), MP_ROM_PTR(&pin_GPIO24) }, { MP_ROM_QSTR(MP_QSTR_GPIO24), MP_ROM_PTR(&pin_GPIO24) },
#if !defined(IGNORE_GPIO25) #if !defined(IGNORE_GPIO25)
{ MP_ROM_QSTR(MP_QSTR_GPIO25), MP_ROM_PTR(&pin_GPIO25) }, { MP_ROM_QSTR(MP_QSTR_GPIO25), MP_ROM_PTR(&pin_GPIO25) },
@ -184,6 +186,7 @@ const mp_rom_map_elem_t mcu_pin_global_dict_table[TOTAL_GPIO_COUNT] = {
{ MP_ROM_QSTR(MP_QSTR_GPIO29), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_GPIO29), MP_ROM_PTR(&pin_GPIO29) },
#if CIRCUITPY_CYW43 #if CIRCUITPY_CYW43
{ MP_ROM_QSTR(MP_QSTR_CYW0), MP_ROM_PTR(&pin_CYW0) }, { MP_ROM_QSTR(MP_QSTR_CYW0), MP_ROM_PTR(&pin_CYW0) },
{ MP_ROM_QSTR(MP_QSTR_CYW1), MP_ROM_PTR(&pin_CYW1) },
#endif #endif
}; };
MP_DEFINE_CONST_DICT(mcu_pin_globals, mcu_pin_global_dict_table); MP_DEFINE_CONST_DICT(mcu_pin_globals, mcu_pin_global_dict_table);

View File

@ -37,6 +37,7 @@
#include "py/stream.h" #include "py/stream.h"
#include "shared-bindings/socketpool/SocketPool.h" #include "shared-bindings/socketpool/SocketPool.h"
#include "shared/runtime/interrupt_char.h" #include "shared/runtime/interrupt_char.h"
#include "shared/netutils/netutils.h"
#include "supervisor/port.h" #include "supervisor/port.h"
#include "supervisor/shared/tick.h" #include "supervisor/shared/tick.h"
#include "supervisor/workflow.h" #include "supervisor/workflow.h"
@ -115,6 +116,10 @@ static inline void poll_sockets(void) {
#ifdef MICROPY_EVENT_POLL_HOOK #ifdef MICROPY_EVENT_POLL_HOOK
MICROPY_EVENT_POLL_HOOK; MICROPY_EVENT_POLL_HOOK;
#else #else
RUN_BACKGROUND_TASKS;
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
mp_handle_pending(true);
}
mp_hal_delay_ms(1); mp_hal_delay_ms(1);
#endif #endif
} }
@ -739,14 +744,117 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_
return -MP_EBADF; return -MP_EBADF;
} }
socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *self, socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *socket,
uint8_t *ip, uint32_t *port) { uint8_t *ip, uint32_t *port) {
mp_raise_NotImplementedError(NULL); if (socket->type != MOD_NETWORK_SOCK_STREAM) {
mp_raise_OSError(MP_EOPNOTSUPP);
}
// Create new socket object, do it here because we must not raise an out-of-memory
// exception when the LWIP concurrency lock is held
socketpool_socket_obj_t *socket2 = m_new_ll_obj_with_finaliser(socketpool_socket_obj_t);
socket2->base.type = &socketpool_socket_type;
MICROPY_PY_LWIP_ENTER
if (socket->pcb.tcp == NULL) {
MICROPY_PY_LWIP_EXIT
m_del_obj(socketpool_socket_obj_t, socket2);
mp_raise_OSError(MP_EBADF);
}
// I need to do this because "tcp_accepted", later, is a macro.
struct tcp_pcb *listener = socket->pcb.tcp;
if (listener->state != LISTEN) {
MICROPY_PY_LWIP_EXIT
m_del_obj(socketpool_socket_obj_t, socket2);
mp_raise_OSError(MP_EINVAL);
}
// accept incoming connection
struct tcp_pcb *volatile *incoming_connection = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iget];
if (*incoming_connection == NULL) {
if (socket->timeout == 0) {
MICROPY_PY_LWIP_EXIT
m_del_obj(socketpool_socket_obj_t, socket2);
mp_raise_OSError(MP_EAGAIN);
} else if (socket->timeout != -1) {
mp_uint_t retries = socket->timeout / 100;
while (*incoming_connection == NULL) {
MICROPY_PY_LWIP_EXIT
if (retries-- == 0) {
m_del_obj(socketpool_socket_obj_t, socket2);
mp_raise_OSError(MP_ETIMEDOUT);
}
mp_hal_delay_ms(100);
MICROPY_PY_LWIP_REENTER
}
} else {
while (*incoming_connection == NULL) {
MICROPY_PY_LWIP_EXIT
poll_sockets();
MICROPY_PY_LWIP_REENTER
}
}
}
// We get a new pcb handle...
socket2->pcb.tcp = *incoming_connection;
if (++socket->incoming.connection.iget >= socket->incoming.connection.alloc) {
socket->incoming.connection.iget = 0;
}
*incoming_connection = NULL;
// ...and set up the new socket for it.
socket2->domain = MOD_NETWORK_AF_INET;
socket2->type = MOD_NETWORK_SOCK_STREAM;
socket2->incoming.pbuf = NULL;
socket2->timeout = socket->timeout;
socket2->state = STATE_CONNECTED;
socket2->recv_offset = 0;
socket2->callback = MP_OBJ_NULL;
tcp_arg(socket2->pcb.tcp, (void *)socket2);
tcp_err(socket2->pcb.tcp, _lwip_tcp_error);
tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv);
tcp_accepted(listener);
MICROPY_PY_LWIP_EXIT
// output values
memcpy(ip, &(socket2->pcb.tcp->remote_ip), NETUTILS_IPV4ADDR_BUFSIZE);
*port = (mp_uint_t)socket2->pcb.tcp->remote_port;
return MP_OBJ_FROM_PTR(socket2);
} }
bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self, bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t *socket,
const char *host, size_t hostlen, uint32_t port) { const char *host, size_t hostlen, uint32_t port) {
mp_raise_NotImplementedError(NULL); uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
// get address
ip_addr_t bind_addr;
int error = socketpool_resolve_host(socket->pool, host, &bind_addr);
if (error != 0) {
mp_raise_OSError(EHOSTUNREACH);
}
err_t err = ERR_ARG;
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
err = tcp_bind(socket->pcb.tcp, &bind_addr, port);
break;
}
case MOD_NETWORK_SOCK_DGRAM: {
err = udp_bind(socket->pcb.udp, &bind_addr, port);
break;
}
}
if (err != ERR_OK) {
mp_raise_OSError(error_lookup_table[-err]);
}
return mp_const_none;
} }
STATIC err_t _lwip_tcp_close_poll(void *arg, struct tcp_pcb *pcb) { STATIC err_t _lwip_tcp_close_poll(void *arg, struct tcp_pcb *pcb) {
@ -891,8 +999,34 @@ bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t *socket)
return socket->state == STATE_CONNECTED; return socket->state == STATE_CONNECTED;
} }
bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *self, int backlog) { bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *socket, int backlog) {
mp_raise_NotImplementedError(NULL); if (socket->type != MOD_NETWORK_SOCK_STREAM) {
mp_raise_OSError(MP_EOPNOTSUPP);
}
struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog);
if (new_pcb == NULL) {
mp_raise_OSError(MP_ENOMEM);
}
socket->pcb.tcp = new_pcb;
// Allocate memory for the backlog of connections
if (backlog <= 1) {
socket->incoming.connection.alloc = 0;
socket->incoming.connection.tcp.item = NULL;
} else {
socket->incoming.connection.alloc = backlog;
socket->incoming.connection.tcp.array = m_new0(struct tcp_pcb *, backlog);
}
socket->incoming.connection.iget = 0;
socket->incoming.connection.iput = 0;
tcp_accept(new_pcb, _lwip_tcp_accept);
// Socket is no longer considered "new" for purposes of polling
socket->state = STATE_LISTENING;
return mp_const_none;
} }
mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *socket, mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *socket,

View File

@ -59,6 +59,17 @@
#define NETIF_STA (&cyw43_state.netif[CYW43_ITF_STA]) #define NETIF_STA (&cyw43_state.netif[CYW43_ITF_STA])
#define NETIF_AP (&cyw43_state.netif[CYW43_ITF_AP]) #define NETIF_AP (&cyw43_state.netif[CYW43_ITF_AP])
static inline uint32_t nw_get_le32(const uint8_t *buf) {
return buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
}
static inline void nw_put_le32(uint8_t *buf, uint32_t x) {
buf[0] = x;
buf[1] = x >> 8;
buf[2] = x >> 16;
buf[3] = x >> 24;
}
NORETURN static void ro_attribute(int attr) { NORETURN static void ro_attribute(int attr) {
mp_raise_msg_varg(&mp_type_AttributeError, MP_ERROR_TEXT("'%s' object has no attribute '%q'"), "Radio", attr); mp_raise_msg_varg(&mp_type_AttributeError, MP_ERROR_TEXT("'%s' object has no attribute '%q'"), "Radio", attr);
} }
@ -81,7 +92,10 @@ mp_obj_t common_hal_wifi_radio_get_hostname(wifi_radio_obj_t *self) {
} }
void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *hostname) { void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *hostname) {
ro_attribute(MP_QSTR_hostname); assert(strlen(hostname) < MP_ARRAY_SIZE(self->hostname));
memcpy(self->hostname, hostname, strlen(hostname));
netif_set_hostname(NETIF_STA, self->hostname);
netif_set_hostname(NETIF_AP, self->hostname);
} }
mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) {
@ -93,12 +107,19 @@ void common_hal_wifi_radio_set_mac_address(wifi_radio_obj_t *self, const uint8_t
} }
mp_float_t common_hal_wifi_radio_get_tx_power(wifi_radio_obj_t *self) { mp_float_t common_hal_wifi_radio_get_tx_power(wifi_radio_obj_t *self) {
return MICROPY_FLOAT_CONST(0.); uint8_t buf[13];
memcpy(buf, "qtxpower\x00\x00\x00\x00\x00", 13);
cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_VAR, 13, buf, CYW43_ITF_STA);
return nw_get_le32(buf) * MICROPY_FLOAT_CONST(0.25);
} }
void common_hal_wifi_radio_set_tx_power(wifi_radio_obj_t *self, const mp_float_t tx_power) { void common_hal_wifi_radio_set_tx_power(wifi_radio_obj_t *self, const mp_float_t tx_power) {
ro_attribute(MP_QSTR_tx_power); mp_int_t dbm_times_four = (int)(4 * tx_power);
uint8_t buf[9 + 4];
memcpy(buf, "qtxpower\x00", 9);
nw_put_le32(buf + 9, dbm_times_four);
cyw43_ioctl(&cyw43_state, CYW43_IOCTL_SET_VAR, 9 + 4, buf, CYW43_ITF_STA);
cyw43_ioctl(&cyw43_state, CYW43_IOCTL_SET_VAR, 9 + 4, buf, CYW43_ITF_AP);
} }
mp_obj_t common_hal_wifi_radio_get_mac_address_ap(wifi_radio_obj_t *self) { mp_obj_t common_hal_wifi_radio_get_mac_address_ap(wifi_radio_obj_t *self) {

View File

@ -33,6 +33,7 @@
typedef struct { typedef struct {
mp_obj_base_t base; mp_obj_base_t base;
char hostname[254]; // hostname max is 253 chars, + 1 for trailing NUL
wifi_scannednetworks_obj_t *current_scan; wifi_scannednetworks_obj_t *current_scan;
} wifi_radio_obj_t; } wifi_radio_obj_t;

View File

@ -75,4 +75,5 @@ PIN(28);
PIN(29); PIN(29);
#if CIRCUITPY_CYW43 #if CIRCUITPY_CYW43
CYW_PIN(0); CYW_PIN(0);
CYW_PIN(1);
#endif #endif

View File

@ -72,6 +72,7 @@ extern const mcu_pin_obj_t pin_GPIO29;
#if CIRCUITPY_CYW43 #if CIRCUITPY_CYW43
extern const mcu_pin_obj_t pin_CYW0; extern const mcu_pin_obj_t pin_CYW0;
extern const mcu_pin_obj_t pin_CYW1;
#endif #endif
#endif // MICROPY_INCLUDED_RASPBERRYPI_PERIPHERALS_PINS_H #endif // MICROPY_INCLUDED_RASPBERRYPI_PERIPHERALS_PINS_H