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

Merge remote-tracking branch 'OFW/dev' into dev

This commit is contained in:
MX
2024-07-07 02:22:08 +03:00
67 changed files with 737 additions and 418 deletions

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: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
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: true
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,33 +80,29 @@ 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
@@ -97,19 +127,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: false
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 +160,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: false
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,23 +206,26 @@ 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
BitFieldColonSpacing: Both
Standard: c++03 Standard: c++03
StatementAttributeLikeMacros: StatementAttributeLikeMacros:
- Q_EMIT - Q_EMIT
@@ -179,8 +233,8 @@ 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

View File

@@ -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,76 @@ 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,
uint8_t lc,
uint8_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, uint8_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,
uint8_t lc,
uint8_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 +196,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; if(commandAPDU->CLA == 0x01) {
responseAPDU->SW2 = 0x00; switch(commandAPDU->INS) {
case 0x01:
handle_instruction_01(responseAPDU);
break;
case 0x02:
handle_instruction_02(
commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, commandAPDU->Le, responseAPDU);
break;
case 0x03:
handle_instruction_03(commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, responseAPDU);
break;
case 0x04:
handle_instruction_04(
commandAPDU->P1,
commandAPDU->P2,
commandAPDU->Lc,
commandAPDU->Le,
commandAPDU->Data,
responseAPDU);
break;
default:
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED);
} }
//example 2: sends a command with no body, receives a response with a body with two bytes
//sends APDU 0x01:0x02:0x00:0x00
//receives 'bc' (0x62, 0x63) SW1=0x80, SW2=0x10
else if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x02) {
responseApduDataBuffer[0] = 0x62;
responseApduDataBuffer[1] = 0x63;
*responseApduDataBufferLen = 2;
responseAPDU->SW1 = 0x90;
responseAPDU->SW2 = 0x00;
}
//example 3: ends a command with a body with two bytes, receives a response with a body with two bytes
//sends APDU 0x01:0x03:0x00:0x00:0x02:CA:FE
//receives (0xCA, 0xFE) SW1=0x90, SW2=0x02
else if(
commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x03 && commandApduDataBufferLen == 2 &&
commandAPDU->Lc == 2) {
//echo command body to response body
responseApduDataBuffer[0] = commandApduDataBuffer[0];
responseApduDataBuffer[1] = commandApduDataBuffer[1];
*responseApduDataBufferLen = 2;
responseAPDU->SW1 = 0x90;
responseAPDU->SW2 = 0x00;
} else { } else {
responseAPDU->SW1 = 0x6A; iso7816_set_response(responseAPDU, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED);
responseAPDU->SW2 = 0x00;
} }
} }

View File

@@ -0,0 +1,116 @@
# 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,
)
max_apdu = list(range(0, 0x30))
test_apdu(
connection,
"INS 0x04: Lc=0x30, data=max_apdu, Le=0x30. Expect 0x30 bytes data in return",
[0x01, 0x04, 0x00, 0x00, 0x30] + max_apdu + [0x30],
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];
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]; 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

@@ -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

@@ -206,8 +206,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

@@ -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

@@ -6,8 +6,7 @@
#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)
@@ -21,8 +20,7 @@ const int8_t em_test_timings[EM_TEST_EMULATION_TIMINGS_COUNT] = {
-32, 32, 32, -32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32, -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)
@@ -71,8 +69,7 @@ const int8_t hid10301_test_timings[HID10301_TEST_EMULATION_TIMINGS_COUNT] = {
5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 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)
@@ -116,8 +113,7 @@ const int8_t ioprox_xsf_test_timings[IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] =
}; };
#define INDALA26_EMULATION_TIMINGS_COUNT (1024 * 2) #define INDALA26_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] = {
@@ -209,8 +205,7 @@ 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)

View File

@@ -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;
@@ -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);
@@ -117,15 +113,13 @@ static const NfcSupportedCardsPlugin* nfc_supported_cards_get_plugin(
furi_assert(name); 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);
// Reconstruct path if(flipper_application_preload(instance->app, furi_string_get_cstr(plugin_path)) !=
path_concat(NFC_SUPPORTED_CARDS_PLUGINS_PATH, name, instance->file_path);
furi_string_cat(instance->file_path, NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX);
if(flipper_application_preload(instance->app, furi_string_get_cstr(instance->file_path)) !=
FlipperApplicationPreloadStatusSuccess) FlipperApplicationPreloadStatusSuccess)
break; break;
if(!flipper_application_is_plugin(instance->app)) break; if(!flipper_application_is_plugin(instance->app)) break;
@@ -141,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;
} }
@@ -156,13 +151,19 @@ 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;
size_t trim_suffix = size_t suffix_start_pos = file_name_len - suffix_len;
furi_string_size(instance->file_path) - strlen(NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX); if(memcmp(
instance->file_name[trim_suffix] = '\0'; &instance->file_name[suffix_start_pos],
NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX,
suffix_len) != 0) //-V1051
break;
// 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); plugin = nfc_supported_cards_get_plugin(instance, instance->file_name, api_interface);
} while(plugin == NULL); //-V654 } while(plugin == NULL); //-V654

View File

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

View File

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

View File

