Commit b457c4b6 authored by schneider's avatar schneider
Browse files

feat(interrupt): API for Python interrupts

parent 00750677
Pipeline #1351 passed with stage
in 2 minutes and 10 seconds
#pragma once
#include "epicardium.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
...@@ -26,6 +29,9 @@ struct api_call_mem { ...@@ -26,6 +29,9 @@ struct api_call_mem {
/* ID if the ongoing API call */ /* ID if the ongoing API call */
api_id_t id; api_id_t id;
/* ID of the current interrupt */
api_int_id_t int_id;
/* /*
* Buffer for arguments/return value. This buffer will be * Buffer for arguments/return value. This buffer will be
* *overflown*, because there is guaranteed space behind it. * *overflown*, because there is guaranteed space behind it.
......
#include "max32665.h"
#include "tmr.h"
#include "api/common.h"
#include "epicardium.h"
void api_interrupt_handler_ctrl_c(api_int_id_t id)
__attribute__((weak, alias("api_interrupt_handler_default")));
void api_interrupt_handler_bhi160(api_int_id_t id)
__attribute__((weak, alias("api_interrupt_handler_default")));
/* Timer Interrupt used for control char notification */
void TMR5_IRQHandler(void)
{
TMR_IntClear(MXC_TMR5);
switch (API_CALL_MEM->int_id) {
case API_INT_CTRL_C:
api_interrupt_handler_ctrl_c(API_CALL_MEM->int_id);
break;
case API_INT_BHI160:
api_interrupt_handler_bhi160(API_CALL_MEM->int_id);
break;
}
API_CALL_MEM->int_id = 0;
}
__attribute__((weak)) void api_interrupt_handler_catch_all(api_int_id_t id)
{
}
void api_interrupt_handler_default(api_int_id_t id)
{
api_interrupt_handler_catch_all(id);
}
#include "api/interrupt-sender.h"
#include "api/common.h"
#include "tmr_utils.h"
static bool enabled[API_INT_MAX + 1];
void api_interrupt_trigger(api_int_id_t id)
{
if (id <= API_INT_MAX) {
if (enabled[id]) {
while (API_CALL_MEM->int_id)
;
API_CALL_MEM->int_id = id;
TMR_TO_Start(MXC_TMR5, 1, 0);
}
}
}
void api_interrupt_init(void)
{
int i;
API_CALL_MEM->int_id = 0;
for (i = 0; i <= API_INT_MAX; i++) {
enabled[i] = false;
}
}
void epic_interrupt_enable(api_int_id_t int_id)
{
if (int_id <= API_INT_MAX) {
enabled[int_id] = true;
}
}
void epic_interrupt_disable(api_int_id_t int_id)
{
if (int_id <= API_INT_MAX) {
enabled[int_id] = false;
}
}
#pragma once
#include "api/common.h"
void api_interrupt_init(void);
void api_interrupt_trigger(api_int_id_t id);
...@@ -4,17 +4,24 @@ ...@@ -4,17 +4,24 @@
#include <stddef.h> #include <stddef.h>
#include <errno.h> #include <errno.h>
/* clang-format off */
#define API_INT_CTRL_C 1
#define API_INT_BHI160 2
#define API_INT_MAX API_INT_BHI160
#ifndef API #ifndef API
#define API(id, def) def #define API(id, def) def
#endif #endif
/* clang-format off */
#define API_UART_WRITE 0x1 #define API_UART_WRITE 0x1
#define API_UART_READ 0x2 #define API_UART_READ 0x2
#define API_LEDS_SET 0x3 #define API_LEDS_SET 0x3
#define API_VIBRA_SET 0x4 #define API_VIBRA_SET 0x4
#define API_VIBRA_VIBRATE 0x5 #define API_VIBRA_VIBRATE 0x5
#define API_STREAM_READ 0x6 #define API_STREAM_READ 0x6
#define API_INTERRUPT_ENABLE 0x7
#define API_INTERRUPT_DISABLE 0x8
/* clang-format on */ /* clang-format on */
/** /**
...@@ -139,4 +146,23 @@ API(API_VIBRA_SET, void epic_vibra_set(int status)); ...@@ -139,4 +146,23 @@ API(API_VIBRA_SET, void epic_vibra_set(int status));
*/ */
API(API_VIBRA_VIBRATE, void epic_vibra_vibrate(int millis)); API(API_VIBRA_VIBRATE, void epic_vibra_vibrate(int millis));
/**
* API interrupt type
*/
typedef uint32_t api_int_id_t;
/**
* Enable/unmask an API interrupt
*
* :param int_id: The interrupt to be enabled
*/
API(API_INTERRUPT_ENABLE, void epic_interrupt_enable(api_int_id_t int_id));
/**
* Disable/mask an API interrupt
*
* :param int_id: The interrupt to be disabled
*/
API(API_INTERRUPT_DISABLE, void epic_interrupt_disable(api_int_id_t int_id));
#endif /* _EPICARDIUM_H */ #endif /* _EPICARDIUM_H */
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "modules/modules.h" #include "modules/modules.h"
#include "modules/log.h" #include "modules/log.h"
#include "modules/stream.h" #include "modules/stream.h"
#include "api/interrupt-sender.h"
#include <Heart.h> #include <Heart.h>
#include "GUI_Paint.h" #include "GUI_Paint.h"
...@@ -54,6 +55,7 @@ int main(void) ...@@ -54,6 +55,7 @@ int main(void)
} }
fatfs_init(); fatfs_init();
api_interrupt_init();
stream_init(); stream_init();
LOG_INFO("startup", "Initializing tasks ..."); LOG_INFO("startup", "Initializing tasks ...");
......
...@@ -22,6 +22,7 @@ api = custom_target( ...@@ -22,6 +22,7 @@ api = custom_target(
api_caller_lib = static_library( api_caller_lib = static_library(
'api-caller', 'api-caller',
'api/caller.c', 'api/caller.c',
'api/interrupt-receiver.c',
api[0], # Caller api[0], # Caller
dependencies: periphdriver, dependencies: periphdriver,
) )
...@@ -35,6 +36,7 @@ api_caller = declare_dependency( ...@@ -35,6 +36,7 @@ api_caller = declare_dependency(
api_dispatcher_lib = static_library( api_dispatcher_lib = static_library(
'api-dispatcher', 'api-dispatcher',
'api/dispatcher.c', 'api/dispatcher.c',
'api/interrupt-sender.c',
api[1], # Dispatcher api[1], # Dispatcher
dependencies: periphdriver, dependencies: periphdriver,
) )
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include "max32665.h" #include "max32665.h"
#include "cdcacm.h" #include "cdcacm.h"
#include "uart.h" #include "uart.h"
#include "tmr_utils.h"
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
...@@ -12,6 +11,7 @@ ...@@ -12,6 +11,7 @@
#include "modules.h" #include "modules.h"
#include "modules/log.h" #include "modules/log.h"
#include "api/interrupt-sender.h"
/* Task ID for the serial handler */ /* Task ID for the serial handler */
TaskHandle_t serial_task_id = NULL; TaskHandle_t serial_task_id = NULL;
...@@ -24,7 +24,7 @@ static QueueHandle_t read_queue; ...@@ -24,7 +24,7 @@ static QueueHandle_t read_queue;
/* /*
* API-call to write a string. Output goes to both CDCACM and UART * API-call to write a string. Output goes to both CDCACM and UART
*/ */
void epic_uart_write_str(char *str, intptr_t length) void epic_uart_write_str(const char *str, intptr_t length)
{ {
UART_Write(ConsoleUart, (uint8_t *)str, length); UART_Write(ConsoleUart, (uint8_t *)str, length);
cdcacm_write((uint8_t *)str, length); cdcacm_write((uint8_t *)str, length);
...@@ -57,7 +57,12 @@ static void enqueue_char(char chr) ...@@ -57,7 +57,12 @@ static void enqueue_char(char chr)
{ {
if (chr == 0x3) { if (chr == 0x3) {
/* Control-C */ /* Control-C */
TMR_TO_Start(MXC_TMR5, 1, 0); api_interrupt_trigger(API_INT_CTRL_C);
}
if (chr == 0x0e) {
/* Control-N */
api_interrupt_trigger(API_INT_BHI160);
} }
if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) { if (xQueueSend(read_queue, &chr, 100) == errQUEUE_FULL) {
......
...@@ -19,7 +19,7 @@ int main(void) ...@@ -19,7 +19,7 @@ int main(void)
NVIC_EnableIRQ(TMR5_IRQn); NVIC_EnableIRQ(TMR5_IRQn);
while (1) { while (1) {
gc_init(&__HeapBase, &__HeapLimit); gc_init(&__HeapBase + 1024 * 10, &__HeapLimit);
mp_init(); mp_init();
pyexec_friendly_repl(); pyexec_friendly_repl();
......
...@@ -4,6 +4,7 @@ modsrc = files( ...@@ -4,6 +4,7 @@ modsrc = files(
'modules/utime.c', 'modules/utime.c',
'modules/leds.c', 'modules/leds.c',
'modules/vibra.c', 'modules/vibra.c',
'modules/interrupt.c',
) )
################################# #################################
...@@ -75,7 +76,7 @@ elf = executable( ...@@ -75,7 +76,7 @@ elf = executable(
include_directories: micropython_includes, include_directories: micropython_includes,
dependencies: [max32665_startup_core1, periphdriver, api_caller], dependencies: [max32665_startup_core1, periphdriver, api_caller],
link_with: upy, link_with: upy,
link_whole: [max32665_startup_core1_lib], link_whole: [max32665_startup_core1_lib, api_caller_lib],
link_args: [ link_args: [
'-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map', '-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map',
], ],
......
#include "py/obj.h"
#include "py/runtime.h"
#include "py/builtin.h"
#include "epicardium.h"
#include "api/common.h"
#include "mphalport.h"
// TODO: these should be intialized as mp_const_none
mp_obj_t callbacks[API_INT_MAX + 1] = {
0,
};
void api_interrupt_handler_catch_all(api_int_id_t id)
{
// TODO: check if id is out of rante
// TOOD: check against mp_const_none
if (id <= API_INT_MAX) {
if (callbacks[id]) {
mp_sched_schedule(
callbacks[id], MP_OBJ_NEW_SMALL_INT(id)
);
}
}
}
STATIC mp_obj_t mp_interrupt_set_callback(mp_obj_t id_in, mp_obj_t callback_obj)
{
api_int_id_t id = mp_obj_get_int(id_in);
if (callback_obj != mp_const_none &&
!mp_obj_is_callable(callback_obj)) {
mp_raise_ValueError("handler must be None or callable");
}
// TODO: throw error if id is out of range
if (id <= API_INT_MAX) {
callbacks[id] = callback_obj;
}
return mp_const_none;
}
STATIC mp_obj_t mp_interrupt_enable_callback(mp_obj_t id_in)
{
api_int_id_t id = mp_obj_get_int(id_in);
// TODO: throw error if id is out of range or epic_interrupt_enable failed
epic_interrupt_enable(id);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(
interrupt_set_callback_obj, mp_interrupt_set_callback
);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(
interrupt_enable_callback_obj, mp_interrupt_enable_callback
);
STATIC const mp_rom_map_elem_t interrupt_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_interrupt) },
{ MP_ROM_QSTR(MP_QSTR_set_callback),
MP_ROM_PTR(&interrupt_set_callback_obj) },
{ MP_ROM_QSTR(MP_QSTR_enable_callback),
MP_ROM_PTR(&interrupt_enable_callback_obj) },
{ MP_ROM_QSTR(MP_QSTR_BHI160), MP_OBJ_NEW_SMALL_INT(2) },
};
STATIC MP_DEFINE_CONST_DICT(
interrupt_module_globals, interrupt_module_globals_table
);
// Define module object.
const mp_obj_module_t interrupt_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&interrupt_module_globals,
};
/* clang-format off */
// Register the module to make it available in Python
MP_REGISTER_MODULE(MP_QSTR_interrupt, interrupt_module, MODULE_INTERRUPT_ENABLED);
...@@ -25,3 +25,7 @@ Q(ticks_diff) ...@@ -25,3 +25,7 @@ Q(ticks_diff)
/* vibra */ /* vibra */
Q(vibra) Q(vibra)
Q(vibrate) Q(vibrate)
Q(set_callback)
Q(enable_callback)
Q(BHI160)
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#define MICROPY_HELPER_REPL (1) #define MICROPY_HELPER_REPL (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG)
#define MICROPY_ENABLE_SCHEDULER (1)
/* Builtin function and modules */ /* Builtin function and modules */
#define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1)
#define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP (1)
...@@ -38,6 +40,7 @@ ...@@ -38,6 +40,7 @@
#define MODULE_UTIME_ENABLED (1) #define MODULE_UTIME_ENABLED (1)
#define MODULE_LEDS_ENABLED (1) #define MODULE_LEDS_ENABLED (1)
#define MODULE_VIBRA_ENABLED (1) #define MODULE_VIBRA_ENABLED (1)
#define MODULE_INTERRUPT_ENABLED (1)
/* /*
* This port is intended to be 32-bit, but unfortunately, int32_t for * This port is intended to be 32-bit, but unfortunately, int32_t for
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include "tmr.h" #include "tmr.h"
#include "epicardium.h" #include "epicardium.h"
#include "api/common.h"
/****************************************************************************** /******************************************************************************
* Serial Communication * Serial Communication
*/ */
...@@ -62,23 +62,16 @@ long _write(int fd, const char *buf, size_t cnt) ...@@ -62,23 +62,16 @@ long _write(int fd, const char *buf, size_t cnt)
return cnt; return cnt;
} }
bool do_interrupt = false; void api_interrupt_handler_ctrl_c(void)
/* Timer Interrupt used for control char notification */
void TMR5_IRQHandler(void)
{ {
TMR_IntClear(MXC_TMR5); /* Taken from lib/micropython/micropython/lib/utils/interrupt_char.c */
MP_STATE_VM(mp_pending_exception) =
if (do_interrupt) { MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
/* Taken from lib/micropython/micropython/lib/utils/interrupt_char.c */
MP_STATE_VM(mp_pending_exception) =
MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
#if MICROPY_ENABLE_SCHEDULER #if MICROPY_ENABLE_SCHEDULER
if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
MP_STATE_VM(sched_state) = MP_SCHED_PENDING; MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
}
#endif
} }
#endif
} }
void mp_hal_set_interrupt_char(char c) void mp_hal_set_interrupt_char(char c)
...@@ -88,7 +81,12 @@ void mp_hal_set_interrupt_char(char c) ...@@ -88,7 +81,12 @@ void mp_hal_set_interrupt_char(char c)
MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)) MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))
); );
} }
do_interrupt = (c == 0x03);
if (c == 0x03) {
epic_interrupt_enable(API_INT_CTRL_C);
} else {
epic_interrupt_disable(API_INT_CTRL_C);
}
} }
/****************************************************************************** /******************************************************************************
...@@ -137,7 +135,7 @@ mp_import_stat_t mp_import_stat(const char *path) ...@@ -137,7 +135,7 @@ mp_import_stat_t mp_import_stat(const char *path)
mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs)
{ {
/* TODO: Once fs is implemented, get this working as well */ /* TODO: Once fs is implemented, get this working as well */
mp_raise_NotImplementedError ("FS is not yet implemented"); mp_raise_NotImplementedError("FS is not yet implemented");
return mp_const_none; return mp_const_none;
} }
MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment