Merge remote-tracking branch 'origin/dev' into nfcf

This commit is contained in:
nullableVoidPtr
2022-12-11 11:46:44 +11:00
26 changed files with 292 additions and 129 deletions

View File

@@ -39,7 +39,7 @@ jobs:
fi fi
- name: 'Checkout code' - name: 'Checkout code'
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}

View File

@@ -24,7 +24,7 @@ jobs:
fi fi
- name: 'Checkout code' - name: 'Checkout code'
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
@@ -35,6 +35,7 @@ jobs:
mkdir artifacts mkdir artifacts
- name: 'Get commit details' - name: 'Get commit details'
id: names
run: | run: |
if [[ ${{ github.event_name }} == 'pull_request' ]]; then if [[ ${{ github.event_name }} == 'pull_request' ]]; then
TYPE="pull" TYPE="pull"
@@ -45,14 +46,6 @@ jobs:
fi fi
python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE"
- name: 'Generate suffixes for comment'
id: names
run: |
echo "::set-output name=branch_name::${BRANCH_NAME}"
echo "::set-output name=commit_sha::${COMMIT_SHA}"
echo "::set-output name=default_target::${DEFAULT_TARGET}"
echo "::set-output name=suffix::${SUFFIX}"
- name: 'Bundle scripts' - name: 'Bundle scripts'
if: ${{ !github.event.pull_request.head.repo.fork }} if: ${{ !github.event.pull_request.head.repo.fork }}
run: | run: |
@@ -143,7 +136,7 @@ jobs:
fi fi
- name: 'Checkout code' - name: 'Checkout code'
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true

View File

@@ -20,7 +20,7 @@ jobs:
fi fi
- name: 'Checkout code' - name: 'Checkout code'
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
@@ -36,12 +36,12 @@ jobs:
BRANCHES=$(git branch -r --contains "$SUBMODULE_HASH"); BRANCHES=$(git branch -r --contains "$SUBMODULE_HASH");
COMMITS_IN_BRANCH="$(git rev-list --count dev)"; COMMITS_IN_BRANCH="$(git rev-list --count dev)";
if [ $COMMITS_IN_BRANCH -lt $SUB_COMMITS_MIN ]; then if [ $COMMITS_IN_BRANCH -lt $SUB_COMMITS_MIN ]; then
echo "::set-output name=fails::error"; echo "name=fails::error" >> $GITHUB_OUTPUT
echo "::error::Error: Too low commits in $SUB_BRANCH of submodule $SUB_PATH: $COMMITS_IN_BRANCH(expected $SUB_COMMITS_MIN+)"; echo "::error::Error: Too low commits in $SUB_BRANCH of submodule $SUB_PATH: $COMMITS_IN_BRANCH(expected $SUB_COMMITS_MIN+)";
exit 1; exit 1;
fi fi
if ! grep -q "/$SUB_BRANCH" <<< "$BRANCHES"; then if ! grep -q "/$SUB_BRANCH" <<< "$BRANCHES"; then
echo "::set-output name=fails::error"; echo "name=fails::error" >> $GITHUB_OUTPUT
echo "::error::Error: Submodule $SUB_PATH is not on branch $SUB_BRANCH"; echo "::error::Error: Submodule $SUB_PATH is not on branch $SUB_BRANCH";
exit 1; exit 1;
fi fi

View File

@@ -23,7 +23,7 @@ jobs:
fi fi
- name: 'Checkout code' - name: 'Checkout code'
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}

View File

@@ -20,7 +20,7 @@ jobs:
fi fi
- name: 'Checkout code' - name: 'Checkout code'
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}

41
.github/workflows/merge_report.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: 'Check FL ticket in PR name'
on:
push:
branches:
- dev
jobs:
merge_report:
runs-on: [self-hosted,FlipperZeroShell]
steps:
- name: 'Decontaminate previous build leftovers'
run: |
if [ -d .git ]; then
git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)"
fi
- name: 'Checkout code'
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: 'Get commit details'
run: |
if [[ ${{ github.event_name }} == 'pull_request' ]]; then
TYPE="pull"
elif [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
TYPE="tag"
else
TYPE="other"
fi
python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE"
- name: 'Check ticket and report'
run: |
FBT_TOOLCHAIN_PATH=/runner/_work source scripts/toolchain/fbtenv.sh
python3 -m pip install slack_sdk
python3 scripts/merge_report_qa.py \
${{ secrets.QA_REPORT_SLACK_TOKEN }} \
${{ secrets.QA_REPORT_SLACK_CHANNEL }}

View File

@@ -25,12 +25,13 @@ jobs:
fi fi
- name: 'Checkout code' - name: 'Checkout code'
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: 'Get commit details' - name: 'Get commit details'
id: names
run: | run: |
if [[ ${{ github.event_name }} == 'pull_request' ]]; then if [[ ${{ github.event_name }} == 'pull_request' ]]; then
TYPE="pull" TYPE="pull"
@@ -41,15 +42,6 @@ jobs:
fi fi
python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE" python3 scripts/get_env.py "--event_file=${{ github.event_path }}" "--type=$TYPE"
- name: 'Generate suffixes for comment'
if: ${{ !github.event.pull_request.head.repo.fork && github.event.pull_request }}
id: names
run: |
echo "::set-output name=branch_name::${BRANCH_NAME}"
echo "::set-output name=commit_sha::${COMMIT_SHA}"
echo "::set-output name=default_target::${DEFAULT_TARGET}"
echo "::set-output name=suffix::${SUFFIX}"
- name: 'Make reports directory' - name: 'Make reports directory'
run: | run: |
rm -rf reports/ rm -rf reports/

View File

@@ -11,8 +11,14 @@ jobs:
run_units_on_test_bench: run_units_on_test_bench:
runs-on: [self-hosted, FlipperZeroTest] runs-on: [self-hosted, FlipperZeroTest]
steps: steps:
- name: 'Decontaminate previous build leftovers'
run: |
if [ -d .git ]; then
git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)"
fi
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}

