mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-10 06:54:19 +00:00
Merge remote-tracking branch 'OFW/dev' into dev
This commit is contained in:
commit
a7ca56cf4e
67 changed files with 737 additions and 418 deletions
126
.clang-format
126
.clang-format
|
@ -3,22 +3,55 @@ Language: Cpp
|
|||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveMacros: None
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: 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
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: false
|
||||
AlignTrailingComments:
|
||||
Kind: Never
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowBreakBeforeNoexceptSpecifier: Never
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
|
@ -27,17 +60,18 @@ AttributeMacros:
|
|||
- __capability
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterExternBlock: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
|
@ -46,33 +80,29 @@ BraceWrapping:
|
|||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAdjacentStringLiterals: true
|
||||
BreakAfterAttributes: Leave
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakArrays: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 99
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
PackConstructorInitializers: BinPack
|
||||
BasedOnStyle: ''
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
|
@ -97,19 +127,30 @@ IncludeCategories:
|
|||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: false
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequires: false
|
||||
IndentRequiresClause: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: true
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: false
|
||||
InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
BinaryMinDigits: 0
|
||||
Decimal: 0
|
||||
DecimalMinDigits: 0
|
||||
Hex: 0
|
||||
HexMinDigits: 0
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
KeepEmptyLinesAtEOF: false
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: DeriveLF
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
|
@ -119,34 +160,44 @@ ObjCBlockIndentWidth: 4
|
|||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PackConstructorInitializers: BinPack
|
||||
PenaltyBreakAssignment: 10
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakScopeResolution: 500
|
||||
PenaltyBreakString: 10
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
QualifierAlignment: Leave
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: false
|
||||
RemoveBracesLLVM: false
|
||||
RemoveParentheses: Leave
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SkipMacroDefinitionBody: false
|
||||
SortIncludes: Never
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: false
|
||||
SortUsingDeclarations: Never
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeJsonColon: false
|
||||
SpaceBeforeParens: Never
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: false
|
||||
|
@ -155,23 +206,26 @@ SpaceBeforeParensOptions:
|
|||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: false
|
||||
AfterOverloadedOperator: false
|
||||
AfterPlacementOperator: true
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInParens: Never
|
||||
SpacesInParensOptions:
|
||||
InCStyleCasts: false
|
||||
InConditionalStatements: false
|
||||
InEmptyParentheses: false
|
||||
Other: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: c++03
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
|
@ -179,8 +233,8 @@ StatementMacros:
|
|||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
VerilogBreakBetweenInstancePorts: true
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
|
|
|
@ -384,8 +384,7 @@ BtTestParam* bt_test_param_add(
|
|||
|
||||
void bt_test_set_rssi(BtTest* bt_test, float rssi) {
|
||||
furi_assert(bt_test);
|
||||
with_view_model(
|
||||
bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
|
||||
with_view_model(bt_test->view, BtTestModel * model, { model->rssi = rssi; }, true);
|
||||
}
|
||||
|
||||
void bt_test_set_packets_tx(BtTest* bt_test, uint32_t packets_num) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "iso7816_callbacks.h"
|
||||
#include "iso7816_t0_apdu.h"
|
||||
#include "iso7816_atr.h"
|
||||
#include "iso7816_response.h"
|
||||
|
||||
typedef enum {
|
||||
EventTypeInput,
|
||||
|
@ -118,6 +119,76 @@ static const CcidCallbacks ccid_cb = {
|
|||
ccid_xfr_datablock_callback,
|
||||
};
|
||||
|
||||
//Instruction 1: returns an OK response unconditionally
|
||||
//APDU example: 0x01:0x01:0x00:0x00
|
||||
//response: SW1=0x90, SW2=0x00
|
||||
void handle_instruction_01(ISO7816_Response_APDU* responseAPDU) {
|
||||
responseAPDU->DataLen = 0;
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_OK);
|
||||
}
|
||||
|
||||
//Instruction 2: expect command with no body, replies wit with a body with two bytes
|
||||
//APDU example: 0x01:0x02:0x00:0x00:0x02
|
||||
//response: 'bc' (0x62, 0x63) SW1=0x90, SW2=0x00
|
||||
void handle_instruction_02(
|
||||
uint8_t p1,
|
||||
uint8_t p2,
|
||||
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) {
|
||||
//minimum valid ATR: https://smartcard-atr.apdu.fr/parse?ATR=3B+00
|
||||
atr->TS = 0x3B;
|
||||
|
@ -125,48 +196,38 @@ void iso7816_answer_to_reset(Iso7816Atr* atr) {
|
|||
}
|
||||
|
||||
void iso7816_process_command(
|
||||
const struct ISO7816_Command_APDU* commandAPDU,
|
||||
struct ISO7816_Response_APDU* responseAPDU,
|
||||
const uint8_t* commandApduDataBuffer,
|
||||
uint8_t commandApduDataBufferLen,
|
||||
uint8_t* responseApduDataBuffer,
|
||||
uint8_t* responseApduDataBufferLen) {
|
||||
const ISO7816_Command_APDU* commandAPDU,
|
||||
ISO7816_Response_APDU* responseAPDU) {
|
||||
//example 1: sends a command with no body, receives a response with no body
|
||||
//sends APDU 0x01:0x02:0x00:0x00
|
||||
//sends APDU 0x01:0x01:0x00:0x00
|
||||
//receives SW1=0x90, SW2=0x00
|
||||
if(commandAPDU->CLA == 0x01 && commandAPDU->INS == 0x01) {
|
||||
responseAPDU->SW1 = 0x90;
|
||||
responseAPDU->SW2 = 0x00;
|
||||
}
|
||||
//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;
|
||||
if(commandAPDU->CLA == 0x01) {
|
||||
switch(commandAPDU->INS) {
|
||||
case 0x01:
|
||||
handle_instruction_01(responseAPDU);
|
||||
break;
|
||||
case 0x02:
|
||||
handle_instruction_02(
|
||||
commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, commandAPDU->Le, responseAPDU);
|
||||
break;
|
||||
case 0x03:
|
||||
handle_instruction_03(commandAPDU->P1, commandAPDU->P2, commandAPDU->Lc, responseAPDU);
|
||||
break;
|
||||
case 0x04:
|
||||
handle_instruction_04(
|
||||
commandAPDU->P1,
|
||||
commandAPDU->P2,
|
||||
commandAPDU->Lc,
|
||||
commandAPDU->Le,
|
||||
commandAPDU->Data,
|
||||
responseAPDU);
|
||||
break;
|
||||
default:
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED);
|
||||
}
|
||||
} else {
|
||||
responseAPDU->SW1 = 0x6A;
|
||||
responseAPDU->SW2 = 0x00;
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_CLASS_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
116
applications/debug/ccid_test/client/ccid_client.py
Normal file
116
applications/debug/ccid_test/client/ccid_client.py
Normal 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()
|
2
applications/debug/ccid_test/client/requirements.txt
Normal file
2
applications/debug/ccid_test/client/requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
pyscard
|
||||
# or sudo apt install python3-pyscard
|
|
@ -1,9 +1,6 @@
|
|||
#ifndef _ISO7816_ATR_H_
|
||||
#define _ISO7816_ATR_H_
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
uint8_t TS;
|
||||
uint8_t T0;
|
||||
} Iso7816Atr;
|
||||
|
||||
#endif //_ISO7816_ATR_H_
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
// transforms low level calls such as XFRCallback or ICC Power on to a structured one
|
||||
// an application can register these calls and listen for the callbacks defined in Iso7816Callbacks
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include "iso7816_t0_apdu.h"
|
||||
#include "iso7816_atr.h"
|
||||
#include "iso7816_callbacks.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <furi.h>
|
||||
|
||||
#define ISO7816_RESPONSE_BUFFER_SIZE 255
|
||||
#include "iso7816_response.h"
|
||||
|
||||
static Iso7816Callbacks* callbacks = NULL;
|
||||
|
||||
static uint8_t commandApduBuffer[sizeof(ISO7816_Command_APDU) + CCID_SHORT_APDU_SIZE];
|
||||
static uint8_t responseApduBuffer[sizeof(ISO7816_Response_APDU) + CCID_SHORT_APDU_SIZE];
|
||||
|
||||
void iso7816_set_callbacks(Iso7816Callbacks* cb) {
|
||||
callbacks = cb;
|
||||
}
|
||||
|
@ -36,41 +40,26 @@ void iso7816_xfr_datablock_callback(
|
|||
uint32_t pcToReaderDataBlockLen,
|
||||
uint8_t* readerToPcDataBlock,
|
||||
uint32_t* readerToPcDataBlockLen) {
|
||||
struct ISO7816_Response_APDU responseAPDU;
|
||||
uint8_t responseApduDataBuffer[ISO7816_RESPONSE_BUFFER_SIZE];
|
||||
uint8_t responseApduDataBufferLen = 0;
|
||||
ISO7816_Response_APDU* responseAPDU = (ISO7816_Response_APDU*)&responseApduBuffer;
|
||||
|
||||
if(callbacks != NULL) {
|
||||
struct ISO7816_Command_APDU commandAPDU;
|
||||
ISO7816_Command_APDU* commandAPDU = (ISO7816_Command_APDU*)&commandApduBuffer;
|
||||
|
||||
const uint8_t* commandApduDataBuffer = NULL;
|
||||
uint8_t commandApduDataBufferLen = 0;
|
||||
uint8_t result =
|
||||
iso7816_read_command_apdu(commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen);
|
||||
|
||||
iso7816_read_command_apdu(&commandAPDU, pcToReaderDataBlock, pcToReaderDataBlockLen);
|
||||
if(result == ISO7816_READ_COMMAND_APDU_OK) {
|
||||
callbacks->iso7816_process_command(commandAPDU, responseAPDU);
|
||||
|
||||
if(commandAPDU.Lc > 0) {
|
||||
commandApduDataBufferLen = commandAPDU.Lc;
|
||||
commandApduDataBuffer = &pcToReaderDataBlock[5];
|
||||
furi_assert(responseAPDU->DataLen < CCID_SHORT_APDU_SIZE);
|
||||
} else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE) {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LE);
|
||||
} else if(result == ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH) {
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_WRONG_LENGTH);
|
||||
}
|
||||
|
||||
callbacks->iso7816_process_command(
|
||||
&commandAPDU,
|
||||
&responseAPDU,
|
||||
commandApduDataBuffer,
|
||||
commandApduDataBufferLen,
|
||||
responseApduDataBuffer,
|
||||
&responseApduDataBufferLen);
|
||||
|
||||
} else {
|
||||
//class not supported
|
||||
responseAPDU.SW1 = 0x6E;
|
||||
responseAPDU.SW2 = 0x00;
|
||||
iso7816_set_response(responseAPDU, ISO7816_RESPONSE_INTERNAL_EXCEPTION);
|
||||
}
|
||||
|
||||
iso7816_write_response_apdu(
|
||||
&responseAPDU,
|
||||
readerToPcDataBlock,
|
||||
readerToPcDataBlockLen,
|
||||
responseApduDataBuffer,
|
||||
responseApduDataBufferLen);
|
||||
iso7816_write_response_apdu(responseAPDU, readerToPcDataBlock, readerToPcDataBlockLen);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#ifndef _ISO7816_CALLBACKS_H_
|
||||
#define _ISO7816_CALLBACKS_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "iso7816_atr.h"
|
||||
|
@ -8,12 +7,8 @@
|
|||
typedef struct {
|
||||
void (*iso7816_answer_to_reset)(Iso7816Atr* atr);
|
||||
void (*iso7816_process_command)(
|
||||
const struct ISO7816_Command_APDU* command,
|
||||
struct ISO7816_Response_APDU* response,
|
||||
const uint8_t* commandApduDataBuffer,
|
||||
uint8_t commandApduDataBufferLen,
|
||||
uint8_t* responseApduDataBuffer,
|
||||
uint8_t* responseApduDataBufferLen);
|
||||
const ISO7816_Command_APDU* command,
|
||||
ISO7816_Response_APDU* response);
|
||||
} Iso7816Callbacks;
|
||||
|
||||
void iso7816_set_callbacks(Iso7816Callbacks* cb);
|
||||
|
@ -23,6 +18,4 @@ void iso7816_xfr_datablock_callback(
|
|||
const uint8_t* dataBlock,
|
||||
uint32_t dataBlockLen,
|
||||
uint8_t* responseDataBlock,
|
||||
uint32_t* responseDataBlockLen);
|
||||
|
||||
#endif //_ISO7816_CALLBACKS_H_
|
||||
uint32_t* responseDataBlockLen);
|
8
applications/debug/ccid_test/iso7816_response.c
Normal file
8
applications/debug/ccid_test/iso7816_response.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include <stdint.h>
|
||||
#include "iso7816_t0_apdu.h"
|
||||
#include "iso7816_response.h"
|
||||
|
||||
void iso7816_set_response(ISO7816_Response_APDU* responseAPDU, uint16_t responseCode) {
|
||||
responseAPDU->SW1 = (responseCode >> (8 * 1)) & 0xff;
|
||||
responseAPDU->SW2 = (responseCode >> (8 * 0)) & 0xff;
|
||||
}
|
12
applications/debug/ccid_test/iso7816_response.h
Normal file
12
applications/debug/ccid_test/iso7816_response.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#define ISO7816_RESPONSE_OK 0x9000
|
||||
|
||||
#define ISO7816_RESPONSE_WRONG_LENGTH 0x6700
|
||||
#define ISO7816_RESPONSE_WRONG_PARAMETERS_P1_P2 0x6A00
|
||||
#define ISO7816_RESPONSE_WRONG_LE 0x6C00
|
||||
#define ISO7816_RESPONSE_INSTRUCTION_NOT_SUPPORTED 0x6D00
|
||||
#define ISO7816_RESPONSE_CLASS_NOT_SUPPORTED 0x6E00
|
||||
#define ISO7816_RESPONSE_INTERNAL_EXCEPTION 0x6F00
|
||||
|
||||
void iso7816_set_response(ISO7816_Response_APDU* responseAPDU, uint16_t responseCode);
|
|
@ -2,37 +2,73 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "iso7816_t0_apdu.h"
|
||||
|
||||
//reads dataBuffer with dataLen size, translate it into a ISO7816_Command_APDU type
|
||||
//extra data will be pointed to commandDataBuffer
|
||||
void iso7816_read_command_apdu(
|
||||
struct ISO7816_Command_APDU* command,
|
||||
uint8_t iso7816_read_command_apdu(
|
||||
ISO7816_Command_APDU* command,
|
||||
const uint8_t* dataBuffer,
|
||||
uint32_t dataLen) {
|
||||
UNUSED(dataLen);
|
||||
|
||||
command->CLA = dataBuffer[0];
|
||||
command->INS = dataBuffer[1];
|
||||
command->P1 = dataBuffer[2];
|
||||
command->P2 = dataBuffer[3];
|
||||
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(
|
||||
const struct ISO7816_Response_APDU* response,
|
||||
const ISO7816_Response_APDU* response,
|
||||
uint8_t* readerToPcDataBlock,
|
||||
uint32_t* readerToPcDataBlockLen,
|
||||
uint8_t* responseDataBuffer,
|
||||
uint32_t responseDataLen) {
|
||||
uint32_t* readerToPcDataBlockLen) {
|
||||
uint32_t responseDataBufferIndex = 0;
|
||||
|
||||
//response body
|
||||
if(responseDataLen > 0) {
|
||||
while(responseDataBufferIndex < responseDataLen) {
|
||||
readerToPcDataBlock[responseDataBufferIndex] =
|
||||
responseDataBuffer[responseDataBufferIndex];
|
||||
if(response->DataLen > 0) {
|
||||
while(responseDataBufferIndex < response->DataLen) {
|
||||
readerToPcDataBlock[responseDataBufferIndex] = response->Data[responseDataBufferIndex];
|
||||
responseDataBufferIndex++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#ifndef _ISO7816_T0_APDU_H_
|
||||
#define _ISO7816_T0_APDU_H_
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "iso7816_atr.h"
|
||||
#include "core/common_defines.h"
|
||||
|
||||
struct ISO7816_Command_APDU {
|
||||
#define ISO7816_READ_COMMAND_APDU_OK 0
|
||||
#define ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LE 1
|
||||
#define ISO7816_READ_COMMAND_APDU_ERROR_WRONG_LENGTH 2
|
||||
|
||||
typedef struct {
|
||||
//header
|
||||
uint8_t CLA;
|
||||
uint8_t INS;
|
||||
|
@ -13,24 +16,27 @@ struct ISO7816_Command_APDU {
|
|||
uint8_t P2;
|
||||
|
||||
//body
|
||||
uint8_t Lc;
|
||||
uint8_t Le;
|
||||
} FURI_PACKED;
|
||||
uint16_t Lc; //data length
|
||||
uint16_t Le; //maximum response data length expected by client
|
||||
|
||||
struct ISO7816_Response_APDU {
|
||||
//Le can have value of 0x00, which actually meand 0x100 = 256
|
||||
bool LePresent;
|
||||
uint8_t Data[0];
|
||||
} FURI_PACKED ISO7816_Command_APDU;
|
||||
|
||||
typedef struct {
|
||||
uint8_t SW1;
|
||||
uint8_t SW2;
|
||||
} FURI_PACKED;
|
||||
uint16_t DataLen;
|
||||
uint8_t Data[0];
|
||||
} FURI_PACKED ISO7816_Response_APDU;
|
||||
|
||||
void iso7816_answer_to_reset(Iso7816Atr* atr);
|
||||
void iso7816_read_command_apdu(
|
||||
struct ISO7816_Command_APDU* command,
|
||||
const uint8_t* dataBuffer,
|
||||
uint32_t dataLen);
|
||||
uint8_t iso7816_read_command_apdu(
|
||||
ISO7816_Command_APDU* command,
|
||||
const uint8_t* pcToReaderDataBlock,
|
||||
uint32_t pcToReaderDataBlockLen);
|
||||
void iso7816_write_response_apdu(
|
||||
const struct ISO7816_Response_APDU* response,
|
||||
const ISO7816_Response_APDU* response,
|
||||
uint8_t* readerToPcDataBlock,
|
||||
uint32_t* readerToPcDataBlockLen,
|
||||
uint8_t* responseDataBuffer,
|
||||
uint32_t responseDataLen);
|
||||
#endif //_ISO7816_T0_APDU_H_
|
||||
uint32_t* readerToPcDataBlockLen);
|
||||
|
|
|
@ -150,8 +150,7 @@ static void view_display_test_exit(void* context) {
|
|||
|
||||
static void view_display_test_timer_callback(void* context) {
|
||||
ViewDisplayTest* instance = context;
|
||||
with_view_model(
|
||||
instance->view, ViewDisplayTestModel * model, { model->counter++; }, true);
|
||||
with_view_model(instance->view, ViewDisplayTestModel * model, { model->counter++; }, true);
|
||||
}
|
||||
|
||||
ViewDisplayTest* view_display_test_alloc(void) {
|
||||
|
|
|
@ -223,16 +223,14 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view) {
|
|||
|
||||
uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view) {
|
||||
uint32_t result = false;
|
||||
with_view_model(
|
||||
tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false);
|
||||
with_view_model(tune_view->view, LfRfidTuneViewModel * model, { result = model->ARR; }, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) {
|
||||
uint32_t result = false;
|
||||
with_view_model(
|
||||
tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false);
|
||||
with_view_model(tune_view->view, LfRfidTuneViewModel * model, { result = model->CCR; }, false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -206,8 +206,7 @@ static int32_t uart_echo_worker(void* context) {
|
|||
} while(length > 0);
|
||||
|
||||
notification_message(app->notification, &sequence_notification);
|
||||
with_view_model(
|
||||
app->view, UartDumpModel * model, { UNUSED(model); }, true);
|
||||
with_view_model(app->view, UartDumpModel * model, { UNUSED(model); }, true);
|
||||
}
|
||||
|
||||
if(events & WorkerEventRxIdle) {
|
||||
|
|
|
@ -74,7 +74,8 @@ MU_TEST(furi_hal_i2c_int_3b) {
|
|||
DATA_SIZE - 1,
|
||||
LP5562_I2C_TIMEOUT);
|
||||
mu_assert(ret, "4 rx failed");
|
||||
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "4 invalid data_many");
|
||||
for(size_t i = 0; i < DATA_SIZE; i++)
|
||||
mu_assert(data_many[i] != 0, "4 invalid data_many");
|
||||
|
||||
ret = furi_hal_i2c_tx(
|
||||
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, DATA_SIZE, LP5562_I2C_TIMEOUT);
|
||||
|
@ -90,7 +91,8 @@ MU_TEST(furi_hal_i2c_int_3b) {
|
|||
DATA_SIZE - 1,
|
||||
LP5562_I2C_TIMEOUT);
|
||||
mu_assert(ret, "7 rx failed");
|
||||
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "7 invalid data_many");
|
||||
for(size_t i = 0; i < DATA_SIZE; i++)
|
||||
mu_assert(data_many[i] != 0, "7 invalid data_many");
|
||||
}
|
||||
|
||||
MU_TEST(furi_hal_i2c_int_1b_fail) {
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
|
||||
#define LF_RFID_READ_TIMING_MULTIPLIER 8
|
||||
|
||||
#define EM_TEST_DATA \
|
||||
{ 0x58, 0x00, 0x85, 0x64, 0x02 }
|
||||
#define EM_TEST_DATA {0x58, 0x00, 0x85, 0x64, 0x02}
|
||||
#define EM_TEST_DATA_SIZE 5
|
||||
#define EM_TEST_EMULATION_TIMINGS_COUNT (64 * 2)
|
||||
|
||||
|
@ -21,8 +20,7 @@ const int8_t em_test_timings[EM_TEST_EMULATION_TIMINGS_COUNT] = {
|
|||
-32, 32, 32, -32, -32, 32, -32, 32, -32, 32, -32, 32, -32, 32,
|
||||
};
|
||||
|
||||
#define HID10301_TEST_DATA \
|
||||
{ 0x8D, 0x48, 0xA8 }
|
||||
#define HID10301_TEST_DATA {0x8D, 0x48, 0xA8}
|
||||
#define HID10301_TEST_DATA_SIZE 3
|
||||
#define HID10301_TEST_EMULATION_TIMINGS_COUNT (541 * 2)
|
||||
|
||||
|
@ -71,8 +69,7 @@ const int8_t hid10301_test_timings[HID10301_TEST_EMULATION_TIMINGS_COUNT] = {
|
|||
5, -5, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4, 4, -4,
|
||||
};
|
||||
|
||||
#define IOPROX_XSF_TEST_DATA \
|
||||
{ 0x65, 0x01, 0x05, 0x39 }
|
||||
#define IOPROX_XSF_TEST_DATA {0x65, 0x01, 0x05, 0x39}
|
||||
#define IOPROX_XSF_TEST_DATA_SIZE 4
|
||||
#define IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT (468 * 2)
|
||||
|
||||
|
@ -116,8 +113,7 @@ const int8_t ioprox_xsf_test_timings[IOPROX_XSF_TEST_EMULATION_TIMINGS_COUNT] =
|
|||
};
|
||||
|
||||
#define INDALA26_EMULATION_TIMINGS_COUNT (1024 * 2)
|
||||
#define INDALA26_TEST_DATA \
|
||||
{ 0x3B, 0x73, 0x64, 0xA8 }
|
||||
#define INDALA26_TEST_DATA {0x3B, 0x73, 0x64, 0xA8}
|
||||
#define INDALA26_TEST_DATA_SIZE 4
|
||||
|
||||
const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = {
|
||||
|
@ -209,8 +205,7 @@ const int8_t indala26_test_timings[INDALA26_EMULATION_TIMINGS_COUNT] = {
|
|||
-1, 1, -1, 1, -1, 1, -1, 1,
|
||||
};
|
||||
|
||||
#define FDXB_TEST_DATA \
|
||||
{ 0x44, 0x88, 0x23, 0xF2, 0x5A, 0x6F, 0x00, 0x01, 0x00, 0x00, 0x00 }
|
||||
#define FDXB_TEST_DATA {0x44, 0x88, 0x23, 0xF2, 0x5A, 0x6F, 0x00, 0x01, 0x00, 0x00, 0x00}
|
||||
#define FDXB_TEST_DATA_SIZE 11
|
||||
#define FDXB_TEST_EMULATION_TIMINGS_COUNT (206)
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ typedef enum {
|
|||
typedef struct {
|
||||
Storage* storage;
|
||||
File* directory;
|
||||
FuriString* file_path;
|
||||
char file_name[256];
|
||||
FlipperApplication* app;
|
||||
} NfcSupportedCardsLoadContext;
|
||||
|
@ -86,7 +85,6 @@ static NfcSupportedCardsLoadContext* nfc_supported_cards_load_context_alloc(void
|
|||
|
||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
||||
instance->directory = storage_file_alloc(instance->storage);
|
||||
instance->file_path = furi_string_alloc();
|
||||
|
||||
if(!storage_dir_open(instance->directory, NFC_SUPPORTED_CARDS_PLUGINS_PATH)) {
|
||||
FURI_LOG_D(TAG, "Failed to open directory: %s", NFC_SUPPORTED_CARDS_PLUGINS_PATH);
|
||||
|
@ -100,8 +98,6 @@ static void nfc_supported_cards_load_context_free(NfcSupportedCardsLoadContext*
|
|||
flipper_application_free(instance->app);
|
||||
}
|
||||
|
||||
furi_string_free(instance->file_path);
|
||||
|
||||
storage_dir_close(instance->directory);
|
||||
storage_file_free(instance->directory);
|
||||
|
||||
|
@ -117,15 +113,13 @@ static const NfcSupportedCardsPlugin* nfc_supported_cards_get_plugin(
|
|||
furi_assert(name);
|
||||
|
||||
const NfcSupportedCardsPlugin* plugin = NULL;
|
||||
FuriString* plugin_path = furi_string_alloc_printf(
|
||||
"%s/%s%s", NFC_SUPPORTED_CARDS_PLUGINS_PATH, name, NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX);
|
||||
do {
|
||||
if(instance->app) flipper_application_free(instance->app);
|
||||
instance->app = flipper_application_alloc(instance->storage, api_interface);
|
||||
|
||||
// Reconstruct 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)) !=
|
||||
if(flipper_application_preload(instance->app, furi_string_get_cstr(plugin_path)) !=
|
||||
FlipperApplicationPreloadStatusSuccess)
|
||||
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;
|
||||
} while(false);
|
||||
furi_string_free(plugin_path);
|
||||
|
||||
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)))
|
||||
break;
|
||||
|
||||
furi_string_set(instance->file_path, instance->file_name);
|
||||
if(!furi_string_end_with_str(instance->file_path, NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX))
|
||||
continue;
|
||||
const size_t suffix_len = strlen(NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX);
|
||||
const size_t file_name_len = strlen(instance->file_name);
|
||||
if(file_name_len <= suffix_len) break;
|
||||
|
||||
size_t trim_suffix =
|
||||
furi_string_size(instance->file_path) - strlen(NFC_SUPPORTED_CARDS_PLUGIN_SUFFIX);
|
||||
instance->file_name[trim_suffix] = '\0';
|
||||
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;
|
||||
|
||||
// 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
|
||||
|
|
|
@ -97,6 +97,5 @@ void u2f_view_set_ok_callback(U2fView* u2f, U2fOkCallback callback, void* contex
|
|||
}
|
||||
|
||||
void u2f_view_set_state(U2fView* u2f, U2fViewMsg msg) {
|
||||
with_view_model(
|
||||
u2f->view, U2fModel * model, { model->display_msg = msg; }, true);
|
||||
with_view_model(u2f->view, U2fModel * model, { model->display_msg = msg; }, true);
|
||||
}
|
||||
|
|
|
@ -65,7 +65,8 @@ void cli_command_help(Cli* cli, FuriString* args, void* context) {
|
|||
CliCommandTree_it(it_left, cli->commands);
|
||||
CliCommandTree_it_t it_right;
|
||||
CliCommandTree_it(it_right, cli->commands);
|
||||
for(size_t i = 0; i < commands_count_mid; i++) CliCommandTree_next(it_right);
|
||||
for(size_t i = 0; i < commands_count_mid; i++)
|
||||
CliCommandTree_next(it_right);
|
||||
|
||||
// Iterate throw tree
|
||||
for(size_t i = 0; i < commands_count_mid; i++) {
|
||||
|
@ -408,8 +409,9 @@ static void cli_command_top(Cli* cli, FuriString* args, void* context) {
|
|||
|
||||
uint32_t uptime = tick / furi_kernel_get_tick_frequency();
|
||||
printf(
|
||||
"Threads: %zu, Uptime: %luh%lum%lus\r\n",
|
||||
"Threads: %zu, ISR Time: %0.2f%%, Uptime: %luh%lum%lus\r\n",
|
||||
furi_thread_list_size(thread_list),
|
||||
(double)furi_thread_list_get_isr_time(thread_list),
|
||||
uptime / 60 / 60,
|
||||
uptime / 60 % 60,
|
||||
uptime % 60);
|
||||
|
|
|
@ -321,8 +321,7 @@ void button_menu_reset(ButtonMenu* button_menu) {
|
|||
void button_menu_set_header(ButtonMenu* button_menu, const char* header) {
|
||||
furi_check(button_menu);
|
||||
|
||||
with_view_model(
|
||||
button_menu->view, ButtonMenuModel * model, { model->header = header; }, true);
|
||||
with_view_model(button_menu->view, ButtonMenuModel * model, { model->header = header; }, true);
|
||||
}
|
||||
|
||||
ButtonMenuItem* button_menu_add_item(
|
||||
|
|
|
@ -868,6 +868,5 @@ void byte_input_set_result_callback(
|
|||
void byte_input_set_header_text(ByteInput* byte_input, const char* text) {
|
||||
furi_check(byte_input);
|
||||
|
||||
with_view_model(
|
||||
byte_input->view, ByteInputModel * model, { model->header = text; }, true);
|
||||
with_view_model(byte_input->view, ByteInputModel * model, { model->header = text; }, true);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
furi_check(dialog_ex);
|
||||
with_view_model(
|
||||
dialog_ex->view, DialogExModel * model, { model->left_text = text; }, true);
|
||||
with_view_model(dialog_ex->view, DialogExModel * model, { model->left_text = text; }, true);
|
||||
}
|
||||
|
||||
void dialog_ex_set_center_button_text(DialogEx* dialog_ex, const char* text) {
|
||||
furi_check(dialog_ex);
|
||||
with_view_model(
|
||||
dialog_ex->view, DialogExModel * model, { model->center_text = text; }, true);
|
||||
with_view_model(dialog_ex->view, DialogExModel * model, { model->center_text = text; }, true);
|
||||
}
|
||||
|
||||
void dialog_ex_set_right_button_text(DialogEx* dialog_ex, const char* text) {
|
||||
furi_check(dialog_ex);
|
||||
with_view_model(
|
||||
dialog_ex->view, DialogExModel * model, { model->right_text = text; }, true);
|
||||
with_view_model(dialog_ex->view, DialogExModel * model, { model->right_text = text; }, true);
|
||||
}
|
||||
|
||||
void dialog_ex_reset(DialogEx* dialog_ex) {
|
||||
|
|
|
@ -174,15 +174,13 @@ static void browser_long_load_cb(void* context);
|
|||
static void file_browser_scroll_timer_callback(void* context) {
|
||||
furi_check(context);
|
||||
FileBrowser* browser = context;
|
||||
with_view_model(
|
||||
browser->view, FileBrowserModel * model, { model->scroll_counter++; }, true);
|
||||
with_view_model(browser->view, FileBrowserModel * model, { model->scroll_counter++; }, true);
|
||||
}
|
||||
|
||||
static void file_browser_view_enter_callback(void* context) {
|
||||
furi_check(context);
|
||||
FileBrowser* browser = context;
|
||||
with_view_model(
|
||||
browser->view, FileBrowserModel * model, { model->scroll_counter = 0; }, true);
|
||||
with_view_model(browser->view, FileBrowserModel * model, { model->scroll_counter = 0; }, true);
|
||||
furi_timer_start(browser->scroll_timer, SCROLL_INTERVAL);
|
||||
}
|
||||
|
||||
|
|
|
@ -149,8 +149,7 @@ void menu_free(Menu* menu) {
|
|||
furi_check(menu);
|
||||
|
||||
menu_reset(menu);
|
||||
with_view_model(
|
||||
menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false);
|
||||
with_view_model(menu->view, MenuModel * model, { MenuItemArray_clear(model->items); }, false);
|
||||
view_free(menu->view);
|
||||
|
||||
free(menu);
|
||||
|
|
|
@ -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) {
|
||||
furi_check(text_box);
|
||||
|
||||
with_view_model(
|
||||
text_box->view, TextBoxModel * model, { model->font = font; }, true);
|
||||
with_view_model(text_box->view, TextBoxModel * model, { model->font = font; }, true);
|
||||
}
|
||||
|
||||
void text_box_set_focus(TextBox* text_box, TextBoxFocus focus) {
|
||||
furi_check(text_box);
|
||||
|
||||
with_view_model(
|
||||
text_box->view, TextBoxModel * model, { model->focus = focus; }, true);
|
||||
with_view_model(text_box->view, TextBoxModel * model, { model->focus = focus; }, true);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
furi_check(text_input);
|
||||
with_view_model(
|
||||
text_input->view, TextInputModel * model, { model->header = text; }, true);
|
||||
with_view_model(text_input->view, TextInputModel * model, { model->header = text; }, true);
|
||||
}
|
||||
|
|
|
@ -104,7 +104,8 @@ void view_holder_start(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);
|
||||
}
|
||||
|
||||
|
|
|
@ -137,7 +137,8 @@ int32_t input_srv(void* p) {
|
|||
} else {
|
||||
event.sequence_counter = pin_states[i].counter;
|
||||
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) {
|
||||
event.type = InputTypeShort;
|
||||
furi_pubsub_publish(event_pubsub, &event);
|
||||
|
|
|
@ -400,8 +400,7 @@ HidKeyboard* hid_keyboard_alloc(Hid* bt_hid) {
|
|||
view_set_draw_callback(hid_keyboard->view, hid_keyboard_draw_callback);
|
||||
view_set_input_callback(hid_keyboard->view, hid_keyboard_input_callback);
|
||||
|
||||
with_view_model(
|
||||
hid_keyboard->view, HidKeyboardModel * model, { model->y = 1; }, true);
|
||||
with_view_model(hid_keyboard->view, HidKeyboardModel * model, { model->y = 1; }, true);
|
||||
|
||||
return hid_keyboard;
|
||||
}
|
||||
|
|
|
@ -237,7 +237,10 @@ typedef struct {
|
|||
} UpdateTaskStageGroupMap;
|
||||
|
||||
#define STAGE_DEF(GROUP, WEIGHT) \
|
||||
{ .group = (GROUP), .weight = (WEIGHT), }
|
||||
{ \
|
||||
.group = (GROUP), \
|
||||
.weight = (WEIGHT), \
|
||||
}
|
||||
|
||||
static const UpdateTaskStageGroupMap update_task_stage_progress[] = {
|
||||
[UpdateTaskStageProgress] = STAGE_DEF(UpdateTaskStageGroupMisc, 0),
|
||||
|
|
|
@ -29,8 +29,8 @@ extern "C" {
|
|||
#define FURI_PACKED __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#ifndef FURI_ALWAYS_STATIC_INLINE
|
||||
#define FURI_ALWAYS_STATIC_INLINE __attribute__((always_inline)) static inline
|
||||
#ifndef FURI_ALWAYS_INLINE
|
||||
#define FURI_ALWAYS_INLINE __attribute__((always_inline)) inline
|
||||
#endif
|
||||
|
||||
#ifndef FURI_IS_IRQ_MASKED
|
||||
|
|
|
@ -17,7 +17,7 @@ extern "C" {
|
|||
/**
|
||||
* @brief Furi string failure constant.
|
||||
*/
|
||||
#define FURI_STRING_FAILURE ((size_t)-1)
|
||||
#define FURI_STRING_FAILURE ((size_t) - 1)
|
||||
|
||||
/**
|
||||
* @brief Furi string primitive.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "thread_list.h"
|
||||
#include "check.h"
|
||||
|
||||
#include <furi_hal_interrupt.h>
|
||||
|
||||
#include <m-array.h>
|
||||
#include <m-dict.h>
|
||||
|
||||
|
@ -23,6 +25,8 @@ struct FuriThreadList {
|
|||
FuriThreadListItemDict_t search;
|
||||
uint32_t runtime_previous;
|
||||
uint32_t runtime_current;
|
||||
uint32_t isr_previous;
|
||||
uint32_t isr_current;
|
||||
};
|
||||
|
||||
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_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(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;
|
||||
}
|
|
@ -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);
|
||||
|
||||
/** 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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -4,7 +4,7 @@ public:
|
|||
virtual void on_enter(TApp* app, bool need_restore) = 0;
|
||||
virtual bool on_event(TApp* app, typename TApp::Event* event) = 0;
|
||||
virtual void on_exit(TApp* app) = 0;
|
||||
virtual ~GenericScene(){};
|
||||
virtual ~GenericScene() {};
|
||||
|
||||
private:
|
||||
};
|
||||
|
|
|
@ -175,7 +175,8 @@ public:
|
|||
bool switch_to_previous_scene(uint8_t count = 1) {
|
||||
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;
|
||||
|
||||
|
@ -198,7 +199,8 @@ public:
|
|||
*
|
||||
*/
|
||||
~SceneController() {
|
||||
for(auto& it : scenes) delete it.second;
|
||||
for(auto& it : scenes)
|
||||
delete it.second;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
class GenericViewModule {
|
||||
public:
|
||||
GenericViewModule(){};
|
||||
virtual ~GenericViewModule(){};
|
||||
GenericViewModule() {};
|
||||
virtual ~GenericViewModule() {};
|
||||
virtual View* get_view() = 0;
|
||||
virtual void clean() = 0;
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TOPBIT(X) (1 << ((X)-1))
|
||||
#define TOPBIT(X) (1 << ((X) - 1))
|
||||
|
||||
typedef enum {
|
||||
BitLibParityEven,
|
||||
|
|
|
@ -137,7 +137,8 @@ bool protocol_pac_stanley_encoder_start(ProtocolPACStanley* protocol) {
|
|||
uint8_to_hex_chars(protocol->data, &idbytes[2], 8);
|
||||
|
||||
// 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[1] = 0x20; // start + reflect8(STX)
|
||||
|
|
|
@ -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) {
|
||||
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;
|
||||
return x ^ type;
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit afc499f9a410fc9bbf6c9c48cdd8d8b199d49eb4
|
||||
Subproject commit 6cfe48d6f1593f8fa5c0f90437f5e6522587745e
|
|
@ -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) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -190,7 +190,8 @@ void nfc_poller_start_ex(NfcPoller* instance, NfcGenericCallbackEx callback, voi
|
|||
NfcProtocol parent_protocol = nfc_protocol_get_parent(instance->protocol);
|
||||
if(parent_protocol != NfcProtocolInvalid) {
|
||||
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);
|
||||
}
|
||||
|
@ -254,7 +255,8 @@ bool nfc_poller_detect(NfcPoller* instance) {
|
|||
NfcPollerListElement* iter = 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -155,7 +155,8 @@ static void mf_ultralight_format_mirror_data(
|
|||
FuriString* str,
|
||||
const uint8_t* const data,
|
||||
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) {
|
||||
|
|
|
@ -224,7 +224,8 @@ void onewire_host_target_search(OneWireHost* host, uint8_t family_code) {
|
|||
furi_check(host);
|
||||
|
||||
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_family_discrepancy = 0;
|
||||
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;
|
||||
search_result = false;
|
||||
} 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;
|
||||
|
|
|
@ -616,7 +616,8 @@ static size_t _etoa(
|
|||
FLAGS_ZEROPAD | FLAGS_PLUS);
|
||||
// might need to right-pad spaces
|
||||
if(flags & FLAGS_LEFT) {
|
||||
while(idx - start_idx < width) out(' ', buffer, idx++, maxlen);
|
||||
while(idx - start_idx < width)
|
||||
out(' ', buffer, idx++, maxlen);
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
|
|
|
@ -176,7 +176,8 @@ static bool keys_dict_get_next_key_str(KeysDict* instance, FuriString* 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;
|
||||
}
|
||||
|
|
|
@ -584,7 +584,8 @@ void i2c_transfer(u8x8_t* u8x8, uint8_t adr, uint8_t cnt, uint8_t* data) {
|
|||
uint8_t i;
|
||||
i2c_start(u8x8);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,8 @@ void u8x8_SetupDefaults(u8x8_t* u8x8) {
|
|||
#ifdef U8X8_USE_PINS
|
||||
{
|
||||
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
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ which is the name that most clang tools search for by default.
|
|||
import fnmatch
|
||||
import itertools
|
||||
import json
|
||||
from shlex import join, split
|
||||
from oslex import join, split
|
||||
|
||||
import SCons
|
||||
from SCons.Tool.asm import ASPPSuffixes, ASSuffixes
|
||||
|
|
|
@ -15,4 +15,3 @@ def resolve_port(logger, portname: str = "auto"):
|
|||
logger.error("Failed to find connected Flipper")
|
||||
elif len(flippers) > 1:
|
||||
logger.error("More than one Flipper is attached")
|
||||
logger.error("Failed to guess which port to use")
|
||||
|
|
|
@ -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()
|
|
@ -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
129
scripts/testops.py
Normal 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()()
|
|
@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] (
|
|||
exit /b 0
|
||||
)
|
||||
|
||||
set "FLIPPER_TOOLCHAIN_VERSION=33"
|
||||
set "FLIPPER_TOOLCHAIN_VERSION=37"
|
||||
|
||||
if ["%FBT_TOOLCHAIN_PATH%"] == [""] (
|
||||
set "FBT_TOOLCHAIN_PATH=%FBT_ROOT%"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
# public variables
|
||||
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
|
||||
FBT_TOOLCHAIN_PATH_WAS_SET=0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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_keys_storage.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_early,void,
|
||||
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_set_isr,void,"FuriHalInterruptId, 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_free,void,FuriThreadList*
|
||||
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_process,void,"FuriThreadList*, uint32_t, uint32_t"
|
||||
Function,+,furi_thread_list_size,size_t,FuriThreadList*
|
||||
|
|
|
|
@ -1,5 +1,5 @@
|
|||
entry,status,name,type,params
|
||||
Version,+,68.0,,
|
||||
Version,+,68.1,,
|
||||
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_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_early,void,
|
||||
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_set_isr,void,"FuriHalInterruptId, 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_free,void,FuriThreadList*
|
||||
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_process,void,"FuriThreadList*, uint32_t, uint32_t"
|
||||
Function,+,furi_thread_list_size,size_t,FuriThreadList*
|
||||
|
|
|
|
@ -21,8 +21,7 @@
|
|||
|
||||
#define TAG "FuriHalBt"
|
||||
|
||||
#define furi_hal_bt_DEFAULT_MAC_ADDR \
|
||||
{ 0x6c, 0x7a, 0xd8, 0xac, 0x57, 0x72 }
|
||||
#define furi_hal_bt_DEFAULT_MAC_ADDR {0x6c, 0x7a, 0xd8, 0xac, 0x57, 0x72}
|
||||
|
||||
/* Time, in ms, to wait for mode transition before crashing */
|
||||
#define C2_MODE_SWITCH_TIMEOUT 10000
|
||||
|
|
|
@ -513,8 +513,7 @@ typedef struct {
|
|||
uint32_t* ob_register_address;
|
||||
} FuriHalFlashObMapping;
|
||||
|
||||
#define OB_REG_DEF(INDEX, REG) \
|
||||
{ .ob_reg = INDEX, .ob_register_address = (uint32_t*)(REG) }
|
||||
#define OB_REG_DEF(INDEX, 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] = {
|
||||
OB_REG_DEF(FuriHalFlashObRegisterUserRead, (&FLASH->OPTR)),
|
||||
|
|
|
@ -249,7 +249,7 @@ void furi_hal_gpio_remove_int_callback(const GpioPin* gpio) {
|
|||
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) {
|
||||
gpio_interrupt[pin_num].callback(gpio_interrupt[pin_num].context);
|
||||
}
|
||||
|
|
|
@ -13,12 +13,22 @@
|
|||
|
||||
#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 {
|
||||
FuriHalInterruptISR isr;
|
||||
void* context;
|
||||
} 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] = {
|
||||
// TIM1, TIM16, TIM17
|
||||
|
@ -67,12 +77,16 @@ const IRQn_Type furi_hal_interrupt_irqn[FuriHalInterruptIdMax] = {
|
|||
[FuriHalInterruptIdLpUart1] = LPUART1_IRQn,
|
||||
};
|
||||
|
||||
FURI_ALWAYS_STATIC_INLINE void furi_hal_interrupt_call(FuriHalInterruptId index) {
|
||||
furi_check(furi_hal_interrupt_isr[index].isr);
|
||||
furi_hal_interrupt_isr[index].isr(furi_hal_interrupt_isr[index].context);
|
||||
FURI_ALWAYS_INLINE static void furi_hal_interrupt_call(FuriHalInterruptId index) {
|
||||
const FuriHalInterruptISRPair* isr_descr = &furi_hal_interrupt.isr[index];
|
||||
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) {
|
||||
NVIC_SetPriority(
|
||||
furi_hal_interrupt_irqn[index],
|
||||
|
@ -80,19 +94,19 @@ FURI_ALWAYS_STATIC_INLINE void
|
|||
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]);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
|
@ -137,17 +151,18 @@ void furi_hal_interrupt_set_isr_ex(
|
|||
|
||||
uint16_t real_priority = FURI_HAL_INTERRUPT_DEFAULT_PRIORITY - priority;
|
||||
|
||||
FuriHalInterruptISRPair* isr_descr = &furi_hal_interrupt.isr[index];
|
||||
if(isr) {
|
||||
// Pre ISR set
|
||||
furi_check(furi_hal_interrupt_isr[index].isr == NULL);
|
||||
furi_check(isr_descr->isr == NULL);
|
||||
} else {
|
||||
// Pre ISR clear
|
||||
furi_hal_interrupt_disable(index);
|
||||
furi_hal_interrupt_clear_pending(index);
|
||||
}
|
||||
|
||||
furi_hal_interrupt_isr[index].isr = isr;
|
||||
furi_hal_interrupt_isr[index].context = context;
|
||||
isr_descr->isr = isr;
|
||||
isr_descr->context = context;
|
||||
__DMB();
|
||||
|
||||
if(isr) {
|
||||
|
@ -304,27 +319,37 @@ extern void HW_IPCC_Tx_Handler(void);
|
|||
extern void HW_IPCC_Rx_Handler(void);
|
||||
|
||||
void SysTick_Handler(void) {
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_START();
|
||||
furi_hal_os_tick();
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_END();
|
||||
}
|
||||
|
||||
void USB_LP_IRQHandler(void) {
|
||||
#ifndef FURI_RAM_EXEC
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_START();
|
||||
usbd_poll(&udev);
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_END();
|
||||
#endif
|
||||
}
|
||||
|
||||
void USB_HP_IRQHandler(void) { //-V524
|
||||
#ifndef FURI_RAM_EXEC
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_START();
|
||||
usbd_poll(&udev);
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_END();
|
||||
#endif
|
||||
}
|
||||
|
||||
void IPCC_C1_TX_IRQHandler(void) {
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_START();
|
||||
HW_IPCC_Tx_Handler();
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_END();
|
||||
}
|
||||
|
||||
void IPCC_C1_RX_IRQHandler(void) {
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_START();
|
||||
HW_IPCC_Rx_Handler();
|
||||
FURI_HAL_INTERRUPT_ACCOUNT_END();
|
||||
}
|
||||
|
||||
void FPU_IRQHandler(void) {
|
||||
|
@ -499,3 +524,7 @@ const char* furi_hal_interrupt_get_name(uint8_t exception_number) {
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t furi_hal_interrupt_get_time_in_isr_total(void) {
|
||||
return furi_hal_interrupt.counter_time_in_isr_total;
|
||||
}
|
|
@ -118,6 +118,12 @@ void furi_hal_interrupt_set_isr_ex(
|
|||
*/
|
||||
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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -19,7 +19,8 @@ static const uint8_t USB_DEVICE_NO_PROTOCOL = 0x0;
|
|||
#define CCID_TOTAL_SLOTS 1
|
||||
#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_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);
|
||||
dev_str_desc->bLength = len * 2 + 2;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -368,7 +368,8 @@ static void* hid_set_string_descr(char* str) {
|
|||
struct usb_string_descriptor* dev_str_desc = malloc(len * 2 + 2);
|
||||
dev_str_desc->bLength = len * 2 + 2;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "hid_usage_consumer.h"
|
||||
#include "hid_usage_led.h"
|
||||
|
||||
#define CCID_SHORT_APDU_SIZE (0xFF)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue