kinda parser refactor. datetime format added

This commit is contained in:
Methodius 2024-02-16 17:20:06 +09:00
parent ae160efa16
commit b6a6528526
No known key found for this signature in database
GPG key ID: 122FA99A00B41679
7 changed files with 134 additions and 136 deletions

View file

@ -24,8 +24,8 @@
#include <lib/nfc/protocols/mf_desfire/mf_desfire.h> #include <lib/nfc/protocols/mf_desfire/mf_desfire.h>
#include <bit_lib.h> #include <bit_lib.h>
#include <applications/services/locale/locale.h>
#include <datetime.h> #include <datetime.h>
#include <locale/locale.h>
#include <inttypes.h> #include <inttypes.h>
// //
@ -173,7 +173,6 @@ static void furi_string_cat_timestamp(
const char* date_hdr, const char* date_hdr,
const char* time_hdr, const char* time_hdr,
uint32_t tmst_1900); uint32_t tmst_1900);
static void epoch_1900_datetime_to_furi(uint32_t seconds, DateTime* out);
static bool get_file_contents( static bool get_file_contents(
const MfDesfireApplication* app, const MfDesfireApplication* app,
const MfDesfireFileId* id, const MfDesfireFileId* id,
@ -530,7 +529,7 @@ static void furi_string_cat_timestamp(
uint32_t tmst_1900) { uint32_t tmst_1900) {
DateTime tm; DateTime tm;
epoch_1900_datetime_to_furi(tmst_1900, &tm); datetime_timestamp_to_datetime(tmst_1900, &tm);
FuriString* date_str = furi_string_alloc(); FuriString* date_str = furi_string_alloc();
locale_format_date(date_str, &tm, locale_get_date_format(), "-"); locale_format_date(date_str, &tm, locale_get_date_format(), "-");
@ -550,57 +549,6 @@ static void furi_string_cat_timestamp(
furi_string_free(time_str); furi_string_free(time_str);
} }
// Convert a "1900"-based timestamp to Furi time, assuming a UTC/GMT timezone.
static void epoch_1900_datetime_to_furi(uint32_t seconds, DateTime* out) {
uint16_t year, month, day, hour, minute, second;
// Calculate absolute number of days elapsed since the 1900 epoch
// and save the residual for the time within the day.
uint32_t absolute_days = seconds / 86400;
uint32_t seconds_within_day = seconds % 86400;
// Calculate day of the week.
// January 1, 1900 was a Monday ("day of week" = 1)
uint8_t dow = (absolute_days + 1) % 7;
//
// Compute the date by simply marching through time in as large chunks
// as possible.
//
for(year = 1900;; year++) {
uint16_t year_days = datetime_get_days_per_year(year);
if(absolute_days >= year_days)
absolute_days -= year_days;
else
break;
}
bool is_leap = datetime_is_leap_year(year);
for(month = 1;; month++) {
uint8_t days_in_month = datetime_get_days_per_month(is_leap, month);
if(absolute_days >= days_in_month)
absolute_days -= days_in_month;
else
break;
}
day = absolute_days + 1;
hour = seconds_within_day / 3600;
uint16_t sub_hour = seconds_within_day % 3600;
minute = sub_hour / 60;
second = sub_hour % 60;
out->year = year;
out->month = month;
out->day = day;
out->hour = hour;
out->minute = minute;
out->second = second;
out->weekday = dow;
}
/* Actual implementation of app<>plugin interface */ /* Actual implementation of app<>plugin interface */
static const NfcSupportedCardsPlugin clipper_plugin = { static const NfcSupportedCardsPlugin clipper_plugin = {
.protocol = NfcProtocolMfDesfire, .protocol = NfcProtocolMfDesfire,

View file

@ -23,6 +23,10 @@
#include "protocols/emv/emv.h" #include "protocols/emv/emv.h"
#include "helpers/nfc_emv_parser.h" #include "helpers/nfc_emv_parser.h"
#include <bit_lib.h>
#include <datetime.h>
#include <locale/locale.h>
#define TAG "EMV" #define TAG "EMV"
bool emv_get_currency_name(uint16_t cur_code, FuriString* currency_name) { bool emv_get_currency_name(uint16_t cur_code, FuriString* currency_name) {
@ -96,34 +100,49 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) {
parsed = true; parsed = true;
} }
if(app.effective_month) { bool nevermind = false;
char day[] = "--"; DateTime effective_datetime = {
if(app.effective_day) itoa(app.effective_day, day, 16); 0,
if(day[1] == '\0') { 0,
day[1] = day[0]; 0,
day[0] = '0'; bit_lib_bytes_to_num_bcd(&app.effective_day, 1, &nevermind),
} bit_lib_bytes_to_num_bcd(&app.effective_month, 1, &nevermind),
2000 + bit_lib_bytes_to_num_bcd(&app.effective_year, 1, &nevermind),
0};
DateTime expiration_datetime = {
0,
0,
0,
bit_lib_bytes_to_num_bcd(&app.exp_day, 1, &nevermind),
bit_lib_bytes_to_num_bcd(&app.exp_month, 1, &nevermind),
2000 + bit_lib_bytes_to_num_bcd(&app.exp_year, 1, &nevermind),
0};
LocaleDateFormat date_format = locale_get_date_format();
const char* separator = (date_format == LocaleDateFormatDMY) ? "." : "/";
FuriString* effective_date_str = furi_string_alloc();
locale_format_date(effective_date_str, &effective_datetime, date_format, separator);
FuriString* expiration_date_str = furi_string_alloc();
locale_format_date(expiration_date_str, &expiration_datetime, date_format, separator);
if(app.effective_month) {
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"Effective: %s.%02X.20%02X\n", "Effective: %s\n",
day, app.effective_day ? furi_string_get_cstr(effective_date_str) :
app.effective_month, furi_string_get_cstr(effective_date_str) + 3);
app.effective_year);
parsed = true; parsed = true;
} }
if(app.exp_month) { if(app.exp_month) {
char day[] = "--";
if(app.exp_day) itoa(app.exp_day, day, 16);
if(day[1] == '\0') {
day[1] = day[0];
day[0] = '0';
}
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, "Expires: %s.%02X.20%02X\n", day, app.exp_month, app.exp_year); parsed_data,
"Expires: %s\n",
app.exp_day ? furi_string_get_cstr(expiration_date_str) :
furi_string_get_cstr(expiration_date_str) + 3);
parsed = true; parsed = true;
} }
@ -154,6 +173,10 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) {
if(!parsed) furi_string_cat_printf(parsed_data, "No data was parsed\n"); if(!parsed) furi_string_cat_printf(parsed_data, "No data was parsed\n");
furi_string_free(str);
furi_string_free(effective_date_str);
furi_string_free(expiration_date_str);
parsed = true; parsed = true;
} while(false); } while(false);

