Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cores/arduino/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ zephyr_sources(zephyrCommon.cpp)
zephyr_sources(USB.cpp)
zephyr_sources(itoa.cpp)

zephyr_sources(wiring_analog.cpp)
zephyr_sources(wiring_digital.cpp)
zephyr_sources(wiring_pulse.cpp)
zephyr_sources(Tone.cpp)
zephyr_sources(WMath.cpp)
zephyr_sources(WInterrupts.cpp)

if(DEFINED CONFIG_ARDUINO_ENTRY)
zephyr_sources(main.cpp)
zephyr_sources(threads.cpp)
Expand Down
183 changes: 183 additions & 0 deletions cores/arduino/Tone.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* Copyright (c) 2024 Ayush Singh <ayush@beagleboard.org>
* Copyright (c) 2026 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <Arduino.h>
#include "wiring_private.h"

using namespace zephyr::arduino;

namespace {

#if CONFIG_ARDUINO_MAX_TONES < 0
#define MAX_TONE_PINS DT_PROP_LEN(DT_PATH(zephyr_user), digital_pin_gpios)
#else
#define MAX_TONE_PINS CONFIG_ARDUINO_MAX_TONES
#endif

#define TOGGLES_PER_CYCLE 2ULL

static struct pin_timer {
struct k_timer timer;
uint32_t count{0};
pin_size_t pin{pin_size_t(-1)};
bool infinity{false};
bool timer_initialized{false};
struct k_spinlock lock{};
} arduino_pin_timers[MAX_TONE_PINS];

K_MUTEX_DEFINE(timer_cfg_lock);

void tone_expiry_cb(struct k_timer *timer);

/* Callers must hold timer_cfg_lock while using this helper. */
static struct pin_timer *find_pin_timer(pin_size_t pinNumber, bool active_only) {
for (size_t i = 0; i < ARRAY_SIZE(arduino_pin_timers); i++) {
k_spinlock_key_t key = k_spin_lock(&arduino_pin_timers[i].lock);

if (arduino_pin_timers[i].pin == pinNumber) {
k_spin_unlock(&arduino_pin_timers[i].lock, key);
return &arduino_pin_timers[i];
}

k_spin_unlock(&arduino_pin_timers[i].lock, key);
}

if (active_only) {
return nullptr;
}

for (size_t i = 0; i < ARRAY_SIZE(arduino_pin_timers); i++) {
k_spinlock_key_t key = k_spin_lock(&arduino_pin_timers[i].lock);

if (arduino_pin_timers[i].pin == pin_size_t(-1)) {
arduino_pin_timers[i].pin = pinNumber;
k_spin_unlock(&arduino_pin_timers[i].lock, key);
return &arduino_pin_timers[i];
}

k_spin_unlock(&arduino_pin_timers[i].lock, key);
}

return nullptr;
}

void tone_expiry_cb(struct k_timer *timer) {
struct pin_timer *pt = CONTAINER_OF(timer, struct pin_timer, timer);
k_spinlock_key_t key = k_spin_lock(&pt->lock);
pin_size_t pin = pt->pin;

if (pt->count == 0 && !pt->infinity) {
if (pin != pin_size_t(-1)) {
gpio_pin_set_dt(&arduino_pins[pin], 0);
}

k_timer_stop(timer);
pt->count = 0;
pt->infinity = false;
pt->pin = pin_size_t(-1);
} else {
if (pin != pin_size_t(-1)) {
gpio_pin_toggle_dt(&arduino_pins[pin]);
}
pt->count--;
}

k_spin_unlock(&pt->lock, key);
}

} // anonymous namespace

void tone(pin_size_t pinNumber, unsigned int frequency, unsigned long duration) {
RETURN_ON_INVALID_PIN(pinNumber);

k_spinlock_key_t key;
uint64_t toggles_count;
struct pin_timer *pt;
k_timeout_t timeout;

if (k_is_in_isr()) {
return;
}

k_mutex_lock(&timer_cfg_lock, K_FOREVER);

pt = find_pin_timer(pinNumber, false);

if (pt == nullptr) {
k_mutex_unlock(&timer_cfg_lock);
return;
}

if (!pt->timer_initialized) {
k_timer_init(&pt->timer, tone_expiry_cb, NULL);
pt->timer_initialized = true;
}

pinMode(pinNumber, OUTPUT);
k_timer_stop(&pt->timer);

toggles_count = ((uint64_t)duration * frequency / (MSEC_PER_SEC / TOGGLES_PER_CYCLE));
if (frequency == 0 || (toggles_count == 0 && duration != 0)) {
key = k_spin_lock(&pt->lock);
pt->count = 0;
pt->infinity = false;
pt->pin = pin_size_t(-1);
k_spin_unlock(&pt->lock, key);

gpio_pin_set_dt(&arduino_pins[pinNumber], 0);

k_mutex_unlock(&timer_cfg_lock);
return;
}

timeout = K_NSEC(NSEC_PER_SEC / (TOGGLES_PER_CYCLE * frequency));
if (timeout.ticks == 0) {
timeout.ticks = 1;
}

key = k_spin_lock(&pt->lock);
pt->infinity = (duration == 0);
pt->count = min(toggles_count, UINT32_MAX);
pt->pin = pinNumber;
k_spin_unlock(&pt->lock, key);

gpio_pin_set_dt(&arduino_pins[pinNumber], 1);
k_timer_start(&pt->timer, timeout, timeout);

k_mutex_unlock(&timer_cfg_lock);
}