@@ -321,8 +321,7 @@ void button_menu_reset(ButtonMenu* button_menu) {
void button_menu_set_header(ButtonMenu* button_menu, const char* header) { void button_menu_set_header(ButtonMenu* button_menu, const char* header) {
furi_check(button_menu); furi_check(button_menu);
with_view_model( with_view_model(button_menu->view, ButtonMenuModel * model, { model->header = header; }, true);
button_menu->view, ButtonMenuModel * model, { model->header = header; }, true);
} }
ButtonMenuItem* button_menu_add_item( ButtonMenuItem* button_menu_add_item(

View File

@@ -868,6 +868,5 @@ void byte_input_set_result_callback(
void byte_input_set_header_text(ByteInput* byte_input, const char* text) { void byte_input_set_header_text(ByteInput* byte_input, const char* text) {
furi_check(byte_input); furi_check(byte_input);
with_view_model( with_view_model(byte_input->view, ByteInputModel * model, { model->header = text; }, true);
byte_input->view, ByteInputModel * model, { model->header = text; }, true);
} }

View File

@@ -257,20 +257,17 @@ void dialog_ex_set_icon(DialogEx* dialog_ex, uint8_t x, uint8_t y, const Icon* i
void dialog_ex_set_left_button_text(DialogEx* dialog_ex, const char* text) { void dialog_ex_set_left_button_text(DialogEx* dialog_ex, const char* text) {
furi_check(dialog_ex); furi_check(dialog_ex);
with_view_model( with_view_model(dialog_ex->view, DialogExModel * model, { model->left_text = text; }, true);
dialog_ex->view, DialogExModel * model, { model->left_text = text; }, true);
} }
void dialog_ex_set_center_button_text(DialogEx* dialog_ex, const char* text) { void dialog_ex_set_center_button_text(DialogEx* dialog_ex, const char* text) {
furi_check(dialog_ex); furi_check(dialog_ex);
with_view_model( with_view_model(dialog_ex->view, DialogExModel * model, { model->center_text = text; }, true);
dialog_ex->view, DialogExModel * model, { model->center_text = text; }, true);
} }
void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text) { void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text) {
furi_check(dialog_ex); furi_check(dialog_ex);
with_view_model( with_view_model(dialog_ex->view, DialogExModel * model, { model->right_text = text; }, true);
dialog_ex->view, DialogExModel * model, { model->right_text = text; }, true);
} }
void dialog_ex_reset(DialogEx* dialog_ex) { void dialog_ex_reset(DialogEx* dialog_ex) {

View File

@@ -174,15 +174,13 @@ static void browser_long_load_cb(void* context);
static void file_browser_scroll_timer_callback(void* context) { static void file_browser_scroll_timer_callback(void* context) {
furi_check(context); furi_check(context);
FileBrowser* browser = context; FileBrowser* browser = context;
with_view_model( with_view_model(browser->view, FileBrowserModel * model, { model->scroll_counter++; }, true);
browser->view, FileBrowserModel * model, { model->scroll_counter++; }, true);
} }
static void file_browser_view_enter_callback(void* context) { static void file_browser_view_enter_callback(void* context) {
furi_check(context); furi_check(context);
FileBrowser* browser = context; FileBrowser* browser = context;
with_view_model( with_view_model(browser->view, FileBrowserModel * model, { model->scroll_counter = 0; }, true);
browser->view, FileBrowserModel * model, { model->scroll_counter = 0; }, true);
furi_timer_start(browser->scroll_timer, SCROLL_INTERVAL); furi_timer_start(browser->scroll_timer, SCROLL_INTERVAL);
} }

View File

@@ -149,8 +149,7 @@ void menu_free(Menu* menu) {
furi_check(menu); furi_check(menu);
menu_reset(menu); menu_reset(menu);
with_view_model( with_view_model(menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false);
menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false);
view_free(menu->view); view_free(menu->view);
free(menu); free(menu);

View File

@@ -355,13 +355,11 @@ void text_box_set_text(TextBox* text_box, const char* text) {
void text_box_set_font(TextBox* text_box, TextBoxFont font) { void text_box_set_font(TextBox* text_box, TextBoxFont font) {
furi_check(text_box); furi_check(text_box);
with_view_model( with_view_model(text_box->view, TextBoxModel * model, { model->font = font; }, true);
text_box->view, TextBoxModel * model, { model->font = font; }, true);
} }
void text_box_set_focus(TextBox* text_box, TextBoxFocus focus) { void text_box_set_focus(TextBox* text_box, TextBoxFocus focus) {
furi_check(text_box); furi_check(text_box);
with_view_model( with_view_model(text_box->view, TextBoxModel * model, { model->focus = focus; }, true);
text_box->view, TextBoxModel * model, { model->focus = focus; }, true);
} }

View File

@@ -649,6 +649,5 @@ void* text_input_get_validator_callback_context(TextInput* text_input) {
void text_input_set_header_text(TextInput* text_input, const char* text) { void text_input_set_header_text(TextInput* text_input, const char* text) {
furi_check(text_input); furi_check(text_input);
with_view_model( with_view_model(text_input->view, TextInputModel * model, { model->header = text; }, true);
text_input->view, TextInputModel * model, { model->header = text; }, true);
} }

View File

@@ -104,7 +104,8 @@ void view_holder_start(ViewHolder* view_holder) {
} }
void view_holder_stop(ViewHolder* view_holder) { void view_holder_stop(ViewHolder* view_holder) {
while(view_holder->ongoing_input) furi_delay_tick(1); while(view_holder->ongoing_input)
furi_delay_tick(1);
view_port_enabled_set(view_holder->view_port, false); view_port_enabled_set(view_holder->view_port, false);
} }

View File

@@ -137,7 +137,8 @@ int32_t input_srv(void* p) {
} else { } else {
event.sequence_counter = pin_states[i].counter; event.sequence_counter = pin_states[i].counter;
furi_timer_stop(pin_states[i].press_timer); furi_timer_stop(pin_states[i].press_timer);
while(furi_timer_is_running(pin_states[i].press_timer)) furi_delay_tick(1); while(furi_timer_is_running(pin_states[i].press_timer))
furi_delay_tick(1);
if(pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) { if(pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) {
event.type = InputTypeShort; event.type = InputTypeShort;
furi_pubsub_publish(event_pubsub, &event); furi_pubsub_publish(event_pubsub, &event);

View File

@@ -400,8 +400,7 @@ HidKeyboard* hid_keyboard_alloc(Hid* bt_hid) {
view_set_draw_callback(hid_keyboard->view, hid_keyboard_draw_callback); view_set_draw_callback(hid_keyboard->view, hid_keyboard_draw_callback);
view_set_input_callback(hid_keyboard->view, hid_keyboard_input_callback); view_set_input_callback(hid_keyboard->view, hid_keyboard_input_callback);
with_view_model( with_view_model(hid_keyboard->view, HidKeyboardModel * model, { model->y = 1; }, true);
hid_keyboard->view, HidKeyboardModel * model, { model->y = 1; }, true);
return hid_keyboard; return hid_keyboard;
} }

View File

@@ -237,7 +237,10 @@ typedef struct {
} UpdateTaskStageGroupMap; } UpdateTaskStageGroupMap;
#define STAGE_DEF(GROUP, WEIGHT) \ #define STAGE_DEF(GROUP, WEIGHT) \
{ .group = (GROUP), .weight = (WEIGHT), } { \
.group = (GROUP), \
.weight = (WEIGHT), \
}
static const UpdateTaskStageGroupMap update_task_stage_progress[] = { static const UpdateTaskStageGroupMap update_task_stage_progress[] = {
[UpdateTaskStageProgress] = STAGE_DEF(UpdateTaskStageGroupMisc, 0), [UpdateTaskStageProgress] = STAGE_DEF(UpdateTaskStageGroupMisc, 0),

View File

@@ -29,8 +29,8 @@ extern "C" {
#define FURI_PACKED __attribute__((packed)) #define FURI_PACKED __attribute__((packed))
#endif #endif
#ifndef FURI_ALWAYS_STATIC_INLINE #ifndef FURI_ALWAYS_INLINE
#define FURI_ALWAYS_STATIC_INLINE __attribute__((always_inline)) static inline #define FURI_ALWAYS_INLINE __attribute__((always_inline)) inline
#endif #endif
#ifndef FURI_IS_IRQ_MASKED #ifndef FURI_IS_IRQ_MASKED

View File

@@ -17,7 +17,7 @@ extern "C" {
/** /**
* @brief Furi string failure constant. * @brief Furi string failure constant.
*/ */
#define FURI_STRING_FAILURE ((size_t)-1) #define FURI_STRING_FAILURE ((size_t) - 1)
/** /**
* @brief Furi string primitive. * @brief Furi string primitive.

View File

@@ -1,6 +1,8 @@
#include "thread_list.h" #include "thread_list.h"
#include "check.h" #include "check.h"
#include <furi_hal_interrupt.h>
#include <m-array.h> #include <m-array.h>
#include <m-dict.h> #include <m-dict.h>
@@ -23,6 +25,8 @@ struct FuriThreadList {
FuriThreadListItemDict_t search; FuriThreadListItemDict_t search;
uint32_t runtime_previous; uint32_t runtime_previous;
uint32_t runtime_current; uint32_t runtime_current;
uint32_t isr_previous;
uint32_t isr_current;
}; };
FuriThreadList* furi_thread_list_alloc(void) { FuriThreadList* furi_thread_list_alloc(void) {
@@ -85,7 +89,10 @@ void furi_thread_list_process(FuriThreadList* instance, uint32_t runtime, uint32
instance->runtime_previous = instance->runtime_current; instance->runtime_previous = instance->runtime_current;
instance->runtime_current = runtime; instance->runtime_current = runtime;
uint32_t runtime_counter = instance->runtime_current - instance->runtime_previous; instance->isr_previous = instance->isr_current;
instance->isr_current = furi_hal_interrupt_get_time_in_isr_total();
const uint32_t runtime_counter = instance->runtime_current - instance->runtime_previous;
FuriThreadListItemArray_it_t it; FuriThreadListItemArray_it_t it;
FuriThreadListItemArray_it(it, instance->items); FuriThreadListItemArray_it(it, instance->items);
@@ -108,3 +115,10 @@ void furi_thread_list_process(FuriThreadList* instance, uint32_t runtime, uint32
} }
} }
} }
float furi_thread_list_get_isr_time(FuriThreadList* instance) {
const uint32_t runtime_counter = instance->runtime_current - instance->runtime_previous;
const uint32_t isr_counter = instance->isr_current - instance->isr_previous;
return (float)isr_counter / (float)runtime_counter;
}

View File

@@ -76,6 +76,14 @@ FuriThreadListItem* furi_thread_list_get_or_insert(FuriThreadList* instance, Fur
*/ */
void furi_thread_list_process(FuriThreadList* instance, uint32_t runtime, uint32_t tick); void furi_thread_list_process(FuriThreadList* instance, uint32_t runtime, uint32_t tick);
/** Get percent of time spent in ISR
*
* @param instance The instance
*
* @return percent of time spent in ISR
*/
float furi_thread_list_get_isr_time(FuriThreadList* instance);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -4,7 +4,7 @@ public:
virtual void on_enter(TApp* app, bool need_restore) = 0; virtual void on_enter(TApp* app, bool need_restore) = 0;
virtual bool on_event(TApp* app, typename TApp::Event* event) = 0; virtual bool on_event(TApp* app, typename TApp::Event* event) = 0;
virtual void on_exit(TApp* app) = 0; virtual void on_exit(TApp* app) = 0;
virtual ~GenericScene(){}; virtual ~GenericScene() {};
private: private:
}; };

View File

@@ -175,7 +175,8 @@ public:
bool switch_to_previous_scene(uint8_t count = 1) { bool switch_to_previous_scene(uint8_t count = 1) {
auto previous_scene_index = TApp::SceneType::Start; auto previous_scene_index = TApp::SceneType::Start;
for(uint8_t i = 0; i < count; i++) previous_scene_index = get_previous_scene_index(); for(uint8_t i = 0; i < count; i++)
previous_scene_index = get_previous_scene_index();
if(previous_scene_index == TApp::SceneType::Exit) return true; if(previous_scene_index == TApp::SceneType::Exit) return true;
@@ -198,7 +199,8 @@ public:
* *
*/ */
~SceneController() { ~SceneController() {
for(auto& it : scenes) delete it.second; for(auto& it : scenes)
delete it.second;
} }
private: private:

View File

@@ -3,8 +3,8 @@
class GenericViewModule { class GenericViewModule {
public: public:
GenericViewModule(){}; GenericViewModule() {};
virtual ~GenericViewModule(){}; virtual ~GenericViewModule() {};
virtual View* get_view() = 0; virtual View* get_view() = 0;
virtual void clean() = 0; virtual void clean() = 0;
}; };

View File

@@ -7,7 +7,7 @@
extern "C" { extern "C" {
#endif #endif
#define TOPBIT(X) (1 << ((X)-1)) #define TOPBIT(X) (1 << ((X) - 1))
typedef enum { typedef enum {
BitLibParityEven, BitLibParityEven,

View File

@@ -137,7 +137,8 @@ bool protocol_pac_stanley_encoder_start(ProtocolPACStanley* protocol) {
uint8_to_hex_chars(protocol->data, &idbytes[2], 8); uint8_to_hex_chars(protocol->data, &idbytes[2], 8);
// insert start and stop bits // insert start and stop bits
for(size_t i = 0; i < 16; i++) protocol->encoded_data[i] = 0x40 >> ((i + 3) % 5 * 2); for(size_t i = 0; i < 16; i++)
protocol->encoded_data[i] = 0x40 >> ((i + 3) % 5 * 2);
protocol->encoded_data[0] = 0xFF; // mark + stop protocol->encoded_data[0] = 0xFF; // mark + stop
protocol->encoded_data[1] = 0x20; // start + reflect8(STX) protocol->encoded_data[1] = 0x20; // start + reflect8(STX)

View File

@@ -126,7 +126,8 @@ bool protocol_pyramid_decoder_feed(ProtocolPyramid* protocol, bool level, uint32
bool protocol_pyramid_get_parity(const uint8_t* bits, uint8_t type, int length) { bool protocol_pyramid_get_parity(const uint8_t* bits, uint8_t type, int length) {
int x; int x;
for(x = 0; length > 0; --length) x += bit_lib_get_bit(bits, length - 1); for(x = 0; length > 0; --length)
x += bit_lib_get_bit(bits, length - 1);
x %= 2; x %= 2;
return x ^ type; return x ^ type;
} }

View File

@@ -84,7 +84,8 @@ uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) {
uint32_t prng_successor(uint32_t x, uint32_t n) { uint32_t prng_successor(uint32_t x, uint32_t n) {
SWAPENDIAN(x); SWAPENDIAN(x);
while(n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; while(n--)
x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
return SWAPENDIAN(x); return SWAPENDIAN(x);
} }

View File

@@ -190,7 +190,8 @@ void nfc_poller_start_ex(NfcPoller* instance, NfcGenericCallbackEx callback, voi
NfcProtocol parent_protocol = nfc_protocol_get_parent(instance->protocol); NfcProtocol parent_protocol = nfc_protocol_get_parent(instance->protocol);
if(parent_protocol != NfcProtocolInvalid) { if(parent_protocol != NfcProtocolInvalid) {
NfcPollerListElement* iter = instance->list.head; NfcPollerListElement* iter = instance->list.head;
while(iter->protocol != parent_protocol) iter = iter->child; while(iter->protocol != parent_protocol)
iter = iter->child;
iter->poller_api->set_callback(iter->poller, nfc_poller_start_ex_tail_callback, instance); iter->poller_api->set_callback(iter->poller, nfc_poller_start_ex_tail_callback, instance);
} }
@@ -254,7 +255,8 @@ bool nfc_poller_detect(NfcPoller* instance) {
NfcPollerListElement* iter = instance->list.head; NfcPollerListElement* iter = instance->list.head;
if(tail_poller != instance->list.head) { if(tail_poller != instance->list.head) {
while(iter->child != tail_poller) iter = iter->child; while(iter->child != tail_poller)
iter = iter->child;
iter->poller_api->set_callback(iter->poller, nfc_poller_detect_tail_callback, instance); iter->poller_api->set_callback(iter->poller, nfc_poller_detect_tail_callback, instance);
} }

View File

@@ -155,7 +155,8 @@ static void mf_ultralight_format_mirror_data(
FuriString* str, FuriString* str,
const uint8_t* const data, const uint8_t* const data,
const uint8_t data_len) { const uint8_t data_len) {
for(uint8_t i = 0; i < data_len; i++) furi_string_cat_printf(str, "%02X", data[i]); for(uint8_t i = 0; i < data_len; i++)
furi_string_cat_printf(str, "%02X", data[i]);
} }
void mf_ultralight_mirror_read_prepare(uint8_t start_page, MfUltralightListener* instance) { void mf_ultralight_mirror_read_prepare(uint8_t start_page, MfUltralightListener* instance) {

View File

@@ -224,7 +224,8 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code) {
furi_check(host); furi_check(host);
host->saved_rom[0] = family_code; host->saved_rom[0] = family_code;
for(uint8_t i = 1; i < 8; i++) host->saved_rom[i] = 0; for(uint8_t i = 1; i < 8; i++)
host->saved_rom[i] = 0;
host->last_discrepancy = 64; host->last_discrepancy = 64;
host->last_family_discrepancy = 0; host->last_family_discrepancy = 0;
host->last_device_flag = false; host->last_device_flag = false;
@@ -341,7 +342,8 @@ bool onewire_host_search(OneWireHost* host, uint8_t* new_addr, OneWireHostSearch
host->last_family_discrepancy = 0; host->last_family_discrepancy = 0;
search_result = false; search_result = false;
} else { } else {
for(int i = 0; i < 8; i++) new_addr[i] = host->saved_rom[i]; for(int i = 0; i < 8; i++)
new_addr[i] = host->saved_rom[i];
} }
return search_result; return search_result;

View File

@@ -616,7 +616,8 @@ static size_t _etoa(
FLAGS_ZEROPAD | FLAGS_PLUS); FLAGS_ZEROPAD | FLAGS_PLUS);
// might need to right-pad spaces // might need to right-pad spaces
if(flags & FLAGS_LEFT) { if(flags & FLAGS_LEFT) {
while(idx - start_idx < width) out(' ', buffer, idx++, maxlen); while(idx - start_idx < width)
out(' ', buffer, idx++, maxlen);
} }
} }
return idx; return idx;

View File

@@ -176,7 +176,8 @@ static bool keys_dict_get_next_key_str(KeysDict* instance, FuriString* key) {
furi_string_reset(key); furi_string_reset(key);
while(!key_read && !is_endfile) key_read = keys_dict_read_key_line(instance, key, &is_endfile); while(!key_read && !is_endfile)
key_read = keys_dict_read_key_line(instance, key, &is_endfile);
return key_read; return key_read;
} }

View File

@@ -584,7 +584,8 @@ void i2c_transfer(u8x8_t* u8x8, uint8_t adr, uint8_t cnt, uint8_t* data) {
uint8_t i; uint8_t i;
i2c_start(u8x8); i2c_start(u8x8);
i2c_write_byte(u8x8, adr); i2c_write_byte(u8x8, adr);
for(i = 0; i < cnt; i++) i2c_write_byte(u8x8, data[i]); for(i = 0; i < cnt; i++)
i2c_write_byte(u8x8, data[i]);
i2c_stop(u8x8); i2c_stop(u8x8);
} }

View File

@@ -109,7 +109,8 @@ void u8x8_SetupDefaults(u8x8_t* u8x8) {
#ifdef U8X8_USE_PINS #ifdef U8X8_USE_PINS
{ {
uint8_t i; uint8_t i;
for(i = 0; i < U8X8_PIN_CNT; i++) u8x8->pins[i] = U8X8_PIN_NONE; for(i = 0; i < U8X8_PIN_CNT; i++)
u8x8->pins[i] = U8X8_PIN_NONE;
} }
#endif #endif
} }

View File

@@ -32,7 +32,7 @@ which is the name that most clang tools search for by default.
import fnmatch import fnmatch
import itertools import itertools
import json import json
from shlex import join, split from oslex import join, split
import SCons import SCons
from SCons.Tool.asm import ASPPSuffixes, ASSuffixes from SCons.Tool.asm import ASPPSuffixes, ASSuffixes

View File

@@ -15,4 +15,3 @@ def resolve_port(logger, portname: str = "auto"):
logger.error("Failed to find connected Flipper") logger.error("Failed to find connected Flipper")
elif len(flippers) > 1: elif len(flippers) > 1:
logger.error("More than one Flipper is attached") logger.error("More than one Flipper is attached")
logger.error("Failed to guess which port to use")

View File

@@ -1,61 +0,0 @@
#!/usr/bin/env python3
import logging
import os
import sys
import time
def flp_serial_by_name(flp_name):
if sys.platform == "darwin": # MacOS
flp_serial = "/dev/cu.usbmodemflip_" + flp_name + "1"
logging.info(f"Darwin, looking for {flp_serial}")
elif sys.platform == "linux": # Linux
flp_serial = (
"/dev/serial/by-id/usb-Flipper_Devices_Inc._Flipper_"
+ flp_name
+ "_flip_"
+ flp_name
+ "-if00"
)
logging.info(f"linux, looking for {flp_serial}")
if os.path.exists(flp_serial):
return flp_serial
else:
logging.info(f"Couldn't find {flp_name} on this attempt.")
if os.path.exists(flp_name):
return flp_name
else:
return ""
UPDATE_TIMEOUT = 30 * 4 # 4 minutes
def main():
flipper_name = sys.argv[1]
elapsed = 0
flipper = flp_serial_by_name(flipper_name)
logging.basicConfig(
format="%(asctime)s %(levelname)-8s %(message)s",
level=logging.INFO,
datefmt="%Y-%m-%d %H:%M:%S",
)
logging.info(f"Waiting for Flipper {flipper_name} to be ready...")
while flipper == "" and elapsed < UPDATE_TIMEOUT:
elapsed += 1
time.sleep(1)
flipper = flp_serial_by_name(flipper_name)
if flipper == "":
logging.error("Flipper not found!")
exit(1)
logging.info(f"Found Flipper at {flipper}")
sys.exit(0)
if __name__ == "__main__":
main()

View File

@@ -1,87 +0,0 @@
#!/usr/bin/env python3
import logging
import re
import sys
import serial
from await_flipper import flp_serial_by_name
def main():
logging.basicConfig(
format="%(asctime)s %(levelname)-8s %(message)s",
level=logging.INFO,
datefmt="%Y-%m-%d %H:%M:%S",
)
logging.info("Trying to run units on flipper")
flp_serial = flp_serial_by_name(sys.argv[1])
if flp_serial == "":
logging.error("Flipper not found!")
sys.exit(1)
with serial.Serial(flp_serial, timeout=150) as flipper:
logging.info(f"Found Flipper at {flp_serial}")
flipper.baudrate = 230400
flipper.flushOutput()
flipper.flushInput()
flipper.read_until(b">: ").decode("utf-8")
flipper.write(b"unit_tests\r")
data = flipper.read_until(b">: ").decode("utf-8")
lines = data.split("\r\n")
tests_re = r"Failed tests: \d{0,}"
time_re = r"Consumed: \d{0,}"
leak_re = r"Leaked: \d{0,}"
status_re = r"Status: \w{3,}"
tests_pattern = re.compile(tests_re)
time_pattern = re.compile(time_re)
leak_pattern = re.compile(leak_re)
status_pattern = re.compile(status_re)
tests, time, leak, status = None, None, None, None
total = 0
for line in lines:
logging.info(line)
if "()" in line:
total += 1
if not tests:
tests = re.match(tests_pattern, line)
if not time:
time = re.match(time_pattern, line)
if not leak:
leak = re.match(leak_pattern, line)
if not status:
status = re.match(status_pattern, line)
if None in (tests, time, leak, status):
logging.error(f"Failed to parse output: {leak} {time} {leak} {status}")
sys.exit(1)
leak = int(re.findall(r"[- ]\d+", leak.group(0))[0])
status = re.findall(r"\w+", status.group(0))[1]
tests = int(re.findall(r"\d+", tests.group(0))[0])
time = int(re.findall(r"\d+", time.group(0))[0])
if tests > 0 or status != "PASSED":
logging.error(f"Got {tests} failed tests.")
logging.error(f"Leaked (not failing on this stat): {leak}")
logging.error(f"Status: {status}")
logging.error(f"Time: {time/1000} seconds")
sys.exit(1)
logging.info(f"Leaked (not failing on this stat): {leak}")
logging.info(
f"Tests ran successfully! Time elapsed {time/1000} seconds. Passed {total} tests."
)
sys.exit(0)
if __name__ == "__main__":
main()

129
scripts/testops.py Normal file
View File

@@ -0,0 +1,129 @@
#!/usr/bin/env python3
import re
import sys
import time
from typing import Optional
from flipper.app import App
from flipper.storage import FlipperStorage
from flipper.utils.cdc import resolve_port
class Main(App):
# this is basic use without sub-commands, simply to reboot flipper / power it off, not meant as a full CLI wrapper
def init(self):
self.parser.add_argument("-p", "--port", help="CDC Port", default="auto")
self.parser.add_argument(
"-t", "--timeout", help="Timeout in seconds", type=int, default=10
)
self.subparsers = self.parser.add_subparsers(help="sub-command help")
self.parser_await_flipper = self.subparsers.add_parser(
"await_flipper", help="Wait for Flipper to connect or reconnect"
)
self.parser_await_flipper.set_defaults(func=self.await_flipper)
self.parser_run_units = self.subparsers.add_parser(
"run_units", help="Run unit tests and post result"
)
self.parser_run_units.set_defaults(func=self.run_units)
def _get_flipper(self, retry_count: Optional[int] = 1):
port = None
self.logger.info(f"Attempting to find flipper with {retry_count} attempts.")
for i in range(retry_count):
self.logger.info(f"Attempt to find flipper #{i}.")
if port := resolve_port(self.logger, self.args.port):
self.logger.info(f"Found flipper at {port}")
break
time.sleep(1)
if not port:
self.logger.info(f"Failed to find flipper {port}")
return None
flipper = FlipperStorage(port)
flipper.start()
return flipper
def await_flipper(self):
if not (flipper := self._get_flipper(retry_count=self.args.timeout)):
return 1
self.logger.info("Flipper started")
flipper.stop()
return 0
def run_units(self):
if not (flipper := self._get_flipper(retry_count=10)):
return 1
self.logger.info("Running unit tests")
flipper.send("unit_tests" + "\r")
self.logger.info("Waiting for unit tests to complete")
data = flipper.read.until(">: ")
self.logger.info("Parsing result")
lines = data.decode().split("\r\n")
tests_re = r"Failed tests: \d{0,}"
time_re = r"Consumed: \d{0,}"
leak_re = r"Leaked: \d{0,}"
status_re = r"Status: \w{3,}"
tests_pattern = re.compile(tests_re)
time_pattern = re.compile(time_re)
leak_pattern = re.compile(leak_re)
status_pattern = re.compile(status_re)
tests, elapsed_time, leak, status = None, None, None, None
total = 0
for line in lines:
self.logger.info(line)
if "()" in line:
total += 1
if not tests:
tests = re.match(tests_pattern, line)
if not elapsed_time:
elapsed_time = re.match(time_pattern, line)
if not leak:
leak = re.match(leak_pattern, line)
if not status:
status = re.match(status_pattern, line)
if None in (tests, elapsed_time, leak, status):
self.logger.error(
f"Failed to parse output: {tests} {elapsed_time} {leak} {status}"
)
sys.exit(1)
leak = int(re.findall(r"[- ]\d+", leak.group(0))[0])
status = re.findall(r"\w+", status.group(0))[1]
tests = int(re.findall(r"\d+", tests.group(0))[0])
elapsed_time = int(re.findall(r"\d+", elapsed_time.group(0))[0])
if tests > 0 or status != "PASSED":
self.logger.error(f"Got {tests} failed tests.")
self.logger.error(f"Leaked (not failing on this stat): {leak}")
self.logger.error(f"Status: {status}")
self.logger.error(f"Time: {elapsed_time/1000} seconds")
flipper.stop()
return 1
self.logger.info(f"Leaked (not failing on this stat): {leak}")
self.logger.info(
f"Tests ran successfully! Time elapsed {elapsed_time/1000} seconds. Passed {total} tests."
)
flipper.stop()
return 0
if __name__ == "__main__":
Main()()

View File

@@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] (
exit /b 0 exit /b 0
) )
set "FLIPPER_TOOLCHAIN_VERSION=33" set "FLIPPER_TOOLCHAIN_VERSION=37"
if ["%FBT_TOOLCHAIN_PATH%"] == [""] ( if ["%FBT_TOOLCHAIN_PATH%"] == [""] (
set "FBT_TOOLCHAIN_PATH=%FBT_ROOT%" set "FBT_TOOLCHAIN_PATH=%FBT_ROOT%"

View File

@@ -4,7 +4,7 @@
# public variables # public variables
DEFAULT_SCRIPT_PATH="$(pwd -P)"; DEFAULT_SCRIPT_PATH="$(pwd -P)";
FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"33"}"; FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"37"}";
if [ -z ${FBT_TOOLCHAIN_PATH+x} ] ; then if [ -z ${FBT_TOOLCHAIN_PATH+x} ] ; then
FBT_TOOLCHAIN_PATH_WAS_SET=0; FBT_TOOLCHAIN_PATH_WAS_SET=0;

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,68.0,, Version,+,68.1,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
@@ -1288,6 +1288,7 @@ Function,+,furi_hal_info_get_api_version,void,"uint16_t*, uint16_t*"
Function,-,furi_hal_init,void, Function,-,furi_hal_init,void,
Function,-,furi_hal_init_early,void, Function,-,furi_hal_init_early,void,
Function,+,furi_hal_interrupt_get_name,const char*,uint8_t Function,+,furi_hal_interrupt_get_name,const char*,uint8_t
Function,+,furi_hal_interrupt_get_time_in_isr_total,uint32_t,
Function,-,furi_hal_interrupt_init,void, Function,-,furi_hal_interrupt_init,void,
Function,+,furi_hal_interrupt_set_isr,void,"FuriHalInterruptId, FuriHalInterruptISR, void*" Function,+,furi_hal_interrupt_set_isr,void,"FuriHalInterruptId, FuriHalInterruptISR, void*"
Function,+,furi_hal_interrupt_set_isr_ex,void,"FuriHalInterruptId, FuriHalInterruptPriority, FuriHalInterruptISR, void*" Function,+,furi_hal_interrupt_set_isr_ex,void,"FuriHalInterruptId, FuriHalInterruptPriority, FuriHalInterruptISR, void*"
@@ -1633,6 +1634,7 @@ Function,+,furi_thread_join,_Bool,FuriThread*
Function,+,furi_thread_list_alloc,FuriThreadList*, Function,+,furi_thread_list_alloc,FuriThreadList*,
Function,+,furi_thread_list_free,void,FuriThreadList* Function,+,furi_thread_list_free,void,FuriThreadList*
Function,+,furi_thread_list_get_at,FuriThreadListItem*,"FuriThreadList*, size_t" Function,+,furi_thread_list_get_at,FuriThreadListItem*,"FuriThreadList*, size_t"
Function,+,furi_thread_list_get_isr_time,float,FuriThreadList*
Function,+,furi_thread_list_get_or_insert,FuriThreadListItem*,"FuriThreadList*, FuriThread*" Function,+,furi_thread_list_get_or_insert,FuriThreadListItem*,"FuriThreadList*, FuriThread*"
Function,+,furi_thread_list_process,void,"FuriThreadList*, uint32_t, uint32_t" Function,+,furi_thread_list_process,void,"FuriThreadList*, uint32_t, uint32_t"
Function,+,furi_thread_list_size,size_t,FuriThreadList* Function,+,furi_thread_list_size,size_t,FuriThreadList*
1 entry status name type params
2 Version + 68.0 68.1
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/bt/bt_service/bt_keys_storage.h
5 Header + applications/services/cli/cli.h
1288 Function - furi_hal_init void
1289 Function - furi_hal_init_early void
1290 Function + furi_hal_interrupt_get_name const char* uint8_t
1291 Function + furi_hal_interrupt_get_time_in_isr_total uint32_t
1292 Function - furi_hal_interrupt_init void
1293 Function + furi_hal_interrupt_set_isr void FuriHalInterruptId, FuriHalInterruptISR, void*
1294 Function + furi_hal_interrupt_set_isr_ex void FuriHalInterruptId, FuriHalInterruptPriority, FuriHalInterruptISR, void*
1634 Function + furi_thread_list_alloc FuriThreadList*
1635 Function + furi_thread_list_free void FuriThreadList*
1636 Function + furi_thread_list_get_at FuriThreadListItem* FuriThreadList*, size_t
1637 Function + furi_thread_list_get_isr_time float FuriThreadList*
1638 Function + furi_thread_list_get_or_insert FuriThreadListItem* FuriThreadList*, FuriThread*
1639 Function + furi_thread_list_process void FuriThreadList*, uint32_t, uint32_t
1640 Function + furi_thread_list_size size_t FuriThreadList*

View File

@@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,68.0,, Version,+,68.1,,
Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/bt/bt_service/bt_keys_storage.h,, Header,+,applications/services/bt/bt_service/bt_keys_storage.h,,
@@ -1447,6 +1447,7 @@ Function,+,furi_hal_infrared_set_tx_output,void,FuriHalInfraredTxPin
Function,-,furi_hal_init,void, Function,-,furi_hal_init,void,
Function,-,furi_hal_init_early,void, Function,-,furi_hal_init_early,void,
Function,+,furi_hal_interrupt_get_name,const char*,uint8_t Function,+,furi_hal_interrupt_get_name,const char*,uint8_t
Function,+,furi_hal_interrupt_get_time_in_isr_total,uint32_t,
Function,-,furi_hal_interrupt_init,void, Function,-,furi_hal_interrupt_init,void,
Function,+,furi_hal_interrupt_set_isr,void,"FuriHalInterruptId, FuriHalInterruptISR, void*" Function,+,furi_hal_interrupt_set_isr,void,"FuriHalInterruptId, FuriHalInterruptISR, void*"
Function,+,furi_hal_interrupt_set_isr_ex,void,"FuriHalInterruptId, FuriHalInterruptPriority, FuriHalInterruptISR, void*" Function,+,furi_hal_interrupt_set_isr_ex,void,"FuriHalInterruptId, FuriHalInterruptPriority, FuriHalInterruptISR, void*"
@@ -1887,6 +1888,7 @@ Function,+,furi_thread_join,_Bool,FuriThread*
Function,+,furi_thread_list_alloc,FuriThreadList*, Function,+,furi_thread_list_alloc,FuriThreadList*,
Function,+,furi_thread_list_free,void,FuriThreadList* Function,+,furi_thread_list_free,void,FuriThreadList*
Function,+,furi_thread_list_get_at,FuriThreadListItem*,"FuriThreadList*, size_t" Function,+,furi_thread_list_get_at,FuriThreadListItem*,"FuriThreadList*, size_t"
Function,+,furi_thread_list_get_isr_time,float,FuriThreadList*
Function,+,furi_thread_list_get_or_insert,FuriThreadListItem*,"FuriThreadList*, FuriThread*" Function,+,furi_thread_list_get_or_insert,FuriThreadListItem*,"FuriThreadList*, FuriThread*"
Function,+,furi_thread_list_process,void,"FuriThreadList*, uint32_t, uint32_t" Function,+,furi_thread_list_process,void,"FuriThreadList*, uint32_t, uint32_t"
Function,+,furi_thread_list_size,size_t,FuriThreadList* Function,+,furi_thread_list_size,size_t,FuriThreadList*
1 entry status name type params
2 Version + 68.0 68.1
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/bt/bt_service/bt_keys_storage.h
1447 Function - furi_hal_init void
1448 Function - furi_hal_init_early void
1449 Function + furi_hal_interrupt_get_name const char* uint8_t
1450 Function + furi_hal_interrupt_get_time_in_isr_total uint32_t
1451 Function - furi_hal_interrupt_init void
1452 Function + furi_hal_interrupt_set_isr void FuriHalInterruptId, FuriHalInterruptISR, void*
1453 Function + furi_hal_interrupt_set_isr_ex void FuriHalInterruptId, FuriHalInterruptPriority, FuriHalInterruptISR, void*
1888 Function + furi_thread_list_alloc FuriThreadList*
1889 Function + furi_thread_list_free void FuriThreadList*
1890 Function + furi_thread_list_get_at FuriThreadListItem* FuriThreadList*, size_t
1891 Function + furi_thread_list_get_isr_time float FuriThreadList*
1892 Function + furi_thread_list_get_or_insert FuriThreadListItem* FuriThreadList*, FuriThread*
1893 Function + furi_thread_list_process void FuriThreadList*, uint32_t, uint32_t
1894 Function + furi_thread_list_size size_t FuriThreadList*

View File

@@ -21,8 +21,7 @@
#define TAG "FuriHalBt" #define TAG "FuriHalBt"
#define furi_hal_bt_DEFAULT_MAC_ADDR \ #define furi_hal_bt_DEFAULT_MAC_ADDR {0x6c, 0x7a, 0xd8, 0xac, 0x57, 0x72}
{ 0x6c, 0x7a, 0xd8, 0xac, 0x57, 0x72 }
/* Time, in ms, to wait for mode transition before crashing */ /* Time, in ms, to wait for mode transition before crashing */
#define C2_MODE_SWITCH_TIMEOUT 10000 #define C2_MODE_SWITCH_TIMEOUT 10000

View File

@@ -513,8 +513,7 @@ typedef struct {
uint32_t* ob_register_address; uint32_t* ob_register_address;
} FuriHalFlashObMapping; } FuriHalFlashObMapping;
#define OB_REG_DEF(INDEX, REG) \ #define OB_REG_DEF(INDEX, REG) {.ob_reg = INDEX, .ob_register_address = (uint32_t*)(REG)}
{ .ob_reg = INDEX, .ob_register_address = (uint32_t*)(REG) }
static const FuriHalFlashObMapping furi_hal_flash_ob_reg_map[FURI_HAL_FLASH_OB_TOTAL_WORDS] = { static const FuriHalFlashObMapping furi_hal_flash_ob_reg_map[FURI_HAL_FLASH_OB_TOTAL_WORDS] = {
OB_REG_DEF(FuriHalFlashObRegisterUserRead, (&FLASH->OPTR)), OB_REG_DEF(FuriHalFlashObRegisterUserRead, (&FLASH->OPTR)),

View File

@@ -249,7 +249,7 @@ void furi_hal_gpio_remove_int_callback(const GpioPin* gpio) {
FURI_CRITICAL_EXIT(); FURI_CRITICAL_EXIT();
} }
FURI_ALWAYS_STATIC_INLINE void furi_hal_gpio_int_call(uint16_t pin_num) { FURI_ALWAYS_INLINE static void furi_hal_gpio_int_call(uint16_t pin_num) {
if(gpio_interrupt[pin_num].callback) { if(gpio_interrupt[pin_num].callback) {
gpio_interrupt[pin_num].callback(gpio_interrupt[pin_num].context); gpio_interrupt[pin_num].callback(gpio_interrupt[pin_num].context);
} }

View File

@@ -13,12 +13,22 @@
#define FURI_HAL_INTERRUPT_DEFAULT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 5) #define FURI_HAL_INTERRUPT_DEFAULT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 5)
#define FURI_HAL_INTERRUPT_ACCOUNT_START() const uint32_t _isr_start = DWT->CYCCNT;
#define FURI_HAL_INTERRUPT_ACCOUNT_END() \
const uint32_t _time_in_isr = DWT->CYCCNT - _isr_start; \
furi_hal_interrupt.counter_time_in_isr_total += _time_in_isr;
typedef struct { typedef struct {
FuriHalInterruptISR isr; FuriHalInterruptISR isr;
void* context; void* context;
} FuriHalInterruptISRPair; } FuriHalInterruptISRPair;
FuriHalInterruptISRPair furi_hal_interrupt_isr[FuriHalInterruptIdMax] = {0}; typedef struct {
FuriHalInterruptISRPair isr[FuriHalInterruptIdMax];
uint32_t counter_time_in_isr_total;
} FuriHalIterrupt;
static FuriHalIterrupt furi_hal_interrupt = {};
const IRQn_Type furi_hal_interrupt_irqn[FuriHalInterruptIdMax] = { const IRQn_Type furi_hal_interrupt_irqn[FuriHalInterruptIdMax] = {
// TIM1, TIM16, TIM17 // TIM1, TIM16, TIM17
@@ -67,12 +77,16 @@ const IRQn_Type furi_hal_interrupt_irqn[FuriHalInterruptIdMax] = {
[FuriHalInterruptIdLpUart1] = LPUART1_IRQn, [FuriHalInterruptIdLpUart1] = LPUART1_IRQn,
}; };
FURI_ALWAYS_STATIC_INLINE void furi_hal_interrupt_call(FuriHalInterruptId index) { FURI_ALWAYS_INLINE static void furi_hal_interrupt_call(FuriHalInterruptId index) {
furi_check(furi_hal_interrupt_isr[index].isr); const FuriHalInterruptISRPair* isr_descr = &furi_hal_interrupt.isr[index];
furi_hal_interrupt_isr[index].isr(furi_hal_interrupt_isr[index].context); furi_check(isr_descr->isr);
FURI_HAL_INTERRUPT_ACCOUNT_START();
isr_descr->isr(isr_descr->context);
FURI_HAL_INTERRUPT_ACCOUNT_END();
} }
FURI_ALWAYS_STATIC_INLINE void FURI_ALWAYS_INLINE static void
furi_hal_interrupt_enable(FuriHalInterruptId index, uint16_t priority) { furi_hal_interrupt_enable(FuriHalInterruptId index, uint16_t priority) {
NVIC_SetPriority( NVIC_SetPriority(
furi_hal_interrupt_irqn[index], furi_hal_interrupt_irqn[index],
@@ -80,19 +94,19 @@ FURI_ALWAYS_STATIC_INLINE void
NVIC_EnableIRQ(furi_hal_interrupt_irqn[index]); NVIC_EnableIRQ(furi_hal_interrupt_irqn[index]);
} }
FURI_ALWAYS_STATIC_INLINE void furi_hal_interrupt_clear_pending(FuriHalInterruptId index) { FURI_ALWAYS_INLINE static void furi_hal_interrupt_clear_pending(FuriHalInterruptId index) {
NVIC_ClearPendingIRQ(furi_hal_interrupt_irqn[index]); NVIC_ClearPendingIRQ(furi_hal_interrupt_irqn[index]);
} }
FURI_ALWAYS_STATIC_INLINE void furi_hal_interrupt_get_pending(FuriHalInterruptId index) { FURI_ALWAYS_INLINE static void furi_hal_interrupt_get_pending(FuriHalInterruptId index) {
NVIC_GetPendingIRQ(furi_hal_interrupt_irqn[index]); NVIC_GetPendingIRQ(furi_hal_interrupt_irqn[index]);
} }
FURI_ALWAYS_STATIC_INLINE void furi_hal_interrupt_set_pending(FuriHalInterruptId index) { FURI_ALWAYS_INLINE static void furi_hal_interrupt_set_pending(FuriHalInterruptId index) {
NVIC_SetPendingIRQ(furi_hal_interrupt_irqn[index]); NVIC_SetPendingIRQ(furi_hal_interrupt_irqn[index]);
} }
FURI_ALWAYS_STATIC_INLINE void furi_hal_interrupt_disable(FuriHalInterruptId index) { FURI_ALWAYS_INLINE static void furi_hal_interrupt_disable(FuriHalInterruptId index) {
NVIC_DisableIRQ(furi_hal_interrupt_irqn[index]); NVIC_DisableIRQ(furi_hal_interrupt_irqn[index]);
} }
@@ -137,17 +151,18 @@ void furi_hal_interrupt_set_isr_ex(
uint16_t real_priority = FURI_HAL_INTERRUPT_DEFAULT_PRIORITY - priority; uint16_t real_priority = FURI_HAL_INTERRUPT_DEFAULT_PRIORITY - priority;
FuriHalInterruptISRPair* isr_descr = &furi_hal_interrupt.isr[index];
if(isr) { if(isr) {
// Pre ISR set // Pre ISR set
furi_check(furi_hal_interrupt_isr[index].isr == NULL); furi_check(isr_descr->isr == NULL);
} else { } else {
// Pre ISR clear // Pre ISR clear
furi_hal_interrupt_disable(index); furi_hal_interrupt_disable(index);
furi_hal_interrupt_clear_pending(index); furi_hal_interrupt_clear_pending(index);
} }
furi_hal_interrupt_isr[index].isr = isr; isr_descr->isr = isr;
furi_hal_interrupt_isr[index].context = context; isr_descr->context = context;
__DMB(); __DMB();
if(isr) { if(isr) {
@@ -304,27 +319,37 @@ extern void HW_IPCC_Tx_Handler(void);
extern void HW_IPCC_Rx_Handler(void); extern void HW_IPCC_Rx_Handler(void);
void SysTick_Handler(void) { void SysTick_Handler(void) {
FURI_HAL_INTERRUPT_ACCOUNT_START();
furi_hal_os_tick(); furi_hal_os_tick();
FURI_HAL_INTERRUPT_ACCOUNT_END();
} }
void USB_LP_IRQHandler(void) { void USB_LP_IRQHandler(void) {
#ifndef FURI_RAM_EXEC #ifndef FURI_RAM_EXEC
FURI_HAL_INTERRUPT_ACCOUNT_START();
usbd_poll(&udev); usbd_poll(&udev);
FURI_HAL_INTERRUPT_ACCOUNT_END();
#endif #endif
} }
void USB_HP_IRQHandler(void) { //-V524 void USB_HP_IRQHandler(void) { //-V524
#ifndef FURI_RAM_EXEC #ifndef FURI_RAM_EXEC
FURI_HAL_INTERRUPT_ACCOUNT_START();
usbd_poll(&udev); usbd_poll(&udev);
FURI_HAL_INTERRUPT_ACCOUNT_END();
#endif #endif
} }
void IPCC_C1_TX_IRQHandler(void) { void IPCC_C1_TX_IRQHandler(void) {
FURI_HAL_INTERRUPT_ACCOUNT_START();
HW_IPCC_Tx_Handler(); HW_IPCC_Tx_Handler();
FURI_HAL_INTERRUPT_ACCOUNT_END();
} }
void IPCC_C1_RX_IRQHandler(void) { void IPCC_C1_RX_IRQHandler(void) {
FURI_HAL_INTERRUPT_ACCOUNT_START();
HW_IPCC_Rx_Handler(); HW_IPCC_Rx_Handler();
FURI_HAL_INTERRUPT_ACCOUNT_END();
} }
void FPU_IRQHandler(void) { void FPU_IRQHandler(void) {
@@ -499,3 +524,7 @@ const char* furi_hal_interrupt_get_name(uint8_t exception_number) {
return NULL; return NULL;
} }
} }
uint32_t furi_hal_interrupt_get_time_in_isr_total(void) {
return furi_hal_interrupt.counter_time_in_isr_total;
}

View File

@@ -118,6 +118,12 @@ void furi_hal_interrupt_set_isr_ex(
*/ */
const char* furi_hal_interrupt_get_name(uint8_t exception_number); const char* furi_hal_interrupt_get_name(uint8_t exception_number);
/** Get total time(in CPU clocks) spent in ISR
*
* @return total time in CPU clocks
*/
uint32_t furi_hal_interrupt_get_time_in_isr_total(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -19,7 +19,8 @@ static const uint8_t USB_DEVICE_NO_PROTOCOL = 0x0;
#define CCID_TOTAL_SLOTS 1 #define CCID_TOTAL_SLOTS 1
#define CCID_SLOT_INDEX 0 #define CCID_SLOT_INDEX 0
#define CCID_DATABLOCK_SIZE 256 #define CCID_DATABLOCK_SIZE \
(4 + 1 + CCID_SHORT_APDU_SIZE + 1) //APDU Header + Lc + Short APDU size + Le
#define ENDPOINT_DIR_IN 0x80 #define ENDPOINT_DIR_IN 0x80
#define ENDPOINT_DIR_OUT 0x00 #define ENDPOINT_DIR_OUT 0x00
@@ -193,7 +194,8 @@ static void* ccid_set_string_descr(char* str) {
struct usb_string_descriptor* dev_str_desc = malloc(len * 2 + 2); struct usb_string_descriptor* dev_str_desc = malloc(len * 2 + 2);
dev_str_desc->bLength = len * 2 + 2; dev_str_desc->bLength = len * 2 + 2;
dev_str_desc->bDescriptorType = USB_DTYPE_STRING; dev_str_desc->bDescriptorType = USB_DTYPE_STRING;
for(size_t i = 0; i < len; i++) dev_str_desc->wString[i] = str[i]; for(size_t i = 0; i < len; i++)
dev_str_desc->wString[i] = str[i];
return dev_str_desc; return dev_str_desc;
} }

View File

@@ -368,7 +368,8 @@ static void* hid_set_string_descr(char* str) {
struct usb_string_descriptor* dev_str_desc = malloc(len * 2 + 2); struct usb_string_descriptor* dev_str_desc = malloc(len * 2 + 2);
dev_str_desc->bLength = len * 2 + 2; dev_str_desc->bLength = len * 2 + 2;
dev_str_desc->bDescriptorType = USB_DTYPE_STRING; dev_str_desc->bDescriptorType = USB_DTYPE_STRING;
for(size_t i = 0; i < len; i++) dev_str_desc->wString[i] = str[i]; for(size_t i = 0; i < len; i++)
dev_str_desc->wString[i] = str[i];
return dev_str_desc; return dev_str_desc;
} }

View File

@@ -5,6 +5,8 @@
#include "hid_usage_consumer.h" #include "hid_usage_consumer.h"
#include "hid_usage_led.h" #include "hid_usage_led.h"
#define CCID_SHORT_APDU_SIZE (0xFF)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif