Skip to content

Commit

Permalink
View privdata. Oscilliscope alike view row change.
Browse files Browse the repository at this point in the history
  • Loading branch information
antirez committed Jan 16, 2023
1 parent f885491 commit 2459e55
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 24 deletions.
5 changes: 4 additions & 1 deletion app.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ static void app_switch_view(ProtoViewApp *app, SwitchViewDirection dir) {
* the main subview of the view. When re re-enter it we want to see
* the main thing. */
app->current_subview[old] = 0;
memset(app->view_privdata,0,PROTOVIEW_VIEW_PRIVDATA_LEN);
}

/* Allocate the application state and initialize a number of stuff.
Expand All @@ -125,6 +126,8 @@ ProtoViewApp* protoview_app_alloc() {
app->current_view = ViewRawPulses;
for (int j = 0; j < ViewLast; j++) app->current_subview[j] = 0;
app->direct_sampling_enabled = false;
app->view_privdata = malloc(PROTOVIEW_VIEW_PRIVDATA_LEN);
memset(app->view_privdata,0,PROTOVIEW_VIEW_PRIVDATA_LEN);

// Signal found and visualization defaults
app->signal_bestlen = 0;
Expand All @@ -134,7 +137,7 @@ ProtoViewApp* protoview_app_alloc() {
app->signal_offset = 0;
app->msg_info = NULL;

//init Worker & Protocol
// Init Worker & Protocol
app->txrx = malloc(sizeof(ProtoViewTxRx));

/* Setup rx worker and environment. */
Expand Down
16 changes: 12 additions & 4 deletions app.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
#include "app_buffer.h"

#define TAG "ProtoView"
#define PROTOVIEW_RAW_VIEW_DEFAULT_SCALE 100
#define BITMAP_SEEK_NOT_FOUND UINT32_MAX
#define PROTOVIEW_RAW_VIEW_DEFAULT_SCALE 100 // 100us is 1 pixel by default
#define BITMAP_SEEK_NOT_FOUND UINT32_MAX // Returned by function as sentinel
#define PROTOVIEW_VIEW_PRIVDATA_LEN 32 // View specific private data len

#define DEBUG_MSG 1

Expand Down Expand Up @@ -100,14 +101,14 @@ typedef struct ProtoViewMsgInfo {
/* Low level information of the detected signal: the following are filled
* by the protocol decoding function: */
uint32_t start_off; /* Pulses start offset in the bitmap. */
uint32_t pulses_len; /* Number of pulses of the full message. */
uint32_t pulses_count; /* Number of pulses of the full message. */
/* The following are passed already filled to the decoder. */
uint32_t short_pulse_dur; /* Microseconds duration of the short pulse. */
/* The following are filled by ProtoView core after the decoder returned
* success. */
uint8_t *bits; /* Bitmap with the signal. */
uint32_t bits_bytes; /* Number of full bytes in the bitmap, that
is 'pulses_len/8' rounded to the next
is 'pulses_count/8' rounded to the next
integer. */
} ProtoViewMsgInfo;

Expand All @@ -133,6 +134,13 @@ struct ProtoViewApp {
ProtoViewMsgInfo *msg_info; /* Decoded message info if not NULL. */
bool direct_sampling_enabled; /* This special view needs an explicit
acknowledge to work. */
void *view_privdata; /* This is a piece of memory of total size
PROTOVIEW_VIEW_PRIVDATA_LEN that it is
initialized to zero when we switch to
a a new view. While the view we are using
is the same, it can be used by the view to
store any kind of info inside, just casting
the pointer to a few specific-data structure. */

/* Raw view apps state. */
uint32_t us_scale; /* microseconds per pixel. */
Expand Down
11 changes: 7 additions & 4 deletions protocols/b4b1.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView
"1000000000000000000000000000000001", /* 32 zero bits. */
};

uint32_t off, start;
uint32_t off;
int j;
for (j = 0; j < 3; j++) {
off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_patterns[j]);
if (off != BITMAP_SEEK_NOT_FOUND) break;
}
if (off == BITMAP_SEEK_NOT_FOUND) return false;
if (DEBUG_MSG) FURI_LOG_E(TAG, "B4B1 preamble at: %lu",off);
start = off;
info->start_off = off;

// Seek data setction. Why -1? Last bit is data.
off += strlen(sync_patterns[j])-1;

uint8_t d[3]; /* 24 bits of data. */
Expand All @@ -34,10 +36,11 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView

if (DEBUG_MSG) FURI_LOG_E(TAG, "B4B1 decoded: %lu",decoded);
if (decoded != 24) return false;

off += 24*4; // seek to end symbol offset to calculate the length.
info->pulses_count = off - info->start_off;
snprintf(info->name,PROTOVIEW_MSG_STR_LEN,"PT/SC remote");
snprintf(info->raw,PROTOVIEW_MSG_STR_LEN,"%02X%02X%02X",d[0],d[1],d[2]);
info->start_off = start;
info->pulses_len = 4*24;
return true;
}

Expand Down
10 changes: 8 additions & 2 deletions protocols/keeloq.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView
const char *sync_pattern = "101010101010101010101010" "0000";
uint8_t sync_len = 24+4;
if (numbits-sync_len+sync_len < 3*66) return false;
uint64_t off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_pattern);
uint32_t off = bitmap_seek_bits(bits,numbytes,0,numbits,sync_pattern);
if (off == BITMAP_SEEK_NOT_FOUND) return false;
off += sync_len;

info->start_off = off;
off += sync_len; // Seek start of message.

/* Now there is half the gap left, but we allow from 3 to 7, instead of 5
* symbols of gap, to avoid missing the signal for a matter of wrong
Expand All @@ -54,6 +56,10 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView
FURI_LOG_E(TAG, "Keeloq decoded bits: %lu", decoded);

if (decoded < 66) return false; /* Require the full 66 bits. */

