mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-17 04:34:44 -07:00
Merge branch 'dev' of https://github.com/DarkFlippers/unleashed-firmware into xfw-dev
This commit is contained in:
@@ -20,8 +20,8 @@
|
||||
|
||||
const ProtocolBase* lfrfid_protocols[] = {
|
||||
[LFRFIDProtocolEM4100] = &protocol_em4100,
|
||||
[LFRFIDProtocolEM410032] = &protocol_em4100_32,
|
||||
[LFRFIDProtocolEM410016] = &protocol_em4100_16,
|
||||
[LFRFIDProtocolEM4100_32] = &protocol_em4100_32,
|
||||
[LFRFIDProtocolEM4100_16] = &protocol_em4100_16,
|
||||
[LFRFIDProtocolH10301] = &protocol_h10301,
|
||||
[LFRFIDProtocolIdteck] = &protocol_idteck,
|
||||
[LFRFIDProtocolIndala26] = &protocol_indala26,
|
||||
|
||||
@@ -9,8 +9,8 @@ typedef enum {
|
||||
|
||||
typedef enum {
|
||||
LFRFIDProtocolEM4100,
|
||||
LFRFIDProtocolEM410032,
|
||||
LFRFIDProtocolEM410016,
|
||||
LFRFIDProtocolEM4100_32,
|
||||
LFRFIDProtocolEM4100_16,
|
||||
LFRFIDProtocolH10301,
|
||||
LFRFIDProtocolIdteck,
|
||||
LFRFIDProtocolIndala26,
|
||||
|
||||
@@ -99,7 +99,8 @@ static NfcCommand emv_poller_handler_get_processing_options(EmvPoller* instance)
|
||||
}
|
||||
|
||||
static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) {
|
||||
emv_poller_read_afl(instance);
|
||||
// Search PAN
|
||||
emv_poller_read_afl(instance, false, &instance->records_mask);
|
||||
emv_poller_read_log_entry(instance);
|
||||
|
||||
instance->state = EmvPollerStateReadExtra;
|
||||
@@ -110,6 +111,9 @@ static NfcCommand emv_poller_handler_read_extra_data(EmvPoller* instance) {
|
||||
emv_poller_get_last_online_atc(instance);
|
||||
emv_poller_get_pin_try_counter(instance);
|
||||
|
||||
// Search cardholder name. This operation may break communication with the card, so it should be the last one
|
||||
emv_poller_read_afl(instance, true, &instance->records_mask);
|
||||
|
||||
instance->state = EmvPollerStateReadSuccess;
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ EmvError emv_poller_get_processing_options(EmvPoller* instance);
|
||||
|
||||
EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t record_num);
|
||||
|
||||
EmvError emv_poller_read_afl(EmvPoller* instance);
|
||||
EmvError emv_poller_read_afl(EmvPoller* instance, bool bruteforce_sfi, uint16_t* readed_mask);
|
||||
|
||||
EmvError emv_poller_read_log_entry(EmvPoller* instance);
|
||||
|
||||
|
||||
@@ -621,84 +621,80 @@ EmvError emv_poller_read_sfi_record(EmvPoller* instance, uint8_t sfi, uint8_t re
|
||||
return error;
|
||||
}
|
||||
|
||||
EmvError emv_poller_read_afl(EmvPoller* instance) {
|
||||
EmvError emv_poller_read_afl(EmvPoller* instance, bool bruteforce_sfi, uint16_t* readed_mask) {
|
||||
EmvError error = EmvErrorNone;
|
||||
bool pan_fetched = (instance->data->emv_application.pan_len);
|
||||
bool cardholder_name_fetched = strlen(instance->data->emv_application.cardholder_name);
|
||||
|
||||
APDU* afl = &instance->data->emv_application.afl;
|
||||
if(!bruteforce_sfi) {
|
||||
// SEARCH PAN, RETURN WHEN FOUND
|
||||
APDU* afl = &instance->data->emv_application.afl;
|
||||
|
||||
if(afl->size == 0) {
|
||||
return false;
|
||||
}
|
||||
if(afl->size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FURI_LOG_D(TAG, "Search PAN in SFI");
|
||||
FURI_LOG_D(TAG, "Search PAN in SFI");
|
||||
|
||||
// uint8_t sfi_2_mask = 0;
|
||||
// uint8_t sfi_3_mask = 0;
|
||||
// Iterate through all files
|
||||
for(size_t i = 0; i < instance->data->emv_application.afl.size; i += 4) {
|
||||
uint8_t sfi = afl->data[i] >> 3;
|
||||
uint8_t record_start = afl->data[i + 1];
|
||||
uint8_t record_end = afl->data[i + 2];
|
||||
// Iterate through all records in file
|
||||
for(uint8_t record = record_start; record <= record_end; ++record) {
|
||||
if((sfi <= 3) && (record <= 5))
|
||||
FURI_BIT_SET(
|
||||
*readed_mask,
|
||||
record + ((sfi - 2) * 8)); //black magic: mask 0003333300022222
|
||||
|
||||
// bool pan_fetched = (instance->data->emv_application.pan_len);
|
||||
error = emv_poller_read_sfi_record(instance, sfi, record);
|
||||
if(error != EmvErrorNone) break;
|
||||
|
||||
// Iterate through all files
|
||||
for(size_t i = 0; i < instance->data->emv_application.afl.size; i += 4) {
|
||||
uint8_t sfi = afl->data[i] >> 3;
|
||||
uint8_t record_start = afl->data[i + 1];
|
||||
uint8_t record_end = afl->data[i + 2];
|
||||
// Iterate through all records in file
|
||||
for(uint8_t record = record_start; record <= record_end; ++record) {
|
||||
// if((sfi == 2) && (record < 8)) FURI_BIT_SET(sfi_2_mask, record);
|
||||
// if((sfi == 3) && (record < 8)) FURI_BIT_SET(sfi_3_mask, record);
|
||||
if(!emv_decode_response_tlv(
|
||||
bit_buffer_get_data(instance->rx_buffer),
|
||||
bit_buffer_get_size_bytes(instance->rx_buffer),
|
||||
&instance->data->emv_application)) {
|
||||
error = EmvErrorProtocol;
|
||||
FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
|
||||
}
|
||||
|
||||
error = emv_poller_read_sfi_record(instance, sfi, record);
|
||||
if(error != EmvErrorNone) break;
|
||||
|
||||
if(!emv_decode_response_tlv(
|
||||
bit_buffer_get_data(instance->rx_buffer),
|
||||
bit_buffer_get_size_bytes(instance->rx_buffer),
|
||||
&instance->data->emv_application)) {
|
||||
error = EmvErrorProtocol;
|
||||
FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
|
||||
if(instance->data->emv_application.pan_len) {
|
||||
pan_fetched = true;
|
||||
break;
|
||||
} // Card number fetched
|
||||
}
|
||||
if(pan_fetched) break;
|
||||
}
|
||||
} else { // BRUTFORCE FILES 2-3. SEARCH CARDHOLDER NAME
|
||||
FURI_LOG_T(TAG, "Bruteforce files 2-3");
|
||||
for(size_t sfi = 2; sfi <= 3; sfi++) {
|
||||
// Iterate through records 1-5 in file
|
||||
for(size_t record = 1; record <= 5; record++) {
|
||||
// Skip previously readed sfi
|
||||
if((*readed_mask >> (record + ((sfi - 2) * 8))) & (0b1)) continue;
|
||||
|
||||
// Some READ RECORD returns 1 byte response 0x12/0x13 (IDK WTF),
|
||||
// then poller return Timeout to all subsequent requests.
|
||||
// TODO: remove below lines when it was fixed
|
||||
if(instance->data->emv_application.pan_len != 0)
|
||||
return EmvErrorNone; // Card number fetched
|
||||
// if(instance->data->emv_application.pan_len) pan_fetched = true; // Card number fetched
|
||||
error = emv_poller_read_sfi_record(instance, sfi, record);
|
||||
if(error != EmvErrorNone) break;
|
||||
|
||||
if(!emv_decode_response_tlv(
|
||||
bit_buffer_get_data(instance->rx_buffer),
|
||||
bit_buffer_get_size_bytes(instance->rx_buffer),
|
||||
&instance->data->emv_application)) {
|
||||
error = EmvErrorProtocol;
|
||||
FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
|
||||
}
|
||||
|
||||
if(strlen(instance->data->emv_application.cardholder_name))
|
||||
cardholder_name_fetched = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// bool cardholder_name_fetched = strlen(instance->data->emv_application.cardholder_name);
|
||||
// Bruteforse files 2-3
|
||||
// FURI_LOG_T(TAG, "Bruteforce files 2-3");
|
||||
// for(size_t sfi = 2; sfi <= 3; sfi++) {
|
||||
// // Iterate through records 1-5 in file
|
||||
// for(size_t record = 1; record <= 5; record++) {
|
||||
// // Skip previously readed sfi
|
||||
// // if(sfi == 2) {
|
||||
// // if((sfi_2_mask >> record) & (0b1)) continue;
|
||||
// // }
|
||||
// // if(sfi == 3) {
|
||||
// // if((sfi_3_mask >> record) & (0b1)) continue;
|
||||
// // }
|
||||
|
||||
// if(strlen(instance->data->emv_application.cardholder_name))
|
||||
// cardholder_name_fetched = true;
|
||||
// error = emv_poller_read_sfi_record(instance, sfi, record);
|
||||
// if(error != EmvErrorNone) break;
|
||||
|
||||
// if(!emv_decode_response_tlv(
|
||||
// bit_buffer_get_data(instance->rx_buffer),
|
||||
// bit_buffer_get_size_bytes(instance->rx_buffer),
|
||||
// &instance->data->emv_application)) {
|
||||
// error = EmvErrorProtocol;
|
||||
// FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if(pan_fetched || cardholder_name_fetched)
|
||||
// return EmvErrorNone;
|
||||
// else
|
||||
// return error;
|
||||
return error;
|
||||
if((pan_fetched && (!bruteforce_sfi)) || (cardholder_name_fetched && bruteforce_sfi))
|
||||
return EmvErrorNone;
|
||||
else
|
||||
return error;
|
||||
}
|
||||
|
||||
static EmvError emv_poller_req_get_data(EmvPoller* instance, uint16_t tag) {
|
||||
|
||||
@@ -39,6 +39,7 @@ struct EmvPoller {
|
||||
EmvPollerEvent emv_event;
|
||||
NfcGenericEvent general_event;
|
||||
NfcGenericCallback callback;
|
||||
uint16_t records_mask;
|
||||
void* context;
|
||||
};
|
||||
|
||||
|
||||
@@ -361,15 +361,38 @@ static void subghz_protocol_magellan_check_remote_controller(SubGhzBlockGeneric*
|
||||
*
|
||||
* 0x1275EC => 0x12-event codes, 0x75EC-serial (dec 117236)
|
||||
*
|
||||
* event codes
|
||||
* bit_0: 1-Open/Motion, 0-close/ok
|
||||
* bit_1: 1-Tamper On (alarm), 0-Tamper Off (ok)
|
||||
* bit_2: ?
|
||||
* bit_3: 1-power on
|
||||
* bit_4: model type - wireless reed
|
||||
* bit_5: model type - motion sensor
|
||||
* bit_6: ?
|
||||
* bit_7: ?
|
||||
* Event codes consist of two parts:
|
||||
* - The upper nibble (bits 7-4) represents the event type:
|
||||
* - 0x00: Nothing
|
||||
* - 0x01: Door
|
||||
* - 0x02: Motion
|
||||
* - 0x03: Smoke Alarm
|
||||
* - 0x04: REM1
|
||||
* - 0x05: REM1 with subtype Off1
|
||||
* - 0x06: REM2
|
||||
* - 0x07: REM2 with subtype Off1
|
||||
* - Others: Unknown
|
||||
* - The lower nibble (bits 3-0) represents the event subtype, which varies based on the model type:
|
||||
* - If the model type is greater than 0x03 (e.g., REM1 or REM2):
|
||||
* - 0x00: Arm1
|
||||
* - 0x01: Btn1
|
||||
* - 0x02: Btn2
|
||||
* - 0x03: Btn3
|
||||
* - 0x08: Reset
|
||||
* - 0x09: LowBatt
|
||||
* - 0x0A: BattOk
|
||||
* - 0x0B: Learn
|
||||
* - Others: Unknown
|
||||
* - Otherwise:
|
||||
* - 0x00: Sealed
|
||||
* - 0x01: Alarm
|
||||
* - 0x02: Tamper
|
||||
* - 0x03: Alarm + Tamper
|
||||
* - 0x08: Reset
|
||||
* - 0x09: LowBatt
|
||||
* - 0x0A: BattOk
|
||||
* - 0x0B: Learn
|
||||
* - Others: Unknown
|
||||
*
|
||||
*/
|
||||
uint64_t data_rev = subghz_protocol_blocks_reverse_key(instance->data >> 8, 24);
|
||||
@@ -378,18 +401,49 @@ static void subghz_protocol_magellan_check_remote_controller(SubGhzBlockGeneric*
|
||||
}
|
||||
|
||||
static void subghz_protocol_magellan_get_event_serialize(uint8_t event, FuriString* output) {
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"%s%s%s%s%s%s%s%s",
|
||||
((event >> 4) & 0x1 ? (event & 0x1 ? " Open" : " Close") :
|
||||
(event & 0x1 ? " Motion" : " Ok")),
|
||||
((event >> 1) & 0x1 ? ", Tamper On\n(Alarm)" : ""),
|
||||
((event >> 2) & 0x1 ? ", ?" : ""),
|
||||
((event >> 3) & 0x1 ? ", Power On" : ""),
|
||||
((event >> 4) & 0x1 ? ", MT:Wireless_Reed" : ""),
|
||||
((event >> 5) & 0x1 ? ", MT:Motion_\nSensor" : ""),
|
||||
((event >> 6) & 0x1 ? ", ?" : ""),
|
||||
((event >> 7) & 0x1 ? ", ?" : ""));
|
||||
const char* event_type;
|
||||
const char* event_subtype;
|
||||
|
||||
switch ((event >> 4) & 0x0F) {
|
||||
case 0x00: event_type = "Nothing"; break;
|
||||
case 0x01: event_type = "Door"; break;
|
||||
case 0x02: event_type = "Motion"; break;
|
||||
case 0x03: event_type = "Smoke Alarm"; break;
|
||||
case 0x04: event_type = "REM1"; break;
|
||||
case 0x05:
|
||||
event_type = "REM1";
|
||||
event_subtype = "Off1";
|
||||
furi_string_cat_printf(output, "%s - %s", event_type, event_subtype);
|
||||
return;
|
||||
case 0x06:
|
||||
event_type = "REM2";
|
||||
event_subtype = "Off1";
|
||||
furi_string_cat_printf(output, "%s - %s", event_type, event_subtype);
|
||||
return;
|
||||
default: event_type = "Unknown"; break;
|
||||
}
|
||||
|
||||
switch (event & 0x0F) {
|
||||
case 0x00:
|
||||
event_subtype = (((event >> 4) & 0x0F) > 0x03) ? "Arm1" : "Sealed";
|
||||
break;
|
||||
case 0x01:
|
||||
event_subtype = (((event >> 4) & 0x0F) > 0x03) ? "Btn1" : "Alarm";
|
||||
break;
|
||||
case 0x02:
|
||||
event_subtype = (((event >> 4) & 0x0F) > 0x03) ? "Btn2" : "Tamper";
|
||||
break;
|
||||
case 0x03:
|
||||
event_subtype = (((event >> 4) & 0x0F) > 0x03) ? "Btn3" : "Alarm + Tamper";
|
||||
break;
|
||||
case 0x08: event_subtype = "Reset"; break;
|
||||
case 0x09: event_subtype = "LowBatt"; break;
|
||||
case 0x0A: event_subtype = "BattOk"; break;
|
||||
case 0x0B: event_subtype = "Learn"; break;
|
||||
default: event_subtype = "Unknown"; break;
|
||||
}
|
||||
|
||||
furi_string_cat_printf(output, "%s - %s", event_type, event_subtype);
|
||||
}
|
||||
|
||||
uint32_t subghz_protocol_decoder_magellan_get_hash_data(void* context) {
|
||||
|
||||
@@ -49,7 +49,7 @@ void name_generator_make_auto_datetime(
|
||||
char* name,
|
||||
size_t max_name_size,
|
||||
const char* prefix,
|
||||
FuriHalRtcDateTime* custom_time) {
|
||||
DateTime* custom_time) {
|
||||
if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagRandomFilename)) {
|
||||
name_generator_make_detailed_datetime(
|
||||
name, max_name_size, prefix, custom_time, xtreme_settings.file_naming_prefix_after);
|
||||
@@ -107,13 +107,13 @@ void name_generator_make_detailed_datetime(
|
||||
char* name,
|
||||
size_t max_name_size,
|
||||
const char* prefix,
|
||||
FuriHalRtcDateTime* custom_time,
|
||||
DateTime* custom_time,
|
||||
bool prefix_after) {
|
||||
furi_assert(name);
|
||||
furi_assert(max_name_size);
|
||||
furi_assert(prefix);
|
||||
|
||||
FuriHalRtcDateTime dateTime;
|
||||
DateTime dateTime;
|
||||
if(custom_time) {
|
||||
dateTime = *custom_time;
|
||||
} else {
|
||||
|
||||
@@ -19,7 +19,7 @@ void name_generator_make_auto_datetime(
|
||||
char* name,
|
||||
size_t max_name_size,
|
||||
const char* prefix,
|
||||
FuriHalRtcDateTime* custom_time);
|
||||
DateTime* custom_time);
|
||||
|
||||
/** Generates random name
|
||||
*
|
||||
@@ -45,7 +45,7 @@ void name_generator_make_detailed_datetime(
|
||||
char* name,
|
||||
size_t max_name_size,
|
||||
const char* prefix,
|
||||
FuriHalRtcDateTime* custom_time,
|
||||
DateTime* custom_time,
|
||||
bool prefix_after);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Reference in New Issue
Block a user