From 8907be98a47edcadb672714f2393dee4fbddbfb0 Mon Sep 17 00:00:00 2001 From: "Kwabena W. Agyeman" Date: Tue, 2 Feb 2021 11:20:01 -0800 Subject: [PATCH] Kwabena/flir lepton updates (#1150) * Add timeout support for grabbing a new frame * Fix ffc with a timeout --- src/omv/modules/py_fir.c | 36 ++++++++- src/omv/ports/stm32/modules/py_fir_lepton.c | 84 ++++++++++++++------- src/omv/ports/stm32/modules/py_fir_lepton.h | 6 +- 3 files changed, 95 insertions(+), 31 deletions(-) diff --git a/src/omv/modules/py_fir.c b/src/omv/modules/py_fir.c index 065db0f8d..3d782a067 100644 --- a/src/omv/modules/py_fir.c +++ b/src/omv/modules/py_fir.c @@ -680,6 +680,26 @@ static mp_obj_t py_fir_register_vsync_cb(mp_obj_t cb) STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_fir_register_vsync_cb_obj, py_fir_register_vsync_cb); #endif +static mp_obj_t py_fir_register_frame_cb(mp_obj_t cb) +{ + if (fir_sensor == FIR_LEPTON) { + fir_lepton_register_frame_cb(cb); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_fir_register_frame_cb_obj, py_fir_register_frame_cb); + +static mp_obj_t py_fir_get_frame_available() +{ + if (fir_sensor == FIR_LEPTON) { + return fir_lepton_get_frame_available(); + } + + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_fir_get_frame_available_obj, py_fir_get_frame_available); + static mp_obj_t py_fir_trigger_ffc(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { if (fir_sensor == FIR_LEPTON) { @@ -756,6 +776,9 @@ mp_obj_t py_fir_read_ir(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) bool arg_hmirror = py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_hmirror), false); bool arg_vflip = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_vflip), false); fir_transposed = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_transpose), false); + #if (OMV_ENABLE_FIR_LEPTON == 1) + int arg_timeout = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_timeout), -1); + #endif switch(fir_sensor) { case FIR_NONE: { @@ -807,7 +830,7 @@ mp_obj_t py_fir_read_ir(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) #endif #if (OMV_ENABLE_FIR_LEPTON == 1) case FIR_LEPTON: { - return fir_lepton_read_ir(fir_width, fir_height, arg_hmirror, arg_vflip, fir_transposed); + return fir_lepton_read_ir(fir_width, fir_height, arg_hmirror, arg_vflip, fir_transposed, arg_timeout); } #endif } @@ -1089,8 +1112,11 @@ mp_obj_t py_fir_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) dst_img.data = xalloc(image_size(&dst_img)); } - fb_alloc_mark(); + #if (OMV_ENABLE_FIR_LEPTON == 1) + int arg_timeout = py_helper_keyword_int(n_args, args, 16, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_timeout), -1); + #endif + fb_alloc_mark(); src_img.data = fb_alloc(src_img.w * src_img.h * sizeof(uint8_t), FB_ALLOC_NO_HINT); switch(fir_sensor) { @@ -1157,7 +1183,7 @@ mp_obj_t py_fir_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) #if (OMV_ENABLE_FIR_LEPTON == 1) case FIR_LEPTON: { fir_lepton_fill_image(&src_img, fir_width, fir_height, !scale_obj, min, max, - arg_hmirror, arg_vflip, arg_transpose); + arg_hmirror, arg_vflip, arg_transpose, arg_timeout); break; } #endif @@ -1213,10 +1239,14 @@ STATIC const mp_rom_map_elem_t globals_dict_table[] = { #else { MP_ROM_QSTR(MP_QSTR_register_vsync_cb), MP_ROM_PTR(&py_func_unavailable_obj) }, #endif + { MP_ROM_QSTR(MP_QSTR_register_frame_cb), MP_ROM_PTR(&py_fir_register_frame_cb_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_frame_available), MP_ROM_PTR(&py_fir_get_frame_available_obj) }, { MP_ROM_QSTR(MP_QSTR_trigger_ffc), MP_ROM_PTR(&py_fir_trigger_ffc_obj) }, #else { MP_ROM_QSTR(MP_QSTR_radiometric), MP_ROM_PTR(&py_func_unavailable_obj) }, { MP_ROM_QSTR(MP_QSTR_register_vsync_cb), MP_ROM_PTR(&py_func_unavailable_obj) }, + { MP_ROM_QSTR(MP_QSTR_register_frame_cb), MP_ROM_PTR(&py_func_unavailable_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_frame_available), MP_ROM_PTR(&py_func_unavailable_obj) }, { MP_ROM_QSTR(MP_QSTR_trigger_ffc), MP_ROM_PTR(&py_func_unavailable_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_read_ta), MP_ROM_PTR(&py_fir_read_ta_obj) }, diff --git a/src/omv/ports/stm32/modules/py_fir_lepton.c b/src/omv/ports/stm32/modules/py_fir_lepton.c index 864fa0a6a..3e24e9212 100644 --- a/src/omv/ports/stm32/modules/py_fir_lepton.c +++ b/src/omv/ports/stm32/modules/py_fir_lepton.c @@ -17,7 +17,7 @@ #include "softtimer.h" #include "systick.h" -#include "imlib.h" +#include "py_helper.h" #include "omv_boardconfig.h" #include STM32_HAL_H @@ -115,6 +115,8 @@ static bool fir_lepton_spi_check_crc(const uint16_t *base) } #endif +static mp_obj_t fir_lepton_frame_cb = mp_const_none; + void fir_lepton_spi_callback(const uint16_t *base) { #if defined(MCU_SERIES_F7) || defined(MCU_SERIES_H7) @@ -189,6 +191,11 @@ void fir_lepton_spi_callback(const uint16_t *base) if (fir_lepton_spi_rx_cb_head == framebuffer_tail) { fir_lepton_spi_rx_cb_head = (fir_lepton_spi_rx_cb_head + 1) % FRAMEBUFFER_COUNT; } + + // User should use micropython.schedule() in their callback to process the new frame. + if (fir_lepton_frame_cb != mp_const_none) { + mp_call_function_0(fir_lepton_frame_cb); + } } } } @@ -530,9 +537,36 @@ mp_obj_t fir_lepton_get_radiometry() return mp_obj_new_bool(fir_lepton_rad_en); } -static const uint16_t *fir_lepton_get_frame() +void fir_lepton_register_frame_cb(mp_obj_t cb) +{ + fir_lepton_frame_cb = cb; +} + +mp_obj_t fir_lepton_get_frame_available() +{ + return mp_obj_new_bool(framebuffer_head != framebuffer_tail); +} + +static const uint16_t *fir_lepton_get_frame(int timeout) { int sampled_framebuffer_head = framebuffer_head; + + if (timeout >= 0) { + for (uint32_t start = systick_current_millis();;) { + sampled_framebuffer_head = framebuffer_head; + + if (framebuffer_tail != sampled_framebuffer_head) { + break; + } + + if ((systick_current_millis() - start) >= timeout) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Timeout!")); + } + + __WFI(); + } + } + framebuffer_tail = sampled_framebuffer_head; return framebuffers[sampled_framebuffer_head]; } @@ -553,11 +587,11 @@ mp_obj_t fir_lepton_read_ta() return mp_obj_new_float((fir_lepton_get_temperature() * 0.01f) - 273.15f); } -mp_obj_t fir_lepton_read_ir(int w, int h, bool mirror, bool flip, bool transpose) +mp_obj_t fir_lepton_read_ir(int w, int h, bool mirror, bool flip, bool transpose, int timeout) { int kelvin = fir_lepton_get_temperature(); mp_obj_list_t *list = (mp_obj_list_t *) mp_obj_new_list(w * h, NULL); - const uint16_t *data = fir_lepton_get_frame(); + const uint16_t *data = fir_lepton_get_frame(timeout); float min = +FLT_MAX; float max = -FLT_MAX; int w_1 = w - 1; @@ -606,10 +640,10 @@ mp_obj_t fir_lepton_read_ir(int w, int h, bool mirror, bool flip, bool transpose } void fir_lepton_fill_image(image_t *img, int w, int h, bool auto_range, float min, float max, - bool mirror, bool flip, bool transpose) + bool mirror, bool flip, bool transpose, int timeout) { int kelvin = fir_lepton_get_temperature(); - const uint16_t *data = fir_lepton_get_frame(); + const uint16_t *data = fir_lepton_get_frame(timeout); int new_min; int new_max; @@ -678,34 +712,32 @@ void fir_lepton_fill_image(image_t *img, int w, int h, bool auto_range, float mi } } -void fir_lepton_trigger_ffc() +void fir_lepton_trigger_ffc(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { if (LEP_RunSysFFCNormalization(&fir_lepton_handle) != LEP_OK) { mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("FFC Error!")); } -} -void fir_lepton_wait_on_ffc(uint n_args, const mp_obj_t *args) -{ - uint32_t start = systick_current_millis(); - uint32_t delay_ms = (n_args < 1) ? 5000 : mp_obj_get_int(args[0]); + int timeout = py_helper_keyword_int(n_args, args, 0, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_timeout), -1); - for (;;) { - LEP_SYS_STATUS_E status; + if (timeout >= 0) { + for (uint32_t start = systick_current_millis();;) { + LEP_SYS_STATUS_E status; - if (LEP_GetSysFFCStatus(&fir_lepton_handle, &status) != LEP_OK) { - mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SYS Error!")); + if (LEP_GetSysFFCStatus(&fir_lepton_handle, &status) != LEP_OK) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SYS Error!")); + } + + if (status == LEP_SYS_STATUS_READY) { + break; + } + + if ((systick_current_millis() - start) >= timeout) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Timeout!")); + } + + systick_sleep(1); } - - if (status == LEP_SYS_STATUS_READY) { - break; - } - - if ((systick_current_millis() - start) >= delay_ms) { - mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Timeout!")); - } - - systick_sleep(1); } } diff --git a/src/omv/ports/stm32/modules/py_fir_lepton.h b/src/omv/ports/stm32/modules/py_fir_lepton.h index 4eeeb5bfa..5664a6219 100644 --- a/src/omv/ports/stm32/modules/py_fir_lepton.h +++ b/src/omv/ports/stm32/modules/py_fir_lepton.h @@ -14,9 +14,11 @@ void fir_lepton_deinit(); int fir_lepton_init(cambus_t *bus, int *w, int *h, int *refresh, int *resolution); void fir_lepton_register_vsync_cb(mp_obj_t cb); mp_obj_t fir_lepton_get_radiometry(); +void fir_lepton_register_frame_cb(mp_obj_t cb); +mp_obj_t fir_lepton_get_frame_available(); mp_obj_t fir_lepton_read_ta(); -mp_obj_t fir_lepton_read_ir(int w, int h, bool mirror, bool flip, bool transpose); +mp_obj_t fir_lepton_read_ir(int w, int h, bool mirror, bool flip, bool transpose, int timeout); void fir_lepton_fill_image(image_t *img, int w, int h, bool auto_range, float min, float max, - bool mirror, bool flip, bool transpose); + bool mirror, bool flip, bool transpose, int timeout); void fir_lepton_trigger_ffc(uint n_args, const mp_obj_t *args, mp_map_t *kw_args); #endif // __PY_FIR_LEPTON_H__