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:
@@ -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 @@
|
||||
|
||||
129
.clang-format
129
.clang-format
@@ -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
3
.gitignore
vendored
@@ -45,9 +45,6 @@ null.d
|
||||
.sconsign.dblite
|
||||
|
||||
|
||||
# Visual Studio Code
|
||||
/.vscode
|
||||
|
||||
# bundle output
|
||||
/dist
|
||||
/artifacts-default
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -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
|
||||
|
||||
@@ -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
8
.sublime-project
vendored
@@ -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
8
.vscode/.gitignore
vendored
@@ -1,5 +1,3 @@
|
||||
/c_cpp_properties.json
|
||||
/extensions.json
|
||||
/launch.json
|
||||
/settings.json
|
||||
/tasks.json
|
||||
*
|
||||
!example/
|
||||
!ReadMe.md
|
||||
|
||||
@@ -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"
|
||||
105
CHANGELOG.md
105
CHANGELOG.md
@@ -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)
|
||||
|
||||
11
ReadMe.md
11
ReadMe.md
@@ -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)
|
||||
|
||||
17
SConstruct
17
SConstruct
@@ -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"]))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
119
applications/debug/ccid_test/client/ccid_client.py
Executable file
119
applications/debug/ccid_test/client/ccid_client.py
Executable 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()
|
||||
2
applications/debug/ccid_test/client/requirements.txt
Normal file
2
applications/debug/ccid_test/client/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
pyscard
|
||||
# or sudo apt install python3-pyscard
|
||||
@@ -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_
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
8
applications/debug/ccid_test/iso7816_response.c
Normal file
8
applications/debug/ccid_test/iso7816_response.c
Normal 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;
|
||||
}
|
||||
12
applications/debug/ccid_test/iso7816_response.h
Normal file
12
applications/debug/ccid_test/iso7816_response.h
Normal 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);
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
10
applications/debug/event_loop_blink_test/application.fam
Normal file
10
applications/debug/event_loop_blink_test/application.fam
Normal 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",
|
||||
)
|
||||
169
applications/debug/event_loop_blink_test/event_loop_blink_test.c
Normal file
169
applications/debug/event_loop_blink_test/event_loop_blink_test.c
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <toolbox/args.h>
|
||||
|
||||
#define TAG "SpeakerDebug"
|
||||
|
||||
#define CLI_COMMAND "speaker_debug"
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ typedef enum {
|
||||
typedef struct {
|
||||
MfUltralightAuthType type;
|
||||
MfUltralightAuthPassword password;
|
||||
MfUltralightC3DesAuthKey tdes_key;
|
||||
MfUltralightAuthPack pack;
|
||||
} MfUltralightAuth;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 =
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <bit_lib.h>
|
||||
|
||||
#define TAG "Microel"
|
||||
|
||||
#define KEY_LENGTH 6
|
||||
#define UID_LENGTH 4
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <bit_lib.h>
|
||||
|
||||
#define TAG "Saflok"
|
||||
|
||||
#define MAGIC_TABLE_SIZE 192
|
||||
#define KEY_LENGTH 6
|
||||
#define UID_LENGTH 4
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
31
applications/main/nfc/scenes/nfc_scene_emv_transactions.c
Normal file
31
applications/main/nfc/scenes/nfc_scene_emv_transactions.c
Normal 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);
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../subghz_i.h"
|
||||
|
||||
#define TAG "SubGhzThresholdRssi"
|
||||
|
||||
#define THRESHOLD_RSSI_LOW_COUNT 10
|
||||
|
||||
struct SubGhzThresholdRssi {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) !=
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Submodule applications/main/subghz_remote updated: 73ca3f2ac0...6ba386c09e
@@ -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) {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user