mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-14 20:48:35 -07:00
Merge remote-tracking branch 'origin/dev' into nfcf
This commit is contained in:
2
.github/workflows/amap_analyse.yml
vendored
2
.github/workflows/amap_analyse.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
13
.github/workflows/build.yml
vendored
13
.github/workflows/build.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
@@ -35,6 +35,7 @@ jobs:
|
||||
mkdir artifacts
|
||||
|
||||
- name: 'Get commit details'
|
||||
id: names
|
||||
run: |
|
||||
if [[ ${{ github.event_name }} == 'pull_request' ]]; then
|
||||
TYPE="pull"
|
||||
@@ -45,14 +46,6 @@ jobs:
|
||||
fi
|
||||
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'
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
run: |
|
||||
@@ -143,7 +136,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
6
.github/workflows/check_submodules.yml
vendored
6
.github/workflows/check_submodules.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
@@ -36,12 +36,12 @@ jobs:
|
||||
BRANCHES=$(git branch -r --contains "$SUBMODULE_HASH");
|
||||
COMMITS_IN_BRANCH="$(git rev-list --count dev)";
|
||||
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+)";
|
||||
exit 1;
|
||||
fi
|
||||
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";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
2
.github/workflows/lint_c.yml
vendored
2
.github/workflows/lint_c.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
2
.github/workflows/lint_python.yml
vendored
2
.github/workflows/lint_python.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
41
.github/workflows/merge_report.yml
vendored
Normal file
41
.github/workflows/merge_report.yml
vendored
Normal 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 }}
|
||||
|
||||
12
.github/workflows/pvs_studio.yml
vendored
12
.github/workflows/pvs_studio.yml
vendored
@@ -25,12 +25,13 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: 'Checkout code'
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: 'Get commit details'
|
||||
id: names
|
||||
run: |
|
||||
if [[ ${{ github.event_name }} == 'pull_request' ]]; then
|
||||
TYPE="pull"
|
||||
@@ -41,15 +42,6 @@ jobs:
|
||||
fi
|
||||
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'
|
||||
run: |
|
||||
rm -rf reports/
|
||||
|
||||
8
.github/workflows/unit_tests.yml
vendored
8
.github/workflows/unit_tests.yml
vendored
@@ -11,8 +11,14 @@ jobs:
|
||||
run_units_on_test_bench:
|
||||
runs-on: [self-hosted, FlipperZeroTest]
|
||||
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@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <lib/nfc/helpers/mf_classic_dict.h>
|
||||
#include <lib/digital_signal/digital_signal.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/toolbox/stream/file_stream.h>
|
||||
@@ -102,7 +102,10 @@ static bool nfc_test_digital_signal_test_encode(
|
||||
|
||||
do {
|
||||
// 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
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <lib/nfc/nfc_device.h>
|
||||
#include <lib/nfc/helpers/mf_classic_dict.h>
|
||||
#include <lib/nfc/parsers/nfc_supported_card.h>
|
||||
#include <lib/nfc/helpers/nfc_generators.h>
|
||||
|
||||
#include "views/dict_attack.h"
|
||||
#include "views/detect_reader.h"
|
||||
@@ -63,9 +64,6 @@ typedef enum {
|
||||
NfcRpcStateEmulated,
|
||||
} NfcRpcState;
|
||||
|
||||
// Forward declaration due to circular dependency
|
||||
typedef struct NfcGenerator NfcGenerator;
|
||||
|
||||
struct Nfc {
|
||||
NfcWorker* worker;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#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) {
|
||||
Nfc* nfc = context;
|
||||
@@ -39,7 +39,12 @@ bool nfc_scene_generate_info_on_event(void* context, SceneManagerEvent event) {
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "../nfc_i.h"
|
||||
#include "../helpers/nfc_generators.h"
|
||||
#include "lib/nfc/helpers/nfc_generators.h"
|
||||
|
||||
enum SubmenuIndex {
|
||||
SubmenuIndexNFCA4,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <m-array.h>
|
||||
|
||||
#define FRAME_HEIGHT 12
|
||||
#define MAX_LEN_PX 100
|
||||
#define MAX_LEN_PX 111
|
||||
#define MENU_ITEMS 4u
|
||||
#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);
|
||||
item_menu = SubGhzReceiverMenuItemArray_get(model->history->data, idx);
|
||||
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) {
|
||||
subghz_view_receiver_draw_frame(canvas, i, scrollbar);
|
||||
} else {
|
||||
|
||||
BIN
applications/plugins/weather_station/images/Humid_8x13.png
Normal file
BIN
applications/plugins/weather_station/images/Humid_8x13.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
BIN
applications/plugins/weather_station/images/Timer_11x11.png
Normal file
BIN
applications/plugins/weather_station/images/Timer_11x11.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
@@ -99,6 +99,17 @@ bool ws_block_generic_serialize(
|
||||
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;
|
||||
if(!flipper_format_write_uint32(flipper_format, "Ch", &temp_data, 1)) {
|
||||
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;
|
||||
|
||||
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)) {
|
||||
FURI_LOG_E(TAG, "Missing Channel");
|
||||
break;
|
||||
|
||||
@@ -29,6 +29,7 @@ struct WSBlockGeneric {
|
||||
uint8_t data_count_bit;
|
||||
uint8_t battery_low;
|
||||
uint8_t humidity;
|
||||
uint32_t timestamp;
|
||||
uint8_t channel;
|
||||
uint8_t btn;
|
||||
float temp;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <m-array.h>
|
||||
|
||||
#define FRAME_HEIGHT 12
|
||||
#define MAX_LEN_PX 100
|
||||
#define MAX_LEN_PX 112
|
||||
#define MENU_ITEMS 4u
|
||||
#define UNLOCK_CNT 3
|
||||
|
||||
@@ -189,7 +189,7 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if(scrollbar) {
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
|
||||
struct WSReceiverInfo {
|
||||
View* view;
|
||||
FuriTimer* timer;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t curr_ts;
|
||||
FuriString* protocol_name;
|
||||
WSBlockGeneric* generic;
|
||||
} 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);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -44,46 +50,76 @@ void ws_view_receiver_info_draw(Canvas* canvas, WSReceiverInfoModel* model) {
|
||||
"%s %db",
|
||||
furi_string_get_cstr(model->protocol_name),
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
snprintf(
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
canvas_draw_str_aligned(canvas, 63, 46, AlignRight, AlignTop, buffer);
|
||||
canvas_draw_circle(canvas, 55, 45, 1);
|
||||
canvas_draw_str_aligned(canvas, 47, 47, AlignRight, AlignTop, buffer);
|
||||
canvas_draw_circle(canvas, 38, 46, 1);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
void ws_view_receiver_info_enter(void* context) {
|
||||
furi_assert(context);
|
||||
}
|
||||
|
||||
void ws_view_receiver_info_exit(void* context) {
|
||||
static void ws_view_receiver_info_enter(void* context) {
|
||||
furi_assert(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(
|
||||
ws_receiver_info->view,
|
||||
WSReceiverInfoModel * model,
|
||||
@@ -113,6 +154,20 @@ void ws_view_receiver_info_exit(void* context) {
|
||||
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_receiver_info = malloc(sizeof(WSReceiverInfo));
|
||||
|
||||
@@ -135,12 +190,17 @@ WSReceiverInfo* ws_view_receiver_info_alloc() {
|
||||
},
|
||||
true);
|
||||
|
||||
ws_receiver_info->timer =
|
||||
furi_timer_alloc(ws_view_receiver_info_timer, FuriTimerTypePeriodic, ws_receiver_info);
|
||||
|
||||
return ws_receiver_info;
|
||||
}
|
||||
|
||||
void ws_view_receiver_info_free(WSReceiverInfo* ws_receiver_info) {
|
||||
furi_assert(ws_receiver_info);
|
||||
|
||||
furi_timer_free(ws_receiver_info->timer);
|
||||
|
||||
with_view_model(
|
||||
ws_receiver_info->view,
|
||||
WSReceiverInfoModel * model,
|
||||
|
||||
@@ -30,7 +30,7 @@ struct ButtonMenu {
|
||||
|
||||
typedef struct {
|
||||
ButtonMenuItemArray_t items;
|
||||
uint8_t position;
|
||||
size_t position;
|
||||
const char* header;
|
||||
} ButtonMenuModel;
|
||||
|
||||
@@ -102,11 +102,9 @@ static void button_menu_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
ButtonMenuModel* model = (ButtonMenuModel*)_model;
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
uint8_t item_position = 0;
|
||||
int8_t active_screen = model->position / BUTTONS_PER_SCREEN;
|
||||
size_t items_size = ButtonMenuItemArray_size(model->items);
|
||||
int8_t max_screen = ((int16_t)items_size - 1) / BUTTONS_PER_SCREEN;
|
||||
ButtonMenuItemArray_it_t it;
|
||||
const size_t active_screen = model->position / BUTTONS_PER_SCREEN;
|
||||
const size_t items_size = ButtonMenuItemArray_size(model->items);
|
||||
const size_t max_screen = items_size ? (items_size - 1) / BUTTONS_PER_SCREEN : 0;
|
||||
|
||||
if(active_screen > 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
size_t item_position = 0;
|
||||
ButtonMenuItemArray_it_t it;
|
||||
|
||||
for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it);
|
||||
ButtonMenuItemArray_next(it), ++item_position) {
|
||||
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->type == ButtonMenuItemTypeControl) {
|
||||
if(type == InputTypeShort) {
|
||||
if(item && item->callback) {
|
||||
if(item->callback) {
|
||||
item->callback(item->callback_context, item->index, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(item->type == ButtonMenuItemTypeCommon) {
|
||||
if((type == InputTypePress) || (type == InputTypeRelease)) {
|
||||
if(item && item->callback) {
|
||||
if(item->callback) {
|
||||
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,
|
||||
ButtonMenuModel * model,
|
||||
{
|
||||
uint8_t item_position = 0;
|
||||
size_t item_position = 0;
|
||||
ButtonMenuItemArray_it_t it;
|
||||
for(ButtonMenuItemArray_it(it, model->items); !ButtonMenuItemArray_end_p(it);
|
||||
ButtonMenuItemArray_next(it), ++item_position) {
|
||||
|
||||
@@ -20,8 +20,8 @@ ARRAY_DEF(SubmenuItemArray, SubmenuItem, M_POD_OPLIST);
|
||||
typedef struct {
|
||||
SubmenuItemArray_t items;
|
||||
const char* header;
|
||||
uint8_t position;
|
||||
uint8_t window_position;
|
||||
size_t position;
|
||||
size_t window_position;
|
||||
} SubmenuModel;
|
||||
|
||||
static void submenu_process_up(Submenu* submenu);
|
||||
@@ -36,19 +36,19 @@ static void submenu_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
|
||||
canvas_clear(canvas);
|
||||
|
||||
uint8_t position = 0;
|
||||
SubmenuItemArray_it_t it;
|
||||
|
||||
if(model->header) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 4, 11, model->header);
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
size_t position = 0;
|
||||
SubmenuItemArray_it_t it;
|
||||
for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it);
|
||||
SubmenuItemArray_next(it)) {
|
||||
uint8_t item_position = position - model->window_position;
|
||||
uint8_t items_on_screen = model->header ? 3 : 4;
|
||||
const size_t item_position = position - model->window_position;
|
||||
const size_t items_on_screen = model->header ? 3 : 4;
|
||||
uint8_t y_offset = model->header ? 16 : 0;
|
||||
|
||||
if(item_position < items_on_screen) {
|
||||
@@ -198,7 +198,7 @@ void submenu_set_selected_item(Submenu* submenu, uint32_t index) {
|
||||
submenu->view,
|
||||
SubmenuModel * model,
|
||||
{
|
||||
uint32_t position = 0;
|
||||
size_t position = 0;
|
||||
SubmenuItemArray_it_t it;
|
||||
for(SubmenuItemArray_it(it, model->items); !SubmenuItemArray_end_p(it);
|
||||
SubmenuItemArray_next(it)) {
|
||||
@@ -208,7 +208,9 @@ void submenu_set_selected_item(Submenu* submenu, uint32_t index) {
|
||||
position++;
|
||||
}
|
||||
|
||||
if(position >= SubmenuItemArray_size(model->items)) {
|
||||
const size_t items_size = SubmenuItemArray_size(model->items);
|
||||
|
||||
if(position >= items_size) {
|
||||
position = 0;
|
||||
}
|
||||
|
||||
@@ -219,16 +221,12 @@ void submenu_set_selected_item(Submenu* submenu, uint32_t index) {
|
||||
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;
|
||||
} else {
|
||||
if(model->window_position >=
|
||||
(SubmenuItemArray_size(model->items) - items_on_screen)) {
|
||||
model->window_position =
|
||||
(SubmenuItemArray_size(model->items) - items_on_screen);
|
||||
}
|
||||
} else if(model->window_position >= items_size - items_on_screen) {
|
||||
model->window_position = items_size - items_on_screen;
|
||||
}
|
||||
},
|
||||
true);
|
||||
@@ -239,16 +237,18 @@ void submenu_process_up(Submenu* submenu) {
|
||||
submenu->view,
|
||||
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) {
|
||||
model->position--;
|
||||
if(((model->position - model->window_position) < 1) &&
|
||||
model->window_position > 0) {
|
||||
if((model->position - model->window_position < 1) &&
|
||||
(model->window_position > 0)) {
|
||||
model->window_position--;
|
||||
}
|
||||
} else {
|
||||
model->position = SubmenuItemArray_size(model->items) - 1;
|
||||
if(model->position > (items_on_screen - 1)) {
|
||||
model->position = items_size - 1;
|
||||
if(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,
|
||||
SubmenuModel * model,
|
||||
{
|
||||
uint8_t items_on_screen = model->header ? 3 : 4;
|
||||
if(model->position < (SubmenuItemArray_size(model->items) - 1)) {
|
||||
const size_t items_on_screen = model->header ? 3 : 4;
|
||||
const size_t items_size = SubmenuItemArray_size(model->items);
|
||||
|
||||
if(model->position < items_size - 1) {
|
||||
model->position++;
|
||||
if((model->position - model->window_position) > (items_on_screen - 2) &&
|
||||
model->window_position <
|
||||
(SubmenuItemArray_size(model->items) - items_on_screen)) {
|
||||
if((model->position - model->window_position > items_on_screen - 2) &&
|
||||
(model->window_position < items_size - items_on_screen)) {
|
||||
model->window_position++;
|
||||
}
|
||||
} else {
|
||||
@@ -284,7 +285,8 @@ void submenu_process_ok(Submenu* submenu) {
|
||||
submenu->view,
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -81,7 +81,6 @@ FIRMWARE_APPS = {
|
||||
"basic_services",
|
||||
"updater_app",
|
||||
"unit_tests",
|
||||
"nfc",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -376,103 +376,86 @@ static void nfc_generate_mf_classic_4k_7b_uid(NfcDeviceData* data) {
|
||||
static const NfcGenerator mf_ul_generator = {
|
||||
.name = "Mifare Ultralight",
|
||||
.generator_func = nfc_generate_mf_ul_orig,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator mf_ul_11_generator = {
|
||||
.name = "Mifare Ultralight EV1 11",
|
||||
.generator_func = nfc_generate_mf_ul_11,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator mf_ul_h11_generator = {
|
||||
.name = "Mifare Ultralight EV1 H11",
|
||||
.generator_func = nfc_generate_mf_ul_h11,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator mf_ul_21_generator = {
|
||||
.name = "Mifare Ultralight EV1 21",
|
||||
.generator_func = nfc_generate_mf_ul_21,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator mf_ul_h21_generator = {
|
||||
.name = "Mifare Ultralight EV1 H21",
|
||||
.generator_func = nfc_generate_mf_ul_h21,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator ntag203_generator = {
|
||||
.name = "NTAG203",
|
||||
.generator_func = nfc_generate_mf_ul_ntag203,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator ntag213_generator = {
|
||||
.name = "NTAG213",
|
||||
.generator_func = nfc_generate_ntag213,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator ntag215_generator = {
|
||||
.name = "NTAG215",
|
||||
.generator_func = nfc_generate_ntag215,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator ntag216_generator = {
|
||||
.name = "NTAG216",
|
||||
.generator_func = nfc_generate_ntag216,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator ntag_i2c_1k_generator = {
|
||||
.name = "NTAG I2C 1k",
|
||||
.generator_func = nfc_generate_ntag_i2c_1k,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator ntag_i2c_2k_generator = {
|
||||
.name = "NTAG I2C 2k",
|
||||
.generator_func = nfc_generate_ntag_i2c_2k,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator ntag_i2c_plus_1k_generator = {
|
||||
.name = "NTAG I2C Plus 1k",
|
||||
.generator_func = nfc_generate_ntag_i2c_plus_1k,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator ntag_i2c_plus_2k_generator = {
|
||||
.name = "NTAG I2C Plus 2k",
|
||||
.generator_func = nfc_generate_ntag_i2c_plus_2k,
|
||||
.next_scene = NfcSceneMfUltralightMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator mifare_classic_1k_4b_uid_generator = {
|
||||
.name = "Mifare Classic 1k 4byte UID",
|
||||
.generator_func = nfc_generate_mf_classic_1k_4b_uid,
|
||||
.next_scene = NfcSceneMfClassicMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator mifare_classic_1k_7b_uid_generator = {
|
||||
.name = "Mifare Classic 1k 7byte UID",
|
||||
.generator_func = nfc_generate_mf_classic_1k_7b_uid,
|
||||
.next_scene = NfcSceneMfClassicMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator mifare_classic_4k_4b_uid_generator = {
|
||||
.name = "Mifare Classic 4k 4byte UID",
|
||||
.generator_func = nfc_generate_mf_classic_4k_4b_uid,
|
||||
.next_scene = NfcSceneMfClassicMenu,
|
||||
};
|
||||
|
||||
static const NfcGenerator mifare_classic_4k_7b_uid_generator = {
|
||||
.name = "Mifare Classic 4k 7byte UID",
|
||||
.generator_func = nfc_generate_mf_classic_4k_7b_uid,
|
||||
.next_scene = NfcSceneMfClassicMenu,
|
||||
};
|
||||
|
||||
const NfcGenerator* const nfc_generators[] = {
|
||||
@@ -1,14 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "../nfc_i.h"
|
||||
#include "../nfc_device.h"
|
||||
|
||||
typedef void (*NfcGeneratorFunc)(NfcDeviceData* data);
|
||||
|
||||
struct NfcGenerator {
|
||||
typedef struct {
|
||||
const char* name;
|
||||
NfcGeneratorFunc generator_func;
|
||||
NfcScene next_scene;
|
||||
};
|
||||
} NfcGenerator;
|
||||
|
||||
extern const NfcGenerator* const nfc_generators[];
|
||||
|
||||
@@ -77,28 +77,38 @@ def add_env(name, value, file):
|
||||
print(f"{delimeter}", file=file)
|
||||
|
||||
|
||||
def add_envs(data, env_file, args):
|
||||
add_env("COMMIT_MSG", data["commit_comment"], env_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)
|
||||
add_env("BRANCH_NAME", data["branch_name"], env_file)
|
||||
add_env("DIST_SUFFIX", data["suffix"], env_file)
|
||||
add_env("WORKFLOW_BRANCH_OR_TAG", data["branch_name"], env_file)
|
||||
def add_set_output_var(name, value, file):
|
||||
print(f"{name}={value}", file=file)
|
||||
|
||||
|
||||
def add_envs(data, gh_env_file, gh_out_file, args):
|
||||
add_env("COMMIT_MSG", data["commit_comment"], gh_env_file)
|
||||
add_env("COMMIT_HASH", data["commit_hash"], gh_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":
|
||||
add_env("PULL_ID", data["pull_id"], env_file)
|
||||
add_env("PULL_NAME", data["pull_name"], env_file)
|
||||
add_env("PULL_ID", data["pull_id"], gh_env_file)
|
||||
add_env("PULL_NAME", data["pull_name"], gh_env_file)
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
event_file = open(args.event_file)
|
||||
event_file = open(args.event_file, "r")
|
||||
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)
|
||||
add_envs(data, env_file, args)
|
||||
add_envs(data, gh_env_file, gh_out_file, args)
|
||||
event_file.close()
|
||||
env_file.close()
|
||||
gh_env_file.close()
|
||||
gh_out_file.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
53
scripts/merge_report_qa.py
Executable file
53
scripts/merge_report_qa.py
Executable 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()
|
||||
Reference in New Issue
Block a user