1
mirror of https://github.com/DarkFlippers/unleashed-firmware.git synced 2025-12-12 20:49:49 +04:00

Merge branch 'dev' into release

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

View File

@@ -1,5 +1,5 @@
diff --git a/applications/services/notification/notification_app.c b/applications/services/notification/notification_app.c 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 --- a/applications/services/notification/notification_app.c
+++ b/applications/services/notification/notification_app.c +++ b/applications/services/notification/notification_app.c
@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
@@ -10,7 +10,7 @@ index 9baa738..91ad7c1 100644
#define TAG "NotificationSrv" #define TAG "NotificationSrv"
@@ -589,6 +590,7 @@ int32_t notification_srv(void* p) { @@ -588,6 +589,7 @@ int32_t notification_srv(void* p) {
break; break;
case SaveSettingsMessage: case SaveSettingsMessage:
notification_save_settings(app); 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 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 --- a/applications/settings/notification_settings/notification_settings_app.c
+++ b/applications/settings/notification_settings/notification_settings_app.c +++ b/applications/settings/notification_settings/notification_settings_app.c
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
@@ -99,7 +99,7 @@ index 2a1d988..dda86f3 100644
static uint32_t notification_app_settings_exit(void* context) { static uint32_t notification_app_settings_exit(void* context) {
UNUSED(context); UNUSED(context);
return VIEW_NONE; 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_index(item, value_index);
variable_item_set_current_value_text(item, contrast_text[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); 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 diff --git a/applications/settings/notification_settings/rgb_backlight.c b/applications/settings/notification_settings/rgb_backlight.c
new file mode 100644 new file mode 100644
index 0000000..98f0d3a index 0000000..4edd775
--- /dev/null --- /dev/null
+++ b/applications/settings/notification_settings/rgb_backlight.c +++ b/applications/settings/notification_settings/rgb_backlight.c
@@ -0,0 +1,217 @@ @@ -0,0 +1,217 @@
@@ -169,9 +169,9 @@ index 0000000..98f0d3a
+#include <furi_hal.h> +#include <furi_hal.h>
+#include <storage/storage.h> +#include <storage/storage.h>
+ +
+#define RGB_BACKLIGHT_SETTINGS_VERSION 6 +#define RGB_BACKLIGHT_SETTINGS_VERSION 6
+#define RGB_BACKLIGHT_SETTINGS_FILE_NAME ".rgb_backlight.settings" +#define RGB_BACKLIGHT_SETTINGS_FILE_NAME ".rgb_backlight.settings"
+#define RGB_BACKLIGHT_SETTINGS_PATH INT_PATH(RGB_BACKLIGHT_SETTINGS_FILE_NAME) +#define RGB_BACKLIGHT_SETTINGS_PATH INT_PATH(RGB_BACKLIGHT_SETTINGS_FILE_NAME)
+ +
+#define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor)) +#define COLOR_COUNT (sizeof(colors) / sizeof(RGBBacklightColor))
+ +
@@ -263,7 +263,7 @@ index 0000000..98f0d3a
+ storage_file_free(file); + storage_file_free(file);
+ furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_STORAGE);
+ rgb_settings.settings_is_loaded = true; + rgb_settings.settings_is_loaded = true;
+}; +}
+ +
+void rgb_backlight_save_settings(void) { +void rgb_backlight_save_settings(void) {
+ RGBBacklightSettings settings; + RGBBacklightSettings settings;
@@ -294,7 +294,7 @@ index 0000000..98f0d3a
+ storage_file_close(file); + storage_file_close(file);
+ storage_file_free(file); + storage_file_free(file);
+ furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_STORAGE);
+}; +}
+ +
+RGBBacklightSettings* rgb_backlight_get_settings(void) { +RGBBacklightSettings* rgb_backlight_get_settings(void) {
+ if(!rgb_settings.settings_is_loaded) { + 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 diff --git a/applications/settings/notification_settings/rgb_backlight.h b/applications/settings/notification_settings/rgb_backlight.h
new file mode 100644 new file mode 100644
index 0000000..68dacda index 0000000..f215ed3
--- /dev/null --- /dev/null
+++ b/applications/settings/notification_settings/rgb_backlight.h +++ b/applications/settings/notification_settings/rgb_backlight.h
@@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
@@ -461,10 +461,9 @@ index 0000000..68dacda
+ * @return Указатель на строку с названием цвета + * @return Указатель на строку с названием цвета
+ */ + */
+const char* rgb_backlight_get_color_text(uint8_t index); +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 diff --git a/lib/drivers/SK6805.c b/lib/drivers/SK6805.c
new file mode 100644 new file mode 100644
index 0000000..572e1df index 0000000..b89f82a
--- /dev/null --- /dev/null
+++ b/lib/drivers/SK6805.c +++ b/lib/drivers/SK6805.c
@@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
@@ -491,14 +490,14 @@ index 0000000..572e1df
+ +
+/* Настройки */ +/* Настройки */
+#define SK6805_LED_COUNT 3 //Количество светодиодов на плате подсветки +#define SK6805_LED_COUNT 3 //Количество светодиодов на плате подсветки
+#define SK6805_LED_PIN &led_pin //Порт подключения светодиодов +#define SK6805_LED_PIN &led_pin //Порт подключения светодиодов
+ +
+#ifdef FURI_DEBUG +#ifdef FURI_DEBUG
+#define DEBUG_PIN &gpio_ext_pa7 +#define DEBUG_PIN &gpio_ext_pa7
+#define DEBUG_INIT() \ +#define DEBUG_INIT() \
+ furi_hal_gpio_init(DEBUG_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh) + furi_hal_gpio_init(DEBUG_PIN, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh)
+#define DEBUG_SET_HIGH() furi_hal_gpio_write(DEBUG_PIN, true) +#define DEBUG_SET_HIGH() furi_hal_gpio_write(DEBUG_PIN, true)
+#define DEBUG_SET_LOW() furi_hal_gpio_write(DEBUG_PIN, false) +#define DEBUG_SET_LOW() furi_hal_gpio_write(DEBUG_PIN, false)
+#else +#else
+#define DEBUG_INIT() +#define DEBUG_INIT()
+#define DEBUG_SET_HIGH() +#define DEBUG_SET_HIGH()
@@ -571,7 +570,7 @@ index 0000000..572e1df
+} +}
diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h diff --git a/lib/drivers/SK6805.h b/lib/drivers/SK6805.h
new file mode 100644 new file mode 100644
index 0000000..7c58956 index 0000000..c97054f
--- /dev/null --- /dev/null
+++ b/lib/drivers/SK6805.h +++ b/lib/drivers/SK6805.h
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
@@ -626,9 +625,8 @@ index 0000000..7c58956
+void SK6805_update(void); +void SK6805_update(void);
+ +
+#endif /* SK6805_H_ */ +#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 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 --- a/targets/f7/furi_hal/furi_hal_light.c
+++ b/targets/f7/furi_hal/furi_hal_light.c +++ b/targets/f7/furi_hal/furi_hal_light.c
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
@@ -637,7 +635,7 @@ index 83e1603..45798ca 100644
#include <stdint.h> #include <stdint.h>
+#include <applications/settings/notification_settings/rgb_backlight.h> +#include <applications/settings/notification_settings/rgb_backlight.h>
#define LED_CURRENT_RED (50u) #define LED_CURRENT_RED (50u)
#define LED_CURRENT_GREEN (50u) #define LED_CURRENT_GREEN (50u)
@@ -31,22 +32,21 @@ void furi_hal_light_init(void) { @@ -31,22 +32,21 @@ void furi_hal_light_init(void) {
} }

View File

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

3
.gitignore vendored
View File

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

3
.gitmodules vendored
View File

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

View File

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

22
.sublime-project vendored
View File

@@ -6,16 +6,20 @@
} }
], ],
"settings": { "settings": {
"LSP": { "LSP": {
"clangd": { "clangd": {
"initializationOptions": {
"clangd.compile-commands-dir": "build/latest",
"clangd.header-insertion": "never",
"clangd.query-driver": "**",
"clangd.clang-tidy": true,
},
"enabled": true, "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": "**/arm-none-eabi-*",
"clangd.clang-tidy": true,
},
}, },
}, },
}, },
} }

8
.vscode/.gitignore vendored
View File

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

View File

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

View File

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

View File

@@ -79,6 +79,7 @@
- Infrared -> External IR modules support (with autodetect by OFW) - Infrared -> External IR modules support (with autodetect by OFW)
- **NFC/RFID/iButton** - **NFC/RFID/iButton**
* LFRFID and iButton Fuzzer plugins * LFRFID and iButton Fuzzer plugins
* Add DEZ 8 display form for EM4100 (by @korden32)
* Extra Mifare Classic keys in system dict * Extra Mifare Classic keys in system dict
* EMV Protocol + Public data parser (by @Leptopt1los and @wosk) * EMV Protocol + Public data parser (by @Leptopt1los and @wosk)
* NFC `Add manually` -> Mifare Classic with custom UID * 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) 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) - Nero Radio 57bit (+ 56bit support)
- CAME 12bit/24bit encoder fixes (Fixes are now merged in OFW) - 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) - 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) - 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) - Keeloq: BFT Mitto -> Update! Check out new [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)
- Star Line - Star Line
- Security+ v1 & v2 (encoders was made in OFW) - Security+ v1 & v2
Encoders made by @assasinfil and @xMasterX: 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) - Somfy Telis -> How to create new remote - [instructions](https://github.com/DarkFlippers/unleashed-firmware/blob/dev/documentation/SubGHzRemoteProg.md)

View File

@@ -43,10 +43,10 @@ distenv = coreenv.Clone(
"blackmagic", "blackmagic",
"jflash", "jflash",
"doxygen", "doxygen",
"textfile",
], ],
ENV=os.environ, ENV=os.environ,
UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}", UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}",
VSCODE_LANG_SERVER=ARGUMENTS.get("LANG_SERVER", "cpptools"),
) )
firmware_env = distenv.AddFwProject( firmware_env = distenv.AddFwProject(
@@ -403,14 +403,23 @@ distenv.PhonyTarget(
) )
# Prepare vscode environment # Prepare vscode environment
VSCODE_LANG_SERVER = cmd_environment["LANG_SERVER"]
vscode_dist = distenv.Install( vscode_dist = distenv.Install(
"#.vscode", "#.vscode",
[ [
distenv.Glob("#.vscode/example/*.json"), distenv.Glob("#.vscode/example/*.json", exclude="*.tmpl"),
distenv.Glob(f"#.vscode/example/{VSCODE_LANG_SERVER}/*.json"), 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.Precious(vscode_dist)
distenv.NoClean(vscode_dist) distenv.NoClean(vscode_dist)
distenv.Alias("vscode_dist", (vscode_dist, firmware_env["FW_CDB"])) distenv.Alias("vscode_dist", (vscode_dist, firmware_env["FW_CDB"]))

View File

@@ -3,7 +3,7 @@
#include <gui/elements.h> #include <gui/elements.h>
#include <assets_icons.h> #include <assets_icons.h>
#define LOW_CHARGE_THRESHOLD 10 #define LOW_CHARGE_THRESHOLD 10
#define HIGH_DRAIN_CURRENT_THRESHOLD 100 #define HIGH_DRAIN_CURRENT_THRESHOLD 100
struct BatteryInfo { struct BatteryInfo {
@@ -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_draw_box(canvas, x - 4, y + 16, 24, 6);
canvas_set_color(canvas, ColorBlack); canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val); canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val);
}; }
static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
char emote[20] = {}; 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 + 3, AlignCenter, AlignCenter, emote);
canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header); canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header);
canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value); canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value);
}; }
static void battery_info_draw_callback(Canvas* canvas, void* context) { static void battery_info_draw_callback(Canvas* canvas, void* context) {
furi_assert(context); furi_assert(context);

View File

@@ -39,7 +39,7 @@ typedef struct {
} BtTestModel; } BtTestModel;
#define BT_TEST_START_MESSAGE "Ok - Start" #define BT_TEST_START_MESSAGE "Ok - Start"
#define BT_TEST_STOP_MESSAGE "Ok - Stop" #define BT_TEST_STOP_MESSAGE "Ok - Stop"
static void bt_test_process_up(BtTest* bt_test); static void bt_test_process_up(BtTest* bt_test);
static void bt_test_process_down(BtTest* bt_test); static void bt_test_process_down(BtTest* bt_test);
@@ -384,8 +384,7 @@ BtTestParam* bt_test_param_add(
void bt_test_set_rssi(BtTest* bt_test, float rssi) { void bt_test_set_rssi(BtTest* bt_test, float rssi) {
furi_assert(bt_test); furi_assert(bt_test);
with_view_model( with_view_model(bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
} }
void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) { void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) {

View File

@@ -9,6 +9,7 @@
#include "iso7816_callbacks.h" #include "iso7816_callbacks.h"
#include "iso7816_t0_apdu.h" #include "iso7816_t0_apdu.h"
#include "iso7816_atr.h" #include "iso7816_atr.h"
#include "iso7816_response.h"
typedef enum { typedef enum {
EventTypeInput, EventTypeInput,
@@ -118,6 +119,80 @@ static const CcidCallbacks ccid_cb = {
ccid_xfr_datablock_callback, 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) { void iso7816_answer_to_reset(Iso7816Atr* atr) {
//minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00 //minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00
atr->TS = 0x3B; atr->TS = 0x3B;
@@ -125,48 +200,38 @@ void iso7816_answer_to_reset(Iso7816Atr* atr) {
} }
void iso7816_process_command( void iso7816_process_command(
const struct ISO7816_Command_APDU* commandAPDU, const ISO7816_Command_APDU* commandAPDU,
struct ISO7816_Response_APDU* responseAPDU, ISO7816_Response_APDU* responseAPDU) {
const uint8_t* commandApduDataBuffer,
uint8_t commandApduDataBufferLen,
uint8_t* responseApduDataBuffer,
uint8_t* responseApduDataBufferLen) {
//example 1: sends a command with no body, receives a response with no body //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 //receives SW1=0x90, SW2=0x00
if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x01) {
responseAPDU->SW1 = 0x90;
responseAPDU->SW2 = 0x00;
}
//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; if(commandAPDU->CLA == 0x01) {
switch(commandAPDU->INS) {
responseAPDU->SW1 = 0x90; case 0x01:
responseAPDU->SW2 = 0x00; handle_instruction_01(responseAPDU);
} break;
//example 3: ends a command with a body with two bytes, receives a response with a body with two bytes case 0x02:
//sends APDU 0x01:0x03:0x00:0x00:0x02:CA:FE handle_instruction_02(
//receives (0xCA, 0xFE) SW1=0x90, SW2=0x02 commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, commandAPDU->Le, responseAPDU);
else if( break;
commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x03 && commandApduDataBufferLen == 2 && case 0x03:
commandAPDU->Lc == 2) { handle_instruction_03(commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, responseAPDU);
//echo command body to response body break;
responseApduDataBuffer[0] = commandApduDataBuffer[0]; case 0x04:
responseApduDataBuffer[1] = commandApduDataBuffer[1]; handle_instruction_04(
commandAPDU->P1,
*responseApduDataBufferLen = 2; commandAPDU->P2,
commandAPDU->Lc,
responseAPDU->SW1 = 0x90; commandAPDU->Le,
responseAPDU->SW2 = 0x00; commandAPDU->Data,
responseAPDU);
break;
default:
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED);
}
} else { } else {
responseAPDU->SW1 = 0x6A; iso7816_set_response(responseAPDU, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED);
responseAPDU->SW2 = 0x00;
} }
} }
@@ -188,8 +253,10 @@ int32_t ccid_test_app(void* p) {
FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config();
furi_hal_usb_unlock(); 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_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); iso7816_set_callbacks((Iso7816Callbacks*)&iso87816_cb);
@@ -210,8 +277,8 @@ int32_t ccid_test_app(void* p) {
} }
//tear down USB //tear down USB
furi_hal_usb_ccid_set_callbacks(NULL, NULL);
furi_hal_usb_set_config(usb_mode_prev, NULL); furi_hal_usb_set_config(usb_mode_prev, NULL);
furi_hal_ccid_set_callbacks(NULL, NULL);
iso7816_set_callbacks(NULL); iso7816_set_callbacks(NULL);

View File

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

View File

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

View File

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

View File

@@ -1,17 +1,21 @@
// transforms low level calls such as XFRCallback or ICC Power on to a structured one // 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 // 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_t0_apdu.h"
#include "iso7816_atr.h" #include "iso7816_atr.h"
#include "iso7816_callbacks.h" #include "iso7816_callbacks.h"
#include <stdint.h> #include "iso7816_response.h"
#include <stddef.h>
#include <furi.h>
#define ISO7816_RESPONSE_BUFFER_SIZE 255
static Iso7816Callbacks* callbacks = NULL; 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) { void iso7816_set_callbacks(Iso7816Callbacks* cb) {
callbacks = cb; callbacks = cb;
} }
@@ -36,41 +40,26 @@ void iso7816_xfr_datablock_callback(
uint32_t pcToReaderDataBlockLen, uint32_t pcToReaderDataBlockLen,
uint8_t* readerToPcDataBlock, uint8_t* readerToPcDataBlock,
uint32_t* readerToPcDataBlockLen) { uint32_t* readerToPcDataBlockLen) {
struct ISO7816_Response_APDU responseAPDU; ISO7816_Response_APDU* responseAPDU = (ISO7816_Response_APDU*)&responseApduBuffer;
uint8_t responseApduDataBuffer[ISO7816_RESPONSE_BUFFER_SIZE];
uint8_t responseApduDataBufferLen = 0;
if(callbacks != NULL) { if(callbacks != NULL) {
struct ISO7816_Command_APDU commandAPDU; ISO7816_Command_APDU* commandAPDU = (ISO7816_Command_APDU*)&commandApduBuffer;
const uint8_t* commandApduDataBuffer = NULL; uint8_t result =
uint8_t commandApduDataBufferLen = 0; 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) { furi_assert(responseAPDU->DataLen < CCID_SHORT_APDU_SIZE);
commandApduDataBufferLen = commandAPDU.Lc; } else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE) {
commandApduDataBuffer = &pcToReaderDataBlock[5]; 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 { } else {
//class not supported iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INTERNAL_EXCEPTION);
responseAPDU.SW1 = 0x6E;
responseAPDU.SW2 = 0x00;
} }
iso7816_write_response_apdu( iso7816_write_response_apdu(responseAPDU, readerToPcDataBlock, readerToPcDataBlockLen);
&responseAPDU,
readerToPcDataBlock,
readerToPcDataBlockLen,
responseApduDataBuffer,
responseApduDataBufferLen);
} }

View File

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

View File

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

View File

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

View File