off += decoded+66*3; // Seek end to compute total length.
info->pulses_count = off - info->start_off;

bitmap_reverse_bytes(raw,sizeof(raw)); /* Keeloq is LSB first. */

int buttons = raw[7]>>4;
Expand Down
18 changes: 12 additions & 6 deletions signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,22 @@ void scan_for_signal(ProtoViewApp *app) {
than a few samples it's very easy to
mistake noise for signal. */

ProtoViewMsgInfo *info = malloc(sizeof(ProtoViewMsgInfo));
uint32_t i = 0;

while (i < copy->total-1) {
uint32_t thislen = search_coherent_signal(copy,i);

/* For messages that are long enough, attempt decoding. */
if (thislen > minlen) {
/* Allocate the message information that some decoder may
* fill, in case it is able to decode a message. */
ProtoViewMsgInfo *info = malloc(sizeof(ProtoViewMsgInfo));
init_msg_info(info,app);

uint32_t saved_idx = copy->idx; /* Save index, see later. */

/* decode_signal() expects the detected signal to start
* from index .*/
* from index zero .*/
raw_samples_center(copy,i);
bool decoded = decode_signal(copy,thislen,info);
copy->idx = saved_idx; /* Restore the index as we are scanning
Expand Down Expand Up @@ -175,6 +179,8 @@ void scan_for_signal(ProtoViewApp *app) {
else if (DetectedSamples->short_pulse_dur < 145)
app->us_scale = 30;
} else {
/* If the structure was not filled, discard it. Otherwise
* now the owner is app->msg_info. */
free_msg_info(info);
}
}
Expand Down Expand Up @@ -571,13 +577,13 @@ bool decode_signal(RawSamplesBuffer *s, uint64_t len, ProtoViewMsgInfo *info) {
/* The message was correctly decoded: fill the info structure
* with the decoded signal. The decoder may not implement offset/len
* filling of the structure. In such case we have no info and
* pulses_len will be set to zero. */
if (info->pulses_len) {
info->bits_bytes = (info->pulses_len+7)/8; // Round to full byte.
* pulses_count will be set to zero. */
if (info->pulses_count) {
info->bits_bytes = (info->pulses_count+7)/8; // Round to full byte.
info->bits = malloc(info->bits_bytes);
bitmap_copy(info->bits,info->bits_bytes,0,
bitmap,bitmap_size,info->start_off,
info->pulses_len);
info->pulses_count);
}
}
free(bitmap);
Expand Down
42 changes: 35 additions & 7 deletions view_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ enum {
SubViewInfoLast, /* Just a sentinel. */
};

/* Our view private data. */
typedef struct {
/* Our save view displays an oscilloscope-alike resampled signal,
* so that the user can see what they are saving. With left/right
* you can move to next rows. Here we store where we are. */
uint32_t signal_display_start_row;
} InfoViewPrivData;

/* Render the view with the detected message information. */
static void render_subview_main(Canvas *const canvas, ProtoViewApp *app) {
/* Protocol name as title. */
Expand All @@ -33,22 +41,31 @@ static void render_subview_main(Canvas *const canvas, ProtoViewApp *app) {

/* Render view with save option. */
static void render_subview_save(Canvas *const canvas, ProtoViewApp *app) {
InfoViewPrivData *privdata = app->view_privdata;

/* Display our signal in digital form: here we don't show the
* signal with the exact timing of the received samples, but as it
* is in its logic form, in exact multiples of the short pulse length. */
uint8_t rows = 6;
uint8_t rowheight = 8;
uint8_t rowheight = 11;
uint8_t bitwidth = 4;
uint8_t bitheight = 5;
uint32_t idx = 0;
uint32_t idx = privdata->signal_display_start_row * (128/4);
bool prevbit = false;
for (uint8_t y = bitheight; y < rows*rowheight; y += rowheight) {
for (uint8_t y = bitheight+12; y <= rows*rowheight; y += rowheight) {
for (uint8_t x = 5; x < 128; x += 4) {
bool bit = bitmap_get(app->msg_info->bits,
app->msg_info->bits_bytes,idx++);
uint8_t prevy = y + prevbit*bitheight - 1;
uint8_t thisy = y + bit*bitheight - 1;
uint8_t prevy = y + prevbit*(bitheight*-1) - 1;
uint8_t thisy = y + bit*(bitheight*-1) - 1;
canvas_draw_line(canvas,x,prevy,x,thisy);
canvas_draw_line(canvas,x,thisy,x+bitwidth-1,thisy);
prevbit = bit;
}
}

canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 0, 6, "ok: save, < >: slide rows");
}

/* Render the selected subview of this view. */
Expand All @@ -69,10 +86,21 @@ void render_view_info(Canvas *const canvas, ProtoViewApp *app) {
/* Handle input for the info view. */
void process_input_info(ProtoViewApp *app, InputEvent input) {
if (process_subview_updown(app,input,SubViewInfoLast)) return;
if (input.type == InputTypeShort) {
if (input.key == InputKeyOk) {
InfoViewPrivData *privdata = app->view_privdata;
int subview = get_current_subview(app);

/* Main subview. */
if (subview == SubViewInfoMain) {
if (input.type == InputTypeShort && input.key == InputKeyOk) {
/* Reset the current sample to capture the next. */
reset_current_signal(app);
}
} else if (subview == SubViewInfoSave) {
/* Save subview. */
if (input.type == InputTypePress && input.key == InputKeyRight) {
privdata->signal_display_start_row++;
} else if (input.type == InputTypePress && input.key == InputKeyLeft) {
privdata->signal_display_start_row--;
}
}
}

0 comments on commit 2459e55

Please sign in to comment.