1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-13 05:06:30 +04:00

Merge branch 'dev' into release

This commit is contained in:
MX
2024-07-23 00:03:30 +03:00
780 changed files with 9840 additions and 5503 deletions

View File

@@ -1,5 +1,5 @@
diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c
index 9baa738..91ad7c1 100644
index d4c5b91..8b43599 100644
--- a/applications/services/notification/notification_app.c
+++ b/applications/services/notification/notification_app.c
@@ -9,6 +9,7 @@
@@ -10,7 +10,7 @@ index 9baa738..91ad7c1 100644
#define TAG "NotificationSrv"
@@ -589,6 +590,7 @@ int32_t notification_srv(void* p) {
@@ -588,6 +589,7 @@ int32_t notification_srv(void* p) {
break;
case SaveSettingsMessage:
notification_save_settings(app);
@@ -19,7 +19,7 @@ index 9baa738..91ad7c1 100644
}
diff --git a/applications/settings/notification_settings/notification_settings_app.c b/applications/settings/notification_settings/notification_settings_app.c
index 2a1d988..dda86f3 100644
index 7576dcf..ae022e2 100644
--- a/applications/settings/notification_settings/notification_settings_app.c
+++ b/applications/settings/notification_settings/notification_settings_app.c
@@ -3,6 +3,7 @@
@@ -99,7 +99,7 @@ index 2a1d988..dda86f3 100644
static uint32_t notification_app_settings_exit(void* context) {
UNUSED(context);
return VIEW_NONE;
@@ -192,8 +248,40 @@ static NotificationAppSettings* alloc_settings() {
@@ -192,8 +248,40 @@ static NotificationAppSettings* alloc_settings(void) {
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, contrast_text[value_index]);
@@ -143,7 +143,7 @@ index 2a1d988..dda86f3 100644
variable_item_set_current_value_index(item, value_index);
diff --git a/applications/settings/notification_settings/rgb_backlight.c b/applications/settings/notification_settings/rgb_backlight.c
new file mode 100644
index 0000000..98f0d3a
index 0000000..4edd775
--- /dev/null
+++ b/applications/settings/notification_settings/rgb_backlight.c
@@ -0,0 +1,217 @@
@@ -263,7 +263,7 @@ index 0000000..98f0d3a
+ storage_file_free(file);
+ furi_record_close(RECORD_STORAGE);
+ rgb_settings.settings_is_loaded = true;
+};
+}
+
+void rgb_backlight_save_settings(void) {
+ RGBBacklightSettings settings;
@@ -294,7 +294,7 @@ index 0000000..98f0d3a
+ storage_file_close(file);
+ storage_file_free(file);
+ furi_record_close(RECORD_STORAGE);
+};
+}
+
+RGBBacklightSettings* rgb_backlight_get_settings(void) {
+ if(!rgb_settings.settings_is_loaded) {
@@ -366,7 +366,7 @@ index 0000000..98f0d3a
+}
diff --git a/applications/settings/notification_settings/rgb_backlight.h b/applications/settings/notification_settings/rgb_backlight.h
new file mode 100644
index 0000000..68dacda
index 0000000..f215ed3
--- /dev/null
+++ b/applications/settings/notification_settings/rgb_backlight.h
@@ -0,0 +1,91 @@
@@ -461,10 +461,9 @@ index 0000000..68dacda
+ * @return Указатель на строку с названием цвета
+ */
+const char* rgb_backlight_get_color_text(uint8_t index);
\ No newline at end of file
diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c
new file mode 100644
index 0000000..572e1df
index 0000000..b89f82a
--- /dev/null
+++ b/lib/drivers/SK6805.c
@@ -0,0 +1,101 @@
@@ -571,7 +570,7 @@ index 0000000..572e1df
+}
diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h
new file mode 100644
index 0000000..7c58956
index 0000000..c97054f
--- /dev/null
+++ b/lib/drivers/SK6805.h
@@ -0,0 +1,51 @@
@@ -626,9 +625,8 @@ index 0000000..7c58956
+void SK6805_update(void);
+
+#endif /* SK6805_H_ */
\ No newline at end of file
diff --git a/targets/f7/furi_hal/furi_hal_light.c b/targets/f7/furi_hal/furi_hal_light.c
index 83e1603..45798ca 100644
index 621478d..ef15153 100644
--- a/targets/f7/furi_hal/furi_hal_light.c
+++ b/targets/f7/furi_hal/furi_hal_light.c
@@ -3,6 +3,7 @@

View File

@@ -3,22 +3,55 @@ Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: AlwaysBreak
AlignArrayOfStructures: None
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
AlignCompound: true
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseColons: false
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: false
AlignTrailingComments:
Kind: Never
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
@@ -27,17 +60,18 @@ AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
@@ -46,38 +80,35 @@ BraceWrapping:
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: false
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeColon
BreakStringLiterals: false
ColumnLimit: 99
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: BinPack
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
- M_EACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
@@ -97,19 +128,30 @@ IncludeCategories:
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentRequiresClause: false
IndentWidth: 4
IndentWrappedFunctionNames: true
InsertBraces: false
InsertNewlineAtEOF: true
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
KeepEmptyLinesAtEOF: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
@@ -119,34 +161,44 @@ ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 10
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: false
RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: true
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: Never
SortJavaStaticImport: Before
SortUsingDeclarations: false
SortUsingDeclarations: Never
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: Never
SpaceBeforeParensOptions:
AfterControlStatements: false
@@ -155,32 +207,35 @@ SpaceBeforeParensOptions:
AfterFunctionDeclarationName: false
AfterIfMacros: false
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInParens: Never
SpacesInParensOptions:
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: c++03
Standard: c++20
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE

3
.gitignore vendored
View File

@@ -45,9 +45,6 @@ null.d
.sconsign.dblite
# Visual Studio Code
/.vscode
# bundle output
/dist
/artifacts-default

3
.gitmodules vendored
View File

@@ -23,9 +23,6 @@
[submodule "lib/mbedtls"]
path = lib/mbedtls
url = https://github.com/Mbed-TLS/mbedtls.git
[submodule "lib/cxxheaderparser"]
path = lib/cxxheaderparser
url = https://github.com/robotpy/cxxheaderparser.git
[submodule "lib/heatshrink"]
path = lib/heatshrink
url = https://github.com/flipperdevices/heatshrink.git

View File

@@ -3,10 +3,12 @@
//-V:M_EACH:1048,1044
//-V:ARRAY_DEF:760,747,568,776,729,712,654,1103
//-V:LIST_DEF:760,747,568,712,729,654,776,1103
//-V:LIST_DUAL_PUSH_DEF:524,760,774
//-V:BPTREE_DEF2:779,1086,557,773,512
//-V:DICT_DEF2:779,524,776,760,1044,1001,729,590,568,747,685,1103
//-V:ALGO_DEF:1048,747,1044
//-V:TUPLE_DEF2:524,590,1001,760
//-V:DEQUE_DEF:658,747,760
# Non-severe malloc/null pointer deref warnings
//-V::522:2,3

8
.sublime-project vendored
View File

@@ -8,13 +8,17 @@
"settings": {
"LSP": {
"clangd": {
"enabled": true,
"initializationOptions": {
// Use with toolchain version 39+
// Set `"binary": "custom",` option in LSP-clangd config to use toolchain clangd
// "custom_command": ["toolchain/current/bin/clangd"],
"clangd.compile-commands-dir": "build/latest",
"clangd.header-insertion": "never",
"clangd.query-driver": "**",
"clangd.query-driver": "**/arm-none-eabi-*",
"clangd.clang-tidy": true,
},
"enabled": true,
},
},
},

8
.vscode/.gitignore vendored
View File

@@ -1,5 +1,3 @@
/c_cpp_properties.json
/extensions.json
/launch.json
/settings.json
/tasks.json
*
!example/
!ReadMe.md

View File