void noTone(pin_size_t pinNumber) {
RETURN_ON_INVALID_PIN(pinNumber);

struct pin_timer *pt;
k_spinlock_key_t key;

if (k_is_in_isr()) {
return;
}

k_mutex_lock(&timer_cfg_lock, K_FOREVER);

pt = find_pin_timer(pinNumber, true);

if (pt == nullptr) {
k_mutex_unlock(&timer_cfg_lock);
return;
}

key = k_spin_lock(&pt->lock);
k_timer_stop(&pt->timer);
pt->count = 0;
pt->infinity = false;
pt->pin = pin_size_t(-1);
k_spin_unlock(&pt->lock, key);

gpio_pin_set_dt(&arduino_pins[pinNumber], 0);

k_mutex_unlock(&timer_cfg_lock);
}
154 changes: 154 additions & 0 deletions cores/arduino/WInterrupts.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright (c) 2022 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <Arduino.h>
#include "wiring_private.h"

using namespace zephyr::arduino;

namespace {

/*
* GPIO callback implementation
*/

struct arduino_callback {
voidFuncPtr handler;
bool enabled;
};

struct gpio_port_callback {
struct gpio_callback callback;
struct arduino_callback handlers[max_ngpios];
gpio_port_pins_t pins;
const struct device *dev;
} port_callback[port_num] = {};

unsigned int irq_key;
bool interrupts_disabled = false;

struct gpio_port_callback *find_gpio_port_callback(const struct device *dev) {
for (size_t i = 0; i < ARRAY_SIZE(port_callback); i++) {
if (port_callback[i].dev == dev) {
return &port_callback[i];
}
if (port_callback[i].dev == nullptr) {
port_callback[i].dev = dev;
return &port_callback[i];
}
}

return nullptr;
}

void setInterruptHandler(pin_size_t pinNumber, voidFuncPtr func) {
RETURN_ON_INVALID_PIN(pinNumber);

struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port);

if (pcb) {
pcb->handlers[arduino_pins[pinNumber].pin].handler = func;
}
}

void handleGpioCallback(const struct device *port, struct gpio_callback *cb, uint32_t pins) {
(void)port; // unused
struct gpio_port_callback *pcb = (struct gpio_port_callback *)cb;

for (uint32_t i = 0; i < max_ngpios; i++) {
if (pins & BIT(i) && pcb->handlers[i].enabled) {
pcb->handlers[i].handler();
}
}
}

void enableInterrupt(pin_size_t pinNumber) {
RETURN_ON_INVALID_PIN(pinNumber);

struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port);

if (pcb) {
pcb->handlers[arduino_pins[pinNumber].pin].enabled = true;
}
}

void disableInterrupt(pin_size_t pinNumber) {
RETURN_ON_INVALID_PIN(pinNumber);

struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port);

if (pcb) {
pcb->handlers[arduino_pins[pinNumber].pin].enabled = false;
}
}

} // anonymous namespace

void attachInterrupt(pin_size_t pinNumber, voidFuncPtr callback, PinStatus pinStatus) {
RETURN_ON_INVALID_PIN(pinNumber);

struct gpio_port_callback *pcb;
gpio_flags_t intmode = 0;

if (!callback) {
return;
}

if (pinStatus == LOW) {
intmode |= GPIO_INT_LEVEL_LOW;
} else if (pinStatus == HIGH) {
intmode |= GPIO_INT_LEVEL_HIGH;
} else if (pinStatus == CHANGE) {
intmode |= GPIO_INT_EDGE_BOTH;
} else if (pinStatus == FALLING) {
intmode |= GPIO_INT_EDGE_FALLING;
} else if (pinStatus == RISING) {
intmode |= GPIO_INT_EDGE_RISING;
} else {
return;
}

pcb = find_gpio_port_callback(arduino_pins[pinNumber].port);
__ASSERT(pcb != nullptr, "gpio_port_callback not found");

pcb->pins |= BIT(arduino_pins[pinNumber].pin);
setInterruptHandler(pinNumber, callback);
enableInterrupt(pinNumber);

gpio_pin_interrupt_configure(arduino_pins[pinNumber].port, arduino_pins[pinNumber].pin,
intmode);
gpio_init_callback(&pcb->callback, handleGpioCallback, pcb->pins);
gpio_add_callback(arduino_pins[pinNumber].port, &pcb->callback);
}

void detachInterrupt(pin_size_t pinNumber) {
RETURN_ON_INVALID_PIN(pinNumber);

setInterruptHandler(pinNumber, nullptr);
disableInterrupt(pinNumber);
}

void interrupts(void) {
if (interrupts_disabled) {
irq_unlock(irq_key);
interrupts_disabled = false;
}
}

void noInterrupts(void) {
if (!interrupts_disabled) {
irq_key = irq_lock();
interrupts_disabled = true;
}
}

int digitalPinToInterrupt(pin_size_t pinNumber) {
RETURN_ON_INVALID_PIN(pinNumber, -1);

struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port);

return (pcb) ? pinNumber : -1;
}
26 changes: 26 additions & 0 deletions cores/arduino/WMath.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 Ayush Singh <ayush@beagleboard.org>
* Copyright (c) 2026 TOKITA Hiroshi
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <Arduino.h>

#ifndef CONFIG_MINIMAL_LIBC_RAND

#include <stdlib.h>

void randomSeed(unsigned long seed) {
srand(seed);
}

long random(long min, long max) {
return rand() % (max - min) + min;
}

long random(long max) {
return rand() % max;
}

#endif
Loading
Loading