From 23a8793616dcf0b1f5926424a09de72ced5ea66f Mon Sep 17 00:00:00 2001 From: antirez Date: Sat, 21 Jan 2023 18:54:15 +0100 Subject: [PATCH] Build message view introduced. --- app.c | 5 ++++ app.h | 12 +++++++- protocols/b4b1.c | 14 ++++++++-- protocols/keeloq.c | 14 ++++++++-- view_build.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 view_build.c diff --git a/app.c b/app.c index b1c4b168a78..f8eba44b35e 100644 --- a/app.c +++ b/app.c @@ -57,6 +57,7 @@ static void render_callback(Canvas *const canvas, void *ctx) { case ViewModulationSettings: render_view_settings(canvas,app); break; case ViewDirectSampling: render_view_direct_sampling(canvas,app); break; + case ViewBuildMessage: render_view_build_message(canvas,app); break; default: furi_crash(TAG "Invalid view selected"); break; } @@ -97,6 +98,7 @@ static void app_switch_view(ProtoViewApp *app, ProtoViewCurrentView switchto) { /* Call the enter/exit view callbacks if needed. */ if (old == ViewDirectSampling) view_exit_direct_sampling(app); if (new == ViewDirectSampling) view_enter_direct_sampling(app); + if (old == ViewBuildMessage) view_exit_build_message(app); /* The frequency/modulation settings are actually a single view: * as long as the user stays between the two modes of this view we * don't need to call the exit-view callback. */ @@ -331,6 +333,9 @@ int32_t protoview_app_entry(void* p) { case ViewDirectSampling: process_input_direct_sampling(app,input); break; + case ViewBuildMessage: + process_input_build_message(app,input); + break; default: furi_crash(TAG "Invalid view selected"); break; } } diff --git a/app.h b/app.h index 80eee33ce93..80f537176b4 100644 --- a/app.h +++ b/app.h @@ -53,6 +53,7 @@ typedef enum { ViewInfo, ViewFrequencySettings, ViewModulationSettings, + ViewBuildMessage, ViewDirectSampling, ViewLast, /* Just a sentinel to wrap around. */ @@ -225,7 +226,13 @@ typedef struct ProtoViewDecoder { * functions that perform bit extraction with bound checking, such as * bitmap_get() and so forth. */ bool (*decode)(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoViewMsgInfo *info); - void (*get_fields)(ProtoViewMsgInfo *info, ProtoViewFieldSet *fields); + /* This method is used by the decoder to return the fields it needs + * in order to build a new message. This way the message builder view + * can ask the user to fill the right set of fields of the specified + * type. */ + void (*get_fields)(ProtoViewFieldSet *fields); + /* This method takes the fields supported by the decoder, and + * renders a message in 'samples'. */ void (*build_message)(RawSamplesBuffer *samples, ProtoViewFieldSet *fields); } ProtoViewDecoder; @@ -269,6 +276,9 @@ void render_view_info(Canvas *const canvas, ProtoViewApp *app); void process_input_info(ProtoViewApp *app, InputEvent input); void render_view_direct_sampling(Canvas *const canvas, ProtoViewApp *app); void process_input_direct_sampling(ProtoViewApp *app, InputEvent input); +void render_view_build_message(Canvas *const canvas, ProtoViewApp *app); +void process_input_build_message(ProtoViewApp *app, InputEvent input); +void view_exit_build_message(ProtoViewApp *app); void view_enter_direct_sampling(ProtoViewApp *app); void view_exit_direct_sampling(ProtoViewApp *app); void view_exit_settings(ProtoViewApp *app); diff --git a/protocols/b4b1.c b/protocols/b4b1.c index eb0cbb41d89..db758dcca49 100644 --- a/protocols/b4b1.c +++ b/protocols/b4b1.c @@ -46,9 +46,19 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView return true; } +static void get_fields(ProtoViewFieldSet *fields) { + UNUSED(fields); +} + +static void build_message(RawSamplesBuffer *samples, ProtoViewFieldSet *fields) +{ + UNUSED(samples); + UNUSED(fields); +} + ProtoViewDecoder B4B1Decoder = { .name = "PT/SC remote", .decode = decode, - .get_fields = NULL, - .build_message = NULL + .get_fields = get_fields, + .build_message = build_message }; diff --git a/protocols/keeloq.c b/protocols/keeloq.c index ccff75a246c..bf80a8f3dd5 100644 --- a/protocols/keeloq.c +++ b/protocols/keeloq.c @@ -75,9 +75,19 @@ static bool decode(uint8_t *bits, uint32_t numbytes, uint32_t numbits, ProtoView return true; } +static void get_fields(ProtoViewFieldSet *fields) { + UNUSED(fields); +} + +static void build_message(RawSamplesBuffer *samples, ProtoViewFieldSet *fields) +{ + UNUSED(samples); + UNUSED(fields); +} + ProtoViewDecoder KeeloqDecoder = { .name = "Keeloq", .decode = decode, - .get_fields = NULL, - .build_message = NULL + .get_fields = get_fields, + .build_message = build_message }; diff --git a/view_build.c b/view_build.c new file mode 100644 index 00000000000..34e6027c154 --- /dev/null +++ b/view_build.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2022-2023 Salvatore Sanfilippo -- All Rights Reserved + * See the LICENSE file for information about the license. */ + +#include "app.h" + +extern ProtoViewDecoder *Decoders[]; // Defined in signal.c. + +/* Our view private data. */ +typedef struct { + ProtoViewDecoder *decoder; // Decoder we are using to create a message. + uint32_t cur_decoder; // Decoder index when we are yet selecting + // a decoder. Used when decoder is NULL. + ProtoViewFieldSet *fieldset; // The fields to populate. + uint32_t cur_field; // Field we are editing right now. This + // is the index inside the 'fieldset' + // fields. +} BuildViewPrivData; + +/* Render the view to select the decoder, among the ones that + * support message building. */ +static void render_view_select_decoder(Canvas *const canvas, ProtoViewApp *app) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 0, 9, "Signal builder"); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 0, 19, "up/down: select, ok: choose"); + + UNUSED(app); // XXX +} + +/* Render the view that allows the user to populate the fields needed + * for the selected decoder to build a message. */ +static void render_view_set_fields(Canvas *const canvas, ProtoViewApp *app) { + BuildViewPrivData *privdata = app->view_privdata; + char buf[32]; + snprintf(buf,sizeof(buf), "%s field %d/%d", + privdata->decoder->name, (int)privdata->cur_field, + (int)privdata->fieldset->numfields); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 0, 9, buf); + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 0, 19, "up/down: next field, ok: edit"); +} + +/* Render the build message view. */ +void render_view_build_message(Canvas *const canvas, ProtoViewApp *app) { + BuildViewPrivData *privdata = app->view_privdata; + + if (privdata->decoder == NULL) + render_view_select_decoder(canvas,app); + else + render_view_set_fields(canvas,app); +} + +/* Handle input for the build message view. */ +void process_input_build_message(ProtoViewApp *app, InputEvent input) { + UNUSED(app); + if (input.type == InputTypeShort) { + if (input.key == InputKeyOk) { + } else if (input.key == InputKeyDown) { + } else if (input.key == InputKeyUp) { + } + } +} + +/* Called on exit for cleanup. */ +void view_exit_build_message(ProtoViewApp *app) { + BuildViewPrivData *privdata = app->view_privdata; + if (privdata->fieldset) fieldset_free(privdata->fieldset); +}