@@ -2,37 +2,73 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <furi.h> #include <furi.h>
#include <furi_hal.h>
#include "iso7816_t0_apdu.h" #include "iso7816_t0_apdu.h"
//reads dataBuffer with dataLen size, translate it into a ISO7816_Command_APDU type //reads dataBuffer with dataLen size, translate it into a ISO7816_Command_APDU type
//extra data will be pointed to commandDataBuffer //extra data will be pointed to commandDataBuffer
void iso7816_read_command_apdu( uint8_t iso7816_read_command_apdu(
struct ISO7816_Command_APDU* command, ISO7816_Command_APDU* command,
const uint8_t* dataBuffer, const uint8_t* dataBuffer,
uint32_t dataLen) { uint32_t dataLen) {
UNUSED(dataLen);
command->CLA = dataBuffer[0]; command->CLA = dataBuffer[0];
command->INS = dataBuffer[1]; command->INS = dataBuffer[1];
command->P1 = dataBuffer[2]; command->P1 = dataBuffer[2];
command->P2 = dataBuffer[3]; command->P2 = dataBuffer[3];
command->Lc = dataBuffer[4];
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( void iso7816_write_response_apdu(
const struct ISO7816_Response_APDU* response, const ISO7816_Response_APDU* response,
uint8_t* readerToPcDataBlock, uint8_t* readerToPcDataBlock,
uint32_t* readerToPcDataBlockLen, uint32_t* readerToPcDataBlockLen) {
uint8_t* responseDataBuffer,
uint32_t responseDataLen) {
uint32_t responseDataBufferIndex = 0; uint32_t responseDataBufferIndex = 0;
//response body //response body
if(responseDataLen > 0) { if(response->DataLen > 0) {
while(responseDataBufferIndex < responseDataLen) { while(responseDataBufferIndex < response->DataLen) {
readerToPcDataBlock[responseDataBufferIndex] = readerToPcDataBlock[responseDataBufferIndex] = response->Data[responseDataBufferIndex];
responseDataBuffer[responseDataBufferIndex];
responseDataBufferIndex++; responseDataBufferIndex++;
} }
} }

View File

@@ -1,11 +1,14 @@
#ifndef _ISO7816_T0_APDU_H_ #pragma once
#define _ISO7816_T0_APDU_H_
#include <stdint.h> #include <stdint.h>
#include "iso7816_atr.h" #include "iso7816_atr.h"
#include "core/common_defines.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 //header
uint8_t CLA; uint8_t CLA;
uint8_t INS; uint8_t INS;
@@ -13,24 +16,27 @@ struct ISO7816_Command_APDU {
uint8_t P2; uint8_t P2;
//body //body
uint8_t Lc; uint16_t Lc; //data length
uint8_t Le; uint16_t Le; //maximum response data length expected by client
} FURI_PACKED;
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 SW1;
uint8_t SW2; 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_answer_to_reset(Iso7816Atr* atr);
void iso7816_read_command_apdu( uint8_t iso7816_read_command_apdu(
struct ISO7816_Command_APDU* command, ISO7816_Command_APDU* command,
const uint8_t* dataBuffer, const uint8_t* pcToReaderDataBlock,
uint32_t dataLen); uint32_t pcToReaderDataBlockLen);
void iso7816_write_response_apdu( void iso7816_write_response_apdu(
const struct ISO7816_Response_APDU* response, const ISO7816_Response_APDU* response,
uint8_t* readerToPcDataBlock, uint8_t* readerToPcDataBlock,
uint32_t* readerToPcDataBlockLen, uint32_t* readerToPcDataBlockLen);
uint8_t* responseDataBuffer,
uint32_t responseDataLen);
#endif //_ISO7816_T0_APDU_H_

View File

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

View File

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

View File

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

View File

@@ -40,11 +40,11 @@
#define TAG "ExpansionTest" #define TAG "ExpansionTest"
#define TEST_DIR_PATH EXT_PATH(TAG) #define TEST_DIR_PATH EXT_PATH(TAG)
#define TEST_FILE_NAME "test.txt" #define TEST_FILE_NAME "test.txt"
#define TEST_FILE_PATH EXT_PATH(TAG "/" TEST_FILE_NAME) #define TEST_FILE_PATH EXT_PATH(TAG "/" TEST_FILE_NAME)
#define HOST_SERIAL_ID (FuriHalSerialIdLpuart) #define HOST_SERIAL_ID (FuriHalSerialIdLpuart)
#define MODULE_SERIAL_ID (FuriHalSerialIdUsart) #define MODULE_SERIAL_ID (FuriHalSerialIdUsart)
#define RECEIVE_BUFFER_SIZE (sizeof(ExpansionFrame) + sizeof(ExpansionFrameChecksum)) #define RECEIVE_BUFFER_SIZE (sizeof(ExpansionFrame) + sizeof(ExpansionFrameChecksum))

View File

@@ -2,7 +2,7 @@
#include <furi.h> #include <furi.h>
#define DEFAULT_PATH "/" #define DEFAULT_PATH "/"
#define EXTENSION "*" #define EXTENSION "*"
bool file_browser_scene_browser_on_event(void* context, SceneManagerEvent event) { bool file_browser_scene_browser_on_event(void* context, SceneManagerEvent event) {
UNUSED(context); UNUSED(context);

View File

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

View File

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

View File

@@ -4,8 +4,8 @@
#include <furi_hal.h> #include <furi_hal.h>
#define SUBGHZ_TEST_VERSION_APP "0.1" #define SUBGHZ_TEST_VERSION_APP "0.1"
#define SUBGHZ_TEST_DEVELOPED "SkorP" #define SUBGHZ_TEST_DEVELOPED "SkorP"
#define SUBGHZ_TEST_GITHUB "https://github.com/flipperdevices/flipperzero-firmware" #define SUBGHZ_TEST_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
typedef enum { typedef enum {
SubGhzTestViewVariableItemList, SubGhzTestViewVariableItemList,

View File

@@ -16,7 +16,7 @@
(value) &= ~(_one << (bit)); \ (value) &= ~(_one << (bit)); \
}) })
#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit)) #define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit))
#define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y))) #define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View File

@@ -9,13 +9,13 @@
* *
*/ */
#define SUBGHZ_PT_SHORT 300 #define SUBGHZ_PT_SHORT 300
#define SUBGHZ_PT_LONG (SUBGHZ_PT_SHORT * 3) #define SUBGHZ_PT_LONG (SUBGHZ_PT_SHORT * 3)
#define SUBGHZ_PT_GUARD (SUBGHZ_PT_SHORT * 30) #define SUBGHZ_PT_GUARD (SUBGHZ_PT_SHORT * 30)
#define SUBGHZ_PT_COUNT_KEY_433 9 #define SUBGHZ_PT_COUNT_KEY_433 9
#define SUBGHZ_PT_TIMEOUT_433 900 #define SUBGHZ_PT_TIMEOUT_433 900
#define SUBGHZ_PT_COUNT_KEY_868 9 #define SUBGHZ_PT_COUNT_KEY_868 9
#define SUBGHZ_PT_TIMEOUT_868 14000 #define SUBGHZ_PT_TIMEOUT_868 14000
#define TAG "SubGhzProtocolPrinceton" #define TAG "SubGhzProtocolPrinceton"

View File

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

View File

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

View File

@@ -72,7 +72,7 @@ void test_runner_free(TestRunner* instance) {
free(instance); free(instance);
} }
#define TEST_RUNNER_TMP_DIR EXT_PATH(".tmp") #define TEST_RUNNER_TMP_DIR EXT_PATH(".tmp")
#define TEST_RUNNER_TMP_UNIT_TESTS_DIR TEST_RUNNER_TMP_DIR "/unit_tests" #define TEST_RUNNER_TMP_UNIT_TESTS_DIR TEST_RUNNER_TMP_DIR "/unit_tests"
static bool test_runner_run_plugin(TestRunner* instance, const char* path) { static bool test_runner_run_plugin(TestRunner* instance, const char* path) {

View File

@@ -6,7 +6,7 @@
#include <storage/storage.h> #include <storage/storage.h>
#define BT_TEST_KEY_STORAGE_FILE_PATH EXT_PATH("unit_tests/bt_test.keys") #define BT_TEST_KEY_STORAGE_FILE_PATH EXT_PATH("unit_tests/bt_test.keys")
#define BT_TEST_NVM_RAM_BUFF_SIZE (507 * 4) // The same as in ble NVM storage #define BT_TEST_NVM_RAM_BUFF_SIZE (507 * 4) // The same as in ble NVM storage
typedef struct { typedef struct {
Storage* storage; Storage* storage;

View File

@@ -1,6 +1,9 @@
#include "../test.h" // IWYU pragma: keep #include "../test.h" // IWYU pragma: keep
#include <toolbox/compress.h> #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.h>
#include <furi_hal.h> #include <furi_hal.h>
@@ -56,7 +59,7 @@ static void compress_test_reference_comp_decomp() {
furi_record_close(RECORD_STORAGE); furi_record_close(RECORD_STORAGE);
uint8_t* temp_buffer = malloc(1024); 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; size_t encoded_size = 0;
mu_assert( 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 // 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; 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* src_buff = malloc(src_buffer_size);
uint8_t* encoded_buff = malloc(encoded_buffer_size); uint8_t* encoded_buff = malloc(encoded_buffer_size);
uint8_t* decoded_buff = malloc(src_buffer_size); uint8_t* decoded_buff = malloc(src_buffer_size);
@@ -146,9 +149,200 @@ static void compress_test_random_comp_decomp() {
compress_free(comp); 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_TEST_SUITE(test_compress) {
MU_RUN_TEST(compress_test_random_comp_decomp); MU_RUN_TEST(compress_test_random_comp_decomp);
MU_RUN_TEST(compress_test_reference_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) { int run_minunit_test_compress(void) {

View File

@@ -5,8 +5,8 @@
#include <expansion/expansion_protocol.h> #include <expansion/expansion_protocol.h>
#define EXPANSION_TEST_GARBAGE_MAGIC (0xB19AF) #define EXPANSION_TEST_GARBAGE_MAGIC (0xB19AF)
#define EXPANSION_TEST_GARBAGE_BUF_SIZE (0x100U) #define EXPANSION_TEST_GARBAGE_BUF_SIZE (0x100U)
#define EXPANSION_TEST_GARBAGE_ITERATIONS (100U) #define EXPANSION_TEST_GARBAGE_ITERATIONS (100U)
MU_TEST(test_expansion_encoded_size) { MU_TEST(test_expansion_encoded_size) {

View File

@@ -5,7 +5,7 @@
#include "../test.h" // IWYU pragma: keep #include "../test.h" // IWYU pragma: keep
#define TEST_DIR_NAME EXT_PATH(".tmp/unit_tests/ff") #define TEST_DIR_NAME EXT_PATH(".tmp/unit_tests/ff")
#define TEST_DIR TEST_DIR_NAME "/" #define TEST_DIR TEST_DIR_NAME "/"
static const char* test_filetype = "Flipper File test"; static const char* test_filetype = "Flipper File test";
static const uint32_t test_version = 666; static const uint32_t test_version = 666;

View File

@@ -5,11 +5,11 @@
#include <lp5562_reg.h> #include <lp5562_reg.h>
#include "../test.h" // IWYU pragma: keep #include "../test.h" // IWYU pragma: keep
#define DATA_SIZE 4 #define DATA_SIZE 4
#define EEPROM_ADDRESS 0b10101000 #define EEPROM_ADDRESS 0b10101000
#define EEPROM_ADDRESS_HIGH (EEPROM_ADDRESS | 0b10) #define EEPROM_ADDRESS_HIGH (EEPROM_ADDRESS | 0b10)
#define EEPROM_SIZE 512 #define EEPROM_SIZE 512
#define EEPROM_PAGE_SIZE 16 #define EEPROM_PAGE_SIZE 16
#define EEPROM_WRITE_DELAY_MS 6 #define EEPROM_WRITE_DELAY_MS 6
static void furi_hal_i2c_int_setup(void) { static void furi_hal_i2c_int_setup(void) {
@@ -74,7 +74,8 @@ MU_TEST(furi_hal_i2c_int_3b) {
DATA_SIZE - 1, DATA_SIZE - 1,
LP5562_I2C_TIMEOUT); LP5562_I2C_TIMEOUT);
mu_assert(ret, "4 rx failed"); 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( ret = furi_hal_i2c_tx(
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, DATA_SIZE, LP5562_I2C_TIMEOUT); &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, DATA_SIZE - 1,
LP5562_I2C_TIMEOUT); LP5562_I2C_TIMEOUT);
mu_assert(ret, "7 rx failed"); 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) { MU_TEST(furi_hal_i2c_int_1b_fail) {

View File

@@ -4,7 +4,7 @@
#include <common/infrared_common_i.h> #include <common/infrared_common_i.h>
#include "../test.h" // IWYU pragma: keep #include "../test.h" // IWYU pragma: keep
#define IR_TEST_FILES_DIR EXT_PATH("unit_tests/infrared/") #define IR_TEST_FILES_DIR EXT_PATH("unit_tests/infrared/")
#define IR_TEST_FILE_PREFIX "test_" #define IR_TEST_FILE_PREFIX "test_"
#define IR_TEST_FILE_SUFFIX ".irtest" #define IR_TEST_FILE_SUFFIX ".irtest"

View File

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

View File

@@ -71,7 +71,7 @@ extern "C" {
/* Maximum length of last message */ /* Maximum length of last message */
#define MINUNIT_MESSAGE_LEN 1024 #define MINUNIT_MESSAGE_LEN 1024
/* Accuracy with which floats are compared */ /* Accuracy with which floats are compared */
#define MINUNIT_EPSILON 1E-12 #define MINUNIT_EPSILON 1E-12
#include "minunit_vars_ex.h" #include "minunit_vars_ex.h"
@@ -84,9 +84,9 @@ void minunit_print_fail(const char* error);
void minunit_printf_warning(const char* format, ...); void minunit_printf_warning(const char* format, ...);
/* Definitions */ /* Definitions */
#define MU_TEST(method_name) static void method_name(void) #define MU_TEST(method_name) static void method_name(void)
#define MU_TEST_1(method_name, arg_1) static void method_name(arg_1) #define MU_TEST_1(method_name, arg_1) static void method_name(arg_1)
#define MU_TEST_SUITE(suite_name) static void suite_name(void) #define MU_TEST_SUITE(suite_name) static void suite_name(void)
#define MU__SAFE_BLOCK(block) \ #define MU__SAFE_BLOCK(block) \
do { \ do { \

View File

@@ -30,7 +30,7 @@
#define TAG "NfcTest" #define TAG "NfcTest"
#define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_device_test.nfc") #define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_device_test.nfc")
#define NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_dict.nfc") #define NFC_APP_MF_CLASSIC_DICT_UNIT_TEST_PATH EXT_PATH("unit_tests/mf_dict.nfc")
#define NFC_TEST_FLAG_WORKER_DONE (1) #define NFC_TEST_FLAG_WORKER_DONE (1)
@@ -286,6 +286,10 @@ MU_TEST(mf_ultralight_21_reader) {
mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ultralight_21.nfc")); 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) { MU_TEST(ntag_215_reader) {
mf_ultralight_reader_test(EXT_PATH("unit_tests/nfc/Ntag215.nfc")); 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_215_reader);
MU_RUN_TEST(ntag_216_reader); MU_RUN_TEST(ntag_216_reader);
MU_RUN_TEST(ntag_213_locked_reader); MU_RUN_TEST(ntag_213_locked_reader);
MU_RUN_TEST(mf_ultralight_c_reader);
MU_RUN_TEST(mf_ultralight_write); MU_RUN_TEST(mf_ultralight_write);

View File

@@ -43,14 +43,15 @@ typedef struct {
static RpcSessionContext rpc_session[TEST_RPC_SESSIONS]; static RpcSessionContext rpc_session[TEST_RPC_SESSIONS];
#define TAG "UnitTestsRpc" #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
#define TEST_DIR_NAME EXT_PATH(".tmp/unit_tests/rpc")
#define TEST_DIR TEST_DIR_NAME "/"
#define MD5SUM_SIZE 16
#define PING_REQUEST 0 #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
#define TEST_DIR_NAME EXT_PATH(".tmp/unit_tests/rpc")
#define TEST_DIR TEST_DIR_NAME "/"
#define MD5SUM_SIZE 16
#define PING_REQUEST 0
#define PING_RESPONSE 1 #define PING_RESPONSE 1
#define WRITE_REQUEST 0 #define WRITE_REQUEST 0
#define READ_RESPONSE 1 #define READ_RESPONSE 1
@@ -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); time_left = MAX(time_left, 0);
bytes_received = bytes_received =
furi_stream_buffer_receive(session_context->output_stream, buf, count, time_left); furi_stream_buffer_receive(session_context->output_stream, buf, count, time_left);
return (count == bytes_received); return count == bytes_received;
} }
static void static void
@@ -971,7 +972,7 @@ MU_TEST(test_storage_info) {
} }
#define TEST_DIR_STAT_NAME TEST_DIR "stat_dir" #define TEST_DIR_STAT_NAME TEST_DIR "stat_dir"
#define TEST_DIR_STAT TEST_DIR_STAT_NAME "/" #define TEST_DIR_STAT TEST_DIR_STAT_NAME "/"
MU_TEST(test_storage_stat) { MU_TEST(test_storage_stat) {
test_create_dir(TEST_DIR_STAT_NAME); test_create_dir(TEST_DIR_STAT_NAME);
test_create_file(TEST_DIR_STAT "empty.txt", 0); test_create_file(TEST_DIR_STAT "empty.txt", 0);
@@ -1212,7 +1213,7 @@ static void test_storage_delete_run(
} }
#define TEST_DIR_RMRF_NAME TEST_DIR "rmrf_test" #define TEST_DIR_RMRF_NAME TEST_DIR "rmrf_test"
#define TEST_DIR_RMRF TEST_DIR_RMRF_NAME "/" #define TEST_DIR_RMRF TEST_DIR_RMRF_NAME "/"
MU_TEST(test_storage_delete_recursive) { MU_TEST(test_storage_delete_recursive) {
test_create_dir(TEST_DIR_RMRF_NAME); test_create_dir(TEST_DIR_RMRF_NAME);

View File

@@ -9,7 +9,7 @@
#define UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/" path) #define UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/" path)
#define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test") #define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test")
#define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX #define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX
#define STORAGE_TEST_DIR UNIT_TESTS_PATH("test_dir") #define STORAGE_TEST_DIR UNIT_TESTS_PATH("test_dir")

View File

@@ -11,13 +11,14 @@
#include <lib/subghz/devices/cc1101_configs.h> #include <lib/subghz/devices/cc1101_configs.h>
#define TAG "SubGhzTest" #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 KEYSTORE_DIR_NAME EXT_PATH("subghz/assets/keeloq_mfcodes")
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s") #define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
#define ALUTECH_AT_4N_DIR_NAME EXT_PATH("subghz/assets/alutech_at_4n") #define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub") #define ALUTECH_AT_4N_DIR_NAME EXT_PATH("subghz/assets/alutech_at_4n")
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub")
#define TEST_RANDOM_COUNT_PARSE 329 #define TEST_RANDOM_COUNT_PARSE 329
#define TEST_TIMEOUT 10000 #define TEST_TIMEOUT 10000
static SubGhzEnvironment* environment_handler; static SubGhzEnvironment* environment_handler;
static SubGhzReceiver* receiver_handler; static SubGhzReceiver* receiver_handler;

View File

@@ -2,7 +2,7 @@
#include <flipper_application/flipper_application.h> #include <flipper_application/flipper_application.h>
#define APPID "UnitTest" #define APPID "UnitTest"
#define API_VERSION (0u) #define API_VERSION (0u)
typedef struct { typedef struct {

View File

@@ -4,7 +4,7 @@
#include <input/input.h> #include <input/input.h>
#define MOUSE_MOVE_SHORT 5 #define MOUSE_MOVE_SHORT 5
#define MOUSE_MOVE_LONG 20 #define MOUSE_MOVE_LONG 20
typedef enum { typedef enum {
EventTypeInput, EventTypeInput,

View File

@@ -17,18 +17,18 @@
#define TAG "SubGhzDeviceCc1101Ext" #define TAG "SubGhzDeviceCc1101Ext"
#define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO (&gpio_ext_pb2) #define SUBGHZ_DEVICE_CC1101_EXT_TX_GPIO (&gpio_ext_pb2)
#define SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO &gpio_ext_pc3 #define SUBGHZ_DEVICE_CC1101_EXT_E07_AMP_GPIO &gpio_ext_pc3
#define SUBGHZ_DEVICE_CC1101_EXT_FORCE_DANGEROUS_RANGE false #define SUBGHZ_DEVICE_CC1101_EXT_FORCE_DANGEROUS_RANGE false
#define SUBGHZ_DEVICE_CC1101_CONFIG_VER 1 #define SUBGHZ_DEVICE_CC1101_CONFIG_VER 1
/* DMA Channels definition */ /* DMA Channels definition */
#define SUBGHZ_DEVICE_CC1101_EXT_DMA (DMA2) #define SUBGHZ_DEVICE_CC1101_EXT_DMA (DMA2)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL (LL_DMA_CHANNEL_3) #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL (LL_DMA_CHANNEL_3)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL (LL_DMA_CHANNEL_4) #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_CHANNEL (LL_DMA_CHANNEL_4)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL (LL_DMA_CHANNEL_5) #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH5_CHANNEL (LL_DMA_CHANNEL_5)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ (FuriHalInterruptIdDma2Ch3) #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_IRQ (FuriHalInterruptIdDma2Ch3)
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \ #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_DEF \
SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL SUBGHZ_DEVICE_CC1101_EXT_DMA, SUBGHZ_DEVICE_CC1101_EXT_DMA_CH3_CHANNEL
#define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \ #define SUBGHZ_DEVICE_CC1101_EXT_DMA_CH4_DEF \
@@ -390,7 +390,7 @@ bool subghz_device_cc1101_ext_is_rx_data_crc_valid(void) {
cc1101_read_reg( cc1101_read_reg(
subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data); subghz_device_cc1101_ext->spi_bus_handle, CC1101_STATUS_LQI | CC1101_BURST, data);
furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle); furi_hal_spi_release(subghz_device_cc1101_ext->spi_bus_handle);
if(((data[0] >> 7) & 0x01)) { if((data[0] >> 7) & 0x01) {
return true; return true;
} else { } else {
return false; 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) { bool subghz_device_cc1101_ext_is_async_tx_complete(void) {
return ( return (subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) &&
(subghz_device_cc1101_ext->state == SubGhzDeviceCC1101ExtStateAsyncTx) && (LL_TIM_GetAutoReload(TIM17) == 0);
(LL_TIM_GetAutoReload(TIM17) == 0));
} }
void subghz_device_cc1101_ext_stop_async_tx(void) { void subghz_device_cc1101_ext_stop_async_tx(void) {

View File

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

View File

@@ -6,7 +6,7 @@
*/ */
#pragma once #pragma once
#define PLUGIN_APP_ID "example_plugins" #define PLUGIN_APP_ID "example_plugins"
#define PLUGIN_API_VERSION 1 #define PLUGIN_API_VERSION 1
typedef struct { typedef struct {

View File

@@ -6,7 +6,7 @@
*/ */
#pragma once #pragma once
#define PLUGIN_APP_ID "example_plugins_advanced" #define PLUGIN_APP_ID "example_plugins_advanced"
#define PLUGIN_API_VERSION 1 #define PLUGIN_API_VERSION 1
typedef struct { typedef struct {

View File

@@ -25,15 +25,15 @@
#include <furi_hal_power.h> #include <furi_hal_power.h>
#define UPDATE_PERIOD_MS 1000UL #define UPDATE_PERIOD_MS 1000UL
#define TEXT_STORE_SIZE 64U #define TEXT_STORE_SIZE 64U
#define DS18B20_CMD_SKIP_ROM 0xccU #define DS18B20_CMD_SKIP_ROM 0xccU
#define DS18B20_CMD_CONVERT 0x44U #define DS18B20_CMD_CONVERT 0x44U
#define DS18B20_CMD_READ_SCRATCHPAD 0xbeU #define DS18B20_CMD_READ_SCRATCHPAD 0xbeU
#define DS18B20_CFG_RESOLUTION_POS 5U #define DS18B20_CFG_RESOLUTION_POS 5U
#define DS18B20_CFG_RESOLUTION_MASK 0x03U #define DS18B20_CFG_RESOLUTION_MASK 0x03U
#define DS18B20_DECIMAL_PART_MASK 0x0fU #define DS18B20_DECIMAL_PART_MASK 0x0fU
#define DS18B20_SIGN_MASK 0xf0U #define DS18B20_SIGN_MASK 0xf0U

View File

@@ -344,7 +344,7 @@ bool archive_is_home(ArchiveBrowserView* browser) {
} }
const char* default_path = archive_get_default_path(archive_get_tab(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) { const char* archive_get_name(ArchiveBrowserView* browser) {

View File

@@ -3,8 +3,8 @@
#include "../archive_i.h" #include "../archive_i.h"
#include <storage/storage.h> #include <storage/storage.h>
#define TAB_LEFT InputKeyLeft // Default tab switch direction #define TAB_LEFT InputKeyLeft // Default tab switch direction
#define TAB_DEFAULT ArchiveTabFavorites // Start tab #define TAB_DEFAULT ArchiveTabFavorites // Start tab
#define FILE_LIST_BUF_LEN 50 #define FILE_LIST_BUF_LEN 50
static const char* tab_default_paths[] = { static const char* tab_default_paths[] = {
@@ -67,7 +67,7 @@ static inline const char* archive_get_default_path(ArchiveTabEnum tab) {
} }
inline bool archive_is_known_app(ArchiveFileTypeEnum type) { 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); bool archive_is_item_in_array(ArchiveBrowserViewModel* model, uint32_t idx);

View File

@@ -2,7 +2,7 @@
#include <storage/storage.h> #include <storage/storage.h>
#define ARCHIVE_FAV_PATH ANY_PATH("favorites.txt") #define ARCHIVE_FAV_PATH ANY_PATH("favorites.txt")
#define ARCHIVE_FAV_TEMP_PATH ANY_PATH("favorites.tmp") #define ARCHIVE_FAV_TEMP_PATH ANY_PATH("favorites.tmp")
uint16_t archive_favorites_count(void* context); uint16_t archive_favorites_count(void* context);

View File

@@ -8,7 +8,7 @@
#define TAG "ArchiveSceneBrowser" #define TAG "ArchiveSceneBrowser"
#define SCENE_STATE_DEFAULT (0) #define SCENE_STATE_DEFAULT (0)
#define SCENE_STATE_NEED_REFRESH (1) #define SCENE_STATE_NEED_REFRESH (1)
static const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) { static const char* archive_get_flipper_app_name(ArchiveFileTypeEnum file_type) {

View File

@@ -3,7 +3,7 @@
#include "../helpers/archive_browser.h" #include "../helpers/archive_browser.h"
#define SCENE_DELETE_CUSTOM_EVENT (0UL) #define SCENE_DELETE_CUSTOM_EVENT (0UL)
#define MAX_TEXT_INPUT_LEN 22 #define MAX_TEXT_INPUT_LEN 22
void archive_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { void archive_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context); furi_assert(context);

View File

@@ -9,7 +9,7 @@
#define TAG "Archive" #define TAG "Archive"
#define SCENE_RENAME_CUSTOM_EVENT (0UL) #define SCENE_RENAME_CUSTOM_EVENT (0UL)
#define MAX_TEXT_INPUT_LEN 22 #define MAX_TEXT_INPUT_LEN 22
void archive_scene_rename_text_input_callback(void* context) { void archive_scene_rename_text_input_callback(void* context) {
ArchiveApp* archive = (ArchiveApp*)context; ArchiveApp* archive = (ArchiveApp*)context;

View File

@@ -4,9 +4,9 @@
#include "archive_browser_view.h" #include "archive_browser_view.h"
#include "../helpers/archive_browser.h" #include "../helpers/archive_browser.h"
#define TAG "Archive" #define TAG "Archive"
#define SCROLL_INTERVAL (333) #define SCROLL_INTERVAL (333)
#define SCROLL_DELAY (2) #define SCROLL_DELAY (2)
static const char* ArchiveTabNames[] = { static const char* ArchiveTabNames[] = {
[ArchiveTabFavorites] = "Favorites", [ArchiveTabFavorites] = "Favorites",

View File

@@ -14,15 +14,15 @@
#include "../helpers/archive_favorites.h" #include "../helpers/archive_favorites.h"
#include "gui/modules/file_browser_worker.h" #include "gui/modules/file_browser_worker.h"
#define MAX_LEN_PX 110 #define MAX_LEN_PX 110
#define MAX_NAME_LEN 255 #define MAX_NAME_LEN 255
#define MAX_EXT_LEN 6 #define MAX_EXT_LEN 6
#define FRAME_HEIGHT 12 #define FRAME_HEIGHT 12
#define MENU_ITEMS 5u #define MENU_ITEMS 5u
#define MOVE_OFFSET 5u #define MOVE_OFFSET 5u
#define CLIPBOARD_MODE_OFF (0U) #define CLIPBOARD_MODE_OFF (0U)
#define CLIPBOARD_MODE_CUT (1U) #define CLIPBOARD_MODE_CUT (1U)
#define CLIPBOARD_MODE_COPY (2U) #define CLIPBOARD_MODE_COPY (2U)
typedef enum { typedef enum {

View File

@@ -5,9 +5,9 @@
#include <lib/toolbox/path.h> #include <lib/toolbox/path.h>
#include <flipper_format/flipper_format.h> #include <flipper_format/flipper_format.h>
#define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/.badusb.settings" #define BAD_USB_SETTINGS_PATH BAD_USB_APP_BASE_FOLDER "/.badusb.settings"
#define BAD_USB_SETTINGS_FILE_TYPE "Flipper BadUSB Settings File" #define BAD_USB_SETTINGS_FILE_TYPE "Flipper BadUSB Settings File"
#define BAD_USB_SETTINGS_VERSION 1 #define BAD_USB_SETTINGS_VERSION 1
#define BAD_USB_SETTINGS_DEFAULT_LAYOUT BAD_USB_APP_PATH_LAYOUT_FOLDER "/en-US.kl" #define BAD_USB_SETTINGS_DEFAULT_LAYOUT BAD_USB_APP_PATH_LAYOUT_FOLDER "/en-US.kl"
static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) { static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) {

View File

@@ -16,10 +16,10 @@
#include "views/bad_usb_view.h" #include "views/bad_usb_view.h"
#include <furi_hal_usb.h> #include <furi_hal_usb.h>
#define BAD_USB_APP_BASE_FOLDER EXT_PATH("badusb") #define BAD_USB_APP_BASE_FOLDER EXT_PATH("badusb")
#define BAD_USB_APP_PATH_LAYOUT_FOLDER BAD_USB_APP_BASE_FOLDER "/assets/layouts" #define BAD_USB_APP_PATH_LAYOUT_FOLDER BAD_USB_APP_BASE_FOLDER "/assets/layouts"
#define BAD_USB_APP_SCRIPT_EXTENSION ".txt" #define BAD_USB_APP_SCRIPT_EXTENSION ".txt"
#define BAD_USB_APP_LAYOUT_EXTENSION ".kl" #define BAD_USB_APP_LAYOUT_EXTENSION ".kl"
typedef enum { typedef enum {
BadUsbAppErrorNoFiles, BadUsbAppErrorNoFiles,

View File

@@ -9,6 +9,7 @@
#include <dolphin/dolphin.h> #include <dolphin/dolphin.h>
#define TAG "BadUsb" #define TAG "BadUsb"
#define WORKER_TAG TAG "Worker" #define WORKER_TAG TAG "Worker"
#define BADUSB_ASCII_TO_KEY(script, x) \ #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) { 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) { 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)) { 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; 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); FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_usb->st.line_cur - 1U);
return SCRIPT_STATE_ERROR; return SCRIPT_STATE_ERROR;
} else { } 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); FURI_LOG_E(WORKER_TAG, "Unknown command at line %zu", bad_usb->st.line_cur);
return SCRIPT_STATE_ERROR; return SCRIPT_STATE_ERROR;
} else { } else {
return (delay_val + bad_usb->defdelay); return delay_val + bad_usb->defdelay;
} }
} else { } else {
furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]); furi_string_push_back(bad_usb->line, bad_usb->file_buf[i]);

View File

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

View File

@@ -9,10 +9,10 @@ extern "C" {
#include "ducky_script.h" #include "ducky_script.h"
#include "bad_usb_hid.h" #include "bad_usb_hid.h"
#define SCRIPT_STATE_ERROR (-1) #define SCRIPT_STATE_ERROR (-1)
#define SCRIPT_STATE_END (-2) #define SCRIPT_STATE_END (-2)
#define SCRIPT_STATE_NEXT_LINE (-3) #define SCRIPT_STATE_NEXT_LINE (-3)
#define SCRIPT_STATE_CMD_UNKNOWN (-4) #define SCRIPT_STATE_CMD_UNKNOWN (-4)
#define SCRIPT_STATE_STRING_START (-5) #define SCRIPT_STATE_STRING_START (-5)
#define SCRIPT_STATE_WAIT_FOR_BTN (-6) #define SCRIPT_STATE_WAIT_FOR_BTN (-6)

View File

@@ -7,14 +7,14 @@
#define CLOCK_ISO_DATE_FORMAT "%.4d-%.2d-%.2d" #define CLOCK_ISO_DATE_FORMAT "%.4d-%.2d-%.2d"
#define CLOCK_RFC_DATE_FORMAT "%.2d-%.2d-%.4d" #define CLOCK_RFC_DATE_FORMAT "%.2d-%.2d-%.4d"
#define CLOCK_TIME_FORMAT "%.2d:%.2d:%.2d" #define CLOCK_TIME_FORMAT "%.2d:%.2d:%.2d"
#define MERIDIAN_FORMAT "%s" #define MERIDIAN_FORMAT "%s"
#define MERIDIAN_STRING_AM "AM" #define MERIDIAN_STRING_AM "AM"
#define MERIDIAN_STRING_PM "PM" #define MERIDIAN_STRING_PM "PM"
#define TIME_LEN 12 #define TIME_LEN 12
#define DATE_LEN 14 #define DATE_LEN 14
#define MERIDIAN_LEN 3 #define MERIDIAN_LEN 3
typedef enum { typedef enum {

View File

@@ -10,11 +10,11 @@
#include <stm32wbxx_ll_lpuart.h> #include <stm32wbxx_ll_lpuart.h>
#include <stm32wbxx_ll_usart.h> #include <stm32wbxx_ll_usart.h>
#define USB_CDC_PKT_LEN CDC_DATA_SZ #define USB_CDC_PKT_LEN CDC_DATA_SZ
#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) #define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5)
#define USB_CDC_BIT_DTR (1 << 0) #define USB_CDC_BIT_DTR (1 << 0)
#define USB_CDC_BIT_RTS (1 << 1) #define USB_CDC_BIT_RTS (1 << 1)
#define USB_USART_DE_RE_PIN &gpio_ext_pa4 #define USB_USART_DE_RE_PIN &gpio_ext_pa4
static const GpioPin* flow_pins[][2] = { static const GpioPin* flow_pins[][2] = {

View File

@@ -28,8 +28,8 @@
#include "ibutton_custom_event.h" #include "ibutton_custom_event.h"
#include "scenes/ibutton_scene.h" #include "scenes/ibutton_scene.h"
#define IBUTTON_APP_FOLDER ANY_PATH("ibutton") #define IBUTTON_APP_FOLDER ANY_PATH("ibutton")
#define IBUTTON_APP_FILENAME_PREFIX "iBtn" #define IBUTTON_APP_FILENAME_PREFIX "iBtn"
#define IBUTTON_APP_FILENAME_EXTENSION ".ibtn" #define IBUTTON_APP_FILENAME_EXTENSION ".ibtn"
#define IBUTTON_KEY_NAME_SIZE 22 #define IBUTTON_KEY_NAME_SIZE 22

View File

@@ -36,7 +36,27 @@ bool ibutton_scene_add_value_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
if(event.event == iButtonCustomEventByteEditResult) { if(event.event == iButtonCustomEventByteEditResult) {
scene_manager_next_scene(scene_manager, iButtonSceneSaveName); 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) { } else if(event.event == iButtonCustomEventByteEditChanged) {
ibutton_protocols_apply_edits(ibutton->protocols, ibutton->key); ibutton_protocols_apply_edits(ibutton->protocols, ibutton->key);
} }

View File

@@ -41,9 +41,17 @@ bool ibutton_scene_save_name_on_event(void* context, SceneManagerEvent event) {
iButton* ibutton = context; iButton* ibutton = context;
bool consumed = false; bool consumed = false;
const bool is_new_file = furi_string_empty(ibutton->file_path);
if(event.type == SceneManagerEventTypeCustom) { if(event.type == SceneManagerEventTypeCustom) {
consumed = true; consumed = true;
if(event.event == iButtonCustomEventTextEditResult) { 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( furi_string_printf(
ibutton->file_path, ibutton->file_path,
"%s/%s%s", "%s/%s%s",

View File

@@ -6,6 +6,7 @@ enum SubmenuIndex {
SubmenuIndexWriteBlank, SubmenuIndexWriteBlank,
SubmenuIndexWriteCopy, SubmenuIndexWriteCopy,
SubmenuIndexEdit, SubmenuIndexEdit,
SubmenuIndexRename,
SubmenuIndexDelete, SubmenuIndexDelete,
SubmenuIndexInfo, 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, "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, "Delete", SubmenuIndexDelete, ibutton_submenu_callback, ibutton);
submenu_add_item(submenu, "Info", SubmenuIndexInfo, 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); scene_manager_next_scene(scene_manager, iButtonSceneWrite);
} else if(event.event == SubmenuIndexEdit) { } else if(event.event == SubmenuIndexEdit) {
scene_manager_next_scene(scene_manager, iButtonSceneAddValue); scene_manager_next_scene(scene_manager, iButtonSceneAddValue);
} else if(event.event == SubmenuIndexRename) {
scene_manager_next_scene(scene_manager, iButtonSceneSaveName);
} else if(event.event == SubmenuIndexDelete) { } else if(event.event == SubmenuIndexDelete) {
scene_manager_next_scene(scene_manager, iButtonSceneDeleteConfirm); scene_manager_next_scene(scene_manager, iButtonSceneDeleteConfirm);
} else if(event.event == SubmenuIndexInfo) { } else if(event.event == SubmenuIndexInfo) {

View File

@@ -10,7 +10,7 @@
#define TAG "InfraredApp" #define TAG "InfraredApp"
#define INFRARED_TX_MIN_INTERVAL_MS (50U) #define INFRARED_TX_MIN_INTERVAL_MS (50U)
#define INFRARED_TASK_STACK_SIZE (2048UL) #define INFRARED_TASK_STACK_SIZE (2048UL)
static const NotificationSequence* static const NotificationSequence*
infrared_notification_sequences[InfraredNotificationMessageCount] = { infrared_notification_sequences[InfraredNotificationMessageCount] = {

View File

@@ -17,9 +17,9 @@ typedef struct InfraredApp InfraredApp;
#include <storage/storage.h> #include <storage/storage.h>
#include <furi_hal_infrared.h> #include <furi_hal_infrared.h>
#define INFRARED_SETTINGS_PATH EXT_PATH("infrared/.infrared.settings") #define INFRARED_SETTINGS_PATH EXT_PATH("infrared/.infrared.settings")
#define INFRARED_SETTINGS_VERSION (1) #define INFRARED_SETTINGS_VERSION (1)
#define INFRARED_SETTINGS_MAGIC (0x1F) #define INFRARED_SETTINGS_MAGIC (0x1F)
typedef struct { typedef struct {
FuriHalInfraredTxPin tx_pin; FuriHalInfraredTxPin tx_pin;

View File

@@ -39,18 +39,18 @@
#include "views/infrared_debug_view.h" #include "views/infrared_debug_view.h"
#include "views/infrared_move_view.h" #include "views/infrared_move_view.h"
#define INFRARED_FILE_NAME_SIZE 100 #define INFRARED_FILE_NAME_SIZE 100
#define INFRARED_TEXT_STORE_NUM 2 #define INFRARED_TEXT_STORE_NUM 2
#define INFRARED_TEXT_STORE_SIZE 128 #define INFRARED_TEXT_STORE_SIZE 128
#define INFRARED_MAX_BUTTON_NAME_LENGTH 22 #define INFRARED_MAX_BUTTON_NAME_LENGTH 22
#define INFRARED_MAX_REMOTE_NAME_LENGTH 22 #define INFRARED_MAX_REMOTE_NAME_LENGTH 22
#define INFRARED_APP_FOLDER ANY_PATH("infrared") #define INFRARED_APP_FOLDER ANY_PATH("infrared")
#define INFRARED_APP_EXTENSION ".ir" #define INFRARED_APP_EXTENSION ".ir"
#define INFRARED_DEFAULT_REMOTE_NAME "Remote" #define INFRARED_DEFAULT_REMOTE_NAME "Remote"
#define INFRARED_LOG_TAG "InfraredApp" #define INFRARED_LOG_TAG "InfraredApp"
/** /**
* @brief Enumeration of invalid remote button indices. * @brief Enumeration of invalid remote button indices.
@@ -86,7 +86,7 @@ typedef struct {
bool is_transmitting; /**< Whether a signal is currently being transmitted. */ bool is_transmitting; /**< Whether a signal is currently being transmitted. */
bool is_otg_enabled; /**< Whether OTG power (external 5V) is enabled. */ bool is_otg_enabled; /**< Whether OTG power (external 5V) is enabled. */
InfraredEditTarget edit_target : 8; /**< Selected editing target (a remote or a button). */ InfraredEditTarget edit_target : 8; /**< Selected editing target (a remote or a button). */
InfraredEditMode edit_mode : 8; /**< Selected editing operation (rename or delete). */ InfraredEditMode edit_mode : 8; /**< Selected editing operation (rename or delete). */
int32_t current_button_index; /**< Selected button index (move destination). */ int32_t current_button_index; /**< Selected button index (move destination). */
int32_t prev_button_index; /**< Previous button index (move source). */ int32_t prev_button_index; /**< Previous button index (move source). */
uint32_t last_transmit_time; /**< Lat time a signal was transmitted. */ uint32_t last_transmit_time; /**< Lat time a signal was transmitted. */

View File

@@ -10,10 +10,10 @@
#include "infrared_signal.h" #include "infrared_signal.h"
#include "infrared_brute_force.h" #include "infrared_brute_force.h"
#define INFRARED_CLI_BUF_SIZE (10U) #define INFRARED_CLI_BUF_SIZE (10U)
#define INFRARED_CLI_FILE_NAME_SIZE (256U) #define INFRARED_CLI_FILE_NAME_SIZE (256U)
#define INFRARED_FILE_EXTENSION ".ir" #define INFRARED_FILE_EXTENSION ".ir"
#define INFRARED_ASSETS_FOLDER EXT_PATH("infrared/assets") #define INFRARED_ASSETS_FOLDER EXT_PATH("infrared/assets")
#define INFRARED_BRUTE_FORCE_DUMMY_INDEX 0 #define INFRARED_BRUTE_FORCE_DUMMY_INDEX 0
DICT_DEF2(dict_signals, FuriString*, FURI_STRING_OPLIST, int, M_DEFAULT_OPLIST) DICT_DEF2(dict_signals, FuriString*, FURI_STRING_OPLIST, int, M_DEFAULT_OPLIST)

View File

@@ -8,7 +8,7 @@
#define TAG "InfraredRemote" #define TAG "InfraredRemote"
#define INFRARED_FILE_HEADER "IR signals file" #define INFRARED_FILE_HEADER "IR signals file"
#define INFRARED_FILE_VERSION (1) #define INFRARED_FILE_VERSION (1)
ARRAY_DEF(StringArray, const char*, M_CSTR_DUP_OPLIST); //-V575 ARRAY_DEF(StringArray, const char*, M_CSTR_DUP_OPLIST); //-V575

View File

@@ -13,18 +13,18 @@
#define INFRARED_SIGNAL_TYPE_KEY "type" #define INFRARED_SIGNAL_TYPE_KEY "type"
// Type key values // Type key values
#define INFRARED_SIGNAL_TYPE_RAW "raw" #define INFRARED_SIGNAL_TYPE_RAW "raw"
#define INFRARED_SIGNAL_TYPE_PARSED "parsed" #define INFRARED_SIGNAL_TYPE_PARSED "parsed"
// Raw signal keys // Raw signal keys
#define INFRARED_SIGNAL_DATA_KEY "data" #define INFRARED_SIGNAL_DATA_KEY "data"
#define INFRARED_SIGNAL_FREQUENCY_KEY "frequency" #define INFRARED_SIGNAL_FREQUENCY_KEY "frequency"
#define INFRARED_SIGNAL_DUTY_CYCLE_KEY "duty_cycle" #define INFRARED_SIGNAL_DUTY_CYCLE_KEY "duty_cycle"
// Parsed signal keys // Parsed signal keys
#define INFRARED_SIGNAL_PROTOCOL_KEY "protocol" #define INFRARED_SIGNAL_PROTOCOL_KEY "protocol"
#define INFRARED_SIGNAL_ADDRESS_KEY "address" #define INFRARED_SIGNAL_ADDRESS_KEY "address"
#define INFRARED_SIGNAL_COMMAND_KEY "command" #define INFRARED_SIGNAL_COMMAND_KEY "command"
struct InfraredSignal { struct InfraredSignal {
bool is_raw; bool is_raw;

View File

@@ -7,9 +7,9 @@
#include <toolbox/m_cstr_dup.h> #include <toolbox/m_cstr_dup.h>
#define LIST_ITEMS 4U #define LIST_ITEMS 4U
#define LIST_LINE_H 13U #define LIST_LINE_H 13U
#define HEADER_H 12U #define HEADER_H 12U
#define MOVE_X_OFFSET 5U #define MOVE_X_OFFSET 5U
struct InfraredMoveView { struct InfraredMoveView {
@@ -98,7 +98,7 @@ static bool infrared_move_view_input_callback(InputEvent* event, void* context)
bool consumed = false; bool consumed = false;
if(((event->type == InputTypeShort || event->type == InputTypeRepeat)) && if((event->type == InputTypeShort || event->type == InputTypeRepeat) &&
((event->key == InputKeyUp) || (event->key == InputKeyDown))) { ((event->key == InputKeyUp) || (event->key == InputKeyDown))) {
with_view_model( with_view_model(
move_view->view, move_view->view,

View File

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

View File

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

View File

@@ -35,13 +35,13 @@
#include <lfrfid/scenes/lfrfid_scene.h> #include <lfrfid/scenes/lfrfid_scene.h>
#define LFRFID_KEY_NAME_SIZE 22 #define LFRFID_KEY_NAME_SIZE 22
#define LFRFID_TEXT_STORE_SIZE 40 #define LFRFID_TEXT_STORE_SIZE 40
#define LFRFID_APP_FOLDER ANY_PATH("lfrfid") #define LFRFID_APP_FOLDER ANY_PATH("lfrfid")
#define LFRFID_SD_FOLDER EXT_PATH("lfrfid") #define LFRFID_SD_FOLDER EXT_PATH("lfrfid")
#define LFRFID_APP_FILENAME_PREFIX "RFID" #define LFRFID_APP_FILENAME_PREFIX "RFID"
#define LFRFID_APP_FILENAME_EXTENSION ".rfid" #define LFRFID_APP_FILENAME_EXTENSION ".rfid"
#define LFRFID_APP_SHADOW_FILENAME_EXTENSION ".shd" #define LFRFID_APP_SHADOW_FILENAME_EXTENSION ".shd"
#define LFRFID_APP_RAW_ASK_EXTENSION ".ask.raw" #define LFRFID_APP_RAW_ASK_EXTENSION ".ask.raw"

View File

@@ -31,8 +31,21 @@ bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) {
consumed = true; consumed = true;
size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id); 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); protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size);
scene_manager_next_scene(scene_manager, LfRfidSceneSaveName);
scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1); if(scene_manager_has_previous_scene(scene_manager, LfRfidSceneSaveType)) {
scene_manager_next_scene(scene_manager, LfRfidSceneSaveName);
} 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) { } else if(event.type == SceneManagerEventTypeBack) {
scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 0); scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 0);

View File

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

View File

@@ -3,7 +3,7 @@
#include <furi/furi.h> #include <furi/furi.h>
#include <storage/storage.h> #include <storage/storage.h>
#define NFC_APP_KEYS_EXTENSION ".keys" #define NFC_APP_KEYS_EXTENSION ".keys"
#define NFC_APP_KEY_CACHE_FOLDER "/ext/nfc/.cache" #define NFC_APP_KEY_CACHE_FOLDER "/ext/nfc/.cache"
static const char* mf_classic_key_cache_file_header = "Flipper NFC keys"; static const char* mf_classic_key_cache_file_header = "Flipper NFC keys";

View File

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

View File

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

View File

@@ -4,7 +4,7 @@
#include <nfc/protocols/mf_classic/mf_classic.h> #include <nfc/protocols/mf_classic/mf_classic.h>
#include <furi/furi.h> #include <furi/furi.h>
#define NFC_APP_FOLDER ANY_PATH("nfc") #define NFC_APP_FOLDER ANY_PATH("nfc")
#define NFC_APP_MF_CLASSIC_DICT_USER_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict_user.nfc") #define NFC_APP_MF_CLASSIC_DICT_USER_PATH (NFC_APP_FOLDER "/assets/mf_classic_dict_user.nfc")
struct MfUserDict { struct MfUserDict {

View File

@@ -14,7 +14,7 @@
#define TAG "NfcSupportedCards" #define TAG "NfcSupportedCards"
#define NFC_SUPPORTED_CARDS_PLUGINS_PATH APP_DATA_PATH("plugins") #define NFC_SUPPORTED_CARDS_PLUGINS_PATH APP_DATA_PATH("plugins")
#define NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX "_parser.fal" #define NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX "_parser.fal"
typedef enum { typedef enum {
@@ -24,7 +24,7 @@ typedef enum {
} NfcSupportedCardsPluginFeature; } NfcSupportedCardsPluginFeature;
typedef struct { typedef struct {
FuriString* path; FuriString* name;
NfcProtocol protocol; NfcProtocol protocol;
NfcSupportedCardsPluginFeature feature; NfcSupportedCardsPluginFeature feature;
} NfcSupportedCardsPluginCache; } NfcSupportedCardsPluginCache;
@@ -41,7 +41,6 @@ typedef enum {
typedef struct { typedef struct {
Storage* storage; Storage* storage;
File* directory; File* directory;
FuriString* file_path;
char file_name[256]; char file_name[256];
FlipperApplication* app; FlipperApplication* app;
} NfcSupportedCardsLoadContext; } NfcSupportedCardsLoadContext;
@@ -73,7 +72,7 @@ void nfc_supported_cards_free(NfcSupportedCards* instance) {
!NfcSupportedCardsPluginCache_end_p(iter); !NfcSupportedCardsPluginCache_end_p(iter);
NfcSupportedCardsPluginCache_next(iter)) { NfcSupportedCardsPluginCache_next(iter)) {
NfcSupportedCardsPluginCache* plugin_cache = NfcSupportedCardsPluginCache_ref(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); 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->storage = furi_record_open(RECORD_STORAGE);
instance->directory = storage_file_alloc(instance->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)) { 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); 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); flipper_application_free(instance->app);
} }
furi_string_free(instance->file_path);
storage_dir_close(instance->directory); storage_dir_close(instance->directory);
storage_file_free(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( static const NfcSupportedCardsPlugin* nfc_supported_cards_get_plugin(
NfcSupportedCardsLoadContext* instance, NfcSupportedCardsLoadContext* instance,
const FuriString* path, const char* name,
const ElfApiInterface* api_interface) { const ElfApiInterface* api_interface) {
furi_assert(instance); furi_assert(instance);
furi_assert(path); furi_assert(name);
const NfcSupportedCardsPlugin* plugin = NULL; 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 { do {
if(instance->app) flipper_application_free(instance->app); if(instance->app) flipper_application_free(instance->app);
instance->app = flipper_application_alloc(instance->storage, api_interface); 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) FlipperApplicationPreloadStatusSuccess)
break; break;
if(!flipper_application_is_plugin(instance->app)) 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; plugin = descriptor->entry_point;
} while(false); } while(false);
furi_string_free(plugin_path);
return plugin; 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))) instance->directory, NULL, instance->file_name, sizeof(instance->file_name)))
break; break;
furi_string_set(instance->file_path, instance->file_name); const size_t suffix_len = strlen(NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX);
if(!furi_string_end_with_str(instance->file_path, NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX)) const size_t file_name_len = strlen(instance->file_name);
continue; 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 } while(plugin == NULL); //-V654
return plugin; return plugin;
@@ -181,7 +189,7 @@ void nfc_supported_cards_load_cache(NfcSupportedCards* instance) {
if(plugin == NULL) break; //-V547 if(plugin == NULL) break; //-V547
NfcSupportedCardsPluginCache plugin_cache = {}; //-V779 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; plugin_cache.protocol = plugin->protocol;
if(plugin->verify) { if(plugin->verify) {
plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasVerify; plugin_cache.feature |= NfcSupportedCardsPluginFeatureHasVerify;
@@ -233,7 +241,7 @@ bool nfc_supported_cards_read(NfcSupportedCards* instance, NfcDevice* device, Nf
const ElfApiInterface* api_interface = const ElfApiInterface* api_interface =
composite_api_resolver_get(instance->api_resolver); composite_api_resolver_get(instance->api_resolver);
const NfcSupportedCardsPlugin* plugin = nfc_supported_cards_get_plugin( 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 == NULL) continue;
if(plugin->verify) { if(plugin->verify) {
@@ -281,7 +289,7 @@ bool nfc_supported_cards_parse(
const ElfApiInterface* api_interface = const ElfApiInterface* api_interface =
composite_api_resolver_get(instance->api_resolver); composite_api_resolver_get(instance->api_resolver);
const NfcSupportedCardsPlugin* plugin = nfc_supported_cards_get_plugin( 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 == NULL) continue;
if(plugin->parse) { if(plugin->parse) {

View File

@@ -9,6 +9,10 @@
#include "../nfc_protocol_support_gui_common.h" #include "../nfc_protocol_support_gui_common.h"
#include "../iso14443_4a/iso14443_4a_i.h" #include "../iso14443_4a/iso14443_4a_i.h"
enum {
SubmenuIndexTransactions = SubmenuIndexCommonMax,
};
static void nfc_scene_info_on_enter_emv(NfcApp* instance) { static void nfc_scene_info_on_enter_emv(NfcApp* instance) {
const NfcDevice* device = instance->nfc_device; const NfcDevice* device = instance->nfc_device;
const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); 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); 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) { static NfcCommand nfc_scene_read_poller_callback_emv(NfcGenericEvent event, void* context) {
furi_assert(event.protocol == NfcProtocolEmv); 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); 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) { static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) {
const NfcDevice* device = instance->nfc_device; const NfcDevice* device = instance->nfc_device;
const EmvData* data = nfc_device_get_data(device, NfcProtocolEmv); 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); 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 = { const NfcProtocolSupportBase nfc_protocol_support_emv = {
.features = NfcProtocolFeatureMoreInfo, .features = NfcProtocolFeatureNone,
.scene_info = .scene_info =
{ {
@@ -74,7 +100,7 @@ const NfcProtocolSupportBase nfc_protocol_support_emv = {
}, },
.scene_more_info = .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, .on_event = nfc_protocol_support_common_on_event_empty,
}, },
.scene_read = .scene_read =
@@ -84,8 +110,8 @@ const NfcProtocolSupportBase nfc_protocol_support_emv = {
}, },
.scene_read_menu = .scene_read_menu =
{ {
.on_enter = nfc_protocol_support_common_on_enter_empty, .on_enter = nfc_scene_read_menu_on_enter_emv,
.on_event = nfc_protocol_support_common_on_event_empty, .on_event = nfc_scene_read_menu_on_event_emv,
}, },
.scene_read_success = .scene_read_success =
{ {

View File

@@ -68,7 +68,8 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) {
const uint8_t len = apl->aid_len; const uint8_t len = apl->aid_len;
furi_string_cat_printf(str, "AID: "); 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"); furi_string_cat_printf(str, "\n");
} }

View File

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

View File

@@ -71,7 +71,7 @@ void nfc_render_iso15693_3_system_info(const Iso15693_3Data* data, FuriString* s
void nfc_render_iso15693_3_extra(const Iso15693_3Data* data, FuriString* str) { void nfc_render_iso15693_3_extra(const Iso15693_3Data* data, FuriString* str) {
furi_string_cat(str, "\n::::::::::::::::[General info]:::::::::::::::::\n"); furi_string_cat(str, "\n::::::::::::::::[General info]:::::::::::::::::\n");
if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_DSFID) { 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) { if(data->system_info.flags & ISO15693_3_SYSINFO_FLAG_AFI) {

View File

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

View File

@@ -150,6 +150,7 @@ static NfcCommand
} }
if(!mf_ultralight_event->data->auth_context.skip_auth) { 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.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) { } else if(mf_ultralight_event->type == MfUltralightPollerEventTypeAuthSuccess) {
instance->mf_ul_auth->pack = mf_ultralight_event->data->auth_context.pack; 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.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexUnlock) { 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; consumed = true;
} else if(event.event == SubmenuIndexWrite) { } else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite); scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite);

View File

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

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