From caf1ad698be7f61ff9a69d8bfb32908b7206dbcb Mon Sep 17 00:00:00 2001 From: Peter Hoddie Date: Sun, 21 Feb 2021 23:38:28 -0800 Subject: [PATCH] pico digital monitor based on esp8266 --- modules/pins/digital/monitor/manifest.json | 7 +- .../pins/digital/monitor/pico/modMonitor.c | 216 ++++++++++++++++++ 2 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 modules/pins/digital/monitor/pico/modMonitor.c diff --git a/modules/pins/digital/monitor/manifest.json b/modules/pins/digital/monitor/manifest.json index 9c5322ccf9..a20e0171ff 100644 --- a/modules/pins/digital/monitor/manifest.json +++ b/modules/pins/digital/monitor/manifest.json @@ -20,13 +20,18 @@ "*": "$(MODULES)/pins/digital/monitor/gecko/*" } }, + "pico": { + "modules": { + "*": "$(MODULES)/pins/digital/monitor/pico/*" + } + }, "qca4020": { "modules": { "*": "$(MODULES)/pins/digital/monitor/qca4020/*" } }, "...": { - "error": "pins/digital module unsupported" + "error": "pins/digital/monitor module unsupported" } } } diff --git a/modules/pins/digital/monitor/pico/modMonitor.c b/modules/pins/digital/monitor/pico/modMonitor.c new file mode 100644 index 0000000000..50ef298f1d --- /dev/null +++ b/modules/pins/digital/monitor/pico/modMonitor.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2018-2021 Moddable Tech, Inc. + * + * This file is part of the Moddable SDK Runtime. + * + * The Moddable SDK Runtime is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Runtime is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the Moddable SDK Runtime. If not, see . + * + */ + +#include "xsmc.h" +#include "xsHost.h" +#include "modGPIO.h" +#include "mc.xs.h" // for xsID_ values +#include "hardware/gpio.h" + +struct modDigitalMonitorRecord { + struct modDigitalMonitorRecord *next; + xsMachine *the; + xsSlot obj; + uint8_t pin; + uint8_t edge; + uint8_t triggered; + uint32_t rises; + uint32_t falls; +}; +typedef struct modDigitalMonitorRecord modDigitalMonitorRecord; +typedef struct modDigitalMonitorRecord *modDigitalMonitor; + +static void gpioISR(uint gpio, uint32_t events); +static void digitalMonitorDeliver(void *the, void *refcon, uint8_t *message, uint16_t messageLength); + +static modDigitalMonitor gMonitors; + +void xs_digital_monitor_destructor(void *data) +{ + modDigitalMonitor monitor = data; + if (NULL == monitor) + return; + + modCriticalSectionBegin(); + + if (gMonitors == monitor) + gMonitors = monitor->next; + else { + modDigitalMonitor walker; + for (walker = gMonitors; walker; walker = walker->next) { + if (walker->next == monitor) { + walker->next = monitor->next; + break; + } + } + } + + // disable interrupt for this pin + gpio_set_irq_enabled(monitor->pin, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, false); + gpio_init(monitor->pin); + + // remove ISR +// if (NULL == gMonitors) +// ETS_GPIO_INTR_DISABLE(); + + modCriticalSectionEnd(); + + c_free(monitor); +} + +void xs_digital_monitor(xsMachine *the) +{ + modDigitalMonitor monitor; + int pin, edge, mode = kModGPIOInput; + modGPIOConfigurationRecord config; + + xsmcVars(1); + + if (!xsmcHas(xsArg(0), xsID_pin)) + xsUnknownError("pin missing"); + + if (!xsmcHas(xsArg(0), xsID_edge)) + xsUnknownError("edge missing"); + + xsmcGet(xsVar(0), xsArg(0), xsID_pin); + pin = xsmcToInteger(xsVar(0)); + if ((pin < 0) || (pin > 29)) + xsUnknownError("invalid pin"); + + xsmcGet(xsVar(0), xsArg(0), xsID_edge); + edge = xsmcToInteger(xsVar(0)); + if ((edge < 1) || (edge > 3)) + xsUnknownError("invalid edge"); + + if (xsmcHas(xsArg(0), xsID_mode)) { + xsmcGet(xsVar(0), xsArg(0), xsID_mode); + mode = xsmcToInteger(xsVar(0)); + } + + monitor = c_malloc(sizeof(modDigitalMonitorRecord)); + if (!monitor) + xsUnknownError("no memory"); + + monitor->the = the; + monitor->obj = xsThis; + monitor->pin = pin; + monitor->edge = edge; + monitor->triggered = false; + monitor->rises = 0; + monitor->falls = 0; + + xsRemember(monitor->obj); + + xsmcSetHostData(xsThis, monitor); + + config.pin = (uint8_t)pin; + modGPIOSetMode(&config, mode); + + // install ISR + if (NULL == gMonitors) + gpio_set_irq_enabled_with_callback(pin, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, false, gpioISR); + + modCriticalSectionBegin(); + monitor->next = gMonitors; + gMonitors = monitor; + modCriticalSectionEnd(); + + // enable interrupt for this pin + gpio_set_irq_enabled(monitor->pin, edge << 2, true); // shift to GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE + +} + +void xs_digital_monitor_close(xsMachine *the) +{ + modDigitalMonitor monitor = xsmcGetHostData(xsThis); + xsForget(monitor->obj); + xs_digital_monitor_destructor(monitor); + xsmcSetHostData(xsThis, NULL); +} + +void xs_digital_monitor_read(xsMachine *the) +{ + modDigitalMonitor monitor = xsmcGetHostData(xsThis); + + xsmcSetInteger(xsResult, gpio_get(monitor->pin)); +} + +void xs_digital_monitor_get_rises(xsMachine *the) +{ + modDigitalMonitor monitor = xsmcGetHostData(xsThis); + + if (!(monitor->edge & 1)) + xsUnknownError("not configured"); + + xsmcSetInteger(xsResult, monitor->rises); +} + +void xs_digital_monitor_get_falls(xsMachine *the) +{ + modDigitalMonitor monitor = xsmcGetHostData(xsThis); + + if (!(monitor->edge & 2)) + xsUnknownError("not configured"); + + xsmcSetInteger(xsResult, monitor->falls); +} + +void gpioISR(uint gpio, uint32_t events) +{ + modDigitalMonitor walker; + uint8_t doUpdate = 0; + + for (walker = gMonitors; walker; walker = walker->next) { + if (walker->pin != gpio) + continue; + + if (gpio_get(gpio)) { + if (1 & walker->edge) { + walker->rises += 1; + doUpdate = !walker->triggered; + walker->triggered = true; + } + } + else if (2 & walker->edge) { + walker->falls += 1; + doUpdate = !walker->triggered; + walker->triggered = true; + } + break; + } + + if (doUpdate) + modMessagePostToMachineFromISR(walker->the, digitalMonitorDeliver, walker); +} + +void digitalMonitorDeliver(void *the, void *refcon, uint8_t *message, uint16_t messageLength) +{ + modDigitalMonitor walker = refcon; + + walker->triggered = false; + + xsBeginHost(walker->the); + xsCall0(walker->obj, xsID_onChanged); + xsEndHost(walker->the); +} + +void xs_digital_monitor_get_pwm_duty(xsMachine *the) {} +void xs_digital_monitor_get_pwm_freq(xsMachine *the) {} +