View file

@ -89,6 +89,7 @@ static bool itso_parse(const NfcDevice* device, FuriString* parsed_data) {
DateTime timestamp = {0}; DateTime timestamp = {0};
datetime_timestamp_to_datetime(unixTimestamp, &timestamp); datetime_timestamp_to_datetime(unixTimestamp, &timestamp);
FuriString* timestamp_str = furi_string_alloc(); FuriString* timestamp_str = furi_string_alloc();
locale_format_date(timestamp_str, &timestamp, locale_get_date_format(), "-"); locale_format_date(timestamp_str, &timestamp, locale_get_date_format(), "-");

View file

@ -23,6 +23,7 @@
#include <bit_lib.h> #include <bit_lib.h>
#include <datetime.h> #include <datetime.h>
#include <locale/locale.h>
#define TAG "Kazan" #define TAG "Kazan"
@ -317,74 +318,75 @@ static bool kazan_parse(const NfcDevice* device, FuriString* parsed_data) {
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, "\e#Kazan transport card\nCard number: %lu\n", card_number); parsed_data, "\e#Kazan transport card\nCard number: %lu\n", card_number);
LocaleDateFormat date_format = locale_get_date_format();
const char* separator = (date_format == LocaleDateFormatDMY) ? "." : "/";
FuriString* valid_from_str = furi_string_alloc();
locale_format_date(valid_from_str, &valid_from, date_format, separator);
FuriString* valid_to_str = furi_string_alloc();
locale_format_date(valid_to_str, &valid_to, date_format, separator);
FuriString* last_trip_date_str = furi_string_alloc();
locale_format_date(last_trip_date_str, &last_trip, date_format, separator);
FuriString* last_trip_time_str = furi_string_alloc();
locale_format_time(last_trip_time_str, &last_trip, locale_get_time_format(), false);
if(subscription_type == SUBSCRIPTION_TYPE_PURSE) { if(subscription_type == SUBSCRIPTION_TYPE_PURSE) {
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"Type: purse\nBalance: %lu RUR\nBalance valid:\nfrom: %02u.%02u.%u\nto: %02u.%02u.%u", "Type: purse\nBalance: %lu RUR\nBalance valid:\nfrom: %s\nto: %s",
trip_counter, trip_counter,
valid_from.day, furi_string_get_cstr(valid_from_str),
valid_from.month, furi_string_get_cstr(valid_to_str));
valid_from.year,
valid_to.day,
valid_to.month,
valid_to.year);
} }
if(subscription_type == SUBSCRIPTION_TYPE_ABONNEMENT_BY_TRIPS) { if(subscription_type == SUBSCRIPTION_TYPE_ABONNEMENT_BY_TRIPS) {
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"Type: abonnement\nTariff: %s\nTrips left: %lu\nCard valid:\nfrom: %02u.%02u.%u\nto: %02u.%02u.%u", "Type: abonnement\nTariff: %s\nTrips left: %lu\nCard valid:\nfrom: %s\nto: %s",
furi_string_get_cstr(tariff_name), furi_string_get_cstr(tariff_name),
trip_counter, trip_counter,
valid_from.day, furi_string_get_cstr(valid_from_str),
valid_from.month, furi_string_get_cstr(valid_to_str));
valid_from.year,
valid_to.day,
valid_to.month,
valid_to.year);
} }
if(subscription_type == SUBSCRIPTION_TYPE_ABONNEMENT_BY_TIME) { if(subscription_type == SUBSCRIPTION_TYPE_ABONNEMENT_BY_TIME) {
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"Type: abonnement\nTariff: %s\nTotal valid time: %lu days\nCard valid:\nfrom: %02u.%02u.%u\nto: %02u.%02u.%u", "Type: abonnement\nTariff: %s\nTotal valid time: %lu days\nCard valid:\nfrom: %s\nto: %s",
furi_string_get_cstr(tariff_name), furi_string_get_cstr(tariff_name),
trip_counter, trip_counter,
valid_from.day, furi_string_get_cstr(valid_from_str),
valid_from.month, furi_string_get_cstr(valid_to_str));
valid_from.year,
valid_to.day,
valid_to.month,
valid_to.year);
} }
if(subscription_type == SUBSCRIPTION_TYPE_UNKNOWN) { if(subscription_type == SUBSCRIPTION_TYPE_UNKNOWN) {
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"Type: unknown\nTariff: %s\nCounter: %lu\nValid from: %02u.%02u.%u\nValid to: %02u.%02u.%u", "Type: unknown\nTariff: %s\nCounter: %lu\nValid from: %s\nValid to: %s",
furi_string_get_cstr(tariff_name), furi_string_get_cstr(tariff_name),
trip_counter, trip_counter,
valid_from.day, furi_string_get_cstr(valid_from_str),
valid_from.month, furi_string_get_cstr(valid_to_str));
valid_from.year,
valid_to.day,
valid_to.month,
valid_to.year);
} }
if(is_last_trip_valid) { if(is_last_trip_valid) {
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"\nLast trip: %02u.%02u.%u at %02u:%02u", "\nLast trip: %s at %s",
last_trip.day, furi_string_get_cstr(last_trip_date_str),
last_trip.month, furi_string_get_cstr(last_trip_time_str));
last_trip.year,
last_trip.hour,
last_trip.minute);
} }
furi_string_free(tariff_name); furi_string_free(tariff_name);
furi_string_free(valid_from_str);
furi_string_free(valid_to_str);
furi_string_free(last_trip_date_str);
furi_string_free(last_trip_time_str);
parsed = true; parsed = true;
} while(false); } while(false);