View File

@@ -6,7 +6,7 @@
#include <lib/nfc/helpers/mf_classic_dict.h> #include <lib/nfc/helpers/mf_classic_dict.h>
#include <lib/digital_signal/digital_signal.h> #include <lib/digital_signal/digital_signal.h>
#include <lib/nfc/nfc_device.h> #include <lib/nfc/nfc_device.h>
#include <applications/main/nfc/helpers/nfc_generators.h> #include <lib/nfc/helpers/nfc_generators.h>
#include <lib/flipper_format/flipper_format_i.h> #include <lib/flipper_format/flipper_format_i.h>
#include <lib/toolbox/stream/file_stream.h> #include <lib/toolbox/stream/file_stream.h>
@@ -102,7 +102,10 @@ static bool nfc_test_digital_signal_test_encode(
do { do {
// Read test data // Read test data
if(!nfc_test_read_signal_from_file(file_name)) break; if(!nfc_test_read_signal_from_file(file_name)) {
FURI_LOG_E(TAG, "Failed to read signal from file");
break;
}
// Encode signal // Encode signal
FURI_CRITICAL_ENTER(); FURI_CRITICAL_ENTER();

View File

@@ -27,6 +27,7 @@
#include <lib/nfc/nfc_device.h> #include <lib/nfc/nfc_device.h>
#include <lib/nfc/helpers/mf_classic_dict.h> #include <lib/nfc/helpers/mf_classic_dict.h>
#include <lib/nfc/parsers/nfc_supported_card.h> #include <lib/nfc/parsers/nfc_supported_card.h>
#include <lib/nfc/helpers/nfc_generators.h>
#include "views/dict_attack.h" #include "views/dict_attack.h"
#include "views/detect_reader.h" #include "views/detect_reader.h"
@@ -63,9 +64,6 @@ typedef enum {
NfcRpcStateEmulated, NfcRpcStateEmulated,
} NfcRpcState; } NfcRpcState;
// Forward declaration due to circular dependency
typedef struct NfcGenerator NfcGenerator;
struct Nfc { struct Nfc {
NfcWorker* worker; NfcWorker* worker;
ViewDispatcher* view_dispatcher; ViewDispatcher* view_dispatcher;

View File

@@ -1,5 +1,5 @@
#include "../nfc_i.h" #include "../nfc_i.h"
#include "../helpers/nfc_generators.h" #include "lib/nfc/helpers/nfc_generators.h"
void nfc_scene_generate_info_dialog_callback(DialogExResult result, void* context) { void nfc_scene_generate_info_dialog_callback(DialogExResult result, void* context) {
Nfc* nfc = context; Nfc* nfc = context;
@@ -39,7 +39,12 @@ bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultRight) { if(event.event == DialogExResultRight) {
scene_manager_next_scene(nfc->scene_manager, nfc->generator->next_scene); // Switch either to NfcSceneMfClassicMenu or NfcSceneMfUltralightMenu
if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareClassic) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicMenu);
} else if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightMenu);
}
consumed = true; consumed = true;
} }
} }

View File

