Skip to content

File port_rp2040.c

File List > port > rp2040 > port_rp2040.c

Go to the documentation of this file

#if defined(PICO_BOARD) && !defined(ARDUINO)

#include "hardware/sync.h"
#include "hardware/watchdog.h"
#include "pico/stdlib.h"
#include "syntropic/common/syn_defs.h"
#include "syntropic/port/syn_port_gpio.h"
#include "syntropic/port/syn_port_system.h"
#include "syntropic/port/syn_port_uart.h"

/* ── System Port ────────────────────────────────────────────────────────── */

static uint32_t critical_status = 0;
static uint32_t critical_nesting = 0;

void syn_port_enter_critical(void)
{
    uint32_t status = save_and_disable_interrupts();
    if (critical_nesting == 0) {
        critical_status = status;
    }
    critical_nesting++;
}

void syn_port_exit_critical(void)
{
    if (critical_nesting > 0) {
        critical_nesting--;
        if (critical_nesting == 0) {
            restore_interrupts(critical_status);
        }
    }
}

uint32_t syn_port_get_tick_ms(void)
{
    return to_ms_since_boot(get_absolute_time());
}

void syn_port_delay_ms(uint32_t ms)
{
    sleep_ms(ms);
}

void syn_port_system_reset(void)
{
    // Reboot immediately using watchdog register control
    watchdog_reboot(0, 0, 0);
    for (;;)
        ;
}

/* ── GPIO Port ──────────────────────────────────────────────────────────── */

SYN_Status syn_port_gpio_init(SYN_GPIO_Pin pin, SYN_GPIO_Mode mode)
{
    gpio_init(pin);
    switch (mode) {
    case SYN_GPIO_INPUT:
        gpio_set_dir(pin, GPIO_IN);
        break;
    case SYN_GPIO_OUTPUT:
        gpio_set_dir(pin, GPIO_OUT);
        break;
    case SYN_GPIO_INPUT_PULLUP:
        gpio_set_dir(pin, GPIO_IN);
        gpio_pull_up(pin);
        break;
    case SYN_GPIO_INPUT_PULLDOWN:
        gpio_set_dir(pin, GPIO_IN);
        gpio_pull_down(pin);
        break;
    default:
        return SYN_NOT_IMPLEMENTED;
    }
    return SYN_OK;
}

SYN_Status syn_port_gpio_deinit(SYN_GPIO_Pin pin)
{
    gpio_deinit(pin);
    return SYN_OK;
}

SYN_Status syn_port_gpio_write(SYN_GPIO_Pin pin, SYN_GPIO_State state)
{
    gpio_put(pin, (state == SYN_GPIO_HIGH) ? 1 : 0);
    return SYN_OK;
}

SYN_GPIO_State syn_port_gpio_read(SYN_GPIO_Pin pin)
{
    return gpio_get(pin) ? SYN_GPIO_HIGH : SYN_GPIO_LOW;
}

SYN_Status syn_port_gpio_toggle(SYN_GPIO_Pin pin)
{
    gpio_put(pin, !gpio_get(pin));
    return SYN_OK;
}

/* ── UART Port ──────────────────────────────────────────────────────────── */

static uart_inst_t *get_uart_instance(SYN_UARTInstance instance)
{
    if (instance == 0)
        return uart0;
    if (instance == 1)
        return uart1;
    return NULL;
}

SYN_Status syn_port_uart_init(SYN_UARTInstance instance, uint32_t baudrate)
{
    uart_inst_t *uart = get_uart_instance(instance);
    if (!uart)
        return SYN_INVALID_PARAM;

    uart_init(uart, baudrate);

    // Set standard GPIO function pins for the UART instance
    if (uart == uart0) {
        gpio_set_function(0, GPIO_FUNC_UART); // TX
        gpio_set_function(1, GPIO_FUNC_UART); // RX
    } else {
        gpio_set_function(8, GPIO_FUNC_UART); // TX
        gpio_set_function(9, GPIO_FUNC_UART); // RX
    }

    return SYN_OK;
}

SYN_Status syn_port_uart_deinit(SYN_UARTInstance instance)
{
    uart_inst_t *uart = get_uart_instance(instance);
    if (!uart)
        return SYN_INVALID_PARAM;
    uart_deinit(uart);
    return SYN_OK;
}

SYN_Status syn_port_uart_transmit(SYN_UARTInstance instance, const uint8_t *data, size_t len,
                                  uint32_t timeout_ms)
{
    uart_inst_t *uart = get_uart_instance(instance);
    if (!uart)
        return SYN_INVALID_PARAM;
    (void)timeout_ms; // Timeout ignored (SDK blocking transmit does not timeout)

    uart_write_blocking(uart, data, len);
    return SYN_OK;
}

SYN_Status syn_port_uart_receive(SYN_UARTInstance instance, uint8_t *data, size_t len,
                                 size_t *received, uint32_t timeout_ms)
{
    uart_inst_t *uart = get_uart_instance(instance);
    if (!uart)
        return SYN_INVALID_PARAM;

    size_t count = 0;
    uint32_t start_ms = syn_port_get_tick_ms();

    while (count < len) {
        if (uart_is_readable(uart)) {
            data[count++] = uart_getc(uart);
        } else {
            if (timeout_ms > 0 && (syn_port_get_tick_ms() - start_ms) >= timeout_ms) {
                break;
            }
            // Yield CPU slightly
            best_effort_wfe_or_timeout(make_timeout_time_us(100));
        }
    }

    if (received)
        *received = count;
    return (count > 0) ? SYN_OK : SYN_TIMEOUT;
}

SYN_Status syn_port_uart_transmit_byte(SYN_UARTInstance instance, uint8_t byte)
{
    uart_inst_t *uart = get_uart_instance(instance);
    if (!uart)
        return SYN_INVALID_PARAM;
    uart_putc(uart, (char)byte);
    return SYN_OK;
}

SYN_Status syn_port_uart_receive_byte(SYN_UARTInstance instance, uint8_t *byte, uint32_t timeout_ms)
{
    uart_inst_t *uart = get_uart_instance(instance);
    if (!uart)
        return SYN_INVALID_PARAM;

    uint32_t start_ms = syn_port_get_tick_ms();
    while (!uart_is_readable(uart)) {
        if (timeout_ms > 0 && (syn_port_get_tick_ms() - start_ms) >= timeout_ms) {
            return SYN_TIMEOUT;
        }
    }
    *byte = (uint8_t)uart_getc(uart);
    return SYN_OK;
}

/* ── Console serial port (Pico SDK stdio) ──────────────────────────────── */

#include "syntropic/port/syn_port_serial.h"

SYN_WEAK SYN_Status syn_port_serial_init(uint32_t baudrate)
{
    (void)baudrate;
    /* stdio_init_all() must be called by the application before this.
     * It configures USB CDC and/or UART console via Pico SDK. */
    return SYN_OK;
}

SYN_WEAK int syn_port_serial_write(const uint8_t *data, size_t len)
{
    for (size_t i = 0; i < len; i++) {
        putchar_raw(data[i]);
    }
    return (int)len;
}

SYN_WEAK int syn_port_serial_read(uint8_t *buf, size_t max_len)
{
    size_t count = 0;
    while (count < max_len) {
        int ch = getchar_timeout_us(0); /* non-blocking */
        if (ch == PICO_ERROR_TIMEOUT)
            break;
        buf[count++] = (uint8_t)ch;
    }
    return (int)count;
}

#endif /* PICO_BOARD && !ARDUINO */