From b060c507cb9e04492d051dcc3a89fd3da7255b59 Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 24 Jan 2023 12:40:23 +0100 Subject: [PATCH] Direct sampling: brand new implementation. --- view_direct_sampling.c | 99 ++++++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/view_direct_sampling.c b/view_direct_sampling.c index b4b7aa479b0..4dd7b6a05a6 100644 --- a/view_direct_sampling.c +++ b/view_direct_sampling.c @@ -2,10 +2,13 @@ * See the LICENSE file for information about the license. */ #include "app.h" - #include -#define CAPTURED_BITMAP_SIZE 128*64/8 +static void direct_sampling_timer_start(ProtoViewApp *app); +static void direct_sampling_timer_stop(ProtoViewApp *app); + +#define CAPTURED_BITMAP_BITS (128*64) +#define CAPTURED_BITMAP_BYTES (CAPTURED_BITMAP_BITS/8) #define DEFAULT_USEC_PER_PIXEL 50 #define USEC_PER_PIXEL_SMALL_CHANGE 5 #define USEC_PER_PIXEL_LARGE_CHANGE 25 @@ -13,7 +16,9 @@ #define USEC_PER_PIXEL_MAX 300 typedef struct { uint8_t *captured; // Bitmap with the last captured screen. + uint32_t captured_idx; // Current index to write into the bitmap uint32_t usec_per_pixel; // Number of useconds a pixel should represent + bool show_usage_info; } DirectSamplingViewPrivData; /* Read directly from the G0 CC1101 pin, and draw a black or white @@ -21,41 +26,25 @@ typedef struct { void render_view_direct_sampling(Canvas *const canvas, ProtoViewApp *app) { DirectSamplingViewPrivData *privdata = app->view_privdata; - if (!app->direct_sampling_enabled && privdata->captured == NULL) { + if (!app->direct_sampling_enabled && privdata->show_usage_info) { canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas,2,9,"Direct sampling is a special"); - canvas_draw_str(canvas,2,18,"mode that displays the signal"); - canvas_draw_str(canvas,2,27,"captured in real time. Like in"); - canvas_draw_str(canvas,2,36,"a old CRT TV. It's very slow."); - canvas_draw_str(canvas,2,45,"Can crash your Flipper."); + canvas_draw_str(canvas,2,9, "Direct sampling displays the"); + canvas_draw_str(canvas,2,18,"the captured signal in real"); + canvas_draw_str(canvas,2,27,"time, like in a CRT TV set."); + canvas_draw_str(canvas,2,36,"Use UP/DOWN to change the"); + canvas_draw_str(canvas,2,45,"resolution (usec/pixel)."); canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas,14,60,"To enable press OK"); + canvas_draw_str(canvas,5,60,"To start/stop, press OK"); return; } - - /* Allocate the bitmap only the first time. */ - if (privdata->captured == NULL) - privdata->captured = malloc(CAPTURED_BITMAP_SIZE); - - /* Read from data from GPIO */ - if (app->direct_sampling_enabled) { - for (int j = 0; j < CAPTURED_BITMAP_SIZE*8; j++) { - uint32_t start_time = DWT->CYCCNT; - bool level = furi_hal_gpio_read(&gpio_cc1101_g0); - bitmap_set(privdata->captured,CAPTURED_BITMAP_SIZE,j,level); - uint32_t period = - furi_hal_cortex_instructions_per_microsecond() * - privdata->usec_per_pixel; - while(DWT->CYCCNT - start_time < period); - } - } + privdata->show_usage_info = false; /* Draw on screen. */ int idx = 0; for (int y = 0; y < 64; y++) { for (int x = 0; x < 128; x++) { bool level = bitmap_get(privdata->captured, - CAPTURED_BITMAP_SIZE,idx++); + CAPTURED_BITMAP_BYTES,idx++); if (level) canvas_draw_dot(canvas,x,y); } } @@ -63,7 +52,7 @@ void render_view_direct_sampling(Canvas *const canvas, ProtoViewApp *app) { char buf[32]; snprintf(buf,sizeof(buf),"%lu usec/px", privdata->usec_per_pixel); canvas_set_font(canvas, FontSecondary); - canvas_draw_str_with_border(canvas,0,60,buf,ColorWhite,ColorBlack); + canvas_draw_str_with_border(canvas,1,60,buf,ColorWhite,ColorBlack); } /* Handle input */ @@ -86,6 +75,9 @@ void process_input_direct_sampling(ProtoViewApp *app, InputEvent input) { privdata->usec_per_pixel = USEC_PER_PIXEL_MIN; else if (privdata->usec_per_pixel > USEC_PER_PIXEL_MAX) privdata->usec_per_pixel = USEC_PER_PIXEL_MAX; + /* Update the timer frequency. */ + direct_sampling_timer_stop(app); + direct_sampling_timer_start(app); } } @@ -95,6 +87,8 @@ void view_enter_direct_sampling(ProtoViewApp *app) { /* Set view defaults. */ DirectSamplingViewPrivData *privdata = app->view_privdata; privdata->usec_per_pixel = DEFAULT_USEC_PER_PIXEL; + privdata->captured = malloc(CAPTURED_BITMAP_BYTES); + privdata->show_usage_info = true; if (app->txrx->txrx_state == TxRxStateRx && !app->txrx->debug_timer_sampling) @@ -111,6 +105,9 @@ void view_enter_direct_sampling(ProtoViewApp *app) { } else { raw_sampling_worker_stop(app); } + + // Start the timer to capture raw data + direct_sampling_timer_start(app); } /* Exit view. Restore the subghz thread. */ @@ -119,6 +116,8 @@ void view_exit_direct_sampling(ProtoViewApp *app) { if (privdata->captured) free(privdata->captured); app->direct_sampling_enabled = false; + direct_sampling_timer_stop(app); + /* Restart normal data feeding. */ if (app->txrx->txrx_state == TxRxStateRx && !app->txrx->debug_timer_sampling) @@ -128,3 +127,47 @@ void view_exit_direct_sampling(ProtoViewApp *app) { raw_sampling_worker_start(app); } } + +/* =========================== Timer implementation ========================= */ + +static void ds_timer_isr(void *ctx) { + ProtoViewApp *app = ctx; + DirectSamplingViewPrivData *privdata = app->view_privdata; + + if (app->direct_sampling_enabled) { + bool level = furi_hal_gpio_read(&gpio_cc1101_g0); + bitmap_set(privdata->captured,CAPTURED_BITMAP_BYTES, + privdata->captured_idx,level); + privdata->captured_idx = (privdata->captured_idx+1) % + CAPTURED_BITMAP_BITS; + } + LL_TIM_ClearFlag_UPDATE(TIM2); +} + +static void direct_sampling_timer_start(ProtoViewApp *app) { + DirectSamplingViewPrivData *privdata = app->view_privdata; + + LL_TIM_InitTypeDef tim_init = { + .Prescaler = 63, /* CPU frequency is ~64Mhz. */ + .CounterMode = LL_TIM_COUNTERMODE_UP, + .Autoreload = privdata->usec_per_pixel + }; + + LL_TIM_Init(TIM2, &tim_init); + LL_TIM_SetClockSource(TIM2, LL_TIM_CLOCKSOURCE_INTERNAL); + LL_TIM_DisableCounter(TIM2); + LL_TIM_SetCounter(TIM2, 0); + furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, ds_timer_isr, app); + LL_TIM_EnableIT_UPDATE(TIM2); + LL_TIM_EnableCounter(TIM2); +} + +static void direct_sampling_timer_stop(ProtoViewApp *app) { + UNUSED(app); + FURI_CRITICAL_ENTER(); + LL_TIM_DisableCounter(TIM2); + LL_TIM_DisableIT_UPDATE(TIM2); + furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL); + LL_TIM_DeInit(TIM2); + FURI_CRITICAL_EXIT(); +}