@@ -1,5 +1,5 @@
#include "../nfc_i.h" #include "../nfc_i.h"
#include "../helpers/nfc_generators.h" #include "lib/nfc/helpers/nfc_generators.h"
enum SubmenuIndex { enum SubmenuIndex {
SubmenuIndexNFCA4, SubmenuIndexNFCA4,

View File

@@ -8,7 +8,7 @@
#include <m-array.h> #include <m-array.h>
#define FRAME_HEIGHT 12 #define FRAME_HEIGHT 12
#define MAX_LEN_PX 100 #define MAX_LEN_PX 111
#define MENU_ITEMS 4u #define MENU_ITEMS 4u
#define UNLOCK_CNT 3 #define UNLOCK_CNT 3
@@ -186,7 +186,7 @@ void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0); size_t idx = CLAMP((uint16_t)(i + model->list_offset), model->history_item, 0);
item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx); item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx);
furi_string_set(str_buff, item_menu->item_str); furi_string_set(str_buff, item_menu->item_str);
elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 7 : MAX_LEN_PX);
if(model->idx == idx) { if(model->idx == idx) {
subghz_view_receiver_draw_frame(canvas, i, scrollbar); subghz_view_receiver_draw_frame(canvas, i, scrollbar);
} else { } else {

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -99,6 +99,17 @@ bool ws_block_generic_serialize(
break; break;
} }
//DATE AGE set
FuriHalRtcDateTime curr_dt;
furi_hal_rtc_get_datetime(&curr_dt);
uint32_t curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
temp_data = curr_ts;
if(!flipper_format_write_uint32(flipper_format, "Ts", &temp_data, 1)) {
FURI_LOG_E(TAG, "Unable to add timestamp");
break;
}
temp_data = instance->channel; temp_data = instance->channel;
if(!flipper_format_write_uint32(flipper_format, "Ch", &temp_data, 1)) { if(!flipper_format_write_uint32(flipper_format, "Ch", &temp_data, 1)) {
FURI_LOG_E(TAG, "Unable to add Channel"); FURI_LOG_E(TAG, "Unable to add Channel");
@@ -168,6 +179,12 @@ bool ws_block_generic_deserialize(WSBlockGeneric* instance, FlipperFormat* flipp
} }
instance->humidity = (uint8_t)temp_data; instance->humidity = (uint8_t)temp_data;
if(!flipper_format_read_uint32(flipper_format, "Ts", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing timestamp");
break;
}
instance->timestamp = (uint32_t)temp_data;
if(!flipper_format_read_uint32(flipper_format, "Ch", (uint32_t*)&temp_data, 1)) { if(!flipper_format_read_uint32(flipper_format, "Ch", (uint32_t*)&temp_data, 1)) {
FURI_LOG_E(TAG, "Missing Channel"); FURI_LOG_E(TAG, "Missing Channel");
break; break;

View File

@@ -29,6 +29,7 @@ struct WSBlockGeneric {
uint8_t data_count_bit; uint8_t data_count_bit;
uint8_t battery_low; uint8_t battery_low;
uint8_t humidity; uint8_t humidity;
uint32_t timestamp;
uint8_t channel; uint8_t channel;
uint8_t btn; uint8_t btn;
float temp; float temp;

View File

@@ -8,7 +8,7 @@
#include <m-array.h> #include <m-array.h>
#define FRAME_HEIGHT 12 #define FRAME_HEIGHT 12
#define MAX_LEN_PX 100 #define MAX_LEN_PX 112
#define MENU_ITEMS 4u #define MENU_ITEMS 4u
#define UNLOCK_CNT 3 #define UNLOCK_CNT 3
@@ -189,7 +189,7 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) {
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
} }
canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]); canvas_draw_icon(canvas, 4, 2 + i * FRAME_HEIGHT, ReceiverItemIcons[item_menu->type]);
canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buff)); canvas_draw_str(canvas, 14, 9 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buff));
furi_string_reset(str_buff); furi_string_reset(str_buff);
} }
if(scrollbar) { if(scrollbar) {

View File

@@ -9,9 +9,11 @@
struct WSReceiverInfo { struct WSReceiverInfo {
View* view; View* view;
FuriTimer* timer;
}; };
typedef struct { typedef struct {
uint32_t curr_ts;
FuriString* protocol_name; FuriString* protocol_name;
WSBlockGeneric* generic; WSBlockGeneric* generic;
} WSReceiverInfoModel; } WSReceiverInfoModel;
@@ -28,6 +30,10 @@ void ws_view_receiver_info_update(WSReceiverInfo* ws_receiver_info, FlipperForma
flipper_format_read_string(fff, "Protocol", model->protocol_name); flipper_format_read_string(fff, "Protocol", model->protocol_name);
ws_block_generic_deserialize(model->generic, fff); ws_block_generic_deserialize(model->generic, fff);
FuriHalRtcDateTime curr_dt;
furi_hal_rtc_get_datetime(&curr_dt);
model->curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
}, },
true); true);
} }
@@ -44,46 +50,76 @@ void ws_view_receiver_info_draw(Canvas* canvas, WSReceiverInfoModel* model) {
"%s %db", "%s %db",
furi_string_get_cstr(model->protocol_name), furi_string_get_cstr(model->protocol_name),
model->generic->data_count_bit); model->generic->data_count_bit);
canvas_draw_str(canvas, 5, 8, buffer); canvas_draw_str(canvas, 0, 8, buffer);
if(model->generic->channel != WS_NO_CHANNEL) { if(model->generic->channel != WS_NO_CHANNEL) {
snprintf(buffer, sizeof(buffer), "Ch: %01d", model->generic->channel); snprintf(buffer, sizeof(buffer), "Ch: %01d", model->generic->channel);
canvas_draw_str(canvas, 105, 8, buffer); canvas_draw_str(canvas, 106, 8, buffer);
} }
if(model->generic->id != WS_NO_ID) { if(model->generic->id != WS_NO_ID) {
snprintf(buffer, sizeof(buffer), "Sn: 0x%02lX", model->generic->id); snprintf(buffer, sizeof(buffer), "Sn: 0x%02lX", model->generic->id);
canvas_draw_str(canvas, 5, 20, buffer); canvas_draw_str(canvas, 0, 20, buffer);
} }
if(model->generic->btn != WS_NO_BTN) { if(model->generic->btn != WS_NO_BTN) {
snprintf(buffer, sizeof(buffer), "Btn: %01d", model->generic->btn); snprintf(buffer, sizeof(buffer), "Btn: %01d", model->generic->btn);
canvas_draw_str(canvas, 62, 20, buffer); canvas_draw_str(canvas, 57, 20, buffer);
} }
if(model->generic->battery_low != WS_NO_BATT) { if(model->generic->battery_low != WS_NO_BATT) {
snprintf( snprintf(
buffer, sizeof(buffer), "Batt: %s", (!model->generic->battery_low ? "ok" : "low")); buffer, sizeof(buffer), "Batt: %s", (!model->generic->battery_low ? "ok" : "low"));
canvas_draw_str(canvas, 90, 20, buffer); canvas_draw_str_aligned(canvas, 126, 17, AlignRight, AlignCenter, buffer);
} }
snprintf(buffer, sizeof(buffer), "Data: 0x%llX", model->generic->data); snprintf(buffer, sizeof(buffer), "Data: 0x%llX", model->generic->data);
canvas_draw_str(canvas, 5, 32, buffer); canvas_draw_str(canvas, 0, 32, buffer);
elements_bold_rounded_frame(canvas, 2, 37, 123, 25); elements_bold_rounded_frame(canvas, 0, 38, 127, 25);
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
if(model->generic->temp != WS_NO_TEMPERATURE) { if(model->generic->temp != WS_NO_TEMPERATURE) {
canvas_draw_icon(canvas, 18, 42, &I_Therm_7x16); canvas_draw_icon(canvas, 6, 43, &I_Therm_7x16);
snprintf(buffer, sizeof(buffer), "%3.1f C", (double)model->generic->temp); snprintf(buffer, sizeof(buffer), "%3.1f C", (double)model->generic->temp);
canvas_draw_str_aligned(canvas, 63, 46, AlignRight, AlignTop, buffer); canvas_draw_str_aligned(canvas, 47, 47, AlignRight, AlignTop, buffer);
canvas_draw_circle(canvas, 55, 45, 1); canvas_draw_circle(canvas, 38, 46, 1);
} }
if(model->generic->humidity != WS_NO_HUMIDITY) { if(model->generic->humidity != WS_NO_HUMIDITY) {
canvas_draw_icon(canvas, 75, 42, &I_Humid_10x15); canvas_draw_icon(canvas, 53, 44, &I_Humid_8x13);
snprintf(buffer, sizeof(buffer), "%d%%", model->generic->humidity); snprintf(buffer, sizeof(buffer), "%d%%", model->generic->humidity);
canvas_draw_str(canvas, 91, 54, buffer); canvas_draw_str(canvas, 64, 55, buffer);
}
if((int)model->generic->timestamp > 0 && model->curr_ts) {
int ts_diff = (int)model->curr_ts - (int)model->generic->timestamp;
canvas_draw_icon(canvas, 91, 46, &I_Timer_11x11);
if(ts_diff > 60) {
int tmp_sec = ts_diff;
int cnt_min = 1;
for(int i = 1; tmp_sec > 60; i++) {
tmp_sec = tmp_sec - 60;
cnt_min = i;
}
if(model->curr_ts % 2 == 0) {
canvas_draw_str_aligned(canvas, 105, 51, AlignLeft, AlignCenter, "Old");
} else {
if(cnt_min >= 59) {
canvas_draw_str_aligned(canvas, 105, 51, AlignLeft, AlignCenter, "Old");
} else {
snprintf(buffer, sizeof(buffer), "%dm", cnt_min);
canvas_draw_str_aligned(canvas, 114, 51, AlignCenter, AlignCenter, buffer);
}
}
} else {
snprintf(buffer, sizeof(buffer), "%d", ts_diff);
canvas_draw_str_aligned(canvas, 112, 51, AlignCenter, AlignCenter, buffer);
}
} }
} }
@@ -98,14 +134,19 @@ bool ws_view_receiver_info_input(InputEvent* event, void* context) {
return true; return true;
} }
void ws_view_receiver_info_enter(void* context) { static void ws_view_receiver_info_enter(void* context) {
furi_assert(context);
}
void ws_view_receiver_info_exit(void* context) {
furi_assert(context); furi_assert(context);
WSReceiverInfo* ws_receiver_info = context; WSReceiverInfo* ws_receiver_info = context;
furi_timer_start(ws_receiver_info->timer, 1000);
}
static void ws_view_receiver_info_exit(void* context) {
furi_assert(context);
WSReceiverInfo* ws_receiver_info = context;
furi_timer_stop(ws_receiver_info->timer);
with_view_model( with_view_model(
ws_receiver_info->view, ws_receiver_info->view,
WSReceiverInfoModel * model, WSReceiverInfoModel * model,
@@ -113,6 +154,20 @@ void ws_view_receiver_info_exit(void* context) {
false); false);
} }
static void ws_view_receiver_info_timer(void* context) {
WSReceiverInfo* ws_receiver_info = context;
// Force redraw
with_view_model(
ws_receiver_info->view,
WSReceiverInfoModel * model,
{
FuriHalRtcDateTime curr_dt;
furi_hal_rtc_get_datetime(&curr_dt);
model->curr_ts = furi_hal_rtc_datetime_to_timestamp(&curr_dt);
},
true);
}
WSReceiverInfo* ws_view_receiver_info_alloc() { WSReceiverInfo* ws_view_receiver_info_alloc() {
WSReceiverInfo* ws_receiver_info = malloc(sizeof(WSReceiverInfo)); WSReceiverInfo* ws_receiver_info = malloc(sizeof(WSReceiverInfo));
@@ -135,12 +190,17 @@ WSReceiverInfo* ws_view_receiver_info_alloc() {
}, },
true); true);
ws_receiver_info->timer =
furi_timer_alloc(ws_view_receiver_info_timer, FuriTimerTypePeriodic, ws_receiver_info);
return ws_receiver_info; return ws_receiver_info;
} }
void ws_view_receiver_info_free(WSReceiverInfo* ws_receiver_info) { void ws_view_receiver_info_free(WSReceiverInfo* ws_receiver_info) {
furi_assert(ws_receiver_info); furi_assert(ws_receiver_info);
furi_timer_free(ws_receiver_info->timer);
with_view_model( with_view_model(
ws_receiver_info->view, ws_receiver_info->view,
WSReceiverInfoModel * model, WSReceiverInfoModel * model,

View File

@@ -30,7 +30,7 @@ struct ButtonMenu {
typedef struct { typedef struct {
ButtonMenuItemArray_t items; ButtonMenuItemArray_t items;
uint8_t position; size_t position;
const char* header; const char* header;
} ButtonMenuModel; } ButtonMenuModel;
@@ -102,11 +102,9 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) {
ButtonMenuModel* model = (ButtonMenuModel*)_model; ButtonMenuModel* model = (ButtonMenuModel*)_model;
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
uint8_t item_position = 0; const size_t active_screen = model->position / BUTTONS_PER_SCREEN;
int8_t active_screen = model->position / BUTTONS_PER_SCREEN; const size_t items_size = ButtonMenuItemArray_size(model->items);
size_t items_size = ButtonMenuItemArray_size(model->items); const size_t max_screen = items_size ? (items_size - 1) / BUTTONS_PER_SCREEN : 0;
int8_t max_screen = ((int16_t)items_size - 1) / BUTTONS_PER_SCREEN;
ButtonMenuItemArray_it_t it;
if(active_screen > 0) { if(active_screen > 0) {
canvas_draw_icon(canvas, 28, 1, &I_InfraredArrowUp_4x8); canvas_draw_icon(canvas, 28, 1, &I_InfraredArrowUp_4x8);
@@ -125,6 +123,9 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) {
furi_string_free(disp_str); furi_string_free(disp_str);
} }
size_t item_position = 0;
ButtonMenuItemArray_it_t it;
for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it); for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it);
ButtonMenuItemArray_next(it), ++item_position) { ButtonMenuItemArray_next(it), ++item_position) {
if(active_screen == (item_position / BUTTONS_PER_SCREEN)) { if(active_screen == (item_position / BUTTONS_PER_SCREEN)) {
@@ -195,14 +196,14 @@ static void button_menu_process_ok(ButtonMenu* button_menu, InputType type) {
if(item) { if(item) {
if(item->type == ButtonMenuItemTypeControl) { if(item->type == ButtonMenuItemTypeControl) {
if(type == InputTypeShort) { if(type == InputTypeShort) {
if(item && item->callback) { if(item->callback) {
item->callback(item->callback_context, item->index, type); item->callback(item->callback_context, item->index, type);
} }
} }
} }
if(item->type == ButtonMenuItemTypeCommon) { if(item->type == ButtonMenuItemTypeCommon) {
if((type == InputTypePress) || (type == InputTypeRelease)) { if((type == InputTypePress) || (type == InputTypeRelease)) {
if(item && item->callback) { if(item->callback) {
item->callback(item->callback_context, item->index, type); item->callback(item->callback_context, item->index, type);
} }
} }
@@ -341,7 +342,7 @@ void button_menu_set_selected_item(ButtonMenu* button_menu, uint32_t index) {
button_menu->view, button_menu->view,
ButtonMenuModel * model, ButtonMenuModel * model,
{ {
uint8_t item_position = 0; size_t item_position = 0;
ButtonMenuItemArray_it_t it; ButtonMenuItemArray_it_t it;
for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it); for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it);
ButtonMenuItemArray_next(it), ++item_position) { ButtonMenuItemArray_next(it), ++item_position) {

View File

@@ -20,8 +20,8 @@ ARRAY_DEF(SubmenuItemArray, SubmenuItem, M_POD_OPLIST);
typedef struct { typedef struct {
SubmenuItemArray_t items; SubmenuItemArray_t items;
const char* header; const char* header;
uint8_t position; size_t position;
uint8_t window_position; size_t window_position;
} SubmenuModel; } SubmenuModel;
static void submenu_process_up(Submenu* submenu); static void submenu_process_up(Submenu* submenu);
@@ -36,19 +36,19 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) {
canvas_clear(canvas); canvas_clear(canvas);
uint8_t position = 0;
SubmenuItemArray_it_t it;
if(model->header) { if(model->header) {
canvas_set_font(canvas, FontPrimary); canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 4, 11, model->header); canvas_draw_str(canvas, 4, 11, model->header);
} }
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
size_t position = 0;
SubmenuItemArray_it_t it;
for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it); for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it);
SubmenuItemArray_next(it)) { SubmenuItemArray_next(it)) {
uint8_t item_position = position - model->window_position; const size_t item_position = position - model->window_position;
uint8_t items_on_screen = model->header ? 3 : 4; const size_t items_on_screen = model->header ? 3 : 4;
uint8_t y_offset = model->header ? 16 : 0; uint8_t y_offset = model->header ? 16 : 0;
if(item_position < items_on_screen) { if(item_position < items_on_screen) {
@@ -198,7 +198,7 @@ void submenu_set_selected_item(Submenu* submenu, uint32_t index) {
submenu->view, submenu->view,
SubmenuModel * model, SubmenuModel * model,
{ {
uint32_t position = 0; size_t position = 0;
SubmenuItemArray_it_t it; SubmenuItemArray_it_t it;
for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it); for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it);
SubmenuItemArray_next(it)) { SubmenuItemArray_next(it)) {
@@ -208,7 +208,9 @@ void submenu_set_selected_item(Submenu* submenu, uint32_t index) {
position++; position++;
} }
if(position >= SubmenuItemArray_size(model->items)) { const size_t items_size = SubmenuItemArray_size(model->items);
if(position >= items_size) {
position = 0; position = 0;
} }
@@ -219,16 +221,12 @@ void submenu_set_selected_item(Submenu* submenu, uint32_t index) {
model->window_position -= 1; model->window_position -= 1;
} }
uint8_t items_on_screen = model->header ? 3 : 4; const size_t items_on_screen = model->header ? 3 : 4;
if(SubmenuItemArray_size(model->items) <= items_on_screen) { if(items_size <= items_on_screen) {
model->window_position = 0; model->window_position = 0;
} else { } else if(model->window_position >= items_size - items_on_screen) {
if(model->window_position >= model->window_position = items_size - items_on_screen;
(SubmenuItemArray_size(model->items) - items_on_screen)) {
model->window_position =
(SubmenuItemArray_size(model->items) - items_on_screen);
}
} }
}, },
true); true);
@@ -239,16 +237,18 @@ void submenu_process_up(Submenu* submenu) {
submenu->view, submenu->view,
SubmenuModel * model, SubmenuModel * model,
{ {
uint8_t items_on_screen = model->header ? 3 : 4; const size_t items_on_screen = model->header ? 3 : 4;
const size_t items_size = SubmenuItemArray_size(model->items);
if(model->position > 0) { if(model->position > 0) {
model->position--; model->position--;
if(((model->position - model->window_position) < 1) && if((model->position - model->window_position < 1) &&
model->window_position > 0) { (model->window_position > 0)) {
model->window_position--; model->window_position--;
} }
} else { } else {
model->position = SubmenuItemArray_size(model->items) - 1; model->position = items_size - 1;
if(model->position > (items_on_screen - 1)) { if(model->position > items_on_screen - 1) {
model->window_position = model->position - (items_on_screen - 1); model->window_position = model->position - (items_on_screen - 1);
} }
} }
@@ -261,12 +261,13 @@ void submenu_process_down(Submenu* submenu) {
submenu->view, submenu->view,
SubmenuModel * model, SubmenuModel * model,
{ {
uint8_t items_on_screen = model->header ? 3 : 4; const size_t items_on_screen = model->header ? 3 : 4;
if(model->position < (SubmenuItemArray_size(model->items) - 1)) { const size_t items_size = SubmenuItemArray_size(model->items);
if(model->position < items_size - 1) {
model->position++; model->position++;
if((model->position - model->window_position) > (items_on_screen - 2) && if((model->position - model->window_position > items_on_screen - 2) &&
model->window_position < (model->window_position < items_size - items_on_screen)) {
(SubmenuItemArray_size(model->items) - items_on_screen)) {
model->window_position++; model->window_position++;
} }
} else { } else {
@@ -284,7 +285,8 @@ void submenu_process_ok(Submenu* submenu) {
submenu->view, submenu->view,
SubmenuModel * model, SubmenuModel * model,
{ {
if(model->position < (SubmenuItemArray_size(model->items))) { const size_t items_size = SubmenuItemArray_size(model->items);
if(model->position < items_size) {
item = SubmenuItemArray_get(model->items, model->position); item = SubmenuItemArray_get(model->items, model->position);
} }
}, },

View File

@@ -81,7 +81,6 @@ FIRMWARE_APPS = {
"basic_services", "basic_services",
"updater_app", "updater_app",
"unit_tests", "unit_tests",
"nfc",
], ],
} }

View File

@@ -376,103 +376,86 @@ static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceData* data) {
static const NfcGenerator mf_ul_generator = { static const NfcGenerator mf_ul_generator = {
.name = "Mifare Ultralight", .name = "Mifare Ultralight",
.generator_func = nfc_generate_mf_ul_orig, .generator_func = nfc_generate_mf_ul_orig,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator mf_ul_11_generator = { static const NfcGenerator mf_ul_11_generator = {
.name = "Mifare Ultralight EV1 11", .name = "Mifare Ultralight EV1 11",
.generator_func = nfc_generate_mf_ul_11, .generator_func = nfc_generate_mf_ul_11,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator mf_ul_h11_generator = { static const NfcGenerator mf_ul_h11_generator = {
.name = "Mifare Ultralight EV1 H11", .name = "Mifare Ultralight EV1 H11",
.generator_func = nfc_generate_mf_ul_h11, .generator_func = nfc_generate_mf_ul_h11,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator mf_ul_21_generator = { static const NfcGenerator mf_ul_21_generator = {
.name = "Mifare Ultralight EV1 21", .name = "Mifare Ultralight EV1 21",
.generator_func = nfc_generate_mf_ul_21, .generator_func = nfc_generate_mf_ul_21,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator mf_ul_h21_generator = { static const NfcGenerator mf_ul_h21_generator = {
.name = "Mifare Ultralight EV1 H21", .name = "Mifare Ultralight EV1 H21",
.generator_func = nfc_generate_mf_ul_h21, .generator_func = nfc_generate_mf_ul_h21,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator ntag203_generator = { static const NfcGenerator ntag203_generator = {
.name = "NTAG203", .name = "NTAG203",
.generator_func = nfc_generate_mf_ul_ntag203, .generator_func = nfc_generate_mf_ul_ntag203,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator ntag213_generator = { static const NfcGenerator ntag213_generator = {
.name = "NTAG213", .name = "NTAG213",
.generator_func = nfc_generate_ntag213, .generator_func = nfc_generate_ntag213,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator ntag215_generator = { static const NfcGenerator ntag215_generator = {
.name = "NTAG215", .name = "NTAG215",
.generator_func = nfc_generate_ntag215, .generator_func = nfc_generate_ntag215,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator ntag216_generator = { static const NfcGenerator ntag216_generator = {
.name = "NTAG216", .name = "NTAG216",
.generator_func = nfc_generate_ntag216, .generator_func = nfc_generate_ntag216,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator ntag_i2c_1k_generator = { static const NfcGenerator ntag_i2c_1k_generator = {
.name = "NTAG I2C 1k", .name = "NTAG I2C 1k",
.generator_func = nfc_generate_ntag_i2c_1k, .generator_func = nfc_generate_ntag_i2c_1k,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator ntag_i2c_2k_generator = { static const NfcGenerator ntag_i2c_2k_generator = {
.name = "NTAG I2C 2k", .name = "NTAG I2C 2k",
.generator_func = nfc_generate_ntag_i2c_2k, .generator_func = nfc_generate_ntag_i2c_2k,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator ntag_i2c_plus_1k_generator = { static const NfcGenerator ntag_i2c_plus_1k_generator = {
.name = "NTAG I2C Plus 1k", .name = "NTAG I2C Plus 1k",
.generator_func = nfc_generate_ntag_i2c_plus_1k, .generator_func = nfc_generate_ntag_i2c_plus_1k,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator ntag_i2c_plus_2k_generator = { static const NfcGenerator ntag_i2c_plus_2k_generator = {
.name = "NTAG I2C Plus 2k", .name = "NTAG I2C Plus 2k",
.generator_func = nfc_generate_ntag_i2c_plus_2k, .generator_func = nfc_generate_ntag_i2c_plus_2k,
.next_scene = NfcSceneMfUltralightMenu,
}; };
static const NfcGenerator mifare_classic_1k_4b_uid_generator = { static const NfcGenerator mifare_classic_1k_4b_uid_generator = {
.name = "Mifare Classic 1k 4byte UID", .name = "Mifare Classic 1k 4byte UID",
.generator_func = nfc_generate_mf_classic_1k_4b_uid, .generator_func = nfc_generate_mf_classic_1k_4b_uid,
.next_scene = NfcSceneMfClassicMenu,
}; };
static const NfcGenerator mifare_classic_1k_7b_uid_generator = { static const NfcGenerator mifare_classic_1k_7b_uid_generator = {
.name = "Mifare Classic 1k 7byte UID", .name = "Mifare Classic 1k 7byte UID",
.generator_func = nfc_generate_mf_classic_1k_7b_uid, .generator_func = nfc_generate_mf_classic_1k_7b_uid,
.next_scene = NfcSceneMfClassicMenu,
}; };
static const NfcGenerator mifare_classic_4k_4b_uid_generator = { static const NfcGenerator mifare_classic_4k_4b_uid_generator = {
.name = "Mifare Classic 4k 4byte UID", .name = "Mifare Classic 4k 4byte UID",
.generator_func = nfc_generate_mf_classic_4k_4b_uid, .generator_func = nfc_generate_mf_classic_4k_4b_uid,
.next_scene = NfcSceneMfClassicMenu,
}; };
static const NfcGenerator mifare_classic_4k_7b_uid_generator = { static const NfcGenerator mifare_classic_4k_7b_uid_generator = {
.name = "Mifare Classic 4k 7byte UID", .name = "Mifare Classic 4k 7byte UID",
.generator_func = nfc_generate_mf_classic_4k_7b_uid, .generator_func = nfc_generate_mf_classic_4k_7b_uid,
.next_scene = NfcSceneMfClassicMenu,
}; };
const NfcGenerator* const nfc_generators[] = { const NfcGenerator* const nfc_generators[] = {

View File

@@ -1,14 +1,13 @@
#pragma once #pragma once
#include "../nfc_i.h" #include "../nfc_device.h"
typedef void (*NfcGeneratorFunc)(NfcDeviceData* data); typedef void (*NfcGeneratorFunc)(NfcDeviceData* data);
struct NfcGenerator { typedef struct {
const char* name; const char* name;
NfcGeneratorFunc generator_func; NfcGeneratorFunc generator_func;
NfcScene next_scene; } NfcGenerator;
};
extern const NfcGenerator* const nfc_generators[]; extern const NfcGenerator* const nfc_generators[];

View File

@@ -77,28 +77,38 @@ def add_env(name, value, file):
print(f"{delimeter}", file=file) print(f"{delimeter}", file=file)
def add_envs(data, env_file, args): def add_set_output_var(name, value, file):
add_env("COMMIT_MSG", data["commit_comment"], env_file) print(f"{name}={value}", file=file)
add_env("COMMIT_HASH", data["commit_hash"], env_file)
add_env("COMMIT_SHA", data["commit_sha"], env_file)
add_env("SUFFIX", data["suffix"], env_file) def add_envs(data, gh_env_file, gh_out_file, args):
add_env("BRANCH_NAME", data["branch_name"], env_file) add_env("COMMIT_MSG", data["commit_comment"], gh_env_file)
add_env("DIST_SUFFIX", data["suffix"], env_file) add_env("COMMIT_HASH", data["commit_hash"], gh_env_file)
add_env("WORKFLOW_BRANCH_OR_TAG", data["branch_name"], env_file) add_env("COMMIT_SHA", data["commit_sha"], gh_env_file)
add_env("SUFFIX", data["suffix"], gh_env_file)
add_env("BRANCH_NAME", data["branch_name"], gh_env_file)
add_env("DIST_SUFFIX", data["suffix"], gh_env_file)
add_env("WORKFLOW_BRANCH_OR_TAG", data["branch_name"], gh_env_file)
add_set_output_var("branch_name", data["branch_name"], gh_out_file)
add_set_output_var("commit_sha", data["commit_sha"], gh_out_file)
add_set_output_var("default_target", os.getenv("DEFAULT_TARGET"), gh_out_file)
add_set_output_var("suffix", data["suffix"], gh_out_file)
if args.type == "pull": if args.type == "pull":
add_env("PULL_ID", data["pull_id"], env_file) add_env("PULL_ID", data["pull_id"], gh_env_file)
add_env("PULL_NAME", data["pull_name"], env_file) add_env("PULL_NAME", data["pull_name"], gh_env_file)
def main(): def main():
args = parse_args() args = parse_args()
event_file = open(args.event_file) event_file = open(args.event_file, "r")
event = json.load(event_file) event = json.load(event_file)
env_file = open(os.environ["GITHUB_ENV"], "a") gh_env_file = open(os.environ["GITHUB_ENV"], "a")
gh_out_file = open(os.environ["GITHUB_OUTPUT"], "a")
data = get_details(event, args) data = get_details(event, args)
add_envs(data, env_file, args) add_envs(data, gh_env_file, gh_out_file, args)
event_file.close() event_file.close()
env_file.close() gh_env_file.close()
gh_out_file.close()
if __name__ == "__main__": if __name__ == "__main__":

53
scripts/merge_report_qa.py Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env python3
import os
import re
import sys
import argparse
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("slack_token")
parser.add_argument("slack_channel")
args = parser.parse_args()
return args
def checkCommitMessage(msg):
regex = re.compile(r"^'?\[FL-\d+\]")
if regex.match(msg):
return True
return False
def reportSlack(commit_hash, slack_token, slack_channel, message):
client = WebClient(token=slack_token)
try:
client.chat_postMessage(channel="#" + slack_channel, text=message)
except SlackApiError as e:
print(e)
sys.exit(1)
def main():
args = parse_args()
commit_msg = os.getenv("COMMIT_MSG")
commit_hash = os.getenv("COMMIT_HASH")
commit_sha = os.getenv("COMMIT_SHA")
commit_link = (
"<https://github.com/flipperdevices/flipperzero-firmware/commit/"
+ commit_hash
+ "|"
+ commit_sha
+ ">"
)
message = "Commit " + commit_link + " merged to dev without 'FL' ticket!"
if not checkCommitMessage(commit_msg):
reportSlack(commit_hash, args.slack_token, args.slack_channel, message)
if __name__ == "__main__":
main()