mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-26 06:20:21 +00:00
Merge remote-tracking branch 'OFW/dev' into dev
This commit is contained in:
commit
5434405c34
2 changed files with 103 additions and 0 deletions
|
@ -281,6 +281,15 @@ App(
|
||||||
sources=["plugins/supported_cards/hworld.c"],
|
sources=["plugins/supported_cards/hworld.c"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
App(
|
||||||
|
appid="trt_parser",
|
||||||
|
apptype=FlipperAppType.PLUGIN,
|
||||||
|
entry_point="trt_plugin_ep",
|
||||||
|
targets=["f7"],
|
||||||
|
requires=["nfc"],
|
||||||
|
sources=["plugins/supported_cards/trt.c"],
|
||||||
|
)
|
||||||
|
|
||||||
App(
|
App(
|
||||||
appid="nfc_cli",
|
appid="nfc_cli",
|
||||||
targets=["f7"],
|
targets=["f7"],
|
||||||
|
|
94
applications/main/nfc/plugins/supported_cards/trt.c
Normal file
94
applications/main/nfc/plugins/supported_cards/trt.c
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// Flipper Zero parser for for Tianjin Railway Transit (TRT)
|
||||||
|
// https://en.wikipedia.org/wiki/Tianjin_Metro
|
||||||
|
// Reverse engineering and parser development by @Torron (Github: @zinongli)
|
||||||
|
|
||||||
|
#include "nfc_supported_card_plugin.h"
|
||||||
|
#include <flipper_application.h>
|
||||||
|
#include <nfc/protocols/mf_ultralight/mf_ultralight.h>
|
||||||
|
#include <bit_lib.h>
|
||||||
|
|
||||||
|
#define TAG "TrtParser"
|
||||||
|
#define LATEST_SALE_MARKER 0x02
|
||||||
|
#define FULL_SALE_TIME_STAMP_PAGE 0x09
|
||||||
|
#define BALANCE_PAGE 0x08
|
||||||
|
#define SALE_RECORD_TIME_STAMP_A 0x0C
|
||||||
|
#define SALE_RECORD_TIME_STAMP_B 0x0E
|
||||||
|
#define SALE_YEAR_OFFSET 2000
|
||||||
|
|
||||||
|
static bool trt_parse(const NfcDevice* device, FuriString* parsed_data) {
|
||||||
|
furi_assert(device);
|
||||||
|
furi_assert(parsed_data);
|
||||||
|
|
||||||
|
const MfUltralightData* data = nfc_device_get_data(device, NfcProtocolMfUltralight);
|
||||||
|
|
||||||
|
bool parsed = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint8_t latest_sale_page = 0;
|
||||||
|
|
||||||
|
// Look for sale record signature
|
||||||
|
if(data->page[SALE_RECORD_TIME_STAMP_A].data[0] == LATEST_SALE_MARKER) {
|
||||||
|
latest_sale_page = SALE_RECORD_TIME_STAMP_A;
|
||||||
|
} else if(data->page[SALE_RECORD_TIME_STAMP_B].data[0] == LATEST_SALE_MARKER) {
|
||||||
|
latest_sale_page = SALE_RECORD_TIME_STAMP_B;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the sale record was backed up
|
||||||
|
const uint8_t* partial_record_pointer = &data->page[latest_sale_page - 1].data[0];
|
||||||
|
const uint8_t* full_record_pointer = &data->page[FULL_SALE_TIME_STAMP_PAGE].data[0];
|
||||||
|
uint32_t latest_sale_record = bit_lib_get_bits_32(partial_record_pointer, 3, 20);
|
||||||
|
uint32_t latest_sale_full_record = bit_lib_get_bits_32(full_record_pointer, 0, 27);
|
||||||
|
if(latest_sale_record != (latest_sale_full_record & 0xFFFFF)) break;
|
||||||
|
|
||||||
|
// Parse date
|
||||||
|
// yyy yyyymmmm dddddhhh hhnnnnnn
|
||||||
|
uint16_t sale_year = ((latest_sale_full_record & 0x7F00000) >> 20) + SALE_YEAR_OFFSET;
|
||||||
|
uint8_t sale_month = (latest_sale_full_record & 0xF0000) >> 16;
|
||||||
|
uint8_t sale_day = (latest_sale_full_record & 0xF800) >> 11;
|
||||||
|
uint8_t sale_hour = (latest_sale_full_record & 0x7C0) >> 6;
|
||||||
|
uint8_t sale_minute = latest_sale_full_record & 0x3F;
|
||||||
|
|
||||||
|
// Parse balance
|
||||||
|
uint16_t balance = bit_lib_get_bits_16(&data->page[BALANCE_PAGE].data[2], 0, 16);
|
||||||
|
uint16_t balance_yuan = balance / 100;
|
||||||
|
uint8_t balance_cent = balance % 100;
|
||||||
|
|
||||||
|
// Format string for rendering
|
||||||
|
furi_string_cat_printf(parsed_data, "\e#TRT Tianjin Metro\n");
|
||||||
|
furi_string_cat_printf(parsed_data, "Single-Use Ticket\n");
|
||||||
|
furi_string_cat_printf(parsed_data, "Balance: %u.%02u RMB\n", balance_yuan, balance_cent);
|
||||||
|
furi_string_cat_printf(
|
||||||
|
parsed_data,
|
||||||
|
"Sale Date: \n%04u-%02d-%02d %02d:%02d",
|
||||||
|
sale_year,
|
||||||
|
sale_month,
|
||||||
|
sale_day,
|
||||||
|
sale_hour,
|
||||||
|
sale_minute);
|
||||||
|
parsed = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Actual implementation of app<>plugin interface */
|
||||||
|
static const NfcSupportedCardsPlugin trt_plugin = {
|
||||||
|
.protocol = NfcProtocolMfUltralight,
|
||||||
|
.verify = NULL,
|
||||||
|
.read = NULL,
|
||||||
|
.parse = trt_parse,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Plugin descriptor to comply with basic plugin specification */
|
||||||
|
static const FlipperAppPluginDescriptor trt_plugin_descriptor = {
|
||||||
|
.appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID,
|
||||||
|
.ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION,
|
||||||
|
.entry_point = &trt_plugin,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Plugin entry point - must return a pointer to const descriptor */
|
||||||
|
const FlipperAppPluginDescriptor* trt_plugin_ep(void) {
|
||||||
|
return &trt_plugin_descriptor;
|
||||||
|
}
|
Loading…
Reference in a new issue