Skip to content

Commit

Permalink
Direct sampling: brand new implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
antirez committed Jan 24, 2023
1 parent da2f928 commit b060c50
Showing 1 changed file with 71 additions and 28 deletions.
99 changes: 71 additions & 28 deletions view_direct_sampling.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,57 @@
* See the LICENSE file for information about the license. */

#include "app.h"

#include <cc1101.h>

#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
#define USEC_PER_PIXEL_MIN 5
#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
* dot depending on the level. */
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);
}
}

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 */
Expand All @@ -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);
}
}

Expand All @@ -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)
Expand All @@ -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. */
Expand All @@ -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)
Expand All @@ -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();
}

0 comments on commit b060c50

Please sign in to comment.