@@ -1,11 +1,7 @@
{
"C_Cpp.default.cStandard": "gnu23",
"C_Cpp.default.cppStandard": "c++20",
"python.formatting.provider": "black",
"workbench.tree.indent": 12,
"cortex-debug.enableTelemetry": false,
"cortex-debug.variableUseNaturalFormat": true,
"cortex-debug.showRTOS": true,
"cortex-debug.armToolchainPath": "${workspaceFolder}/toolchain/current/bin",
"cortex-debug.openocdPath": "${workspaceFolder}/toolchain/current/bin/openocd",
"cortex-debug.gdbPath": "${workspaceFolder}/toolchain/current/bin/arm-none-eabi-gdb-py3",
@@ -16,9 +12,9 @@
"SConstruct": "python",
"*.fam": "python"
},
// "clangd.path": "${workspaceFolder}/toolchain/current/bin/clangd@FBT_PLATFORM_EXECUTABLE_EXT@",
"clangd.arguments": [
// We might be able to tighten this a bit more to only include the correct toolchain.
"--query-driver=**",
"--query-driver=**/arm-none-eabi-*",
"--compile-commands-dir=${workspaceFolder}/build/latest",
"--clang-tidy",
"--header-insertion=never"

View File

@@ -1,57 +1,64 @@
## Main changes
- SubGHz:
- Add new protocol - legrand 18bit (by @user890104)
- OFW: Princeton protocol add custom guard time support
- Princeton fix guard time bounds and show guard time multiplier in UI
- **Novoferm** remotes full support
- Fix Decode scene in RAW files
- Add manually -> Add Sommer FM238 option for cases when default option doesn't work (named as Sommer fm2)
- Remove broken preset modulation
- Normstahl, Sommer, MHouse, Aprimatic -> Fixes for button codes and more in Add manually
- Custom button improvements for MHouse, Novoferm, Nice Smilo
- Hormann EcoStar -> Add manually support, and custom button support
- Hormann HSM 44bit static -> Button code decoding fix
- Choose RSSI threshold for Hopping mode (by @Willy-JL)
- NFC:
- Fix Mifare DESFire reading (revert of buffer check workaround for rare emv cases) (some emv cards can be read only via Extra Actions -> Read specific card type -> EMV)
- Better plugins(parsers) loading - much faster emulation launch from favourites, no more lags in Saved menu
- OFW: MF Ultralight Original write support
- OFW: Mifare Plus detection support
- OFW: Felica emulation
- OFW: Write to ultralight cards is now possible (no UID writing)
- OFW: Fixed infinite loop in dictionary attack scene
* LF RFID: OFW: Added Support for Securakey Protocol
* JS: `adc` support in `gpio` module (by @jamisonderek)
* JS: `storage` module (without virtual mount API at the moment) (by @Willy-JL)
* BadUSB: Add Finnish keyboard layout (by @nicou | PR #761)
* Archive: Fix SubGHz Remote files in favourites falling into non working and non removable state
- OFW: Ultralight C authentication with des key
- EMV Transactions less nested, hide if unavailable (by @Willy-JL | PR #771)
- Update Mifare Classic default keys dict with new keys from proxmark3 repo and UberGuidoZ repo
- LF RFID:
- Update T5577 password list (by @korden32 | PR #774)
- Add DEZ 8 display form for EM4100 (by @korden32 | PR #776 & (#777 by @mishamyte))
- JS:
- Refactor widget and keyboard modules, fix crash (by @Willy-JL | PR #770)
- SubGHz module fixes and improvements (by @Willy-JL)
* OFW: Infrared: check for negative timings
* OFW: Fix iButton/LFRFID Add Manually results being discarded
* OFW: Event Loop Timers
* OFW: Updater: resource compression
* Apps: **Check out more Apps updates and fixes by following** [this link](https://github.com/xMasterX/all-the-plugins/commits/dev)
## Other changes
* SubGHz: Fix add manually princeton
* SubGHz: Sync signal delete scene with OFW
* SubGHz: Fix incorrect rx key state when opening Read menu
* SubGHz: Fix incorrect state in decode raw exit - causing keys to be not removed from history and showing up in Read menu after exit from decode raw
* Misc: Remove outdated brew sdk install files
* Misc: Revert USB CDC changes to fix usb serial
* Misc: Fix usage of deprecated `icon_get_data`
* Loader: Better API Mismatch message (by @Willy-JL)
* CLI: Move part of the CLI to microsd to free up space for COMPACT 0 builds (by @Willy-JL)
* NFC: Fix typo in parsers
* Apps: Fix `input_callback` and `timer_callback` usage of non `void` argument as input
* LF RFID: OFW PR 3728: Securakey - Add Support for RKKTH Plain Text Format (by @zinongli)
* OFW: ReadMe: update outdated bits and pieces
* OFW: Debug: backup openocd work area, fix crash after fresh debugger connect and continue
* OFW: ELF, Flipper application: do not crash on "out of memory"
* OFW: MF Plus - Don't crash on reading weird cards
* OFW: SubGhz: fix Missed the "Deleted" screen when deleting RAW Subghz (by @Skorpionm)
* OFW: JS: Disable logging in mjs +2k free flash (by @hedger)
* OFW: Archive: fix memory leak in favorites add/remove
* OFW: Furi: Fix EventLoop state persisting on same thread after free
* OFW: Cli: top
* OFW: Desktop lockup fix, GUI improvements
* OFW: Loader: fix crash on "locked via cli loader"
* OFW: SubGhz: fix navigation GUI
* OFW: Furi: event loop
* OFW: Code Cleanup: unused includes, useless checks, unused variables, etc...
* OFW: SubGhz: fix gui "No transition to the "Saved" menu when deleting a SubGHz RAW file"
* OFW: RPC: Add TarExtract command, some small fixes
* OFW: Use static synchronisation primitives
* OFW: cleanup of various warnings from clangd
* OFW: Add initial ISO7816 support
* OFW: fbt, vscode: tweaks for cdb generation for clangd
* OFW: Updater: fix inability to update with bigger updater.bin
* OFW: Furi: wrap message queue in container, prepare it for epoll. Accessor: disable expansion service on start.
* OFW: HID/BLE Keyboard UI refactoring
* OFW: CCID: Add CCIDWorker
* OFW: Disabled ISR runtime stats collection for updater builds
* OFW: VSCode fixes: .gitignore & clangd
* OFW: ufbt: synced .clang-format rules with main
* OFW: Code formatting update
* OFW: scripts: runfap: fixed starting apps with spaces in path
* OFW: toolchain: v38. clangd as default language server
* OFW: NFC: ISO15693 Render Typo Fix
* OFW: tar archive: fix double free
* OFW: ufbt: added ARGS to commandline parser
* OFW: lib: sconscript todo cleanup
* OFW: Intruder animation
* OFW: Desktop: allow to close blocking bad sd animation
* OFW: Updater: reset various debug flags on production build flash (was done in same way in UL before)
* OFW: Fix PVS Warnings
* OFW: CCID: Improve request and response data handling
* OFW: Furi: count ISR time. Cli: show ISR time in top.
* OFW: toolchain: v37
* OFW: NFC: Cache plugin name not full path, saves some RAM (by @Willy-JL)
* OFW: copro: bumped to 1.20.0
* OFW: input_srv: Put input state data on the stack of the service
* OFW: Coalesce some allocations
* OFW: updater: slightly smaller image
* OFW: Updater: Fix double dir cleanup
* OFW: cli: storage: minor subcommand lookup refactor
* OFW: LFRFID Securakey: Add Support for RKKTH Plain Text Format
* OFW: NFC: Add mf_classic_set_sector_trailer_read function
* OFW: Separate editing and renaming in iButton and LFRFID
* OFW: New js modules documentation added
* OFW: Update link to mfkey32
* OFW: NFC: Desfire Renderer Minor Debug
* OFW: RPC: Fix input lockup on disconnect
* OFW: Thread Signals
<br><br>
#### Known NFC post-refactor regressions list:
- Mifare Mini clones reading is broken (original mini working fine) (OFW)

View File

@@ -79,6 +79,7 @@
- Infrared -> External IR modules support (with autodetect by OFW)
- **NFC/RFID/iButton**
* LFRFID and iButton Fuzzer plugins
* Add DEZ 8 display form for EM4100 (by @korden32)
* Extra Mifare Classic keys in system dict
* EMV Protocol + Public data parser (by @Leptopt1los and @wosk)
* NFC `Add manually` -> Mifare Classic with custom UID
@@ -104,18 +105,18 @@ Thanks to Official team (to their SubGHz Developer, Skorp) for implementing supp
Keeloq [Not ALL systems supported for decode or emulation!] - [Supported manufacturers list](https://pastes.io/raw/unuj9bhe4m)
Encoders or emulation support made by @xMasterX:
Encoders or emulation (+ programming mode) support made by @xMasterX:
- Nero Radio 57bit (+ 56bit support)
- CAME 12bit/24bit encoder fixes (Fixes are now merged in OFW)
- Keeloq: Dea Mio, Genius Bravo, GSN, HCS101, AN-Motors, JCM Tech, MHouse, Nice Smilo, DTM Neo, FAAC RC,XT, Mutancode, Normstahl, Beninca + Allmatic, Stilmatic, CAME Space, Aprimatic (model TR and similar), Centurion Nova (thanks Carlos !)
- Keeloq: Dea Mio, Genius Bravo, GSN, HCS101, AN-Motors, JCM Tech, MHouse, Nice Smilo, DTM Neo, FAAC RC,XT, Mutancode, Normstahl, Beninca + Allmatic, Stilmatic, CAME Space, Aprimatic (model TR and similar), Centurion Nova (thanks Carlos !), Hormann EcoStar, Novoferm
Encoders or emulation made by @Eng1n33r(first implementation in Q2 2022) and @xMasterX (current version):
Protocols support made by Skorp (original implementation) and @xMasterX (current version):
- CAME Atomo -> Update! check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Nice Flor S -> How to create new remote - [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- FAAC SLH (Spa) -> Update!!! Check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- FAAC SLH (Spa) -> Update!!! (Programming mode!) Check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Keeloq: BFT Mitto -> Update! Check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Star Line
- Security+ v1 & v2 (encoders was made in OFW)
- Security+ v1 & v2
Encoders made by @assasinfil and @xMasterX:
- Somfy Telis -> How to create new remote - [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)

View File

@@ -43,10 +43,10 @@ distenv = coreenv.Clone(
"blackmagic",
"jflash",
"doxygen",
"textfile",
],
ENV=os.environ,
UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}",
VSCODE_LANG_SERVER=ARGUMENTS.get("LANG_SERVER", "cpptools"),
)
firmware_env = distenv.AddFwProject(
@@ -403,14 +403,23 @@ distenv.PhonyTarget(
)
# Prepare vscode environment
VSCODE_LANG_SERVER = cmd_environment["LANG_SERVER"]
vscode_dist = distenv.Install(
"#.vscode",
[
distenv.Glob("#.vscode/example/*.json"),
distenv.Glob(f"#.vscode/example/{VSCODE_LANG_SERVER}/*.json"),
distenv.Glob("#.vscode/example/*.json", exclude="*.tmpl"),
distenv.Glob("#.vscode/example/${LANG_SERVER}/*.json"),
],
)
for template_file in distenv.Glob("#.vscode/example/*.tmpl"):
vscode_dist.append(
distenv.Substfile(
distenv.Dir("#.vscode").File(template_file.name.replace(".tmpl", "")),
template_file,
SUBST_DICT={
"@FBT_PLATFORM_EXECUTABLE_EXT@": ".exe" if os.name == "nt" else ""
},
)
)
distenv.Precious(vscode_dist)
distenv.NoClean(vscode_dist)
distenv.Alias("vscode_dist", (vscode_dist, firmware_env["FW_CDB"]))

View File

@@ -17,7 +17,7 @@ static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val)
canvas_draw_box(canvas, x - 4, y + 16, 24, 6);
canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val);
};
}
static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
char emote[20] = {};
@@ -85,7 +85,7 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote);
canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header);
canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value);
};
}
static void battery_info_draw_callback(Canvas* canvas, void* context) {
furi_assert(context);

View File

@@ -384,8 +384,7 @@ BtTestParam* bt_test_param_add(
void bt_test_set_rssi(BtTest* bt_test, float rssi) {
furi_assert(bt_test);
with_view_model(
bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
with_view_model(bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
}
void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) {

View File

@@ -9,6 +9,7 @@
#include "iso7816_callbacks.h"
#include "iso7816_t0_apdu.h"
#include "iso7816_atr.h"
#include "iso7816_response.h"
typedef enum {
EventTypeInput,
@@ -118,6 +119,80 @@ static const CcidCallbacks ccid_cb = {
ccid_xfr_datablock_callback,
};
//Instruction 1: returns an OK response unconditionally
//APDU example: 0x01:0x01:0x00:0x00
//response: SW1=0x90, SW2=0x00
void handle_instruction_01(ISO7816_Response_APDU* responseAPDU) {
responseAPDU->DataLen = 0;
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK);
}
//Instruction 2: expect command with no body, replies wit with a body with two bytes
//APDU example: 0x01:0x02:0x00:0x00:0x02
//response: 'bc' (0x62, 0x63) SW1=0x90, SW2=0x00
void handle_instruction_02(
uint8_t p1,
uint8_t p2,
uint16_t lc,
uint16_t le,
ISO7816_Response_APDU* responseAPDU) {
if(p1 == 0 && p2 == 0 && lc == 0 && le >= 2) {
responseAPDU->Data[0] = 0x62;
responseAPDU->Data[1] = 0x63;
responseAPDU->DataLen = 2;
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK);
} else if(p1 != 0 || p2 != 0) {
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2);
} else {
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH);
}
}
//Instruction 3: sends a command with a body with two bytes, receives a response with no bytes
//APDU example: 0x01:0x03:0x00:0x00:0x02:CA:FE
//response SW1=0x90, SW2=0x00
void handle_instruction_03(
uint8_t p1,
uint8_t p2,
uint16_t lc,
ISO7816_Response_APDU* responseAPDU) {
if(p1 == 0 && p2 == 0 && lc == 2) {
responseAPDU->DataLen = 0;
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK);
} else if(p1 != 0 || p2 != 0) {
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2);
} else {
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH);
}
}
//instruction 4: sends a command with a body with 'n' bytes, receives a response with 'n' bytes
//APDU example: 0x01:0x04:0x00:0x00:0x04:0x01:0x02:0x03:0x04:0x04
//receives (0x01, 0x02, 0x03, 0x04) SW1=0x90, SW2=0x00
void handle_instruction_04(
uint8_t p1,
uint8_t p2,
uint16_t lc,
uint16_t le,
const uint8_t* commandApduDataBuffer,
ISO7816_Response_APDU* responseAPDU) {
if(p1 == 0 && p2 == 0 && lc > 0 && le > 0 && le >= lc) {
for(uint16_t i = 0; i < lc; i++) {
responseAPDU->Data[i] = commandApduDataBuffer[i];
}
responseAPDU->DataLen = lc;
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK);
} else if(p1 != 0 || p2 != 0) {
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2);
} else {
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH);
}
}
void iso7816_answer_to_reset(Iso7816Atr* atr) {
//minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00
atr->TS = 0x3B;
@@ -125,48 +200,38 @@ void iso7816_answer_to_reset(Iso7816Atr* atr) {
}
void iso7816_process_command(
const struct ISO7816_Command_APDU* commandAPDU,
struct ISO7816_Response_APDU* responseAPDU,
const uint8_t* commandApduDataBuffer,
uint8_t commandApduDataBufferLen,
uint8_t* responseApduDataBuffer,
uint8_t* responseApduDataBufferLen) {
const ISO7816_Command_APDU* commandAPDU,
ISO7816_Response_APDU* responseAPDU) {
//example 1: sends a command with no body, receives a response with no body
//sends APDU 0x01:0x02:0x00:0x00
//sends APDU 0x01:0x01:0x00:0x00
//receives SW1=0x90, SW2=0x00
if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x01) {
responseAPDU->SW1 = 0x90;
responseAPDU->SW2 = 0x00;
if(commandAPDU->CLA == 0x01) {
switch(commandAPDU->INS) {
case 0x01:
handle_instruction_01(responseAPDU);
break;
case 0x02:
handle_instruction_02(
commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, commandAPDU->Le, responseAPDU);
break;
case 0x03:
handle_instruction_03(commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, responseAPDU);
break;
case 0x04:
handle_instruction_04(
commandAPDU->P1,
commandAPDU->P2,
commandAPDU->Lc,
commandAPDU->Le,
commandAPDU->Data,
responseAPDU);
break;
default:
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED);
}
//example 2: sends a command with no body, receives a response with a body with two bytes
//sends APDU 0x01:0x02:0x00:0x00
//receives 'bc' (0x62, 0x63) SW1=0x80, SW2=0x10
else if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x02) {
responseApduDataBuffer[0] = 0x62;
responseApduDataBuffer[1] = 0x63;
*responseApduDataBufferLen = 2;
responseAPDU->SW1 = 0x90;
responseAPDU->SW2 = 0x00;
}
//example 3: ends a command with a body with two bytes, receives a response with a body with two bytes
//sends APDU 0x01:0x03:0x00:0x00:0x02:CA:FE
//receives (0xCA, 0xFE) SW1=0x90, SW2=0x02
else if(
commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x03 && commandApduDataBufferLen == 2 &&
commandAPDU->Lc == 2) {
//echo command body to response body
responseApduDataBuffer[0] = commandApduDataBuffer[0];
responseApduDataBuffer[1] = commandApduDataBuffer[1];
*responseApduDataBufferLen = 2;
responseAPDU->SW1 = 0x90;
responseAPDU->SW2 = 0x00;
} else {
responseAPDU->SW1 = 0x6A;
responseAPDU->SW2 = 0x00;
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED);
}
}
@@ -188,8 +253,10 @@ int32_t ccid_test_app(void* p) {
FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
furi_hal_usb_unlock();
furi_hal_ccid_set_callbacks((CcidCallbacks*)&ccid_cb, NULL);
furi_check(furi_hal_usb_set_config(&usb_ccid, &app->ccid_cfg) == true);
furi_hal_usb_ccid_set_callbacks((CcidCallbacks*)&ccid_cb, NULL);
furi_hal_usb_ccid_insert_smartcard();
iso7816_set_callbacks((Iso7816Callbacks*)&iso87816_cb);
@@ -210,8 +277,8 @@ int32_t ccid_test_app(void* p) {
}
//tear down USB
furi_hal_usb_ccid_set_callbacks(NULL, NULL);
furi_hal_usb_set_config(usb_mode_prev, NULL);
furi_hal_ccid_set_callbacks(NULL, NULL);
iso7816_set_callbacks(NULL);

View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python
# pylint: disable=missing-module-docstring, too-many-arguments, consider-using-f-string, missing-function-docstring
from smartcard.System import readers
def test_apdu(connection, test_name, apdu, expected_sw1, expected_sw2, expected_data):
print("Running test: [%s]" % test_name)
data, sw1, sw2 = connection.transmit(apdu)
failed = []
if sw1 != expected_sw1:
failed.append("SW1: Expected %x, actual %x" % (expected_sw1, sw1))
if sw2 != expected_sw2:
failed.append("SW2: Expected %x, actual %x" % (expected_sw2, sw2))
if len(data) != len(expected_data):
failed.append(
"Data: Sizes differ: Expected %x, actual %x"
% (len(expected_data), len(data))
)
print(data)
elif len(data) > 0:
data_matches = True
for i, _ in enumerate(data):
if data[i] != expected_data[i]:
data_matches = False
if not data_matches:
failed.append("Data: Expected %s, actual %s" % (expected_data, data))
if len(failed) > 0:
print("Test failed: ")
for failure in failed:
print("- %s" % failure)
else:
print("Test passed!")
def main():
r = readers()
print("Found following smartcard readers: ")
for i, sc in enumerate(r):
print("[%d] %s" % (i, sc))
print("Select the smartcard reader you want to run tests against:")
reader_index = int(input())
if reader_index < len(r):
connection = r[reader_index].createConnection()
connection.connect()
test_apdu(
connection,
"INS 0x01: No Lc, no Data, No Le. Expect no data in return",
[0x01, 0x01, 0x00, 0x00],
0x90,
0x00,
[],
)
test_apdu(
connection,
"INS 0x02: No Lc, no Data, Le=2. Expect 2 byte data in return",
[0x01, 0x02, 0x00, 0x00, 0x02],
0x90,
0x00,
[0x62, 0x63],
)
test_apdu(
connection,
"INS 0x03: Lc=2, data=[0xCA, 0xFE], No Le. Expect no data in return",
[0x01, 0x03, 0x00, 0x00, 0x02, 0xCA, 0xFE],
0x90,
0x00,
[],
)
test_apdu(
connection,
"INS 0x04: Lc=2, data=[0xCA, 0xFE], Le=2. Expect 1 byte data in return",
[0x01, 0x04, 0x00, 0x00, 0x02, 0xCA, 0xFE, 0x02],
0x90,
0x00,
[0xCA, 0xFE],
)
small_apdu = list(range(0, 0x0F))
test_apdu(
connection,
"INS 0x04: Lc=0x0F, data=small_apdu, Le=0x0F. Expect 14 bytes data in return",
[0x01, 0x04, 0x00, 0x00, 0x0F] + small_apdu + [0x0F],
0x90,
0x00,
small_apdu,
)
upper_bound = 0xF0
max_apdu = list(range(0, upper_bound))
test_apdu(
connection,
"INS 0x04: Lc=0x%x, data=max_apdu, Le=0x%x. Expect 0x%x bytes data in return"
% (upper_bound, upper_bound, upper_bound),
[0x01, 0x04, 0x00, 0x00, upper_bound] + max_apdu + [upper_bound],
0x90,
0x00,
max_apdu,
)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,2 @@
pyscard
# or sudo apt install python3-pyscard

View File

@@ -1,9 +1,6 @@
#ifndef _ISO7816_ATR_H_
#define _ISO7816_ATR_H_
#pragma once
typedef struct {
uint8_t TS;
uint8_t T0;
} Iso7816Atr;
#endif //_ISO7816_ATR_H_

View File

@@ -1,17 +1,21 @@
// transforms low level calls such as XFRCallback or ICC Power on to a structured one
// an application can register these calls and listen for the callbacks defined in Iso7816Callbacks
#include <stdint.h>
#include <stddef.h>
#include <furi.h>
#include <furi_hal.h>
#include "iso7816_t0_apdu.h"
#include "iso7816_atr.h"
#include "iso7816_callbacks.h"
#include <stdint.h>
#include <stddef.h>
#include <furi.h>
#define ISO7816_RESPONSE_BUFFER_SIZE 255
#include "iso7816_response.h"
static Iso7816Callbacks* callbacks = NULL;
static uint8_t commandApduBuffer[sizeof(ISO7816_Command_APDU) + CCID_SHORT_APDU_SIZE];
static uint8_t responseApduBuffer[sizeof(ISO7816_Response_APDU) + CCID_SHORT_APDU_SIZE];
void iso7816_set_callbacks(Iso7816Callbacks* cb) {
callbacks = cb;
}
@@ -36,41 +40,26 @@ void iso7816_xfr_datablock_callback(
uint32_t pcToReaderDataBlockLen,
uint8_t* readerToPcDataBlock,
uint32_t* readerToPcDataBlockLen) {
struct ISO7816_Response_APDU responseAPDU;
uint8_t responseApduDataBuffer[ISO7816_RESPONSE_BUFFER_SIZE];
uint8_t responseApduDataBufferLen = 0;
ISO7816_Response_APDU* responseAPDU = (ISO7816_Response_APDU*)&responseApduBuffer;
if(callbacks != NULL) {
struct ISO7816_Command_APDU commandAPDU;
ISO7816_Command_APDU* commandAPDU = (ISO7816_Command_APDU*)&commandApduBuffer;
const uint8_t* commandApduDataBuffer = NULL;
uint8_t commandApduDataBufferLen = 0;
uint8_t result =
iso7816_read_command_apdu(commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen);
iso7816_read_command_apdu(&commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen);
if(result == ISO7816_READ_COMMAND_APDU_OK) {
callbacks->iso7816_process_command(commandAPDU, responseAPDU);
if(commandAPDU.Lc > 0) {
commandApduDataBufferLen = commandAPDU.Lc;
commandApduDataBuffer = &pcToReaderDataBlock[5];
furi_assert(responseAPDU->DataLen < CCID_SHORT_APDU_SIZE);
} else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE) {
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LE);
} else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH) {
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH);
}
callbacks->iso7816_process_command(
&commandAPDU,
&responseAPDU,
commandApduDataBuffer,
commandApduDataBufferLen,
responseApduDataBuffer,
&responseApduDataBufferLen);
} else {
//class not supported
responseAPDU.SW1 = 0x6E;
responseAPDU.SW2 = 0x00;
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INTERNAL_EXCEPTION);
}
iso7816_write_response_apdu(
&responseAPDU,
readerToPcDataBlock,
readerToPcDataBlockLen,
responseApduDataBuffer,
responseApduDataBufferLen);
iso7816_write_response_apdu(responseAPDU, readerToPcDataBlock, readerToPcDataBlockLen);
}

View File

@@ -1,5 +1,4 @@
#ifndef _ISO7816_CALLBACKS_H_
#define _ISO7816_CALLBACKS_H_
#pragma once
#include <stdint.h>
#include "iso7816_atr.h"
@@ -8,12 +7,8 @@
typedef struct {
void (*iso7816_answer_to_reset)(Iso7816Atr* atr);
void (*iso7816_process_command)(
const struct ISO7816_Command_APDU* command,
struct ISO7816_Response_APDU* response,
const uint8_t* commandApduDataBuffer,
uint8_t commandApduDataBufferLen,
uint8_t* responseApduDataBuffer,
uint8_t* responseApduDataBufferLen);
const ISO7816_Command_APDU* command,
ISO7816_Response_APDU* response);
} Iso7816Callbacks;
void iso7816_set_callbacks(Iso7816Callbacks* cb);
@@ -24,5 +19,3 @@ void iso7816_xfr_datablock_callback(
uint32_t dataBlockLen,
uint8_t* responseDataBlock,
uint32_t* responseDataBlockLen);
#endif //_ISO7816_CALLBACKS_H_

View File

