Merge branch 'dev' into DigitalSequence_PulseReader

This commit is contained in:
g3gg0.de
2022-12-19 14:50:28 +01:00
committed by GitHub
98 changed files with 3306 additions and 340 deletions
+3 -2
View File
@@ -11,6 +11,7 @@ on:
env:
TARGETS: f7
FBT_TOOLCHAIN_PATH: /opt
jobs:
amap_analyse:
@@ -39,7 +40,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 }}
@@ -78,7 +79,7 @@ jobs:
- name: 'Upload report to DB'
run: |
FBT_TOOLCHAIN_PATH=/opt source scripts/toolchain/fbtenv.sh
source scripts/toolchain/fbtenv.sh
get_size()
{
SECTION="$1";
+6 -12
View File
@@ -12,6 +12,7 @@ on:
env:
TARGETS: f7
DEFAULT_TARGET: f7
FBT_TOOLCHAIN_PATH: /runner/_work
jobs:
main:
@@ -24,7 +25,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 +36,7 @@ jobs:
mkdir artifacts
- name: 'Get commit details'
id: names
run: |
if [[ ${{ github.event_name }} == 'pull_request' ]]; then
TYPE="pull"
@@ -45,14 +47,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: |
@@ -62,7 +56,7 @@ jobs:
run: |
set -e
for TARGET in ${TARGETS}; do
FBT_TOOLCHAIN_PATH=/runner/_work ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \
./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \
copro_dist updater_package ${{ startsWith(github.ref, 'refs/tags') && 'DEBUG=0 COMPACT=1' || '' }}
done
@@ -143,7 +137,7 @@ jobs:
fi
- name: 'Checkout code'
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: true
@@ -164,6 +158,6 @@ jobs:
run: |
set -e
for TARGET in ${TARGETS}; do
FBT_TOOLCHAIN_PATH=/runner/_work ./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \
./fbt TARGET_HW="$(echo "${TARGET}" | sed 's/f//')" \
updater_package DEBUG=0 COMPACT=1
done
+3 -3
View File
@@ -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
+4 -2
View File
@@ -11,6 +11,8 @@ on:
env:
TARGETS: f7
FBT_TOOLCHAIN_PATH: /runner/_work
SET_GH_OUTPUT: 1
jobs:
lint_c_cpp:
@@ -23,14 +25,14 @@ 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: 'Check code formatting'
id: syntax_check
run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/runner/_work ./fbt lint
run: ./fbt lint
- name: Report code formatting errors
if: failure() && steps.syntax_check.outputs.errors && github.event.pull_request
+6 -2
View File
@@ -9,6 +9,10 @@ on:
- '*'
pull_request:
env:
FBT_TOOLCHAIN_PATH: /runner/_work
SET_GH_OUTPUT: 1
jobs:
lint_python:
runs-on: [self-hosted,FlipperZeroShell]
@@ -20,10 +24,10 @@ 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: 'Check code formatting'
run: SET_GH_OUTPUT=1 FBT_TOOLCHAIN_PATH=/runner/_work ./fbt lint_py
run: ./fbt lint_py
+45
View File
@@ -0,0 +1,45 @@
name: 'Check FL ticket in PR name'
on:
push:
branches:
- dev
env:
FBT_TOOLCHAIN_PATH: /runner/_work
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: |
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 }}
+5 -12
View File
@@ -12,6 +12,7 @@ on:
env:
TARGETS: f7
DEFAULT_TARGET: f7
FBT_TOOLCHAIN_PATH: /runner/_work
jobs:
analyse_c_cpp:
@@ -25,12 +26,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 +43,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/
@@ -57,11 +50,11 @@ jobs:
- name: 'Generate compile_comands.json'
run: |
FBT_TOOLCHAIN_PATH=/runner/_work ./fbt COMPACT=1 version_json proto_ver icons firmware_cdb dolphin_internal dolphin_blocking _fap_icons
./fbt COMPACT=1 version_json proto_ver icons firmware_cdb dolphin_internal dolphin_blocking _fap_icons
- name: 'Static code analysis'
run: |
FBT_TOOLCHAIN_PATH=/runner/_work source scripts/toolchain/fbtenv.sh
source scripts/toolchain/fbtenv.sh
pvs-studio-analyzer credentials ${{ secrets.PVS_STUDIO_CREDENTIALS }}
pvs-studio-analyzer analyze \
@.pvsoptions \
+70 -17
View File
@@ -6,13 +6,20 @@ on:
env:
TARGETS: f7
DEFAULT_TARGET: f7
FBT_TOOLCHAIN_PATH: /opt
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 }}
@@ -22,35 +29,81 @@ jobs:
run: |
echo "flipper=/dev/ttyACM0" >> $GITHUB_OUTPUT
- name: 'Flashing target firmware'
id: first_full_flash
run: |
./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1
source scripts/toolchain/fbtenv.sh
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
- name: 'Validating updater'
id: second_full_flash
if: success()
run: |
./fbt flash_usb_full PORT=${{steps.device.outputs.flipper}} FORCE=1
source scripts/toolchain/fbtenv.sh
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
- name: 'Flash unit tests firmware'
id: flashing
if: success()
run: |
FBT_TOOLCHAIN_PATH=/opt ./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1
./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1
- name: 'Wait for flipper to finish updating'
id: connect
if: steps.flashing.outcome == 'success'
run: |
. scripts/toolchain/fbtenv.sh
./scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
- name: 'Format flipper SD card'
id: format
if: steps.connect.outcome == 'success'
run: |
. scripts/toolchain/fbtenv.sh
./scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext
source scripts/toolchain/fbtenv.sh
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
- name: 'Copy assets and unit tests data to flipper'
id: copy
if: steps.format.outcome == 'success'
if: steps.connect.outcome == 'success'
run: |
. scripts/toolchain/fbtenv.sh
./scripts/storage.py -p ${{steps.device.outputs.flipper}} send assets/resources /ext
./scripts/storage.py -p ${{steps.device.outputs.flipper}} send assets/unit_tests /ext/unit_tests
source scripts/toolchain/fbtenv.sh
python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} -f send assets/unit_tests /ext/unit_tests
- name: 'Run units and validate results'
if: steps.copy.outcome == 'success'
run: |
. scripts/toolchain/fbtenv.sh
./scripts/testing/units.py ${{steps.device.outputs.flipper}}
source scripts/toolchain/fbtenv.sh
python3 scripts/testing/units.py ${{steps.device.outputs.flipper}}
- name: 'Get last release tag'
id: release_tag
if: success()
run: |
echo "tag=$(git tag -l --sort=-version:refname | grep -v "rc\|RC" | head -1)" >> $GITHUB_OUTPUT
- name: 'Decontaminate previous build leftovers'
if: success()
run: |
if [ -d .git ]; then
git submodule status || git checkout "$(git rev-list --max-parents=0 HEAD | tail -n 1)"
fi
- name: 'Checkout latest release'
uses: actions/checkout@v3
if: success()
with:
fetch-depth: 0
ref: ${{ steps.release_tag.outputs.tag }}
- name: 'Flash last release'
if: success()
run: |
./fbt flash OPENOCD_ADAPTER_SERIAL=2A0906016415303030303032 FIRMWARE_APP_SET=unit_tests FORCE=1
- name: 'Wait for flipper to finish updating'
if: success()
run: |
source scripts/toolchain/fbtenv.sh
python3 scripts/testing/await_flipper.py ${{steps.device.outputs.flipper}}
- name: 'Format flipper SD card'
id: format
if: success()
run: |
source scripts/toolchain/fbtenv.sh
python3 scripts/storage.py -p ${{steps.device.outputs.flipper}} format_ext
+33 -1
View File
@@ -128,6 +128,38 @@
"group": "build",
"type": "shell",
"command": "./fbt COMPACT=1 DEBUG=0 launch_app APPSRC=${relativeFileDirname}"
},
{
"label": "[Debug] Launch App on Flipper with Serial Console",
"dependsOrder": "sequence",
"group": "build",
"dependsOn": [
"[Debug] Launch App on Flipper",
"Serial Console"
]
},
{
// Press Ctrl+] to quit
"label": "Serial Console",
"type": "shell",
"command": "./fbt cli",
"group": "none",
"isBackground": true,
"options": {
"env": {
"FBT_NO_SYNC": "0"
}
},
"presentation": {
"reveal": "always",
"revealProblems": "never",
"showReuseMessage": false,
"panel": "dedicated",
"focus": true,
"echo": true,
"close": true,
"group": "Logger"
}
}
]
}
}
@@ -0,0 +1,11 @@
App(
appid="locale_test",
name="Locale Test",
apptype=FlipperAppType.DEBUG,
entry_point="locale_test_app",
cdefines=["APP_LOCALE"],
requires=["gui", "locale"],
stack_size=2 * 1024,
order=70,
fap_category="Debug",
)
@@ -0,0 +1,102 @@
#include <furi.h>
#include <gui/gui.h>
#include <gui/elements.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/dialog_ex.h>
#include <locale/locale.h>
typedef struct {
Gui* gui;
ViewDispatcher* view_dispatcher;
View* view;
} LocaleTestApp;
static void locale_test_view_draw_callback(Canvas* canvas, void* _model) {
UNUSED(_model);
// Prepare canvas
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontSecondary);
FuriString* tmp_string = furi_string_alloc();
float temp = 25.3f;
LocaleMeasurementUnits units = locale_get_measurement_unit();
if(units == LocaleMeasurementUnitsMetric) {
furi_string_printf(tmp_string, "Temp: %5.1fC", (double)temp);
} else {
temp = locale_celsius_to_fahrenheit(temp);
furi_string_printf(tmp_string, "Temp: %5.1fF", (double)temp);
}
canvas_draw_str(canvas, 0, 10, furi_string_get_cstr(tmp_string));
FuriHalRtcDateTime datetime;
furi_hal_rtc_get_datetime(&datetime);
locale_format_time(tmp_string, &datetime, locale_get_time_format(), false);
canvas_draw_str(canvas, 0, 25, furi_string_get_cstr(tmp_string));
locale_format_date(tmp_string, &datetime, locale_get_date_format(), "/");
canvas_draw_str(canvas, 0, 40, furi_string_get_cstr(tmp_string));
furi_string_free(tmp_string);
}
static bool locale_test_view_input_callback(InputEvent* event, void* context) {
UNUSED(event);
UNUSED(context);
return false;
}
static uint32_t locale_test_exit(void* context) {
UNUSED(context);
return VIEW_NONE;
}
static LocaleTestApp* locale_test_alloc() {
LocaleTestApp* app = malloc(sizeof(LocaleTestApp));
// Gui
app->gui = furi_record_open(RECORD_GUI);
// View dispatcher
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
// Views
app->view = view_alloc();
view_set_draw_callback(app->view, locale_test_view_draw_callback);
view_set_input_callback(app->view, locale_test_view_input_callback);
view_set_previous_callback(app->view, locale_test_exit);
view_dispatcher_add_view(app->view_dispatcher, 0, app->view);
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
return app;
}
static void locale_test_free(LocaleTestApp* app) {
furi_assert(app);
// Free views
view_dispatcher_remove_view(app->view_dispatcher, 0);
view_free(app->view);
view_dispatcher_free(app->view_dispatcher);
// Close gui record
furi_record_close(RECORD_GUI);
app->gui = NULL;
// Free rest
free(app);
}
int32_t locale_test_app(void* p) {
UNUSED(p);
LocaleTestApp* app = locale_test_alloc();
view_dispatcher_run(app->view_dispatcher);
locale_test_free(app);
return 0;
}
+5 -2
View File
@@ -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();
@@ -13,7 +13,7 @@
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub")
#define TEST_RANDOM_COUNT_PARSE 244
#define TEST_RANDOM_COUNT_PARSE 253
#define TEST_TIMEOUT 10000
static SubGhzEnvironment* environment_handler;
@@ -587,6 +587,13 @@ MU_TEST(subghz_decoder_ansonic_test) {
"Test decoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n");
}
MU_TEST(subghz_decoder_smc5326_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/smc5326_raw.sub"), SUBGHZ_PROTOCOL_SMC5326_NAME),
"Test decoder " SUBGHZ_PROTOCOL_SMC5326_NAME " error\r\n");
}
//test encoders
MU_TEST(subghz_encoder_princeton_test) {
mu_assert(
@@ -714,6 +721,12 @@ MU_TEST(subghz_encoder_ansonic_test) {
"Test encoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n");
}
MU_TEST(subghz_encoder_smc5326_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/smc5326.sub")),
"Test encoder " SUBGHZ_PROTOCOL_SMC5326_NAME " error\r\n");
}
MU_TEST(subghz_random_test) {
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
}
@@ -757,6 +770,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_decoder_intertechno_v3_test);
MU_RUN_TEST(subghz_decoder_clemsa_test);
MU_RUN_TEST(subghz_decoder_ansonic_test);
MU_RUN_TEST(subghz_decoder_smc5326_test);
MU_RUN_TEST(subghz_encoder_princeton_test);
MU_RUN_TEST(subghz_encoder_came_test);
@@ -779,6 +793,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_encoder_intertechno_v3_test);
MU_RUN_TEST(subghz_encoder_clemsa_test);
MU_RUN_TEST(subghz_encoder_ansonic_test);
MU_RUN_TEST(subghz_encoder_smc5326_test);
MU_RUN_TEST(subghz_random_test);
subghz_test_deinit();
+1 -3
View File
@@ -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"
@@ -50,9 +51,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,
@@ -28,6 +28,13 @@ typedef enum {
SubGhzHopperStateRSSITimeOut,
} SubGhzHopperState;
/** SubGhzSpeakerState state */
typedef enum {
SubGhzSpeakerStateDisable,
SubGhzSpeakerStateShutdown,
SubGhzSpeakerStateEnable,
} SubGhzSpeakerState;
/** SubGhzRxKeyState state */
typedef enum {
SubGhzRxKeyStateIDLE,
@@ -259,6 +259,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
case SubGhzCustomEventViewReadRAWSendStop:
subghz->state_notifications = SubGhzNotificationStateIDLE;
if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
subghz_speaker_unmute(subghz);
subghz_tx_stop(subghz);
subghz_sleep(subghz);
}
@@ -376,10 +377,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false);
subghz_protocol_raw_save_to_file_pause(
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true);
subghz_speaker_mute(subghz);
} else {
subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true);
subghz_protocol_raw_save_to_file_pause(
(SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false);
subghz_speaker_unmute(subghz);
}
}
@@ -5,6 +5,7 @@ enum SubGhzSettingIndex {
SubGhzSettingIndexFrequency,
SubGhzSettingIndexHopping,
SubGhzSettingIndexModulation,
SubGhzSettingIndexSound,
SubGhzSettingIndexLock,
SubGhzSettingIndexRAWThesholdRSSI,
};
@@ -48,6 +49,16 @@ const uint32_t hopping_value[HOPPING_COUNT] = {
SubGhzHopperStateRunnig,
};
#define SPEAKER_COUNT 2
const char* const speaker_text[SPEAKER_COUNT] = {
"OFF",
"ON",
};
const uint32_t speaker_value[SPEAKER_COUNT] = {
SubGhzSpeakerStateShutdown,
SubGhzSpeakerStateEnable,
};
uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
furi_assert(context);
SubGhz* subghz = context;
@@ -167,6 +178,14 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item)
subghz->txrx->hopper_state = hopping_value[index];
}
static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, speaker_text[index]);
subghz->txrx->speaker_state = speaker_value[index];
}
static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
@@ -235,6 +254,16 @@ void subghz_scene_receiver_config_on_enter(void* context) {
variable_item_set_current_value_text(
item, subghz_setting_get_preset_name(subghz->setting, value_index));
item = variable_item_list_add(
subghz->variable_item_list,
"Sound:",
SPEAKER_COUNT,
subghz_scene_receiver_config_set_speaker,
subghz);
value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, speaker_text[value_index]);
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
SubGhzCustomEventManagerSet) {
variable_item_list_add(subghz->variable_item_list, "Lock Keyboard", 1, NULL, NULL);
+1
View File
@@ -177,6 +177,7 @@ SubGhz* subghz_alloc() {
subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
subghz->txrx->hopper_state = SubGhzHopperStateOFF;
subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN;
subghz->txrx->history = subghz_history_alloc();
+42
View File
@@ -86,6 +86,7 @@ uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) {
uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
furi_hal_subghz_flush_rx();
subghz_speaker_on(subghz);
furi_hal_subghz_rx();
furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker);
@@ -104,6 +105,7 @@ static bool subghz_tx(SubGhz* subghz, uint32_t frequency) {
furi_hal_subghz_set_frequency_and_path(frequency);
furi_hal_gpio_write(&gpio_cc1101_g0, false);
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
subghz_speaker_on(subghz);
bool ret = furi_hal_subghz_tx();
subghz->txrx->txrx_state = SubGhzTxRxStateTx;
return ret;
@@ -119,11 +121,13 @@ void subghz_idle(SubGhz* subghz) {
void subghz_rx_end(SubGhz* subghz) {
furi_assert(subghz);
furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx);
if(subghz_worker_is_running(subghz->txrx->worker)) {
subghz_worker_stop(subghz->txrx->worker);
furi_hal_subghz_stop_async_rx();
}
furi_hal_subghz_idle();
subghz_speaker_off(subghz);
subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
}
@@ -212,6 +216,7 @@ void subghz_tx_stop(SubGhz* subghz) {
subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path));
}
subghz_idle(subghz);
subghz_speaker_off(subghz);
notification_message(subghz->notifications, &sequence_reset_red);
}
@@ -585,3 +590,40 @@ void subghz_hopper_update(SubGhz* subghz) {
subghz_rx(subghz, subghz->txrx->preset->frequency);
}
}
void subghz_speaker_on(SubGhz* subghz) {
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
if(furi_hal_speaker_acquire(30)) {
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
} else {
subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
}
}
}
void subghz_speaker_off(SubGhz* subghz) {
if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) {
if(furi_hal_speaker_is_mine()) {
furi_hal_subghz_set_async_mirror_pin(NULL);
furi_hal_speaker_release();
if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown)
subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
}
}
}
void subghz_speaker_mute(SubGhz* subghz) {
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
if(furi_hal_speaker_is_mine()) {
furi_hal_subghz_set_async_mirror_pin(NULL);
}
}
}
void subghz_speaker_unmute(SubGhz* subghz) {
if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
if(furi_hal_speaker_is_mine()) {
furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
}
}
}
+5
View File
@@ -53,6 +53,7 @@ struct SubGhzTxRx {
uint16_t idx_menu_chosen;
SubGhzTxRxState txrx_state;
SubGhzHopperState hopper_state;
SubGhzSpeakerState speaker_state;
uint8_t hopper_timeout;
uint8_t hopper_idx_frequency;
SubGhzRxKeyState rx_key_state;
@@ -131,3 +132,7 @@ void subghz_file_name_clear(SubGhz* subghz);
bool subghz_path_is_file(FuriString* path);
uint32_t subghz_random_serial(void);
void subghz_hopper_update(SubGhz* subghz);
void subghz_speaker_on(SubGhz* subghz);
void subghz_speaker_off(SubGhz* subghz);
void subghz_speaker_mute(SubGhz* subghz);
void subghz_speaker_unmute(SubGhz* subghz);
+2 -2
View File
@@ -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 {
+25 -4
View File
@@ -9,10 +9,10 @@ enum HidDebugSubmenuIndex {
HidSubmenuIndexKeynote,
HidSubmenuIndexKeyboard,
HidSubmenuIndexMedia,
BtHidSubmenuIndexTikTok,
HidSubmenuIndexTikTok,
HidSubmenuIndexMouse,
HidSubmenuIndexMouseJiggler,
};
typedef enum { ConnTypeSubmenuIndexBluetooth, ConnTypeSubmenuIndexUsb } ConnTypeDebugSubmenuIndex;
static void hid_submenu_callback(void* context, uint32_t index) {
furi_assert(context);
@@ -29,9 +29,12 @@ static void hid_submenu_callback(void* context, uint32_t index) {
} else if(index == HidSubmenuIndexMouse) {
app->view_id = HidViewMouse;
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouse);
} else if(index == BtHidSubmenuIndexTikTok) {
} else if(index == HidSubmenuIndexTikTok) {
app->view_id = BtHidViewTikTok;
view_dispatcher_switch_to_view(app->view_dispatcher, BtHidViewTikTok);
} else if(index == HidSubmenuIndexMouseJiggler) {
app->view_id = HidViewMouseJiggler;
view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler);
}
}
@@ -48,6 +51,7 @@ static void bt_hid_connection_status_changed_callback(BtStatus status, void* con
hid_keyboard_set_connected_status(hid->hid_keyboard, connected);
hid_media_set_connected_status(hid->hid_media, connected);
hid_mouse_set_connected_status(hid->hid_mouse, connected);
hid_mouse_jiggler_set_connected_status(hid->hid_mouse_jiggler, connected);
hid_tiktok_set_connected_status(hid->hid_tiktok, connected);
}
@@ -104,10 +108,16 @@ Hid* hid_alloc(HidTransport transport) {
submenu_add_item(
app->device_type_submenu,
"TikTok Controller",
BtHidSubmenuIndexTikTok,
HidSubmenuIndexTikTok,
hid_submenu_callback,
app);
}
submenu_add_item(
app->device_type_submenu,
"Mouse Jiggler",
HidSubmenuIndexMouseJiggler,
hid_submenu_callback,
app);
view_set_previous_callback(submenu_get_view(app->device_type_submenu), hid_exit);
view_dispatcher_add_view(
app->view_dispatcher, HidViewSubmenu, submenu_get_view(app->device_type_submenu));
@@ -160,6 +170,15 @@ Hid* hid_app_alloc_view(void* context) {
view_dispatcher_add_view(
app->view_dispatcher, HidViewMouse, hid_mouse_get_view(app->hid_mouse));
// Mouse jiggler view
app->hid_mouse_jiggler = hid_mouse_jiggler_alloc(app);
view_set_previous_callback(
hid_mouse_jiggler_get_view(app->hid_mouse_jiggler), hid_exit_confirm_view);
view_dispatcher_add_view(
app->view_dispatcher,
HidViewMouseJiggler,
hid_mouse_jiggler_get_view(app->hid_mouse_jiggler));
return app;
}
@@ -182,6 +201,8 @@ void hid_free(Hid* app) {
hid_media_free(app->hid_media);
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouse);
hid_mouse_free(app->hid_mouse);
view_dispatcher_remove_view(app->view_dispatcher, HidViewMouseJiggler);
hid_mouse_jiggler_free(app->hid_mouse_jiggler);
view_dispatcher_remove_view(app->view_dispatcher, BtHidViewTikTok);
hid_tiktok_free(app->hid_tiktok);
view_dispatcher_free(app->view_dispatcher);
+2
View File
@@ -19,6 +19,7 @@
#include "views/hid_keyboard.h"
#include "views/hid_media.h"
#include "views/hid_mouse.h"
#include "views/hid_mouse_jiggler.h"
#include "views/hid_tiktok.h"
typedef enum {
@@ -39,6 +40,7 @@ struct Hid {
HidKeyboard* hid_keyboard;
HidMedia* hid_media;
HidMouse* hid_mouse;
HidMouseJiggler* hid_mouse_jiggler;
HidTikTok* hid_tiktok;
HidTransport transport;
+1
View File
@@ -4,6 +4,7 @@ typedef enum {
HidViewKeyboard,
HidViewMedia,
HidViewMouse,
HidViewMouseJiggler,
BtHidViewTikTok,
HidViewExitConfirm,
} HidView;
@@ -0,0 +1,149 @@
#include "hid_mouse_jiggler.h"
#include <gui/elements.h>
#include "../hid.h"
#include "hid_icons.h"
#define TAG "HidMouseJiggler"
struct HidMouseJiggler {
View* view;
Hid* hid;
FuriTimer* timer;
};
typedef struct {
bool connected;
bool running;
uint8_t counter;
} HidMouseJigglerModel;
static void hid_mouse_jiggler_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);
HidMouseJigglerModel* model = context;
// Header
if(model->connected) {
canvas_draw_icon(canvas, 0, 0, &I_Ble_connected_15x15);
} else {
canvas_draw_icon(canvas, 0, 0, &I_Ble_disconnected_15x15);
}
canvas_set_font(canvas, FontPrimary);
elements_multiline_text_aligned(canvas, 17, 3, AlignLeft, AlignTop, "Mouse Jiggler");
canvas_set_font(canvas, FontPrimary);
elements_multiline_text(canvas, AlignLeft, 35, "Press Start\nto jiggle");
canvas_set_font(canvas, FontSecondary);
// Ok
canvas_draw_icon(canvas, 63, 25, &I_Space_65x18);
if(model->running) {
elements_slightly_rounded_box(canvas, 66, 27, 60, 13);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_icon(canvas, 74, 29, &I_Ok_btn_9x9);
if(model->running) {
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Stop");
} else {
elements_multiline_text_aligned(canvas, 91, 36, AlignLeft, AlignBottom, "Start");
}
canvas_set_color(canvas, ColorBlack);
// Back
canvas_draw_icon(canvas, 74, 49, &I_Pin_back_arrow_10x8);
elements_multiline_text_aligned(canvas, 91, 57, AlignLeft, AlignBottom, "Quit");
}
static void hid_mouse_jiggler_timer_callback(void* context) {
furi_assert(context);
HidMouseJiggler* hid_mouse_jiggler = context;
with_view_model(
hid_mouse_jiggler->view,
HidMouseJigglerModel * model,
{
if(model->running) {
model->counter++;
hid_hal_mouse_move(
hid_mouse_jiggler->hid,
(model->counter % 2 == 0) ? MOUSE_MOVE_SHORT : -MOUSE_MOVE_SHORT,
0);
}
},
false);
}
static void hid_mouse_jiggler_enter_callback(void* context) {
furi_assert(context);
HidMouseJiggler* hid_mouse_jiggler = context;
furi_timer_start(hid_mouse_jiggler->timer, 500);
}
static void hid_mouse_jiggler_exit_callback(void* context) {
furi_assert(context);
HidMouseJiggler* hid_mouse_jiggler = context;
furi_timer_stop(hid_mouse_jiggler->timer);
}
static bool hid_mouse_jiggler_input_callback(InputEvent* event, void* context) {
furi_assert(context);
HidMouseJiggler* hid_mouse_jiggler = context;
bool consumed = false;
if(event->key == InputKeyOk) {
with_view_model(
hid_mouse_jiggler->view,
HidMouseJigglerModel * model,
{ model->running = !model->running; },
true);
consumed = true;
}
return consumed;
}
HidMouseJiggler* hid_mouse_jiggler_alloc(Hid* hid) {
HidMouseJiggler* hid_mouse_jiggler = malloc(sizeof(HidMouseJiggler));
hid_mouse_jiggler->view = view_alloc();
view_set_context(hid_mouse_jiggler->view, hid_mouse_jiggler);
view_allocate_model(
hid_mouse_jiggler->view, ViewModelTypeLocking, sizeof(HidMouseJigglerModel));
view_set_draw_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_draw_callback);
view_set_input_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_input_callback);
view_set_enter_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_enter_callback);
view_set_exit_callback(hid_mouse_jiggler->view, hid_mouse_jiggler_exit_callback);
hid_mouse_jiggler->hid = hid;
hid_mouse_jiggler->timer = furi_timer_alloc(
hid_mouse_jiggler_timer_callback, FuriTimerTypePeriodic, hid_mouse_jiggler);
return hid_mouse_jiggler;
}
void hid_mouse_jiggler_free(HidMouseJiggler* hid_mouse_jiggler) {
furi_assert(hid_mouse_jiggler);
furi_timer_stop(hid_mouse_jiggler->timer);
furi_timer_free(hid_mouse_jiggler->timer);
view_free(hid_mouse_jiggler->view);
free(hid_mouse_jiggler);
}
View* hid_mouse_jiggler_get_view(HidMouseJiggler* hid_mouse_jiggler) {
furi_assert(hid_mouse_jiggler);
return hid_mouse_jiggler->view;
}
void hid_mouse_jiggler_set_connected_status(HidMouseJiggler* hid_mouse_jiggler, bool connected) {
furi_assert(hid_mouse_jiggler);
with_view_model(
hid_mouse_jiggler->view,
HidMouseJigglerModel * model,
{ model->connected = connected; },
true);
}
@@ -0,0 +1,17 @@
#pragma once
#include <gui/view.h>
#define MOUSE_MOVE_SHORT 5
#define MOUSE_MOVE_LONG 20
typedef struct Hid Hid;
typedef struct HidMouseJiggler HidMouseJiggler;
HidMouseJiggler* hid_mouse_jiggler_alloc(Hid* bt_hid);
void hid_mouse_jiggler_free(HidMouseJiggler* hid_mouse_jiggler);
View* hid_mouse_jiggler_get_view(HidMouseJiggler* hid_mouse_jiggler);
void hid_mouse_jiggler_set_connected_status(HidMouseJiggler* hid_mouse_jiggler, bool connected);
@@ -47,47 +47,51 @@ static int32_t music_player_worker_thread_callback(void* context) {
NoteBlockArray_it_t it;
NoteBlockArray_it(it, instance->notes);
if(furi_hal_speaker_acquire(1000)) {
while(instance->should_work) {
if(NoteBlockArray_end_p(it)) {
NoteBlockArray_it(it, instance->notes);
furi_delay_ms(10);
} else {
NoteBlock* note_block = NoteBlockArray_ref(it);
while(instance->should_work) {
if(NoteBlockArray_end_p(it)) {
NoteBlockArray_it(it, instance->notes);
furi_delay_ms(10);
} else {
NoteBlock* note_block = NoteBlockArray_ref(it);
float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE;
float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4);
float duration = 60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm /
note_block->duration;
uint32_t dots = note_block->dots;
while(dots > 0) {
duration += duration / 2;
dots--;
}
uint32_t next_tick = furi_get_tick() + duration;
float volume = instance->volume;
float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE;
float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4);
float duration =
60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm / note_block->duration;
uint32_t dots = note_block->dots;
while(dots > 0) {
duration += duration / 2;
dots--;
if(instance->callback) {
instance->callback(
note_block->semitone,
note_block->dots,
note_block->duration,
0.0,
instance->callback_context);
}
furi_hal_speaker_stop();
furi_hal_speaker_start(frequency, volume);
while(instance->should_work && furi_get_tick() < next_tick) {
volume *= 0.9945679;
furi_hal_speaker_set_volume(volume);
furi_delay_ms(2);
}
NoteBlockArray_next(it);
}
uint32_t next_tick = furi_get_tick() + duration;
float volume = instance->volume;
if(instance->callback) {
instance->callback(
note_block->semitone,
note_block->dots,
note_block->duration,
0.0,
instance->callback_context);
}
furi_hal_speaker_stop();
furi_hal_speaker_start(frequency, volume);
while(instance->should_work && furi_get_tick() < next_tick) {
volume *= 0.9945679;
furi_hal_speaker_set_volume(volume);
furi_delay_ms(2);
}
NoteBlockArray_next(it);
}
}
furi_hal_speaker_stop();
furi_hal_speaker_stop();
furi_hal_speaker_release();
} else {
FURI_LOG_E(TAG, "Speaker system is busy with another process.");
}
return 0;
}
@@ -3,7 +3,7 @@
#include <furi.h>
#include <furi_hal.h>
#define WS_VERSION_APP "0.5"
#define WS_VERSION_APP "0.6"
#define WS_DEVELOPED "SkorP"
#define WS_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