View file

@ -82,7 +82,7 @@ static_assert(sizeof(OpalFile) == 16, "OpalFile");
// //
// Opal measures days since 1980-01-01 and minutes since midnight, and presumes // Opal measures days since 1980-01-01 and minutes since midnight, and presumes
// all days are 1440 minutes. // all days are 1440 minutes.
static void opal_date_time_to_furi(uint16_t days, uint16_t minutes, DateTime* out) { static void opal_days_minutes_to_datetime(uint16_t days, uint16_t minutes, DateTime* out) {
out->year = 1980; out->year = 1980;
out->month = 1; out->month = 1;
// 1980-01-01 is a Tuesday // 1980-01-01 is a Tuesday
@ -155,7 +155,7 @@ static bool opal_parse(const NfcDevice* device, FuriString* parsed_data) {
const int32_t balance_dollars = balance / 100; const int32_t balance_dollars = balance / 100;
DateTime timestamp; DateTime timestamp;
opal_date_time_to_furi(opal_file->days, opal_file->minutes, &timestamp); opal_days_minutes_to_datetime(opal_file->days, opal_file->minutes, &timestamp);
// Usages 4..6 associated with the Manly Ferry, which correspond to // Usages 4..6 associated with the Manly Ferry, which correspond to
// usages 1..3 for other modes. // usages 1..3 for other modes.

View file

@ -30,6 +30,7 @@
#include <bit_lib.h> #include <bit_lib.h>
#include <datetime.h> #include <datetime.h>
#include <locale/locale.h>
#define TAG "Umarsh" #define TAG "Umarsh"
@ -91,6 +92,19 @@ static bool umarsh_parse(const NfcDevice* device, FuriString* parsed_data) {
bool is_last_refill_datetime_valid = bool is_last_refill_datetime_valid =
parse_datetime(last_refill_date, &last_refill_datetime); parse_datetime(last_refill_date, &last_refill_datetime);
LocaleDateFormat date_format = locale_get_date_format();
const char* separator = (date_format == LocaleDateFormatDMY) ? "." : "/";
FuriString* expiry_datetime_str = furi_string_alloc();
locale_format_date(expiry_datetime_str, &expiry_datetime, date_format, separator);
FuriString* valid_to_datetime_str = furi_string_alloc();
locale_format_date(valid_to_datetime_str, &valid_to_datetime, date_format, separator);
FuriString* last_refill_datetime_str = furi_string_alloc();
locale_format_date(
last_refill_datetime_str, &last_refill_datetime, date_format, separator);
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"\e#Umarsh\nCard number: %lu\nRegion: %02u\nTerminal number: %lu\nRefill counter: %u\nBalance: %u.%02u RUR", "\e#Umarsh\nCard number: %lu\nRegion: %02u\nTerminal number: %lu\nRefill counter: %u\nBalance: %u.%02u RUR",
@ -103,25 +117,17 @@ static bool umarsh_parse(const NfcDevice* device, FuriString* parsed_data) {
if(is_expiry_datetime_valid) if(is_expiry_datetime_valid)
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data, "\nExpires: %s", furi_string_get_cstr(expiry_datetime_str));
"\nExpires: %02u.%02u.%u",
expiry_datetime.day,
expiry_datetime.month,
expiry_datetime.year);
if(is_valid_to_datetime_valid) if(is_valid_to_datetime_valid)
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data, "\nValid to: %s", furi_string_get_cstr(valid_to_datetime_str));
"\nValid to: %02u.%02u.%u",
valid_to_datetime.day,
valid_to_datetime.month,
valid_to_datetime.year);
if(is_last_refill_datetime_valid) if(is_last_refill_datetime_valid)
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data, "\nLast refill: %s", furi_string_get_cstr(last_refill_datetime_str));
"\nLast refill: %02u.%02u.%u",
last_refill_datetime.day, furi_string_free(expiry_datetime_str);
last_refill_datetime.month, furi_string_free(valid_to_datetime_str);
last_refill_datetime.year); furi_string_free(last_refill_datetime_str);
parsed = true; parsed = true;
} while(false); } while(false);

