Commit b457c4b6 authored by schneider's avatar schneider
Browse files

feat(interrupt): API for Python interrupts

parent 00750677
#pragma once
#include "epicardium.h"
#include <stdint.h>
#include <stdbool.h>
......@@ -26,6 +29,9 @@ struct api_call_mem {
/* ID if the ongoing API call */
api_id_t id;
/* ID of the current interrupt */
api_int_id_t int_id;
/*
* Buffer for arguments/return value. This buffer will be
* *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 @@
#include <stddef.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
#define API(id, def) def
#endif
/* clang-format off */
#define API_UART_WRITE 0x1
#define API_UART_READ 0x2
#define API_LEDS_SET 0x3
#define API_VIBRA_SET 0x4
#define API_VIBRA_VIBRATE 0x5
#define API_STREAM_READ 0x6
#define API_INTERRUPT_ENABLE 0x7
#define API_INTERRUPT_DISABLE 0x8
/* clang-format on */
/**
......@@ -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 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 */
......@@ -12,6 +12,7 @@
#include "modules/modules.h"
#include "modules/log.h"
#include "modules/stream.h"
#include "api/interrupt-sender.h"
#include <Heart.h>
#include "GUI_Paint.h"
......@@ -54,6 +55,7 @@ int main(void)
}
fatfs_init();
api_interrupt_init();
stream_init();
LOG_INFO("startup", "Initializing tasks ...");
......
......@@ -22,6 +22,7 @@ api = custom_target(
api_caller_lib = static_library(
'api-caller',
'api/caller.c',
'api/interrupt-receiver.c',
api[0], # Caller
dependencies: periphdriver,
)
......@@ -35,6 +36,7 @@ api_caller = declare_dependency(
api_dispatcher_lib = static_library(
'api-dispatcher',
'api/dispatcher.c',
'api/interrupt-sender.c',
api[1], # Dispatcher
dependencies: periphdriver,
)
......
......@@ -4,7 +4,6 @@
#include "max32665.h"
#include "cdcacm.h"
#include "uart.h"
#include "tmr_utils.h"
#include "FreeRTOS.h"
#include "task.h"
......@@ -12,6 +11,7 @@
#include "modules.h"
#include "modules/log.h"
#include "api/interrupt-sender.h"
/* Task ID for the serial handler */
TaskHandle_t serial_task_id = NULL;
......@@ -24,7 +24,7 @@ static QueueHandle_t read_queue;
/*
* 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);
cdcacm_write((uint8_t *)str, length);
......@@ -57,7 +57,12 @@ static void enqueue_char(char chr)
{
if (chr == 0x3) {
/* 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) {
......
......@@ -19,7 +19,7 @@ int main(void)
NVIC_EnableIRQ(TMR5_IRQn);
while (1) {
gc_init(&__HeapBase, &__HeapLimit);
gc_init(&__HeapBase + 1024 * 10, &__HeapLimit);
mp_init();
pyexec_friendly_repl();
......
......@@ -4,6 +4,7 @@ modsrc = files(
'modules/utime.c',
'modules/leds.c',
'modules/vibra.c',
'modules/interrupt.c',
)
#################################
......@@ -75,7 +76,7 @@ elf = executable(
include_directories: micropython_includes,
dependencies: [max32665_startup_core1, periphdriver, api_caller],
link_with: upy,
link_whole: [max32665_startup_core1_lib],
link_whole: [max32665_startup_core1_lib, api_caller_lib],
link_args: [
'-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)
/* vibra */
Q(vibra)
Q(vibrate)
Q(set_callback)
Q(enable_callback)
Q(BHI160)
......@@ -19,6 +19,8 @@
#define MICROPY_HELPER_REPL (1)
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG)
#define MICROPY_ENABLE_SCHEDULER (1)
/* Builtin function and modules */
#define MICROPY_PY_ALL_SPECIAL_METHODS (1)
#define MICROPY_PY_BUILTINS_HELP (1)
......@@ -38,6 +40,7 @@
#define MODULE_UTIME_ENABLED (1)
#define MODULE_LEDS_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
......
......@@ -14,7 +14,7 @@
#include "tmr.h"
#include "epicardium.h"
#include "api/common.h"
/******************************************************************************
* Serial Communication
*/
......@@ -62,23 +62,16 @@ long _write(int fd, const char *buf, size_t cnt)
return cnt;
}
bool do_interrupt = false;
/* Timer Interrupt used for control char notification */
void TMR5_IRQHandler(void)
void api_interrupt_handler_ctrl_c(void)
{
TMR_IntClear(MXC_TMR5);
if (do_interrupt) {
/* 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));
/* 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 (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
}
#endif
if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
}
#endif
}
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))
);
}
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)
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 */
mp_raise_NotImplementedError ("FS is not yet implemented");
mp_raise_NotImplementedError("FS is not yet implemented");
return mp_const_none;
}
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