|
| 1 | +/* |
| 2 | + * Copyright (c) 2022 TOKITA Hiroshi |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <Arduino.h> |
| 8 | +#include "wiring_private.h" |
| 9 | + |
| 10 | +using namespace zephyr::arduino; |
| 11 | + |
| 12 | +namespace { |
| 13 | + |
| 14 | +/* |
| 15 | + * GPIO callback implementation |
| 16 | + */ |
| 17 | + |
| 18 | +struct arduino_callback { |
| 19 | + voidFuncPtr handler; |
| 20 | + bool enabled; |
| 21 | +}; |
| 22 | + |
| 23 | +struct gpio_port_callback { |
| 24 | + struct gpio_callback callback; |
| 25 | + struct arduino_callback handlers[max_ngpios]; |
| 26 | + gpio_port_pins_t pins; |
| 27 | + const struct device *dev; |
| 28 | +} port_callback[port_num] = {0}; |
| 29 | + |
| 30 | +unsigned int irq_key; |
| 31 | +bool interrupts_disabled = false; |
| 32 | + |
| 33 | +struct gpio_port_callback *find_gpio_port_callback(const struct device *dev) { |
| 34 | + for (size_t i = 0; i < ARRAY_SIZE(port_callback); i++) { |
| 35 | + if (port_callback[i].dev == dev) { |
| 36 | + return &port_callback[i]; |
| 37 | + } |
| 38 | + if (port_callback[i].dev == nullptr) { |
| 39 | + port_callback[i].dev = dev; |
| 40 | + return &port_callback[i]; |
| 41 | + } |
| 42 | + } |
| 43 | + |
| 44 | + return nullptr; |
| 45 | +} |
| 46 | + |
| 47 | +void setInterruptHandler(pin_size_t pinNumber, voidFuncPtr func) { |
| 48 | + struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port); |
| 49 | + |
| 50 | + if (pcb) { |
| 51 | + pcb->handlers[arduino_pins[pinNumber].pin].handler = func; |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +void handleGpioCallback(const struct device *port, struct gpio_callback *cb, uint32_t pins) { |
| 56 | + (void)port; // unused |
| 57 | + struct gpio_port_callback *pcb = (struct gpio_port_callback *)cb; |
| 58 | + |
| 59 | + for (uint32_t i = 0; i < max_ngpios; i++) { |
| 60 | + if (pins & BIT(i) && pcb->handlers[i].enabled) { |
| 61 | + pcb->handlers[i].handler(); |
| 62 | + } |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +void enableInterrupt(pin_size_t pinNumber) { |
| 67 | + struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port); |
| 68 | + |
| 69 | + if (pcb) { |
| 70 | + pcb->handlers[arduino_pins[pinNumber].pin].enabled = true; |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +void disableInterrupt(pin_size_t pinNumber) { |
| 75 | + struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pinNumber].port); |
| 76 | + |
| 77 | + if (pcb) { |
| 78 | + pcb->handlers[arduino_pins[pinNumber].pin].enabled = false; |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +} // anonymous namespace |
| 83 | + |
| 84 | +void attachInterrupt(pin_size_t pinNumber, voidFuncPtr callback, PinStatus pinStatus) { |
| 85 | + struct gpio_port_callback *pcb; |
| 86 | + gpio_flags_t intmode = 0; |
| 87 | + |
| 88 | + if (!callback) { |
| 89 | + return; |
| 90 | + } |
| 91 | + |
| 92 | + if (pinStatus == LOW) { |
| 93 | + intmode |= GPIO_INT_LEVEL_LOW; |
| 94 | + } else if (pinStatus == HIGH) { |
| 95 | + intmode |= GPIO_INT_LEVEL_HIGH; |
| 96 | + } else if (pinStatus == CHANGE) { |
| 97 | + intmode |= GPIO_INT_EDGE_BOTH; |
| 98 | + } else if (pinStatus == FALLING) { |
| 99 | + intmode |= GPIO_INT_EDGE_FALLING; |
| 100 | + } else if (pinStatus == RISING) { |
| 101 | + intmode |= GPIO_INT_EDGE_RISING; |
| 102 | + } else { |
| 103 | + return; |
| 104 | + } |
| 105 | + |
| 106 | + pcb = find_gpio_port_callback(arduino_pins[pinNumber].port); |
| 107 | + __ASSERT(pcb != nullptr, "gpio_port_callback not found"); |
| 108 | + |
| 109 | + pcb->pins |= BIT(arduino_pins[pinNumber].pin); |
| 110 | + setInterruptHandler(pinNumber, callback); |
| 111 | + enableInterrupt(pinNumber); |
| 112 | + |
| 113 | + gpio_pin_interrupt_configure(arduino_pins[pinNumber].port, arduino_pins[pinNumber].pin, |
| 114 | + intmode); |
| 115 | + gpio_init_callback(&pcb->callback, handleGpioCallback, pcb->pins); |
| 116 | + gpio_add_callback(arduino_pins[pinNumber].port, &pcb->callback); |
| 117 | +} |
| 118 | + |
| 119 | +void detachInterrupt(pin_size_t pinNumber) { |
| 120 | + setInterruptHandler(pinNumber, nullptr); |
| 121 | + disableInterrupt(pinNumber); |
| 122 | +} |
| 123 | + |
| 124 | +void interrupts(void) { |
| 125 | + if (interrupts_disabled) { |
| 126 | + irq_unlock(irq_key); |
| 127 | + interrupts_disabled = false; |
| 128 | + } |
| 129 | +} |
| 130 | + |
| 131 | +void noInterrupts(void) { |
| 132 | + if (!interrupts_disabled) { |
| 133 | + irq_key = irq_lock(); |
| 134 | + interrupts_disabled = true; |
| 135 | + } |
| 136 | +} |
| 137 | + |
| 138 | +int digitalPinToInterrupt(pin_size_t pin) { |
| 139 | + struct gpio_port_callback *pcb = find_gpio_port_callback(arduino_pins[pin].port); |
| 140 | + |
| 141 | + return (pcb) ? pin : -1; |
| 142 | +} |
0 commit comments