View file

@ -24,6 +24,7 @@
#include "protocols/mf_classic/mf_classic.h" #include "protocols/mf_classic/mf_classic.h"
#include <bit_lib.h> #include <bit_lib.h>
#include <locale/locale.h>
#include <furi_hal_rtc.h> #include <furi_hal_rtc.h>
#define TAG "Zolotaya Korona" #define TAG "Zolotaya Korona"
@ -124,6 +125,23 @@ static bool zolotaya_korona_parse(const NfcDevice* device, FuriString* parsed_da
uint32_t balance_rub = balance / 100; uint32_t balance_rub = balance / 100;
uint8_t balance_kop = balance % 100; uint8_t balance_kop = balance % 100;
LocaleDateFormat date_format = locale_get_date_format();
const char* separator = (date_format == LocaleDateFormatDMY) ? "." : "/";
FuriString* last_refill_date_str = furi_string_alloc();
locale_format_date(last_refill_date_str, &last_refill_datetime, date_format, separator);
FuriString* last_refill_time_str = furi_string_alloc();
locale_format_time(
last_refill_time_str, &last_refill_datetime, locale_get_time_format(), false);
FuriString* last_trip_date_str = furi_string_alloc();
locale_format_date(last_trip_date_str, &last_trip_datetime, date_format, separator);
FuriString* last_trip_time_str = furi_string_alloc();
locale_format_time(
last_trip_time_str, &last_trip_datetime, locale_get_time_format(), false);
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"\e#Zolotaya korona\nCard number: %u%015llu\nRegion: %u\nBalance: %lu.%02u RUR\nPrev. balance: %lu.%02u RUR", "\e#Zolotaya korona\nCard number: %u%015llu\nRegion: %u\nBalance: %lu.%02u RUR\nPrev. balance: %lu.%02u RUR",
@ -137,25 +155,19 @@ static bool zolotaya_korona_parse(const NfcDevice* device, FuriString* parsed_da
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"\nLast refill amount: %lu.%02u RUR\nRefill counter: %u\nLast refill: %u.%02u.%02u %02u:%02u\nRefill machine id: %u", "\nLast refill amount: %lu.%02u RUR\nRefill counter: %u\nLast refill: %s at %s\nRefill machine id: %u",
last_refill_amount_rub, last_refill_amount_rub,
last_refill_amount_kop, last_refill_amount_kop,
refill_counter, refill_counter,
last_refill_datetime.day, furi_string_get_cstr(last_refill_date_str),
last_refill_datetime.month, furi_string_get_cstr(last_refill_time_str),
last_refill_datetime.year,
last_refill_datetime.hour,
last_refill_datetime.minute,
refill_machine_id); refill_machine_id);
furi_string_cat_printf( furi_string_cat_printf(
parsed_data, parsed_data,
"\nLast trip: %u.%02u.%02u %02u:%02u\nTrack number: %u\nValidator: %c%06lu", "\nLast trip: %s at %s\nTrack number: %u\nValidator: %c%06lu",
last_trip_datetime.day, furi_string_get_cstr(last_trip_date_str),
last_trip_datetime.month, furi_string_get_cstr(last_trip_time_str),
last_trip_datetime.year,
last_trip_datetime.hour,
last_trip_datetime.minute,
track_number, track_number,
validator_first_letter, validator_first_letter,
validator_id); validator_id);
@ -169,6 +181,12 @@ static bool zolotaya_korona_parse(const NfcDevice* device, FuriString* parsed_da
discount_code); discount_code);
} }
furi_string_free(last_refill_date_str);
furi_string_free(last_refill_time_str);
furi_string_free(last_trip_date_str);
furi_string_free(last_trip_time_str);
parsed = true; parsed = true;
} while(false); } while(false);