@@ -0,0 +1,8 @@
#include <stdint.h>
#include "iso7816_t0_apdu.h"
#include "iso7816_response.h"
void iso7816_set_response(ISO7816_Response_APDU* responseAPDU, uint16_t responseCode) {
responseAPDU->SW1 = (responseCode >> (8 * 1)) & 0xff;
responseAPDU->SW2 = (responseCode >> (8 * 0)) & 0xff;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#define ISO7816_RESPONSE_OK 0x9000
#define ISO7816_RESPONSE_WRONG_LENGTH 0x6700
#define ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2 0x6A00
#define ISO7816_RESPONSE_WRONG_LE 0x6C00
#define ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED 0x6D00
#define ISO7816_RESPONSE_CLASS_NOT_SUPPORTED 0x6E00
#define ISO7816_RESPONSE_INTERNAL_EXCEPTION 0x6F00
void iso7816_set_response(ISO7816_Response_APDU* responseAPDU, uint16_t responseCode);

View File

@@ -2,37 +2,73 @@
#include <stdint.h>
#include <string.h>
#include <furi.h>
#include <furi_hal.h>
#include "iso7816_t0_apdu.h"
//reads dataBuffer with dataLen size, translate it into a ISO7816_Command_APDU type
//extra data will be pointed to commandDataBuffer
void iso7816_read_command_apdu(
struct ISO7816_Command_APDU* command,
uint8_t iso7816_read_command_apdu(
ISO7816_Command_APDU* command,
const uint8_t* dataBuffer,
uint32_t dataLen) {
UNUSED(dataLen);
command->CLA = dataBuffer[0];
command->INS = dataBuffer[1];
command->P1 = dataBuffer[2];
command->P2 = dataBuffer[3];
if(dataLen == 4) {
command->Lc = 0;
command->Le = 0;
command->LePresent = false;
return ISO7816_READ_COMMAND_APDU_OK;
} else if(dataLen == 5) {
//short le
command->Lc = 0;
command->Le = dataBuffer[4];
command->LePresent = true;
return ISO7816_READ_COMMAND_APDU_OK;
} else if(dataLen > 5 && dataBuffer[4] != 0x00) {
//short lc
command->Lc = dataBuffer[4];
if(command->Lc > 0 && command->Lc < CCID_SHORT_APDU_SIZE) { //-V560
memcpy(command->Data, &dataBuffer[5], command->Lc);
//does it have a short le too?
if(dataLen == (uint32_t)(command->Lc + 5)) {
command->Le = 0;
command->LePresent = false;
return ISO7816_READ_COMMAND_APDU_OK;
} else if(dataLen == (uint32_t)(command->Lc + 6)) {
command->Le = dataBuffer[dataLen - 1];
command->LePresent = true;
return ISO7816_READ_COMMAND_APDU_OK;
} else {
return ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH;
}
} else {
return ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH;
}
} else {
return ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH;
}
}
//data buffer countains the whole APU response (response + trailer (SW1+SW2))
//data buffer contains the whole APU response (response + trailer (SW1+SW2))
void iso7816_write_response_apdu(
const struct ISO7816_Response_APDU* response,
const ISO7816_Response_APDU* response,
uint8_t* readerToPcDataBlock,
uint32_t* readerToPcDataBlockLen,
uint8_t* responseDataBuffer,
uint32_t responseDataLen) {
uint32_t* readerToPcDataBlockLen) {
uint32_t responseDataBufferIndex = 0;
//response body
if(responseDataLen > 0) {
while(responseDataBufferIndex < responseDataLen) {
readerToPcDataBlock[responseDataBufferIndex] =
responseDataBuffer[responseDataBufferIndex];
if(response->DataLen > 0) {
while(responseDataBufferIndex < response->DataLen) {
readerToPcDataBlock[responseDataBufferIndex] = response->Data[responseDataBufferIndex];
responseDataBufferIndex++;
}
}

View File

@@ -1,11 +1,14 @@
#ifndef _ISO7816_T0_APDU_H_
#define _ISO7816_T0_APDU_H_
#pragma once
#include <stdint.h>
#include "iso7816_atr.h"
#include "core/common_defines.h"
struct ISO7816_Command_APDU {
#define ISO7816_READ_COMMAND_APDU_OK 0
#define ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE 1
#define ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH 2
typedef struct {
//header
uint8_t CLA;
uint8_t INS;
@@ -13,24 +16,27 @@ struct ISO7816_Command_APDU {
uint8_t P2;
//body
uint8_t Lc;
uint8_t Le;
} FURI_PACKED;
uint16_t Lc; //data length
uint16_t Le; //maximum response data length expected by client
struct ISO7816_Response_APDU {
//Le can have value of 0x00, which actually meand 0x100 = 256
bool LePresent;
uint8_t Data[0];
} FURI_PACKED ISO7816_Command_APDU;
typedef struct {
uint8_t SW1;
uint8_t SW2;
} FURI_PACKED;
uint16_t DataLen;
uint8_t Data[0];
} FURI_PACKED ISO7816_Response_APDU;
void iso7816_answer_to_reset(Iso7816Atr* atr);
void iso7816_read_command_apdu(
struct ISO7816_Command_APDU* command,
const uint8_t* dataBuffer,
uint32_t dataLen);
uint8_t iso7816_read_command_apdu(
ISO7816_Command_APDU* command,
const uint8_t* pcToReaderDataBlock,
uint32_t pcToReaderDataBlockLen);
void iso7816_write_response_apdu(
const struct ISO7816_Response_APDU* response,
const ISO7816_Response_APDU* response,
uint8_t* readerToPcDataBlock,
uint32_t* readerToPcDataBlockLen,
uint8_t* responseDataBuffer,
uint32_t responseDataLen);
#endif //_ISO7816_T0_APDU_H_
uint32_t* readerToPcDataBlockLen);

View File

@@ -150,8 +150,7 @@ static void view_display_test_exit(void* context) {
static void view_display_test_timer_callback(void* context) {
ViewDisplayTest* instance = context;
with_view_model(
instance->view, ViewDisplayTestModel * model, { model->counter++; }, true);
with_view_model(instance->view, ViewDisplayTestModel * model, { model->counter++; }, true);
}
ViewDisplayTest* view_display_test_alloc(void) {

View File

@@ -0,0 +1,10 @@
App(
appid="event_loop_blink_test",
name="Event Loop Blink Test",
apptype=FlipperAppType.DEBUG,
entry_point="event_loop_blink_test_app",
requires=["input"],
stack_size=1 * 1024,
order=20,
fap_category="Debug",
)

View File

@@ -0,0 +1,169 @@
#include <furi.h>
#include <furi_hal_resources.h>
#include <gui/gui.h>
#include <gui/elements.h>
#include <gui/view_port.h>
#include <input/input.h>
#define TAG "EventLoopBlinkTest"
#define TIMER_COUNT (6U)
typedef struct {
FuriEventLoop* event_loop;
FuriMessageQueue* input_queue;
FuriEventLoopTimer* timers[TIMER_COUNT];
} EventLoopBlinkTestApp;
static const GpioPin* blink_gpio_pins[] = {
&gpio_ext_pa7,
&gpio_ext_pa6,
&gpio_ext_pa4,
&gpio_ext_pb3,
&gpio_ext_pb2,
&gpio_ext_pc3,
};
static_assert(COUNT_OF(blink_gpio_pins) == TIMER_COUNT);
static const uint32_t timer_intervals[] = {
25,
50,
100,
200,
400,
800,
};
static_assert(COUNT_OF(timer_intervals) == TIMER_COUNT);
static void blink_gpio_init(void) {
for(size_t i = 0; i < TIMER_COUNT; ++i) {
furi_hal_gpio_init_simple(blink_gpio_pins[i], GpioModeOutputPushPull);
furi_hal_gpio_write(blink_gpio_pins[i], false);
}
furi_hal_gpio_init_simple(&gpio_ext_pc0, GpioModeOutputPushPull);
furi_hal_gpio_write(&gpio_ext_pc0, false);
}
static void blink_gpio_deinit(void) {
for(size_t i = 0; i < TIMER_COUNT; ++i) {
furi_hal_gpio_write(blink_gpio_pins[i], false);
furi_hal_gpio_init_simple(blink_gpio_pins[i], GpioModeAnalog);
}
furi_hal_gpio_write(&gpio_ext_pc0, false);
furi_hal_gpio_init_simple(&gpio_ext_pc0, GpioModeAnalog);
}
static void view_port_draw_callback(Canvas* canvas, void* context) {
UNUSED(context);
canvas_clear(canvas);
elements_text_box(
canvas,
0,
0,
canvas_width(canvas),
canvas_height(canvas),
AlignCenter,
AlignCenter,
"\e#Event Loop Timers Test\e#\n"
"Press buttons\n"
"to enable or disable timers\n"
"\e#Exit\e# = long press \e#Back\e#",
false);
}
static void view_port_input_callback(InputEvent* input_event, void* context) {
EventLoopBlinkTestApp* app = context;
furi_message_queue_put(app->input_queue, input_event, 0);
}
static bool input_queue_callback(FuriMessageQueue* queue, void* context) {
EventLoopBlinkTestApp* app = context;
InputEvent event;
FuriStatus status = furi_message_queue_get(queue, &event, 0);
furi_assert(status == FuriStatusOk);
if(event.type == InputTypeShort) {
const size_t timer_idx = event.key;
furi_assert(timer_idx < TIMER_COUNT);
FuriEventLoopTimer* timer = app->timers[timer_idx];
if(furi_event_loop_timer_is_running(timer)) {
furi_event_loop_timer_stop(timer);
} else {
furi_event_loop_timer_restart(timer);
}
} else if(event.type == InputTypeLong) {
if(event.key == InputKeyBack) {
furi_event_loop_stop(app->event_loop);
}
}
return true;
}
static void blink_timer_callback(void* context) {
const GpioPin* gpio = blink_gpio_pins[(size_t)context];
furi_hal_gpio_write(gpio, !furi_hal_gpio_read(gpio));
}
static void event_loop_tick_callback(void* context) {
UNUSED(context);
furi_hal_gpio_write(&gpio_ext_pc0, !furi_hal_gpio_read(&gpio_ext_pc0));
}
int32_t event_loop_blink_test_app(void* arg) {
UNUSED(arg);
blink_gpio_init();
EventLoopBlinkTestApp app;
app.event_loop = furi_event_loop_alloc();
app.input_queue = furi_message_queue_alloc(3, sizeof(InputEvent));
for(size_t i = 0; i < TIMER_COUNT; ++i) {
app.timers[i] = furi_event_loop_timer_alloc(
app.event_loop, blink_timer_callback, FuriEventLoopTimerTypePeriodic, (void*)i);
furi_event_loop_timer_start(app.timers[i], timer_intervals[i]);
}
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, view_port_draw_callback, &app);
view_port_input_callback_set(view_port, view_port_input_callback, &app);
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
furi_event_loop_tick_set(app.event_loop, 500, event_loop_tick_callback, &app);
furi_event_loop_message_queue_subscribe(
app.event_loop, app.input_queue, FuriEventLoopEventIn, input_queue_callback, &app);
furi_event_loop_run(app.event_loop);
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_record_close(RECORD_GUI);
furi_event_loop_message_queue_unsubscribe(app.event_loop, app.input_queue);
furi_message_queue_free(app.input_queue);
for(size_t i = 0; i < TIMER_COUNT; ++i) {
furi_event_loop_timer_free(app.timers[i]);
}
furi_event_loop_free(app.event_loop);
blink_gpio_deinit();
return 0;
}

View File

@@ -223,16 +223,14 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) {
uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) {
uint32_t result = false;
with_view_model(
tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false);
with_view_model(tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false);
return result;
}
uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) {
uint32_t result = false;
with_view_model(
tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false);
with_view_model(tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false);
return result;
}

View File

@@ -5,6 +5,7 @@
#include <toolbox/args.h>
#define TAG "SpeakerDebug"
#define CLI_COMMAND "speaker_debug"
typedef enum {

View File

@@ -9,9 +9,10 @@
#include <notification/notification.h>
#include <notification/notification_messages.h>
#define TAG "UartEcho"
#define LINES_ON_SCREEN 6
#define COLUMNS_ON_SCREEN 21
#define TAG "UartEcho"
#define DEFAULT_BAUD_RATE 230400
typedef struct UartDumpModel UartDumpModel;
@@ -147,7 +148,7 @@ static void uart_echo_push_to_list(UartDumpModel* model, const char data) {
bool new_string_needed = false;
if(furi_string_size(model->list[model->line]->text) >= COLUMNS_ON_SCREEN) {
new_string_needed = true;
} else if((data == '\n' || data == '\r')) {
} else if(data == '\n' || data == '\r') {
// pack line breaks
if(model->last_char != '\n' && model->last_char != '\r') {
new_string_needed = true;
@@ -206,8 +207,7 @@ static int32_t uart_echo_worker(void* context) {
} while(length > 0);
notification_message(app->notification, &sequence_notification);
with_view_model(
app->view, UartDumpModel * model, { UNUSED(model); }, true);
with_view_model(app->view, UartDumpModel * model, { UNUSED(model); }, true);
}
if(events & WorkerEventRxIdle) {

View File

@@ -0,0 +1,71 @@
Filetype: Flipper NFC device
Version: 4
# Device type can be ISO14443-3A, ISO14443-3B, ISO14443-4A, ISO14443-4B, ISO15693-3, FeliCa, NTAG/Ultralight, Mifare Classic, Mifare DESFire, SLIX, ST25TB
Device type: NTAG/Ultralight
# UID is common for all formats
UID: 04 BA FF CA 4D 5D 80
# ISO14443-3A specific data
ATQA: 00 44
SAK: 00
# NTAG/Ultralight specific data
Data format version: 2
NTAG/Ultralight type: Mifare Ultralight C
Signature: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Mifare version: 00 00 00 00 00 00 00 00
Counter 0: 0
Tearing 0: 00
Counter 1: 0
Tearing 1: 00
Counter 2: 0
Tearing 2: 00
Pages total: 48
Pages read: 48
Page 0: 04 BA FF C9
Page 1: CA 4D 5D 80
Page 2: 5A 48 00 00
Page 3: E1 10 12 00
Page 4: 01 03 A0 0C
Page 5: 34 03 00 FE
Page 6: 00 00 00 00
Page 7: 00 00 00 00
Page 8: 00 00 00 00
Page 9: 00 00 00 00
Page 10: 00 00 BE AF
Page 11: 00 00 00 00
Page 12: 00 00 00 00
Page 13: 00 00 00 00
Page 14: 00 00 00 00
Page 15: 00 00 00 00
Page 16: 00 00 00 00
Page 17: 00 00 00 00
Page 18: 00 00 00 00
Page 19: 00 00 00 00
Page 20: 00 00 00 00
Page 21: 00 00 00 00
Page 22: 00 00 00 00
Page 23: 00 00 00 00
Page 24: 00 00 00 00
Page 25: 00 00 00 00
Page 26: 00 00 00 00
Page 27: 00 00 00 00
Page 28: 00 00 00 00
Page 29: 00 00 00 00
Page 30: 00 00 00 00
Page 31: 00 00 00 00
Page 32: 00 00 00 00
Page 33: 00 00 00 00
Page 34: 00 00 00 00
Page 35: 00 00 00 00
Page 36: 00 00 00 00
Page 37: 00 00 00 00
Page 38: 00 00 00 00
Page 39: 00 00 00 00
Page 40: 00 00 00 00
Page 41: 00 00 00 00
Page 42: 05 00 00 00
Page 43: 00 00 00 00
Page 44: 00 00 00 00
Page 45: 00 00 00 00
Page 46: 00 00 00 00
Page 47: 00 00 00 00
Failed authentication attempts: 0

View File

@@ -1,6 +1,9 @@
#include "../test.h" // IWYU pragma: keep
#include <toolbox/compress.h>
#include <toolbox/md5_calc.h>
#include <toolbox/tar/tar_archive.h>
#include <toolbox/dir_walk.h>
#include <furi.h>
#include <furi_hal.h>
@@ -56,7 +59,7 @@ static void compress_test_reference_comp_decomp() {
furi_record_close(RECORD_STORAGE);
uint8_t* temp_buffer = malloc(1024);
Compress* comp = compress_alloc(1024);
Compress* comp = compress_alloc(CompressTypeHeatshrink, &compress_config_heatshrink_default);
size_t encoded_size = 0;
mu_assert(
@@ -98,7 +101,7 @@ static void compress_test_random_comp_decomp() {
// We only fill half of the buffer with random data, so if anything goes wrong, there's no overflow
static const size_t src_data_size = src_buffer_size / 2;
Compress* comp = compress_alloc(src_buffer_size);
Compress* comp = compress_alloc(CompressTypeHeatshrink, &compress_config_heatshrink_default);
uint8_t* src_buff = malloc(src_buffer_size);
uint8_t* encoded_buff = malloc(encoded_buffer_size);
uint8_t* decoded_buff = malloc(src_buffer_size);
@@ -146,9 +149,200 @@ static void compress_test_random_comp_decomp() {
compress_free(comp);
}
static int32_t hs_unpacker_file_read(void* context, uint8_t* buffer, size_t size) {
File* file = (File*)context;
return storage_file_read(file, buffer, size);
}
static int32_t hs_unpacker_file_write(void* context, uint8_t* buffer, size_t size) {
File* file = (File*)context;
return storage_file_write(file, buffer, size);
}
/*
Source file was generated with:
```python3
import random, string
random.seed(1337)
with open("hsstream.out.bin", "wb") as f:
for c in random.choices(string.printable, k=1024):
for _ in range(random.randint(1, 10)):
f.write(c.encode())
```
It was compressed with heatshrink using the following command:
`python3 -m heatshrink2 compress -w 9 -l 4 hsstream.out.bin hsstream.in.bin`
*/
#define HSSTREAM_IN COMPRESS_UNIT_TESTS_PATH("hsstream.in.bin")
#define HSSTREAM_OUT COMPRESS_UNIT_TESTS_PATH("hsstream.out.bin")
static void compress_test_heatshrink_stream() {
Storage* api = furi_record_open(RECORD_STORAGE);
File* comp_file = storage_file_alloc(api);
File* dest_file = storage_file_alloc(api);
CompressConfigHeatshrink config = {
.window_sz2 = 9,
.lookahead_sz2 = 4,
.input_buffer_sz = 128,
};
Compress* compress = compress_alloc(CompressTypeHeatshrink, &config);
do {
storage_simply_remove(api, HSSTREAM_OUT);
mu_assert(
storage_file_open(comp_file, HSSTREAM_IN, FSAM_READ, FSOM_OPEN_EXISTING),
"Failed to open compressed file");
mu_assert(
storage_file_open(dest_file, HSSTREAM_OUT, FSAM_WRITE, FSOM_OPEN_ALWAYS),
"Failed to open decompressed file");
mu_assert(
compress_decode_streamed(
compress, hs_unpacker_file_read, comp_file, hs_unpacker_file_write, dest_file),
"Decompression failed");
storage_file_close(dest_file);
unsigned char md5[16];
FS_Error file_error;
mu_assert(
md5_calc_file(dest_file, HSSTREAM_OUT, md5, &file_error), "Failed to calculate md5");
const unsigned char expected_md5[16] = {
0xa3,
0x70,
0xe8,
0x8b,
0xa9,
0x42,
0x74,
0xf4,
0xaa,
0x12,
0x8d,
0x41,
0xd2,
0xb6,
0x71,
0xc9};
mu_assert(memcmp(md5, expected_md5, sizeof(md5)) == 0, "MD5 mismatch after decompression");
storage_simply_remove(api, HSSTREAM_OUT);
} while(false);
compress_free(compress);
storage_file_free(comp_file);
storage_file_free(dest_file);
furi_record_close(RECORD_STORAGE);
}
#define HS_TAR_PATH COMPRESS_UNIT_TESTS_PATH("test.ths")
#define HS_TAR_EXTRACT_PATH COMPRESS_UNIT_TESTS_PATH("tar_out")
static bool file_counter(const char* name, bool is_dir, void* context) {
UNUSED(name);
UNUSED(is_dir);
int32_t* n_entries = (int32_t*)context;
(*n_entries)++;
return true;
}
/*
Heatshrink tar file contents and MD5 sums:
file1.txt: 64295676ceed5cce2d0dcac402e4bda4
file2.txt: 188f67f297eedd7bf3d6a4d3c2fc31c4
dir/file3.txt: 34d98ad8135ffe502dba374690136d16
dir/big_file.txt: ee169c1e1791a4d319dbfaefaa850e98
dir/nested_dir/file4.txt: e099fcb2aaa0672375eaedc549247ee6
dir/nested_dir/empty_file.txt: d41d8cd98f00b204e9800998ecf8427e
XOR of all MD5 sums: 92ed5729786d0e1176d047e35f52d376
*/
static void compress_test_heatshrink_tar() {
Storage* api = furi_record_open(RECORD_STORAGE);
TarArchive* archive = tar_archive_alloc(api);
FuriString* path = furi_string_alloc();
FileInfo fileinfo;
File* file = storage_file_alloc(api);
do {
storage_simply_remove_recursive(api, HS_TAR_EXTRACT_PATH);
mu_assert(storage_simply_mkdir(api, HS_TAR_EXTRACT_PATH), "Failed to create extract dir");
mu_assert(
tar_archive_get_mode_for_path(HS_TAR_PATH) == TarOpenModeReadHeatshrink,
"Invalid mode for heatshrink tar");
mu_assert(
tar_archive_open(archive, HS_TAR_PATH, TarOpenModeReadHeatshrink),
"Failed to open heatshrink tar");
int32_t n_entries = 0;
tar_archive_set_file_callback(archive, file_counter, &n_entries);
mu_assert(
tar_archive_unpack_to(archive, HS_TAR_EXTRACT_PATH, NULL),
"Failed to unpack heatshrink tar");
mu_assert(n_entries == 9, "Invalid number of entries in heatshrink tar");
uint8_t md5_total[16] = {0}, md5_file[16];
DirWalk* dir_walk = dir_walk_alloc(api);
mu_assert(dir_walk_open(dir_walk, HS_TAR_EXTRACT_PATH), "Failed to open dirwalk");
while(dir_walk_read(dir_walk, path, &fileinfo) == DirWalkOK) {
if(file_info_is_dir(&fileinfo)) {
continue;
}
mu_assert(
md5_calc_file(file, furi_string_get_cstr(path), md5_file, NULL),
"Failed to calc md5");
for(size_t i = 0; i < 16; i++) {
md5_total[i] ^= md5_file[i];
}
}
dir_walk_free(dir_walk);
static const unsigned char expected_md5[16] = {
0x92,
0xed,
0x57,
0x29,
0x78,
0x6d,
0x0e,
0x11,
0x76,
0xd0,
0x47,
0xe3,
0x5f,
0x52,
0xd3,
0x76};
mu_assert(memcmp(md5_total, expected_md5, sizeof(md5_total)) == 0, "MD5 mismatch");
storage_simply_remove_recursive(api, HS_TAR_EXTRACT_PATH);
} while(false);
storage_file_free(file);
furi_string_free(path);
tar_archive_free(archive);
furi_record_close(RECORD_STORAGE);
}
MU_TEST_SUITE(test_compress) {
MU_RUN_TEST(compress_test_random_comp_decomp);
MU_RUN_TEST(compress_test_reference_comp_decomp);
MU_RUN_TEST(compress_test_heatshrink_stream);
MU_RUN_TEST(compress_test_heatshrink_tar);
}
int run_minunit_test_compress(void) {

View File

@@ -74,7 +74,8 @@ MU_TEST(furi_hal_i2c_int_3b) {
DATA_SIZE - 1,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "4 rx failed");
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "4 invalid data_many");
for(size_t i = 0; i < DATA_SIZE; i++)
mu_assert(data_many[i] != 0, "4 invalid data_many");
ret = furi_hal_i2c_tx(
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, DATA_SIZE, LP5562_I2C_TIMEOUT);
@@ -90,7 +91,8 @@ MU_TEST(furi_hal_i2c_int_3b) {
DATA_SIZE - 1,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "7 rx failed");
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "7 invalid data_many");
for(size_t i = 0; i < DATA_SIZE; i++)
mu_assert(data_many[i] != 0, "7 invalid data_many");
}
MU_TEST(furi_hal_i2c_int_1b_fail) {

View File

@@ -6,8 +6,7 @@
#define LF_RFID_READ_TIMING_MULTIPLIER 8
#define EM_TEST_DATA \
{ 0x58, 0x00, 0x85, 0x64, 0x02 }
#define EM_TEST_DATA {0x58, 0x00, 0x85, 0x64, 0x02}
#define EM_TEST_DATA_SIZE 5
#define EM_TEST_EMULATION_TIMINGS_COUNT (64 * 2)
@@ -21,8 +20,7 @@ const int8_t em_test_timings[EM_TEST_EMULATION_TIMINGS_COUNT] = {
-32, 32, 32, -32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32,
};
#define HID10301_TEST_DATA \
{ 0x8D, 0x48, 0xA8 }
#define HID10301_TEST_DATA {0x8D, 0x48, 0xA8}
#define HID10301_TEST_DATA_SIZE 3
#define HID10301_TEST_EMULATION_TIMINGS_COUNT (541 * 2)
@@ -71,8 +69,7 @@ const int8_t hid10301_test_timings[HID10301_TEST_EMULATION_TIMINGS_COUNT] = {
5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
};
#define IOPROX_XSF_TEST_DATA \
{ 0x65, 0x01, 0x05, 0x39 }
#define IOPROX_XSF_TEST_DATA {0x65, 0x01, 0x05, 0x39}
#define IOPROX_XSF_TEST_DATA_SIZE 4
#define IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT (468 * 2)
@@ -116,8 +113,7 @@ const int8_t ioprox_xsf_test_timings[IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] =
};
#define INDALA26_EMULATION_TIMINGS_COUNT (1024 * 2)
#define INDALA26_TEST_DATA \
{ 0x3B, 0x73, 0x64, 0xA8 }
#define INDALA26_TEST_DATA {0x3B, 0x73, 0x64, 0xA8}
#define INDALA26_TEST_DATA_SIZE 4
const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = {
@@ -209,8 +205,7 @@ const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = {
-1, 1, -1, 1, -1, 1, -1, 1,
};
#define FDXB_TEST_DATA \
{ 0x44, 0x88, 0x23, 0xF2, 0x5A, 0x6F, 0x00, 0x01, 0x00, 0x00, 0x00 }
#define FDXB_TEST_DATA {0x44, 0x88, 0x23, 0xF2, 0x5A, 0x6F, 0x00, 0x01, 0x00, 0x00, 0x00}
#define FDXB_TEST_DATA_SIZE 11
#define FDXB_TEST_EMULATION_TIMINGS_COUNT (206)

View File

@@ -286,6 +286,10 @@ MU_TEST(mf_ultralight_21_reader) {
mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ultralight_21.nfc"));
}
MU_TEST(mf_ultralight_c_reader) {
mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ultralight_C.nfc"));
}
MU_TEST(ntag_215_reader) {
mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ntag215.nfc"));
}
@@ -828,6 +832,7 @@ MU_TEST_SUITE(nfc) {
MU_RUN_TEST(ntag_215_reader);
MU_RUN_TEST(ntag_216_reader);
MU_RUN_TEST(ntag_213_locked_reader);
MU_RUN_TEST(mf_ultralight_c_reader);
MU_RUN_TEST(mf_ultralight_write);

View File

@@ -43,6 +43,7 @@ typedef struct {
static RpcSessionContext rpc_session[TEST_RPC_SESSIONS];
#define TAG "UnitTestsRpc"
#define MAX_RECEIVE_OUTPUT_TIMEOUT 3000
#define MAX_NAME_LENGTH 255
#define MAX_DATA_SIZE 512u // have to be exact as in rpc_storage.c
@@ -554,7 +555,7 @@ static bool test_rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_
time_left = MAX(time_left, 0);
bytes_received =
furi_stream_buffer_receive(session_context->output_stream, buf, count, time_left);
return (count == bytes_received);
return count == bytes_received;
}
static void

View File

@@ -11,6 +11,7 @@
#include <lib/subghz/devices/cc1101_configs.h>
#define TAG "SubGhzTest"
#define KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes")
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")

View File

@@ -390,7 +390,7 @@ bool subghz_device_cc1101_ext_is_rx_data_crc_valid(void) {
cc1101_read_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(((data[0] >> 7) & 0x01)) {
if((data[0] >> 7) & 0x01) {
return true;
} else {
return false;
@@ -879,9 +879,8 @@ bool subghz_device_cc1101_ext_start_async_tx(SubGhzDeviceCC1101ExtCallback callb
}
bool subghz_device_cc1101_ext_is_async_tx_complete(void) {
return (
(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) &&
(LL_TIM_GetAutoReload(TIM17) == 0));
return (subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) &&
(LL_TIM_GetAutoReload(TIM17) == 0);
}
void subghz_device_cc1101_ext_stop_async_tx(void) {

View File

@@ -5,7 +5,7 @@
#include <string.h>
#define TAG "ble_beacon_app"
#define TAG "BleBeaconApp"
static bool ble_beacon_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);

View File

@@ -344,7 +344,7 @@ bool archive_is_home(ArchiveBrowserView* browser) {
}
const char* default_path = archive_get_default_path(archive_get_tab(browser));
return (furi_string_cmp_str(browser->path, default_path) == 0);
return furi_string_cmp_str(browser->path, default_path) == 0;
}
const char* archive_get_name(ArchiveBrowserView* browser) {

View File

@@ -67,7 +67,7 @@ static inline const char* archive_get_default_path(ArchiveTabEnum tab) {
}
inline bool archive_is_known_app(ArchiveFileTypeEnum type) {
return (type != ArchiveFileTypeFolder && type != ArchiveFileTypeUnknown);
return type != ArchiveFileTypeFolder && type != ArchiveFileTypeUnknown;
}
bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx);

View File

@@ -9,6 +9,7 @@
#include <dolphin/dolphin.h>
#define TAG "BadUsb"
#define WORKER_TAG TAG "Worker"
#define BADUSB_ASCII_TO_KEY(script, x) \
@@ -46,7 +47,7 @@ uint32_t ducky_get_command_len(const char* line) {
}
bool ducky_is_line_end(const char chr) {
return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n'));
return (chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n');
}
uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept_chars) {
@@ -56,7 +57,7 @@ uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept
}
if((accept_chars) && (strlen(param) > 0)) {
return (BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF);
return BADUSB_ASCII_TO_KEY(bad_usb, param[0]) & 0xFF;
}
return 0;
}
@@ -309,7 +310,7 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_usb->st.line_cur - 1U);
return SCRIPT_STATE_ERROR;
} else {
return (delay_val + bad_usb->defdelay);
return delay_val + bad_usb->defdelay;
}
}
@@ -348,7 +349,7 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_usb->st.line_cur);
return SCRIPT_STATE_ERROR;
} else {
return (delay_val + bad_usb->defdelay);
return delay_val + bad_usb->defdelay;
}
} else {
furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]);

View File

@@ -216,6 +216,7 @@ static const DuckyCmd ducky_commands[] = {
};
#define TAG "BadUsb"
#define WORKER_TAG TAG "Worker"
int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) {
@@ -231,7 +232,7 @@ int32_t ducky_execute_cmd(BadUsbScript* bad_usb, const char* line) {
if(ducky_commands[i].callback == NULL) {
return 0;
} else {
return ((ducky_commands[i].callback)(bad_usb, line, ducky_commands[i].param));
return (ducky_commands[i].callback)(bad_usb, line, ducky_commands[i].param);
}
}
}

View File

@@ -36,7 +36,27 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventByteEditResult) {
if(scene_manager_has_previous_scene(scene_manager, iButtonSceneAddType)) {
ibutton_protocols_apply_edits(ibutton->protocols, ibutton->key);
scene_manager_next_scene(scene_manager, iButtonSceneSaveName);
} else {
furi_string_printf(
ibutton->file_path,
"%s/%s%s",
IBUTTON_APP_FOLDER,
ibutton->key_name,
IBUTTON_APP_FILENAME_EXTENSION);
if(ibutton_save_key(ibutton)) {
scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveSuccess);
} else {
const uint32_t possible_scenes[] = {
iButtonSceneReadKeyMenu, iButtonSceneSavedKeyMenu, iButtonSceneAddType};
scene_manager_search_and_switch_to_previous_scene_one_of(
ibutton->scene_manager, possible_scenes, COUNT_OF(possible_scenes));
}
}
} else if(event.event == iButtonCustomEventByteEditChanged) {
ibutton_protocols_apply_edits(ibutton->protocols, ibutton->key);
}

View File

@@ -41,9 +41,17 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context;
bool consumed = false;
const bool is_new_file = furi_string_empty(ibutton->file_path);
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
if(event.event == iButtonCustomEventTextEditResult) {
if(!is_new_file) {
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_simply_remove(storage, furi_string_get_cstr(ibutton->file_path));
furi_record_close(RECORD_STORAGE);
}
furi_string_printf(
ibutton->file_path,
"%s/%s%s",

View File

@@ -6,6 +6,7 @@ enum SubmenuIndex {
SubmenuIndexWriteBlank,
SubmenuIndexWriteCopy,
SubmenuIndexEdit,
SubmenuIndexRename,
SubmenuIndexDelete,
SubmenuIndexInfo,
};
@@ -34,6 +35,7 @@ void ibutton_scene_saved_key_menu_on_enter(void* context) {
}
submenu_add_item(submenu, "Edit", SubmenuIndexEdit, ibutton_submenu_callback, ibutton);
submenu_add_item(submenu, "Rename", SubmenuIndexRename, ibutton_submenu_callback, ibutton);
submenu_add_item(submenu, "Delete", SubmenuIndexDelete, ibutton_submenu_callback, ibutton);
submenu_add_item(submenu, "Info", SubmenuIndexInfo, ibutton_submenu_callback, ibutton);
@@ -61,6 +63,8 @@ bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent even
scene_manager_next_scene(scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexEdit) {
scene_manager_next_scene(scene_manager, iButtonSceneAddValue);
} else if(event.event == SubmenuIndexRename) {
scene_manager_next_scene(scene_manager, iButtonSceneSaveName);
} else if(event.event == SubmenuIndexDelete) {
scene_manager_next_scene(scene_manager, iButtonSceneDeleteConfirm);
} else if(event.event == SubmenuIndexInfo) {

View File

@@ -98,7 +98,7 @@ static bool infrared_move_view_input_callback(InputEvent* event, void* context)
bool consumed = false;
if(((event->type == InputTypeShort || event->type == InputTypeRepeat)) &&
if((event->type == InputTypeShort || event->type == InputTypeRepeat) &&
((event->key == InputKeyUp) || (event->key == InputKeyDown))) {
with_view_model(
move_view->view,

View File

@@ -3,22 +3,22 @@
//TODO: use .txt file in resources for passwords.
const uint32_t default_passwords[] = {
0x51243648, 0x000D8787, 0x19920427, 0x50524F58, 0xF9DCEBA0, 0x65857569, 0x05D73B9F, 0x89A69E60,
0x314159E0, 0xAA55BBBB, 0xA5B4C3D2, 0x1C0B5848, 0x00434343, 0x444E4752, 0x4E457854, 0x44B44CAE,
0x88661858, 0xE9920427, 0x575F4F4B, 0x50520901, 0x20206666, 0x65857569, 0x5469616E, 0x7686962A,
0xC0F5009A, 0x07CEE75D, 0xfeedbeef, 0xdeadc0de, 0x00000000, 0x11111111, 0x22222222, 0x33333333,
0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, 0x99999999, 0xAAAAAAAA, 0xBBBBBBBB,
0xCCCCCCCC, 0xDDDDDDDD, 0xEEEEEEEE, 0xFFFFFFFF, 0xa0a1a2a3, 0xb0b1b2b3, 0x50415353, 0x00000001,
0x00000002, 0x0000000a, 0x0000000b, 0x01020304, 0x02030405, 0x03040506, 0x04050607, 0x05060708,
0x06070809, 0x0708090A, 0x08090A0B, 0x090A0B0C, 0x0A0B0C0D, 0x0B0C0D0E, 0x0C0D0E0F, 0x01234567,
0x12345678, 0x10000000, 0x20000000, 0x30000000, 0x40000000, 0x50000000, 0x60000000, 0x70000000,
0x80000000, 0x90000000, 0xA0000000, 0xB0000000, 0xC0000000, 0xD0000000, 0xE0000000, 0xF0000000,
0x10101010, 0x01010101, 0x11223344, 0x22334455, 0x33445566, 0x44556677, 0x55667788, 0x66778899,
0x778899AA, 0x8899AABB, 0x99AABBCC, 0xAABBCCDD, 0xBBCCDDEE, 0xCCDDEEFF, 0x0CB7E7FC, 0xFABADA11,
0x87654321, 0x12341234, 0x69696969, 0x12121212, 0x12344321, 0x1234ABCD, 0x11112222, 0x13131313,
0x10041004, 0x31415926, 0xabcd1234, 0x20002000, 0x19721972, 0xaa55aa55, 0x55aa55aa, 0x4f271149,
0x07d7bb0b, 0x9636ef8f, 0xb5f44686, 0x9E3779B9, 0xC6EF3720, 0x7854794A, 0xF1EA5EED, 0x69314718,
0x57721566, 0x93C467E3, 0x27182818, 0x50415353};
0x00000000, 0x00000001, 0x00000002, 0x0000000A, 0x0000000B, 0x00012323, 0x000D8787, 0x00434343,
0x01010101, 0x01020304, 0x01234567, 0x02030405, 0x03040506, 0x04050607, 0x05060708, 0x05D73B9F,
0x06070809, 0x0708090A, 0x07CEE75D, 0x07D7BB0B, 0x08090A0B, 0x090A0B0C, 0x0A0B0C0D, 0x0B0C0D0E,
0x0C0D0E0F, 0x0CB7E7FC, 0x10000000, 0x10041004, 0x10101010, 0x11111111, 0x11112222, 0x11223344,
0x12121212, 0x121AD038, 0x12341234, 0x12344321, 0x12345678, 0x1234ABCD, 0x126C248A, 0x13131313,
0x19721972, 0x19920427, 0x1C0B5848, 0x20000000, 0x20002000, 0x20206666, 0x22222222, 0x22334455,
0x27182818, 0x30000000, 0x31415926, 0x314159E0, 0x33333333, 0x33445566, 0x40000000, 0x44444444,
0x444E4752, 0x44556677, 0x44B44CAE, 0x4E457854, 0x4F271149, 0x50000000, 0x50415353, 0x50520901,
0x50524F58, 0x51243648, 0x5469616E, 0x55555555, 0x55667788, 0x55AA55AA, 0x575F4F4B, 0x57721566,
0x60000000, 0x65857569, 0x66666666, 0x66778899, 0x69314718, 0x69696969, 0x70000000, 0x7686962A,
0x77777777, 0x778899AA, 0x7854794A, 0x80000000, 0x87654321, 0x88661858, 0x88888888, 0x8899AABB,
0x89A69E60, 0x90000000, 0x932D9963, 0x93C467E3, 0x9636EF8F, 0x99999999, 0x99AABBCC, 0x9E3779B9,
0xA0000000, 0xA0A1A2A3, 0xA5B4C3D2, 0xAA55AA55, 0xAA55BBBB, 0xAAAAAAAA, 0xAABBCCDD, 0xABCD1234,
0xB0000000, 0xB0B1B2B3, 0xB5F44686, 0xBBBBBBBB, 0xBBCCDDEE, 0xC0000000, 0xC0F5009A, 0xC6EF3720,
0xCCCCCCCC, 0xCCDDEEFF, 0xD0000000, 0xDDDDDDDD, 0xDEADC0DE, 0xE0000000, 0xE4204998, 0xE9920427,
0xEEEEEEEE, 0xF0000000, 0xF1EA5EED, 0xF9DCEBA0, 0xFABADA11, 0xFEEDBEEF, 0xFFFFFFFF};
const uint32_t* lfrfid_get_t5577_default_passwords(uint8_t* len) {
*len = sizeof(default_passwords) / sizeof(uint32_t);

View File

@@ -23,7 +23,7 @@ static void lfrfid_cli_print_usage(void) {
"rfid raw_emulate <filename> - emulate raw data (not very useful, but helps debug protocols)\r\n");
printf(
"rfid raw_analyze <filename> - outputs raw data to the cli and tries to decode it (useful for protocol development)\r\n");
};
}
typedef struct {
ProtocolId protocol;

View File

@@ -31,8 +31,21 @@ bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) {
consumed = true;
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size);
if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSaveType)) {
scene_manager_next_scene(scene_manager, LfRfidSceneSaveName);
scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1);
} else {
if(!furi_string_empty(app->file_name)) {
lfrfid_delete_key(app);
}
if(lfrfid_save_key(app)) {
scene_manager_next_scene(scene_manager, LfRfidSceneSaveSuccess);
} else {
scene_manager_search_and_switch_to_previous_scene(
scene_manager, LfRfidSceneSavedKeyMenu);
}
}
}
} else if(event.type == SceneManagerEventTypeBack) {
scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 0);

View File

@@ -6,6 +6,7 @@ typedef enum {
SubmenuIndexWrite,
SubmenuIndexWriteAndSetPass,
SubmenuIndexEdit,
SubmenuIndexRename,
SubmenuIndexDelete,
SubmenuIndexInfo,
} SubmenuIndex;
@@ -32,6 +33,8 @@ void lfrfid_scene_saved_key_menu_on_enter(void* context) {
app);
submenu_add_item(
submenu, "Edit", SubmenuIndexEdit, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
submenu, "Rename", SubmenuIndexRename, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
submenu, "Delete", SubmenuIndexDelete, lfrfid_scene_saved_key_menu_submenu_callback, app);
submenu_add_item(
@@ -63,6 +66,9 @@ bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event
} else if(event.event == SubmenuIndexEdit) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData);
consumed = true;
} else if(event.event == SubmenuIndexRename) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveName);
consumed = true;
} else if(event.event == SubmenuIndexDelete) {
scene_manager_next_scene(app->scene_manager, LfRfidSceneDeleteConfirm);
consumed = true;

View File

@@ -20,6 +20,7 @@ void mf_ultralight_auth_reset(MfUltralightAuth* instance) {
instance->type = MfUltralightAuthTypeNone;
memset(&instance->password, 0, sizeof(MfUltralightAuthPassword));
memset(&instance->tdes_key, 0, sizeof(MfUltralightC3DesAuthKey));
memset(&instance->pack, 0, sizeof(MfUltralightAuthPack));
}

View File

@@ -17,6 +17,7 @@ typedef enum {
typedef struct {
MfUltralightAuthType type;
MfUltralightAuthPassword password;
MfUltralightC3DesAuthKey tdes_key;
MfUltralightAuthPack pack;
} MfUltralightAuth;

View File

@@ -24,7 +24,7 @@ typedef enum {
} NfcSupportedCardsPluginFeature;
typedef struct {
FuriString* path;
FuriString* name;
NfcProtocol protocol;
NfcSupportedCardsPluginFeature feature;
} NfcSupportedCardsPluginCache;
@@ -41,7 +41,6 @@ typedef enum {
typedef struct {
Storage* storage;
File* directory;
FuriString* file_path;
char file_name[256];
FlipperApplication* app;
} NfcSupportedCardsLoadContext;
@@ -73,7 +72,7 @@ void nfc_supported_cards_free(NfcSupportedCards* instance) {
!NfcSupportedCardsPluginCache_end_p(iter);
NfcSupportedCardsPluginCache_next(iter)) {
NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(iter);
furi_string_free(plugin_cache->path);
furi_string_free(plugin_cache->name);
}
NfcSupportedCardsPluginCache_clear(instance->plugins_cache_arr);
@@ -86,7 +85,6 @@ static NfcSupportedCardsLoadContext* nfc_supported_cards_load_context_alloc(void
instance->storage = furi_record_open(RECORD_STORAGE);
instance->directory = storage_file_alloc(instance->storage);
instance->file_path = furi_string_alloc();
if(!storage_dir_open(instance->directory, NFC_SUPPORTED_CARDS_PLUGINS_PATH)) {
FURI_LOG_D(TAG, "Failed to open directory: %s", NFC_SUPPORTED_CARDS_PLUGINS_PATH);
@@ -100,8 +98,6 @@ static void nfc_supported_cards_load_context_free(NfcSupportedCardsLoadContext*
flipper_application_free(instance->app);
}
furi_string_free(instance->file_path);
storage_dir_close(instance->directory);
storage_file_free(instance->directory);
@@ -111,16 +107,19 @@ static void nfc_supported_cards_load_context_free(NfcSupportedCardsLoadContext*
static const NfcSupportedCardsPlugin* nfc_supported_cards_get_plugin(
NfcSupportedCardsLoadContext* instance,
const FuriString* path,
const char* name,
const ElfApiInterface* api_interface) {
furi_assert(instance);
furi_assert(path);
furi_assert(name);
const NfcSupportedCardsPlugin* plugin = NULL;
FuriString* plugin_path = furi_string_alloc_printf(
"%s/%s%s", NFC_SUPPORTED_CARDS_PLUGINS_PATH, name, NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX);
do {
if(instance->app) flipper_application_free(instance->app);
instance->app = flipper_application_alloc(instance->storage, api_interface);
if(flipper_application_preload(instance->app, furi_string_get_cstr(path)) !=
if(flipper_application_preload(instance->app, furi_string_get_cstr(plugin_path)) !=
FlipperApplicationPreloadStatusSuccess)
break;
if(!flipper_application_is_plugin(instance->app)) break;
@@ -136,6 +135,7 @@ static const NfcSupportedCardsPlugin* nfc_supported_cards_get_plugin(
plugin = descriptor->entry_point;
} while(false);
furi_string_free(plugin_path);
return plugin;
}
@@ -151,13 +151,21 @@ static const NfcSupportedCardsPlugin* nfc_supported_cards_get_next_plugin(
instance->directory, NULL, instance->file_name, sizeof(instance->file_name)))
break;
furi_string_set(instance->file_path, instance->file_name);
if(!furi_string_end_with_str(instance->file_path, NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX))
continue;
const size_t suffix_len = strlen(NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX);
const size_t file_name_len = strlen(instance->file_name);
if(file_name_len <= suffix_len) break;
path_concat(NFC_SUPPORTED_CARDS_PLUGINS_PATH, instance->file_name, instance->file_path);
size_t suffix_start_pos = file_name_len - suffix_len;
if(memcmp(
&instance->file_name[suffix_start_pos],
NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX,
suffix_len) != 0) //-V1051
break;
plugin = nfc_supported_cards_get_plugin(instance, instance->file_path, api_interface);
// Trim suffix from file_name to save memory. The suffix will be concatenated on plugin load.
instance->file_name[suffix_start_pos] = '\0';
plugin = nfc_supported_cards_get_plugin(instance, instance->file_name, api_interface);
} while(plugin == NULL); //-V654
return plugin;
@@ -181,7 +189,7 @@ void nfc_supported_cards_load_cache(NfcSupportedCards* instance) {
if(plugin == NULL) break; //-V547
NfcSupportedCardsPluginCache plugin_cache = {}; //-V779
plugin_cache.path = furi_string_alloc_set(instance->load_context->file_path);
plugin_cache.name = furi_string_alloc_set(instance->load_context->file_name);
plugin_cache.protocol = plugin->protocol;
if(plugin->verify) {
plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasVerify;
@@ -233,7 +241,7 @@ bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nf
const ElfApiInterface* api_interface =
composite_api_resolver_get(instance->api_resolver);
const NfcSupportedCardsPlugin* plugin = nfc_supported_cards_get_plugin(
instance->load_context, plugin_cache->path, api_interface);
instance->load_context, furi_string_get_cstr(plugin_cache->name), api_interface);
if(plugin == NULL) continue;
if(plugin->verify) {
@@ -281,7 +289,7 @@ bool nfc_supported_cards_parse(
const ElfApiInterface* api_interface =
composite_api_resolver_get(instance->api_resolver);
const NfcSupportedCardsPlugin* plugin = nfc_supported_cards_get_plugin(
instance->load_context, plugin_cache->path, api_interface);
instance->load_context, furi_string_get_cstr(plugin_cache->name), api_interface);
if(plugin == NULL) continue;
if(plugin->parse) {

View File

@@ -9,6 +9,10 @@
#include "../nfc_protocol_support_gui_common.h"
#include "../iso14443_4a/iso14443_4a_i.h"
enum {
SubmenuIndexTransactions = SubmenuIndexCommonMax,
};
static void nfc_scene_info_on_enter_emv(NfcApp* instance) {
const NfcDevice* device = instance->nfc_device;
const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv);
@@ -24,11 +28,6 @@ static void nfc_scene_info_on_enter_emv(NfcApp* instance) {
furi_string_free(temp_str);
}
static void nfc_scene_more_info_on_enter_emv(NfcApp* instance) {
// Jump to advanced scene right away
scene_manager_next_scene(instance->scene_manager, NfcSceneEmvMoreInfo);
}
static NfcCommand nfc_scene_read_poller_callback_emv(NfcGenericEvent event, void* context) {
furi_assert(event.protocol == NfcProtocolEmv);
@@ -49,6 +48,20 @@ static void nfc_scene_read_on_enter_emv(NfcApp* instance) {
nfc_poller_start(instance->poller, nfc_scene_read_poller_callback_emv, instance);
}
static void nfc_scene_read_menu_on_enter_emv(NfcApp* instance) {
Submenu* submenu = instance->submenu;
const EmvData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolEmv);
if(data->emv_application.active_tr > 0) {
submenu_add_item(
submenu,
"Transactions",
SubmenuIndexTransactions,
nfc_protocol_support_common_submenu_callback,
instance);
}
}
static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) {
const NfcDevice* device = instance->nfc_device;
const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv);
@@ -64,8 +77,21 @@ static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) {
furi_string_free(temp_str);
}
static bool nfc_scene_read_menu_on_event_emv(NfcApp* instance, SceneManagerEvent event) {
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexTransactions) {
scene_manager_next_scene(instance->scene_manager, NfcSceneEmvTransactions);
consumed = true;
}
}
return consumed;
}
const NfcProtocolSupportBase nfc_protocol_support_emv = {
.features = NfcProtocolFeatureMoreInfo,
.features = NfcProtocolFeatureNone,
.scene_info =
{
@@ -74,7 +100,7 @@ const NfcProtocolSupportBase nfc_protocol_support_emv = {
},
.scene_more_info =
{
.on_enter = nfc_scene_more_info_on_enter_emv,
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
},
.scene_read =
@@ -84,8 +110,8 @@ const NfcProtocolSupportBase nfc_protocol_support_emv = {
},
.scene_read_menu =
{
.on_enter = nfc_protocol_support_common_on_enter_empty,
.on_event = nfc_protocol_support_common_on_event_empty,
.on_enter = nfc_scene_read_menu_on_enter_emv,
.on_event = nfc_scene_read_menu_on_event_emv,
},
.scene_read_success =
{

View File

@@ -68,7 +68,8 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) {
const uint8_t len = apl->aid_len;
furi_string_cat_printf(str, "AID: ");
for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]);
for(uint8_t i = 0; i < len; i++)
furi_string_cat_printf(str, "%02X", apl->aid[i]);
furi_string_cat_printf(str, "\n");
}

View File

@@ -106,7 +106,7 @@ static void nfc_scene_read_success_on_enter_felica(NfcApp* instance) {
FuriString* temp_str = furi_string_alloc();
if(!scene_manager_has_previous_scene(instance->scene_manager, NfcSceneFelicaUnlockWarn)) {
if(!scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDesAuthUnlockWarn)) {
furi_string_cat_printf(
temp_str, "\e#%s\n", nfc_device_get_name(device, NfcDeviceNameTypeFull));
nfc_render_felica_info(data, NfcProtocolFormatTypeShort, temp_str);
@@ -163,7 +163,7 @@ static void nfc_scene_read_menu_on_enter_felica(NfcApp* instance) {
static bool nfc_scene_read_menu_on_event_felica(NfcApp* instance, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexUnlock) {
scene_manager_next_scene(instance->scene_manager, NfcSceneFelicaKeyInput);
scene_manager_next_scene(instance->scene_manager, NfcSceneDesAuthKeyInput);
return true;
}
}

View File

@@ -71,7 +71,7 @@ void nfc_render_iso15693_3_system_info(const Iso15693_3Data* data, FuriString* s
void nfc_render_iso15693_3_extra(const Iso15693_3Data* data, FuriString* str) {
furi_string_cat(str, "\n::::::::::::::::[General info]:::::::::::::::::\n");
if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) {
furi_string_cat_printf(str, "DSFID: %02X\n", data->system_info.ic_ref);
furi_string_cat_printf(str, "DSFID: %02X\n", data->system_info.dsfid);
}
if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_AFI) {

View File

@@ -91,7 +91,7 @@ void nfc_render_mf_desfire_version(const MfDesfireVersion* data, FuriString* str
furi_string_cat_printf(
str,
"batch %02x:%02x:%02x:%02x:%02x\n"
"week %d year %d\n",
"week %02x year 20%02x\n",
data->batch[0],
data->batch[1],
data->batch[2],

View File

@@ -150,6 +150,7 @@ static NfcCommand
}
if(!mf_ultralight_event->data->auth_context.skip_auth) {
mf_ultralight_event->data->auth_context.password = instance->mf_ul_auth->password;
mf_ultralight_event->data->auth_context.tdes_key = instance->mf_ul_auth->tdes_key;
}
} else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthSuccess) {
instance->mf_ul_auth->pack = mf_ultralight_event->data->auth_context.pack;
@@ -243,7 +244,13 @@ static bool nfc_scene_read_and_saved_menu_on_event_mf_ultralight(
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexUnlock) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu);
const MfUltralightData* data =
nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight);
uint32_t next_scene = (data->type == MfUltralightTypeMfulC) ?
NfcSceneDesAuthKeyInput :
NfcSceneMfUltralightUnlockMenu;
scene_manager_next_scene(instance->scene_manager, next_scene);
consumed = true;
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite);

View File

@@ -22,7 +22,7 @@ void nfc_unlock_helper_setup_from_state(NfcApp* instance) {
bool unlocking =
scene_manager_has_previous_scene(
instance->scene_manager, NfcSceneMfUltralightUnlockWarn) ||
scene_manager_has_previous_scene(instance->scene_manager, NfcSceneFelicaUnlockWarn);
scene_manager_has_previous_scene(instance->scene_manager, NfcSceneDesAuthUnlockWarn);
uint32_t state = unlocking ? NfcSceneReadMenuStateCardSearch : NfcSceneReadMenuStateCardFound;

View File

@@ -6,6 +6,7 @@
#include <bit_lib.h>
#define TAG "HI!"
#define KEY_LENGTH 6
#define HI_KEY_TO_GEN 5
#define UID_LENGTH 7

View File

@@ -6,6 +6,7 @@
#include <bit_lib.h>
#define TAG "Microel"
#define KEY_LENGTH 6
#define UID_LENGTH 4

View File

@@ -6,6 +6,7 @@
#include <bit_lib.h>
#define TAG "MiZIP"
#define KEY_LENGTH 6
#define MIZIP_KEY_TO_GEN 5
#define UID_LENGTH 4

View File

@@ -10,6 +10,7 @@
#include <bit_lib.h>
#define TAG "Saflok"
#define MAGIC_TABLE_SIZE 192
#define KEY_LENGTH 6
#define UID_LENGTH 4

View File

@@ -38,7 +38,7 @@ bool parse_datetime(uint16_t date, DateTime* result) {
result->year = 2000 + (date >> 9);
result->month = date >> 5 & 0x0F;
result->day = date & 0x1F;
return (date != 0);
return date != 0;
}
static bool umarsh_parse(const NfcDevice* device, FuriString* parsed_data) {

View File

@@ -1,7 +1,7 @@
###########################
# Do not edit, this file will be overwritten after firmware update
# Use the user_dict file for user keys
# Last updated 17 December 2023
# Last updated 11 July 2024
###########################
# +-----------------------------------------------------------------------------------------------------+
# | https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_default_keys.dic |
@@ -244,15 +244,15 @@ E3429281EFC1
# 3dprinter
# EPI Envisionte
AAFB06045877
# gym
# Gyms / Fitness Clubs / Health Clubs / Wellness Centres
# Fysiken A
3E65E4FB65B3
# Fysiken B
25094DF6F148
# https://mattionline.de/fitnessstudio-armband-reverse-engineering/
# https://mattionline.de/milazycracker/
# gym wistband A, same as Fysiken A
# gym wistband B
# Gym Wristband A - Same as Fysiken A
# Gym Wristband B
81CC25EBBB6A
195DC63DB3A3
# CleverFit
@@ -260,9 +260,12 @@ A05DBD98E0FC
# GoFit
AA4DDA458EBB
EAB8066C7479
# Nordic Wellness A, same as Fysiken A
# Nordic Wellness A - Same as Fysiken A
# Nordic Wellness B
E5519E1CC92B
# Jett's 24 Hour Fitness S0 KA/B
# 049979614077
# 829338771705
# Hotel KeyCard
D3B595E9DD63
AFBECD121004
@@ -290,6 +293,8 @@ F101622750B7
B39AE17435DC
# key A
454841585443
# Lift system
190819842023
# Data from http://pastebin.com/gQ6nk38G
D39BB83F5297
85675B200017
@@ -958,6 +963,14 @@ EA0FD73CB149
FC0001877BF7
FD8705E721B0
00ADA2CD516D
518108E061E2
558AAD64EB5B
001122334455
6CA761AB6CA7
B1C4A8F7F6E3
FF75AFDA5A3C
FCDDF7767C10
A6B3F6C8F1D4
237A4D0D9119
0ED7846C2BC9
FFFFD06F83E3
@@ -1935,6 +1948,13 @@ E69DD9015A43
C8382A233993
7B304F2A12A6
FC9418BF788B
# Guest Cashless Prepaid Arcade Payment Cards
168168168168
198407157610
4E4F584D2101
4E4F584D2105
686B35333376
861861861861
# Data from "the more the marriott" mifare project (colonelborkmundus)
# aka The Horde
# These keys seem to be from Vingcard / Saflok system which means they are diversified
@@ -2111,6 +2131,122 @@ B12000000000
B13000000000
B14000000000
B15000000000
# Pittsburgh, PA, USA - Pittsburgh Regional Transit ConnectCard
A7AE4A5A33DC
6B857B568C10
E2CE9A674CBE
A4896B2EBA4E
0724DF9AEDE8
0E368FB140C1
874EB25C8721
5C313F4539CD
C5498606E0A8
79C69F7EC7C0
DA7DD0044DA2
1B8189BD966B
765584147990
4B7C7C315E6E
46CAAD12C524
53BD03DEA5C9
D2D72CB60F59
14D258786538
E2E89A375B36
B3FA87DB0C45
44D3B1561B34
2817C6E02F97
A513FF1232E9
BD454BD52792
391771654DC8
5162797F8E1C
F700BD8E042D
3973ABFD8B66
CE8BFF3728EE
09938D05DA78
EACDA4DBE420
EC2B9FD483CA
# Hotel Intelier Orange - Benicasim, Spain
# block 1 - key A
04256CFE0425
# InsideWash Membership Card - Portugal
C18063858BB9
# An apartment building in Sydney Olympic Park
13254608D0AB
24A2971BC0B2
14264709D1AC
25A3981CC1B3
1527480AD2AD
26A4991DC2B4
1628490BD3AE
27A59A1EC3B5
17294A0CD4AF
28A69B1FC4B6
182A4B0DD5B0
29A79C20C5B7
192B4C0ED6B1
2AA89D21C6B8
1A2C4D0FD7B2
2BA99E22C7B9
1B2D4E10D8B3
2CAA9F23C8BA
1C2E4F11D9B4
2DABA024C9BB
1D2F5012DAB5
2EACA125CABC
1E305113DBB6
2FADA226CBBD
1F315214DCB7
30AEA327CCBE
20325315DDB8
31AFA428CDBF
21335416DEB9
32B0A529CEC0
22345517DFBA
33B1A62ACFC1
# Universidade de Sao Paulo (USP) student card
17B50E38F1B0
24E311F594CE
3794FBFB1A54
43B229069F6A
4531952F765F
4943F2F35E0A
4985E681EF88
4F56C88E0337
710070E92C79
8A036C5C35D4
A027BD830A06
D33673C19243
D89A506542F2
E5813CD228F1
FAB943906E9C
# R.A.T.T transport card key A/B
AA034F342A55
456776908C48
# BusFacil - Brazilian public transport card for some cities
FAE9B14365A9
C567DD4A6004
C567DD4A6005
C567DD4A6006
C567DD4A6007
C567DD4A6008
C567DD4A6009
C567DD4A600A
C567DD4A600D
C567DD4A600E
C567DD4A600F
5EF014EC5D7F
5086052022AC
BD6AF9754C18
5D67D4732A7D
17FE45604A04
17FE45604A05
17FE45604A06
17FE45604A07
17FE45604A08
17FE45604A09
17FE45604A0A
17FE45604A0D
17FE45604A0E
17FE45604A0F
# +--------------------------------------------------------------------------------------------------------+
# | https://github.com/RfidResearchGroup/proxmark3/blob/master/client/dictionaries/mfc_keys_bmp_sorted.dic |
# +--------------------------------------------------------------------------------------------------------+
@@ -4120,17 +4256,7 @@ EED69A391464
# +-----------------------------------------------------------------------------------------------------------------------------------+
# | https://github.com/ikarus23/MifareClassicTool/blob/master/Mifare%20Classic%20Tool/app/src/main/assets/key-files/extended-std.keys |
# +-----------------------------------------------------------------------------------------------------------------------------------+
# Wojo coworking space, Fance
FF75AFDA5A3C
558AAD64EB5B
518108E061E2
FCDDF7767C10
A6B3F6C8F1D4
B1C4A8F7F6E3
# Key from some random card
001122334455
# Key from hotel in Spain
6CA761AB6CA7
# Nothing currently, all included in blocks above
# +----------------------------------------------------------------------------------------------+
# | https://github.com/UberGuidoZ/Flipper/blob/main/NFC/mf_classic_dict/mf_classic_dict_user.nfc |
# +----------------------------------------------------------------------------------------------+
@@ -4147,7 +4273,6 @@ A2CA48CA4C05
193DFE0FA18E
3D6F823FFFFF
48C8852D15F9
4E4F584D2105
7213B13D02E0
7ADD3D735725
7F796F60FFFF
@@ -4158,6 +4283,32 @@ AEF617B3D040
C1F6C7B55F5E
# Metro card Sec 001 Blk 007 key B
EDA4BF3E7B04
# Lime Fitness
113355779933
# Some employee badges and other interesting things
4D4946415245
2B29232D3624
2D2F182C4024
BE3C1BF60B37
D156F66D38EC
4A1094F378D8
CB5ED0E57B08
AE381EA0811B
40454EE64229
66A4932816D3
B54D99618ADC
08D6A7765640
3E0557273982
68C867397AD5
4427385D72AB
9B2C3E00B561
120A7837BB5D
B19A0664ECA6
B456E1951216
E87E3554727E
8D96A0BA7234
124F004321D3
D881B675D881
# +--------------------------------------------------------------------------------------------------------------------------------+
# | https://github.com/flipperdevices/flipperzero-firmware/blob/dev/applications/main/nfc/resources/nfc/assets/mf_classic_dict.nfc |
# +--------------------------------------------------------------------------------------------------------------------------------+
@@ -4338,9 +4489,3 @@ EA19E58DD046
3F41891454EE
7EDAE7923287
11DDA4862A1C
##############################################
# Bubbleland Play Card - keys from Bubble Land Arcade
# Found with FlipperNestedRecovery by CaitSith2
168168168168
861861861861
686B35333376

View File

@@ -33,13 +33,13 @@ ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu)
ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn)
ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput)
ADD_SCENE(nfc, mf_ultralight_capture_pass, MfUltralightCapturePass)
ADD_SCENE(nfc, felica_key_input, FelicaKeyInput)
ADD_SCENE(nfc, felica_unlock_warn, FelicaUnlockWarn)
ADD_SCENE(nfc, des_auth_key_input, DesAuthKeyInput)
ADD_SCENE(nfc, des_auth_unlock_warn, DesAuthUnlockWarn)
ADD_SCENE(nfc, mf_desfire_more_info, MfDesfireMoreInfo)
ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp)
ADD_SCENE(nfc, emv_more_info, EmvMoreInfo)
ADD_SCENE(nfc, emv_transactions, EmvTransactions)
ADD_SCENE(nfc, mf_classic_dict_attack, MfClassicDictAttack)
ADD_SCENE(nfc, mf_classic_detect_reader, MfClassicDetectReader)

View File

@@ -1,43 +1,54 @@
#include "../nfc_app_i.h"
void nfc_scene_felica_key_input_byte_input_callback(void* context) {
void nfc_scene_des_auth_key_input_byte_input_callback(void* context) {
NfcApp* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventByteInputDone);
}
void nfc_scene_felica_key_input_on_enter(void* context) {
void nfc_scene_des_auth_key_input_on_enter(void* context) {
NfcApp* nfc = context;
// Setup view
NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device);
uint8_t* key = (protocol == NfcProtocolFelica) ? nfc->felica_auth->card_key.data :
nfc->mf_ul_auth->tdes_key.data;
ByteInput* byte_input = nfc->byte_input;
byte_input_set_header_text(byte_input, "Enter key in hex");
byte_input_set_result_callback(
byte_input,
nfc_scene_felica_key_input_byte_input_callback,
nfc_scene_des_auth_key_input_byte_input_callback,
NULL,
nfc,
nfc->felica_auth->card_key.data,
key,
FELICA_DATA_BLOCK_SIZE);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
}
bool nfc_scene_felica_key_input_on_event(void* context, SceneManagerEvent event) {
bool nfc_scene_des_auth_key_input_on_event(void* context, SceneManagerEvent event) {
NfcApp* nfc = context;
UNUSED(event);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcCustomEventByteInputDone) {
NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device);
if(protocol == NfcProtocolFelica) {
nfc->felica_auth->skip_auth = false;
scene_manager_next_scene(nfc->scene_manager, NfcSceneFelicaUnlockWarn);
} else {
nfc->mf_ul_auth->type = MfUltralightAuthTypeManual;
}
scene_manager_next_scene(nfc->scene_manager, NfcSceneDesAuthUnlockWarn);
consumed = true;
}
}
return consumed;
}
void nfc_scene_felica_key_input_on_exit(void* context) {
void nfc_scene_des_auth_key_input_on_exit(void* context) {
NfcApp* nfc = context;
// Clear view

View File

@@ -1,25 +1,30 @@
#include "../nfc_app_i.h"
void nfc_scene_felica_unlock_warn_dialog_callback(DialogExResult result, void* context) {
void nfc_scene_des_auth_unlock_warn_dialog_callback(DialogExResult result, void* context) {
NfcApp* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, result);
}
void nfc_scene_felica_unlock_warn_on_enter(void* context) {
void nfc_scene_des_auth_unlock_warn_on_enter(void* context) {
NfcApp* nfc = context;
const char* message = "Risky Action!";
DialogEx* dialog_ex = nfc->dialog_ex;
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_felica_unlock_warn_dialog_callback);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_des_auth_unlock_warn_dialog_callback);
dialog_ex_set_header(dialog_ex, message, 64, 0, AlignCenter, AlignTop);
FuriString* str = furi_string_alloc();
furi_string_cat_printf(str, "Unlock with key: ");
NfcProtocol protocol = nfc_device_get_protocol(nfc->nfc_device);
uint8_t* key = (protocol == NfcProtocolFelica) ? nfc->felica_auth->card_key.data :
nfc->mf_ul_auth->tdes_key.data;
for(uint8_t i = 0; i < FELICA_DATA_BLOCK_SIZE; i++)
furi_string_cat_printf(str, "%02X ", nfc->felica_auth->card_key.data[i]);
furi_string_cat_printf(str, "%02X ", key[i]);
furi_string_cat_printf(str, "?");
nfc_text_store_set(nfc, furi_string_get_cstr(str));
@@ -33,7 +38,7 @@ void nfc_scene_felica_unlock_warn_on_enter(void* context) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
}
bool nfc_scene_felica_unlock_warn_on_event(void* context, SceneManagerEvent event) {
bool nfc_scene_des_auth_unlock_warn_on_event(void* context, SceneManagerEvent event) {
NfcApp* nfc = context;
UNUSED(event);
bool consumed = false;
@@ -51,7 +56,7 @@ bool nfc_scene_felica_unlock_warn_on_event(void* context, SceneManagerEvent even
return consumed;
}
void nfc_scene_felica_unlock_warn_on_exit(void* context) {
void nfc_scene_des_auth_unlock_warn_on_exit(void* context) {
NfcApp* nfc = context;
dialog_ex_reset(nfc->dialog_ex);

View File

@@ -1,76 +0,0 @@
#include "../nfc_app_i.h"
#include "../helpers/protocol_support/nfc_protocol_support_gui_common.h"
#include "../helpers/protocol_support/emv/emv_render.h"
enum {
EmvMoreInfoStateMenu,
EmvMoreInfoStateItem, // MUST be last, states >= this correspond with submenu index
};
enum SubmenuIndex {
SubmenuIndexTransactions,
SubmenuIndexDynamic, // dynamic indices start here
};
void nfc_scene_emv_more_info_on_enter(void* context) {
NfcApp* nfc = context;
Submenu* submenu = nfc->submenu;
text_box_set_font(nfc->text_box, TextBoxFontHex);
submenu_add_item(
submenu,
"Transactions",
SubmenuIndexTransactions,
nfc_protocol_support_common_submenu_callback,
nfc);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
bool nfc_scene_emv_more_info_on_event(void* context, SceneManagerEvent event) {
NfcApp* nfc = context;
bool consumed = false;
const uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneEmvMoreInfo);
const EmvData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolEmv);
if(event.type == SceneManagerEventTypeCustom) {
widget_reset(nfc->widget);
if(event.event == SubmenuIndexTransactions) {
FuriString* temp_str = furi_string_alloc();
nfc_render_emv_transactions(&data->emv_application, temp_str);
widget_add_text_scroll_element(
nfc->widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
scene_manager_set_scene_state(
nfc->scene_manager,
NfcSceneEmvMoreInfo,
EmvMoreInfoStateItem + SubmenuIndexTransactions);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
if(state >= EmvMoreInfoStateItem) {
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneEmvMoreInfo, EmvMoreInfoStateMenu);
} else {
// Return directly to the Info scene
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneInfo);
}
consumed = true;
}
return consumed;
}
void nfc_scene_emv_more_info_on_exit(void* context) {
NfcApp* nfc = context;
// Clear views
widget_reset(nfc->widget);
submenu_reset(nfc->submenu);
}

View File

@@ -0,0 +1,31 @@
#include "../nfc_app_i.h"
#include "../helpers/protocol_support/nfc_protocol_support_gui_common.h"
#include "../helpers/protocol_support/emv/emv_render.h"
void nfc_scene_emv_transactions_on_enter(void* context) {
NfcApp* nfc = context;
Widget* widget = nfc->widget;
const EmvData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolEmv);
FuriString* temp_str = furi_string_alloc();
nfc_render_emv_transactions(&data->emv_application, temp_str);
widget_add_text_scroll_element(widget, 0, 0, 128, 52, furi_string_get_cstr(temp_str));
furi_string_free(temp_str);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
bool nfc_scene_emv_transactions_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void nfc_scene_emv_transactions_on_exit(void* context) {
NfcApp* nfc = context;
widget_reset(nfc->widget);
}

View File

@@ -22,7 +22,7 @@ void nfc_scene_mf_classic_mfkey_complete_on_enter(void* context) {
AlignCenter,
AlignTop,
FontSecondary,
"Now use Mfkey32 to extract \nkeys: lab.flipper.net/nfc-tools");
"Now use Mfkey32 to extract \nkeys: r.flipper.net/nfc-tools");
widget_add_icon_element(instance->widget, 50, 39, &I_MFKey_qr_25x25);
widget_add_button_element(
instance->widget,

View File

@@ -2,6 +2,7 @@
#include <lib/subghz/subghz_tx_rx_worker.h>
#define TAG "SubGhzChat"
#define SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES 500
struct SubGhzChatWorker {

View File

@@ -83,6 +83,8 @@ typedef enum {
SetTypeCenturion433,
SetTypeSommer_FM_434,
SetTypeSommer_FM_868,
SetTypeSommer_FM238_434,
SetTypeSommer_FM238_868,
SetTypeStilmatic,
SetTypeIronLogic,
SetTypeDeaMio433,
@@ -93,6 +95,8 @@ typedef enum {
SetTypeElmesElectronic,
SetTypeNormstahl_433_92,
SetTypeJCM_433_92,
SetTypeNovoferm_433_92,
SetTypeHormannEcoStar_433_92,
SetTypeFAACRCXT_433_92,
SetTypeFAACRCXT_868,
SetTypeGeniusBravo433,

View File

@@ -3,6 +3,7 @@
#include "../subghz_i.h"
#define TAG "SubGhzThresholdRssi"
#define THRESHOLD_RSSI_LOW_COUNT 10
struct SubGhzThresholdRssi {

View File

@@ -363,7 +363,7 @@ void subghz_txrx_stop(SubGhzTxRx* instance) {
}
}
void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
void subghz_txrx_hopper_update(SubGhzTxRx* instance, float stay_threshold) {
furi_assert(instance);
switch(instance->hopper_state) {
@@ -386,7 +386,7 @@ void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
float rssi = subghz_devices_get_rssi(instance->radio_device);
// Stay if RSSI is high enough
if(rssi > -90.0f) {
if(rssi > stay_threshold) {
instance->hopper_timeout = 10;
instance->hopper_state = SubGhzHopperStateRSSITimeOut;
return;
@@ -528,22 +528,19 @@ SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) {
bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) {
furi_assert(instance);
return (
(instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
SubGhzProtocolFlag_Save);
return (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
SubGhzProtocolFlag_Save;
}
bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) {
furi_assert(instance);
const SubGhzProtocol* protocol = instance->decoder_result->protocol;
if(check_type) {
return (
((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic);
return ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic;
}
return (
((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
protocol->encoder->deserialize);
return ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
protocol->encoder->deserialize;
}
void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) {

View File

@@ -121,8 +121,9 @@ void subghz_txrx_sleep(SubGhzTxRx* instance);
* Update frequency CC1101 in automatic mode (hopper)
*
* @param instance Pointer to a SubGhzTxRx
* @param stay_threshold RSSI theshold over which to stay before hopping
*/
void subghz_txrx_hopper_update(SubGhzTxRx* instance);
void subghz_txrx_hopper_update(SubGhzTxRx* instance, float stay_threshold);
/**
* Get state hopper

View File

@@ -1,59 +1,60 @@
Filetype: Flipper SubGhz Keystore File
Version: 0
Encryption: 1
IV: AD 0B A4 A1 51 C0 C0 41 36 78 26 82 17 24 9D 62
0D18FF475E57A67CC5C0B430664E8EF6E07CB6AF72454995F17DE84E2E876D87
C9BC55E1E3A9B312E341D7E2663C66C2479D5C51AE2EB83BAE47D8C6C79DB8A0
776E01A7B4FCB929FA59CFE1F16D2D600F6FD9FD8BE1E9E41667144E61E023E4
C354F854F14AAC08C6A51606582CD73EECEED54779927DC1E04A0D72C4E6A58E
09BA4DC551CDB0141F4A053133DBF9B7B99CBAA402C7B6B2AC8ADB516CA2FCB29FF9744DD95FB009BED6A09AE3303317
675777F65042358100A9A2BE142C42E10CC5CF98CA6BFF82284FFD9BF7E7FB11
4739972DCC08EFF0E8547694A67E116F3EC8638F286E333E7D89F2D61218F65D
FE8D5A0A9ED36545004CEE70D3C1FE477F34212364CF7C9EBA0FDD4F6B8F1D3E
453D5C6FE0EA7FD779B54696E66DE6BD6AEF3B1EE347142A3DB7505609077219
A52339EE40D046E7DF6C130CEC7F9F686753A73A5F72EF344E01B00C3A3CF5F2
94029CE386CC0403984F7C9D80B40FF12BE6E50412891FD45B347742340D1E6E679102DEC6F7D36C36863701A2BBDA7B
793633A3D97D704779E2E841A5F616ED0BB0BD50740C0B196D72C6C6453124183CA93ADCAC1A5042EBD579AC238B9DBC
B1C6EBB7320CAE97E28A244228B288BEEA44C9FD262E2C448219DAC6E194CB14
A6C374B3FB7E8BB6F3052ED9DB67E5BCFA6CCC42F5A0D7F20BEDB7C0B58592A5
DF4FCBDCA3414B7551797A856048625186B2EC7B836EB35B4B080CEE4A72C39F
4127F58BDEB18D79EA8317B1858F7575CF4B648E3C53338975B4A093FA9730C0
294659EBD39D7CC01DC4E0E3B0B90A3555704E736D3BE4485BAAACBC58A84652CF3A7DA3C271E3198C72561332F2A141
9E2CC77756BE7AB3D500C0B4A91271C0A4DED5BCB78484217EA922B7878AA8F5
BF13D9949C783CF6B2F0E489A6912E56DDD9183D651D7F36FD0342981596A85C
8441C62006E1334FC31F53DAFF5281260C463AF3E92B1E797CB67882C49566846825606804C14C49FFD440F4E05CE692
BE7E62E9CFA1C703CCB971F2B0C6C0F339C78A951CA8DB287B40C3BA76EA7179E8B62C29EAC8293FD218CF981BB84BEF
DA53C52101FAC8FD8F9545768CF1DB59F3B31C9249A2FC64B66DB259C721ABE1
C9842AD0A8A8E94FCE94F46BDE89DAA8D11C41F9C83A7F6394D595028829AB92
904A94542BCD85F72D470640A220FD28EBC337C0673C189C96BFB8CE373B4F84
EEEE187B03FE77B955F22214707017DB8A60B2E3979D5C2F6BED61D0623D4D50
CEF91BE6EBD8F331E2422B6B948053E8DA143F3DD907C922E0328D49B0ADA8A6
A6F0F8A4F03B45062CEA86B291E80EE15906C0B226ABDB77E222EB95B026952D
62280870E48A2E8B8A18AD5DFF0089E927BEACE1F81A8BB1A8A2BE8EB0E92BFD
C9A3DE8165D47D1D41715F00192313755226C1B0A3D04BCD7A121B1CB4999FBD
3CAEEB62FCF601F34D3320E3EACE9EFC5D627BF69FEE965F8B84A258A765B6FE
8D83CC36514CE5CC46B181AE28089BE5BC99CE3096C569751B4E07A7D956AFA3
0F81DDB18F60E238C7FF751E70431AA5328EFDBBDFF03D5F360A524AA968CEE9
1F1E498A279E9BA15CB6BB836E90FEE522F2BE16572A4D057DF9C2B104487458
68C60FF95056BE4D814CE9B8A4175625DB3E365712C2D3E42CEEBA2E0977CDB9
D95FB21943FCAD5A21F157E629314986D92F568FD3067B65911135E6335FB7E8
17908EF142C4B6740CBE7DCA43DA3C23C7912739299786473A994E5752E7E9459B23653EE0D7775FCECB7B7608CB0495
6D17B6BA17DBFFAA4E90953CE6A73AB967076B8FBC14A9361D93A01C0850CC38
8723740BCC0A5CCEE52B6EF73DD441672FB6728965CC588044C78D495AB0675F
CA548FA44A444C8F45490A11DBC8FB24E6DB38F910EC60520A3890C8B45664FE
591356440344AAFEC21FAA0C85B6A8F354D45074932E37E0972F851E08937469
DE3A54CAAC8014625EE502F547A93754AFAD0A7EB6028599D03CCB0473BC8D5C
B2C2F6F971034E1591AD374793D6D17A595D6544DF5A9585780C6B2E3505BCFF
54447BE6C626D1CA37FD799B76B35ED266D12757B5DA1AB9277F671BBF7F07B461D0CE26593F1372354979E836972F85
45FBD88AA7C26B967BC3638F6083A6B83AA82D5B974B37DF1C3F52839DDA020C
33B9890FBE46FDB7AEE404B71C893DC20059F96224CF48F284A66D3A8D91918E
CCEA5BC148BC84DB4825320A2B8D39A30BAB4641FFEE33BD4B8700339F15892D
4BC4E0D1263E9B02DA401C884923778D1A6FACACFFE7F660381ECD64CCA5CCD2
0284EA911FB1B37F623F92B1662E10D79AEBD0009C107A9C554D417F7553B28E
FE48F26C44FA4C3EB3B2F3497FE99AC30A0A7BF9FF261740E177D7A2A5BD7880
1EA96FEBB62543A8731D19BBDD1C7FE323CADBAB7242E5A8F4B1D706964B4C32
4AB7EEF02FD59EA5D16837A50282A6254B93A34F31FE9335DA9FABEF76EA714591029C64967506B99860358E5CBF4EDA
A0F25C5387FE9B871E246F33FE64396A5DC0A9BC9AD9DF9E219F3482ADD6497E
0130F99FA395F4364491E6718B53E9D6983B68E29A70035B158CA7629C31C33E
3CDAEDA88534C2E31D1235C99DEC466221C89F63E1F8F59C9CE224573E39E2D4
F5ED2863D8B51DA620484CDE23D590F4A208DA6D155E645FCD6BCF5FEB39EE551EAE9C0366F7FFD4CBF1DCA063D154E1
IV: 41 72 65 20 79 6F 75 20 61 20 46 75 72 72 79 3F
8B441920A9F30EA40001F37E0F3C0D72161467678511928D219A7DBC42F8D9B7
1ADE5B8541491C46674EECC05A1C4297CB28259954FD7C6DA0EAADE8D57773FC
0497A50135FA4468B49694974DAADEF2A9CC2B7BAFC8465E0AA58E940C085850
4BC77520AE09B4F6A5A5365B6B9C16CA53566E096159A98EF0AB6E7FE5C2DD1C
B674AC1674312E74471E44917F6FC049DAB48BBB65B84F14A4CD64223A49E93DC0C507B8E17BFFDCBB67B55F1B4091C6
FBBE4E4F703A9C1F17268F73EC00A3F76517A4470783363102D2B7647F0F2E7F
21BE8A51F32CE62DA6B5E207E627D224639877860C71933C4F54AC7BD742B265
74E3EA89CC7AA99855C1BC87734506413B882CF36D68C3329022415EB29D1360
567937E84052F230610B3A2FC26CA1BE32B9617F7554EF5E6E7CB35A76718ADA
4C34F7FE5D6EAE40B0EB6BAB7DE4F0D059C32E4F312F9C62F2C50C54C5486276
74C8656F8EA033C60F3183FA0923C9AF1EB6689FAACC39E6548ECE16E3312D39DCF45AC6EC70A70421FBFFA43D91E19E
275903678A81B6E62CD2BB4C50E93CB3E4B092E2894EBAA04AC4E0244E4D5BA9FCDFC6BCF845EA41DF0691BF2AEDF300
BFE52324D666ADEB3D33D94331376B33A3D31566331DE0F372548FE7255F8085
8E1B2E82B4C78360B3174741FB8031EE0DFEB479859BE8708F8AF40C5228BFDF
6014A4A9D9703DAC11DA6B93FB7A0E0E0856E9379148F3CC125D77BA4C3D4931
B8C22EA72B35E60A7A3DD02956D2375EE7C07E243F17F413CA4AC3A1445AA250
B545037B8798370A8638B7ADCBE9EEF748F73C89EB5E04B460057BAFA52B1D7DF29B009FBB3FA07CE87247D185BE4926
09AEA3223E4FFB06333425BA977403E7C2F9B5F121FDA8313E73FE98D0041425
E7A97F65883E4D3CDA02483738219E219EED0681C2BB140EF3E5D02230433D42
4AE67B9EA288183047A9498F58978E7C41BB8905533F42FF5B94E41AFEFF0EB4907A8C472B9E32F6D659CFA6C391179B
1F9752FBA7A7A00D518D91BA8A8C1ADEF2EDF6282A5AFB2E4332B4351CF67F18317D2BCFF2DA6B5216EA138A4CCBDB81
EDC508FE0D0E894B529C5E4AB82A7188072592BE9D4D9A3D2485822A9F4C5A67
780582645A71D3A9841B0E8F5E84A2285F783872102AA1A98A956B98AEA19421
37E2858B90868BCAA6B3198C3B205DC1413A9D378AF1671BEA3B8F47FCE1C5CE
229719C5AFE1E567B8BD5F07EFF89C30B11CB79C9C841FFE7B53404CA5422EDB
CDA16E59B8C24DBE95ABF978CAD4D04A4F124DED1965124F92AACA4C5AEB8721
5C61D5C655DD9EB78C4F8E965101F98D7899155D2379EF6553FA9DEA0302A232
7D3DCFDE942398244624C7ABFE08363404BA688EDA39D45A05BB6FB982BB9042
ECCB10BCB2A8CF2093C61634E9AFEE9B69EB4A7C8B7139061730B5FA869F65BF
7AE6C19ED3C97F45D1167FC9EF52CCE321EA002D31D8AEA94106A2F711626551
793A984F6EBD35253C319FAB671348A4C6843AEA7CCCD5A52ACA9BBE96484B5E
BB3ADBB5FD60F0FB01E5A8B1610D30A24975DC67ED1B70472E509218E213393E
BB971C6304723B9928F50FA2E5C30A48ED5527556EE1BA5A7EA75AB7A4ED4137
489579673025F7A351072EB8D5C7FC1DBF651AA6233FB01D99DAC4BDC0A60F2F
ACA000B78B091A9B2621A9FA1A50FA6A3B63DDDF7D966224837028F93D570C08
C1EB4EA179EC0437D5B0E72C47AAD06803F7619C53D3D2FEF38DD3C068118766B73202B75C534C6249312245218C9285
639C6F53600C0F01410361164FEF715DB8E08C68D68B8AE76CF2D09A0C6C4CA1
F5F2D77DD3AF60489312055EBA3B511F7D9E312F02465639FFF3E71A862BB9EB
3EC1F7B2C43646249C4D14B4B1B85B3416B8D3B0B8DA9E87BD6199DC27BD45C2
AA24DB7345317FE980C917909F364EAA13591A664E0893271E9DBCC250782EA5
32C18DBA479AD57BFF9FE7B7BD1022D4969D8E2EC99BC0799148809796E227D5
494B44697DACDFDBBFEB0FDBEF6E9B5D7291B6CB43B4C93088F3ED8632AF23B5
B79CC1A90C7AC36DA2F318BF69E6BB1FAC32C178453663069C0CF2C4AE77B211
A059D006EF98446BDF9E1F5E09641A641CA88348E79499D79BCFDE6646C716A0BE2253421858D327E796EB5237B6E2C4
9E90AE6138A3676E3E5058FF277331032CD6BBF114768104A33D684B0825C5A5
7477B55332666FC6B1279F5FDF84DCA01176498984809B74E17AB726F888000F
6A0300B90BC11127A031E62537468A1CA7A0775BE85ED12069074E26181FBA50
4DAF986F9A850EB18F0FE3B88B9796D80EEC3984C92F4F8B32D513A176CCAA9A
EB84517DCAA7D10A6E7C4D0A7995AE278AAF3FDE52DAE30C7FD3FB853C799369
0941FB8965604ABC852B94F29396783783632E4C80AEE665E42C233B6E7AA7D0
71FEF69734589BE3C0893A1584FC1C0A75A5D4BF88CFF323C8C68E0EEC06993C
790A26B77912EE07BABCDF478D8E492422B73465DC209E5DBC8E31F43AA2DA7448EAB6312AC1DC4FE3F20D7A2EC93968
CE0AA966F33B7AC9E9982D2241524F2FC7613DAAC6C5C768AAAE29A630B414CE
93FA632D945E18DE6358D4F443CB6F023C640407B7FAD6E8AF6EF15139B044E3
059ABA7A866A865159D4E0B3E30FA1900BAB2BAB82A1D1F9D74CAEC11FA95393
9C5A4CF1D49E0F741577BAB868575739AEBBDC15D7178C87A46EA3B3E7E856EFD815AD5F998778E8FBAA2832F387B967

View File

@@ -1,6 +1,7 @@
#include "../subghz_i.h"
#define TAG "SubGhzDecodeRaw"
#define SAMPLES_TO_READ_PER_TICK 400
static void subghz_scene_receiver_update_statusbar(void* context) {
@@ -207,8 +208,6 @@ bool subghz_scene_decode_raw_on_event(void* context, SceneManagerEvent event) {
subghz_txrx_set_rx_callback(subghz->txrx, NULL, subghz);
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
if(subghz_file_encoder_worker_is_running(subghz->decode_raw_file_worker_encoder)) {
subghz_file_encoder_worker_stop(subghz->decode_raw_file_worker_encoder);
}

View File

@@ -294,7 +294,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
}
} else if(event.type == SceneManagerEventTypeTick) {
if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) {
subghz_txrx_hopper_update(subghz->txrx);
subghz_txrx_hopper_update(subghz->txrx, subghz->last_settings->hopping_threshold);
subghz_scene_receiver_update_statusbar(subghz);
}

View File

@@ -49,6 +49,37 @@ const float raw_threshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = {
-40.0f,
};
#define HOPPING_MODE_COUNT 12
const char* const hopping_mode_text[HOPPING_MODE_COUNT] = {
"OFF",
"-90dBm",
"-85dBm",
"-80dBm",
"-75dBm",
"-70dBm",
"-65dBm",
"-60dBm",
"-55dBm",
"-50dBm",
"-45dBm",
"-40dBm",
};
const float hopping_mode_value[HOPPING_MODE_COUNT] = {
NAN,
-90.0f,
-85.0f,
-80.0f,
-75.0f,
-70.0f,
-65.0f,
-60.0f,
-55.0f,
-50.0f,
-45.0f,
-40.0f,
};
#define COMBO_BOX_COUNT 2
const uint32_t hopping_value[COMBO_BOX_COUNT] = {
@@ -121,18 +152,19 @@ uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void*
return index;
}
SubGhzHopperState subghz_scene_receiver_config_hopper_value_index(void* context) {
uint8_t subghz_scene_receiver_config_hopper_value_index(void* context) {
furi_assert(context);
SubGhz* subghz = context;
if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) {
return SubGhzHopperStateOFF;
return 0;
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig),
variable_item_list_get(subghz->variable_item_list, SubGhzSettingIndexFrequency),
" -----");
return SubGhzHopperStateRunning;
return value_index_float(
subghz->last_settings->hopping_threshold, hopping_mode_value, HOPPING_MODE_COUNT);
;
}
}
@@ -188,16 +220,16 @@ static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
subghz->last_settings->preset_index = index;
}
static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) {
static void subghz_scene_receiver_config_set_hopping(VariableItem* item) {
SubGhz* subghz = variable_item_get_context(item);
SubGhzHopperState index = variable_item_get_current_value_index(item);
uint8_t index = variable_item_get_current_value_index(item);
SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
VariableItem* frequency_item = (VariableItem*)scene_manager_get_scene_state(
subghz->scene_manager, SubGhzSceneReceiverConfig);
VariableItem* frequency_item =
variable_item_list_get(subghz->variable_item_list, SubGhzSettingIndexFrequency);
variable_item_set_current_value_text(item, combobox_text[(uint8_t)index]);
variable_item_set_current_value_text(item, hopping_mode_text[index]);
if(index == SubGhzHopperStateOFF) {
if(index == 0) {
char text_buf[10] = {0};
uint32_t frequency = subghz_setting_get_default_frequency(setting);
SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
@@ -219,13 +251,18 @@ static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item)
preset.data_size);
variable_item_set_current_value_index(
frequency_item, subghz_setting_get_frequency_default_index(setting));
variable_item_set_item_label(item, "Hopping");
} else {
variable_item_set_current_value_text(frequency_item, " -----");
variable_item_set_current_value_index(
frequency_item, subghz_setting_get_frequency_default_index(setting));
variable_item_set_item_label(item, "Hopping RSSI");
}
subghz->last_settings->enable_hopping = index != SubGhzHopperStateOFF;
subghz_txrx_hopper_set_state(subghz->txrx, index);
subghz->last_settings->enable_hopping = index != 0;
subghz->last_settings->hopping_threshold = hopping_mode_value[index];
subghz_txrx_hopper_set_state(
subghz->txrx, index != 0 ? SubGhzHopperStateRunning : SubGhzHopperStateOFF);
}
static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
@@ -380,16 +417,16 @@ void subghz_scene_receiver_config_on_enter(void* context) {
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
SubGhzCustomEventManagerSet) {
// Hopping
value_index = subghz_scene_receiver_config_hopper_value_index(subghz);
item = variable_item_list_add(
subghz->variable_item_list,
"Hopping",
COMBO_BOX_COUNT,
subghz_scene_receiver_config_set_hopping_running,
value_index ? "Hopping RSSI" : "Hopping",
HOPPING_MODE_COUNT,
subghz_scene_receiver_config_set_hopping,
subghz);
value_index = subghz_scene_receiver_config_hopper_value_index(subghz);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, combobox_text[value_index]);
variable_item_set_current_value_text(item, hopping_mode_text[value_index]);
}
if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=

View File

@@ -175,7 +175,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
}
} else if(event.type == SceneManagerEventTypeTick) {
if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) {
subghz_txrx_hopper_update(subghz->txrx);
subghz_txrx_hopper_update(subghz->txrx, subghz->last_settings->hopping_threshold);
}
switch(subghz->state_notifications) {
case SubGhzNotificationStateTx:

View File

@@ -50,6 +50,8 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event)
subghz_file_encoder_worker_free(subghz->decode_raw_file_worker_encoder);
subghz->state_notifications = SubGhzNotificationStateIDLE;
subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
if(!scene_manager_search_and_switch_to_previous_scene(

View File

@@ -30,6 +30,8 @@ static const char* submenu_names[SetTypeMAX] = {
[SetTypeCenturion433] = "KL: Centurion 433MHz",
[SetTypeSommer_FM_434] = "KL: Sommer 434MHz",
[SetTypeSommer_FM_868] = "KL: Sommer 868MHz",
[SetTypeSommer_FM238_434] = "KL: Sommer fm2 434Mhz",
[SetTypeSommer_FM238_868] = "KL: Sommer fm2 868Mhz",
[SetTypeStilmatic] = "KL: Stilmatic 433MHz",
[SetTypeIronLogic] = "KL: IronLogic 433MHz",
[SetTypeDeaMio433] = "KL: DEA Mio 433MHz",
@@ -40,10 +42,12 @@ static const char* submenu_names[SetTypeMAX] = {
[SetTypeElmesElectronic] = "KL: Elmes (PL) 433MHz",
[SetTypeNormstahl_433_92] = "KL: Normstahl 433MHz",
[SetTypeJCM_433_92] = "KL: JCM Tech 433MHz",
[SetTypeNovoferm_433_92] = "KL: Novoferm 433MHz",
[SetTypeHormannEcoStar_433_92] = "KL: Hor. EcoStar 433MHz",
[SetTypeFAACRCXT_433_92] = "KL: FAAC RC,XT 433MHz",
[SetTypeFAACRCXT_868] = "KL: FAAC RC,XT 868MHz",
[SetTypeGeniusBravo433] = "KL: Genius Bravo 433MHz",
[SetTypeNiceMHouse_433_92] = "KL: Nice Mhouse 433MHz",
[SetTypeNiceMHouse_433_92] = "KL: Mhouse 433MHz",
[SetTypeNiceSmilo_433_92] = "KL: Nice Smilo 433MHz",
[SetTypeNiceFlorS_433_92] = "Nice FloR-S 433MHz",
[SetTypeNiceOne_433_92] = "Nice One 433MHz",
@@ -396,7 +400,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x000FFFFF) | 0x00600000,
.keeloq.btn = 0x04,
.keeloq.btn = 0x08,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Aprimatic"};
break;
@@ -445,7 +449,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
.type = GenKeeloq,
.mod = "FM476",
.freq = 434420000,
.keeloq.serial = (key & 0x0000FFFF) | 0x07150000,
.keeloq.serial = (key & 0x0000FFFF) | 0x01700000,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Sommer(fsk476)"};
@@ -455,7 +459,27 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
.type = GenKeeloq,
.mod = "FM476",
.freq = 868800000,
.keeloq.serial = (key & 0x0000FFFF) | 0x07150000,
.keeloq.serial = (key & 0x0000FFFF) | 0x01700000,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Sommer(fsk476)"};
break;
case SetTypeSommer_FM238_434:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "FM238",
.freq = 434420000,
.keeloq.serial = key & 0x0000FFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Sommer(fsk476)"};
break;
case SetTypeSommer_FM238_868:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "FM238",
.freq = 868800000,
.keeloq.serial = key & 0x0000FFFF,
.keeloq.btn = 0x02,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Sommer(fsk476)"};
@@ -476,7 +500,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x02,
.keeloq.btn = 0x04,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Came_Space"};
break;
@@ -581,7 +605,7 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x02,
.keeloq.btn = 0x09,
.keeloq.cnt = 0x03,
.keeloq.manuf = "NICE_MHOUSE"};
break;
@@ -615,6 +639,26 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
.keeloq.cnt = 0x03,
.keeloq.manuf = "JCM_Tech"};
break;
case SetTypeNovoferm_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x0000FFFF) | 0x018F0000,
.keeloq.btn = 0x01,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Novoferm"};
break;
case SetTypeHormannEcoStar_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = (key & 0x000FFFFF) | 0x02200000,
.keeloq.btn = 0x04,
.keeloq.cnt = 0x03,
.keeloq.manuf = "EcoStar"};
break;
case SetTypeFAACRCXT_433_92:
gen_info = (GenInfo){
.type = GenKeeloq,
@@ -640,8 +684,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
.type = GenKeeloq,
.mod = "AM650",
.freq = 433920000,
.keeloq.serial = key & 0x00FFFFFF,
.keeloq.btn = 0x02,
.keeloq.serial = key & 0x0000FFFF,
.keeloq.btn = 0x04,
.keeloq.cnt = 0x03,
.keeloq.manuf = "Normstahl"};
break;

View File

@@ -68,10 +68,6 @@ static void subghz_load_custom_presets(SubGhzSetting* setting) {
// Pagers
{"Pagers",
"02 0D 07 04 08 32 0B 06 10 64 11 93 12 0C 13 02 14 00 15 15 18 18 19 16 1B 07 1C 00 1D 91 20 FB 21 56 22 10 00 00 C0 00 00 00 00 00 00 00"},
// # HND - FM preset
{"HND_1",
"02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 36 10 69 15 32 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00"},
};
FlipperFormat* fff_temp = flipper_format_string_alloc();

View File

@@ -414,7 +414,7 @@ void subghz_unlock(SubGhz* subghz) {
bool subghz_is_locked(SubGhz* subghz) {
furi_assert(subghz);
return (subghz->lock == SubGhzLockOn);
return subghz->lock == SubGhzLockOn;
}
void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state) {

View File

@@ -17,6 +17,7 @@
#define SUBGHZ_LAST_SETTING_FIELD_FILTER "Filter"
#define SUBGHZ_LAST_SETTING_FIELD_RSSI_THRESHOLD "RSSI"
#define SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD "DelOldSignals"
#define SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD "HoppingThreshold"
SubGhzLastSettings* subghz_last_settings_alloc(void) {
SubGhzLastSettings* instance = malloc(sizeof(SubGhzLastSettings));
@@ -40,6 +41,7 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
// See bin_raw_value in scenes/subghz_scene_receiver_config.c
instance->filter = SubGhzProtocolFlag_Decodable;
instance->rssi = SUBGHZ_RAW_THRESHOLD_MIN;
instance->hopping_threshold = -90.0f;
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
@@ -114,6 +116,13 @@ void subghz_last_settings_load(SubGhzLastSettings* instance, size_t preset_count
1)) {
flipper_format_rewind(fff_data_file);
}
if(!flipper_format_read_float(
fff_data_file,
SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD,
&instance->hopping_threshold,
1)) {
flipper_format_rewind(fff_data_file);
}
} while(0);
} else {
@@ -203,6 +212,13 @@ bool subghz_last_settings_save(SubGhzLastSettings* instance) {
file, SUBGHZ_LAST_SETTING_FIELD_DELETE_OLD, &instance->delete_old_signals, 1)) {
break;
}
if(!flipper_format_write_float(
file,
SUBGHZ_LAST_SETTING_FIELD_HOPPING_THRESHOLD,
&instance->hopping_threshold,
1)) {
break;
}
saved = true;
} while(0);

View File

@@ -24,6 +24,7 @@ typedef struct {
uint32_t filter;
float rssi;
bool delete_old_signals;
float hopping_threshold;
} SubGhzLastSettings;
SubGhzLastSettings* subghz_last_settings_alloc(void);

View File

@@ -186,7 +186,7 @@ void subghz_view_receiver_add_item_to_menu(
item_menu->time = furi_string_alloc_set(time);
item_menu->item_str = furi_string_alloc_set(name);
item_menu->type = type;
if((model->idx == model->history_item - 1)) {
if(model->idx == model->history_item - 1) {
model->history_item++;
model->idx++;
subghz_view_receiver_show_time_moment(subghz_receiver);

View File

@@ -402,7 +402,8 @@ uint32_t round_int(uint32_t value, uint8_t n) {
value /= 10;
if(i >= 5) value++;
}
while(on--) value *= 10;
while(on--)
value *= 10;
return value;
}

View File

@@ -12,6 +12,7 @@
#include <mbedtls/error.h>
#define TAG "U2f"
#define WORKER_TAG TAG "Worker"
#define MCHECK(expr) furi_check((expr) == 0)
@@ -315,7 +316,7 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) {
uint8_t signature_len = u2f_der_encode_signature(resp->cert + cert_len, signature);
memcpy(resp->cert + cert_len + signature_len, state_no_error, 2);
return (sizeof(U2fRegisterResp) + cert_len + signature_len + 2);
return sizeof(U2fRegisterResp) + cert_len + signature_len + 2;
}
static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
@@ -410,7 +411,7 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
if(U2F->callback != NULL) U2F->callback(U2fNotifyAuthSuccess, U2F->context);
return (sizeof(U2fAuthResp) + signature_len + 2);
return sizeof(U2fAuthResp) + signature_len + 2;
}
uint16_t u2f_msg_parse(U2fData* U2F, uint8_t* buf, uint16_t len) {

View File

@@ -9,6 +9,7 @@
#include <storage/storage.h>
#define TAG "U2fHid"
#define WORKER_TAG TAG "Worker"
#define U2F_HID_MAX_PAYLOAD_LEN ((HID_U2F_PACKET_LEN - 7) + 128 * (HID_U2F_PACKET_LEN - 5))

View File

@@ -97,6 +97,5 @@ void u2f_view_set_ok_callback(U2fView* u2f, U2fOkCallback callback, void* contex
}
void u2f_view_set_state(U2fView* u2f, U2fViewMsg msg) {
with_view_model(
u2f->view, U2fModel * model, { model->display_msg = msg; }, true);
with_view_model(u2f->view, U2fModel * model, { model->display_msg = msg; }, true);
}

View File

@@ -79,7 +79,7 @@ size_t cli_read_timeout(Cli* cli, uint8_t* buffer, size_t size, uint32_t timeout
bool cli_is_connected(Cli* cli) {
furi_check(cli);
if(cli->session != NULL) {
return (cli->session->is_connected());
return cli->session->is_connected();
}
return false;
}

View File

@@ -65,7 +65,8 @@ void cli_command_help(Cli* cli, FuriString* args, void* context) {
CliCommandTree_it(it_left, cli->commands);
CliCommandTree_it_t it_right;
CliCommandTree_it(it_right, cli->commands);
for(size_t i = 0; i < commands_count_mid; i++) CliCommandTree_next(it_right);
for(size_t i = 0; i < commands_count_mid; i++)
CliCommandTree_next(it_right);
// Iterate throw tree
for(size_t i = 0; i < commands_count_mid; i++) {
@@ -408,8 +409,9 @@ static void cli_command_top(Cli* cli, FuriString* args, void* context) {
uint32_t uptime = tick / furi_kernel_get_tick_frequency();
printf(
"Threads: %zu, Uptime: %luh%lum%lus\r\n",
"Threads: %zu, ISR Time: %0.2f%%, Uptime: %luh%lum%lus\r\n",
furi_thread_list_size(thread_list),
(double)furi_thread_list_get_isr_time(thread_list),
uptime / 60 / 60,
uptime / 60 % 60,
uptime % 60);

View File

@@ -15,7 +15,7 @@ void crypto_cli_print_usage(void) {
printf("\thas_key <key_slot:int>\t - Check if secure enclave has key in slot\r\n");
printf(
"\tstore_key <key_slot:int> <key_type:str> <key_size:int> <key_data:hex>\t - Store key in secure enclave. !!! NON-REVERSIBLE OPERATION - READ MANUAL FIRST !!!\r\n");
};
}
void crypto_cli_encrypt(Cli* cli, FuriString* args) {
int key_slot = 0;

View File

@@ -32,11 +32,6 @@ typedef enum {
} AnimationManagerState;
struct AnimationManager {
bool sd_show_url;
bool sd_shown_no_db;
bool sd_shown_sd_ok;
bool levelup_pending;
bool levelup_active;
AnimationManagerState state;
FuriPubSubSubscription* pubsub_subscription_storage;
FuriPubSubSubscription* pubsub_subscription_dolphin;
@@ -51,7 +46,14 @@ struct AnimationManager {
FuriString* freezed_animation_name;
int32_t freezed_animation_time_left;
ViewStack* view_stack;
bool dummy_mode;
bool dummy_mode : 1;
bool blocking_shown_url : 1;
bool blocking_shown_sd_bad : 1;
bool blocking_shown_no_db : 1;
bool blocking_shown_sd_ok : 1;
bool levelup_pending : 1;
bool levelup_active : 1;
};
static StorageAnimation*
@@ -214,27 +216,31 @@ static bool animation_manager_check_blocking(AnimationManager* animation_manager
FS_Error sd_status = storage_sd_status(storage);
if(sd_status == FSE_INTERNAL) {
if(!animation_manager->blocking_shown_sd_bad) {
blocking_animation = animation_storage_find_animation(BAD_SD_ANIMATION_NAME);
furi_assert(blocking_animation);
animation_manager->blocking_shown_sd_bad = true;
}
} else if(sd_status == FSE_NOT_READY) {
animation_manager->sd_shown_sd_ok = false;
animation_manager->sd_shown_no_db = false;
animation_manager->blocking_shown_sd_bad = false;
animation_manager->blocking_shown_sd_ok = false;
animation_manager->blocking_shown_no_db = false;
} else if(sd_status == FSE_OK) {
if(!animation_manager->sd_shown_sd_ok) {
if(!animation_manager->blocking_shown_sd_ok) {
blocking_animation = animation_storage_find_animation(SD_OK_ANIMATION_NAME);
furi_assert(blocking_animation);
animation_manager->sd_shown_sd_ok = true;
} else if(!animation_manager->sd_shown_no_db) {
animation_manager->blocking_shown_sd_ok = true;
} else if(!animation_manager->blocking_shown_no_db) {
if(!storage_file_exists(storage, EXT_PATH("Manifest"))) {
blocking_animation = animation_storage_find_animation(NO_DB_ANIMATION_NAME);
furi_assert(blocking_animation);
animation_manager->sd_shown_no_db = true;
animation_manager->sd_show_url = true;
animation_manager->blocking_shown_no_db = true;
animation_manager->blocking_shown_url = true;
}
} else if(animation_manager->sd_show_url) {
} else if(animation_manager->blocking_shown_url) {
blocking_animation = animation_storage_find_animation(URL_ANIMATION_NAME);
furi_assert(blocking_animation);
animation_manager->sd_show_url = false;
animation_manager->blocking_shown_url = false;
}
}
@@ -299,7 +305,7 @@ AnimationManager* animation_manager_alloc(void) {
dolphin_get_pubsub(dolphin), animation_manager_check_blocking_callback, animation_manager);
furi_record_close(RECORD_DOLPHIN);
animation_manager->sd_shown_sd_ok = true;
animation_manager->blocking_shown_sd_ok = true;
if(!animation_manager_check_blocking(animation_manager)) {
animation_manager_start_new_idle(animation_manager);
}

Some files were not shown because too many files have changed in this diff Show More