@@ -135,6 +135,10 @@ static void ws_protocol_nexus_th_remote_controller(WSBlockGeneric* instance) {
}
instance->humidity = instance->data & 0xFF;
if(instance->humidity > 95)
instance->humidity = 95;
else if(instance->humidity < 20)
instance->humidity = 20;
}
void ws_protocol_decoder_nexus_th_feed(void* context, bool level, uint32_t duration) {
@@ -0,0 +1,331 @@
#include "oregon_v1.h"
#include <lib/toolbox/manchester_decoder.h>
#define TAG "WSProtocolOregon_V1"
/*
* Help
* https://github.dev/merbanan/rtl_433/blob/bb1be7f186ac0fdb7dc5d77693847d96fb95281e/src/devices/oregon_scientific_v1.c
*
* OSv1 protocol.
*
* MC with nominal bit width of 2930 us.
* Pulses are somewhat longer than nominal half-bit width, 1748 us / 3216 us,
* Gaps are somewhat shorter than nominal half-bit width, 1176 us / 2640 us.
* After 12 preamble bits there is 4200 us gap, 5780 us pulse, 5200 us gap.
* And next 32 bit data
*
* Care must be taken with the gap after the sync pulse since it
* is outside of the normal clocking. Because of this a data stream
* beginning with a 0 will have data in this gap.
*
*
* Data is in reverse order of bits
* RevBit(data32bit)=> tib23atad
*
* tib23atad => xxxxxxxx | busuTTTT | ttttzzzz | ccuuiiii
*
* - i: ID
* - x: CRC;
* - u: unknown;
* - b: battery low; flag to indicate low battery voltage
* - s: temperature sign
* - T: BCD, Temperature; in °C * 10
* - t: BCD, Temperature; in °C * 1
* - z: BCD, Temperature; in °C * 0.1
* - c: Channel 00=CH1, 01=CH2, 10=CH3
*
*/
#define OREGON_V1_HEADER_OK 0xFF
static const SubGhzBlockConst ws_protocol_oregon_v1_const = {
.te_short = 1465,
.te_long = 2930,
.te_delta = 350,
.min_count_bit_for_found = 32,
};
struct WSProtocolDecoderOregon_V1 {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
WSBlockGeneric generic;
ManchesterState manchester_state;
uint16_t header_count;
uint8_t first_bit;
};
struct WSProtocolEncoderOregon_V1 {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
WSBlockGeneric generic;
};
typedef enum {
Oregon_V1DecoderStepReset = 0,
Oregon_V1DecoderStepFoundPreamble,
Oregon_V1DecoderStepParse,
} Oregon_V1DecoderStep;
const SubGhzProtocolDecoder ws_protocol_oregon_v1_decoder = {
.alloc = ws_protocol_decoder_oregon_v1_alloc,
.free = ws_protocol_decoder_oregon_v1_free,
.feed = ws_protocol_decoder_oregon_v1_feed,
.reset = ws_protocol_decoder_oregon_v1_reset,
.get_hash_data = ws_protocol_decoder_oregon_v1_get_hash_data,
.serialize = ws_protocol_decoder_oregon_v1_serialize,
.deserialize = ws_protocol_decoder_oregon_v1_deserialize,
.get_string = ws_protocol_decoder_oregon_v1_get_string,
};
const SubGhzProtocolEncoder ws_protocol_oregon_v1_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol ws_protocol_oregon_v1 = {
.name = WS_PROTOCOL_OREGON_V1_NAME,
.type = SubGhzProtocolWeatherStation,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &ws_protocol_oregon_v1_decoder,
.encoder = &ws_protocol_oregon_v1_encoder,
};
void* ws_protocol_decoder_oregon_v1_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
WSProtocolDecoderOregon_V1* instance = malloc(sizeof(WSProtocolDecoderOregon_V1));
instance->base.protocol = &ws_protocol_oregon_v1;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void ws_protocol_decoder_oregon_v1_free(void* context) {
furi_assert(context);
WSProtocolDecoderOregon_V1* instance = context;
free(instance);
}
void ws_protocol_decoder_oregon_v1_reset(void* context) {
furi_assert(context);
WSProtocolDecoderOregon_V1* instance = context;
instance->decoder.parser_step = Oregon_V1DecoderStepReset;
}
static bool ws_protocol_oregon_v1_check(WSProtocolDecoderOregon_V1* instance) {
if(!instance->decoder.decode_data) return false;
uint64_t data = subghz_protocol_blocks_reverse_key(instance->decoder.decode_data, 32);
uint16_t crc = (data & 0xff) + ((data >> 8) & 0xff) + ((data >> 16) & 0xff);
crc = (crc & 0xff) + ((crc >> 8) & 0xff);
return (crc == ((data >> 24) & 0xFF));
}
/**
* Analysis of received data
* @param instance Pointer to a WSBlockGeneric* instance
*/
static void ws_protocol_oregon_v1_remote_controller(WSBlockGeneric* instance) {
uint64_t data = subghz_protocol_blocks_reverse_key(instance->data, 32);
instance->id = data & 0xFF;
instance->channel = ((data >> 6) & 0x03) + 1;
float temp_raw =
((data >> 8) & 0x0F) * 0.1f + ((data >> 12) & 0x0F) + ((data >> 16) & 0x0F) * 10.0f;
if(!((data >> 21) & 1)) {
instance->temp = temp_raw;
} else {
instance->temp = -temp_raw;
}
instance->battery_low = !(instance->data >> 23) & 1;
instance->btn = WS_NO_BTN;
instance->humidity = WS_NO_HUMIDITY;
}
void ws_protocol_decoder_oregon_v1_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
WSProtocolDecoderOregon_V1* instance = context;
ManchesterEvent event = ManchesterEventReset;
switch(instance->decoder.parser_step) {
case Oregon_V1DecoderStepReset:
if((level) && (DURATION_DIFF(duration, ws_protocol_oregon_v1_const.te_short) <
ws_protocol_oregon_v1_const.te_delta)) {
instance->decoder.parser_step = Oregon_V1DecoderStepFoundPreamble;
instance->decoder.te_last = duration;
instance->header_count = 0;
}
break;
case Oregon_V1DecoderStepFoundPreamble:
if(level) {
//keep high levels, if they suit our durations
if((DURATION_DIFF(duration, ws_protocol_oregon_v1_const.te_short) <
ws_protocol_oregon_v1_const.te_delta) ||
(DURATION_DIFF(duration, ws_protocol_oregon_v1_const.te_short * 4) <
ws_protocol_oregon_v1_const.te_delta)) {
instance->decoder.te_last = duration;
} else {
instance->decoder.parser_step = Oregon_V1DecoderStepReset;
}
} else if(
//checking low levels
(DURATION_DIFF(duration, ws_protocol_oregon_v1_const.te_short) <
ws_protocol_oregon_v1_const.te_delta) &&
(DURATION_DIFF(instance->decoder.te_last, ws_protocol_oregon_v1_const.te_short) <
ws_protocol_oregon_v1_const.te_delta)) {
// Found header
instance->header_count++;
} else if(
(DURATION_DIFF(duration, ws_protocol_oregon_v1_const.te_short * 3) <
ws_protocol_oregon_v1_const.te_delta) &&
(DURATION_DIFF(instance->decoder.te_last, ws_protocol_oregon_v1_const.te_short) <
ws_protocol_oregon_v1_const.te_delta)) {
// check header
if(instance->header_count > 7) {
instance->header_count = OREGON_V1_HEADER_OK;
}
} else if(
(instance->header_count == OREGON_V1_HEADER_OK) &&
(DURATION_DIFF(instance->decoder.te_last, ws_protocol_oregon_v1_const.te_short * 4) <
ws_protocol_oregon_v1_const.te_delta)) {
//found all the necessary patterns
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 1;
manchester_advance(
instance->manchester_state,
ManchesterEventReset,
&instance->manchester_state,
NULL);
instance->decoder.parser_step = Oregon_V1DecoderStepParse;
if(duration < ws_protocol_oregon_v1_const.te_short * 4) {
instance->first_bit = 1;
} else {
instance->first_bit = 0;
}
} else {
instance->decoder.parser_step = Oregon_V1DecoderStepReset;
}
break;
case Oregon_V1DecoderStepParse:
if(level) {
if(DURATION_DIFF(duration, ws_protocol_oregon_v1_const.te_short) <
ws_protocol_oregon_v1_const.te_delta) {
event = ManchesterEventShortHigh;
} else if(
DURATION_DIFF(duration, ws_protocol_oregon_v1_const.te_long) <
ws_protocol_oregon_v1_const.te_delta) {
event = ManchesterEventLongHigh;
} else {
instance->decoder.parser_step = Oregon_V1DecoderStepReset;
}
} else {
if(DURATION_DIFF(duration, ws_protocol_oregon_v1_const.te_short) <
ws_protocol_oregon_v1_const.te_delta) {
event = ManchesterEventShortLow;
} else if(
DURATION_DIFF(duration, ws_protocol_oregon_v1_const.te_long) <
ws_protocol_oregon_v1_const.te_delta) {
event = ManchesterEventLongLow;
} else if(duration >= ((uint32_t)ws_protocol_oregon_v1_const.te_long * 2)) {
if(instance->decoder.decode_count_bit ==
ws_protocol_oregon_v1_const.min_count_bit_for_found) {
if(instance->first_bit) {
instance->decoder.decode_data = ~instance->decoder.decode_data | (1 << 31);
}
if(ws_protocol_oregon_v1_check(instance)) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
ws_protocol_oregon_v1_remote_controller(&instance->generic);
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
manchester_advance(
instance->manchester_state,
ManchesterEventReset,
&instance->manchester_state,
NULL);
} else {
instance->decoder.parser_step = Oregon_V1DecoderStepReset;
}
}
if(event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
instance->manchester_state, event, &instance->manchester_state, &data);
if(data_ok) {
instance->decoder.decode_data = (instance->decoder.decode_data << 1) | !data;
instance->decoder.decode_count_bit++;
}
}
break;
}
}
uint8_t ws_protocol_decoder_oregon_v1_get_hash_data(void* context) {
furi_assert(context);
WSProtocolDecoderOregon_V1* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool ws_protocol_decoder_oregon_v1_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
WSProtocolDecoderOregon_V1* instance = context;
return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
}
bool ws_protocol_decoder_oregon_v1_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
WSProtocolDecoderOregon_V1* instance = context;
bool ret = false;
do {
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_oregon_v1_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_oregon_v1_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderOregon_V1* 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);
}
@@ -0,0 +1,79 @@
#pragma once
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/blocks/const.h>
#include <lib/subghz/blocks/decoder.h>
#include <lib/subghz/blocks/encoder.h>
#include "ws_generic.h"
#include <lib/subghz/blocks/math.h>
#define WS_PROTOCOL_OREGON_V1_NAME "Oregon-v1"
typedef struct WSProtocolDecoderOregon_V1 WSProtocolDecoderOregon_V1;
typedef struct WSProtocolEncoderOregon_V1 WSProtocolEncoderOregon_V1;
extern const SubGhzProtocolDecoder ws_protocol_oregon_v1_decoder;
extern const SubGhzProtocolEncoder ws_protocol_oregon_v1_encoder;
extern const SubGhzProtocol ws_protocol_oregon_v1;
/**
* Allocate WSProtocolDecoderOregon_V1.
* @param environment Pointer to a SubGhzEnvironment instance
* @return WSProtocolDecoderOregon_V1* pointer to a WSProtocolDecoderOregon_V1 instance
*/
void* ws_protocol_decoder_oregon_v1_alloc(SubGhzEnvironment* environment);
/**
* Free WSProtocolDecoderOregon_V1.
* @param context Pointer to a WSProtocolDecoderOregon_V1 instance
*/
void ws_protocol_decoder_oregon_v1_free(void* context);
/**
* Reset decoder WSProtocolDecoderOregon_V1.
* @param context Pointer to a WSProtocolDecoderOregon_V1 instance
*/
void ws_protocol_decoder_oregon_v1_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a WSProtocolDecoderOregon_V1 instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void ws_protocol_decoder_oregon_v1_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a WSProtocolDecoderOregon_V1 instance
* @return hash Hash sum
*/
uint8_t ws_protocol_decoder_oregon_v1_get_hash_data(void* context);
/**
* Serialize data WSProtocolDecoderOregon_V1.
* @param context Pointer to a WSProtocolDecoderOregon_V1 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_oregon_v1_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data WSProtocolDecoderOregon_V1.
* @param context Pointer to a WSProtocolDecoderOregon_V1 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
bool ws_protocol_decoder_oregon_v1_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a WSProtocolDecoderOregon_V1 instance
* @param output Resulting text
*/
void ws_protocol_decoder_oregon_v1_get_string(void* context, FuriString* output);
@@ -13,6 +13,8 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = {
&ws_protocol_acurite_592txr,
&ws_protocol_ambient_weather,
&ws_protocol_auriol_th,
&ws_protocol_oregon_v1,
&ws_protocol_tx_8300,
};
const SubGhzProtocolRegistry weather_station_protocol_registry = {
@@ -13,5 +13,7 @@
#include "acurite_592txr.h"
#include "ambient_weather.h"
#include "auriol_hg0601a.h"
#include "oregon_v1.h"
#include "tx_8300.h"
extern const SubGhzProtocolRegistry weather_station_protocol_registry;
@@ -0,0 +1,293 @@
#include "tx_8300.h"
#define TAG "WSProtocolTX_8300"
/*
* Help
* https://github.com/merbanan/rtl_433/blob/master/src/devices/ambientweather_tx8300.c
*
* Ambient Weather TX-8300 (also sold as TFA 30.3211.02).
* 1970us pulse with variable gap (third pulse 3920 us).
* Above 79% humidity, gap after third pulse is 5848 us.
* - Bit 1 : 1970us pulse with 3888 us gap
* - Bit 0 : 1970us pulse with 1936 us gap
* 74 bit (2 bit preamble and 72 bit data => 9 bytes => 18 nibbles)
* The preamble seems to be a repeat counter (00, and 01 seen),
* the first 4 bytes are data,
* the second 4 bytes the same data inverted,
* the last byte is a checksum.
* Preamble format (2 bits):
* [1 bit (0)] [1 bit rolling count]
* Payload format (32 bits):
* HHHHhhhh ??CCNIII IIIITTTT ttttuuuu
* - H = First BCD digit humidity (the MSB might be distorted by the demod)
* - h = Second BCD digit humidity, invalid humidity seems to be 0x0e
* - ? = Likely battery flag, 2 bits
* - C = Channel, 2 bits
* - N = Negative temperature sign bit
* - I = ID, 7-bit
* - T = First BCD digit temperature
* - t = Second BCD digit temperature
* - u = Third BCD digit temperature
* The Checksum seems to covers the 4 data bytes and is something like Fletcher-8.
**/
#define TX_8300_PACKAGE_SIZE 32
static const SubGhzBlockConst ws_protocol_tx_8300_const = {
.te_short = 1940,
.te_long = 3880,
.te_delta = 250,
.min_count_bit_for_found = 72,
};
struct WSProtocolDecoderTX_8300 {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
WSBlockGeneric generic;
uint32_t package_1;
uint32_t package_2;
};
struct WSProtocolEncoderTX_8300 {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
WSBlockGeneric generic;
};
typedef enum {
TX_8300DecoderStepReset = 0,
TX_8300DecoderStepCheckPreambule,
TX_8300DecoderStepSaveDuration,
TX_8300DecoderStepCheckDuration,
} TX_8300DecoderStep;
const SubGhzProtocolDecoder ws_protocol_tx_8300_decoder = {
.alloc = ws_protocol_decoder_tx_8300_alloc,
.free = ws_protocol_decoder_tx_8300_free,
.feed = ws_protocol_decoder_tx_8300_feed,
.reset = ws_protocol_decoder_tx_8300_reset,
.get_hash_data = ws_protocol_decoder_tx_8300_get_hash_data,
.serialize = ws_protocol_decoder_tx_8300_serialize,
.deserialize = ws_protocol_decoder_tx_8300_deserialize,
.get_string = ws_protocol_decoder_tx_8300_get_string,
};
const SubGhzProtocolEncoder ws_protocol_tx_8300_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol ws_protocol_tx_8300 = {
.name = WS_PROTOCOL_TX_8300_NAME,
.type = SubGhzProtocolWeatherStation,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &ws_protocol_tx_8300_decoder,
.encoder = &ws_protocol_tx_8300_encoder,
};
void* ws_protocol_decoder_tx_8300_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
WSProtocolDecoderTX_8300* instance = malloc(sizeof(WSProtocolDecoderTX_8300));
instance->base.protocol = &ws_protocol_tx_8300;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void ws_protocol_decoder_tx_8300_free(void* context) {
furi_assert(context);
WSProtocolDecoderTX_8300* instance = context;
free(instance);
}
void ws_protocol_decoder_tx_8300_reset(void* context) {
furi_assert(context);
WSProtocolDecoderTX_8300* instance = context;
instance->decoder.parser_step = TX_8300DecoderStepReset;
}
static bool ws_protocol_tx_8300_check_crc(WSProtocolDecoderTX_8300* instance) {
if(!instance->package_2) return false;
if(instance->package_1 != ~instance->package_2) return false;
uint16_t x = 0;
uint16_t y = 0;
for(int i = 0; i < 32; i += 4) {
x += (instance->package_1 >> i) & 0x0F;
y += (instance->package_1 >> i) & 0x05;
}
uint8_t crc = (~x & 0xF) << 4 | (~y & 0xF);
return (crc == ((instance->decoder.decode_data) & 0xFF));
}
/**
* Analysis of received data
* @param instance Pointer to a WSBlockGeneric* instance
*/
static void ws_protocol_tx_8300_remote_controller(WSBlockGeneric* instance) {
instance->humidity = (((instance->data >> 28) & 0x0F) * 10) + ((instance->data >> 24) & 0x0F);
instance->btn = WS_NO_BTN;
if(!((instance->data >> 22) & 0x03))
instance->battery_low = 0;
else
instance->battery_low = 1;
instance->channel = (instance->data >> 20) & 0x03;
instance->id = (instance->data >> 12) & 0x7F;
float temp_raw = ((instance->data >> 8) & 0x0F) * 10.0f + ((instance->data >> 4) & 0x0F) +
(instance->data & 0x0F) * 0.1f;
if(!((instance->data >> 19) & 1)) {
instance->temp = temp_raw;
} else {
instance->temp = -temp_raw;
}
}
void ws_protocol_decoder_tx_8300_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
WSProtocolDecoderTX_8300* instance = context;
switch(instance->decoder.parser_step) {
case TX_8300DecoderStepReset:
if((level) && (DURATION_DIFF(duration, ws_protocol_tx_8300_const.te_short * 2) <
ws_protocol_tx_8300_const.te_delta)) {
instance->decoder.parser_step = TX_8300DecoderStepCheckPreambule;
}
break;
case TX_8300DecoderStepCheckPreambule:
if((!level) && ((DURATION_DIFF(duration, ws_protocol_tx_8300_const.te_short * 2) <
ws_protocol_tx_8300_const.te_delta) ||
(DURATION_DIFF(duration, ws_protocol_tx_8300_const.te_short * 3) <
ws_protocol_tx_8300_const.te_delta))) {
instance->decoder.parser_step = TX_8300DecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 1;
instance->package_1 = 0;
instance->package_2 = 0;
} else {
instance->decoder.parser_step = TX_8300DecoderStepReset;
}
break;
case TX_8300DecoderStepSaveDuration:
if(level) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = TX_8300DecoderStepCheckDuration;
} else {
instance->decoder.parser_step = TX_8300DecoderStepReset;
}
break;
case TX_8300DecoderStepCheckDuration:
if(!level) {
if(duration >= ((uint32_t)ws_protocol_tx_8300_const.te_short * 5)) {
//Found syncPostfix
if((instance->decoder.decode_count_bit ==
ws_protocol_tx_8300_const.min_count_bit_for_found) &&
ws_protocol_tx_8300_check_crc(instance)) {
instance->generic.data = instance->package_1;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
ws_protocol_tx_8300_remote_controller(&instance->generic);
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 1;
instance->decoder.parser_step = TX_8300DecoderStepReset;
break;
} else if(
(DURATION_DIFF(instance->decoder.te_last, ws_protocol_tx_8300_const.te_short) <
ws_protocol_tx_8300_const.te_delta) &&
(DURATION_DIFF(duration, ws_protocol_tx_8300_const.te_long) <
ws_protocol_tx_8300_const.te_delta * 2)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = TX_8300DecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, ws_protocol_tx_8300_const.te_short) <
ws_protocol_tx_8300_const.te_delta) &&
(DURATION_DIFF(duration, ws_protocol_tx_8300_const.te_short) <
ws_protocol_tx_8300_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = TX_8300DecoderStepSaveDuration;
} else {
instance->decoder.parser_step = TX_8300DecoderStepReset;
}
if(instance->decoder.decode_count_bit == TX_8300_PACKAGE_SIZE) {
instance->package_1 = instance->decoder.decode_data;
instance->decoder.decode_data = 0;
} else if(instance->decoder.decode_count_bit == TX_8300_PACKAGE_SIZE * 2) {
instance->package_2 = instance->decoder.decode_data;
instance->decoder.decode_data = 0;
}
} else {
instance->decoder.parser_step = TX_8300DecoderStepReset;
}
break;
}
}
uint8_t ws_protocol_decoder_tx_8300_get_hash_data(void* context) {
furi_assert(context);
WSProtocolDecoderTX_8300* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool ws_protocol_decoder_tx_8300_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
WSProtocolDecoderTX_8300* instance = context;
return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
}
bool ws_protocol_decoder_tx_8300_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
WSProtocolDecoderTX_8300* instance = context;
bool ret = false;
do {
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit != ws_protocol_tx_8300_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_tx_8300_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderTX_8300* 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);
}
@@ -0,0 +1,79 @@
#pragma once
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/blocks/const.h>
#include <lib/subghz/blocks/decoder.h>
#include <lib/subghz/blocks/encoder.h>
#include "ws_generic.h"
#include <lib/subghz/blocks/math.h>
#define WS_PROTOCOL_TX_8300_NAME "TX8300"
typedef struct WSProtocolDecoderTX_8300 WSProtocolDecoderTX_8300;
typedef struct WSProtocolEncoderTX_8300 WSProtocolEncoderTX_8300;
extern const SubGhzProtocolDecoder ws_protocol_tx_8300_decoder;
extern const SubGhzProtocolEncoder ws_protocol_tx_8300_encoder;
extern const SubGhzProtocol ws_protocol_tx_8300;
/**
* Allocate WSProtocolDecoderTX_8300.
* @param environment Pointer to a SubGhzEnvironment instance
* @return WSProtocolDecoderTX_8300* pointer to a WSProtocolDecoderTX_8300 instance
*/
void* ws_protocol_decoder_tx_8300_alloc(SubGhzEnvironment* environment);
/**
* Free WSProtocolDecoderTX_8300.
* @param context Pointer to a WSProtocolDecoderTX_8300 instance
*/
void ws_protocol_decoder_tx_8300_free(void* context);
/**
* Reset decoder WSProtocolDecoderTX_8300.
* @param context Pointer to a WSProtocolDecoderTX_8300 instance
*/
void ws_protocol_decoder_tx_8300_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a WSProtocolDecoderTX_8300 instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void ws_protocol_decoder_tx_8300_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a WSProtocolDecoderTX_8300 instance
* @return hash Hash sum
*/
uint8_t ws_protocol_decoder_tx_8300_get_hash_data(void* context);
/**
* Serialize data WSProtocolDecoderTX_8300.
* @param context Pointer to a WSProtocolDecoderTX_8300 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_tx_8300_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data WSProtocolDecoderTX_8300.
* @param context Pointer to a WSProtocolDecoderTX_8300 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
bool ws_protocol_decoder_tx_8300_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a WSProtocolDecoderTX_8300 instance
* @param output Resulting text
*/
void ws_protocol_decoder_tx_8300_get_string(void* context, FuriString* output);
@@ -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,82 @@ 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);
uint8_t temp_x1 = 47;
uint8_t temp_x2 = 38;
if(model->generic->temp < -9.0) {
temp_x1 = 49;
temp_x2 = 40;
}
canvas_draw_str_aligned(canvas, temp_x1, 47, AlignRight, AlignTop, buffer);
canvas_draw_circle(canvas, temp_x2, 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 +140,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 +160,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 +196,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,
+32 -39
View File
@@ -11,6 +11,12 @@
#define VCP_IF_NUM 0
#ifdef CLI_VCP_DEBUG
#define VCP_DEBUG(...) FURI_LOG_D(TAG, __VA_ARGS__)
#else
#define VCP_DEBUG(...)
#endif
typedef enum {
VcpEvtStop = (1 << 0),
VcpEvtConnect = (1 << 1),
@@ -104,9 +110,8 @@ static int32_t vcp_worker(void* context) {
// VCP session opened
if(flags & VcpEvtConnect) {
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "Connect");
#endif
VCP_DEBUG("Connect");
if(vcp->connected == false) {
vcp->connected = true;
furi_stream_buffer_send(vcp->rx_stream, &ascii_soh, 1, FuriWaitForever);
@@ -115,9 +120,8 @@ static int32_t vcp_worker(void* context) {
// VCP session closed
if(flags & VcpEvtDisconnect) {
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "Disconnect");
#endif
VCP_DEBUG("Disconnect");
if(vcp->connected == true) {
vcp->connected = false;
furi_stream_buffer_receive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
@@ -127,9 +131,8 @@ static int32_t vcp_worker(void* context) {
// Rx buffer was read, maybe there is enough space for new data?
if((flags & VcpEvtStreamRx) && (missed_rx > 0)) {
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "StreamRx");
#endif
VCP_DEBUG("StreamRx");
if(furi_stream_buffer_spaces_available(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
flags |= VcpEvtRx;
missed_rx--;
@@ -140,9 +143,8 @@ static int32_t vcp_worker(void* context) {
if(flags & VcpEvtRx) {
if(furi_stream_buffer_spaces_available(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
int32_t len = furi_hal_cdc_receive(VCP_IF_NUM, vcp->data_buffer, USB_CDC_PKT_LEN);
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "Rx %d", len);
#endif
VCP_DEBUG("Rx %ld", len);
if(len > 0) {
furi_check(
furi_stream_buffer_send(
@@ -150,18 +152,15 @@ static int32_t vcp_worker(void* context) {
(size_t)len);
}
} else {
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "Rx missed");
#endif
VCP_DEBUG("Rx missed");
missed_rx++;
}
}
// New data in Tx buffer
if(flags & VcpEvtStreamTx) {
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "StreamTx");
#endif
VCP_DEBUG("StreamTx");
if(tx_idle) {
flags |= VcpEvtTx;
}
@@ -171,9 +170,9 @@ static int32_t vcp_worker(void* context) {
if(flags & VcpEvtTx) {
size_t len =
furi_stream_buffer_receive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "Tx %d", len);
#endif
VCP_DEBUG("Tx %d", len);
if(len > 0) { // Some data left in Tx buffer. Sending it now
tx_idle = false;
furi_hal_cdc_send(VCP_IF_NUM, vcp->data_buffer, len);
@@ -216,9 +215,7 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) {
return 0;
}
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "rx %u start", size);
#endif
VCP_DEBUG("rx %u start", size);
size_t rx_cnt = 0;
@@ -227,19 +224,21 @@ static size_t cli_vcp_rx(uint8_t* buffer, size_t size, uint32_t timeout) {
if(batch_size > VCP_RX_BUF_SIZE) batch_size = VCP_RX_BUF_SIZE;
size_t len = furi_stream_buffer_receive(vcp->rx_stream, buffer, batch_size, timeout);
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "rx %u ", batch_size);
#endif
VCP_DEBUG("rx %u ", batch_size);
if(len == 0) break;
if(vcp->running == false) {
// EOT command is received after VCP session close
rx_cnt += len;
break;
}
furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamRx);
size -= len;
buffer += len;
rx_cnt += len;
}
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "rx %u end", size);
#endif
VCP_DEBUG("rx %u end", size);
return rx_cnt;
}
@@ -251,9 +250,7 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
return;
}
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "tx %u start", size);
#endif
VCP_DEBUG("tx %u start", size);
while(size > 0 && vcp->connected) {
size_t batch_size = size;
@@ -261,17 +258,13 @@ static void cli_vcp_tx(const uint8_t* buffer, size_t size) {
furi_stream_buffer_send(vcp->tx_stream, buffer, batch_size, FuriWaitForever);
furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtStreamTx);
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "tx %u", batch_size);
#endif
VCP_DEBUG("tx %u", batch_size);
size -= batch_size;
buffer += batch_size;
}
#ifdef CLI_VCP_DEBUG
FURI_LOG_D(TAG, "tx %u end", size);
#endif
VCP_DEBUG("tx %u end", size);
}
static void cli_vcp_tx_stdout(const char* data, size_t size) {
@@ -52,6 +52,7 @@ struct AnimationManager {
FuriString* freezed_animation_name;
int32_t freezed_animation_time_left;
ViewStack* view_stack;
bool dummy_mode;
};
static StorageAnimation*
@@ -93,6 +94,12 @@ void animation_manager_set_interact_callback(
animation_manager->interact_callback = callback;
}
void animation_manager_set_dummy_mode_state(AnimationManager* animation_manager, bool enabled) {
furi_assert(animation_manager);
animation_manager->dummy_mode = enabled;
animation_manager_start_new_idle(animation_manager);
}
static void animation_manager_check_blocking_callback(const void* message, void* context) {
const StorageEvent* storage_event = message;
@@ -363,7 +370,9 @@ static bool animation_manager_is_valid_idle_animation(
static StorageAnimation*
animation_manager_select_idle_animation(AnimationManager* animation_manager) {
UNUSED(animation_manager);
if(animation_manager->dummy_mode) {
return animation_storage_find_animation(HARDCODED_ANIMATION_NAME);
}
StorageAnimationList_t animation_list;
StorageAnimationList_init(animation_list);
animation_storage_fill_animation_list(&animation_list);
@@ -157,3 +157,11 @@ void animation_manager_unload_and_stall_animation(AnimationManager* animation_ma
* @animation_manager instance
*/
void animation_manager_load_and_continue_animation(AnimationManager* animation_manager);
/**
* Enable or disable dummy mode backgrounds of animation manager.
*
* @animation_manager instance
* @enabled bool
*/
void animation_manager_set_dummy_mode_state(AnimationManager* animation_manager, bool enabled);
+3
View File
@@ -144,6 +144,7 @@ void desktop_unlock(Desktop* desktop) {
void desktop_set_dummy_mode_state(Desktop* desktop, bool enabled) {
view_port_enabled_set(desktop->dummy_mode_icon_viewport, enabled);
desktop_main_set_dummy_mode_state(desktop->main_view, enabled);
animation_manager_set_dummy_mode_state(desktop->animation_manager, enabled);
desktop->settings.dummy_mode = enabled;
DESKTOP_SETTINGS_SAVE(&desktop->settings);
}
@@ -330,6 +331,8 @@ int32_t desktop_srv(void* p) {
view_port_enabled_set(desktop->dummy_mode_icon_viewport, desktop->settings.dummy_mode);
desktop_main_set_dummy_mode_state(desktop->main_view, desktop->settings.dummy_mode);
animation_manager_set_dummy_mode_state(
desktop->animation_manager, desktop->settings.dummy_mode);
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
@@ -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) {
+30 -28
View File
@@ -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);
}
},
@@ -0,0 +1,9 @@
App(
appid="locale",
name="LocaleSrv",
apptype=FlipperAppType.STARTUP,
entry_point="locale_on_system_start",
cdefines=["SRV_LOCALE"],
order=90,
sdk_headers=["locale.h"],
)
+109
View File
@@ -0,0 +1,109 @@
#include "locale.h"
#define TAG "LocaleSrv"
LocaleMeasurementUnits locale_get_measurement_unit(void) {
return (LocaleMeasurementUnits)furi_hal_rtc_get_locale_units();
}
void locale_set_measurement_unit(LocaleMeasurementUnits format) {
furi_hal_rtc_set_locale_units((FuriHalRtcLocaleUnits)format);
}
LocaleTimeFormat locale_get_time_format(void) {
return (LocaleTimeFormat)furi_hal_rtc_get_locale_timeformat();
}
void locale_set_time_format(LocaleTimeFormat format) {
furi_hal_rtc_set_locale_timeformat((FuriHalRtcLocaleTimeFormat)format);
}
LocaleDateFormat locale_get_date_format(void) {
return (LocaleDateFormat)furi_hal_rtc_get_locale_dateformat();
}
void locale_set_date_format(LocaleDateFormat format) {
furi_hal_rtc_set_locale_dateformat((FuriHalRtcLocaleDateFormat)format);
}
float locale_fahrenheit_to_celsius(float temp_f) {
return (temp_f - 32.f) / 1.8f;
}
float locale_celsius_to_fahrenheit(float temp_c) {
return (temp_c * 1.8f + 32.f);
}
void locale_format_time(
FuriString* out_str,
const FuriHalRtcDateTime* datetime,
const LocaleTimeFormat format,
const bool show_seconds) {
furi_assert(out_str);
furi_assert(datetime);
uint8_t hours = datetime->hour;
uint8_t am_pm = 0;
if(format == LocaleTimeFormat12h) {
if(hours > 12) {
hours -= 12;
am_pm = 2;
} else {
am_pm = 1;
}
}
if(show_seconds) {
furi_string_printf(out_str, "%02u:%02u:%02u", hours, datetime->minute, datetime->second);
} else {
furi_string_printf(out_str, "%02u:%02u", hours, datetime->minute);
}
if(am_pm > 0) {
furi_string_cat_printf(out_str, " %s", (am_pm == 1) ? ("AM") : ("PM"));
}
}
void locale_format_date(
FuriString* out_str,
const FuriHalRtcDateTime* datetime,
const LocaleDateFormat format,
const char* separator) {
furi_assert(out_str);
furi_assert(datetime);
furi_assert(separator);
if(format == LocaleDateFormatDMY) {
furi_string_printf(
out_str,
"%02u%s%02u%s%04u",
datetime->day,
separator,
datetime->month,
separator,
datetime->year);
} else if(format == LocaleDateFormatMDY) {
furi_string_printf(
out_str,
"%02u%s%02u%s%04u",
datetime->month,
separator,
datetime->day,
separator,
datetime->year);
} else {
furi_string_printf(
out_str,
"%04u%s%02u%s%02u",
datetime->year,
separator,
datetime->month,
separator,
datetime->day);
}
}
int32_t locale_on_system_start(void* p) {
UNUSED(p);
return 0;
}
+107
View File
@@ -0,0 +1,107 @@
#pragma once
#include <stdbool.h>
#include <furi.h>
#include <furi_hal.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
LocaleMeasurementUnitsMetric = 0, /**< Metric measurement units */
LocaleMeasurementUnitsImperial = 1, /**< Imperial measurement units */
} LocaleMeasurementUnits;
typedef enum {
LocaleTimeFormat24h = 0, /**< 24-hour format */
LocaleTimeFormat12h = 1, /**< 12-hour format */
} LocaleTimeFormat;
typedef enum {
LocaleDateFormatDMY = 0, /**< Day/Month/Year */
LocaleDateFormatMDY = 1, /**< Month/Day/Year */
LocaleDateFormatYMD = 2, /**< Year/Month/Day */
} LocaleDateFormat;
/** Get Locale measurement units
*
* @return The locale measurement units.
*/
LocaleMeasurementUnits locale_get_measurement_unit();
/** Set locale measurement units
*
* @param[in] format The locale measurements units
*/
void locale_set_measurement_unit(LocaleMeasurementUnits format);
/** Convert Fahrenheit to Celsius
*
* @param[in] temp_f The Temperature in Fahrenheit
*
* @return The Temperature in Celsius
*/
float locale_fahrenheit_to_celsius(float temp_f);
/** Convert Celsius to Fahrenheit
*
* @param[in] temp_c The Temperature in Celsius
*
* @return The Temperature in Fahrenheit
*/
float locale_celsius_to_fahrenheit(float temp_c);
/** Get Locale time format
*
* @return The locale time format.
*/
LocaleTimeFormat locale_get_time_format();
/** Set Locale Time Format
*
* @param[in] format The Locale Time Format
*/
void locale_set_time_format(LocaleTimeFormat format);
/** Format time to furi string
*
* @param[out] out_str The FuriString to store formatted time
* @param[in] datetime Pointer to the datetime
* @param[in] format The Locale Time Format
* @param[in] show_seconds The show seconds flag
*/
void locale_format_time(
FuriString* out_str,
const FuriHalRtcDateTime* datetime,
const LocaleTimeFormat format,
const bool show_seconds);
/** Get Locale DateFormat
*
* @return The Locale DateFormat.
*/
LocaleDateFormat locale_get_date_format();
/** Set Locale DateFormat
*
* @param[in] format The Locale DateFormat
*/
void locale_set_date_format(LocaleDateFormat format);
/** Format date to furi string
*
* @param[out] out_str The FuriString to store formatted date
* @param[in] datetime Pointer to the datetime
* @param[in] format The format
* @param[in] separator The separator
*/
void locale_format_date(
FuriString* out_str,
const FuriHalRtcDateTime* datetime,
const LocaleDateFormat format,
const char* separator);
#ifdef __cplusplus
}
#endif
@@ -150,11 +150,16 @@ void notification_vibro_off() {
}
void notification_sound_on(float freq, float volume) {
furi_hal_speaker_start(freq, volume);
if(furi_hal_speaker_is_mine() || furi_hal_speaker_acquire(30)) {
furi_hal_speaker_start(freq, volume);
}
}
void notification_sound_off() {
furi_hal_speaker_stop();
if(furi_hal_speaker_is_mine()) {
furi_hal_speaker_stop();
furi_hal_speaker_release();
}
}
// display timer
+1 -1
View File
@@ -3,7 +3,7 @@ App(
name="System",
apptype=FlipperAppType.SETTINGS,
entry_point="system_settings_app",
requires=["gui"],
requires=["gui", "locale"],
stack_size=1 * 1024,
order=70,
)
@@ -1,6 +1,7 @@
#include "system_settings.h"
#include <loader/loader.h>
#include <lib/toolbox/value_index.h>
#include <locale/locale.h>
const char* const log_level_text[] = {
"Default",
@@ -70,6 +71,59 @@ static void heap_trace_mode_changed(VariableItem* item) {
furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[index]);
}
const char* const mesurement_units_text[] = {
"Metric",
"Imperial",
};
const uint32_t mesurement_units_value[] = {
LocaleMeasurementUnitsMetric,
LocaleMeasurementUnitsImperial,
};
static void mesurement_units_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, mesurement_units_text[index]);
locale_set_measurement_unit(mesurement_units_value[index]);
}
const char* const time_format_text[] = {
"24h",
"12h",
};
const uint32_t time_format_value[] = {
LocaleTimeFormat24h,
LocaleTimeFormat12h,
};
static void time_format_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, time_format_text[index]);
locale_set_time_format(time_format_value[index]);
}
const char* const date_format_text[] = {
"D/M/Y",
"M/D/Y",
"Y/M/D",
};
const uint32_t date_format_value[] = {
LocaleDateFormatDMY,
LocaleDateFormatMDY,
LocaleDateFormatYMD,
};
static void date_format_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, date_format_text[index]);
locale_set_date_format(date_format_value[index]);
}
static uint32_t system_settings_exit(void* context) {
UNUSED(context);
return VIEW_NONE;
@@ -91,6 +145,31 @@ SystemSettings* system_settings_alloc() {
uint8_t value_index;
app->var_item_list = variable_item_list_alloc();
item = variable_item_list_add(
app->var_item_list,
"Units",
COUNT_OF(mesurement_units_text),
mesurement_units_changed,
app);
value_index = value_index_uint32(
locale_get_measurement_unit(), mesurement_units_value, COUNT_OF(mesurement_units_value));
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, mesurement_units_text[value_index]);
item = variable_item_list_add(
app->var_item_list, "Time Format", COUNT_OF(time_format_text), time_format_changed, app);
value_index = value_index_uint32(
locale_get_time_format(), time_format_value, COUNT_OF(time_format_value));
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, time_format_text[value_index]);
item = variable_item_list_add(
app->var_item_list, "Date Format", COUNT_OF(date_format_text), date_format_changed, app);
value_index = value_index_uint32(
locale_get_date_format(), date_format_value, COUNT_OF(date_format_value));
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, date_format_text[value_index]);
item = variable_item_list_add(
app->var_item_list, "Log Level", COUNT_OF(log_level_text), log_level_changed, app);
value_index = value_index_uint32(
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,23 @@
Filetype: Flipper Animation
Version: 1
Width: 128
Height: 64
Passive frames: 10
Active frames: 18
Frames order: 0 1 2 1 0 1 2 1 0 1 2 3 4 5 6 5 4 7 2 8 9 10 11 10 9 10 11 12
Active cycles: 1
Frame rate: 2
Duration: 3600
Active cooldown: 7
Bubble slots: 1
Slot: 0
X: 11
Y: 19
Text: HAPPY\nHOLIDAYS!
AlignH: Right
AlignV: Center
StartFrame: 22
EndFrame: 27
+10 -3
View File
@@ -36,10 +36,10 @@ Min level: 1
Max level: 1
Weight: 3
Name: L2_Wake_up_128x64
Name: L1_Happy_holidays_128x64
Min butthurt: 0
Max butthurt: 12
Min level: 2
Max butthurt: 14
Min level: 1
Max level: 3
Weight: 4
@@ -92,6 +92,13 @@ Min level: 1
Max level: 3
Weight: 3
Name: L2_Wake_up_128x64
Min butthurt: 0
Max butthurt: 12
Min level: 2
Max level: 3
Weight: 4
Name: L2_Furippa2_128x64
Min butthurt: 0
Max butthurt: 6
@@ -244,6 +244,7 @@ FEE470A4CB58
1F1A0A111B5B
1F1FFE000000
2031D1E57A3B
# HID Key B
204752454154
21A600056CB0
22729A9BD40F
@@ -292,6 +293,7 @@ FEE470A4CB58
45635EF66EF3
476242304C53
484558414354
# HID Key A
484944204953
484A57696F4A
48734389EDC3
@@ -1226,6 +1228,7 @@ C41514DEFC07
ABFEDC124578
046154274C11
5429D67E1F57
# SMARTair Key B
E7316853E731
CD7FFFF81C4A
F253C30568C4
@@ -1308,4 +1311,4 @@ CE99FBC8BD26
# PIK Comfort Moscow keys (ISBC Mifare Plus SE 1K)
009FB42D98ED
002E626E2820
002E626E2820
@@ -0,0 +1,47 @@
## From https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/iclass_default_keys.dic
# AA1
AEA684A6DAB23278
# key1/Kc from PicoPass 2k documentation
7665544332211000
# SAGEM
0123456789ABCDEF
# from loclass demo file.
5b7c62c491c11b39
# Kd from PicoPass 2k documentation
F0E1D2C3B4A59687
# PicoPass Default Exchange Key
5CBCF1DA45D5FB4F
# From HID multiclassSE reader
31ad7ebd2f282168
# From pastebin: https://pastebin.com/uHqpjiuU
6EFD46EFCBB3C875
E033CA419AEE43F9
# iCopy-x DRM keys
# iCL tags
2020666666668888
# iCS tags reversed from the SOs
6666202066668888
# default picopass KD / Page 0 / Book 1
FDCB5A52EA8F3090
237FF9079863DF44
5ADC25FB27181D32
83B881F2936B2E49
43644E61EE866BA5
897034143D016080
82D17B44C0122963
4895CA7DE65E2025
DADAD4C57BE271B7
E41E9EDEF5719ABF
293D275EC3AF9C7F
C3C169251B8A70FB
F41DAF58B20C8B91
28877A609EC0DD2B
66584C91EE80D5E5
C1B74D7478053AE2
# default iCLASS RFIDeas
6B65797374726B72
+8
View File
@@ -0,0 +1,8 @@
Filetype: Flipper SubGhz Key File
Version: 1
Frequency: 433920000
Preset: FuriHalSubGhzPresetOok650Async
Protocol: SMC5326
Bit: 25
Key: 00 00 00 00 01 7D 55 80
TE: 210
+7
View File
@@ -0,0 +1,7 @@
Filetype: Flipper SubGhz RAW File
Version: 1
Frequency: 433920000
Preset: FuriHalSubGhzPresetOok650Async
Protocol: RAW
RAW_Data: 2442 -312 275 -972 949 -310 941 -322 923 -342 921 -352 923 -334 281 -954 945 -350 279 -958 907 -354 289 -980 909 -352 281 -962 907 -330 311 -964 913 -350 317 -930 933 -344 921 -352 893 -330 311 -954 943 -318 315 -958 909 -324 947 -7854 953 -322 289 -948 939 -354 927 -332 911 -324 943 -344 917 -318 317 -964 905 -344 303 -942 947 -312 319 -960 913 -348 281 -958 941 -322 295 -978 905 -350 279 -962 931 -328 947 -324 939 -346 267 -964 935 -348 283 -938 953 -318 931 -7868 935 -346 269 -968 953 -310 941 -322 921 -330 935 -342 931 -318 311 -962 939 -290 337 -950 909 -352 317 -924 943 -324 313 -938 941 -318 317 -932 939 -344 301 -938 933 -350 921 -322 959 -310 301 -942 933 -352 317 -926 957 -314 919 -7868 943 -314 317 -958 909 -322 951 -344 919 -352 921 -324 937 -326 281 -964 941 -318 317 -930 939 -344 301 -938 933 -352 281 -962 953 -314 317 -922 933 -330 315 -954 943 -318 921 -342 943 -320 291 -980 909 -354 281 -962 943 -296 967 -7836 943 -332 309 -950 935 -318 929 -340 943 -320 921 -344 921 -354 283 -960 943 -296 309 -964 945 -318 279 -964 941 -322 333 -944 939 -314 279 -992 903 -342 319 -932 933 -330 931 -340 929 -348 281 -964 935 -334 281 -970 927 -346 921 -7862 951 -314 319 -922 953 -320 923 -346 921 -320 965 -298 943 -324 313 -942 941 -320 317 -930 941 -344 303 -940 945 -312 321 -940 953 -314 303 -960 933 -348 287 -962 911 -352 917 -350 905 -324 333 -918 971 -322 317 -924 945 -324 937 -7872 919 -324 317 -942 941 -318 933 -330 943 -324 943 -310 951 -318 317 -930 939 -344 301 -938 933 -352 317 -926 953 -314 319 -924 939 -324 331 -950 907 -354 315 -926 945 -324 939 -312 953 -318 317 -930 937 -344 301 -940 947 -348 909 -7864 949 -310 319 -956 915 -350 919 -348 905 -322 963 -296 935 -348 317 -922 951 -322 295 -976 939 -314 281 -996 915 -326 307 -940 959 -310 301 -966 935 -346 285 -958 915 -348 921 -348 903 -354 303 -948 911 -350 315 -926 945 -324 941 -7874 943 -290 319 -942 973 -318 929 -314 937 -328 941 -324 939 -310 303 -962 933 -352 285 -962 949 -314 319 -924 951 -320 293 -948 941 -354 283 -962 943 -294 309 -966 943 -320 931 -328 943 -326 311 -940 939 -320 309 -958 933 -338 943 -7840 933 -352 277 -964 941 -322 923 -344 923 -350 931 -310 955 -320 291 -974 907 -350 281 -958 963 -298 313 -956 945 -314 311 -960 937 -312 311 -966 909 -324 319 -944 941 -354 929 -298 945 -324 315 -940
RAW_Data: 943 -354 281 -964 905 -330 933 -7868 951 -324 315 -938 943 -354 893 -330 943 -324 943 -344 919 -318 317 -962 903 -344 301 -974 903 -350 317 -932 931 -342 269 -972 949 -346 285 -938 955 -310 301 -964 935 -348 921 -320 921 -344 301 -940 935 -350 317 -930 929 -318 937 -7872 939 -344 301 -940 947 -346 917 -322 921 -344 923 -352 927 -334 281 -970 925 -334 277 -982 943 -318 317 -932 931 -344 301 -936 935 -350 281 -960 957 -312 303 -960 935 -346 907 -322 929 -344 301 -942 935 -350 317 -924 955 -312 951 -7858 919 -342 309 -940 949 -348 909 -322 923 -344 923 -352 923 -336 317 -924 945 -312 311 -966 921 -340 317 -924 947 -350 281 -958 941 -322 291 -976 905 -350 279 -960 935 -342 943 -320 919 -330 311 -958 943 -320 315 -932 935 -344 919 -7866 957 -312 303 -964 917 -342 945 -320 923 -344 923 -354 929 -298 315 -956 941 -318 315 -960 911 -324 317 -942 939 -354 281 -964 941 -294 311 -968 943 -318 317 -932 937 -330 931 -350 919 -348 283 -960 917 -350 317 -922 939 -322 965 -7864 921 -324 329 -950 909 -354 923 -336 913 -322 947 -344 919 -354 281 -962 941 -294 311 -960 935 -354 281 -962 939 -294 311 -964 937 -354 281 -964 941 -296 309 -964 939 -318 931 -330 945 -324 315 -940 939 -354 281 -964 909 -344 921 -7862 963 -304 307 -976 933 -320 929 -328 941 -324 939 -348 915 -320 317 -930 939 -344 301 -940 965 -320 319 -926 953 -312 303 -960 933 -312 321 -960 913 -348 319 -924 943 -320 959 -310 921 -354 319 -924 943 -324 311 -938 941 -318 957 -7862 943 -318 317 -932 933 -344 925 -352 897 -332 943 -324 943 -346 267 -966 951 -310 321 -960 911 -350 281 -958 949 -320 291 -978 937 -316 279 -964 949 -326 309 -944 943 -314 959 -318 933 -336 317 -934 933 -344 267 -964 937 -350 905 -7896 943 -318 319 -926 955 -314 919 -350 935 -324 941 -294 967 -312 303 -962 933 -348 285 -960 917 -348 317 -922 941 -322 329 -950 907 -354 315 -926 943 -326 313 -940 941 -352 893 -332 949 -324 315 -938 941 -352 283 -962 943 -310 925 -7890 931 -344 269 -968 949 -310 943 -320 923 -350 937 -310 955 -318 317 -930 935 -344 301 -942 947 -346 285 -958 915 -346 317 -924 951 -322 295 -982 905 -352 317 -924 945 -324 941 -346 917 -318 317 -962 905 -330 311 -956 937 -352 897 -7878 939 -354 283 -960 941 -294 965 -312 953 -318 385 -201512 165 -198 265 -526 229 -298 755 -164 61687 -17310 131 -1056 99 -296 195 -296 65 -66 1617
+3 -1
View File
@@ -165,4 +165,6 @@ RAW_Data: 1125 -536 1145 -19444 567 -542 1151 -1086 581 -534 1133 -1084 583 -530
RAW_Data: 317 -144 57 -486 53 -282 115 -585 97 -72 229 -174 257 -440 225 -86 173 -518 243 -167 95 -259 137 -96 694 -58 227 -80 279 -287 71 -72 301 -72 121 -106 51 -84 57 -58 199 -260 143 -288 219 -174 113 -681 115 -172 403 -58 113 -116 113 -432 171 -202 55 -108 95 -212 113 -72 527 -166 95 -212 195 -108 603 -142 239 -296 173 -346 373 -287 53 -80 79 -72 95 -238 95 -312 167 -618 143 -288 95 -72 95 -72 141 -210 55 -258 143 -328 305 -58 87 -86 315 -116 195 -218 85 -290 285 -220 215 -189 201 -58 57 -645 119 -96 71 -144 119 -406 143 -72 191 -72 631 -268 344 -56 115 -260 315 -140 455 -518 57 -58 171 -144 488 -86 219 -232 257 -144 85 -174 171 -260 115 -56 87 -166 197 -58 83 -56 85 -288 113 -410 115 -172 163 -202 113 -58 201 -144 201 -86 143 -264 167 -212 113 -116 139 -72 181 -287 343 -430 201 -260 201 -462 143 -192 301 -230 191 -454 187 -144 315 -164 143 -477 165 -58 201 -114 143 -490 115 -86 201 -58 113 -88 85 -58 203 -198 375 -86 171 -346 95 -88 257 -170 81 -56 143 -172 335 -230 173 -202 133 -471 187 -264 215 -86 115 -198 159 -72 179 -112 195 -116 449 -216 93 -96 167 -216 71 -216 71 -166 235 -86 447 -102 101 -226 195 -213 71 -144 215 -144 215 -261 241 -136 269 -142 263 -311 215 -172 201 -144 265 -168 71 -404 259 -86 85 -230 115 -650 143 -202 749 -512 248 -316 201 -154 71 -96 95 -360 105 -56 57 -432 95 -288 95 -286 95 -96 166 -144 93 -144 167 -150 904 -162 95 -526 287 -244 95 -240 383 -120 167 -394 430 -854 95 -72 143 -194 227 -120 167 -264 405 -144 143 -72 143 -72 141 -120 187 -86 143 -164 170 -96 143 -58 143 -86 402 -166 153 -120 95 -96 69 -96 71 -359 404 -338 71 -225 93 -74 97 -54 161 -114 319 -288 113 -116 459 -202 115 -114 115 -116 143 -86 57 -56 87 -114 85 -375 113 -58 311 -240 203 -288 95 -72 119 -383 213 -384 115 -86 171 -58 53 -104 401 -58 115 -86 373 -116 143 -144 161 -216 406 -72 263 -96 215 -72 95 -94 167 -96 191 -240 95 -94 214 -120 403 -116 200 -114 57 -172 220 -120 137 -364 334 -392 115 -260 199 -116 373 -188 95 -110 143 -172 87 -114 172 -230 57 -316 201 -56 249 -485 171 -202 87 -86 85 -144 345 -86 171 -58 259 -58 295 -120 95 -120 71 -192 635 -118 167 -96 375 -72 119 -120 261 -144 167 -96 95 -96 923 -215 71 -433 71 -477
RAW_Data: 191 -240 85 -72 637 -408 213 -510 261 -168 143 -126 79 -106 167 -72 117 -218 251 -168 119 -96 215 -182 191 -238 517 -116 201 -144 255 -154 97 -94 215 -72 95 -120 71 -288 261 -106 434 -96 606 -232 229 -432 85 -174 343 -58 329 -156 55 -116 259 -144 488 -56 307 -339 115 -202 334 -88 113 -86 57 -174 143 -144 401 -376 85 -240 267 -82 95 -216 137 -158 85 -144 143 -58 221 -308 295 -114 87 -114 301 -120 358 -517 71 -262 191 -144 57 -140 165 -407 53 -262 217 -120 238 -358 119 -357 71 -72 119 -96 428 -72 95 -72 167 -72 93 -240 335 -96 357 -240 173 -230 143 -114 87 -200 143 -232 287 -150 97 -288 71 -72 93 -288 115 -58 143 -230 109 -264 71 -72 119 -72 238 -242 97 -78 163 -86 115 -518 79 -560 205 -449 969 -144 507 -86 231 -114 345 -58 979 -110 85 -288 287 -404 229 -202 57 -274 233 -86 115 -202 632 -230 85 -312 369 -392 460 -450 75 -280 85 -202 201 -86 229 -174 143 -144 233 -528 115 -212 127 -202 287 -172 403 -172 139 -128 165 -138 261 -392 143 -480 142 -189 291 -80 53 -283 167 -140 113 -1008 191 -144 119 -120 71 -193 241 -462 201 -58 143 -344 539 -316 113 -174 85 -116 113 -250 239 -168 405 -168 239 -158 85 -144 115 -86 57 -86 341 -144 171 -202 85 -202 115 -114 719 -88 55 -318 257 -56 254 -86 171 -116 459 -174 171 -329 95 -134 85 -314 431 -306 77 -316 401 -86 173 -404 281 -1073 488 -94 217 -78 101 -98 214 -120 215 -340 403 -535 143 -564 115 -116 199 -58 85 -174 315 -58 335 -136 55 -260 143 -144 229 -460 143 -58 143 -144 171 -202 115 -374 291 -130 339 -82 143 -58 171 -58 201 -86 85 -174 1022 -56 85 -82 255 -240 103 -202 431 -278 95 -216 119 -72 71 -96 71 -559 57 -144 171 -88 113 -86 231 -414 131 -192 237 -360 95 -168 145 -168 213 -120 167 -96 143 -110 57 -86 259 -56 87 -777 295 -96 57 -86 173 -86 171 -404 143 -172 231 -200 57 -441 55 -58 173 -56 87 -86 171 -72 287 -72 119 -262 119 -144 71 -72 121 -310 71 -302 113 -54 193 -80 307 -58 257 -232 143 -56 143 -116 219 -72 695 -70 71 -460 85 -232 719 -363 57 -402 604 -230 287 -138 83 -172 259 -58 171 -174 55 -88 489 -114 143 -116 171 -116 143 -58 199 -144 145 -343 374 -186 235 -140 77 -86 143 -202 143 -144 113 -144 143 -58 732 -96 263 -264 71 -206 95 -168 215 -144 271 -80 139 -88 85 -414 75 -100
RAW_Data: 285 -96 627 -362 53 -84 201 -374 113 -202 115 -202 421 -316 85 -58 139 -224 87 -86 229 -58 243 -178 267 -288 95 -336 171 -96 213 -288 71 -405 95 -96 95 -384 95 -72 213 -72 95 -96 95 -272 87 -1083 85 -58 113 -88 257 -116 143 -292 175 -318 95 -120 95 -144 95 -72 71 -216 368 -116 373 -172 115 -58 85 -116 143 -86 85 -144 201 -86 201 -202 257 -144 201 -174 113 -144 115 -144 257 -202 585 -364 173 -138 287 -422 431 -86 85 -96 869 -186 95 -52 115 -86 115 -58 55 -276 365 -86 85 -489 171 -140 577 -106 718 -144 391 -232 195 -82 143 -172 109 -120 167 -96 280 -216 145 -240 215 -186 163 -96 141 -172 159 -603 257 -108 629 -192 119 -80 87 -172 57 -144 286 -86 57 -230 344 -58 113 -537 75 -96 537 -86 403 -196 167 -264 119 -238 119 -120 167 -96 95 -478 95 -120 167 -216 1085 -96 358 -72 263 -72 69 -120 143 -96 71 -96 191 -362 55 -144 57 -260 113 -58 85 -174 55 -88 257 -86 231 -194 55 -58 115 -56 55 -339 55 -58 374 -172 139 -82 419 -98 119 -261 71 -72 71 -240 713 -86 143 -218 295 -72 53 -56 431 -58 317 -144 161 -144 373 -144 173 -144 57 -114 85 -116 195 -72 708 -172 115 -86 191 -96 506 -120 71 -174 85 -58 363 -114 317 -230 316 -200 87 -114 57 -230 115 -315 173 -280 694 -212 453 -256 143 -202 113 -540 352 -116 257 -116 457 -56 109 -58 143 -230 259 -144 259 -525 119 -408 247 -112 389 -72 431 -96 137 -236 97 -474 201 -298 71 -82 55 -116 55 -112 199 -174 191 -86 143 -144 115 -114 317 -86 85 -230 87 -114 259 -84 107 -130 143 -94 153 -86 135 -94 215 -72 239 -94 435 -96 263 -142 166 -334 87 -194 179 -96 115 -284 135 -56 57 -144 463 -204 143 -316 201 -58 403 -86 141 -288 85 -202 139 -397 171 -174 305 -202 85 -144 373 -253 161 -492 181 -191 95 -216 315 -191 71 -166 97 -126 337 -96 71 -96 189 -168 295 -84 197 -86 259 -345 137 -144 167 -796 115 -344 455 -72 119 -96 119 -550 209 -88 85 -86 143 -340 167 -260 143 -537 85 -226 51 -537 57 -260 315 -461 51 -84 199 -358 383 -96 143 -257 115 -86 173 -86 201 -144 143 -316 85 -86 479 -88 85 -72 71 -104 115 -116 267 -72 137 -144 143 -116 85 -86 373 -288 115 -200 87 -114 259 -114 259 -462 143 -144 171 -86 57 -58 137 -144 57 -634 343 -72 205 -86 143 -258 57 -232 113 -230 461 -58 185 -74 537 -86
RAW_Data: 535 -142 57 -58 55 -116 115 -432 85 -172 259 -192 167 -120 117 -72 119 -240 334 -72 71 -267 285 -144 119 -374 85 -88 85 -114 143 -202 229 -58 143 -202 115 -202 171 -86 71 -144 87 -56 173 -373 143 -116 113 -462 169 -80 215 -148 115 -336 85 -230 163 -432 85 -374 639 -174 85 -58 57 -82 295 -352 269 -532 414 -322 95 -287 263 -268 115 -56 259 -76 85 -282 401 -305 516 -114 115 -202 171 -86 451 -110 85 -346 201 -274 149 -202 85 -364 366 -258 57 -114 259 -172 142 -144 85 -116 85 -480 171 -144 57 -352 115 -116 535 -404 315 -202 163 -158 517 -316 215 -98 85 -346 85 -144 87 -86 257 -82 167 -58 85 -116 113 -894 233 -186 77 -266 147 -72 71 -82 57 -86 171 -58 57 -86 201 -364 143 -202 115 -114 85 -88 113 -86 87 -230 57 -76 613 -72 85 -96 209 -346 458 -58 547 -490 201 -315 315 -116 75 -168 359 -335 95 -384 93 -120 71 -312 251 -366 233 -96 189 -240 263 -192 271 -58 115 -58 229 -346 459 -174 113 -144 173 -144 218 -224 57 -116 215 -72 103 -202 513 -210 433 -116 113 -174 650 -273 147 -450 375 -86 115 -172 536 -84 85 -230 85 -58 195 -468 287 -110 551 -214 167 -311 213 -250 85 -58 85 -355 113 -230 115 -144 117 -288 195 -202 57 -376 123 -144 236 -168 553 -284 119 -72 143 -188 161 -120 93 -312 335 -58 55 -260 105 -244 143 -120 381 -268 173 -268 635 -168 453 -318 71 -167 71 -406 191 -172 215 -408 119 -144 93 -120 97 -130 143 -192 308 -122 147 -550 313 -96 139 -162 167 -96 431 -80 83 -112 201 -86 287 -86 229 -116 57 -288 113 -174 143 -116 113 -144 115 -518 57 -230 57 -172 231 -86 113 -314 183 -144 119 -72 165 -446 81 -86 135 -190 143 -96 71 -72 411 -96 143 -120 69 -216 349 -72 95 -96 517 -646 163 -86 113 -116 171 -116 143 -116 113 -287 259 -114 517 -168 141 -116 105 -72 95 -96 311 -118 159 -310 191 -54 143 -258 115 -450 219 -54 339 -372 239 -72 167 -174 113 -58 57 -144 259 -172 143 -336 113 -174 85 -230 83 -668 85 -202 113 -144 57 -116 373 -316 719 -288 115 -58 75 -120 139 -144 229 -144 57 -144 171 -192 391 -202 403 -58 315 -188 259 -56 115 -144 85 -404 57 -58 105 -102 429 -406 81 -172 57 -144 287 -230 287 -220 317 -458 283 -58 113 -86 269 -72 281 -58 85 -202 113 -52 421 -58 229 -480 259 -58 143 -660 155 -638 123 -86 57 -86 143 -346 143 -144 57 -144
RAW_Data: 535 -142 57 -58 55 -116 115 -432 85 -172 259 -192 167 -120 117 -72 119 -240 334 -72 71 -267 285 -144 119 -374 85 -88 85 -114 143 -202 229 -58 143 -202 115 -202 171 -86 71 -144 87 -56 173 -373 143 -116 113 -462 169 -80 215 -148 115 -336 85 -230 163 -432 85 -374 639 -174 85 -58 57 -82 295 -352 269 -532 414 -322 95 -287 263 -268 115 -56 259 -76 85 -282 401 -305 516 -114 115 -202 171 -86 451 -110 85 -346 201 -274 149 -202 85 -364 366 -258 57 -114 259 -172 142 -144 85 -116 85 -480 171 -144 57 -352 115 -116 535 -404 315 -202 163 -158 517 -316 215 -98 85 -346 85 -144 87 -86 257 -82 167 -58 85 -116 113 -894 233 -186 77 -266 147 -72 71 -82 57 -86 171 -58 57 -86 201 -364 143 -202 115 -114 85 -88 113 -86 87 -230 57 -76 613 -72 85 -96 209 -346 458 -58 547 -490 201 -315 315 -116 75 -168 359 -335 95 -384 93 -120 71 -312 251 -366 233 -96 189 -240 263 -192 271 -58 115 -58 229 -346 459 -174 113 -144 173 -144 218 -224 57 -116 215 -72 103 -202 513 -210 433 -116 113 -174 650 -273 147 -450 375 -86 115 -172 536 -84 85 -230 85 -58 195 -468 287 -110 551 -214 167 -311 213 -250 85 -58 85 -355 113 -230 115 -144 117 -288 195 -202 57 -376 123 -144 236 -168 553 -284 119 -72 143 -188 161 -120 93 -312 335 -58 55 -260 105 -244 143 -120 381 -268 173 -268 635 -168 453 -318 71 -167 71 -406 191 -172 215 -408 119 -144 93 -120 97 -130 143 -192 308 -122 147 -550 313 -96 139 -162 167 -96 431 -80 83 -112 201 -86 287 -86 229 -116 57 -288 113 -174 143 -116 113 -144 115 -518 57 -230 57 -172 231 -86 113 -314 183 -144 119 -72 165 -446 81 -86 135 -190 143 -96 71 -72 411 -96 143 -120 69 -216 349 -72 95 -96 517 -646 163 -86 113 -116 171 -116 143 -116 113 -287 259 -114 517 -168 141 -116 105 -72 95 -96 311 -118 159 -310 191 -54 143 -258 115 -450 219 -54 339 -372 239 -72 167 -174 113 -58 57 -144 259 -172 143 -336 113 -174 85 -230 83 -668 85 -202 113 -144 57 -116 373 -316 719 -288 115 -58 75 -120 139 -144 229 -144 57 -144 171 -192 391 -202 403 -58 315 -188 259 -56 115 -144 85 -404 57 -58 105 -102 429 -406 81 -172 57 -144 287 -230 287 -220 317 -458 283 -58 113 -86 269 -72 281 -58 85 -202 113 -52 421 -58 229 -480 259 -58 143 -660 155 -638 123 -86 57 -86 143 -346 143 -144 57 -144
RAW_Data: 2442 -312 275 -972 949 -310 941 -322 923 -342 921 -352 923 -334 281 -954 945 -350 279 -958 907 -354 289 -980 909 -352 281 -962 907 -330 311 -964 913 -350 317 -930 933 -344 921 -352 893 -330 311 -954 943 -318 315 -958 909 -324 947 -7854 953 -322 289 -948 939 -354 927 -332 911 -324 943 -344 917 -318 317 -964 905 -344 303 -942 947 -312 319 -960 913 -348 281 -958 941 -322 295 -978 905 -350 279 -962 931 -328 947 -324 939 -346 267 -964 935 -348 283 -938 953 -318 931 -7868 935 -346 269 -968 953 -310 941 -322 921 -330 935 -342 931 -318 311 -962 939 -290 337 -950 909 -352 317 -924 943 -324 313 -938 941 -318 317 -932 939 -344 301 -938 933 -350 921 -322 959 -310 301 -942 933 -352 317 -926 957 -314 919 -7868 943 -314 317 -958 909 -322 951 -344 919 -352 921 -324 937 -326 281 -964 941 -318 317 -930 939 -344 301 -938 933 -352 281 -962 953 -314 317 -922 933 -330 315 -954 943 -318 921 -342 943 -320 291 -980 909 -354 281 -962 943 -296 967 -7836 943 -332 309 -950 935 -318 929 -340 943 -320 921 -344 921 -354 283 -960 943 -296 309 -964 945 -318 279 -964 941 -322 333 -944 939 -314 279 -992 903 -342 319 -932 933 -330 931 -340 929 -348 281 -964 935 -334 281 -970 927 -346 921 -7862 951 -314 319 -922 953 -320 923 -346 921 -320 965 -298 943 -324 313 -942 941 -320 317 -930 941 -344 303 -940 945 -312 321 -940 953 -314 303 -960 933 -348 287 -962 911 -352 917 -350 905 -324 333 -918 971 -322 317 -924 945 -324 937 -7872 919 -324 317 -942 941 -318 933 -330 943 -324 943 -310 951 -318 317 -930 939 -344 301 -938 933 -352 317 -926 953 -314 319 -924 939 -324 331 -950 907 -354 315 -926 945 -324 939 -312 953 -318 317 -930 937 -344 301 -940 947 -348 909 -7864 949 -310 319 -956 915 -350 919 -348 905 -322 963 -296 935 -348 317 -922 951 -322 295 -976 939 -314 281 -996 915 -326 307 -940 959 -310 301 -966 935 -346 285 -958 915 -348 921 -348 903 -354 303 -948 911 -350 315 -926 945 -324 941 -7874 943 -290 319 -942 973 -318 929 -314 937 -328 941 -324 939 -310 303 -962 933 -352 285 -962 949 -314 319 -924 951 -320 293 -948 941 -354 283 -962 943 -294 309 -966 943 -320 931 -328 943 -326 311 -940 939 -320 309 -958 933 -338 943 -7840 933 -352 277 -964 941 -322 923 -344 923 -350 931 -310 955 -320 291 -974 907 -350 281 -958 963 -298 313 -956 945 -314 311 -960 937 -312 311 -966 909 -324 319 -944 941 -354 929 -298 945 -324 315 -940
RAW_Data: 943 -354 281 -964 905 -330 933 -7868 951 -324 315 -938 943 -354 893 -330 943 -324 943 -344 919 -318 317 -962 903 -344 301 -974 903 -350 317 -932 931 -342 269 -972 949 -346 285 -938 955 -310 301 -964 935 -348 921 -320 921 -344 301 -940 935 -350 317 -930 929 -318 937 -7872 939 -344 301 -940 947 -346 917 -322 921 -344 923 -352 927 -334 281 -970 925 -334 277 -982 943 -318 317 -932 931 -344 301 -936 935 -350 281 -960 957 -312 303 -960 935 -346 907 -322 929 -344 301 -942 935 -350 317 -924 955 -312 951 -7858 919 -342 309 -940 949 -348 909 -322 923 -344 923 -352 923 -336 317 -924 945 -312 311 -966 921 -340 317 -924 947 -350 281 -958 941 -322 291 -976 905 -350 279 -960 935 -342 943 -320 919 -330 311 -958 943 -320 315 -932 935 -344 919 -7866 957 -312 303 -964 917 -342 945 -320 923 -344 923 -354 929 -298 315 -956 941 -318 315 -960 911 -324 317 -942 939 -354 281 -964 941 -294 311 -968 943 -318 317 -932 937 -330 931 -350 919 -348 283 -960 917 -350 317 -922 939 -322 965 -7864 921 -324 329 -950 909 -354 923 -336 913 -322 947 -344 919 -354 281 -962 941 -294 311 -960 935 -354 281 -962 939 -294 311 -964 937 -354 281 -964 941 -296 309 -964 939 -318 931 -330 945 -324 315 -940 939 -354 281 -964 909 -344 921 -7862 963 -304 307 -976 933 -320 929 -328 941 -324 939 -348 915 -320 317 -930 939 -344 301 -940 965 -320 319 -926 953 -312 303 -960 933 -312 321 -960 913 -348 319 -924 943 -320 959 -310 921 -354 319 -924 943 -324 311 -938 941 -318 957 -7862 943 -318 317 -932 933 -344 925 -352 897 -332 943 -324 943 -346 267 -966 951 -310 321 -960 911 -350 281 -958 949 -320 291 -978 937 -316 279 -964 949 -326 309 -944 943 -314 959 -318 933 -336 317 -934 933 -344 267 -964 937 -350 905 -7896 943 -318 319 -926 955 -314 919 -350 935 -324 941 -294 967 -312 303 -962 933 -348 285 -960 917 -348 317 -922 941 -322 329 -950 907 -354 315 -926 943 -326 313 -940 941 -352 893 -332 949 -324 315 -938 941 -352 283 -962 943 -310 925 -7890 931 -344 269 -968 949 -310 943 -320 923 -350 937 -310 955 -318 317 -930 935 -344 301 -942 947 -346 285 -958 915 -346 317 -924 951 -322 295 -982 905 -352 317 -924 945 -324 941 -346 917 -318 317 -962 905 -330 311 -956 937 -352 897 -7878 939 -354 283 -960 941 -294 965 -312 953 -318 385 -201512 165 -198 265 -526 229 -298 755 -164 61687 -17310 131 -1056 99 -296 195 -296 65 -66 1617
-1
View File
@@ -81,7 +81,6 @@ FIRMWARE_APPS = {
"basic_services",
"updater_app",
"unit_tests",
"nfc",
],
}
+23 -1
View File
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,10.2,,
Version,+,11.1,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@@ -29,6 +29,7 @@ Header,+,applications/services/gui/view_dispatcher.h,,
Header,+,applications/services/gui/view_stack.h,,
Header,+,applications/services/input/input.h,,
Header,+,applications/services/loader/loader.h,,
Header,+,applications/services/locale/locale.h,,
Header,+,applications/services/notification/notification.h,,
Header,+,applications/services/notification/notification_messages.h,,
Header,+,applications/services/power/power_service/power.h,,
@@ -1274,6 +1275,9 @@ Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode,
Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime*
Function,+,furi_hal_rtc_get_fault_data,uint32_t,
Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode,
Function,+,furi_hal_rtc_get_locale_dateformat,FuriHalRtcLocaleDateFormat,
Function,+,furi_hal_rtc_get_locale_timeformat,FuriHalRtcLocaleTimeFormat,
Function,+,furi_hal_rtc_get_locale_units,FuriHalRtcLocaleUnits,
Function,+,furi_hal_rtc_get_log_level,uint8_t,
Function,+,furi_hal_rtc_get_pin_fails,uint32_t,
Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister
@@ -1287,11 +1291,18 @@ Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime*
Function,+,furi_hal_rtc_set_fault_data,void,uint32_t
Function,+,furi_hal_rtc_set_flag,void,FuriHalRtcFlag
Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode
Function,+,furi_hal_rtc_set_locale_dateformat,void,FuriHalRtcLocaleDateFormat
Function,+,furi_hal_rtc_set_locale_timeformat,void,FuriHalRtcLocaleTimeFormat
Function,+,furi_hal_rtc_set_locale_units,void,FuriHalRtcLocaleUnits
Function,+,furi_hal_rtc_set_log_level,void,uint8_t
Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
Function,+,furi_hal_rtc_validate_datetime,_Bool,FuriHalRtcDateTime*
Function,+,furi_hal_speaker_acquire,_Bool,uint32_t
Function,-,furi_hal_speaker_deinit,void,
Function,-,furi_hal_speaker_init,void,
Function,+,furi_hal_speaker_is_mine,_Bool,
Function,+,furi_hal_speaker_release,void,
Function,+,furi_hal_speaker_set_volume,void,float
Function,+,furi_hal_speaker_start,void,"float, float"
Function,+,furi_hal_speaker_stop,void,
@@ -1325,6 +1336,7 @@ Function,+,furi_hal_subghz_read_packet,void,"uint8_t*, uint8_t*"
Function,+,furi_hal_subghz_reset,void,
Function,+,furi_hal_subghz_rx,void,
Function,+,furi_hal_subghz_rx_pipe_not_empty,_Bool,
Function,+,furi_hal_subghz_set_async_mirror_pin,void,const GpioPin*
Function,+,furi_hal_subghz_set_frequency,uint32_t,uint32_t
Function,+,furi_hal_subghz_set_frequency_and_path,uint32_t,uint32_t
Function,+,furi_hal_subghz_set_path,void,FuriHalSubGhzPath
@@ -1740,6 +1752,16 @@ Function,+,loader_update_menu,void,
Function,+,loading_alloc,Loading*,
Function,+,loading_free,void,Loading*
Function,+,loading_get_view,View*,Loading*
Function,+,locale_celsius_to_fahrenheit,float,float
Function,+,locale_fahrenheit_to_celsius,float,float
Function,+,locale_format_date,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleDateFormat, const char*"
Function,+,locale_format_time,void,"FuriString*, const FuriHalRtcDateTime*, const LocaleTimeFormat, const _Bool"
Function,+,locale_get_date_format,LocaleDateFormat,
Function,+,locale_get_measurement_unit,LocaleMeasurementUnits,
Function,+,locale_get_time_format,LocaleTimeFormat,
Function,+,locale_set_date_format,void,LocaleDateFormat
Function,+,locale_set_measurement_unit,void,LocaleMeasurementUnits
Function,+,locale_set_time_format,void,LocaleTimeFormat
Function,-,localtime,tm*,const time_t*
Function,-,localtime_r,tm*,"const time_t*, tm*"
Function,-,log,double,double
1 entry status name type params
2 Version + 10.2 11.1
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
29 Header + applications/services/gui/view_stack.h
30 Header + applications/services/input/input.h
31 Header + applications/services/loader/loader.h
32 Header + applications/services/locale/locale.h
33 Header + applications/services/notification/notification.h
34 Header + applications/services/notification/notification_messages.h
35 Header + applications/services/power/power_service/power.h
1275 Function + furi_hal_rtc_get_datetime void FuriHalRtcDateTime*
1276 Function + furi_hal_rtc_get_fault_data uint32_t
1277 Function + furi_hal_rtc_get_heap_track_mode FuriHalRtcHeapTrackMode
1278 Function + furi_hal_rtc_get_locale_dateformat FuriHalRtcLocaleDateFormat
1279 Function + furi_hal_rtc_get_locale_timeformat FuriHalRtcLocaleTimeFormat
1280 Function + furi_hal_rtc_get_locale_units FuriHalRtcLocaleUnits
1281 Function + furi_hal_rtc_get_log_level uint8_t
1282 Function + furi_hal_rtc_get_pin_fails uint32_t
1283 Function + furi_hal_rtc_get_register uint32_t FuriHalRtcRegister
1291 Function + furi_hal_rtc_set_fault_data void uint32_t
1292 Function + furi_hal_rtc_set_flag void FuriHalRtcFlag
1293 Function + furi_hal_rtc_set_heap_track_mode void FuriHalRtcHeapTrackMode
1294 Function + furi_hal_rtc_set_locale_dateformat void FuriHalRtcLocaleDateFormat
1295 Function + furi_hal_rtc_set_locale_timeformat void FuriHalRtcLocaleTimeFormat
1296 Function + furi_hal_rtc_set_locale_units void FuriHalRtcLocaleUnits
1297 Function + furi_hal_rtc_set_log_level void uint8_t
1298 Function + furi_hal_rtc_set_pin_fails void uint32_t
1299 Function + furi_hal_rtc_set_register void FuriHalRtcRegister, uint32_t
1300 Function + furi_hal_rtc_validate_datetime _Bool FuriHalRtcDateTime*
1301 Function + furi_hal_speaker_acquire _Bool uint32_t
1302 Function - furi_hal_speaker_deinit void
1303 Function - furi_hal_speaker_init void
1304 Function + furi_hal_speaker_is_mine _Bool
1305 Function + furi_hal_speaker_release void
1306 Function + furi_hal_speaker_set_volume void float
1307 Function + furi_hal_speaker_start void float, float
1308 Function + furi_hal_speaker_stop void
1336 Function + furi_hal_subghz_reset void
1337 Function + furi_hal_subghz_rx void
1338 Function + furi_hal_subghz_rx_pipe_not_empty _Bool
1339 Function + furi_hal_subghz_set_async_mirror_pin void const GpioPin*
1340 Function + furi_hal_subghz_set_frequency uint32_t uint32_t
1341 Function + furi_hal_subghz_set_frequency_and_path uint32_t uint32_t
1342 Function + furi_hal_subghz_set_path void FuriHalSubGhzPath
1752 Function + loading_alloc Loading*
1753 Function + loading_free void Loading*
1754 Function + loading_get_view View* Loading*
1755 Function + locale_celsius_to_fahrenheit float float
1756 Function + locale_fahrenheit_to_celsius float float
1757 Function + locale_format_date void FuriString*, const FuriHalRtcDateTime*, const LocaleDateFormat, const char*
1758 Function + locale_format_time void FuriString*, const FuriHalRtcDateTime*, const LocaleTimeFormat, const _Bool
1759 Function + locale_get_date_format LocaleDateFormat
1760 Function + locale_get_measurement_unit LocaleMeasurementUnits
1761 Function + locale_get_time_format LocaleTimeFormat
1762 Function + locale_set_date_format void LocaleDateFormat
1763 Function + locale_set_measurement_unit void LocaleMeasurementUnits
1764 Function + locale_set_time_format void LocaleTimeFormat
1765 Function - localtime tm* const time_t*
1766 Function - localtime_r tm* const time_t*, tm*
1767 Function - log double double
+58 -16
View File
@@ -29,12 +29,15 @@ typedef struct {
uint8_t log_level : 4;
uint8_t log_reserved : 4;
uint8_t flags;
uint8_t boot_mode : 4;
uint8_t heap_track_mode : 2;
uint16_t reserved : 10;
} DeveloperReg;
FuriHalRtcBootMode boot_mode : 4;
FuriHalRtcHeapTrackMode heap_track_mode : 2;
FuriHalRtcLocaleUnits locale_units : 1;
FuriHalRtcLocaleTimeFormat locale_timeformat : 1;
FuriHalRtcLocaleDateFormat locale_dateformat : 2;
uint8_t reserved : 6;
} SystemReg;
_Static_assert(sizeof(DeveloperReg) == 4, "DeveloperReg size mismatch");
_Static_assert(sizeof(SystemReg) == 4, "SystemReg size mismatch");
#define FURI_HAL_RTC_SECONDS_PER_MINUTE 60
#define FURI_HAL_RTC_SECONDS_PER_HOUR (FURI_HAL_RTC_SECONDS_PER_MINUTE * 60)
@@ -172,7 +175,7 @@ void furi_hal_rtc_set_register(FuriHalRtcRegister reg, uint32_t value) {
void furi_hal_rtc_set_log_level(uint8_t level) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
SystemReg* data = (SystemReg*)&data_reg;
data->log_level = level;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
furi_log_set_level(level);
@@ -180,13 +183,13 @@ void furi_hal_rtc_set_log_level(uint8_t level) {
uint8_t furi_hal_rtc_get_log_level() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
SystemReg* data = (SystemReg*)&data_reg;
return data->log_level;
}
void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
SystemReg* data = (SystemReg*)&data_reg;
data->flags |= flag;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
@@ -197,7 +200,7 @@ void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) {
void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
SystemReg* data = (SystemReg*)&data_reg;
data->flags &= ~flag;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
@@ -208,34 +211,73 @@ void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) {
bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
SystemReg* data = (SystemReg*)&data_reg;
return data->flags & flag;
}
void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
SystemReg* data = (SystemReg*)&data_reg;
data->boot_mode = mode;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
}
FuriHalRtcBootMode furi_hal_rtc_get_boot_mode() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
return (FuriHalRtcBootMode)data->boot_mode;
SystemReg* data = (SystemReg*)&data_reg;
return data->boot_mode;
}
void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
SystemReg* data = (SystemReg*)&data_reg;
data->heap_track_mode = mode;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
}
FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
return (FuriHalRtcHeapTrackMode)data->heap_track_mode;
SystemReg* data = (SystemReg*)&data_reg;
return data->heap_track_mode;
}
void furi_hal_rtc_set_locale_units(FuriHalRtcLocaleUnits value) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
data->locale_units = value;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
}
FuriHalRtcLocaleUnits furi_hal_rtc_get_locale_units() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
return data->locale_units;
}
void furi_hal_rtc_set_locale_timeformat(FuriHalRtcLocaleTimeFormat value) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
data->locale_timeformat = value;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
}
FuriHalRtcLocaleTimeFormat furi_hal_rtc_get_locale_timeformat() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
return data->locale_timeformat;
}
void furi_hal_rtc_set_locale_dateformat(FuriHalRtcLocaleDateFormat value) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
data->locale_dateformat = value;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
}
FuriHalRtcLocaleDateFormat furi_hal_rtc_get_locale_dateformat() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
SystemReg* data = (SystemReg*)&data_reg;
return data->locale_dateformat;
}
void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) {
@@ -1,23 +1,66 @@
#include <furi_hal_speaker.h>
#include <furi_hal_gpio.h>
#include <furi_hal_resources.h>
#include <furi_hal_power.h>
#include <stm32wbxx_ll_tim.h>
#include <furi_hal_cortex.h>
#define TAG "FuriHalSpeaker"
#define FURI_HAL_SPEAKER_TIMER TIM16
#define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1
#define FURI_HAL_SPEAKER_PRESCALER 500
#define FURI_HAL_SPEAKER_MAX_VOLUME 60
static FuriMutex* furi_hal_speaker_mutex = NULL;
// #define FURI_HAL_SPEAKER_NEW_VOLUME
void furi_hal_speaker_init() {
furi_assert(furi_hal_speaker_mutex == NULL);
furi_hal_speaker_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
FURI_CRITICAL_ENTER();
LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER);
FURI_CRITICAL_EXIT();
FURI_LOG_I(TAG, "Init OK");
}
furi_hal_gpio_init_ex(
&gpio_speaker, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn14TIM16);
void furi_hal_speaker_deinit() {
furi_check(furi_hal_speaker_mutex != NULL);
LL_TIM_DeInit(FURI_HAL_SPEAKER_TIMER);
furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_mutex_free(furi_hal_speaker_mutex);
furi_hal_speaker_mutex = NULL;
}
bool furi_hal_speaker_acquire(uint32_t timeout) {
furi_check(!FURI_IS_IRQ_MODE());
if(furi_mutex_acquire(furi_hal_speaker_mutex, timeout) == FuriStatusOk) {
furi_hal_power_insomnia_enter();
furi_hal_gpio_init_ex(
&gpio_speaker, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn14TIM16);
return true;
} else {
return false;
}
}
void furi_hal_speaker_release() {
furi_check(!FURI_IS_IRQ_MODE());
furi_check(furi_hal_speaker_is_mine());
furi_hal_speaker_stop();
furi_hal_gpio_init(&gpio_speaker, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
furi_hal_power_insomnia_exit();
furi_check(furi_mutex_release(furi_hal_speaker_mutex) == FuriStatusOk);
}
bool furi_hal_speaker_is_mine() {
return (FURI_IS_IRQ_MODE()) ||
(furi_mutex_get_owner(furi_hal_speaker_mutex) == furi_thread_get_current_id());
}
static inline uint32_t furi_hal_speaker_calculate_autoreload(float frequency) {
@@ -54,6 +97,8 @@ static inline uint32_t furi_hal_speaker_calculate_compare(float volume) {
}
void furi_hal_speaker_start(float frequency, float volume) {
furi_check(furi_hal_speaker_is_mine());
if(volume <= 0) {
furi_hal_speaker_stop();
return;
@@ -75,6 +120,7 @@ void furi_hal_speaker_start(float frequency, float volume) {
}
void furi_hal_speaker_set_volume(float volume) {
furi_check(furi_hal_speaker_is_mine());
if(volume <= 0) {
furi_hal_speaker_stop();
return;
@@ -88,6 +134,7 @@ void furi_hal_speaker_set_volume(float volume) {
}
void furi_hal_speaker_stop() {
furi_check(furi_hal_speaker_is_mine());
LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER);
LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER);
}
+64 -61
View File
@@ -4,7 +4,6 @@
#include <furi_hal_region.h>
#include <furi_hal_version.h>
#include <furi_hal_rtc.h>
#include <furi_hal_gpio.h>
#include <furi_hal_spi.h>
#include <furi_hal_interrupt.h>
#include <furi_hal_resources.h>
@@ -17,39 +16,26 @@
#define TAG "FuriHalSubGhz"
/*
* Uncomment define to enable duplication of
* IO GO0 CC1101 to an external comb.
* Debug pin can be assigned
* gpio_ext_pc0
* gpio_ext_pc1
* gpio_ext_pc3
* gpio_ext_pb2
* gpio_ext_pb3
* gpio_ext_pa4
* gpio_ext_pa6
* gpio_ext_pa7
* Attention this setting switches pin to output.
* Make sure it is not connected directly to power or ground
*/
//#define SUBGHZ_DEBUG_CC1101_PIN gpio_ext_pa7
#ifdef SUBGHZ_DEBUG_CC1101_PIN
uint32_t subghz_debug_gpio_buff[2];
#endif
static uint32_t furi_hal_subghz_debug_gpio_buff[2];
typedef struct {
volatile SubGhzState state;
volatile SubGhzRegulation regulation;
volatile FuriHalSubGhzPreset preset;
const GpioPin* async_mirror_pin;
} FuriHalSubGhz;
volatile FuriHalSubGhz furi_hal_subghz = {
.state = SubGhzStateInit,
.regulation = SubGhzRegulationTxRx,
.preset = FuriHalSubGhzPresetIDLE,
.async_mirror_pin = NULL,
};
void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin) {
furi_hal_subghz.async_mirror_pin = pin;
}
void furi_hal_subghz_init() {
furi_assert(furi_hal_subghz.state == SubGhzStateInit);
furi_hal_subghz.state = SubGhzStateIdle;
@@ -372,6 +358,29 @@ void furi_hal_subghz_set_path(FuriHalSubGhzPath path) {
furi_hal_spi_release(&furi_hal_spi_bus_handle_subghz);
}
static bool furi_hal_subghz_start_debug() {
bool ret = false;
if(furi_hal_subghz.async_mirror_pin != NULL) {
furi_hal_gpio_init(
furi_hal_subghz.async_mirror_pin,
GpioModeOutputPushPull,
GpioPullNo,
GpioSpeedVeryHigh);
ret = true;
}
return ret;
}
static bool furi_hal_subghz_stop_debug() {
bool ret = false;
if(furi_hal_subghz.async_mirror_pin != NULL) {
furi_hal_gpio_init(
furi_hal_subghz.async_mirror_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
ret = true;
}
return ret;
}
volatile uint32_t furi_hal_subghz_capture_delta_duration = 0;
volatile FuriHalSubGhzCaptureCallback furi_hal_subghz_capture_callback = NULL;
volatile void* furi_hal_subghz_capture_callback_context = NULL;
@@ -382,9 +391,9 @@ static void furi_hal_subghz_capture_ISR() {
LL_TIM_ClearFlag_CC1(TIM2);
furi_hal_subghz_capture_delta_duration = LL_TIM_IC_GetCaptureCH1(TIM2);
if(furi_hal_subghz_capture_callback) {
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, false);
#endif
if(furi_hal_subghz.async_mirror_pin != NULL)
furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, false);
furi_hal_subghz_capture_callback(
true,
furi_hal_subghz_capture_delta_duration,
@@ -395,9 +404,9 @@ static void furi_hal_subghz_capture_ISR() {
if(LL_TIM_IsActiveFlag_CC2(TIM2)) {
LL_TIM_ClearFlag_CC2(TIM2);
if(furi_hal_subghz_capture_callback) {
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_write(&SUBGHZ_DEBUG_CC1101_PIN, true);
#endif
if(furi_hal_subghz.async_mirror_pin != NULL)
furi_hal_gpio_write(furi_hal_subghz.async_mirror_pin, true);
furi_hal_subghz_capture_callback(
false,
LL_TIM_IC_GetCaptureCH2(TIM2) - furi_hal_subghz_capture_delta_duration,
@@ -459,10 +468,8 @@ void furi_hal_subghz_start_async_rx(FuriHalSubGhzCaptureCallback callback, void*
LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2);
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_init(
&SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
#endif
// Start debug
furi_hal_subghz_start_debug();
// Switch to RX
furi_hal_subghz_rx();
@@ -478,9 +485,8 @@ void furi_hal_subghz_stop_async_rx() {
FURI_CRITICAL_ENTER();
LL_TIM_DeInit(TIM2);
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
#endif
// Stop debug
furi_hal_subghz_stop_debug();
FURI_CRITICAL_EXIT();
furi_hal_interrupt_set_isr(FuriHalInterruptIdTIM2, NULL, NULL);
@@ -673,30 +679,27 @@ bool furi_hal_subghz_start_async_tx(FuriHalSubGhzAsyncTxCallback callback, void*
LL_TIM_SetCounter(TIM2, 0);
LL_TIM_EnableCounter(TIM2);
#ifdef SUBGHZ_DEBUG_CC1101_PIN
furi_hal_gpio_init(
&SUBGHZ_DEBUG_CC1101_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
// Start debug
if(furi_hal_subghz_start_debug()) {
const GpioPin* gpio = furi_hal_subghz.async_mirror_pin;
furi_hal_subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER;
furi_hal_subghz_debug_gpio_buff[1] = gpio->pin;
const GpioPin* gpio = &SUBGHZ_DEBUG_CC1101_PIN;
subghz_debug_gpio_buff[0] = (uint32_t)gpio->pin << GPIO_NUMBER;
subghz_debug_gpio_buff[1] = gpio->pin;
dma_config.MemoryOrM2MDstAddress = (uint32_t)subghz_debug_gpio_buff;
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR);
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dma_config.Mode = LL_DMA_MODE_CIRCULAR;
dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
dma_config.NbData = 2;
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH;
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
#endif
dma_config.MemoryOrM2MDstAddress = (uint32_t)furi_hal_subghz_debug_gpio_buff;
dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->BSRR);
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dma_config.Mode = LL_DMA_MODE_CIRCULAR;
dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
dma_config.NbData = 2;
dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH;
LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, 2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
}
return true;
}
@@ -730,10 +733,10 @@ void furi_hal_subghz_stop_async_tx() {
// Deinitialize GPIO
furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
#ifdef SUBGHZ_DEBUG_CC1101_PIN
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
furi_hal_gpio_init(&SUBGHZ_DEBUG_CC1101_PIN, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
#endif
// Stop debug
if(furi_hal_subghz_stop_debug()) {
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
}
FURI_CRITICAL_EXIT();
@@ -59,53 +59,194 @@ typedef enum {
FuriHalRtcRegisterMAX, /**< Service value, do not use */
} FuriHalRtcRegister;
typedef enum {
FuriHalRtcLocaleUnitsMetric = 0, /**< Metric measurement units */
FuriHalRtcLocaleUnitsImperial = 1, /**< Imperial measurement units */
} FuriHalRtcLocaleUnits;
typedef enum {
FuriHalRtcLocaleTimeFormat24h = 0, /**< 24-hour format */
FuriHalRtcLocaleTimeFormat12h = 1, /**< 12-hour format */
} FuriHalRtcLocaleTimeFormat;
typedef enum {
FuriHalRtcLocaleDateFormatDMY = 0, /**< Day/Month/Year */
FuriHalRtcLocaleDateFormatMDY = 1, /**< Month/Day/Year */
FuriHalRtcLocaleDateFormatYMD = 2, /**< Year/Month/Day */
} FuriHalRtcLocaleDateFormat;
/** Early initialization */
void furi_hal_rtc_init_early();
/** Early deinitialization */
/** Early de-initialization */
void furi_hal_rtc_deinit_early();
/** Initialize RTC subsystem */
void furi_hal_rtc_init();
/** Get RTC register content
*
* @param[in] reg The register identifier
*
* @return content of the register
*/
uint32_t furi_hal_rtc_get_register(FuriHalRtcRegister reg);
/** Set register content
*
* @param[in] reg The register identifier
* @param[in] value The value to store into register
*/
void furi_hal_rtc_set_register(FuriHalRtcRegister reg, uint32_t value);
/** Set Log Level value
*
* @param[in] level The level to store
*/
void furi_hal_rtc_set_log_level(uint8_t level);
/** Get Log Level value
*
* @return The Log Level value
*/
uint8_t furi_hal_rtc_get_log_level();
/** Set RTC Flag
*
* @param[in] flag The flag to set
*/
void furi_hal_rtc_set_flag(FuriHalRtcFlag flag);
/** Reset RTC Flag
*
* @param[in] flag The flag to reset
*/
void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag);
/** Check if RTC Flag is set
*
* @param[in] flag The flag to check
*
* @return true if set
*/
bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag);
/** Set RTC boot mode
*
* @param[in] mode The mode to set
*/
void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode);
/** Get RTC boot mode
*
* @return The RTC boot mode.
*/
FuriHalRtcBootMode furi_hal_rtc_get_boot_mode();
/** Set Heap Track mode
*
* @param[in] mode The mode to set
*/
void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode);
/** Get RTC Heap Track mode
*
* @return The RTC heap track mode.
*/
FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode();
/** Set locale units
*
* @param[in] mode The RTC Locale Units
*/
void furi_hal_rtc_set_locale_units(FuriHalRtcLocaleUnits value);
/** Get RTC Locale Units
*
* @return The RTC Locale Units.
*/
FuriHalRtcLocaleUnits furi_hal_rtc_get_locale_units();
/** Set RTC Locale Time Format
*
* @param[in] value The RTC Locale Time Format
*/
void furi_hal_rtc_set_locale_timeformat(FuriHalRtcLocaleTimeFormat value);
/** Get RTC Locale Time Format
*
* @return The RTC Locale Time Format.
*/
FuriHalRtcLocaleTimeFormat furi_hal_rtc_get_locale_timeformat();
/** Set RTC Locale Date Format
*
* @param[in] value The RTC Locale Date Format
*/
void furi_hal_rtc_set_locale_dateformat(FuriHalRtcLocaleDateFormat value);
/** Get RTC Locale Date Format
*
* @return The RTC Locale Date Format
*/
FuriHalRtcLocaleDateFormat furi_hal_rtc_get_locale_dateformat();
/** Set RTC Date Time
*
* @param datetime The date time to set
*/
void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime);
/** Get RTC Date Time
*
* @param datetime The datetime
*/
void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime);
/** Validate Date Time
*
* @param datetime The datetime to validate
*
* @return { description_of_the_return_value }
*/
bool furi_hal_rtc_validate_datetime(FuriHalRtcDateTime* datetime);
/** Set RTC Fault Data
*
* @param[in] value The value
*/
void furi_hal_rtc_set_fault_data(uint32_t value);
/** Get RTC Fault Data
*
* @return RTC Fault Data value
*/
uint32_t furi_hal_rtc_get_fault_data();
/** Set Pin Fails count
*
* @param[in] value The Pin Fails count
*/
void furi_hal_rtc_set_pin_fails(uint32_t value);
/** Get Pin Fails count
*
* @return Pin Fails Count
*/
uint32_t furi_hal_rtc_get_pin_fails();
/** Get UNIX Timestamp
*
* @return Unix Timestamp in seconds from UNIX epoch start
*/
uint32_t furi_hal_rtc_get_timestamp();
/** Convert DateTime to UNIX timestamp
*
* @param datetime The datetime
*
* @return UNIX Timestamp in seconds from UNIX epoch start
*/
uint32_t furi_hal_rtc_datetime_to_timestamp(FuriHalRtcDateTime* datetime);
#ifdef __cplusplus
@@ -4,16 +4,63 @@
*/
#pragma once
#include <furi.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Init speaker */
void furi_hal_speaker_init();
/** Deinit speaker */
void furi_hal_speaker_deinit();
/** Acquire speaker ownership
*
* @warning You must acquire speaker ownership before use
*
* @param timeout Timeout during which speaker ownership must be acquired
*
* @return bool returns true on success
*/
FURI_WARN_UNUSED bool furi_hal_speaker_acquire(uint32_t timeout);
/** Release speaker ownership
*
* @warning You must release speaker ownership after use
*/
void furi_hal_speaker_release();
/** Check current process speaker ownership
*
* @warning always returns true if called from ISR
*
* @return bool returns true if process owns speaker
*/
bool furi_hal_speaker_is_mine();
/** Play a note
*
* @warning no ownership check if called from ISR
*
* @param frequency The frequency
* @param volume The volume
*/
void furi_hal_speaker_start(float frequency, float volume);
/** Set volume
*
* @warning no ownership check if called from ISR
*
* @param volume The volume
*/
void furi_hal_speaker_set_volume(float volume);
/** Stop playback
*
* @warning no ownership check if called from ISR
*/
void furi_hal_speaker_stop();
#ifdef __cplusplus
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <stddef.h>
#include <toolbox/level_duration.h>
#include <furi_hal_gpio.h>
#ifdef __cplusplus
extern "C" {
@@ -34,9 +35,9 @@ typedef enum {
/** Switchable Radio Paths */
typedef enum {
FuriHalSubGhzPathIsolate, /**< Isolate Radio from antenna */
FuriHalSubGhzPath433, /**< Center Frquency: 433MHz. Path 1: SW1RF1-SW2RF2, LCLCL */
FuriHalSubGhzPath315, /**< Center Frquency: 315MHz. Path 2: SW1RF2-SW2RF1, LCLCLCL */
FuriHalSubGhzPath868, /**< Center Frquency: 868MHz. Path 3: SW1RF3-SW2RF3, LCLC */
FuriHalSubGhzPath433, /**< Center Frequency: 433MHz. Path 1: SW1RF1-SW2RF2, LCLCL */
FuriHalSubGhzPath315, /**< Center Frequency: 315MHz. Path 2: SW1RF2-SW2RF1, LCLCLCL */
FuriHalSubGhzPath868, /**< Center Frequency: 868MHz. Path 3: SW1RF3-SW2RF3, LCLC */
} FuriHalSubGhzPath;
/** SubGhz state */
@@ -60,8 +61,17 @@ typedef enum {
SubGhzRegulationTxRx, /**TxRx*/
} SubGhzRegulation;
/* Mirror RX/TX async modulation signal to specified pin
*
* @warning Configures pin to output mode. Make sure it is not connected
* directly to power or ground.
*
* @param[in] pin pointer to the gpio pin structure or NULL to disable
*/
void furi_hal_subghz_set_async_mirror_pin(const GpioPin* pin);
/** Initialize and switch to power save mode Used by internal API-HAL
* initalization routine Can be used to reinitialize device to safe state and
* initialization routine Can be used to reinitialize device to safe state and
* send it to sleep
*/
void furi_hal_subghz_init();
@@ -105,13 +115,13 @@ void furi_hal_subghz_load_patable(const uint8_t data[8]);
*/
void furi_hal_subghz_write_packet(const uint8_t* data, uint8_t size);
/** Check if recieve pipe is not empty
/** Check if receive pipe is not empty
*
* @return true if not empty
*/
bool furi_hal_subghz_rx_pipe_not_empty();
/** Check if recieved data crc is valid
/** Check if received data crc is valid
*
* @return true if valid
*/
@@ -132,7 +142,7 @@ void furi_hal_subghz_flush_rx();
*/
void furi_hal_subghz_flush_tx();
/** Shutdown Issue spwd command
/** Shutdown Issue SPWD command
* @warning registers content will be lost
*/
void furi_hal_subghz_shutdown();
@@ -146,7 +156,7 @@ void furi_hal_subghz_reset();
*/
void furi_hal_subghz_idle();
/** Switch to Recieve
/** Switch to Receive
*/
void furi_hal_subghz_rx();
@@ -172,7 +182,7 @@ uint8_t furi_hal_subghz_get_lqi();
*
* @param value frequency in Hz
*
* @return true if frequncy is valid, otherwise false
* @return true if frequency is valid, otherwise false
*/
bool furi_hal_subghz_is_frequency_valid(uint32_t value);
@@ -181,7 +191,7 @@ bool furi_hal_subghz_is_frequency_valid(uint32_t value);
*
* @param value frequency in Hz
*
* @return real frequency in herz
* @return real frequency in Hz
*/
uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value);
@@ -189,7 +199,7 @@ uint32_t furi_hal_subghz_set_frequency_and_path(uint32_t value);
*
* @param value frequency in Hz
*
* @return real frequency in herz
* @return real frequency in Hz
*/
uint32_t furi_hal_subghz_set_frequency(uint32_t value);
+4
View File
@@ -11,6 +11,10 @@ extern "C" {
#include <cmsis_compiler.h>
#ifndef FURI_WARN_UNUSED
#define FURI_WARN_UNUSED __attribute__((warn_unused_result))
#endif
#ifndef FURI_IS_IRQ_MASKED
#define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U)
#endif
+2
View File
@@ -1,6 +1,7 @@
#include "lfrfid_protocols.h"
#include "protocol_em4100.h"
#include "protocol_h10301.h"
#include "protocol_idteck.h"
#include "protocol_indala26.h"
#include "protocol_io_prox_xsf.h"
#include "protocol_awid.h"
@@ -19,6 +20,7 @@
const ProtocolBase* lfrfid_protocols[] = {
[LFRFIDProtocolEM4100] = &protocol_em4100,
[LFRFIDProtocolH10301] = &protocol_h10301,
[LFRFIDProtocolIdteck] = &protocol_idteck,
[LFRFIDProtocolIndala26] = &protocol_indala26,
[LFRFIDProtocolIOProxXSF] = &protocol_io_prox_xsf,
[LFRFIDProtocolAwid] = &protocol_awid,
+1
View File
@@ -10,6 +10,7 @@ typedef enum {
typedef enum {
LFRFIDProtocolEM4100,
LFRFIDProtocolH10301,
LFRFIDProtocolIdteck,
LFRFIDProtocolIndala26,
LFRFIDProtocolIOProxXSF,
LFRFIDProtocolAwid,
+269
View File
@@ -0,0 +1,269 @@
#include <furi.h>
#include <toolbox/protocols/protocol.h>
#include <lfrfid/tools/bit_lib.h>
#include "lfrfid_protocols.h"
// Example: 4944544B 351FBE4B
// 01001001 01000100 01010100 01001011 00110101 00011111 10111110 01001011
// 4 9 4 4 5 4 4 B 3 5 1 F B E 4 B
// 0100 1001 0100 0100 0101 0100 0100 1011 0011 0101 0001 1111 1011 1110 0100 1011
#define IDTECK_PREAMBLE_BIT_SIZE (32)
#define IDTECK_PREAMBLE_DATA_SIZE (8)
#define IDTECK_ENCODED_BIT_SIZE (64)
#define IDTECK_ENCODED_DATA_SIZE (((IDTECK_ENCODED_BIT_SIZE) / 8) + IDTECK_PREAMBLE_DATA_SIZE)
#define IDTECK_ENCODED_DATA_LAST ((IDTECK_ENCODED_BIT_SIZE) / 8)
#define IDTECK_DECODED_BIT_SIZE (64)
#define IDTECK_DECODED_DATA_SIZE (8)
#define IDTECK_US_PER_BIT (255)
#define IDTECK_ENCODER_PULSES_PER_BIT (16)
typedef struct {
uint8_t data_index;
uint8_t bit_clock_index;
bool last_bit;
bool current_polarity;
bool pulse_phase;
} ProtocolIdteckEncoder;
typedef struct {
uint8_t encoded_data[IDTECK_ENCODED_DATA_SIZE];
uint8_t negative_encoded_data[IDTECK_ENCODED_DATA_SIZE];
uint8_t corrupted_encoded_data[IDTECK_ENCODED_DATA_SIZE];
uint8_t corrupted_negative_encoded_data[IDTECK_ENCODED_DATA_SIZE];
uint8_t data[IDTECK_DECODED_DATA_SIZE];
ProtocolIdteckEncoder encoder;
} ProtocolIdteck;
ProtocolIdteck* protocol_idteck_alloc(void) {
ProtocolIdteck* protocol = malloc(sizeof(ProtocolIdteck));
return protocol;
};
void protocol_idteck_free(ProtocolIdteck* protocol) {
free(protocol);
};
uint8_t* protocol_idteck_get_data(ProtocolIdteck* protocol) {
return protocol->data;
};
void protocol_idteck_decoder_start(ProtocolIdteck* protocol) {
memset(protocol->encoded_data, 0, IDTECK_ENCODED_DATA_SIZE);
memset(protocol->negative_encoded_data, 0, IDTECK_ENCODED_DATA_SIZE);
memset(protocol->corrupted_encoded_data, 0, IDTECK_ENCODED_DATA_SIZE);
memset(protocol->corrupted_negative_encoded_data, 0, IDTECK_ENCODED_DATA_SIZE);
};
static bool protocol_idteck_check_preamble(uint8_t* data, size_t bit_index) {
// Preamble 01001001 01000100 01010100 01001011
if(*(uint32_t*)&data[bit_index / 8] != 0b01001011010101000100010001001001) return false;
return true;
}
static bool protocol_idteck_can_be_decoded(uint8_t* data) {
if(!protocol_idteck_check_preamble(data, 0)) return false;
return true;
}
static bool protocol_idteck_decoder_feed_internal(bool polarity, uint32_t time, uint8_t* data) {
time += (IDTECK_US_PER_BIT / 2);
size_t bit_count = (time / IDTECK_US_PER_BIT);
bool result = false;
if(bit_count < IDTECK_ENCODED_BIT_SIZE) {
for(size_t i = 0; i < bit_count; i++) {
bit_lib_push_bit(data, IDTECK_ENCODED_DATA_SIZE, polarity);
if(protocol_idteck_can_be_decoded(data)) {
result = true;
break;
}
}
}
return result;
}
static void protocol_idteck_decoder_save(uint8_t* data_to, const uint8_t* data_from) {
bit_lib_copy_bits(data_to, 0, 64, data_from, 0);
}
bool protocol_idteck_decoder_feed(ProtocolIdteck* protocol, bool level, uint32_t duration) {
bool result = false;
if(duration > (IDTECK_US_PER_BIT / 2)) {
if(protocol_idteck_decoder_feed_internal(level, duration, protocol->encoded_data)) {
protocol_idteck_decoder_save(protocol->data, protocol->encoded_data);
FURI_LOG_D("Idteck", "Positive");
result = true;
return result;
}
if(protocol_idteck_decoder_feed_internal(
!level, duration, protocol->negative_encoded_data)) {
protocol_idteck_decoder_save(protocol->data, protocol->negative_encoded_data);
FURI_LOG_D("Idteck", "Negative");
result = true;
return result;
}
}
if(duration > (IDTECK_US_PER_BIT / 4)) {
// Try to decode wrong phase synced data
if(level) {
duration += 120;
} else {
if(duration > 120) {
duration -= 120;
}
}
if(protocol_idteck_decoder_feed_internal(
level, duration, protocol->corrupted_encoded_data)) {
protocol_idteck_decoder_save(protocol->data, protocol->corrupted_encoded_data);
FURI_LOG_D("Idteck", "Positive Corrupted");
result = true;
return result;
}
if(protocol_idteck_decoder_feed_internal(
!level, duration, protocol->corrupted_negative_encoded_data)) {
protocol_idteck_decoder_save(
protocol->data, protocol->corrupted_negative_encoded_data);
FURI_LOG_D("Idteck", "Negative Corrupted");
result = true;
return result;
}
}
return result;
};
bool protocol_idteck_encoder_start(ProtocolIdteck* protocol) {
memset(protocol->encoded_data, 0, IDTECK_ENCODED_DATA_SIZE);
*(uint32_t*)&protocol->encoded_data[0] = 0b01001011010101000100010001001001;
bit_lib_copy_bits(protocol->encoded_data, 32, 32, protocol->data, 32);
protocol->encoder.last_bit =
bit_lib_get_bit(protocol->encoded_data, IDTECK_ENCODED_BIT_SIZE - 1);
protocol->encoder.data_index = 0;
protocol->encoder.current_polarity = true;
protocol->encoder.pulse_phase = true;
protocol->encoder.bit_clock_index = 0;
return true;
};
LevelDuration protocol_idteck_encoder_yield(ProtocolIdteck* protocol) {
LevelDuration level_duration;
ProtocolIdteckEncoder* encoder = &protocol->encoder;
if(encoder->pulse_phase) {
level_duration = level_duration_make(encoder->current_polarity, 1);
encoder->pulse_phase = false;
} else {
level_duration = level_duration_make(!encoder->current_polarity, 1);
encoder->pulse_phase = true;
encoder->bit_clock_index++;
if(encoder->bit_clock_index >= IDTECK_ENCODER_PULSES_PER_BIT) {
encoder->bit_clock_index = 0;
bool current_bit = bit_lib_get_bit(protocol->encoded_data, encoder->data_index);
if(current_bit != encoder->last_bit) {
encoder->current_polarity = !encoder->current_polarity;
}
encoder->last_bit = current_bit;
bit_lib_increment_index(encoder->data_index, IDTECK_ENCODED_BIT_SIZE);
}
}
return level_duration;
};
// factory code
static uint32_t get_fc(const uint8_t* data) {
uint32_t fc = 0;
fc = bit_lib_get_bits_32(data, 0, 32);
return fc;
}
// card number
static uint32_t get_card(const uint8_t* data) {
uint32_t cn = 0;
cn = bit_lib_get_bits_32(data, 32, 32);
return cn;
}
void protocol_idteck_render_data_internal(ProtocolIdteck* protocol, FuriString* result, bool brief) {
const uint32_t fc = get_fc(protocol->data);
const uint32_t card = get_card(protocol->data);
if(brief) {
furi_string_printf(result, "FC: %08lX\r\nCard: %08lX", fc, card);
} else {
furi_string_printf(
result,
"FC: %08lX\r\n"
"Card: %08lX\r\n",
fc,
card);
}
}
void protocol_idteck_render_data(ProtocolIdteck* protocol, FuriString* result) {
protocol_idteck_render_data_internal(protocol, result, false);
}
void protocol_idteck_render_brief_data(ProtocolIdteck* protocol, FuriString* result) {
protocol_idteck_render_data_internal(protocol, result, true);
}
bool protocol_idteck_write_data(ProtocolIdteck* protocol, void* data) {
LFRFIDWriteRequest* request = (LFRFIDWriteRequest*)data;
bool result = false;
protocol_idteck_encoder_start(protocol);
if(request->write_type == LFRFIDWriteTypeT5577) {
request->t5577.block[0] = LFRFID_T5577_BITRATE_RF_32 | LFRFID_T5577_MODULATION_PSK1 |
(2 << LFRFID_T5577_MAXBLOCK_SHIFT);
request->t5577.block[1] = bit_lib_get_bits_32(protocol->encoded_data, 0, 32);
request->t5577.block[2] = bit_lib_get_bits_32(protocol->encoded_data, 32, 32);
request->t5577.blocks_to_write = 3;
result = true;
}
return result;
};
const ProtocolBase protocol_idteck = {
.name = "Idteck",
.manufacturer = "IDTECK",
.data_size = IDTECK_DECODED_DATA_SIZE,
.features = LFRFIDFeaturePSK,
.validate_count = 6,
.alloc = (ProtocolAlloc)protocol_idteck_alloc,
.free = (ProtocolFree)protocol_idteck_free,
.get_data = (ProtocolGetData)protocol_idteck_get_data,
.decoder =
{
.start = (ProtocolDecoderStart)protocol_idteck_decoder_start,
.feed = (ProtocolDecoderFeed)protocol_idteck_decoder_feed,
},
.encoder =
{
.start = (ProtocolEncoderStart)protocol_idteck_encoder_start,
.yield = (ProtocolEncoderYield)protocol_idteck_encoder_yield,
},
.render_data = (ProtocolRenderData)protocol_idteck_render_data,
.render_brief_data = (ProtocolRenderData)protocol_idteck_render_brief_data,
.write_data = (ProtocolWriteData)protocol_idteck_write_data,
};
+4
View File
@@ -0,0 +1,4 @@
#pragma once
#include <toolbox/protocols/protocol.h>
extern const ProtocolBase protocol_idteck;
@@ -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[];
+1 -1
View File
@@ -12,7 +12,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = {
&subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec,
&subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2,
&subghz_protocol_honeywell_wdb, &subghz_protocol_magellan, &subghz_protocol_intertechno_v3,
&subghz_protocol_clemsa, &subghz_protocol_ansonic,
&subghz_protocol_clemsa, &subghz_protocol_ansonic, &subghz_protocol_smc5326,
};
const SubGhzProtocolRegistry subghz_protocol_registry = {
+1
View File
@@ -36,5 +36,6 @@
#include "intertechno_v3.h"
#include "clemsa.h"
#include "ansonic.h"
#include "smc5326.h"
extern const SubGhzProtocolRegistry subghz_protocol_registry;
+387
View File
@@ -0,0 +1,387 @@
#include "smc5326.h"
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
/*
* Help
* https://datasheetspdf.com/pdf-file/532079/Aslic/AX5326-4/1
*
*/
#define TAG "SubGhzProtocolSMC5326"
#define DIP_P 0b11 //(+)
#define DIP_O 0b10 //(0)
#define DIP_N 0b00 //(-)
#define DIP_PATTERN "%c%c%c%c%c%c%c%c"
#define SHOW_DIP_P(dip, check_dip) \
((((dip >> 0xE) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0xC) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0xA) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x8) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x6) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x4) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x2) & 0x3) == check_dip) ? '*' : '_'), \
((((dip >> 0x0) & 0x3) == check_dip) ? '*' : '_')
static const SubGhzBlockConst subghz_protocol_smc5326_const = {
.te_short = 300,
.te_long = 900,
.te_delta = 200,
.min_count_bit_for_found = 25,
};
struct SubGhzProtocolDecoderSMC5326 {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint32_t te;
uint32_t last_data;
};
struct SubGhzProtocolEncoderSMC5326 {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
uint32_t te;
};
typedef enum {
SMC5326DecoderStepReset = 0,
SMC5326DecoderStepSaveDuration,
SMC5326DecoderStepCheckDuration,
} SMC5326DecoderStep;
const SubGhzProtocolDecoder subghz_protocol_smc5326_decoder = {
.alloc = subghz_protocol_decoder_smc5326_alloc,
.free = subghz_protocol_decoder_smc5326_free,
.feed = subghz_protocol_decoder_smc5326_feed,
.reset = subghz_protocol_decoder_smc5326_reset,
.get_hash_data = subghz_protocol_decoder_smc5326_get_hash_data,
.serialize = subghz_protocol_decoder_smc5326_serialize,
.deserialize = subghz_protocol_decoder_smc5326_deserialize,
.get_string = subghz_protocol_decoder_smc5326_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_smc5326_encoder = {
.alloc = subghz_protocol_encoder_smc5326_alloc,
.free = subghz_protocol_encoder_smc5326_free,
.deserialize = subghz_protocol_encoder_smc5326_deserialize,
.stop = subghz_protocol_encoder_smc5326_stop,
.yield = subghz_protocol_encoder_smc5326_yield,
};
const SubGhzProtocol subghz_protocol_smc5326 = {
.name = SUBGHZ_PROTOCOL_SMC5326_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_315 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load |
SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_smc5326_decoder,
.encoder = &subghz_protocol_smc5326_encoder,
};
void* subghz_protocol_encoder_smc5326_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolEncoderSMC5326* instance = malloc(sizeof(SubGhzProtocolEncoderSMC5326));
instance->base.protocol = &subghz_protocol_smc5326;
instance->generic.protocol_name = instance->base.protocol->name;
instance->encoder.repeat = 10;
instance->encoder.size_upload = 128;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;
}
void subghz_protocol_encoder_smc5326_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderSMC5326* instance = context;
free(instance->encoder.upload);
free(instance);
}
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderSMC5326 instance
* @return true On success
*/
static bool subghz_protocol_encoder_smc5326_get_upload(SubGhzProtocolEncoderSMC5326* instance) {
furi_assert(instance);
size_t index = 0;
size_t size_upload = (instance->generic.data_count_bit * 2) + 2;
if(size_upload > instance->encoder.size_upload) {
FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
return false;
} else {
instance->encoder.size_upload = size_upload;
}
//Send key data
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
if(bit_read(instance->generic.data, i - 1)) {
//send bit 1
instance->encoder.upload[index++] =
level_duration_make(true, (uint32_t)instance->te * 3);
instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)instance->te);
} else {
//send bit 0
instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)instance->te);
instance->encoder.upload[index++] =
level_duration_make(false, (uint32_t)instance->te * 3);
}
}
//Send Stop bit
instance->encoder.upload[index++] = level_duration_make(true, (uint32_t)instance->te);
//Send PT_GUARD
instance->encoder.upload[index++] = level_duration_make(false, (uint32_t)instance->te * 25);
return true;
}
bool subghz_protocol_encoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderSMC5326* instance = context;
bool res = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) {
FURI_LOG_E(TAG, "Missing TE");
break;
}
if(instance->generic.data_count_bit !=
subghz_protocol_smc5326_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
//optional parameter parameter
flipper_format_read_uint32(
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
if(!subghz_protocol_encoder_smc5326_get_upload(instance)) break;
instance->encoder.is_running = true;
res = true;
} while(false);
return res;
}
void subghz_protocol_encoder_smc5326_stop(void* context) {
SubGhzProtocolEncoderSMC5326* instance = context;
instance->encoder.is_running = false;
}
LevelDuration subghz_protocol_encoder_smc5326_yield(void* context) {
SubGhzProtocolEncoderSMC5326* instance = context;
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
instance->encoder.is_running = false;
return level_duration_reset();
}
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
if(++instance->encoder.front == instance->encoder.size_upload) {
instance->encoder.repeat--;
instance->encoder.front = 0;
}
return ret;
}
void* subghz_protocol_decoder_smc5326_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolDecoderSMC5326* instance = malloc(sizeof(SubGhzProtocolDecoderSMC5326));
instance->base.protocol = &subghz_protocol_smc5326;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_smc5326_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderSMC5326* instance = context;
free(instance);
}
void subghz_protocol_decoder_smc5326_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderSMC5326* instance = context;
instance->decoder.parser_step = SMC5326DecoderStepReset;
instance->last_data = 0;
}
void subghz_protocol_decoder_smc5326_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderSMC5326* instance = context;
switch(instance->decoder.parser_step) {
case SMC5326DecoderStepReset:
if((!level) && (DURATION_DIFF(duration, subghz_protocol_smc5326_const.te_short * 24) <
subghz_protocol_smc5326_const.te_delta * 12)) {
//Found Preambula
instance->decoder.parser_step = SMC5326DecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->te = 0;
}
break;
case SMC5326DecoderStepSaveDuration:
//save duration
if(level) {
instance->decoder.te_last = duration;
instance->te += duration;
instance->decoder.parser_step = SMC5326DecoderStepCheckDuration;
}
break;
case SMC5326DecoderStepCheckDuration:
if(!level) {
if(duration >= ((uint32_t)subghz_protocol_smc5326_const.te_long * 2)) {
instance->decoder.parser_step = SMC5326DecoderStepSaveDuration;
if(instance->decoder.decode_count_bit ==
subghz_protocol_smc5326_const.min_count_bit_for_found) {
if((instance->last_data == instance->decoder.decode_data) &&
instance->last_data) {
instance->te /= (instance->decoder.decode_count_bit * 4 + 1);
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
instance->last_data = instance->decoder.decode_data;
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
instance->te = 0;
break;
}
instance->te += duration;
if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_smc5326_const.te_short) <
subghz_protocol_smc5326_const.te_delta) &&
(DURATION_DIFF(duration, subghz_protocol_smc5326_const.te_long) <
subghz_protocol_smc5326_const.te_delta * 3)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = SMC5326DecoderStepSaveDuration;
} else if(
(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_smc5326_const.te_long) <
subghz_protocol_smc5326_const.te_delta * 3) &&
(DURATION_DIFF(duration, subghz_protocol_smc5326_const.te_short) <
subghz_protocol_smc5326_const.te_delta)) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = SMC5326DecoderStepSaveDuration;
} else {
instance->decoder.parser_step = SMC5326DecoderStepReset;
}
} else {
instance->decoder.parser_step = SMC5326DecoderStepReset;
}
break;
}
}
uint8_t subghz_protocol_decoder_smc5326_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderSMC5326* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool subghz_protocol_decoder_smc5326_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolDecoderSMC5326* instance = context;
bool res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
if(res && !flipper_format_write_uint32(flipper_format, "TE", &instance->te, 1)) {
FURI_LOG_E(TAG, "Unable to add TE");
res = false;
}
return res;
}
bool subghz_protocol_decoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderSMC5326* instance = context;
bool res = false;
do {
if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
FURI_LOG_E(TAG, "Deserialize error");
break;
}
if(instance->generic.data_count_bit !=
subghz_protocol_smc5326_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
break;
}
if(!flipper_format_read_uint32(flipper_format, "TE", (uint32_t*)&instance->te, 1)) {
FURI_LOG_E(TAG, "Missing TE");
break;
}
res = true;
} while(false);
return res;
}
static void subghz_protocol_smc5326_get_event_serialize(uint8_t event, FuriString* output) {
furi_string_cat_printf(
output,
"%s%s%s%s\r\n",
(((event >> 6) & 0x3) == 0x3 ? "B1 " : ""),
(((event >> 4) & 0x3) == 0x3 ? "B2 " : ""),
(((event >> 2) & 0x3) == 0x3 ? "B3 " : ""),
(((event >> 0) & 0x3) == 0x3 ? "B4 " : ""));
}
void subghz_protocol_decoder_smc5326_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderSMC5326* instance = context;
uint32_t data = (uint32_t)((instance->generic.data >> 9) & 0xFFFF);
furi_string_cat_printf(
output,
"%s %dbit\r\n"
"Key:%07lX Te:%ldus\r\n"
" +: " DIP_PATTERN "\r\n"
" o: " DIP_PATTERN " ",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data & 0x1FFFFFF),
instance->te,
SHOW_DIP_P(data, DIP_P),
SHOW_DIP_P(data, DIP_O));
subghz_protocol_smc5326_get_event_serialize(instance->generic.data >> 1, output);
furi_string_cat_printf(output, " -: " DIP_PATTERN "\r\n", SHOW_DIP_P(data, DIP_N));
}
+107
View File
@@ -0,0 +1,107 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_SMC5326_NAME "SMC5326"
typedef struct SubGhzProtocolDecoderSMC5326 SubGhzProtocolDecoderSMC5326;
typedef struct SubGhzProtocolEncoderSMC5326 SubGhzProtocolEncoderSMC5326;
extern const SubGhzProtocolDecoder subghz_protocol_smc5326_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_smc5326_encoder;
extern const SubGhzProtocol subghz_protocol_smc5326;
/**
* Allocate SubGhzProtocolEncoderSMC5326.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolEncoderSMC5326* pointer to a SubGhzProtocolEncoderSMC5326 instance
*/
void* subghz_protocol_encoder_smc5326_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolEncoderSMC5326.
* @param context Pointer to a SubGhzProtocolEncoderSMC5326 instance
*/
void subghz_protocol_encoder_smc5326_free(void* context);
/**
* Deserialize and generating an upload to send.
* @param context Pointer to a SubGhzProtocolEncoderSMC5326 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
bool subghz_protocol_encoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Forced transmission stop.
* @param context Pointer to a SubGhzProtocolEncoderSMC5326 instance
*/
void subghz_protocol_encoder_smc5326_stop(void* context);
/**
* Getting the level and duration of the upload to be loaded into DMA.
* @param context Pointer to a SubGhzProtocolEncoderSMC5326 instance
* @return LevelDuration
*/
LevelDuration subghz_protocol_encoder_smc5326_yield(void* context);
/**
* Allocate SubGhzProtocolDecoderSMC5326.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolDecoderSMC5326* pointer to a SubGhzProtocolDecoderSMC5326 instance
*/
void* subghz_protocol_decoder_smc5326_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolDecoderSMC5326.
* @param context Pointer to a SubGhzProtocolDecoderSMC5326 instance
*/
void subghz_protocol_decoder_smc5326_free(void* context);
/**
* Reset decoder SubGhzProtocolDecoderSMC5326.
* @param context Pointer to a SubGhzProtocolDecoderSMC5326 instance
*/
void subghz_protocol_decoder_smc5326_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a SubGhzProtocolDecoderSMC5326 instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void subghz_protocol_decoder_smc5326_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a SubGhzProtocolDecoderSMC5326 instance
* @return hash Hash sum
*/
uint8_t subghz_protocol_decoder_smc5326_get_hash_data(void* context);
/**
* Serialize data SubGhzProtocolDecoderSMC5326.
* @param context Pointer to a SubGhzProtocolDecoderSMC5326 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 subghz_protocol_decoder_smc5326_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data SubGhzProtocolDecoderSMC5326.
* @param context Pointer to a SubGhzProtocolDecoderSMC5326 instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
bool subghz_protocol_decoder_smc5326_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a SubGhzProtocolDecoderSMC5326 instance
* @param output Resulting text
*/
void subghz_protocol_decoder_smc5326_get_string(void* context, FuriString* output);
+3 -3
View File
@@ -238,9 +238,9 @@ class FlipperStorage:
while read_size < size:
self.read.until("Ready?" + self.CLI_EOL)
self.send("y")
read_size = min(size - read_size, buffer_size)
filedata.extend(self.port.read(read_size))
read_size = read_size + read_size
chunk_size = min(size - read_size, buffer_size)
filedata.extend(self.port.read(chunk_size))
read_size = read_size + chunk_size
percent = str(math.ceil(read_size / size * 100))
total_chunks = str(math.ceil(size / buffer_size))
+24 -14
View File
@@ -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
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()
+1 -1
View File
@@ -24,7 +24,7 @@ def flp_serial_by_name(flp_name):
return ""
UPDATE_TIMEOUT = 30
UPDATE_TIMEOUT = 60
def main():