From 08e533ccf2e3fe7c0d772d3974670378265c7c13 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sat, 26 Nov 2022 17:23:36 +0300 Subject: [PATCH 1/6] SubGHz: Fix Came Atomo and NiceFlorS counters add check for protocols with 16bit counters, to block them for going higher than 16bit --- lib/subghz/protocols/came_atomo.c | 6 +++++- lib/subghz/protocols/nice_flor_s.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/subghz/protocols/came_atomo.c b/lib/subghz/protocols/came_atomo.c index 747d0d074..d12e5976c 100644 --- a/lib/subghz/protocols/came_atomo.c +++ b/lib/subghz/protocols/came_atomo.c @@ -135,7 +135,11 @@ static void uint8_t pack[8] = {}; - instance->generic.cnt++; + if(instance->generic.cnt < 0xFFFF) { + instance->generic.cnt++; + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } //Send header instance->encoder.upload[index++] = diff --git a/lib/subghz/protocols/nice_flor_s.c b/lib/subghz/protocols/nice_flor_s.c index bcc5c7466..6913103bd 100644 --- a/lib/subghz/protocols/nice_flor_s.c +++ b/lib/subghz/protocols/nice_flor_s.c @@ -129,7 +129,11 @@ static void subghz_protocol_encoder_nice_flor_s_get_upload( instance->encoder.size_upload = size_upload; } - instance->generic.cnt++; + if(instance->generic.cnt < 0xFFFF) { + instance->generic.cnt++; + } else if(instance->generic.cnt >= 0xFFFF) { + instance->generic.cnt = 0; + } uint64_t decrypt = ((uint64_t)instance->generic.serial << 16) | instance->generic.cnt; uint64_t enc_part = subghz_protocol_nice_flor_s_encrypt(decrypt, file_name); From 2985268fe3d1398ddd7a50c6d5592b1f2f1d39a2 Mon Sep 17 00:00:00 2001 From: StellarStoic <34000272+StellarStoic@users.noreply.github.com> Date: Sat, 26 Nov 2022 22:49:56 +0100 Subject: [PATCH 2/6] Adding Slovenian, Bosnian and Croatian layout Slovenian (si) / Croatian (hr) keyboard layout, which is also the default layout for Bosnian (ba) (Latin, Bosnia and Herzegovina) --- assets/resources/badusb/layouts/ba-BA.kl | Bin 0 -> 256 bytes assets/resources/badusb/layouts/hr-HR.kl | Bin 0 -> 256 bytes assets/resources/badusb/layouts/si-SI.kl | Bin 0 -> 256 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/resources/badusb/layouts/ba-BA.kl create mode 100644 assets/resources/badusb/layouts/hr-HR.kl create mode 100644 assets/resources/badusb/layouts/si-SI.kl diff --git a/assets/resources/badusb/layouts/ba-BA.kl b/assets/resources/badusb/layouts/ba-BA.kl new file mode 100644 index 0000000000000000000000000000000000000000..379f6c649c98ef7f38df9c6d1c2b1588167ee46a GIT binary patch literal 256 zcmaLL%XYy47y#ipa|DTNh+7ar(9@P>V)?)SQ*~|A*?j|_ee=WD=lWN_RGzFod-3X% zn|EKnXnE7o_@LrM&6x{V8gAU_Y;EIV7f*N5GqLZ$p{bc8$4;C&b8ha!rG+ckZrr-F ybnnrFX%vw~9dDcHkV)?)SQ*~|A*?j|_ee=WD=lWN_RGzFod-3X% zn|EKnXnE7o_@LrM&6x{V8gAU_Y;EIV7f*N5GqLZ$p{bc8$4;C&b8ha!rG+ckZrr-F ybnnrFX%vw~9dDcHkV)?)SQ*~|A*?j|_ee=WD=lWN_RGzFod-3X% zn|EKnXnE7o_@LrM&6x{V8gAU_Y;EIV7f*N5GqLZ$p{bc8$4;C&b8ha!rG+ckZrr-F ybnnrFX%vw~9dDcHk Date: Sun, 27 Nov 2022 02:32:43 +0300 Subject: [PATCH 3/6] WS: Add protocol Auriol HG0601A Made by @LY2NEO --- .../protocols/auriol_hg0601a.c | 258 ++++++++++++++++++ .../protocols/auriol_hg0601a.h | 79 ++++++ .../protocols/protocol_items.c | 1 + .../protocols/protocol_items.h | 1 + 4 files changed, 339 insertions(+) create mode 100644 applications/plugins/weather_station/protocols/auriol_hg0601a.c create mode 100644 applications/plugins/weather_station/protocols/auriol_hg0601a.h diff --git a/applications/plugins/weather_station/protocols/auriol_hg0601a.c b/applications/plugins/weather_station/protocols/auriol_hg0601a.c new file mode 100644 index 000000000..cb00cb3c1 --- /dev/null +++ b/applications/plugins/weather_station/protocols/auriol_hg0601a.c @@ -0,0 +1,258 @@ +#include "auriol_hg0601a.h" + +#define TAG "WSProtocolauriol_TH" + +/* + * +Auriol HG06061A-DCF-TX sensor. + +Data layout: + DDDDDDDD-B0-NN-TT-TTTTTTTTTT-CCCC-HHHHHHHH +Exmpl.: 11110100-10-01-00-0001001100-1111-01011101 + +- D: id, 8 bit +- B: where B is the battery status: 1=OK, 0=LOW, 1 bit +- 0: just zero :) +- N: NN is the channel: 00=CH1, 01=CH2, 11=CH3, 2bit +- T: temperature, 12 bit: 2's complement, scaled by 10 +- C: 4 bit: seems to be 0xf constantly, a separator between temp and humidity +- H: humidity sensor, humidity is 8 bits + + * The sensor sends 37 bits 10 times, + * the packets are ppm modulated (distance coding) with a pulse of ~500 us + * followed by a short gap of ~1000 us for a 0 bit or a long ~2000 us gap for a + * 1 bit, the sync gap is ~4000 us. + * + */ + +#define AURIOL_TH_CONST_DATA 0b1110 + +static const SubGhzBlockConst ws_protocol_auriol_th_const = { + .te_short = 500, + .te_long = 2000, + .te_delta = 150, + .min_count_bit_for_found = 37, +}; + +struct WSProtocolDecoderauriol_TH { + SubGhzProtocolDecoderBase base; + + SubGhzBlockDecoder decoder; + WSBlockGeneric generic; +}; + +struct WSProtocolEncoderauriol_TH { + SubGhzProtocolEncoderBase base; + + SubGhzProtocolBlockEncoder encoder; + WSBlockGeneric generic; +}; + +typedef enum { + auriol_THDecoderStepReset = 0, + auriol_THDecoderStepSaveDuration, + auriol_THDecoderStepCheckDuration, +} auriol_THDecoderStep; + +const SubGhzProtocolDecoder ws_protocol_auriol_th_decoder = { + .alloc = ws_protocol_decoder_auriol_th_alloc, + .free = ws_protocol_decoder_auriol_th_free, + + .feed = ws_protocol_decoder_auriol_th_feed, + .reset = ws_protocol_decoder_auriol_th_reset, + + .get_hash_data = ws_protocol_decoder_auriol_th_get_hash_data, + .serialize = ws_protocol_decoder_auriol_th_serialize, + .deserialize = ws_protocol_decoder_auriol_th_deserialize, + .get_string = ws_protocol_decoder_auriol_th_get_string, +}; + +const SubGhzProtocolEncoder ws_protocol_auriol_th_encoder = { + .alloc = NULL, + .free = NULL, + + .deserialize = NULL, + .stop = NULL, + .yield = NULL, +}; + +const SubGhzProtocol ws_protocol_auriol_th = { + .name = WS_PROTOCOL_auriol_TH_NAME, + .type = SubGhzProtocolWeatherStation, + .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 | + SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable, + + .decoder = &ws_protocol_auriol_th_decoder, + .encoder = &ws_protocol_auriol_th_encoder, +}; + +void* ws_protocol_decoder_auriol_th_alloc(SubGhzEnvironment* environment) { + UNUSED(environment); + WSProtocolDecoderauriol_TH* instance = malloc(sizeof(WSProtocolDecoderauriol_TH)); + instance->base.protocol = &ws_protocol_auriol_th; + instance->generic.protocol_name = instance->base.protocol->name; + return instance; +} + +void ws_protocol_decoder_auriol_th_free(void* context) { + furi_assert(context); + WSProtocolDecoderauriol_TH* instance = context; + free(instance); +} + +void ws_protocol_decoder_auriol_th_reset(void* context) { + furi_assert(context); + WSProtocolDecoderauriol_TH* instance = context; + instance->decoder.parser_step = auriol_THDecoderStepReset; +} + +static bool ws_protocol_auriol_th_check(WSProtocolDecoderauriol_TH* instance) { + uint8_t type = (instance->decoder.decode_data >> 8) & 0x0F; + + if((type == AURIOL_TH_CONST_DATA) && ((instance->decoder.decode_data >> 4) != 0xffffffff)) { + return true; + } else { + return false; + } + return true; +} + +/** + * Analysis of received data + * @param instance Pointer to a WSBlockGeneric* instance + */ +static void ws_protocol_auriol_th_remote_controller(WSBlockGeneric* instance) { + instance->id = (instance->data >> 31) & 0xFF; + instance->battery_low = ((instance->data >> 30) & 1); + instance->channel = ((instance->data >> 25) & 0x03) + 1; + instance->btn = WS_NO_BTN; + if(!((instance->data >> 23) & 1)) { + instance->temp = (float)((instance->data >> 13) & 0x07FF) / 10.0f; + } else { + instance->temp = (float)((~(instance->data >> 13) & 0x07FF) + 1) / -10.0f; + } + + instance->humidity = (instance->data >> 1) & 0x7F; +} + +void ws_protocol_decoder_auriol_th_feed(void* context, bool level, uint32_t duration) { + furi_assert(context); + WSProtocolDecoderauriol_TH* instance = context; + + switch(instance->decoder.parser_step) { + case auriol_THDecoderStepReset: + if((!level) && (DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 8) < + ws_protocol_auriol_th_const.te_delta)) { + //Found sync + instance->decoder.parser_step = auriol_THDecoderStepSaveDuration; + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + } + break; + + case auriol_THDecoderStepSaveDuration: + if(level) { + instance->decoder.te_last = duration; + instance->decoder.parser_step = auriol_THDecoderStepCheckDuration; + } else { + instance->decoder.parser_step = auriol_THDecoderStepReset; + } + break; + + case auriol_THDecoderStepCheckDuration: + if(!level) { + if(DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 8) < + ws_protocol_auriol_th_const.te_delta) { + //Found sync + instance->decoder.parser_step = auriol_THDecoderStepReset; + if((instance->decoder.decode_count_bit == + ws_protocol_auriol_th_const.min_count_bit_for_found) && + ws_protocol_auriol_th_check(instance)) { + instance->generic.data = instance->decoder.decode_data; + instance->generic.data_count_bit = instance->decoder.decode_count_bit; + ws_protocol_auriol_th_remote_controller(&instance->generic); + if(instance->base.callback) + instance->base.callback(&instance->base, instance->base.context); + instance->decoder.parser_step = auriol_THDecoderStepCheckDuration; + } + instance->decoder.decode_data = 0; + instance->decoder.decode_count_bit = 0; + + break; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_auriol_th_const.te_short) < + ws_protocol_auriol_th_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 2) < + ws_protocol_auriol_th_const.te_delta)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 0); + instance->decoder.parser_step = auriol_THDecoderStepSaveDuration; + } else if( + (DURATION_DIFF(instance->decoder.te_last, ws_protocol_auriol_th_const.te_short) < + ws_protocol_auriol_th_const.te_delta) && + (DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 4) < + ws_protocol_auriol_th_const.te_delta * 2)) { + subghz_protocol_blocks_add_bit(&instance->decoder, 1); + instance->decoder.parser_step = auriol_THDecoderStepSaveDuration; + } else { + instance->decoder.parser_step = auriol_THDecoderStepReset; + } + } else { + instance->decoder.parser_step = auriol_THDecoderStepReset; + } + break; + } +} + +uint8_t ws_protocol_decoder_auriol_th_get_hash_data(void* context) { + furi_assert(context); + WSProtocolDecoderauriol_TH* instance = context; + return subghz_protocol_blocks_get_hash_data( + &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1); +} + +bool ws_protocol_decoder_auriol_th_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset) { + furi_assert(context); + WSProtocolDecoderauriol_TH* instance = context; + return ws_block_generic_serialize(&instance->generic, flipper_format, preset); +} + +bool ws_protocol_decoder_auriol_th_deserialize(void* context, FlipperFormat* flipper_format) { + furi_assert(context); + WSProtocolDecoderauriol_TH* instance = context; + bool ret = false; + do { + if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) { + break; + } + if(instance->generic.data_count_bit != + ws_protocol_auriol_th_const.min_count_bit_for_found) { + FURI_LOG_E(TAG, "Wrong number of bits in key"); + break; + } + ret = true; + } while(false); + return ret; +} + +void ws_protocol_decoder_auriol_th_get_string(void* context, FuriString* output) { + furi_assert(context); + WSProtocolDecoderauriol_TH* instance = context; + furi_string_printf( + output, + "%s %dbit\r\n" + "Key:0x%lX%08lX\r\n" + "Sn:0x%lX Ch:%d Bat:%d\r\n" + "Temp:%3.1f C Hum:%d%%", + instance->generic.protocol_name, + instance->generic.data_count_bit, + (uint32_t)(instance->generic.data >> 32), + (uint32_t)(instance->generic.data), + instance->generic.id, + instance->generic.channel, + instance->generic.battery_low, + (double)instance->generic.temp, + instance->generic.humidity); +} diff --git a/applications/plugins/weather_station/protocols/auriol_hg0601a.h b/applications/plugins/weather_station/protocols/auriol_hg0601a.h new file mode 100644 index 000000000..b38cdbb05 --- /dev/null +++ b/applications/plugins/weather_station/protocols/auriol_hg0601a.h @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include +#include +#include +#include "ws_generic.h" +#include + +#define WS_PROTOCOL_auriol_TH_NAME "Auriol HG06061" //HG06061A-DCF-TX + +typedef struct WSProtocolDecoderauriol_TH WSProtocolDecoderauriol_TH; +typedef struct WSProtocolEncoderauriol_TH WSProtocolEncoderauriol_TH; + +extern const SubGhzProtocolDecoder ws_protocol_auriol_th_decoder; +extern const SubGhzProtocolEncoder ws_protocol_auriol_th_encoder; +extern const SubGhzProtocol ws_protocol_auriol_th; + +/** + * Allocate WSProtocolDecoderauriol_TH. + * @param environment Pointer to a SubGhzEnvironment instance + * @return WSProtocolDecoderauriol_TH* pointer to a WSProtocolDecoderauriol_TH instance + */ +void* ws_protocol_decoder_auriol_th_alloc(SubGhzEnvironment* environment); + +/** + * Free WSProtocolDecoderauriol_TH. + * @param context Pointer to a WSProtocolDecoderauriol_TH instance + */ +void ws_protocol_decoder_auriol_th_free(void* context); + +/** + * Reset decoder WSProtocolDecoderauriol_TH. + * @param context Pointer to a WSProtocolDecoderauriol_TH instance + */ +void ws_protocol_decoder_auriol_th_reset(void* context); + +/** + * Parse a raw sequence of levels and durations received from the air. + * @param context Pointer to a WSProtocolDecoderauriol_TH instance + * @param level Signal level true-high false-low + * @param duration Duration of this level in, us + */ +void ws_protocol_decoder_auriol_th_feed(void* context, bool level, uint32_t duration); + +/** + * Getting the hash sum of the last randomly received parcel. + * @param context Pointer to a WSProtocolDecoderauriol_TH instance + * @return hash Hash sum + */ +uint8_t ws_protocol_decoder_auriol_th_get_hash_data(void* context); + +/** + * Serialize data WSProtocolDecoderauriol_TH. + * @param context Pointer to a WSProtocolDecoderauriol_TH instance + * @param flipper_format Pointer to a FlipperFormat instance + * @param preset The modulation on which the signal was received, SubGhzRadioPreset + * @return true On success + */ +bool ws_protocol_decoder_auriol_th_serialize( + void* context, + FlipperFormat* flipper_format, + SubGhzRadioPreset* preset); + +/** + * Deserialize data WSProtocolDecoderauriol_TH. + * @param context Pointer to a WSProtocolDecoderauriol_TH instance + * @param flipper_format Pointer to a FlipperFormat instance + * @return true On success + */ +bool ws_protocol_decoder_auriol_th_deserialize(void* context, FlipperFormat* flipper_format); + +/** + * Getting a textual representation of the received data. + * @param context Pointer to a WSProtocolDecoderauriol_TH instance + * @param output Resulting text + */ +void ws_protocol_decoder_auriol_th_get_string(void* context, FuriString* output); diff --git a/applications/plugins/weather_station/protocols/protocol_items.c b/applications/plugins/weather_station/protocols/protocol_items.c index 21768e042..9ad8ce1ac 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.c +++ b/applications/plugins/weather_station/protocols/protocol_items.c @@ -12,6 +12,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = { &ws_protocol_oregon2, &ws_protocol_acurite_592txr, &ws_protocol_ambient_weather, + &ws_protocol_auriol_th, }; const SubGhzProtocolRegistry weather_station_protocol_registry = { diff --git a/applications/plugins/weather_station/protocols/protocol_items.h b/applications/plugins/weather_station/protocols/protocol_items.h index aa064f044..4fef89442 100644 --- a/applications/plugins/weather_station/protocols/protocol_items.h +++ b/applications/plugins/weather_station/protocols/protocol_items.h @@ -12,5 +12,6 @@ #include "oregon2.h" #include "acurite_592txr.h" #include "ambient_weather.h" +#include "auriol_hg0601a.h" extern const SubGhzProtocolRegistry weather_station_protocol_registry; From 6267dc7d5b6e2074e8eaf654b8cdc0ad5a532583 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 27 Nov 2022 02:44:10 +0300 Subject: [PATCH 4/6] Update HEX Viewer --- applications/plugins/hex_viewer/LICENSE | 21 +++++++ applications/plugins/hex_viewer/hex_viewer.c | 66 +++++++++++--------- 2 files changed, 56 insertions(+), 31 deletions(-) create mode 100644 applications/plugins/hex_viewer/LICENSE diff --git a/applications/plugins/hex_viewer/LICENSE b/applications/plugins/hex_viewer/LICENSE new file mode 100644 index 000000000..69004dc62 --- /dev/null +++ b/applications/plugins/hex_viewer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Roman Shchekin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/applications/plugins/hex_viewer/hex_viewer.c b/applications/plugins/hex_viewer/hex_viewer.c index 5289c8654..50c34d634 100644 --- a/applications/plugins/hex_viewer/hex_viewer.c +++ b/applications/plugins/hex_viewer/hex_viewer.c @@ -16,14 +16,14 @@ #define HEX_VIEWER_APP_PATH_FOLDER "/any" #define HEX_VIEWER_APP_EXTENSION "*" -#define HEX_VIEWER_BYTES_PER_ROW 4 -#define HEX_VIEWER_ROW_COUNT 4 -#define HEX_VIEWER_BUF_SIZE (HEX_VIEWER_BYTES_PER_ROW * HEX_VIEWER_ROW_COUNT) +#define HEX_VIEWER_BYTES_PER_LINE 4u +#define HEX_VIEWER_LINES_ON_SCREEN 4u +#define HEX_VIEWER_BUF_SIZE (HEX_VIEWER_LINES_ON_SCREEN * HEX_VIEWER_BYTES_PER_LINE) typedef struct { - uint8_t file_bytes[HEX_VIEWER_ROW_COUNT][HEX_VIEWER_ROW_COUNT]; - uint32_t line; - uint32_t read_bytes; + uint8_t file_bytes[HEX_VIEWER_LINES_ON_SCREEN][HEX_VIEWER_BYTES_PER_LINE]; + uint32_t file_offset; + uint32_t file_read_bytes; uint32_t file_size; Stream* stream; bool mode; // Print address or content @@ -54,27 +54,28 @@ static void render_callback(Canvas* canvas, void* ctx) { int TOP_OFFSET = 10; int LEFT_OFFSET = 3; - uint32_t line_count = hex_viewer->model->file_size / HEX_VIEWER_BYTES_PER_ROW; - if(hex_viewer->model->file_size % HEX_VIEWER_BYTES_PER_ROW != 0) line_count += 1; - if(line_count > HEX_VIEWER_ROW_COUNT) { + uint32_t line_count = hex_viewer->model->file_size / HEX_VIEWER_BYTES_PER_LINE; + if(hex_viewer->model->file_size % HEX_VIEWER_BYTES_PER_LINE != 0) line_count += 1; + uint32_t first_line_on_screen = hex_viewer->model->file_offset / HEX_VIEWER_BYTES_PER_LINE; + if(line_count > HEX_VIEWER_LINES_ON_SCREEN) { uint8_t width = canvas_width(canvas); elements_scrollbar_pos( canvas, width, 0, - ROW_HEIGHT * HEX_VIEWER_ROW_COUNT, - hex_viewer->model->line, - line_count - (HEX_VIEWER_ROW_COUNT - 1)); + ROW_HEIGHT * HEX_VIEWER_LINES_ON_SCREEN, + first_line_on_screen, // TODO + line_count - (HEX_VIEWER_LINES_ON_SCREEN - 1)); } char temp_buf[32]; - uint32_t row_iters = hex_viewer->model->read_bytes / HEX_VIEWER_BYTES_PER_ROW; - if(hex_viewer->model->read_bytes % HEX_VIEWER_BYTES_PER_ROW != 0) row_iters += 1; + uint32_t row_iters = hex_viewer->model->file_read_bytes / HEX_VIEWER_BYTES_PER_LINE; + if(hex_viewer->model->file_read_bytes % HEX_VIEWER_BYTES_PER_LINE != 0) row_iters += 1; for(uint32_t i = 0; i < row_iters; ++i) { - uint32_t bytes_left_per_row = hex_viewer->model->read_bytes - i * HEX_VIEWER_BYTES_PER_ROW; - if(bytes_left_per_row > HEX_VIEWER_BYTES_PER_ROW) - bytes_left_per_row = HEX_VIEWER_BYTES_PER_ROW; + uint32_t bytes_left_per_row = + hex_viewer->model->file_read_bytes - i * HEX_VIEWER_BYTES_PER_LINE; + bytes_left_per_row = MIN(bytes_left_per_row, HEX_VIEWER_BYTES_PER_LINE); if(hex_viewer->model->mode) { memcpy(temp_buf, hex_viewer->model->file_bytes[i], bytes_left_per_row); @@ -85,8 +86,8 @@ static void render_callback(Canvas* canvas, void* ctx) { canvas_set_font(canvas, FontKeyboard); canvas_draw_str(canvas, LEFT_OFFSET, TOP_OFFSET + i * ROW_HEIGHT, temp_buf); } else { - int addr = (i + hex_viewer->model->line) * HEX_VIEWER_BYTES_PER_ROW; - snprintf(temp_buf, 32, "%04X", addr); + uint32_t addr = hex_viewer->model->file_offset + i * HEX_VIEWER_BYTES_PER_LINE; + snprintf(temp_buf, 32, "%04lX", addr); canvas_set_font(canvas, FontKeyboard); canvas_draw_str(canvas, LEFT_OFFSET, TOP_OFFSET + i * ROW_HEIGHT, temp_buf); @@ -105,7 +106,7 @@ static void render_callback(Canvas* canvas, void* ctx) { static void input_callback(InputEvent* input_event, void* ctx) { HexViewer* hex_viewer = ctx; - if(input_event->type == InputTypeShort) { + if(input_event->type == InputTypeShort || input_event->type == InputTypeRepeat) { furi_message_queue_put(hex_viewer->input_queue, input_event, 0); } } @@ -173,19 +174,20 @@ static bool hex_viewer_open_file(HexViewer* hex_viewer, const char* file_path) { static bool hex_viewer_read_file(HexViewer* hex_viewer) { furi_assert(hex_viewer); furi_assert(hex_viewer->model->stream); + furi_assert(hex_viewer->model->file_offset % HEX_VIEWER_BYTES_PER_LINE == 0); memset(hex_viewer->model->file_bytes, 0x0, HEX_VIEWER_BUF_SIZE); bool isOk = true; do { - uint32_t offset = hex_viewer->model->line * HEX_VIEWER_BYTES_PER_ROW; + uint32_t offset = hex_viewer->model->file_offset; if(!stream_seek(hex_viewer->model->stream, offset, true)) { FURI_LOG_E(TAG, "Unable to seek stream"); isOk = false; break; } - hex_viewer->model->read_bytes = stream_read( + hex_viewer->model->file_read_bytes = stream_read( hex_viewer->model->stream, (uint8_t*)hex_viewer->model->file_bytes, HEX_VIEWER_BUF_SIZE); @@ -221,6 +223,8 @@ int32_t hex_viewer_app(void* p) { } } + FURI_LOG_I(TAG, "File selected: %s", furi_string_get_cstr(file_path)); + if(!hex_viewer_open_file(hex_viewer, furi_string_get_cstr(file_path))) break; hex_viewer_read_file(hex_viewer); @@ -231,19 +235,18 @@ int32_t hex_viewer_app(void* p) { break; } else if(input.key == InputKeyUp) { furi_check(furi_mutex_acquire(hex_viewer->mutex, FuriWaitForever) == FuriStatusOk); - if(hex_viewer->model->line > 0) { - hex_viewer->model->line--; - + if(hex_viewer->model->file_offset > 0) { + hex_viewer->model->file_offset -= HEX_VIEWER_BYTES_PER_LINE; if(!hex_viewer_read_file(hex_viewer)) break; } furi_mutex_release(hex_viewer->mutex); } else if(input.key == InputKeyDown) { furi_check(furi_mutex_acquire(hex_viewer->mutex, FuriWaitForever) == FuriStatusOk); - uint32_t cur_pos = hex_viewer->model->line * HEX_VIEWER_BYTES_PER_ROW + - hex_viewer->model->read_bytes; + uint32_t last_byte_on_screen = + hex_viewer->model->file_offset + hex_viewer->model->file_read_bytes; - if(hex_viewer->model->file_size > cur_pos) { - hex_viewer->model->line++; + if(hex_viewer->model->file_size > last_byte_on_screen) { + hex_viewer->model->file_offset += HEX_VIEWER_BYTES_PER_LINE; if(!hex_viewer_read_file(hex_viewer)) break; } furi_mutex_release(hex_viewer->mutex); @@ -256,13 +259,14 @@ int32_t hex_viewer_app(void* p) { buffer = furi_string_alloc(); furi_string_printf( buffer, - "File path: %s\nFile size: %lu bytes", + "File path: %s\nFile size: %lu (0x%lX)", furi_string_get_cstr(file_path), + hex_viewer->model->file_size, hex_viewer->model->file_size); DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); DialogMessage* message = dialog_message_alloc(); - dialog_message_set_header(message, "Hex Viewer", 16, 2, AlignLeft, AlignTop); + dialog_message_set_header(message, "Hex Viewer v1.1", 16, 2, AlignLeft, AlignTop); dialog_message_set_icon(message, &I_hex_10px, 3, 2); dialog_message_set_text( message, furi_string_get_cstr(buffer), 3, 16, AlignLeft, AlignTop); From 0e4cda851c4160146d0ded48dbdfc9d3903aa0aa Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 27 Nov 2022 02:50:15 +0300 Subject: [PATCH 5/6] Update Temp sensor plugin https://github.com/Mywk/FlipperTemperatureSensor --- .../htu21d_temp_sensor/application.fam | 2 +- .../htu21d_temp_sensor/temperature_sensor.c | 161 ++++++++++++++---- 2 files changed, 126 insertions(+), 37 deletions(-) diff --git a/applications/plugins/htu21d_temp_sensor/application.fam b/applications/plugins/htu21d_temp_sensor/application.fam index b3101f42e..0158be2ac 100644 --- a/applications/plugins/htu21d_temp_sensor/application.fam +++ b/applications/plugins/htu21d_temp_sensor/application.fam @@ -1,6 +1,6 @@ App( appid="temperature_sensor", - name="[HTU21D] Temp. Sensor", + name="[HTU/+] Temp. Sensor", apptype=FlipperAppType.EXTERNAL, entry_point="temperature_sensor_app", cdefines=["APP_TEMPERATURE_SENSOR"], diff --git a/applications/plugins/htu21d_temp_sensor/temperature_sensor.c b/applications/plugins/htu21d_temp_sensor/temperature_sensor.c index eb03571fe..b04e40a7d 100644 --- a/applications/plugins/htu21d_temp_sensor/temperature_sensor.c +++ b/applications/plugins/htu21d_temp_sensor/temperature_sensor.c @@ -1,4 +1,4 @@ -/* Flipper App to read the values from a HTU21D Sensor */ +/* Flipper App to read the values from a HTU2XD, SHT2X, SI702X, SI700X, SI701X or AM2320 Sensor */ /* Created by Mywk - https://github.com/Mywk - https://mywk.net */ #include #include @@ -14,16 +14,30 @@ #define TS_DEFAULT_VALUE 0xFFFF -#define HTU21D_ADDRESS (0x40 << 1) +#define TS_AVAILABLE_SENSORS 2 +// HTU2XD, SHT2X, SI702X, SI700X address +#define HTU2XD_SHT2X_SI702X_SI700X_ADDRESS (0x40 << 1) +// SI701X ADDRESS +#define SI701X_ADDRESS (0x41 << 1) + +// HTU2XD, SHT2X, SI702X, SI700X commands #define HTU21D_CMD_TEMPERATURE 0xE3 #define HTU21D_CMD_HUMIDITY 0xE5 +// AM2320 address +#define AM2320_ADDRESS (0x5C << 1) + +// Used for the temperature and humidity buffers #define DATA_BUFFER_SIZE 8 // External I2C BUS #define I2C_BUS &furi_hal_i2c_handle_external +// Typedef enums to make everything easier to read + +typedef enum { TSSCmdNone, TSSCmdTemperature, TSSCmdHumidity } TSSCmdType; + typedef enum { TSSInitializing, TSSNoSensor, @@ -40,11 +54,25 @@ typedef struct { InputEvent input; } TSEvent; +// Possible return values for sensor_cmd +typedef enum { + TSCmdRet_Error, + TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X, + TSCmdRet_SI701X, + TSCmdRet_AM2320, +} TSCmdRet; + +// External NotificationSequence RGB extern const NotificationSequence sequence_blink_red_100; +extern const NotificationSequence sequence_blink_green_100; extern const NotificationSequence sequence_blink_blue_100; +// Current status of the temperature sensor app static TSStatus temperature_sensor_current_status = TSSInitializing; +// We keep track of the last cmd return +static TSCmdRet temperature_sensor_last_cmd_ret = TSCmdRet_Error; + // Temperature and Humidity data buffers, ready to print char ts_data_buffer_temperature_c[DATA_BUFFER_SIZE]; char ts_data_buffer_temperature_f[DATA_BUFFER_SIZE]; @@ -54,46 +82,80 @@ char ts_data_buffer_absolute_humidity[DATA_BUFFER_SIZE]; // // Executes an I2C cmd (trx) // +// +// CRC +// // // true if fetch was successful, false otherwise // -static bool temperature_sensor_cmd(uint8_t cmd, uint8_t* buffer, uint8_t size) { +static TSCmdRet temperature_sensor_cmd(TSSCmdType cmd, uint8_t* buffer) { uint32_t timeout = furi_ms_to_ticks(100); - bool ret = false; + TSCmdRet ret = TSCmdRet_Error; // Aquire I2C and check if device is ready, then release furi_hal_i2c_acquire(I2C_BUS); - if(furi_hal_i2c_is_device_ready(I2C_BUS, HTU21D_ADDRESS, timeout)) { - furi_hal_i2c_release(I2C_BUS); - furi_hal_i2c_acquire(I2C_BUS); - // Transmit given command - ret = furi_hal_i2c_tx(I2C_BUS, HTU21D_ADDRESS, &cmd, 1, timeout); - furi_hal_i2c_release(I2C_BUS); + // Check if HTU2XD, SHT2X, SI702X, SI700X sensor is available + uint8_t isAddress40 = + furi_hal_i2c_is_device_ready(I2C_BUS, HTU2XD_SHT2X_SI702X_SI700X_ADDRESS, timeout); + uint8_t isAddress41 = 0; - if(ret) { - uint32_t wait_ticks = furi_ms_to_ticks(50); - furi_delay_tick(wait_ticks); + // Check if SI701X sensor is available if necessary + if(!isAddress40) isAddress41 = furi_hal_i2c_is_device_ready(I2C_BUS, SI701X_ADDRESS, timeout); - furi_hal_i2c_acquire(I2C_BUS); - // Receive data - ret = furi_hal_i2c_rx(I2C_BUS, HTU21D_ADDRESS, buffer, size, timeout); - furi_hal_i2c_release(I2C_BUS); + if(isAddress40 || isAddress41) { + uint8_t address = isAddress40 ? HTU2XD_SHT2X_SI702X_SI700X_ADDRESS : SI701X_ADDRESS; + + // Better safe than sorry delay + furi_delay_ms(15); + + // Extra delay for the SI70XX + if(isAddress41) furi_delay_ms(50); + + // Transmit either the temperature or the humidity command depending on TSSCmdType + uint8_t c = (cmd == TSSCmdTemperature) ? HTU21D_CMD_TEMPERATURE : HTU21D_CMD_HUMIDITY; + if(furi_hal_i2c_tx(I2C_BUS, address, &c, 1, timeout)) { + // Receive data (2 bytes) + if(furi_hal_i2c_rx(I2C_BUS, address, buffer, 2, timeout + 50)) + ret = isAddress40 ? TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X : TSCmdRet_SI701X; } } else { - furi_hal_i2c_release(I2C_BUS); + // The AM2320 goes to sleep after a period of inactivity, wake it up (check AM2320 datasheet for more info) + furi_hal_i2c_is_device_ready(I2C_BUS, AM2320_ADDRESS, timeout); + furi_delay_ms(30); + + // Check if it's really available + if(furi_hal_i2c_is_device_ready(I2C_BUS, AM2320_ADDRESS, timeout)) { + // {Address, Register, Len} + const uint8_t request[3] = {0x03, 0x00, 0x04}; + + if(furi_hal_i2c_tx(I2C_BUS, AM2320_ADDRESS, request, 3, timeout)) { + // 6 bytes - usually 8 but we currently don't check the CRC + if(furi_hal_i2c_rx(I2C_BUS, (uint8_t)AM2320_ADDRESS, buffer, 6, timeout)) + ret = TSCmdRet_AM2320; + } + } } + furi_hal_i2c_release(I2C_BUS); + + temperature_sensor_last_cmd_ret = ret; return ret; } // // Fetches temperature and humidity from sensor // +// +// temperature in C +// humidity in relative humidity +// // // Temperature and humidity must be preallocated -// Note: CRC is not checked (3rd byte) // +// +// CRC +// // // true if fetch was successful, false otherwise // @@ -102,24 +164,36 @@ static bool temperature_sensor_fetch_data(double* temperature, double* humidity) uint16_t adc_raw; - uint8_t buffer[2] = {0x00}; + uint8_t buffer[DATA_BUFFER_SIZE] = {0x00}; - // Fetch temperature - ret = temperature_sensor_cmd((uint8_t)HTU21D_CMD_TEMPERATURE, buffer, 2); - - if(ret) { + // Check if the sensor is the HTU21D by attempting to fetch the temperature + TSCmdRet cmdRet = temperature_sensor_cmd(TSSCmdTemperature, buffer); + if(cmdRet == TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X || cmdRet == TSCmdRet_SI701X) { // Calculate temperature adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1])); *temperature = (float)(adc_raw * 175.72 / 65536.00) - 46.85; // Fetch humidity - ret = temperature_sensor_cmd((uint8_t)HTU21D_CMD_HUMIDITY, buffer, 2); - - if(ret) { + if(temperature_sensor_cmd(TSSCmdHumidity, buffer)) { // Calculate humidity adc_raw = ((uint16_t)(buffer[0] << 8) | (buffer[1])); *humidity = (float)(adc_raw * 125.0 / 65536.00) - 6.0; + + ret = true; } + } else if(cmdRet == TSCmdRet_AM2320) { + // The AM2320 returns all the data immediately so we just process it all + // Note: CRC isn't currently present in the buffer + + // Temperature + float temp = (((buffer[4] & 0x7F) << 8) + buffer[5]) / 10; + *temperature = ((buffer[4] & 0x80) >> 7) == 1 ? temp * (-1) : temp; + + // Humidity + temp = ((buffer[2] << 8) + buffer[3]) / 10; + *humidity = temp; + + ret = true; } return ret; @@ -133,7 +207,28 @@ static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) { canvas_clear(canvas); canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 2, 10, "HTU21D/Si7021 Sensor"); + + // Update title accordingly (this could be improved by checking the hardware id) + switch(temperature_sensor_last_cmd_ret) { + case TSCmdRet_Error: + canvas_draw_str(canvas, 2, 10, "Temperature Sensor"); + break; + + case TSCmdRet_HTU2XD_SHT2X_SI702X_SI700X: + canvas_draw_str(canvas, 2, 10, "HTU/SHT/SI70 Sensor"); + break; + + case TSCmdRet_SI701X: + canvas_draw_str(canvas, 2, 10, "SI701X Sensor"); + break; + + case TSCmdRet_AM2320: + canvas_draw_str(canvas, 2, 10, "AM2320 Sensor"); + break; + + default: + break; + } canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 2, 62, "Press back to exit."); @@ -165,7 +260,6 @@ static void temperature_sensor_draw_callback(Canvas* canvas, void* ctx) { canvas_draw_str(canvas, 100, 38, "%"); canvas_draw_str(canvas, 68, 48, ts_data_buffer_absolute_humidity); canvas_draw_str(canvas, 100, 48, "g/m3"); - } break; default: break; @@ -199,7 +293,6 @@ static void temperature_sensor_timer_callback(FuriMessageQueue* event_queue) { int32_t temperature_sensor_app(void* p) { UNUSED(p); - furi_hal_power_suppress_charge_enter(); // Declare our variables and assign variables a default value TSEvent tsEvent; bool sensorFound = false; @@ -236,7 +329,6 @@ int32_t temperature_sensor_app(void* p) { if(tsEvent.input.key == InputKeyBack) // We dont check for type here, we can check the type of keypress like: (event.input.type == InputTypeShort) break; - } else if(tsEvent.type == TSEventTypeTick) { // Update sensor data // Fetch data and set the sensor current status accordingly @@ -270,7 +362,6 @@ int32_t temperature_sensor_app(void* p) { snprintf( ts_data_buffer_absolute_humidity, DATA_BUFFER_SIZE, "%.2f", abs_humidity); } - } else { // Reset our variables to their default values celsius = fahrenheit = rel_humidity = abs_humidity = TS_DEFAULT_VALUE; @@ -280,11 +371,9 @@ int32_t temperature_sensor_app(void* p) { } } - uint32_t wait_ticks = furi_ms_to_ticks(!sensorFound ? 100 : 500); - furi_delay_tick(wait_ticks); + furi_delay_ms(!sensorFound ? 100 : 500); } - furi_hal_power_suppress_charge_exit(); // Dobby is freee (free our variables, Flipper will crash if we don't do this!) furi_timer_free(timer); gui_remove_view_port(gui, view_port); @@ -295,4 +384,4 @@ int32_t temperature_sensor_app(void* p) { furi_record_close(RECORD_GUI); return 0; -} +} \ No newline at end of file From 7ed56fca542e45bac66e624ed0dea82e5d2a2323 Mon Sep 17 00:00:00 2001 From: MX <10697207+xMasterX@users.noreply.github.com> Date: Sun, 27 Nov 2022 07:12:34 +0300 Subject: [PATCH 6/6] Update changelog and readme --- CHANGELOG.md | 32 ++++++-------------------------- ReadMe.md | 4 ++-- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3ed1bbee..0757f653b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,30 +1,10 @@ ### New changes -* Plugins: SubGHz Bruteforcer -> Add support for Ansonic 12bit protocol (FM238) -* Plugins: Fix DTMF Dolphin -> Add forgotten scene and menu item -* Plugins: Update DTMF Dolphin [(by litui)](https://github.com/litui/dtmf_dolphin) -* Plugins: Update TOTP [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) -* Plugins: iButton Fuzzer and RFID Fuzzer improvements -* Plugins: i2c tools fix name display -* Plugins: Add 3 new plugins BlackJack, Solitaire [(by teeebor)](https://github.com/teeebor/flipper_games) and HEX Viewer [(by QtRoS)](https://github.com/QtRoS/flipperzero-firmware) -* Plugins -> PR: Wifi marauder BT menus option (by @rf-bandit | PR #164) -* Plugins -> PR: Update i2c tools (New UI) (by @NaejEL | PR #171) -* Plugins -> PR: Fix htu21d falsely reading temp as humidity (by @GottZ | PR #175) -* SubGHz -> PR: GUI Fix - Allow setting RSSI trigger to beggining (by @TQMatvey | PR #180) -* SubGHz: Remove not widely used frequency from hopper -* SubGHz: Fix starline encoder -* SubGHz: Frequency Analyzer -> Save last trigger level -* SubGHz: Speedup subghz launch from favourites -* SubGHz: Add new freqs and modulation to user config -* Infrared: Update universal remote assets (by @Amec0e) -* CI/CD: Improvements, dev builds (can be found in this telegram channel -> https://t.me/kotnehleb) -* Power -> PR: Show battery percentile while charging (by @TQMatvey | PR #178) -* Docs -> PR: Some updates (by @lucemans | PR #169 and #170) -* CLI -> PR: Update cli_commands.c To add `src` / `source` command for people exploring cli (by @PharoahCoder | PR #176) -* OFW: Fix U2F HID vulnerability -* OFW: Core: thread allocation shortcut -* OFW: WS: add protocol GT-WT02 -* OFW: SubGhz: add protocol "Ansonic" -* OFW: SubGhz: add protocol Nice_Flo 20bit +* SubGHz: Fix counter can go higher than 16bits in protocols - Keeloq, SL, Came Atomo, Nice Flor S +* SubGHz -> Plugin: WS - Add protocol Auriol HG0601A (by @LY2NEO) [(Details)](https://github.com/DarkFlippers/unleashed-firmware/issues/184) +* NFC -> PR: Assets - mf classic dict update - Possible keys for Omsk transport cards (by @vadrozh | PR #181) +* BadUSB -> PR: Keyboard layouts: Slovenian (si) / Croatian (hr), Bosnian (ba) (Latin, Bosnia and Herzegovina) (by @StellarStoic | PR #187) +* Plugins: Update Temperature Sensor Plugin - HTU2xD, SHT2x, SI702x, SI700x, SI701x, AM2320 [(by Mywk)](https://github.com/Mywk/FlipperTemperatureSensor) +* Plugins: Update HEX Viewer [(by QtRoS)](https://github.com/QtRoS/flipper-zero-hex-viewer) #### [🎲 Download latest extra apps pack](https://download-directory.github.io/?url=https://github.com/xMasterX/unleashed-extra-pack/tree/main/apps) diff --git a/ReadMe.md b/ReadMe.md index f29e7136e..136f67947 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -98,14 +98,14 @@ Also check changelog in releases for latest updates! - **TOTP (Authenticator)** [(by akopachov)](https://github.com/akopachov/flipper-zero_authenticator) - GPS [(by ezod)](https://github.com/ezod/flipperzero-gps) works with module `NMEA 0183` via UART (13TX, 14RX, GND pins on Flipper) - i2c Tools [(by NaejEL)](https://github.com/NaejEL/flipperzero-i2ctools) - C0 -> SCL / C1 -> SDA / GND -> GND | 3v3 logic levels only! -- Temperature Sensor Plugin - HTU21D / SI7021 [(by Mywk)](https://github.com/Mywk/FlipperTemperatureSensor) - [How to Connect](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/plugins/htu21d_temp_sensor/Readme.md) +- Temperature Sensor Plugin - HTU2xD, SHT2x, SI702x, SI700x, SI701x, AM2320 [(by Mywk)](https://github.com/Mywk/FlipperTemperatureSensor) - [How to Connect](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/applications/plugins/htu21d_temp_sensor/Readme.md) - HC-SR04 Distance sensor - Ported and modified by @xMasterX [(original by Sanqui)](https://github.com/Sanqui/flipperzero-firmware/tree/hc_sr04) - How to connect -> (5V -> VCC) / (GND -> GND) / (13|TX -> Trig) / (14|RX -> Echo) - Morse Code [(by wh00hw)](https://github.com/wh00hw/MorseCodeFAP) - AM2320/AM2321 Temp. Sensor plugin [(by xMasterX)](https://github.com/xMasterX/AM2320_Flipper_Plugin) - [How to Connect](https://github.com/xMasterX/AM2320_Flipper_Plugin) - DHT11/22 Temp. Sensor Monitor [(by quen0n)](https://github.com/quen0n/FipperZero-DHT-Monitor) - How to connect -> (5V -> VCC) / (GND -> GND) / (Selected Pin -> out) - BH1750 - Lightmeter [(by oleksiikutuzov)](https://github.com/oleksiikutuzov/flipperzero-lightmeter) - iButton Fuzzer [(by xMasterX)](https://github.com/xMasterX/ibutton-fuzzer) -- HEX Viewer [(by QtRoS)](https://github.com/QtRoS/flipperzero-firmware) +- HEX Viewer [(by QtRoS)](https://github.com/QtRoS/flipper-zero-hex-viewer) Games: - DOOM (fixed) [(by p4nic4ttack)](https://github.com/p4nic4ttack/doom-flipper-zero/)