From 380bfd307d08caf654a0bdcdbe7464f96084ffaf Mon Sep 17 00:00:00 2001 From: assasinfil Date: Wed, 24 Jan 2024 00:57:32 +0300 Subject: [PATCH 01/39] Updated troyka layout (full version) --- .../main/nfc/plugins/supported_cards/troika.c | 1560 ++++++++++++++++- 1 file changed, 1504 insertions(+), 56 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index 7cf1e4dd8c4..c67be437224 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -1,14 +1,19 @@ #include "nfc_supported_card_plugin.h" +#include #include #include +#include #include #include +#include +#include #define TAG "Troika" typedef struct { + uint8_t s; uint64_t a; uint64_t b; } MfClassicKeyPair; @@ -19,55 +24,1493 @@ typedef struct { } TroikaCardConfig; static const MfClassicKeyPair troika_1k_keys[] = { - {.a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58}, - {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, - {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, - {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, - {.a = 0x73068f118c13, .b = 0x2b7f3253fac5}, - {.a = 0xfbc2793d540b, .b = 0xd3a297dc2698}, - {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, - {.a = 0xae3d65a3dad4, .b = 0x0f1c63013dba}, - {.a = 0xa73f5dc1d333, .b = 0xe35173494a81}, - {.a = 0x69a32f1c2f19, .b = 0x6b8bd9860763}, - {.a = 0x9becdf3d9273, .b = 0xf8493407799d}, - {.a = 0x08b386463229, .b = 0x5efbaecef46b}, - {.a = 0xcd4c61c26e3d, .b = 0x31c7610de3b0}, - {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, - {.a = 0x0e8f64340ba4, .b = 0x4acec1205d75}, - {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.s = 0, .a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58}, + {.s = 1, .a = 0xa82607b01c0d, .b = 0x2910989b6880}, + {.s = 2, .a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.s = 3, .a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.s = 4, .a = 0x73068f118c13, .b = 0x2b7f3253fac5}, + {.s = 5, .a = 0xfbc2793d540b, .b = 0xd3a297dc2698}, + {.s = 6, .a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.s = 7, .a = 0xae3d65a3dad4, .b = 0x0f1c63013dba}, + {.s = 8, .a = 0xa73f5dc1d333, .b = 0xe35173494a81}, + {.s = 9, .a = 0x69a32f1c2f19, .b = 0x6b8bd9860763}, + {.s = 10, .a = 0x9becdf3d9273, .b = 0xf8493407799d}, + {.s = 11, .a = 0x08b386463229, .b = 0x5efbaecef46b}, + {.s = 12, .a = 0xcd4c61c26e3d, .b = 0x31c7610de3b0}, + {.s = 13, .a = 0xa82607b01c0d, .b = 0x2910989b6880}, + {.s = 14, .a = 0x0e8f64340ba4, .b = 0x4acec1205d75}, + {.s = 15, .a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, }; static const MfClassicKeyPair troika_4k_keys[] = { - {.a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58}, {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, - {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, - {.a = 0x73068f118c13, .b = 0x2b7f3253fac5}, {.a = 0xfbc2793d540b, .b = 0xd3a297dc2698}, - {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, {.a = 0xae3d65a3dad4, .b = 0x0f1c63013dbb}, - {.a = 0xa73f5dc1d333, .b = 0xe35173494a81}, {.a = 0x69a32f1c2f19, .b = 0x6b8bd9860763}, - {.a = 0x9becdf3d9273, .b = 0xf8493407799d}, {.a = 0x08b386463229, .b = 0x5efbaecef46b}, - {.a = 0xcd4c61c26e3d, .b = 0x31c7610de3b0}, {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, - {.a = 0x0e8f64340ba4, .b = 0x4acec1205d75}, {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, - {.a = 0x6b02733bb6ec, .b = 0x7038cd25c408}, {.a = 0x403d706ba880, .b = 0xb39d19a280df}, - {.a = 0xc11f4597efb5, .b = 0x70d901648cb9}, {.a = 0x0db520c78c1c, .b = 0x73e5b9d9d3a4}, - {.a = 0x3ebce0925b2f, .b = 0x372cc880f216}, {.a = 0x16a27af45407, .b = 0x9868925175ba}, - {.a = 0xaba208516740, .b = 0xce26ecb95252}, {.a = 0xcd64e567abcd, .b = 0x8f79c4fd8a01}, - {.a = 0x764cd061f1e6, .b = 0xa74332f74994}, {.a = 0x1cc219e9fec1, .b = 0xb90de525ceb6}, - {.a = 0x2fe3cb83ea43, .b = 0xfba88f109b32}, {.a = 0x07894ffec1d6, .b = 0xefcb0e689db3}, - {.a = 0x04c297b91308, .b = 0xc8454c154cb5}, {.a = 0x7a38e3511a38, .b = 0xab16584c972a}, - {.a = 0x7545df809202, .b = 0xecf751084a80}, {.a = 0x5125974cd391, .b = 0xd3eafb5df46d}, - {.a = 0x7a86aa203788, .b = 0xe41242278ca2}, {.a = 0xafcef64c9913, .b = 0x9db96dca4324}, - {.a = 0x04eaa462f70b, .b = 0xac17b93e2fae}, {.a = 0xe734c210f27e, .b = 0x29ba8c3e9fda}, - {.a = 0xd5524f591eed, .b = 0x5daf42861b4d}, {.a = 0xe4821a377b75, .b = 0xe8709e486465}, - {.a = 0x518dc6eea089, .b = 0x97c64ac98ca4}, {.a = 0xbb52f8cce07f, .b = 0x6b6119752c70}, + {.s = 0, .a = 0xEC29806D9738, .b = 0xFBF225DC5D58}, + {.s = 1, .a = 0xA0A1A2A3A4A5, .b = 0x7DE02A7F6025}, + {.s = 2, .a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, + {.s = 3, .a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, + {.s = 4, .a = 0x73068F118C13, .b = 0x2B7F3253FAC5}, + {.s = 5, .a = 0xFBC2793D540B, .b = 0xD3A297DC2698}, + {.s = 6, .a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, + {.s = 7, .a = 0xAE3D65A3DAD4, .b = 0x0F1C63013DBA}, + {.s = 8, .a = 0xA73F5DC1D333, .b = 0xE35173494A81}, + {.s = 9, .a = 0x69A32F1C2F19, .b = 0x6B8BD9860763}, + {.s = 10, .a = 0x9BECDF3D9273, .b = 0xF8493407799D}, + {.s = 11, .a = 0x08B386463229, .b = 0x5EFBAECEF46B}, + {.s = 12, .a = 0xCD4C61C26E3D, .b = 0x31C7610DE3B0}, + {.s = 13, .a = 0xA82607B01C0D, .b = 0x2910989B6880}, + {.s = 14, .a = 0x0E8F64340BA4, .b = 0x4ACEC1205D75}, + {.s = 15, .a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, + {.s = 16, .a = 0x6B02733BB6EC, .b = 0x7038CD25C408}, + {.s = 17, .a = 0x403D706BA880, .b = 0xB39D19A280DF}, + {.s = 18, .a = 0xC11F4597EFB5, .b = 0x70D901648CB9}, + {.s = 19, .a = 0x0DB520C78C1C, .b = 0x73E5B9D9D3A4}, + {.s = 20, .a = 0x3EBCE0925B2F, .b = 0x372CC880F216}, + {.s = 21, .a = 0x16A27AF45407, .b = 0x9868925175BA}, + {.s = 22, .a = 0xABA208516740, .b = 0xCE26ECB95252}, + {.s = 23, .a = 0xCD64E567ABCD, .b = 0x8F79C4FD8A01}, + {.s = 24, .a = 0x764CD061F1E6, .b = 0xA74332F74994}, + {.s = 25, .a = 0x1CC219E9FEC1, .b = 0xB90DE525CEB6}, + {.s = 26, .a = 0x2FE3CB83EA43, .b = 0xFBA88F109B32}, + {.s = 27, .a = 0x07894FFEC1D6, .b = 0xEFCB0E689DB3}, + {.s = 28, .a = 0x04C297B91308, .b = 0xC8454C154CB5}, + {.s = 29, .a = 0x7A38E3511A38, .b = 0xAB16584C972A}, + {.s = 30, .a = 0x7545DF809202, .b = 0xECF751084A80}, + {.s = 31, .a = 0x5125974CD391, .b = 0xD3EAFB5DF46D}, + {.s = 32, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, + {.s = 33, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, + {.s = 34, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, + {.s = 35, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, + {.s = 36, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, + {.s = 37, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, + {.s = 38, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, + {.s = 39, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, }; +#define TOPBIT(X) (1 << ((X)-1)) + +typedef enum { + BitLibParityEven, + BitLibParityOdd, + BitLibParityAlways0, + BitLibParityAlways1, +} BitLibParity; + +typedef struct { + const char mark; + const size_t start; + const size_t length; +} BitLibRegion; + +void bit_lib_push_bit(uint8_t* data, size_t data_size, bool bit) { + size_t last_index = data_size - 1; + + for(size_t i = 0; i < last_index; ++i) { + data[i] = (data[i] << 1) | ((data[i + 1] >> 7) & 1); + } + data[last_index] = (data[last_index] << 1) | bit; +} + +void bit_lib_set_bit(uint8_t* data, size_t position, bool bit) { + if(bit) { + data[position / 8] |= 1UL << (7 - (position % 8)); + } else { + data[position / 8] &= ~(1UL << (7 - (position % 8))); + } +} + +void bit_lib_set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length) { + furi_check(length <= 8); + furi_check(length > 0); + + for(uint8_t i = 0; i < length; ++i) { + uint8_t shift = (length - 1) - i; + bit_lib_set_bit(data, position + i, (byte >> shift) & 1); //-V610 + } +} + +bool bit_lib_get_bit(const uint8_t* data, size_t position) { + return (data[position / 8] >> (7 - (position % 8))) & 1; +} + +uint8_t bit_lib_get_bits(const uint8_t* data, size_t position, uint8_t length) { + uint8_t shift = position % 8; + if(shift == 0) { + return data[position / 8] >> (8 - length); + } else { + // TODO fix read out of bounds + uint8_t value = (data[position / 8] << (shift)); + value |= data[position / 8 + 1] >> (8 - shift); + value = value >> (8 - length); + return value; + } +} + +uint16_t bit_lib_get_bits_16(const uint8_t* data, size_t position, uint8_t length) { + uint16_t value = 0; + if(length <= 8) { + value = bit_lib_get_bits(data, position, length); + } else { + value = bit_lib_get_bits(data, position, 8) << (length - 8); + value |= bit_lib_get_bits(data, position + 8, length - 8); + } + return value; +} + +uint32_t bit_lib_get_bits_32(const uint8_t* data, size_t position, uint8_t length) { + uint32_t value = 0; + if(length <= 8) { + value = bit_lib_get_bits(data, position, length); + } else if(length <= 16) { + value = bit_lib_get_bits(data, position, 8) << (length - 8); + value |= bit_lib_get_bits(data, position + 8, length - 8); + } else if(length <= 24) { + value = bit_lib_get_bits(data, position, 8) << (length - 8); + value |= bit_lib_get_bits(data, position + 8, 8) << (length - 16); + value |= bit_lib_get_bits(data, position + 16, length - 16); + } else { + value = (uint32_t)bit_lib_get_bits(data, position, 8) << (length - 8); + value |= (uint32_t)bit_lib_get_bits(data, position + 8, 8) << (length - 16); + value |= (uint32_t)bit_lib_get_bits(data, position + 16, 8) << (length - 24); + value |= bit_lib_get_bits(data, position + 24, length - 24); + } + + return value; +} + +uint64_t bit_lib_get_bits_64(const uint8_t* data, size_t position, uint8_t length) { + uint64_t value = 0; + if(length <= 8) { + value = bit_lib_get_bits(data, position, length); + } else if(length <= 16) { + value = bit_lib_get_bits(data, position, 8) << (length - 8); + value |= bit_lib_get_bits(data, position + 8, length - 8); + } else if(length <= 24) { + value = bit_lib_get_bits(data, position, 8) << (length - 8); + value |= bit_lib_get_bits(data, position + 8, 8) << (length - 16); + value |= bit_lib_get_bits(data, position + 16, length - 16); + } else if(length <= 32) { + value = (uint64_t)bit_lib_get_bits(data, position, 8) << (length - 8); + value |= (uint64_t)bit_lib_get_bits(data, position + 8, 8) << (length - 16); + value |= (uint64_t)bit_lib_get_bits(data, position + 16, 8) << (length - 24); + value |= bit_lib_get_bits(data, position + 24, length - 24); + } else { + value = (uint64_t)bit_lib_get_bits(data, position, 8) << (length - 8); + value |= (uint64_t)bit_lib_get_bits(data, position + 8, 8) << (length - 16); + value |= (uint64_t)bit_lib_get_bits(data, position + 16, 8) << (length - 24); + value |= (uint64_t)bit_lib_get_bits(data, position + 24, 8) << (length - 32); + value |= (uint64_t)bit_lib_get_bits(data, position + 32, 8) << (length - 40); + value |= (uint64_t)bit_lib_get_bits(data, position + 40, 8) << (length - 48); + value |= (uint64_t)bit_lib_get_bits(data, position + 48, 8) << (length - 56); + value |= (uint64_t)bit_lib_get_bits(data, position + 56, 8) << (length - 64); + value |= bit_lib_get_bits(data, position + 64, length - 64); + } + + return value; +} + +bool bit_lib_test_parity_32(uint32_t bits, BitLibParity parity) { +#if !defined __GNUC__ +#error Please, implement parity test for non-GCC compilers +#else + switch(parity) { + case BitLibParityEven: + return __builtin_parity(bits); + case BitLibParityOdd: + return !__builtin_parity(bits); + default: + furi_crash("Unknown parity"); + } +#endif +} + +bool bit_lib_test_parity( + const uint8_t* bits, + size_t position, + uint8_t length, + BitLibParity parity, + uint8_t parity_length) { + uint32_t parity_block; + bool result = true; + const size_t parity_blocks_count = length / parity_length; + + for(size_t i = 0; i < parity_blocks_count; ++i) { + switch(parity) { + case BitLibParityEven: + case BitLibParityOdd: + parity_block = bit_lib_get_bits_32(bits, position + i * parity_length, parity_length); + if(!bit_lib_test_parity_32(parity_block, parity)) { + result = false; + } + break; + case BitLibParityAlways0: + if(bit_lib_get_bit(bits, position + i * parity_length + parity_length - 1)) { + result = false; + } + break; + case BitLibParityAlways1: + if(!bit_lib_get_bit(bits, position + i * parity_length + parity_length - 1)) { + result = false; + } + break; + } + + if(!result) break; + } + return result; +} + +size_t bit_lib_add_parity( + const uint8_t* data, + size_t position, + uint8_t* dest, + size_t dest_position, + uint8_t source_length, + uint8_t parity_length, + BitLibParity parity) { + uint32_t parity_word = 0; + size_t j = 0, bit_count = 0; + for(int word = 0; word < source_length; word += parity_length - 1) { + for(int bit = 0; bit < parity_length - 1; bit++) { + parity_word = (parity_word << 1) | bit_lib_get_bit(data, position + word + bit); + bit_lib_set_bit( + dest, dest_position + j++, bit_lib_get_bit(data, position + word + bit)); + } + // if parity fails then return 0 + switch(parity) { + case BitLibParityAlways0: + bit_lib_set_bit(dest, dest_position + j++, 0); + break; // marker bit which should be a 0 + case BitLibParityAlways1: + bit_lib_set_bit(dest, dest_position + j++, 1); + break; // marker bit which should be a 1 + default: + bit_lib_set_bit( + dest, + dest_position + j++, + (bit_lib_test_parity_32(parity_word, BitLibParityOdd) ^ parity) ^ 1); + break; + } + bit_count += parity_length; + parity_word = 0; + } + // if we got here then all the parities passed + // return bit count + return bit_count; +} + +size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n) { + size_t counter = 0; + size_t result_counter = 0; + uint8_t bit_buffer = 0; + uint8_t bit_counter = 0; + + while(counter < length) { + if((counter + 1) % n != 0) { + bit_buffer = (bit_buffer << 1) | bit_lib_get_bit(data, position + counter); + bit_counter++; + } + + if(bit_counter == 8) { + bit_lib_set_bits(data, position + result_counter, bit_buffer, 8); + bit_counter = 0; + bit_buffer = 0; + result_counter += 8; + } + counter++; + } + + if(bit_counter != 0) { + bit_lib_set_bits(data, position + result_counter, bit_buffer, bit_counter); + result_counter += bit_counter; + } + return result_counter; +} + +void bit_lib_copy_bits( + uint8_t* data, + size_t position, + size_t length, + const uint8_t* source, + size_t source_position) { + for(size_t i = 0; i < length; ++i) { + bit_lib_set_bit(data, position + i, bit_lib_get_bit(source, source_position + i)); + } +} + +void bit_lib_reverse_bits(uint8_t* data, size_t position, uint8_t length) { + size_t i = 0; + size_t j = length - 1; + + while(i < j) { + bool tmp = bit_lib_get_bit(data, position + i); + bit_lib_set_bit(data, position + i, bit_lib_get_bit(data, position + j)); + bit_lib_set_bit(data, position + j, tmp); + i++; + j--; + } +} + +uint8_t bit_lib_get_bit_count(uint32_t data) { +#if defined __GNUC__ + return __builtin_popcountl(data); +#else +#error Please, implement popcount for non-GCC compilers +#endif +} + +void bit_lib_print_bits(const uint8_t* data, size_t length) { + for(size_t i = 0; i < length; ++i) { + printf("%u", bit_lib_get_bit(data, i)); + } +} + +void bit_lib_print_regions( + const BitLibRegion* regions, + size_t region_count, + const uint8_t* data, + size_t length) { + // print data + bit_lib_print_bits(data, length); + printf("\r\n"); + + // print regions + for(size_t c = 0; c < length; ++c) { + bool print = false; + + for(size_t i = 0; i < region_count; i++) { + if(regions[i].start <= c && c < regions[i].start + regions[i].length) { + print = true; + printf("%c", regions[i].mark); + break; + } + } + + if(!print) { + printf(" "); + } + } + printf("\r\n"); + + // print regions data + for(size_t c = 0; c < length; ++c) { + bool print = false; + + for(size_t i = 0; i < region_count; i++) { + if(regions[i].start <= c && c < regions[i].start + regions[i].length) { + print = true; + printf("%u", bit_lib_get_bit(data, c)); + break; + } + } + + if(!print) { + printf(" "); + } + } + printf("\r\n"); +} + +uint16_t bit_lib_reverse_16_fast(uint16_t data) { + uint16_t result = 0; + result |= (data & 0x8000) >> 15; + result |= (data & 0x4000) >> 13; + result |= (data & 0x2000) >> 11; + result |= (data & 0x1000) >> 9; + result |= (data & 0x0800) >> 7; + result |= (data & 0x0400) >> 5; + result |= (data & 0x0200) >> 3; + result |= (data & 0x0100) >> 1; + result |= (data & 0x0080) << 1; + result |= (data & 0x0040) << 3; + result |= (data & 0x0020) << 5; + result |= (data & 0x0010) << 7; + result |= (data & 0x0008) << 9; + result |= (data & 0x0004) << 11; + result |= (data & 0x0002) << 13; + result |= (data & 0x0001) << 15; + return result; +} + +uint8_t bit_lib_reverse_8_fast(uint8_t byte) { + byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4; + byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2; + byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1; + return byte; +} + +uint16_t bit_lib_crc8( + uint8_t const* data, + size_t data_size, + uint8_t polynom, + uint8_t init, + bool ref_in, + bool ref_out, + uint8_t xor_out) { + uint8_t crc = init; + + for(size_t i = 0; i < data_size; ++i) { + uint8_t byte = data[i]; + if(ref_in) bit_lib_reverse_bits(&byte, 0, 8); + crc ^= byte; + + for(size_t j = 8; j > 0; --j) { + if(crc & TOPBIT(8)) { + crc = (crc << 1) ^ polynom; + } else { + crc = (crc << 1); + } + } + } + + if(ref_out) bit_lib_reverse_bits(&crc, 0, 8); + crc ^= xor_out; + + return crc; +} + +uint16_t bit_lib_crc16( + uint8_t const* data, + size_t data_size, + uint16_t polynom, + uint16_t init, + bool ref_in, + bool ref_out, + uint16_t xor_out) { + uint16_t crc = init; + + for(size_t i = 0; i < data_size; ++i) { + uint8_t byte = data[i]; + if(ref_in) byte = bit_lib_reverse_16_fast(byte) >> 8; + + for(size_t j = 0; j < 8; ++j) { + bool c15 = (crc >> 15 & 1); + bool bit = (byte >> (7 - j) & 1); + crc <<= 1; + if(c15 ^ bit) crc ^= polynom; + } + } + + if(ref_out) crc = bit_lib_reverse_16_fast(crc); + crc ^= xor_out; + + return crc; +} + +#define FURI_HAL_RTC_SECONDS_PER_MINUTE 60 +#define FURI_HAL_RTC_SECONDS_PER_HOUR (FURI_HAL_RTC_SECONDS_PER_MINUTE * 60) +#define FURI_HAL_RTC_SECONDS_PER_DAY (FURI_HAL_RTC_SECONDS_PER_HOUR * 24) +#define FURI_HAL_RTC_EPOCH_START_YEAR 1970 +#define FURI_HAL_RTC_IS_LEAP_YEAR(year) \ + ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0)) + +void timestamp_to_datetime(uint32_t timestamp, FuriHalRtcDateTime* datetime) { + uint32_t days = timestamp / FURI_HAL_RTC_SECONDS_PER_DAY; + uint32_t seconds_in_day = timestamp % FURI_HAL_RTC_SECONDS_PER_DAY; + + datetime->year = FURI_HAL_RTC_EPOCH_START_YEAR; + + while(days >= furi_hal_rtc_get_days_per_year(datetime->year)) { + days -= furi_hal_rtc_get_days_per_year(datetime->year); + (datetime->year)++; + } + + datetime->month = 1; + while(days >= furi_hal_rtc_get_days_per_month( + FURI_HAL_RTC_IS_LEAP_YEAR(datetime->year), datetime->month)) { + days -= furi_hal_rtc_get_days_per_month( + FURI_HAL_RTC_IS_LEAP_YEAR(datetime->year), datetime->month); + (datetime->month)++; + } + + datetime->day = days + 1; + datetime->hour = seconds_in_day / FURI_HAL_RTC_SECONDS_PER_HOUR; + datetime->minute = + (seconds_in_day % FURI_HAL_RTC_SECONDS_PER_HOUR) / FURI_HAL_RTC_SECONDS_PER_MINUTE; + datetime->second = seconds_in_day % FURI_HAL_RTC_SECONDS_PER_MINUTE; +} + +void from_days_to_datetime(uint16_t days, FuriHalRtcDateTime* datetime, uint16_t start_year) { + uint32_t timestamp = days * 24 * 60 * 60; + FuriHalRtcDateTime start_datetime = {0}; + start_datetime.year = start_year - 1; + start_datetime.month = 12; + start_datetime.day = 31; + timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); + timestamp_to_datetime(timestamp, datetime); +} + +void from_minutes_to_datetime(uint32_t minutes, FuriHalRtcDateTime* datetime, uint16_t start_year) { + uint32_t timestamp = minutes * 60; + FuriHalRtcDateTime start_datetime = {0}; + start_datetime.year = start_year - 1; + start_datetime.month = 12; + start_datetime.day = 31; + timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); + timestamp_to_datetime(timestamp, datetime); +} + +bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { + uint16_t transport_departament = bit_lib_get_bits_16(block->data, 0, 10); + + FURI_LOG_I(TAG, "Transport departament: %x", transport_departament); + + uint16_t layout_type = bit_lib_get_bits_16(block->data, 52, 4); + if(layout_type == 0xE) { + layout_type = bit_lib_get_bits_16(block->data, 52, 9); + } else if(layout_type == 0xF) { + layout_type = bit_lib_get_bits_16(block->data, 52, 14); + } + + FURI_LOG_I(TAG, "Layout type %x", layout_type); + + uint16_t card_view = 0; + uint16_t card_type = 0; + uint32_t card_number = 0; + uint8_t card_layout = 0; + uint8_t card_layout2 = 0; + uint16_t card_use_before_date = 0; + uint16_t card_blank_type = 0; + uint32_t card_start_trip_minutes = 0; + uint8_t card_minutes_pass = 0; + uint32_t card_remaining_funds = 0; + uint16_t card_validator = 0; + uint8_t card_blocked = 0; + uint32_t card_hash = 0; + + switch(layout_type) { + case 0x02: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + uint8_t card_benefit_code = bit_lib_get_bits(block->data, 72, 8); //124 + uint32_t card_rfu1 = bit_lib_get_bits_32(block->data, 80, 32); //rfu1 + uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 + card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 177, 12); //403 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 189, 16); //402 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 + uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 173, 16); //312 + uint8_t card_start_trip_seconds = bit_lib_get_bits(block->data, 189, 6); //406 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 + uint16_t card_use_with_date = bit_lib_get_bits_16(block->data, 189, 16); //205 + uint8_t card_route = bit_lib_get_bits(block->data, 205, 1); //424 + uint16_t card_validator1 = bit_lib_get_bits_16(block->data, 206, 15); //422.1 + card_validator = bit_lib_get_bits_16(block->data, 205, 16); //422 + uint16_t card_total_trips = bit_lib_get_bits_16(block->data, 221, 16); //331 + uint8_t card_write_enabled = bit_lib_get_bits(block->data, 237, 1); //write_enabled + uint8_t card_rfu2 = bit_lib_get_bits(block->data, 238, 2); //rfu2 + uint16_t card_crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_use_before_date, + card_benefit_code, + card_rfu1, + card_crc16, + card_blocked, + card_start_trip_time, + card_start_trip_date, + card_valid_from_date, + card_valid_by_date, + card_start_trip_seconds, + card_transport_type1, + card_transport_type2, + card_transport_type3, + card_transport_type4, + card_use_with_date, + card_route, + card_validator1, + card_validator, + card_total_trips, + card_write_enabled, + card_rfu2, + card_crc16_2); + if(card_valid_by_date == 0) { + return false; + } + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_start_trip_date) * 24 * 60 + card_start_trip_time, + &card_start_trip_minutes_s, + 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips: %d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_total_trips, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x06: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + uint8_t card_geozone_a = bit_lib_get_bits(block->data, 72, 4); //GeoZoneA + uint8_t card_geozone_b = bit_lib_get_bits(block->data, 76, 4); //GeoZoneB + card_blank_type = bit_lib_get_bits_16(block->data, 80, 10); //121. + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 90, 10); //122 + uint32_t card_rfu1 = bit_lib_get_bits_16(block->data, 100, 12); //rfu1 + uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 + card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 129, 12); //403 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 141, 16); //402 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 + uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 173, 16); //312 + uint16_t card_company = bit_lib_get_bits(block->data, 189, 4); //Company + uint8_t card_validator1 = bit_lib_get_bits(block->data, 193, 4); //422.1 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 197, 10); //321 + uint8_t card_units = bit_lib_get_bits(block->data, 207, 6); //Units + uint16_t card_validator2 = bit_lib_get_bits_16(block->data, 213, 10); //422.2 + uint16_t card_total_trips = bit_lib_get_bits_16(block->data, 223, 16); //331 + uint8_t card_extended = bit_lib_get_bits(block->data, 239, 1); //123 + uint16_t card_crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %x %x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_use_before_date, + card_geozone_a, + card_geozone_b, + card_blank_type, + card_type_of_extended, + card_rfu1, + card_crc16, + card_blocked, + card_start_trip_time, + card_start_trip_date, + card_valid_from_date, + card_valid_by_date, + card_company, + card_validator1, + card_remaining_trips, + card_units, + card_validator2, + card_total_trips, + card_extended, + card_crc16_2); + card_validator = card_validator1 * 1024 + card_validator2; + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_start_trip_date) * 24 * 60 + card_start_trip_time, + &card_start_trip_minutes_s, + 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips left: %d of %d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_remaining_trips, + card_total_trips, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x08: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 + uint8_t card_rfu2 = bit_lib_get_bits(block->data, 153, 7); //rfu2 + uint8_t card_remaining_trips1 = bit_lib_get_bits(block->data, 160, 8); //321.1 + uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 168, 8); //321 + uint8_t card_validator1 = bit_lib_get_bits(block->data, 193, 2); //422.1 + uint16_t card_validator = bit_lib_get_bits_16(block->data, 177, 15); //422 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 + uint32_t card_rfu3 = bit_lib_get_bits_32(block->data, 224, 32); //rfu3 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %llx %x %x %x %x %x %x %x %x %lx %x %lx", + card_view, + card_type, + card_number, + card_use_before_date, + card_rfu1, + card_valid_from_date, + card_valid_for_days, + card_requires_activation, + card_rfu2, + card_remaining_trips1, + card_remaining_trips, + card_validator1, + card_validator, + card_hash, + card_valid_from_date, + card_rfu3); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips left: %d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_remaining_trips, + card_validator); + break; + } + case 0x0A: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 64, 12); //311 + uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 76, 19); //314 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 95, 1); //301 + card_start_trip_minutes = bit_lib_get_bits_32(block->data, 96, 19); //405 + card_minutes_pass = bit_lib_get_bits(block->data, 119, 7); //412 + uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 126, 2); //421.0 + uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 128, 8); //321 + uint16_t card_validator = bit_lib_get_bits_16(block->data, 136, 16); //422 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 152, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 154, 2); //421.2 + uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 156, 2); //421.3 + uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 158, 2); //421.4 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %lx %x %lx %x %x %x %x %x %x %x %x %lx", + card_view, + card_type, + card_number, + card_use_before_date, + card_valid_from_date, + card_valid_for_minutes, + card_requires_activation, + card_start_trip_minutes, + card_minutes_pass, + card_transport_type_flag, + card_remaining_trips, + card_validator, + card_transport_type1, + card_transport_type2, + card_transport_type3, + card_transport_type4, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_remaining_trips, + card_validator); + break; + } + case 0x0C: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 + uint16_t card_rfu2 = bit_lib_get_bits_16(block->data, 153, 13); //rfu2 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 + uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 + uint8_t card_transport_type = bit_lib_get_bits(block->data, 251, 2); //421 + uint8_t card_rfu3 = bit_lib_get_bits(block->data, 253, 2); //rfu3 + uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 255, 1); //432 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %llx %x %x %x %x %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_use_before_date, + card_rfu1, + card_valid_from_date, + card_valid_for_days, + card_requires_activation, + card_rfu2, + card_remaining_trips, + card_validator, + card_start_trip_date, + card_start_trip_time, + card_transport_type, + card_rfu3, + card_transfer_in_metro); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_start_trip_date) * 24 * 60 + card_start_trip_time, + &card_start_trip_minutes_s, + 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_remaining_trips, + card_validator); + break; + } + case 0x0D: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + uint8_t card_rfu1 = bit_lib_get_bits(block->data, 56, 8); //rfu1 + card_use_before_date = bit_lib_get_bits_16(block->data, 64, 16); //202 + uint16_t card_valid_for_time = bit_lib_get_bits_16(block->data, 80, 11); //316 + uint8_t card_rfu2 = bit_lib_get_bits(block->data, 91, 5); //rfu2 + uint16_t card_use_before_date2 = bit_lib_get_bits_16(block->data, 96, 16); //202.2 + uint16_t card_valid_for_time2 = bit_lib_get_bits_16(block->data, 123, 11); //316.2 + uint8_t card_rfu3 = bit_lib_get_bits(block->data, 123, 5); //rfu3 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 + uint8_t card_rfu4 = bit_lib_get_bits(block->data, 153, 2); //rfu4 + uint8_t card_passage_5_minutes = bit_lib_get_bits(block->data, 155, 5); //413 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 160, 2); //421.1 + uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 162, 1); //431 + uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 163, 3); //433 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 + uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 251, 2); //421.2 + uint8_t card_rfu5 = bit_lib_get_bits(block->data, 253, 2); //rfu5 + uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 255, 1); //432 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_layout, + card_rfu1, + card_use_before_date, + card_valid_for_time, + card_rfu2, + card_use_before_date2, + card_valid_for_time2, + card_rfu3, + card_valid_from_date, + card_valid_for_days, + card_requires_activation, + card_rfu4, + card_passage_5_minutes, + card_transport_type1, + card_passage_in_metro, + card_passages_ground_transport, + card_remaining_trips, + card_validator, + card_start_trip_date, + card_start_trip_time, + card_transport_type2, + card_rfu5, + card_transfer_in_metro); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_start_trip_date) * 24 * 60 + card_start_trip_time, + &card_start_trip_minutes_s, + 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_remaining_trips, + card_validator); + break; + } + case 0x1C1: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121. + card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 144, 16); //402 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 160, 11); //403 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 171, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 173, 2); //421.2 + uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 177, 1); //432 + uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 178, 1); //431 + uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 179, 3); //433 + card_minutes_pass = bit_lib_get_bits(block->data, 185, 8); //412. + card_remaining_funds = bit_lib_get_bits_32(block->data, 196, 19) / 100; //322 + uint8_t card_fare_trip = bit_lib_get_bits(block->data, 215, 2); //441 + card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 + uint8_t card_zoo = bit_lib_get_bits(block->data, 218, 1); //zoo + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %lx %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_use_before_date, + card_blank_type, + card_validator, + card_start_trip_date, + card_start_trip_time, + card_transport_type1, + card_transport_type2, + card_transfer_in_metro, + card_passage_in_metro, + card_passages_ground_transport, + card_minutes_pass, + card_remaining_funds, + card_fare_trip, + card_blocked, + card_zoo, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C2: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 + card_use_before_date = bit_lib_get_bits_16(block->data, 71, 16); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 87, 10); //121. + uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 97, 16); //311 + uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 113, 9); //302 + uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 131, 20); //314 + card_minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412. + uint8_t card_transport_type = bit_lib_get_bits(block->data, 163, 2); //421 + uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 165, 1); //431 + uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 166, 1); //432 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 167, 10); //321 + card_validator = bit_lib_get_bits_16(block->data, 177, 16); //422 + uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 196, 20); //404 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 216, 1); //301 + card_blocked = bit_lib_get_bits(block->data, 217, 1); //303 + uint8_t card_extended = bit_lib_get_bits(block->data, 218, 1); //123 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %x %x %x %x %x %lx %x %x %x %x %x %x %lx %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_type_of_extended, + card_use_before_date, + card_blank_type, + card_valid_to_date, + card_activate_during, + card_valid_for_minutes, + card_minutes_pass, + card_transport_type, + card_passage_in_metro, + card_transfer_in_metro, + card_remaining_trips, + card_validator, + card_start_trip_neg_minutes, + card_requires_activation, + card_blocked, + card_extended, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_valid_to_date) * 24 * 60 + card_valid_for_minutes - card_start_trip_neg_minutes, + &card_start_trip_minutes_s, + 2016); //-time + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C3: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 + card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121 + card_remaining_funds = bit_lib_get_bits_32(block->data, 188, 22) / 100; //322 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 + card_start_trip_minutes = bit_lib_get_bits_32(block->data, 144, 23); //405 + uint8_t card_fare_trip = bit_lib_get_bits(block->data, 210, 2); //441 + card_minutes_pass = bit_lib_get_bits(block->data, 171, 7); //412 + uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 + card_blocked = bit_lib_get_bits(block->data, 212, 1); //303 + FURI_LOG_D( + TAG, + "Card view: %x, type: %x, number: %lx, layout: %x, layout2: %x, use before date: %x, blank type: %x, remaining funds: %lx, hash: %lx, validator: %x, start trip minutes: %lx, fare trip: %x, minutes pass: %x, transport type flag: %x, transport type1: %x, transport type2: %x, transport type3: %x, transport type4: %x, blocked: %x", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_use_before_date, + card_blank_type, + card_remaining_funds, + card_hash, + card_validator, + card_start_trip_minutes, + card_fare_trip, + card_minutes_pass, + card_transport_type_flag, + card_transport_type1, + card_transport_type2, + card_transport_type3, + card_transport_type4, + card_blocked); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nBalance: %ld rub\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_remaining_funds, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C4: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 + card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. + uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 94, 13); //311 + uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 107, 9); //302 + uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 116, 10); //304 + uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 + card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. + uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 169, 10); //321 + card_validator = bit_lib_get_bits_16(block->data, 179, 16); //422 + uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 195, 20); //404 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 215, 1); //301 + card_blocked = bit_lib_get_bits(block->data, 216, 1); //303 + uint8_t card_extended = bit_lib_get_bits(block->data, 217, 1); //123 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %x %x %x %x %x %x %lx %x %x %x %x %x %x %x %x %lx %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_type_of_extended, + card_use_before_date, + card_blank_type, + card_valid_to_date, + card_activate_during, + card_extension_counter, + card_valid_for_minutes, + card_minutes_pass, + card_transport_type_flag, + card_transport_type1, + card_transport_type2, + card_transport_type3, + card_transport_type4, + card_remaining_trips, + card_validator, + card_start_trip_neg_minutes, + card_requires_activation, + card_blocked, + card_extended, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_use_before_date + 1) * 24 * 60 + card_valid_for_minutes - + card_start_trip_neg_minutes, + &card_start_trip_minutes_s, + 2011); //-time + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C5: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + card_use_before_date = bit_lib_get_bits_16(block->data, 61, 13); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 74, 10); //121. + uint32_t card_valid_to_time = bit_lib_get_bits_32(block->data, 84, 23); //317 + uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 107, 10); //304 + card_start_trip_minutes = bit_lib_get_bits_32(block->data, 128, 23); //405 + uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 151, 7); //414 + card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. + card_remaining_funds = bit_lib_get_bits_32(block->data, 167, 19) / 100; //322 + card_validator = bit_lib_get_bits_16(block->data, 186, 16); //422 + card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 + uint16_t card_route = bit_lib_get_bits_16(block->data, 204, 12); //424 + uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 216, 7); //433 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %x %x %lx %x %lx %x %x %lx %x %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_use_before_date, + card_blank_type, + card_valid_to_time, + card_extension_counter, + card_start_trip_minutes, + card_metro_ride_with, + card_minutes_pass, + card_remaining_funds, + card_validator, + card_blocked, + card_route, + card_passages_ground_transport, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2019); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nBalance: %ld rub\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_remaining_funds, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C6: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 + card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. + uint32_t card_valid_from_date = bit_lib_get_bits_32(block->data, 94, 23); //311 + uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 117, 10); //304 + uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 + uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 148, 20); //404 + uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 168, 7); //414 + card_minutes_pass = bit_lib_get_bits(block->data, 175, 7); //412. + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 182, 7); //321 + card_validator = bit_lib_get_bits_16(block->data, 189, 16); //422 + card_blocked = bit_lib_get_bits(block->data, 205, 1); //303 + uint8_t card_extended = bit_lib_get_bits(block->data, 206, 1); //123 + uint16_t card_route = bit_lib_get_bits_16(block->data, 212, 12); //424 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %x %x %x %lx %x %lx %lx %x %x %x %x %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_type_of_extended, + card_use_before_date, + card_blank_type, + card_valid_from_date, + card_extension_counter, + card_valid_for_minutes, + card_start_trip_neg_minutes, + card_metro_ride_with, + card_minutes_pass, + card_remaining_trips, + card_validator, + card_blocked, + card_extended, + card_route, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + card_valid_from_date + card_valid_for_minutes - card_start_trip_neg_minutes, + &card_start_trip_minutes_s, + 2019); //-time + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x3CCB: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code + uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 + uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 + uint8_t card_interval = bit_lib_get_bits(block->data, 98, 4); //interval + uint16_t card_app_code1 = bit_lib_get_bits_16(block->data, 102, 16); //app_code1 + uint16_t card_hash1 = bit_lib_get_bits_16(block->data, 112, 16); //502.1 + uint16_t card_type1 = bit_lib_get_bits_16(block->data, 128, 10); //type1 + uint16_t card_app_code2 = bit_lib_get_bits_16(block->data, 138, 10); //app_code2 + uint16_t card_type2 = bit_lib_get_bits_16(block->data, 148, 10); //type2 + uint16_t card_app_code3 = bit_lib_get_bits_16(block->data, 158, 10); //app_code3 + uint16_t card_type3 = bit_lib_get_bits_16(block->data, 148, 10); //type3 + uint16_t card_app_code4 = bit_lib_get_bits_16(block->data, 168, 10); //app_code4 + uint16_t card_type4 = bit_lib_get_bits_16(block->data, 178, 10); //type4 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502.2 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_tech_code, + card_use_before_date, + card_blank_type, + card_valid_to_minutes, + card_valid_by_date, + card_interval, + card_app_code1, + card_hash1, + card_type1, + card_app_code2, + card_type2, + card_app_code3, + card_type3, + card_app_code4, + card_type4, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); + + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_validator); + break; + } + case 0x3C0B: { + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code + uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 + uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 + uint16_t card_hash = bit_lib_get_bits_16(block->data, 112, 16); //502.1 + + FURI_LOG_D( + TAG, + "%x %x %lx %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_layout, + card_tech_code, + card_use_before_date, + card_blank_type, + card_valid_to_minutes, + card_valid_by_date, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); + + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_validator); + break; + } + default: + return false; + } + + return true; +} + static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) { bool success = true; if(type == MfClassicType1k) { - config->data_sector = 8; + config->data_sector = 11; config->keys = troika_1k_keys; } else if(type == MfClassicType4k) { - config->data_sector = 4; + config->data_sector = 11; config->keys = troika_4k_keys; } else { success = false; @@ -96,7 +1539,7 @@ static bool troika_verify_type(Nfc* nfc, MfClassicType type) { FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); break; } - + FURI_LOG_D(TAG, "Verify success!"); verified = true; } while(false); @@ -171,23 +1614,28 @@ static bool troika_parse(const NfcDevice* device, FuriString* parsed_data) { const uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data)); if(key != cfg.keys[cfg.data_sector].a) break; - // Parse data - const uint8_t start_block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); - - const uint8_t* temp_ptr = &data->block[start_block_num + 1].data[5]; - uint16_t balance = ((temp_ptr[0] << 8) | temp_ptr[1]) / 25; - temp_ptr = &data->block[start_block_num].data[2]; - - uint32_t number = 0; - for(size_t i = 1; i < 5; i++) { - number <<= 8; - number |= temp_ptr[i]; + FuriString* metro_result = furi_string_alloc(); + FuriString* ground_result = furi_string_alloc(); + FuriString* tat_result = furi_string_alloc(); + bool result1 = parse_transport_block(&data->block[32], metro_result); + bool result2 = parse_transport_block(&data->block[28], ground_result); + bool result3 = parse_transport_block(&data->block[16], tat_result); + furi_string_cat_printf(parsed_data, "\e#Troyka card\n"); + if(result1) { + furi_string_cat_printf( + parsed_data, "\e#Metro\n%s\n", furi_string_get_cstr(metro_result)); } - number >>= 4; - number |= (temp_ptr[0] & 0xf) << 28; - - furi_string_printf(parsed_data, "\e#Troika\nNum: %lu\nBalance: %u RUR", number, balance); - parsed = true; + if(result2) { + furi_string_cat_printf( + parsed_data, "\e#Ediniy\n%s\n", furi_string_get_cstr(ground_result)); + } + if(result3) { + furi_string_cat_printf(parsed_data, "\e#TAT\n%s\n", furi_string_get_cstr(tat_result)); + } + furi_string_free(tat_result); + furi_string_free(ground_result); + furi_string_free(metro_result); + parsed = result1 || result2 || result3; } while(false); return parsed; @@ -211,4 +1659,4 @@ static const FlipperAppPluginDescriptor troika_plugin_descriptor = { /* Plugin entry point - must return a pointer to const descriptor */ const FlipperAppPluginDescriptor* troika_plugin_ep() { return &troika_plugin_descriptor; -} +} \ No newline at end of file From fbe2387a94d6dd778a415efb74501a5ecf17ca3f Mon Sep 17 00:00:00 2001 From: assasinfil Date: Wed, 24 Jan 2024 01:03:52 +0300 Subject: [PATCH 02/39] Changed to furi func --- .../main/nfc/plugins/supported_cards/troika.c | 731 +++++++++--------- 1 file changed, 349 insertions(+), 382 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index c67be437224..c1838f626b1 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -100,7 +100,7 @@ typedef struct { const size_t length; } BitLibRegion; -void bit_lib_push_bit(uint8_t* data, size_t data_size, bool bit) { +void push_bit(uint8_t* data, size_t data_size, bool bit) { size_t last_index = data_size - 1; for(size_t i = 0; i < last_index; ++i) { @@ -109,7 +109,7 @@ void bit_lib_push_bit(uint8_t* data, size_t data_size, bool bit) { data[last_index] = (data[last_index] << 1) | bit; } -void bit_lib_set_bit(uint8_t* data, size_t position, bool bit) { +void set_bit(uint8_t* data, size_t position, bool bit) { if(bit) { data[position / 8] |= 1UL << (7 - (position % 8)); } else { @@ -117,21 +117,21 @@ void bit_lib_set_bit(uint8_t* data, size_t position, bool bit) { } } -void bit_lib_set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length) { +void set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length) { furi_check(length <= 8); furi_check(length > 0); for(uint8_t i = 0; i < length; ++i) { uint8_t shift = (length - 1) - i; - bit_lib_set_bit(data, position + i, (byte >> shift) & 1); //-V610 + set_bit(data, position + i, (byte >> shift) & 1); //-V610 } } -bool bit_lib_get_bit(const uint8_t* data, size_t position) { +bool get_bit(const uint8_t* data, size_t position) { return (data[position / 8] >> (7 - (position % 8))) & 1; } -uint8_t bit_lib_get_bits(const uint8_t* data, size_t position, uint8_t length) { +uint8_t get_bits(const uint8_t* data, size_t position, uint8_t length) { uint8_t shift = position % 8; if(shift == 0) { return data[position / 8] >> (8 - length); @@ -144,70 +144,70 @@ uint8_t bit_lib_get_bits(const uint8_t* data, size_t position, uint8_t length) { } } -uint16_t bit_lib_get_bits_16(const uint8_t* data, size_t position, uint8_t length) { +uint16_t get_bits_16(const uint8_t* data, size_t position, uint8_t length) { uint16_t value = 0; if(length <= 8) { - value = bit_lib_get_bits(data, position, length); + value = get_bits(data, position, length); } else { - value = bit_lib_get_bits(data, position, 8) << (length - 8); - value |= bit_lib_get_bits(data, position + 8, length - 8); + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, length - 8); } return value; } -uint32_t bit_lib_get_bits_32(const uint8_t* data, size_t position, uint8_t length) { +uint32_t get_bits_32(const uint8_t* data, size_t position, uint8_t length) { uint32_t value = 0; if(length <= 8) { - value = bit_lib_get_bits(data, position, length); + value = get_bits(data, position, length); } else if(length <= 16) { - value = bit_lib_get_bits(data, position, 8) << (length - 8); - value |= bit_lib_get_bits(data, position + 8, length - 8); + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, length - 8); } else if(length <= 24) { - value = bit_lib_get_bits(data, position, 8) << (length - 8); - value |= bit_lib_get_bits(data, position + 8, 8) << (length - 16); - value |= bit_lib_get_bits(data, position + 16, length - 16); + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, 8) << (length - 16); + value |= get_bits(data, position + 16, length - 16); } else { - value = (uint32_t)bit_lib_get_bits(data, position, 8) << (length - 8); - value |= (uint32_t)bit_lib_get_bits(data, position + 8, 8) << (length - 16); - value |= (uint32_t)bit_lib_get_bits(data, position + 16, 8) << (length - 24); - value |= bit_lib_get_bits(data, position + 24, length - 24); + value = (uint32_t)get_bits(data, position, 8) << (length - 8); + value |= (uint32_t)get_bits(data, position + 8, 8) << (length - 16); + value |= (uint32_t)get_bits(data, position + 16, 8) << (length - 24); + value |= get_bits(data, position + 24, length - 24); } return value; } -uint64_t bit_lib_get_bits_64(const uint8_t* data, size_t position, uint8_t length) { +uint64_t get_bits_64(const uint8_t* data, size_t position, uint8_t length) { uint64_t value = 0; if(length <= 8) { - value = bit_lib_get_bits(data, position, length); + value = get_bits(data, position, length); } else if(length <= 16) { - value = bit_lib_get_bits(data, position, 8) << (length - 8); - value |= bit_lib_get_bits(data, position + 8, length - 8); + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, length - 8); } else if(length <= 24) { - value = bit_lib_get_bits(data, position, 8) << (length - 8); - value |= bit_lib_get_bits(data, position + 8, 8) << (length - 16); - value |= bit_lib_get_bits(data, position + 16, length - 16); + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, 8) << (length - 16); + value |= get_bits(data, position + 16, length - 16); } else if(length <= 32) { - value = (uint64_t)bit_lib_get_bits(data, position, 8) << (length - 8); - value |= (uint64_t)bit_lib_get_bits(data, position + 8, 8) << (length - 16); - value |= (uint64_t)bit_lib_get_bits(data, position + 16, 8) << (length - 24); - value |= bit_lib_get_bits(data, position + 24, length - 24); + value = (uint64_t)get_bits(data, position, 8) << (length - 8); + value |= (uint64_t)get_bits(data, position + 8, 8) << (length - 16); + value |= (uint64_t)get_bits(data, position + 16, 8) << (length - 24); + value |= get_bits(data, position + 24, length - 24); } else { - value = (uint64_t)bit_lib_get_bits(data, position, 8) << (length - 8); - value |= (uint64_t)bit_lib_get_bits(data, position + 8, 8) << (length - 16); - value |= (uint64_t)bit_lib_get_bits(data, position + 16, 8) << (length - 24); - value |= (uint64_t)bit_lib_get_bits(data, position + 24, 8) << (length - 32); - value |= (uint64_t)bit_lib_get_bits(data, position + 32, 8) << (length - 40); - value |= (uint64_t)bit_lib_get_bits(data, position + 40, 8) << (length - 48); - value |= (uint64_t)bit_lib_get_bits(data, position + 48, 8) << (length - 56); - value |= (uint64_t)bit_lib_get_bits(data, position + 56, 8) << (length - 64); - value |= bit_lib_get_bits(data, position + 64, length - 64); + value = (uint64_t)get_bits(data, position, 8) << (length - 8); + value |= (uint64_t)get_bits(data, position + 8, 8) << (length - 16); + value |= (uint64_t)get_bits(data, position + 16, 8) << (length - 24); + value |= (uint64_t)get_bits(data, position + 24, 8) << (length - 32); + value |= (uint64_t)get_bits(data, position + 32, 8) << (length - 40); + value |= (uint64_t)get_bits(data, position + 40, 8) << (length - 48); + value |= (uint64_t)get_bits(data, position + 48, 8) << (length - 56); + value |= (uint64_t)get_bits(data, position + 56, 8) << (length - 64); + value |= get_bits(data, position + 64, length - 64); } return value; } -bool bit_lib_test_parity_32(uint32_t bits, BitLibParity parity) { +bool test_parity_32(uint32_t bits, BitLibParity parity) { #if !defined __GNUC__ #error Please, implement parity test for non-GCC compilers #else @@ -236,18 +236,18 @@ bool bit_lib_test_parity( switch(parity) { case BitLibParityEven: case BitLibParityOdd: - parity_block = bit_lib_get_bits_32(bits, position + i * parity_length, parity_length); - if(!bit_lib_test_parity_32(parity_block, parity)) { + parity_block = get_bits_32(bits, position + i * parity_length, parity_length); + if(!test_parity_32(parity_block, parity)) { result = false; } break; case BitLibParityAlways0: - if(bit_lib_get_bit(bits, position + i * parity_length + parity_length - 1)) { + if(get_bit(bits, position + i * parity_length + parity_length - 1)) { result = false; } break; case BitLibParityAlways1: - if(!bit_lib_get_bit(bits, position + i * parity_length + parity_length - 1)) { + if(!get_bit(bits, position + i * parity_length + parity_length - 1)) { result = false; } break; @@ -270,23 +270,23 @@ size_t bit_lib_add_parity( size_t j = 0, bit_count = 0; for(int word = 0; word < source_length; word += parity_length - 1) { for(int bit = 0; bit < parity_length - 1; bit++) { - parity_word = (parity_word << 1) | bit_lib_get_bit(data, position + word + bit); - bit_lib_set_bit( - dest, dest_position + j++, bit_lib_get_bit(data, position + word + bit)); + parity_word = (parity_word << 1) | get_bit(data, position + word + bit); + set_bit( + dest, dest_position + j++, get_bit(data, position + word + bit)); } // if parity fails then return 0 switch(parity) { case BitLibParityAlways0: - bit_lib_set_bit(dest, dest_position + j++, 0); + set_bit(dest, dest_position + j++, 0); break; // marker bit which should be a 0 case BitLibParityAlways1: - bit_lib_set_bit(dest, dest_position + j++, 1); + set_bit(dest, dest_position + j++, 1); break; // marker bit which should be a 1 default: - bit_lib_set_bit( + set_bit( dest, dest_position + j++, - (bit_lib_test_parity_32(parity_word, BitLibParityOdd) ^ parity) ^ 1); + (test_parity_32(parity_word, BitLibParityOdd) ^ parity) ^ 1); break; } bit_count += parity_length; @@ -305,12 +305,12 @@ size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t leng while(counter < length) { if((counter + 1) % n != 0) { - bit_buffer = (bit_buffer << 1) | bit_lib_get_bit(data, position + counter); + bit_buffer = (bit_buffer << 1) | get_bit(data, position + counter); bit_counter++; } if(bit_counter == 8) { - bit_lib_set_bits(data, position + result_counter, bit_buffer, 8); + set_bits(data, position + result_counter, bit_buffer, 8); bit_counter = 0; bit_buffer = 0; result_counter += 8; @@ -319,7 +319,7 @@ size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t leng } if(bit_counter != 0) { - bit_lib_set_bits(data, position + result_counter, bit_buffer, bit_counter); + set_bits(data, position + result_counter, bit_buffer, bit_counter); result_counter += bit_counter; } return result_counter; @@ -332,7 +332,7 @@ void bit_lib_copy_bits( const uint8_t* source, size_t source_position) { for(size_t i = 0; i < length; ++i) { - bit_lib_set_bit(data, position + i, bit_lib_get_bit(source, source_position + i)); + set_bit(data, position + i, get_bit(source, source_position + i)); } } @@ -341,15 +341,15 @@ void bit_lib_reverse_bits(uint8_t* data, size_t position, uint8_t length) { size_t j = length - 1; while(i < j) { - bool tmp = bit_lib_get_bit(data, position + i); - bit_lib_set_bit(data, position + i, bit_lib_get_bit(data, position + j)); - bit_lib_set_bit(data, position + j, tmp); + bool tmp = get_bit(data, position + i); + set_bit(data, position + i, get_bit(data, position + j)); + set_bit(data, position + j, tmp); i++; j--; } } -uint8_t bit_lib_get_bit_count(uint32_t data) { +uint8_t get_bit_count(uint32_t data) { #if defined __GNUC__ return __builtin_popcountl(data); #else @@ -359,7 +359,7 @@ uint8_t bit_lib_get_bit_count(uint32_t data) { void bit_lib_print_bits(const uint8_t* data, size_t length) { for(size_t i = 0; i < length; ++i) { - printf("%u", bit_lib_get_bit(data, i)); + printf("%u", get_bit(data, i)); } } @@ -397,7 +397,7 @@ void bit_lib_print_regions( for(size_t i = 0; i < region_count; i++) { if(regions[i].start <= c && c < regions[i].start + regions[i].length) { print = true; - printf("%u", bit_lib_get_bit(data, c)); + printf("%u", get_bit(data, c)); break; } } @@ -467,7 +467,7 @@ uint16_t bit_lib_crc8( return crc; } -uint16_t bit_lib_crc16( +uint16_t crc16( uint8_t const* data, size_t data_size, uint16_t polynom, @@ -495,39 +495,6 @@ uint16_t bit_lib_crc16( return crc; } -#define FURI_HAL_RTC_SECONDS_PER_MINUTE 60 -#define FURI_HAL_RTC_SECONDS_PER_HOUR (FURI_HAL_RTC_SECONDS_PER_MINUTE * 60) -#define FURI_HAL_RTC_SECONDS_PER_DAY (FURI_HAL_RTC_SECONDS_PER_HOUR * 24) -#define FURI_HAL_RTC_EPOCH_START_YEAR 1970 -#define FURI_HAL_RTC_IS_LEAP_YEAR(year) \ - ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0)) - -void timestamp_to_datetime(uint32_t timestamp, FuriHalRtcDateTime* datetime) { - uint32_t days = timestamp / FURI_HAL_RTC_SECONDS_PER_DAY; - uint32_t seconds_in_day = timestamp % FURI_HAL_RTC_SECONDS_PER_DAY; - - datetime->year = FURI_HAL_RTC_EPOCH_START_YEAR; - - while(days >= furi_hal_rtc_get_days_per_year(datetime->year)) { - days -= furi_hal_rtc_get_days_per_year(datetime->year); - (datetime->year)++; - } - - datetime->month = 1; - while(days >= furi_hal_rtc_get_days_per_month( - FURI_HAL_RTC_IS_LEAP_YEAR(datetime->year), datetime->month)) { - days -= furi_hal_rtc_get_days_per_month( - FURI_HAL_RTC_IS_LEAP_YEAR(datetime->year), datetime->month); - (datetime->month)++; - } - - datetime->day = days + 1; - datetime->hour = seconds_in_day / FURI_HAL_RTC_SECONDS_PER_HOUR; - datetime->minute = - (seconds_in_day % FURI_HAL_RTC_SECONDS_PER_HOUR) / FURI_HAL_RTC_SECONDS_PER_MINUTE; - datetime->second = seconds_in_day % FURI_HAL_RTC_SECONDS_PER_MINUTE; -} - void from_days_to_datetime(uint16_t days, FuriHalRtcDateTime* datetime, uint16_t start_year) { uint32_t timestamp = days * 24 * 60 * 60; FuriHalRtcDateTime start_datetime = {0}; @@ -535,7 +502,7 @@ void from_days_to_datetime(uint16_t days, FuriHalRtcDateTime* datetime, uint16_t start_datetime.month = 12; start_datetime.day = 31; timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); - timestamp_to_datetime(timestamp, datetime); + furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); } void from_minutes_to_datetime(uint32_t minutes, FuriHalRtcDateTime* datetime, uint16_t start_year) { @@ -545,19 +512,19 @@ void from_minutes_to_datetime(uint32_t minutes, FuriHalRtcDateTime* datetime, ui start_datetime.month = 12; start_datetime.day = 31; timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); - timestamp_to_datetime(timestamp, datetime); + furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); } bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { - uint16_t transport_departament = bit_lib_get_bits_16(block->data, 0, 10); + uint16_t transport_departament = get_bits_16(block->data, 0, 10); FURI_LOG_I(TAG, "Transport departament: %x", transport_departament); - uint16_t layout_type = bit_lib_get_bits_16(block->data, 52, 4); + uint16_t layout_type = get_bits_16(block->data, 52, 4); if(layout_type == 0xE) { - layout_type = bit_lib_get_bits_16(block->data, 52, 9); + layout_type = get_bits_16(block->data, 52, 9); } else if(layout_type == 0xF) { - layout_type = bit_lib_get_bits_16(block->data, 52, 14); + layout_type = get_bits_16(block->data, 52, 14); } FURI_LOG_I(TAG, "Layout type %x", layout_type); @@ -578,32 +545,32 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { switch(layout_type) { case 0x02: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - uint8_t card_benefit_code = bit_lib_get_bits(block->data, 72, 8); //124 - uint32_t card_rfu1 = bit_lib_get_bits_32(block->data, 80, 32); //rfu1 - uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 - card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 177, 12); //403 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 189, 16); //402 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 - uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 173, 16); //312 - uint8_t card_start_trip_seconds = bit_lib_get_bits(block->data, 189, 6); //406 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 - uint16_t card_use_with_date = bit_lib_get_bits_16(block->data, 189, 16); //205 - uint8_t card_route = bit_lib_get_bits(block->data, 205, 1); //424 - uint16_t card_validator1 = bit_lib_get_bits_16(block->data, 206, 15); //422.1 - card_validator = bit_lib_get_bits_16(block->data, 205, 16); //422 - uint16_t card_total_trips = bit_lib_get_bits_16(block->data, 221, 16); //331 - uint8_t card_write_enabled = bit_lib_get_bits(block->data, 237, 1); //write_enabled - uint8_t card_rfu2 = bit_lib_get_bits(block->data, 238, 2); //rfu2 - uint16_t card_crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_use_before_date = get_bits_16(block->data, 56, 16); //202 + uint8_t card_benefit_code = get_bits(block->data, 72, 8); //124 + uint32_t card_rfu1 = get_bits_32(block->data, 80, 32); //rfu1 + uint16_t card_crc16 = get_bits_16(block->data, 112, 16); //501.1 + card_blocked = get_bits(block->data, 128, 1); //303 + uint16_t card_start_trip_time = get_bits_16(block->data, 177, 12); //403 + uint16_t card_start_trip_date = get_bits_16(block->data, 189, 16); //402 + uint16_t card_valid_from_date = get_bits_16(block->data, 157, 16); //311 + uint16_t card_valid_by_date = get_bits_16(block->data, 173, 16); //312 + uint8_t card_start_trip_seconds = get_bits(block->data, 189, 6); //406 + uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 + uint16_t card_use_with_date = get_bits_16(block->data, 189, 16); //205 + uint8_t card_route = get_bits(block->data, 205, 1); //424 + uint16_t card_validator1 = get_bits_16(block->data, 206, 15); //422.1 + card_validator = get_bits_16(block->data, 205, 16); //422 + uint16_t card_total_trips = get_bits_16(block->data, 221, 16); //331 + uint8_t card_write_enabled = get_bits(block->data, 237, 1); //write_enabled + uint8_t card_rfu2 = get_bits(block->data, 238, 2); //rfu2 + uint16_t card_crc16_2 = get_bits_16(block->data, 240, 16); //501.2 FURI_LOG_D( TAG, @@ -661,30 +628,30 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x06: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - uint8_t card_geozone_a = bit_lib_get_bits(block->data, 72, 4); //GeoZoneA - uint8_t card_geozone_b = bit_lib_get_bits(block->data, 76, 4); //GeoZoneB - card_blank_type = bit_lib_get_bits_16(block->data, 80, 10); //121. - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 90, 10); //122 - uint32_t card_rfu1 = bit_lib_get_bits_16(block->data, 100, 12); //rfu1 - uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 - card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 129, 12); //403 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 141, 16); //402 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 - uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 173, 16); //312 - uint16_t card_company = bit_lib_get_bits(block->data, 189, 4); //Company - uint8_t card_validator1 = bit_lib_get_bits(block->data, 193, 4); //422.1 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 197, 10); //321 - uint8_t card_units = bit_lib_get_bits(block->data, 207, 6); //Units - uint16_t card_validator2 = bit_lib_get_bits_16(block->data, 213, 10); //422.2 - uint16_t card_total_trips = bit_lib_get_bits_16(block->data, 223, 16); //331 - uint8_t card_extended = bit_lib_get_bits(block->data, 239, 1); //123 - uint16_t card_crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_use_before_date = get_bits_16(block->data, 56, 16); //202 + uint8_t card_geozone_a = get_bits(block->data, 72, 4); //GeoZoneA + uint8_t card_geozone_b = get_bits(block->data, 76, 4); //GeoZoneB + card_blank_type = get_bits_16(block->data, 80, 10); //121. + uint16_t card_type_of_extended = get_bits_16(block->data, 90, 10); //122 + uint32_t card_rfu1 = get_bits_16(block->data, 100, 12); //rfu1 + uint16_t card_crc16 = get_bits_16(block->data, 112, 16); //501.1 + card_blocked = get_bits(block->data, 128, 1); //303 + uint16_t card_start_trip_time = get_bits_16(block->data, 129, 12); //403 + uint16_t card_start_trip_date = get_bits_16(block->data, 141, 16); //402 + uint16_t card_valid_from_date = get_bits_16(block->data, 157, 16); //311 + uint16_t card_valid_by_date = get_bits_16(block->data, 173, 16); //312 + uint16_t card_company = get_bits(block->data, 189, 4); //Company + uint8_t card_validator1 = get_bits(block->data, 193, 4); //422.1 + uint16_t card_remaining_trips = get_bits_16(block->data, 197, 10); //321 + uint8_t card_units = get_bits(block->data, 207, 6); //Units + uint16_t card_validator2 = get_bits_16(block->data, 213, 10); //422.2 + uint16_t card_total_trips = get_bits_16(block->data, 223, 16); //331 + uint8_t card_extended = get_bits(block->data, 239, 1); //123 + uint16_t card_crc16_2 = get_bits_16(block->data, 240, 16); //501.2 FURI_LOG_D( TAG, @@ -739,22 +706,22 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x08: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 - uint8_t card_rfu2 = bit_lib_get_bits(block->data, 153, 7); //rfu2 - uint8_t card_remaining_trips1 = bit_lib_get_bits(block->data, 160, 8); //321.1 - uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 168, 8); //321 - uint8_t card_validator1 = bit_lib_get_bits(block->data, 193, 2); //422.1 - uint16_t card_validator = bit_lib_get_bits_16(block->data, 177, 15); //422 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 - uint32_t card_rfu3 = bit_lib_get_bits_32(block->data, 224, 32); //rfu3 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_use_before_date = get_bits_16(block->data, 56, 16); //202 + uint64_t card_rfu1 = get_bits_64(block->data, 72, 56); //rfu1 + uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 + uint8_t card_rfu2 = get_bits(block->data, 153, 7); //rfu2 + uint8_t card_remaining_trips1 = get_bits(block->data, 160, 8); //321.1 + uint8_t card_remaining_trips = get_bits(block->data, 168, 8); //321 + uint8_t card_validator1 = get_bits(block->data, 193, 2); //422.1 + uint16_t card_validator = get_bits_16(block->data, 177, 15); //422 + card_hash = get_bits_32(block->data, 192, 32); //502 + uint32_t card_rfu3 = get_bits_32(block->data, 224, 32); //rfu3 FURI_LOG_D( TAG, @@ -790,23 +757,23 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x0A: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 64, 12); //311 - uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 76, 19); //314 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 95, 1); //301 - card_start_trip_minutes = bit_lib_get_bits_32(block->data, 96, 19); //405 - card_minutes_pass = bit_lib_get_bits(block->data, 119, 7); //412 - uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 126, 2); //421.0 - uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 128, 8); //321 - uint16_t card_validator = bit_lib_get_bits_16(block->data, 136, 16); //422 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 152, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 154, 2); //421.2 - uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 156, 2); //421.3 - uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 158, 2); //421.4 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + uint16_t card_valid_from_date = get_bits_16(block->data, 64, 12); //311 + uint32_t card_valid_for_minutes = get_bits_32(block->data, 76, 19); //314 + uint8_t card_requires_activation = get_bits(block->data, 95, 1); //301 + card_start_trip_minutes = get_bits_32(block->data, 96, 19); //405 + card_minutes_pass = get_bits(block->data, 119, 7); //412 + uint8_t card_transport_type_flag = get_bits(block->data, 126, 2); //421.0 + uint8_t card_remaining_trips = get_bits(block->data, 128, 8); //321 + uint16_t card_validator = get_bits_16(block->data, 136, 16); //422 + uint8_t card_transport_type1 = get_bits(block->data, 152, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 154, 2); //421.2 + uint8_t card_transport_type3 = get_bits(block->data, 156, 2); //421.3 + uint8_t card_transport_type4 = get_bits(block->data, 158, 2); //421.4 + card_hash = get_bits_32(block->data, 192, 32); //502 FURI_LOG_D( TAG, @@ -850,24 +817,24 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x0C: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 - uint16_t card_rfu2 = bit_lib_get_bits_16(block->data, 153, 13); //rfu2 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 - uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 - uint8_t card_transport_type = bit_lib_get_bits(block->data, 251, 2); //421 - uint8_t card_rfu3 = bit_lib_get_bits(block->data, 253, 2); //rfu3 - uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 255, 1); //432 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_use_before_date = get_bits_16(block->data, 56, 16); //202 + uint64_t card_rfu1 = get_bits_64(block->data, 72, 56); //rfu1 + uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 + uint16_t card_rfu2 = get_bits_16(block->data, 153, 13); //rfu2 + uint16_t card_remaining_trips = get_bits_16(block->data, 166, 10); //321 + uint16_t card_validator = get_bits_16(block->data, 176, 16); //422 + card_hash = get_bits_32(block->data, 192, 32); //502 + uint16_t card_start_trip_date = get_bits_16(block->data, 224, 16); //402 + uint16_t card_start_trip_time = get_bits_16(block->data, 240, 11); //403 + uint8_t card_transport_type = get_bits(block->data, 251, 2); //421 + uint8_t card_rfu3 = get_bits(block->data, 253, 2); //rfu3 + uint8_t card_transfer_in_metro = get_bits(block->data, 255, 1); //432 FURI_LOG_D( TAG, @@ -912,33 +879,33 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x0D: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - uint8_t card_rfu1 = bit_lib_get_bits(block->data, 56, 8); //rfu1 - card_use_before_date = bit_lib_get_bits_16(block->data, 64, 16); //202 - uint16_t card_valid_for_time = bit_lib_get_bits_16(block->data, 80, 11); //316 - uint8_t card_rfu2 = bit_lib_get_bits(block->data, 91, 5); //rfu2 - uint16_t card_use_before_date2 = bit_lib_get_bits_16(block->data, 96, 16); //202.2 - uint16_t card_valid_for_time2 = bit_lib_get_bits_16(block->data, 123, 11); //316.2 - uint8_t card_rfu3 = bit_lib_get_bits(block->data, 123, 5); //rfu3 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 - uint8_t card_rfu4 = bit_lib_get_bits(block->data, 153, 2); //rfu4 - uint8_t card_passage_5_minutes = bit_lib_get_bits(block->data, 155, 5); //413 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 160, 2); //421.1 - uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 162, 1); //431 - uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 163, 3); //433 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 - uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 251, 2); //421.2 - uint8_t card_rfu5 = bit_lib_get_bits(block->data, 253, 2); //rfu5 - uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 255, 1); //432 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + uint8_t card_rfu1 = get_bits(block->data, 56, 8); //rfu1 + card_use_before_date = get_bits_16(block->data, 64, 16); //202 + uint16_t card_valid_for_time = get_bits_16(block->data, 80, 11); //316 + uint8_t card_rfu2 = get_bits(block->data, 91, 5); //rfu2 + uint16_t card_use_before_date2 = get_bits_16(block->data, 96, 16); //202.2 + uint16_t card_valid_for_time2 = get_bits_16(block->data, 123, 11); //316.2 + uint8_t card_rfu3 = get_bits(block->data, 123, 5); //rfu3 + uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 + uint8_t card_rfu4 = get_bits(block->data, 153, 2); //rfu4 + uint8_t card_passage_5_minutes = get_bits(block->data, 155, 5); //413 + uint8_t card_transport_type1 = get_bits(block->data, 160, 2); //421.1 + uint8_t card_passage_in_metro = get_bits(block->data, 162, 1); //431 + uint8_t card_passages_ground_transport = get_bits(block->data, 163, 3); //433 + uint16_t card_remaining_trips = get_bits_16(block->data, 166, 10); //321 + uint16_t card_validator = get_bits_16(block->data, 176, 16); //422 + card_hash = get_bits_32(block->data, 192, 32); //502 + uint16_t card_start_trip_date = get_bits_16(block->data, 224, 16); //402 + uint16_t card_start_trip_time = get_bits_16(block->data, 240, 11); //403 + uint8_t card_transport_type2 = get_bits(block->data, 251, 2); //421.2 + uint8_t card_rfu5 = get_bits(block->data, 253, 2); //rfu5 + uint8_t card_transfer_in_metro = get_bits(block->data, 255, 1); //432 FURI_LOG_D( TAG, @@ -993,27 +960,27 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x1C1: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121. - card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 144, 16); //402 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 160, 11); //403 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 171, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 173, 2); //421.2 - uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 177, 1); //432 - uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 178, 1); //431 - uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 179, 3); //433 - card_minutes_pass = bit_lib_get_bits(block->data, 185, 8); //412. - card_remaining_funds = bit_lib_get_bits_32(block->data, 196, 19) / 100; //322 - uint8_t card_fare_trip = bit_lib_get_bits(block->data, 215, 2); //441 - card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 - uint8_t card_zoo = bit_lib_get_bits(block->data, 218, 1); //zoo - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + card_use_before_date = get_bits_16(block->data, 61, 16); //202. + card_blank_type = get_bits_16(block->data, 77, 10); //121. + card_validator = get_bits_16(block->data, 128, 16); //422 + uint16_t card_start_trip_date = get_bits_16(block->data, 144, 16); //402 + uint16_t card_start_trip_time = get_bits_16(block->data, 160, 11); //403 + uint8_t card_transport_type1 = get_bits(block->data, 171, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 173, 2); //421.2 + uint8_t card_transfer_in_metro = get_bits(block->data, 177, 1); //432 + uint8_t card_passage_in_metro = get_bits(block->data, 178, 1); //431 + uint8_t card_passages_ground_transport = get_bits(block->data, 179, 3); //433 + card_minutes_pass = get_bits(block->data, 185, 8); //412. + card_remaining_funds = get_bits_32(block->data, 196, 19) / 100; //322 + uint8_t card_fare_trip = get_bits(block->data, 215, 2); //441 + card_blocked = get_bits(block->data, 202, 1); //303 + uint8_t card_zoo = get_bits(block->data, 218, 1); //zoo + card_hash = get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG, @@ -1060,28 +1027,28 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x1C2: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 - card_use_before_date = bit_lib_get_bits_16(block->data, 71, 16); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 87, 10); //121. - uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 97, 16); //311 - uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 113, 9); //302 - uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 131, 20); //314 - card_minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412. - uint8_t card_transport_type = bit_lib_get_bits(block->data, 163, 2); //421 - uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 165, 1); //431 - uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 166, 1); //432 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 167, 10); //321 - card_validator = bit_lib_get_bits_16(block->data, 177, 16); //422 - uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 196, 20); //404 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 216, 1); //301 - card_blocked = bit_lib_get_bits(block->data, 217, 1); //303 - uint8_t card_extended = bit_lib_get_bits(block->data, 218, 1); //123 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 + card_use_before_date = get_bits_16(block->data, 71, 16); //202. + card_blank_type = get_bits_16(block->data, 87, 10); //121. + uint16_t card_valid_to_date = get_bits_16(block->data, 97, 16); //311 + uint16_t card_activate_during = get_bits_16(block->data, 113, 9); //302 + uint32_t card_valid_for_minutes = get_bits_32(block->data, 131, 20); //314 + card_minutes_pass = get_bits(block->data, 154, 8); //412. + uint8_t card_transport_type = get_bits(block->data, 163, 2); //421 + uint8_t card_passage_in_metro = get_bits(block->data, 165, 1); //431 + uint8_t card_transfer_in_metro = get_bits(block->data, 166, 1); //432 + uint16_t card_remaining_trips = get_bits_16(block->data, 167, 10); //321 + card_validator = get_bits_16(block->data, 177, 16); //422 + uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 196, 20); //404 + uint8_t card_requires_activation = get_bits(block->data, 216, 1); //301 + card_blocked = get_bits(block->data, 217, 1); //303 + uint8_t card_extended = get_bits(block->data, 218, 1); //123 + card_hash = get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG, @@ -1132,25 +1099,25 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x1C3: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 - card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121 - card_remaining_funds = bit_lib_get_bits_32(block->data, 188, 22) / 100; //322 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 - card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 - card_start_trip_minutes = bit_lib_get_bits_32(block->data, 144, 23); //405 - uint8_t card_fare_trip = bit_lib_get_bits(block->data, 210, 2); //441 - card_minutes_pass = bit_lib_get_bits(block->data, 171, 7); //412 - uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 - card_blocked = bit_lib_get_bits(block->data, 212, 1); //303 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + card_use_before_date = get_bits_16(block->data, 61, 16); //202 + card_blank_type = get_bits_16(block->data, 77, 10); //121 + card_remaining_funds = get_bits_32(block->data, 188, 22) / 100; //322 + card_hash = get_bits_32(block->data, 224, 32); //502 + card_validator = get_bits_16(block->data, 128, 16); //422 + card_start_trip_minutes = get_bits_32(block->data, 144, 23); //405 + uint8_t card_fare_trip = get_bits(block->data, 210, 2); //441 + card_minutes_pass = get_bits(block->data, 171, 7); //412 + uint8_t card_transport_type_flag = get_bits(block->data, 178, 2); //421.0 + uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 + card_blocked = get_bits(block->data, 212, 1); //303 FURI_LOG_D( TAG, "Card view: %x, type: %x, number: %lx, layout: %x, layout2: %x, use before date: %x, blank type: %x, remaining funds: %lx, hash: %lx, validator: %x, start trip minutes: %lx, fare trip: %x, minutes pass: %x, transport type flag: %x, transport type1: %x, transport type2: %x, transport type3: %x, transport type4: %x, blocked: %x", @@ -1195,31 +1162,31 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x1C4: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 - card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. - uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 94, 13); //311 - uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 107, 9); //302 - uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 116, 10); //304 - uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 - card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. - uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 169, 10); //321 - card_validator = bit_lib_get_bits_16(block->data, 179, 16); //422 - uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 195, 20); //404 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 215, 1); //301 - card_blocked = bit_lib_get_bits(block->data, 216, 1); //303 - uint8_t card_extended = bit_lib_get_bits(block->data, 217, 1); //123 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 + card_use_before_date = get_bits_16(block->data, 71, 13); //202. + card_blank_type = get_bits_16(block->data, 84, 10); //121. + uint16_t card_valid_to_date = get_bits_16(block->data, 94, 13); //311 + uint16_t card_activate_during = get_bits_16(block->data, 107, 9); //302 + uint16_t card_extension_counter = get_bits_16(block->data, 116, 10); //304 + uint32_t card_valid_for_minutes = get_bits_32(block->data, 128, 20); //314 + card_minutes_pass = get_bits(block->data, 158, 7); //412. + uint8_t card_transport_type_flag = get_bits(block->data, 178, 2); //421.0 + uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 + uint16_t card_remaining_trips = get_bits_16(block->data, 169, 10); //321 + card_validator = get_bits_16(block->data, 179, 16); //422 + uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 195, 20); //404 + uint8_t card_requires_activation = get_bits(block->data, 215, 1); //301 + card_blocked = get_bits(block->data, 216, 1); //303 + uint8_t card_extended = get_bits(block->data, 217, 1); //123 + card_hash = get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG, @@ -1274,24 +1241,24 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x1C5: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - card_use_before_date = bit_lib_get_bits_16(block->data, 61, 13); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 74, 10); //121. - uint32_t card_valid_to_time = bit_lib_get_bits_32(block->data, 84, 23); //317 - uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 107, 10); //304 - card_start_trip_minutes = bit_lib_get_bits_32(block->data, 128, 23); //405 - uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 151, 7); //414 - card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. - card_remaining_funds = bit_lib_get_bits_32(block->data, 167, 19) / 100; //322 - card_validator = bit_lib_get_bits_16(block->data, 186, 16); //422 - card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 - uint16_t card_route = bit_lib_get_bits_16(block->data, 204, 12); //424 - uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 216, 7); //433 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + card_use_before_date = get_bits_16(block->data, 61, 13); //202. + card_blank_type = get_bits_16(block->data, 74, 10); //121. + uint32_t card_valid_to_time = get_bits_32(block->data, 84, 23); //317 + uint16_t card_extension_counter = get_bits_16(block->data, 107, 10); //304 + card_start_trip_minutes = get_bits_32(block->data, 128, 23); //405 + uint8_t card_metro_ride_with = get_bits(block->data, 151, 7); //414 + card_minutes_pass = get_bits(block->data, 158, 7); //412. + card_remaining_funds = get_bits_32(block->data, 167, 19) / 100; //322 + card_validator = get_bits_16(block->data, 186, 16); //422 + card_blocked = get_bits(block->data, 202, 1); //303 + uint16_t card_route = get_bits_16(block->data, 204, 12); //424 + uint8_t card_passages_ground_transport = get_bits(block->data, 216, 7); //433 + card_hash = get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG, @@ -1337,26 +1304,26 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x1C6: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 - card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. - uint32_t card_valid_from_date = bit_lib_get_bits_32(block->data, 94, 23); //311 - uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 117, 10); //304 - uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 - uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 148, 20); //404 - uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 168, 7); //414 - card_minutes_pass = bit_lib_get_bits(block->data, 175, 7); //412. - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 182, 7); //321 - card_validator = bit_lib_get_bits_16(block->data, 189, 16); //422 - card_blocked = bit_lib_get_bits(block->data, 205, 1); //303 - uint8_t card_extended = bit_lib_get_bits(block->data, 206, 1); //123 - uint16_t card_route = bit_lib_get_bits_16(block->data, 212, 12); //424 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 + card_use_before_date = get_bits_16(block->data, 71, 13); //202. + card_blank_type = get_bits_16(block->data, 84, 10); //121. + uint32_t card_valid_from_date = get_bits_32(block->data, 94, 23); //311 + uint16_t card_extension_counter = get_bits_16(block->data, 117, 10); //304 + uint32_t card_valid_for_minutes = get_bits_32(block->data, 128, 20); //314 + uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 148, 20); //404 + uint8_t card_metro_ride_with = get_bits(block->data, 168, 7); //414 + card_minutes_pass = get_bits(block->data, 175, 7); //412. + uint16_t card_remaining_trips = get_bits_16(block->data, 182, 7); //321 + card_validator = get_bits_16(block->data, 189, 16); //422 + card_blocked = get_bits(block->data, 205, 1); //303 + uint8_t card_extended = get_bits(block->data, 206, 1); //123 + uint16_t card_route = get_bits_16(block->data, 212, 12); //424 + card_hash = get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG, @@ -1405,24 +1372,24 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x3CCB: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code - uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 - uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 - uint8_t card_interval = bit_lib_get_bits(block->data, 98, 4); //interval - uint16_t card_app_code1 = bit_lib_get_bits_16(block->data, 102, 16); //app_code1 - uint16_t card_hash1 = bit_lib_get_bits_16(block->data, 112, 16); //502.1 - uint16_t card_type1 = bit_lib_get_bits_16(block->data, 128, 10); //type1 - uint16_t card_app_code2 = bit_lib_get_bits_16(block->data, 138, 10); //app_code2 - uint16_t card_type2 = bit_lib_get_bits_16(block->data, 148, 10); //type2 - uint16_t card_app_code3 = bit_lib_get_bits_16(block->data, 158, 10); //app_code3 - uint16_t card_type3 = bit_lib_get_bits_16(block->data, 148, 10); //type3 - uint16_t card_app_code4 = bit_lib_get_bits_16(block->data, 168, 10); //app_code4 - uint16_t card_type4 = bit_lib_get_bits_16(block->data, 178, 10); //type4 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502.2 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + uint16_t card_tech_code = get_bits_32(block->data, 56, 10); //tech_code + uint16_t card_valid_to_minutes = get_bits_16(block->data, 66, 16); //311 + uint16_t card_valid_by_date = get_bits_16(block->data, 82, 16); //312 + uint8_t card_interval = get_bits(block->data, 98, 4); //interval + uint16_t card_app_code1 = get_bits_16(block->data, 102, 16); //app_code1 + uint16_t card_hash1 = get_bits_16(block->data, 112, 16); //502.1 + uint16_t card_type1 = get_bits_16(block->data, 128, 10); //type1 + uint16_t card_app_code2 = get_bits_16(block->data, 138, 10); //app_code2 + uint16_t card_type2 = get_bits_16(block->data, 148, 10); //type2 + uint16_t card_app_code3 = get_bits_16(block->data, 158, 10); //app_code3 + uint16_t card_type3 = get_bits_16(block->data, 148, 10); //type3 + uint16_t card_app_code4 = get_bits_16(block->data, 168, 10); //app_code4 + uint16_t card_type4 = get_bits_16(block->data, 178, 10); //type4 + card_hash = get_bits_32(block->data, 224, 32); //502.2 FURI_LOG_D( TAG, @@ -1461,14 +1428,14 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { break; } case 0x3C0B: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code - uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 - uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 - uint16_t card_hash = bit_lib_get_bits_16(block->data, 112, 16); //502.1 + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + uint16_t card_tech_code = get_bits_32(block->data, 56, 10); //tech_code + uint16_t card_valid_to_minutes = get_bits_16(block->data, 66, 16); //311 + uint16_t card_valid_by_date = get_bits_16(block->data, 82, 16); //312 + uint16_t card_hash = get_bits_16(block->data, 112, 16); //502.1 FURI_LOG_D( TAG, From 4254766b015af416ffc01755558aa7d132d28081 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Wed, 24 Jan 2024 13:17:54 +0300 Subject: [PATCH 03/39] Small refactor --- applications/main/nfc/application.fam | 2 +- .../main/nfc/helpers/mosgortrans_layouts_i.c | 1387 ++++++++++++++++ .../main/nfc/helpers/mosgortrans_layouts_i.h | 10 + .../main/nfc/plugins/supported_cards/troika.c | 1388 +---------------- 4 files changed, 1399 insertions(+), 1388 deletions(-) create mode 100644 applications/main/nfc/helpers/mosgortrans_layouts_i.c create mode 100644 applications/main/nfc/helpers/mosgortrans_layouts_i.h diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index b92d0ebf1ab..6b5e28f65bc 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -62,7 +62,7 @@ App( entry_point="troika_plugin_ep", targets=["f7"], requires=["nfc"], - sources=["plugins/supported_cards/troika.c"], + sources=["plugins/supported_cards/troika.c", "helpers/mosgortrans_layouts_i.c"], ) App( diff --git a/applications/main/nfc/helpers/mosgortrans_layouts_i.c b/applications/main/nfc/helpers/mosgortrans_layouts_i.c new file mode 100644 index 00000000000..11fa9643bad --- /dev/null +++ b/applications/main/nfc/helpers/mosgortrans_layouts_i.c @@ -0,0 +1,1387 @@ +#include "mosgortrans_layouts_i.h" + +#define TOPBIT(X) (1 << ((X)-1)) + +typedef enum { + BitLibParityEven, + BitLibParityOdd, + BitLibParityAlways0, + BitLibParityAlways1, +} BitLibParity; + +typedef struct { + const char mark; + const size_t start; + const size_t length; +} BitLibRegion; + +void push_bit(uint8_t* data, size_t data_size, bool bit) { + size_t last_index = data_size - 1; + + for(size_t i = 0; i < last_index; ++i) { + data[i] = (data[i] << 1) | ((data[i + 1] >> 7) & 1); + } + data[last_index] = (data[last_index] << 1) | bit; +} + +void set_bit(uint8_t* data, size_t position, bool bit) { + if(bit) { + data[position / 8] |= 1UL << (7 - (position % 8)); + } else { + data[position / 8] &= ~(1UL << (7 - (position % 8))); + } +} + +void set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length) { + furi_check(length <= 8); + furi_check(length > 0); + + for(uint8_t i = 0; i < length; ++i) { + uint8_t shift = (length - 1) - i; + set_bit(data, position + i, (byte >> shift) & 1); //-V610 + } +} + +bool get_bit(const uint8_t* data, size_t position) { + return (data[position / 8] >> (7 - (position % 8))) & 1; +} + +uint8_t get_bits(const uint8_t* data, size_t position, uint8_t length) { + uint8_t shift = position % 8; + if(shift == 0) { + return data[position / 8] >> (8 - length); + } else { + // TODO fix read out of bounds + uint8_t value = (data[position / 8] << (shift)); + value |= data[position / 8 + 1] >> (8 - shift); + value = value >> (8 - length); + return value; + } +} + +uint16_t get_bits_16(const uint8_t* data, size_t position, uint8_t length) { + uint16_t value = 0; + if(length <= 8) { + value = get_bits(data, position, length); + } else { + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, length - 8); + } + return value; +} + +uint32_t get_bits_32(const uint8_t* data, size_t position, uint8_t length) { + uint32_t value = 0; + if(length <= 8) { + value = get_bits(data, position, length); + } else if(length <= 16) { + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, length - 8); + } else if(length <= 24) { + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, 8) << (length - 16); + value |= get_bits(data, position + 16, length - 16); + } else { + value = (uint32_t)get_bits(data, position, 8) << (length - 8); + value |= (uint32_t)get_bits(data, position + 8, 8) << (length - 16); + value |= (uint32_t)get_bits(data, position + 16, 8) << (length - 24); + value |= get_bits(data, position + 24, length - 24); + } + + return value; +} + +uint64_t get_bits_64(const uint8_t* data, size_t position, uint8_t length) { + uint64_t value = 0; + if(length <= 8) { + value = get_bits(data, position, length); + } else if(length <= 16) { + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, length - 8); + } else if(length <= 24) { + value = get_bits(data, position, 8) << (length - 8); + value |= get_bits(data, position + 8, 8) << (length - 16); + value |= get_bits(data, position + 16, length - 16); + } else if(length <= 32) { + value = (uint64_t)get_bits(data, position, 8) << (length - 8); + value |= (uint64_t)get_bits(data, position + 8, 8) << (length - 16); + value |= (uint64_t)get_bits(data, position + 16, 8) << (length - 24); + value |= get_bits(data, position + 24, length - 24); + } else { + value = (uint64_t)get_bits(data, position, 8) << (length - 8); + value |= (uint64_t)get_bits(data, position + 8, 8) << (length - 16); + value |= (uint64_t)get_bits(data, position + 16, 8) << (length - 24); + value |= (uint64_t)get_bits(data, position + 24, 8) << (length - 32); + value |= (uint64_t)get_bits(data, position + 32, 8) << (length - 40); + value |= (uint64_t)get_bits(data, position + 40, 8) << (length - 48); + value |= (uint64_t)get_bits(data, position + 48, 8) << (length - 56); + value |= (uint64_t)get_bits(data, position + 56, 8) << (length - 64); + value |= get_bits(data, position + 64, length - 64); + } + + return value; +} + +bool test_parity_32(uint32_t bits, BitLibParity parity) { +#if !defined __GNUC__ +#error Please, implement parity test for non-GCC compilers +#else + switch(parity) { + case BitLibParityEven: + return __builtin_parity(bits); + case BitLibParityOdd: + return !__builtin_parity(bits); + default: + furi_crash("Unknown parity"); + } +#endif +} + +bool bit_lib_test_parity( + const uint8_t* bits, + size_t position, + uint8_t length, + BitLibParity parity, + uint8_t parity_length) { + uint32_t parity_block; + bool result = true; + const size_t parity_blocks_count = length / parity_length; + + for(size_t i = 0; i < parity_blocks_count; ++i) { + switch(parity) { + case BitLibParityEven: + case BitLibParityOdd: + parity_block = get_bits_32(bits, position + i * parity_length, parity_length); + if(!test_parity_32(parity_block, parity)) { + result = false; + } + break; + case BitLibParityAlways0: + if(get_bit(bits, position + i * parity_length + parity_length - 1)) { + result = false; + } + break; + case BitLibParityAlways1: + if(!get_bit(bits, position + i * parity_length + parity_length - 1)) { + result = false; + } + break; + } + + if(!result) break; + } + return result; +} + +size_t bit_lib_add_parity( + const uint8_t* data, + size_t position, + uint8_t* dest, + size_t dest_position, + uint8_t source_length, + uint8_t parity_length, + BitLibParity parity) { + uint32_t parity_word = 0; + size_t j = 0, bit_count = 0; + for(int word = 0; word < source_length; word += parity_length - 1) { + for(int bit = 0; bit < parity_length - 1; bit++) { + parity_word = (parity_word << 1) | get_bit(data, position + word + bit); + set_bit( + dest, dest_position + j++, get_bit(data, position + word + bit)); + } + // if parity fails then return 0 + switch(parity) { + case BitLibParityAlways0: + set_bit(dest, dest_position + j++, 0); + break; // marker bit which should be a 0 + case BitLibParityAlways1: + set_bit(dest, dest_position + j++, 1); + break; // marker bit which should be a 1 + default: + set_bit( + dest, + dest_position + j++, + (test_parity_32(parity_word, BitLibParityOdd) ^ parity) ^ 1); + break; + } + bit_count += parity_length; + parity_word = 0; + } + // if we got here then all the parities passed + // return bit count + return bit_count; +} + +size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n) { + size_t counter = 0; + size_t result_counter = 0; + uint8_t bit_buffer = 0; + uint8_t bit_counter = 0; + + while(counter < length) { + if((counter + 1) % n != 0) { + bit_buffer = (bit_buffer << 1) | get_bit(data, position + counter); + bit_counter++; + } + + if(bit_counter == 8) { + set_bits(data, position + result_counter, bit_buffer, 8); + bit_counter = 0; + bit_buffer = 0; + result_counter += 8; + } + counter++; + } + + if(bit_counter != 0) { + set_bits(data, position + result_counter, bit_buffer, bit_counter); + result_counter += bit_counter; + } + return result_counter; +} + +void bit_lib_copy_bits( + uint8_t* data, + size_t position, + size_t length, + const uint8_t* source, + size_t source_position) { + for(size_t i = 0; i < length; ++i) { + set_bit(data, position + i, get_bit(source, source_position + i)); + } +} + +void bit_lib_reverse_bits(uint8_t* data, size_t position, uint8_t length) { + size_t i = 0; + size_t j = length - 1; + + while(i < j) { + bool tmp = get_bit(data, position + i); + set_bit(data, position + i, get_bit(data, position + j)); + set_bit(data, position + j, tmp); + i++; + j--; + } +} + +uint8_t get_bit_count(uint32_t data) { +#if defined __GNUC__ + return __builtin_popcountl(data); +#else +#error Please, implement popcount for non-GCC compilers +#endif +} + +void bit_lib_print_bits(const uint8_t* data, size_t length) { + for(size_t i = 0; i < length; ++i) { + printf("%u", get_bit(data, i)); + } +} + +void bit_lib_print_regions( + const BitLibRegion* regions, + size_t region_count, + const uint8_t* data, + size_t length) { + // print data + bit_lib_print_bits(data, length); + printf("\r\n"); + + // print regions + for(size_t c = 0; c < length; ++c) { + bool print = false; + + for(size_t i = 0; i < region_count; i++) { + if(regions[i].start <= c && c < regions[i].start + regions[i].length) { + print = true; + printf("%c", regions[i].mark); + break; + } + } + + if(!print) { + printf(" "); + } + } + printf("\r\n"); + + // print regions data + for(size_t c = 0; c < length; ++c) { + bool print = false; + + for(size_t i = 0; i < region_count; i++) { + if(regions[i].start <= c && c < regions[i].start + regions[i].length) { + print = true; + printf("%u", get_bit(data, c)); + break; + } + } + + if(!print) { + printf(" "); + } + } + printf("\r\n"); +} + +uint16_t bit_lib_reverse_16_fast(uint16_t data) { + uint16_t result = 0; + result |= (data & 0x8000) >> 15; + result |= (data & 0x4000) >> 13; + result |= (data & 0x2000) >> 11; + result |= (data & 0x1000) >> 9; + result |= (data & 0x0800) >> 7; + result |= (data & 0x0400) >> 5; + result |= (data & 0x0200) >> 3; + result |= (data & 0x0100) >> 1; + result |= (data & 0x0080) << 1; + result |= (data & 0x0040) << 3; + result |= (data & 0x0020) << 5; + result |= (data & 0x0010) << 7; + result |= (data & 0x0008) << 9; + result |= (data & 0x0004) << 11; + result |= (data & 0x0002) << 13; + result |= (data & 0x0001) << 15; + return result; +} + +uint8_t bit_lib_reverse_8_fast(uint8_t byte) { + byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4; + byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2; + byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1; + return byte; +} + +uint16_t bit_lib_crc8( + uint8_t const* data, + size_t data_size, + uint8_t polynom, + uint8_t init, + bool ref_in, + bool ref_out, + uint8_t xor_out) { + uint8_t crc = init; + + for(size_t i = 0; i < data_size; ++i) { + uint8_t byte = data[i]; + if(ref_in) bit_lib_reverse_bits(&byte, 0, 8); + crc ^= byte; + + for(size_t j = 8; j > 0; --j) { + if(crc & TOPBIT(8)) { + crc = (crc << 1) ^ polynom; + } else { + crc = (crc << 1); + } + } + } + + if(ref_out) bit_lib_reverse_bits(&crc, 0, 8); + crc ^= xor_out; + + return crc; +} + +uint16_t crc16( + uint8_t const* data, + size_t data_size, + uint16_t polynom, + uint16_t init, + bool ref_in, + bool ref_out, + uint16_t xor_out) { + uint16_t crc = init; + + for(size_t i = 0; i < data_size; ++i) { + uint8_t byte = data[i]; + if(ref_in) byte = bit_lib_reverse_16_fast(byte) >> 8; + + for(size_t j = 0; j < 8; ++j) { + bool c15 = (crc >> 15 & 1); + bool bit = (byte >> (7 - j) & 1); + crc <<= 1; + if(c15 ^ bit) crc ^= polynom; + } + } + + if(ref_out) crc = bit_lib_reverse_16_fast(crc); + crc ^= xor_out; + + return crc; +} + +void from_days_to_datetime(uint16_t days, FuriHalRtcDateTime* datetime, uint16_t start_year) { + uint32_t timestamp = days * 24 * 60 * 60; + FuriHalRtcDateTime start_datetime = {0}; + start_datetime.year = start_year - 1; + start_datetime.month = 12; + start_datetime.day = 31; + timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); + furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); +} + +void from_minutes_to_datetime(uint32_t minutes, FuriHalRtcDateTime* datetime, uint16_t start_year) { + uint32_t timestamp = minutes * 60; + FuriHalRtcDateTime start_datetime = {0}; + start_datetime.year = start_year - 1; + start_datetime.month = 12; + start_datetime.day = 31; + timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); + furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); +} + +bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { + uint16_t transport_departament = get_bits_16(block->data, 0, 10); + + FURI_LOG_I(TAG2, "Transport departament: %x", transport_departament); + + uint16_t layout_type = get_bits_16(block->data, 52, 4); + if(layout_type == 0xE) { + layout_type = get_bits_16(block->data, 52, 9); + } else if(layout_type == 0xF) { + layout_type = get_bits_16(block->data, 52, 14); + } + + FURI_LOG_I(TAG2, "Layout type %x", layout_type); + + uint16_t card_view = 0; + uint16_t card_type = 0; + uint32_t card_number = 0; + uint8_t card_layout = 0; + uint8_t card_layout2 = 0; + uint16_t card_use_before_date = 0; + uint16_t card_blank_type = 0; + uint32_t card_start_trip_minutes = 0; + uint8_t card_minutes_pass = 0; + uint32_t card_remaining_funds = 0; + uint16_t card_validator = 0; + uint8_t card_blocked = 0; + uint32_t card_hash = 0; + + switch(layout_type) { + case 0x02: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_use_before_date = get_bits_16(block->data, 56, 16); //202 + uint8_t card_benefit_code = get_bits(block->data, 72, 8); //124 + uint32_t card_rfu1 = get_bits_32(block->data, 80, 32); //rfu1 + uint16_t card_crc16 = get_bits_16(block->data, 112, 16); //501.1 + card_blocked = get_bits(block->data, 128, 1); //303 + uint16_t card_start_trip_time = get_bits_16(block->data, 177, 12); //403 + uint16_t card_start_trip_date = get_bits_16(block->data, 189, 16); //402 + uint16_t card_valid_from_date = get_bits_16(block->data, 157, 16); //311 + uint16_t card_valid_by_date = get_bits_16(block->data, 173, 16); //312 + uint8_t card_start_trip_seconds = get_bits(block->data, 189, 6); //406 + uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 + uint16_t card_use_with_date = get_bits_16(block->data, 189, 16); //205 + uint8_t card_route = get_bits(block->data, 205, 1); //424 + uint16_t card_validator1 = get_bits_16(block->data, 206, 15); //422.1 + card_validator = get_bits_16(block->data, 205, 16); //422 + uint16_t card_total_trips = get_bits_16(block->data, 221, 16); //331 + uint8_t card_write_enabled = get_bits(block->data, 237, 1); //write_enabled + uint8_t card_rfu2 = get_bits(block->data, 238, 2); //rfu2 + uint16_t card_crc16_2 = get_bits_16(block->data, 240, 16); //501.2 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_use_before_date, + card_benefit_code, + card_rfu1, + card_crc16, + card_blocked, + card_start_trip_time, + card_start_trip_date, + card_valid_from_date, + card_valid_by_date, + card_start_trip_seconds, + card_transport_type1, + card_transport_type2, + card_transport_type3, + card_transport_type4, + card_use_with_date, + card_route, + card_validator1, + card_validator, + card_total_trips, + card_write_enabled, + card_rfu2, + card_crc16_2); + if(card_valid_by_date == 0) { + return false; + } + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_start_trip_date) * 24 * 60 + card_start_trip_time, + &card_start_trip_minutes_s, + 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips: %d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_total_trips, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x06: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_use_before_date = get_bits_16(block->data, 56, 16); //202 + uint8_t card_geozone_a = get_bits(block->data, 72, 4); //GeoZoneA + uint8_t card_geozone_b = get_bits(block->data, 76, 4); //GeoZoneB + card_blank_type = get_bits_16(block->data, 80, 10); //121. + uint16_t card_type_of_extended = get_bits_16(block->data, 90, 10); //122 + uint32_t card_rfu1 = get_bits_16(block->data, 100, 12); //rfu1 + uint16_t card_crc16 = get_bits_16(block->data, 112, 16); //501.1 + card_blocked = get_bits(block->data, 128, 1); //303 + uint16_t card_start_trip_time = get_bits_16(block->data, 129, 12); //403 + uint16_t card_start_trip_date = get_bits_16(block->data, 141, 16); //402 + uint16_t card_valid_from_date = get_bits_16(block->data, 157, 16); //311 + uint16_t card_valid_by_date = get_bits_16(block->data, 173, 16); //312 + uint16_t card_company = get_bits(block->data, 189, 4); //Company + uint8_t card_validator1 = get_bits(block->data, 193, 4); //422.1 + uint16_t card_remaining_trips = get_bits_16(block->data, 197, 10); //321 + uint8_t card_units = get_bits(block->data, 207, 6); //Units + uint16_t card_validator2 = get_bits_16(block->data, 213, 10); //422.2 + uint16_t card_total_trips = get_bits_16(block->data, 223, 16); //331 + uint8_t card_extended = get_bits(block->data, 239, 1); //123 + uint16_t card_crc16_2 = get_bits_16(block->data, 240, 16); //501.2 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %x %x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_use_before_date, + card_geozone_a, + card_geozone_b, + card_blank_type, + card_type_of_extended, + card_rfu1, + card_crc16, + card_blocked, + card_start_trip_time, + card_start_trip_date, + card_valid_from_date, + card_valid_by_date, + card_company, + card_validator1, + card_remaining_trips, + card_units, + card_validator2, + card_total_trips, + card_extended, + card_crc16_2); + card_validator = card_validator1 * 1024 + card_validator2; + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_start_trip_date) * 24 * 60 + card_start_trip_time, + &card_start_trip_minutes_s, + 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips left: %d of %d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_remaining_trips, + card_total_trips, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x08: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_use_before_date = get_bits_16(block->data, 56, 16); //202 + uint64_t card_rfu1 = get_bits_64(block->data, 72, 56); //rfu1 + uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 + uint8_t card_rfu2 = get_bits(block->data, 153, 7); //rfu2 + uint8_t card_remaining_trips1 = get_bits(block->data, 160, 8); //321.1 + uint8_t card_remaining_trips = get_bits(block->data, 168, 8); //321 + uint8_t card_validator1 = get_bits(block->data, 193, 2); //422.1 + uint16_t card_validator = get_bits_16(block->data, 177, 15); //422 + card_hash = get_bits_32(block->data, 192, 32); //502 + uint32_t card_rfu3 = get_bits_32(block->data, 224, 32); //rfu3 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %llx %x %x %x %x %x %x %x %x %lx %x %lx", + card_view, + card_type, + card_number, + card_use_before_date, + card_rfu1, + card_valid_from_date, + card_valid_for_days, + card_requires_activation, + card_rfu2, + card_remaining_trips1, + card_remaining_trips, + card_validator1, + card_validator, + card_hash, + card_valid_from_date, + card_rfu3); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips left: %d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_remaining_trips, + card_validator); + break; + } + case 0x0A: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + uint16_t card_valid_from_date = get_bits_16(block->data, 64, 12); //311 + uint32_t card_valid_for_minutes = get_bits_32(block->data, 76, 19); //314 + uint8_t card_requires_activation = get_bits(block->data, 95, 1); //301 + card_start_trip_minutes = get_bits_32(block->data, 96, 19); //405 + card_minutes_pass = get_bits(block->data, 119, 7); //412 + uint8_t card_transport_type_flag = get_bits(block->data, 126, 2); //421.0 + uint8_t card_remaining_trips = get_bits(block->data, 128, 8); //321 + uint16_t card_validator = get_bits_16(block->data, 136, 16); //422 + uint8_t card_transport_type1 = get_bits(block->data, 152, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 154, 2); //421.2 + uint8_t card_transport_type3 = get_bits(block->data, 156, 2); //421.3 + uint8_t card_transport_type4 = get_bits(block->data, 158, 2); //421.4 + card_hash = get_bits_32(block->data, 192, 32); //502 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %lx %x %lx %x %x %x %x %x %x %x %x %lx", + card_view, + card_type, + card_number, + card_use_before_date, + card_valid_from_date, + card_valid_for_minutes, + card_requires_activation, + card_start_trip_minutes, + card_minutes_pass, + card_transport_type_flag, + card_remaining_trips, + card_validator, + card_transport_type1, + card_transport_type2, + card_transport_type3, + card_transport_type4, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_remaining_trips, + card_validator); + break; + } + case 0x0C: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_use_before_date = get_bits_16(block->data, 56, 16); //202 + uint64_t card_rfu1 = get_bits_64(block->data, 72, 56); //rfu1 + uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 + uint16_t card_rfu2 = get_bits_16(block->data, 153, 13); //rfu2 + uint16_t card_remaining_trips = get_bits_16(block->data, 166, 10); //321 + uint16_t card_validator = get_bits_16(block->data, 176, 16); //422 + card_hash = get_bits_32(block->data, 192, 32); //502 + uint16_t card_start_trip_date = get_bits_16(block->data, 224, 16); //402 + uint16_t card_start_trip_time = get_bits_16(block->data, 240, 11); //403 + uint8_t card_transport_type = get_bits(block->data, 251, 2); //421 + uint8_t card_rfu3 = get_bits(block->data, 253, 2); //rfu3 + uint8_t card_transfer_in_metro = get_bits(block->data, 255, 1); //432 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %llx %x %x %x %x %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_use_before_date, + card_rfu1, + card_valid_from_date, + card_valid_for_days, + card_requires_activation, + card_rfu2, + card_remaining_trips, + card_validator, + card_start_trip_date, + card_start_trip_time, + card_transport_type, + card_rfu3, + card_transfer_in_metro); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_start_trip_date) * 24 * 60 + card_start_trip_time, + &card_start_trip_minutes_s, + 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_remaining_trips, + card_validator); + break; + } + case 0x0D: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + uint8_t card_rfu1 = get_bits(block->data, 56, 8); //rfu1 + card_use_before_date = get_bits_16(block->data, 64, 16); //202 + uint16_t card_valid_for_time = get_bits_16(block->data, 80, 11); //316 + uint8_t card_rfu2 = get_bits(block->data, 91, 5); //rfu2 + uint16_t card_use_before_date2 = get_bits_16(block->data, 96, 16); //202.2 + uint16_t card_valid_for_time2 = get_bits_16(block->data, 123, 11); //316.2 + uint8_t card_rfu3 = get_bits(block->data, 123, 5); //rfu3 + uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 + uint8_t card_rfu4 = get_bits(block->data, 153, 2); //rfu4 + uint8_t card_passage_5_minutes = get_bits(block->data, 155, 5); //413 + uint8_t card_transport_type1 = get_bits(block->data, 160, 2); //421.1 + uint8_t card_passage_in_metro = get_bits(block->data, 162, 1); //431 + uint8_t card_passages_ground_transport = get_bits(block->data, 163, 3); //433 + uint16_t card_remaining_trips = get_bits_16(block->data, 166, 10); //321 + uint16_t card_validator = get_bits_16(block->data, 176, 16); //422 + card_hash = get_bits_32(block->data, 192, 32); //502 + uint16_t card_start_trip_date = get_bits_16(block->data, 224, 16); //402 + uint16_t card_start_trip_time = get_bits_16(block->data, 240, 11); //403 + uint8_t card_transport_type2 = get_bits(block->data, 251, 2); //421.2 + uint8_t card_rfu5 = get_bits(block->data, 253, 2); //rfu5 + uint8_t card_transfer_in_metro = get_bits(block->data, 255, 1); //432 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_layout, + card_rfu1, + card_use_before_date, + card_valid_for_time, + card_rfu2, + card_use_before_date2, + card_valid_for_time2, + card_rfu3, + card_valid_from_date, + card_valid_for_days, + card_requires_activation, + card_rfu4, + card_passage_5_minutes, + card_transport_type1, + card_passage_in_metro, + card_passages_ground_transport, + card_remaining_trips, + card_validator, + card_start_trip_date, + card_start_trip_time, + card_transport_type2, + card_rfu5, + card_transfer_in_metro); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_start_trip_date) * 24 * 60 + card_start_trip_time, + &card_start_trip_minutes_s, + 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_remaining_trips, + card_validator); + break; + } + case 0x1C1: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + card_use_before_date = get_bits_16(block->data, 61, 16); //202. + card_blank_type = get_bits_16(block->data, 77, 10); //121. + card_validator = get_bits_16(block->data, 128, 16); //422 + uint16_t card_start_trip_date = get_bits_16(block->data, 144, 16); //402 + uint16_t card_start_trip_time = get_bits_16(block->data, 160, 11); //403 + uint8_t card_transport_type1 = get_bits(block->data, 171, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 173, 2); //421.2 + uint8_t card_transfer_in_metro = get_bits(block->data, 177, 1); //432 + uint8_t card_passage_in_metro = get_bits(block->data, 178, 1); //431 + uint8_t card_passages_ground_transport = get_bits(block->data, 179, 3); //433 + card_minutes_pass = get_bits(block->data, 185, 8); //412. + card_remaining_funds = get_bits_32(block->data, 196, 19) / 100; //322 + uint8_t card_fare_trip = get_bits(block->data, 215, 2); //441 + card_blocked = get_bits(block->data, 202, 1); //303 + uint8_t card_zoo = get_bits(block->data, 218, 1); //zoo + card_hash = get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %lx %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_use_before_date, + card_blank_type, + card_validator, + card_start_trip_date, + card_start_trip_time, + card_transport_type1, + card_transport_type2, + card_transfer_in_metro, + card_passage_in_metro, + card_passages_ground_transport, + card_minutes_pass, + card_remaining_funds, + card_fare_trip, + card_blocked, + card_zoo, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 1992); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C2: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 + card_use_before_date = get_bits_16(block->data, 71, 16); //202. + card_blank_type = get_bits_16(block->data, 87, 10); //121. + uint16_t card_valid_to_date = get_bits_16(block->data, 97, 16); //311 + uint16_t card_activate_during = get_bits_16(block->data, 113, 9); //302 + uint32_t card_valid_for_minutes = get_bits_32(block->data, 131, 20); //314 + card_minutes_pass = get_bits(block->data, 154, 8); //412. + uint8_t card_transport_type = get_bits(block->data, 163, 2); //421 + uint8_t card_passage_in_metro = get_bits(block->data, 165, 1); //431 + uint8_t card_transfer_in_metro = get_bits(block->data, 166, 1); //432 + uint16_t card_remaining_trips = get_bits_16(block->data, 167, 10); //321 + card_validator = get_bits_16(block->data, 177, 16); //422 + uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 196, 20); //404 + uint8_t card_requires_activation = get_bits(block->data, 216, 1); //301 + card_blocked = get_bits(block->data, 217, 1); //303 + uint8_t card_extended = get_bits(block->data, 218, 1); //123 + card_hash = get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %x %x %x %x %x %lx %x %x %x %x %x %x %lx %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_type_of_extended, + card_use_before_date, + card_blank_type, + card_valid_to_date, + card_activate_during, + card_valid_for_minutes, + card_minutes_pass, + card_transport_type, + card_passage_in_metro, + card_transfer_in_metro, + card_remaining_trips, + card_validator, + card_start_trip_neg_minutes, + card_requires_activation, + card_blocked, + card_extended, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_valid_to_date) * 24 * 60 + card_valid_for_minutes - card_start_trip_neg_minutes, + &card_start_trip_minutes_s, + 2016); //-time + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C3: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + card_use_before_date = get_bits_16(block->data, 61, 16); //202 + card_blank_type = get_bits_16(block->data, 77, 10); //121 + card_remaining_funds = get_bits_32(block->data, 188, 22) / 100; //322 + card_hash = get_bits_32(block->data, 224, 32); //502 + card_validator = get_bits_16(block->data, 128, 16); //422 + card_start_trip_minutes = get_bits_32(block->data, 144, 23); //405 + uint8_t card_fare_trip = get_bits(block->data, 210, 2); //441 + card_minutes_pass = get_bits(block->data, 171, 7); //412 + uint8_t card_transport_type_flag = get_bits(block->data, 178, 2); //421.0 + uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 + card_blocked = get_bits(block->data, 212, 1); //303 + FURI_LOG_D( + TAG2, + "Card view: %x, type: %x, number: %lx, layout: %x, layout2: %x, use before date: %x, blank type: %x, remaining funds: %lx, hash: %lx, validator: %x, start trip minutes: %lx, fare trip: %x, minutes pass: %x, transport type flag: %x, transport type1: %x, transport type2: %x, transport type3: %x, transport type4: %x, blocked: %x", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_use_before_date, + card_blank_type, + card_remaining_funds, + card_hash, + card_validator, + card_start_trip_minutes, + card_fare_trip, + card_minutes_pass, + card_transport_type_flag, + card_transport_type1, + card_transport_type2, + card_transport_type3, + card_transport_type4, + card_blocked); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nBalance: %ld rub\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_remaining_funds, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C4: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 + card_use_before_date = get_bits_16(block->data, 71, 13); //202. + card_blank_type = get_bits_16(block->data, 84, 10); //121. + uint16_t card_valid_to_date = get_bits_16(block->data, 94, 13); //311 + uint16_t card_activate_during = get_bits_16(block->data, 107, 9); //302 + uint16_t card_extension_counter = get_bits_16(block->data, 116, 10); //304 + uint32_t card_valid_for_minutes = get_bits_32(block->data, 128, 20); //314 + card_minutes_pass = get_bits(block->data, 158, 7); //412. + uint8_t card_transport_type_flag = get_bits(block->data, 178, 2); //421.0 + uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 + uint16_t card_remaining_trips = get_bits_16(block->data, 169, 10); //321 + card_validator = get_bits_16(block->data, 179, 16); //422 + uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 195, 20); //404 + uint8_t card_requires_activation = get_bits(block->data, 215, 1); //301 + card_blocked = get_bits(block->data, 216, 1); //303 + uint8_t card_extended = get_bits(block->data, 217, 1); //123 + card_hash = get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %x %x %x %x %x %x %lx %x %x %x %x %x %x %x %x %lx %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_type_of_extended, + card_use_before_date, + card_blank_type, + card_valid_to_date, + card_activate_during, + card_extension_counter, + card_valid_for_minutes, + card_minutes_pass, + card_transport_type_flag, + card_transport_type1, + card_transport_type2, + card_transport_type3, + card_transport_type4, + card_remaining_trips, + card_validator, + card_start_trip_neg_minutes, + card_requires_activation, + card_blocked, + card_extended, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + (card_use_before_date + 1) * 24 * 60 + card_valid_for_minutes - + card_start_trip_neg_minutes, + &card_start_trip_minutes_s, + 2011); //-time + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C5: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + card_use_before_date = get_bits_16(block->data, 61, 13); //202. + card_blank_type = get_bits_16(block->data, 74, 10); //121. + uint32_t card_valid_to_time = get_bits_32(block->data, 84, 23); //317 + uint16_t card_extension_counter = get_bits_16(block->data, 107, 10); //304 + card_start_trip_minutes = get_bits_32(block->data, 128, 23); //405 + uint8_t card_metro_ride_with = get_bits(block->data, 151, 7); //414 + card_minutes_pass = get_bits(block->data, 158, 7); //412. + card_remaining_funds = get_bits_32(block->data, 167, 19) / 100; //322 + card_validator = get_bits_16(block->data, 186, 16); //422 + card_blocked = get_bits(block->data, 202, 1); //303 + uint16_t card_route = get_bits_16(block->data, 204, 12); //424 + uint8_t card_passages_ground_transport = get_bits(block->data, 216, 7); //433 + card_hash = get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %x %x %lx %x %lx %x %x %lx %x %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_use_before_date, + card_blank_type, + card_valid_to_time, + card_extension_counter, + card_start_trip_minutes, + card_metro_ride_with, + card_minutes_pass, + card_remaining_funds, + card_validator, + card_blocked, + card_route, + card_passages_ground_transport, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2019); + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nBalance: %ld rub\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_remaining_funds, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x1C6: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + card_layout2 = get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 + card_use_before_date = get_bits_16(block->data, 71, 13); //202. + card_blank_type = get_bits_16(block->data, 84, 10); //121. + uint32_t card_valid_from_date = get_bits_32(block->data, 94, 23); //311 + uint16_t card_extension_counter = get_bits_16(block->data, 117, 10); //304 + uint32_t card_valid_for_minutes = get_bits_32(block->data, 128, 20); //314 + uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 148, 20); //404 + uint8_t card_metro_ride_with = get_bits(block->data, 168, 7); //414 + card_minutes_pass = get_bits(block->data, 175, 7); //412. + uint16_t card_remaining_trips = get_bits_16(block->data, 182, 7); //321 + card_validator = get_bits_16(block->data, 189, 16); //422 + card_blocked = get_bits(block->data, 205, 1); //303 + uint8_t card_extended = get_bits(block->data, 206, 1); //123 + uint16_t card_route = get_bits_16(block->data, 212, 12); //424 + card_hash = get_bits_32(block->data, 224, 32); //502 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %x %x %x %lx %x %lx %lx %x %x %x %x %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_layout2, + card_type_of_extended, + card_use_before_date, + card_blank_type, + card_valid_from_date, + card_extension_counter, + card_valid_for_minutes, + card_start_trip_neg_minutes, + card_metro_ride_with, + card_minutes_pass, + card_remaining_trips, + card_validator, + card_blocked, + card_extended, + card_route, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); + + FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + card_valid_from_date + card_valid_for_minutes - card_start_trip_neg_minutes, + &card_start_trip_minutes_s, + 2019); //-time + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute, + card_validator); + break; + } + case 0x3CCB: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + uint16_t card_tech_code = get_bits_32(block->data, 56, 10); //tech_code + uint16_t card_valid_to_minutes = get_bits_16(block->data, 66, 16); //311 + uint16_t card_valid_by_date = get_bits_16(block->data, 82, 16); //312 + uint8_t card_interval = get_bits(block->data, 98, 4); //interval + uint16_t card_app_code1 = get_bits_16(block->data, 102, 16); //app_code1 + uint16_t card_hash1 = get_bits_16(block->data, 112, 16); //502.1 + uint16_t card_type1 = get_bits_16(block->data, 128, 10); //type1 + uint16_t card_app_code2 = get_bits_16(block->data, 138, 10); //app_code2 + uint16_t card_type2 = get_bits_16(block->data, 148, 10); //type2 + uint16_t card_app_code3 = get_bits_16(block->data, 158, 10); //app_code3 + uint16_t card_type3 = get_bits_16(block->data, 148, 10); //type3 + uint16_t card_app_code4 = get_bits_16(block->data, 168, 10); //app_code4 + uint16_t card_type4 = get_bits_16(block->data, 178, 10); //type4 + card_hash = get_bits_32(block->data, 224, 32); //502.2 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %lx", + card_view, + card_type, + card_number, + card_layout, + card_tech_code, + card_use_before_date, + card_blank_type, + card_valid_to_minutes, + card_valid_by_date, + card_interval, + card_app_code1, + card_hash1, + card_type1, + card_app_code2, + card_type2, + card_app_code3, + card_type3, + card_app_code4, + card_type4, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); + + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_validator); + break; + } + case 0x3C0B: { + card_view = get_bits_16(block->data, 0, 10); //101 + card_type = get_bits_16(block->data, 10, 10); //102 + card_number = get_bits_32(block->data, 20, 32); //201 + card_layout = get_bits(block->data, 52, 4); //111 + uint16_t card_tech_code = get_bits_32(block->data, 56, 10); //tech_code + uint16_t card_valid_to_minutes = get_bits_16(block->data, 66, 16); //311 + uint16_t card_valid_by_date = get_bits_16(block->data, 82, 16); //312 + uint16_t card_hash = get_bits_16(block->data, 112, 16); //502.1 + + FURI_LOG_D( + TAG2, + "%x %x %lx %x %x %x %x %x %x %x", + card_view, + card_type, + card_number, + card_layout, + card_tech_code, + card_use_before_date, + card_blank_type, + card_valid_to_minutes, + card_valid_by_date, + card_hash); + FuriHalRtcDateTime card_use_before_date_s = {0}; + from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); + + furi_string_printf( + result, + "Number: %010lu\nValid for: %02d.%02d.%04d\nValidator: %05d", + card_number, + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year, + card_validator); + break; + } + default: + result = NULL; + return false; + } + + return true; +} diff --git a/applications/main/nfc/helpers/mosgortrans_layouts_i.h b/applications/main/nfc/helpers/mosgortrans_layouts_i.h new file mode 100644 index 00000000000..820b622558e --- /dev/null +++ b/applications/main/nfc/helpers/mosgortrans_layouts_i.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include +#include +#include + +#define TAG2 "Mosgortrans" + +bool parse_transport_block(const MfClassicBlock* block, FuriString* result); \ No newline at end of file diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index c1838f626b1..dbd9d726f9c 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -5,9 +5,8 @@ #include #include -#include +#include #include -#include #include #define TAG "Troika" @@ -85,1391 +84,6 @@ static const MfClassicKeyPair troika_4k_keys[] = { {.s = 39, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, }; -#define TOPBIT(X) (1 << ((X)-1)) - -typedef enum { - BitLibParityEven, - BitLibParityOdd, - BitLibParityAlways0, - BitLibParityAlways1, -} BitLibParity; - -typedef struct { - const char mark; - const size_t start; - const size_t length; -} BitLibRegion; - -void push_bit(uint8_t* data, size_t data_size, bool bit) { - size_t last_index = data_size - 1; - - for(size_t i = 0; i < last_index; ++i) { - data[i] = (data[i] << 1) | ((data[i + 1] >> 7) & 1); - } - data[last_index] = (data[last_index] << 1) | bit; -} - -void set_bit(uint8_t* data, size_t position, bool bit) { - if(bit) { - data[position / 8] |= 1UL << (7 - (position % 8)); - } else { - data[position / 8] &= ~(1UL << (7 - (position % 8))); - } -} - -void set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length) { - furi_check(length <= 8); - furi_check(length > 0); - - for(uint8_t i = 0; i < length; ++i) { - uint8_t shift = (length - 1) - i; - set_bit(data, position + i, (byte >> shift) & 1); //-V610 - } -} - -bool get_bit(const uint8_t* data, size_t position) { - return (data[position / 8] >> (7 - (position % 8))) & 1; -} - -uint8_t get_bits(const uint8_t* data, size_t position, uint8_t length) { - uint8_t shift = position % 8; - if(shift == 0) { - return data[position / 8] >> (8 - length); - } else { - // TODO fix read out of bounds - uint8_t value = (data[position / 8] << (shift)); - value |= data[position / 8 + 1] >> (8 - shift); - value = value >> (8 - length); - return value; - } -} - -uint16_t get_bits_16(const uint8_t* data, size_t position, uint8_t length) { - uint16_t value = 0; - if(length <= 8) { - value = get_bits(data, position, length); - } else { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, length - 8); - } - return value; -} - -uint32_t get_bits_32(const uint8_t* data, size_t position, uint8_t length) { - uint32_t value = 0; - if(length <= 8) { - value = get_bits(data, position, length); - } else if(length <= 16) { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, length - 8); - } else if(length <= 24) { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, 8) << (length - 16); - value |= get_bits(data, position + 16, length - 16); - } else { - value = (uint32_t)get_bits(data, position, 8) << (length - 8); - value |= (uint32_t)get_bits(data, position + 8, 8) << (length - 16); - value |= (uint32_t)get_bits(data, position + 16, 8) << (length - 24); - value |= get_bits(data, position + 24, length - 24); - } - - return value; -} - -uint64_t get_bits_64(const uint8_t* data, size_t position, uint8_t length) { - uint64_t value = 0; - if(length <= 8) { - value = get_bits(data, position, length); - } else if(length <= 16) { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, length - 8); - } else if(length <= 24) { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, 8) << (length - 16); - value |= get_bits(data, position + 16, length - 16); - } else if(length <= 32) { - value = (uint64_t)get_bits(data, position, 8) << (length - 8); - value |= (uint64_t)get_bits(data, position + 8, 8) << (length - 16); - value |= (uint64_t)get_bits(data, position + 16, 8) << (length - 24); - value |= get_bits(data, position + 24, length - 24); - } else { - value = (uint64_t)get_bits(data, position, 8) << (length - 8); - value |= (uint64_t)get_bits(data, position + 8, 8) << (length - 16); - value |= (uint64_t)get_bits(data, position + 16, 8) << (length - 24); - value |= (uint64_t)get_bits(data, position + 24, 8) << (length - 32); - value |= (uint64_t)get_bits(data, position + 32, 8) << (length - 40); - value |= (uint64_t)get_bits(data, position + 40, 8) << (length - 48); - value |= (uint64_t)get_bits(data, position + 48, 8) << (length - 56); - value |= (uint64_t)get_bits(data, position + 56, 8) << (length - 64); - value |= get_bits(data, position + 64, length - 64); - } - - return value; -} - -bool test_parity_32(uint32_t bits, BitLibParity parity) { -#if !defined __GNUC__ -#error Please, implement parity test for non-GCC compilers -#else - switch(parity) { - case BitLibParityEven: - return __builtin_parity(bits); - case BitLibParityOdd: - return !__builtin_parity(bits); - default: - furi_crash("Unknown parity"); - } -#endif -} - -bool bit_lib_test_parity( - const uint8_t* bits, - size_t position, - uint8_t length, - BitLibParity parity, - uint8_t parity_length) { - uint32_t parity_block; - bool result = true; - const size_t parity_blocks_count = length / parity_length; - - for(size_t i = 0; i < parity_blocks_count; ++i) { - switch(parity) { - case BitLibParityEven: - case BitLibParityOdd: - parity_block = get_bits_32(bits, position + i * parity_length, parity_length); - if(!test_parity_32(parity_block, parity)) { - result = false; - } - break; - case BitLibParityAlways0: - if(get_bit(bits, position + i * parity_length + parity_length - 1)) { - result = false; - } - break; - case BitLibParityAlways1: - if(!get_bit(bits, position + i * parity_length + parity_length - 1)) { - result = false; - } - break; - } - - if(!result) break; - } - return result; -} - -size_t bit_lib_add_parity( - const uint8_t* data, - size_t position, - uint8_t* dest, - size_t dest_position, - uint8_t source_length, - uint8_t parity_length, - BitLibParity parity) { - uint32_t parity_word = 0; - size_t j = 0, bit_count = 0; - for(int word = 0; word < source_length; word += parity_length - 1) { - for(int bit = 0; bit < parity_length - 1; bit++) { - parity_word = (parity_word << 1) | get_bit(data, position + word + bit); - set_bit( - dest, dest_position + j++, get_bit(data, position + word + bit)); - } - // if parity fails then return 0 - switch(parity) { - case BitLibParityAlways0: - set_bit(dest, dest_position + j++, 0); - break; // marker bit which should be a 0 - case BitLibParityAlways1: - set_bit(dest, dest_position + j++, 1); - break; // marker bit which should be a 1 - default: - set_bit( - dest, - dest_position + j++, - (test_parity_32(parity_word, BitLibParityOdd) ^ parity) ^ 1); - break; - } - bit_count += parity_length; - parity_word = 0; - } - // if we got here then all the parities passed - // return bit count - return bit_count; -} - -size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n) { - size_t counter = 0; - size_t result_counter = 0; - uint8_t bit_buffer = 0; - uint8_t bit_counter = 0; - - while(counter < length) { - if((counter + 1) % n != 0) { - bit_buffer = (bit_buffer << 1) | get_bit(data, position + counter); - bit_counter++; - } - - if(bit_counter == 8) { - set_bits(data, position + result_counter, bit_buffer, 8); - bit_counter = 0; - bit_buffer = 0; - result_counter += 8; - } - counter++; - } - - if(bit_counter != 0) { - set_bits(data, position + result_counter, bit_buffer, bit_counter); - result_counter += bit_counter; - } - return result_counter; -} - -void bit_lib_copy_bits( - uint8_t* data, - size_t position, - size_t length, - const uint8_t* source, - size_t source_position) { - for(size_t i = 0; i < length; ++i) { - set_bit(data, position + i, get_bit(source, source_position + i)); - } -} - -void bit_lib_reverse_bits(uint8_t* data, size_t position, uint8_t length) { - size_t i = 0; - size_t j = length - 1; - - while(i < j) { - bool tmp = get_bit(data, position + i); - set_bit(data, position + i, get_bit(data, position + j)); - set_bit(data, position + j, tmp); - i++; - j--; - } -} - -uint8_t get_bit_count(uint32_t data) { -#if defined __GNUC__ - return __builtin_popcountl(data); -#else -#error Please, implement popcount for non-GCC compilers -#endif -} - -void bit_lib_print_bits(const uint8_t* data, size_t length) { - for(size_t i = 0; i < length; ++i) { - printf("%u", get_bit(data, i)); - } -} - -void bit_lib_print_regions( - const BitLibRegion* regions, - size_t region_count, - const uint8_t* data, - size_t length) { - // print data - bit_lib_print_bits(data, length); - printf("\r\n"); - - // print regions - for(size_t c = 0; c < length; ++c) { - bool print = false; - - for(size_t i = 0; i < region_count; i++) { - if(regions[i].start <= c && c < regions[i].start + regions[i].length) { - print = true; - printf("%c", regions[i].mark); - break; - } - } - - if(!print) { - printf(" "); - } - } - printf("\r\n"); - - // print regions data - for(size_t c = 0; c < length; ++c) { - bool print = false; - - for(size_t i = 0; i < region_count; i++) { - if(regions[i].start <= c && c < regions[i].start + regions[i].length) { - print = true; - printf("%u", get_bit(data, c)); - break; - } - } - - if(!print) { - printf(" "); - } - } - printf("\r\n"); -} - -uint16_t bit_lib_reverse_16_fast(uint16_t data) { - uint16_t result = 0; - result |= (data & 0x8000) >> 15; - result |= (data & 0x4000) >> 13; - result |= (data & 0x2000) >> 11; - result |= (data & 0x1000) >> 9; - result |= (data & 0x0800) >> 7; - result |= (data & 0x0400) >> 5; - result |= (data & 0x0200) >> 3; - result |= (data & 0x0100) >> 1; - result |= (data & 0x0080) << 1; - result |= (data & 0x0040) << 3; - result |= (data & 0x0020) << 5; - result |= (data & 0x0010) << 7; - result |= (data & 0x0008) << 9; - result |= (data & 0x0004) << 11; - result |= (data & 0x0002) << 13; - result |= (data & 0x0001) << 15; - return result; -} - -uint8_t bit_lib_reverse_8_fast(uint8_t byte) { - byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4; - byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2; - byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1; - return byte; -} - -uint16_t bit_lib_crc8( - uint8_t const* data, - size_t data_size, - uint8_t polynom, - uint8_t init, - bool ref_in, - bool ref_out, - uint8_t xor_out) { - uint8_t crc = init; - - for(size_t i = 0; i < data_size; ++i) { - uint8_t byte = data[i]; - if(ref_in) bit_lib_reverse_bits(&byte, 0, 8); - crc ^= byte; - - for(size_t j = 8; j > 0; --j) { - if(crc & TOPBIT(8)) { - crc = (crc << 1) ^ polynom; - } else { - crc = (crc << 1); - } - } - } - - if(ref_out) bit_lib_reverse_bits(&crc, 0, 8); - crc ^= xor_out; - - return crc; -} - -uint16_t crc16( - uint8_t const* data, - size_t data_size, - uint16_t polynom, - uint16_t init, - bool ref_in, - bool ref_out, - uint16_t xor_out) { - uint16_t crc = init; - - for(size_t i = 0; i < data_size; ++i) { - uint8_t byte = data[i]; - if(ref_in) byte = bit_lib_reverse_16_fast(byte) >> 8; - - for(size_t j = 0; j < 8; ++j) { - bool c15 = (crc >> 15 & 1); - bool bit = (byte >> (7 - j) & 1); - crc <<= 1; - if(c15 ^ bit) crc ^= polynom; - } - } - - if(ref_out) crc = bit_lib_reverse_16_fast(crc); - crc ^= xor_out; - - return crc; -} - -void from_days_to_datetime(uint16_t days, FuriHalRtcDateTime* datetime, uint16_t start_year) { - uint32_t timestamp = days * 24 * 60 * 60; - FuriHalRtcDateTime start_datetime = {0}; - start_datetime.year = start_year - 1; - start_datetime.month = 12; - start_datetime.day = 31; - timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); - furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); -} - -void from_minutes_to_datetime(uint32_t minutes, FuriHalRtcDateTime* datetime, uint16_t start_year) { - uint32_t timestamp = minutes * 60; - FuriHalRtcDateTime start_datetime = {0}; - start_datetime.year = start_year - 1; - start_datetime.month = 12; - start_datetime.day = 31; - timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); - furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); -} - -bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { - uint16_t transport_departament = get_bits_16(block->data, 0, 10); - - FURI_LOG_I(TAG, "Transport departament: %x", transport_departament); - - uint16_t layout_type = get_bits_16(block->data, 52, 4); - if(layout_type == 0xE) { - layout_type = get_bits_16(block->data, 52, 9); - } else if(layout_type == 0xF) { - layout_type = get_bits_16(block->data, 52, 14); - } - - FURI_LOG_I(TAG, "Layout type %x", layout_type); - - uint16_t card_view = 0; - uint16_t card_type = 0; - uint32_t card_number = 0; - uint8_t card_layout = 0; - uint8_t card_layout2 = 0; - uint16_t card_use_before_date = 0; - uint16_t card_blank_type = 0; - uint32_t card_start_trip_minutes = 0; - uint8_t card_minutes_pass = 0; - uint32_t card_remaining_funds = 0; - uint16_t card_validator = 0; - uint8_t card_blocked = 0; - uint32_t card_hash = 0; - - switch(layout_type) { - case 0x02: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_use_before_date = get_bits_16(block->data, 56, 16); //202 - uint8_t card_benefit_code = get_bits(block->data, 72, 8); //124 - uint32_t card_rfu1 = get_bits_32(block->data, 80, 32); //rfu1 - uint16_t card_crc16 = get_bits_16(block->data, 112, 16); //501.1 - card_blocked = get_bits(block->data, 128, 1); //303 - uint16_t card_start_trip_time = get_bits_16(block->data, 177, 12); //403 - uint16_t card_start_trip_date = get_bits_16(block->data, 189, 16); //402 - uint16_t card_valid_from_date = get_bits_16(block->data, 157, 16); //311 - uint16_t card_valid_by_date = get_bits_16(block->data, 173, 16); //312 - uint8_t card_start_trip_seconds = get_bits(block->data, 189, 6); //406 - uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 - uint16_t card_use_with_date = get_bits_16(block->data, 189, 16); //205 - uint8_t card_route = get_bits(block->data, 205, 1); //424 - uint16_t card_validator1 = get_bits_16(block->data, 206, 15); //422.1 - card_validator = get_bits_16(block->data, 205, 16); //422 - uint16_t card_total_trips = get_bits_16(block->data, 221, 16); //331 - uint8_t card_write_enabled = get_bits(block->data, 237, 1); //write_enabled - uint8_t card_rfu2 = get_bits(block->data, 238, 2); //rfu2 - uint16_t card_crc16_2 = get_bits_16(block->data, 240, 16); //501.2 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_use_before_date, - card_benefit_code, - card_rfu1, - card_crc16, - card_blocked, - card_start_trip_time, - card_start_trip_date, - card_valid_from_date, - card_valid_by_date, - card_start_trip_seconds, - card_transport_type1, - card_transport_type2, - card_transport_type3, - card_transport_type4, - card_use_with_date, - card_route, - card_validator1, - card_validator, - card_total_trips, - card_write_enabled, - card_rfu2, - card_crc16_2); - if(card_valid_by_date == 0) { - return false; - } - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); - - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_start_trip_date) * 24 * 60 + card_start_trip_time, - &card_start_trip_minutes_s, - 1992); - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips: %d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_total_trips, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); - break; - } - case 0x06: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_use_before_date = get_bits_16(block->data, 56, 16); //202 - uint8_t card_geozone_a = get_bits(block->data, 72, 4); //GeoZoneA - uint8_t card_geozone_b = get_bits(block->data, 76, 4); //GeoZoneB - card_blank_type = get_bits_16(block->data, 80, 10); //121. - uint16_t card_type_of_extended = get_bits_16(block->data, 90, 10); //122 - uint32_t card_rfu1 = get_bits_16(block->data, 100, 12); //rfu1 - uint16_t card_crc16 = get_bits_16(block->data, 112, 16); //501.1 - card_blocked = get_bits(block->data, 128, 1); //303 - uint16_t card_start_trip_time = get_bits_16(block->data, 129, 12); //403 - uint16_t card_start_trip_date = get_bits_16(block->data, 141, 16); //402 - uint16_t card_valid_from_date = get_bits_16(block->data, 157, 16); //311 - uint16_t card_valid_by_date = get_bits_16(block->data, 173, 16); //312 - uint16_t card_company = get_bits(block->data, 189, 4); //Company - uint8_t card_validator1 = get_bits(block->data, 193, 4); //422.1 - uint16_t card_remaining_trips = get_bits_16(block->data, 197, 10); //321 - uint8_t card_units = get_bits(block->data, 207, 6); //Units - uint16_t card_validator2 = get_bits_16(block->data, 213, 10); //422.2 - uint16_t card_total_trips = get_bits_16(block->data, 223, 16); //331 - uint8_t card_extended = get_bits(block->data, 239, 1); //123 - uint16_t card_crc16_2 = get_bits_16(block->data, 240, 16); //501.2 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %x %x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_use_before_date, - card_geozone_a, - card_geozone_b, - card_blank_type, - card_type_of_extended, - card_rfu1, - card_crc16, - card_blocked, - card_start_trip_time, - card_start_trip_date, - card_valid_from_date, - card_valid_by_date, - card_company, - card_validator1, - card_remaining_trips, - card_units, - card_validator2, - card_total_trips, - card_extended, - card_crc16_2); - card_validator = card_validator1 * 1024 + card_validator2; - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); - - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_start_trip_date) * 24 * 60 + card_start_trip_time, - &card_start_trip_minutes_s, - 1992); - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips left: %d of %d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_remaining_trips, - card_total_trips, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); - break; - } - case 0x08: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_use_before_date = get_bits_16(block->data, 56, 16); //202 - uint64_t card_rfu1 = get_bits_64(block->data, 72, 56); //rfu1 - uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 - uint8_t card_rfu2 = get_bits(block->data, 153, 7); //rfu2 - uint8_t card_remaining_trips1 = get_bits(block->data, 160, 8); //321.1 - uint8_t card_remaining_trips = get_bits(block->data, 168, 8); //321 - uint8_t card_validator1 = get_bits(block->data, 193, 2); //422.1 - uint16_t card_validator = get_bits_16(block->data, 177, 15); //422 - card_hash = get_bits_32(block->data, 192, 32); //502 - uint32_t card_rfu3 = get_bits_32(block->data, 224, 32); //rfu3 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %llx %x %x %x %x %x %x %x %x %lx %x %lx", - card_view, - card_type, - card_number, - card_use_before_date, - card_rfu1, - card_valid_from_date, - card_valid_for_days, - card_requires_activation, - card_rfu2, - card_remaining_trips1, - card_remaining_trips, - card_validator1, - card_validator, - card_hash, - card_valid_from_date, - card_rfu3); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips left: %d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_remaining_trips, - card_validator); - break; - } - case 0x0A: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - uint16_t card_valid_from_date = get_bits_16(block->data, 64, 12); //311 - uint32_t card_valid_for_minutes = get_bits_32(block->data, 76, 19); //314 - uint8_t card_requires_activation = get_bits(block->data, 95, 1); //301 - card_start_trip_minutes = get_bits_32(block->data, 96, 19); //405 - card_minutes_pass = get_bits(block->data, 119, 7); //412 - uint8_t card_transport_type_flag = get_bits(block->data, 126, 2); //421.0 - uint8_t card_remaining_trips = get_bits(block->data, 128, 8); //321 - uint16_t card_validator = get_bits_16(block->data, 136, 16); //422 - uint8_t card_transport_type1 = get_bits(block->data, 152, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 154, 2); //421.2 - uint8_t card_transport_type3 = get_bits(block->data, 156, 2); //421.3 - uint8_t card_transport_type4 = get_bits(block->data, 158, 2); //421.4 - card_hash = get_bits_32(block->data, 192, 32); //502 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %lx %x %lx %x %x %x %x %x %x %x %x %lx", - card_view, - card_type, - card_number, - card_use_before_date, - card_valid_from_date, - card_valid_for_minutes, - card_requires_activation, - card_start_trip_minutes, - card_minutes_pass, - card_transport_type_flag, - card_remaining_trips, - card_validator, - card_transport_type1, - card_transport_type2, - card_transport_type3, - card_transport_type4, - card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); - - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_remaining_trips, - card_validator); - break; - } - case 0x0C: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_use_before_date = get_bits_16(block->data, 56, 16); //202 - uint64_t card_rfu1 = get_bits_64(block->data, 72, 56); //rfu1 - uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 - uint16_t card_rfu2 = get_bits_16(block->data, 153, 13); //rfu2 - uint16_t card_remaining_trips = get_bits_16(block->data, 166, 10); //321 - uint16_t card_validator = get_bits_16(block->data, 176, 16); //422 - card_hash = get_bits_32(block->data, 192, 32); //502 - uint16_t card_start_trip_date = get_bits_16(block->data, 224, 16); //402 - uint16_t card_start_trip_time = get_bits_16(block->data, 240, 11); //403 - uint8_t card_transport_type = get_bits(block->data, 251, 2); //421 - uint8_t card_rfu3 = get_bits(block->data, 253, 2); //rfu3 - uint8_t card_transfer_in_metro = get_bits(block->data, 255, 1); //432 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %llx %x %x %x %x %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_use_before_date, - card_rfu1, - card_valid_from_date, - card_valid_for_days, - card_requires_activation, - card_rfu2, - card_remaining_trips, - card_validator, - card_start_trip_date, - card_start_trip_time, - card_transport_type, - card_rfu3, - card_transfer_in_metro); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_start_trip_date) * 24 * 60 + card_start_trip_time, - &card_start_trip_minutes_s, - 1992); - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_remaining_trips, - card_validator); - break; - } - case 0x0D: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - uint8_t card_rfu1 = get_bits(block->data, 56, 8); //rfu1 - card_use_before_date = get_bits_16(block->data, 64, 16); //202 - uint16_t card_valid_for_time = get_bits_16(block->data, 80, 11); //316 - uint8_t card_rfu2 = get_bits(block->data, 91, 5); //rfu2 - uint16_t card_use_before_date2 = get_bits_16(block->data, 96, 16); //202.2 - uint16_t card_valid_for_time2 = get_bits_16(block->data, 123, 11); //316.2 - uint8_t card_rfu3 = get_bits(block->data, 123, 5); //rfu3 - uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 - uint8_t card_rfu4 = get_bits(block->data, 153, 2); //rfu4 - uint8_t card_passage_5_minutes = get_bits(block->data, 155, 5); //413 - uint8_t card_transport_type1 = get_bits(block->data, 160, 2); //421.1 - uint8_t card_passage_in_metro = get_bits(block->data, 162, 1); //431 - uint8_t card_passages_ground_transport = get_bits(block->data, 163, 3); //433 - uint16_t card_remaining_trips = get_bits_16(block->data, 166, 10); //321 - uint16_t card_validator = get_bits_16(block->data, 176, 16); //422 - card_hash = get_bits_32(block->data, 192, 32); //502 - uint16_t card_start_trip_date = get_bits_16(block->data, 224, 16); //402 - uint16_t card_start_trip_time = get_bits_16(block->data, 240, 11); //403 - uint8_t card_transport_type2 = get_bits(block->data, 251, 2); //421.2 - uint8_t card_rfu5 = get_bits(block->data, 253, 2); //rfu5 - uint8_t card_transfer_in_metro = get_bits(block->data, 255, 1); //432 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_layout, - card_rfu1, - card_use_before_date, - card_valid_for_time, - card_rfu2, - card_use_before_date2, - card_valid_for_time2, - card_rfu3, - card_valid_from_date, - card_valid_for_days, - card_requires_activation, - card_rfu4, - card_passage_5_minutes, - card_transport_type1, - card_passage_in_metro, - card_passages_ground_transport, - card_remaining_trips, - card_validator, - card_start_trip_date, - card_start_trip_time, - card_transport_type2, - card_rfu5, - card_transfer_in_metro); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_start_trip_date) * 24 * 60 + card_start_trip_time, - &card_start_trip_minutes_s, - 1992); - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_remaining_trips, - card_validator); - break; - } - case 0x1C1: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - card_use_before_date = get_bits_16(block->data, 61, 16); //202. - card_blank_type = get_bits_16(block->data, 77, 10); //121. - card_validator = get_bits_16(block->data, 128, 16); //422 - uint16_t card_start_trip_date = get_bits_16(block->data, 144, 16); //402 - uint16_t card_start_trip_time = get_bits_16(block->data, 160, 11); //403 - uint8_t card_transport_type1 = get_bits(block->data, 171, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 173, 2); //421.2 - uint8_t card_transfer_in_metro = get_bits(block->data, 177, 1); //432 - uint8_t card_passage_in_metro = get_bits(block->data, 178, 1); //431 - uint8_t card_passages_ground_transport = get_bits(block->data, 179, 3); //433 - card_minutes_pass = get_bits(block->data, 185, 8); //412. - card_remaining_funds = get_bits_32(block->data, 196, 19) / 100; //322 - uint8_t card_fare_trip = get_bits(block->data, 215, 2); //441 - card_blocked = get_bits(block->data, 202, 1); //303 - uint8_t card_zoo = get_bits(block->data, 218, 1); //zoo - card_hash = get_bits_32(block->data, 224, 32); //502 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %lx %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_use_before_date, - card_blank_type, - card_validator, - card_start_trip_date, - card_start_trip_time, - card_transport_type1, - card_transport_type2, - card_transfer_in_metro, - card_passage_in_metro, - card_passages_ground_transport, - card_minutes_pass, - card_remaining_funds, - card_fare_trip, - card_blocked, - card_zoo, - card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 1992); - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); - break; - } - case 0x1C2: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 - card_use_before_date = get_bits_16(block->data, 71, 16); //202. - card_blank_type = get_bits_16(block->data, 87, 10); //121. - uint16_t card_valid_to_date = get_bits_16(block->data, 97, 16); //311 - uint16_t card_activate_during = get_bits_16(block->data, 113, 9); //302 - uint32_t card_valid_for_minutes = get_bits_32(block->data, 131, 20); //314 - card_minutes_pass = get_bits(block->data, 154, 8); //412. - uint8_t card_transport_type = get_bits(block->data, 163, 2); //421 - uint8_t card_passage_in_metro = get_bits(block->data, 165, 1); //431 - uint8_t card_transfer_in_metro = get_bits(block->data, 166, 1); //432 - uint16_t card_remaining_trips = get_bits_16(block->data, 167, 10); //321 - card_validator = get_bits_16(block->data, 177, 16); //422 - uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 196, 20); //404 - uint8_t card_requires_activation = get_bits(block->data, 216, 1); //301 - card_blocked = get_bits(block->data, 217, 1); //303 - uint8_t card_extended = get_bits(block->data, 218, 1); //123 - card_hash = get_bits_32(block->data, 224, 32); //502 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %x %x %x %x %x %lx %x %x %x %x %x %x %lx %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_type_of_extended, - card_use_before_date, - card_blank_type, - card_valid_to_date, - card_activate_during, - card_valid_for_minutes, - card_minutes_pass, - card_transport_type, - card_passage_in_metro, - card_transfer_in_metro, - card_remaining_trips, - card_validator, - card_start_trip_neg_minutes, - card_requires_activation, - card_blocked, - card_extended, - card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); - - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_valid_to_date) * 24 * 60 + card_valid_for_minutes - card_start_trip_neg_minutes, - &card_start_trip_minutes_s, - 2016); //-time - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); - break; - } - case 0x1C3: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - card_use_before_date = get_bits_16(block->data, 61, 16); //202 - card_blank_type = get_bits_16(block->data, 77, 10); //121 - card_remaining_funds = get_bits_32(block->data, 188, 22) / 100; //322 - card_hash = get_bits_32(block->data, 224, 32); //502 - card_validator = get_bits_16(block->data, 128, 16); //422 - card_start_trip_minutes = get_bits_32(block->data, 144, 23); //405 - uint8_t card_fare_trip = get_bits(block->data, 210, 2); //441 - card_minutes_pass = get_bits(block->data, 171, 7); //412 - uint8_t card_transport_type_flag = get_bits(block->data, 178, 2); //421.0 - uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 - card_blocked = get_bits(block->data, 212, 1); //303 - FURI_LOG_D( - TAG, - "Card view: %x, type: %x, number: %lx, layout: %x, layout2: %x, use before date: %x, blank type: %x, remaining funds: %lx, hash: %lx, validator: %x, start trip minutes: %lx, fare trip: %x, minutes pass: %x, transport type flag: %x, transport type1: %x, transport type2: %x, transport type3: %x, transport type4: %x, blocked: %x", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_use_before_date, - card_blank_type, - card_remaining_funds, - card_hash, - card_validator, - card_start_trip_minutes, - card_fare_trip, - card_minutes_pass, - card_transport_type_flag, - card_transport_type1, - card_transport_type2, - card_transport_type3, - card_transport_type4, - card_blocked); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nBalance: %ld rub\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_remaining_funds, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); - break; - } - case 0x1C4: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 - card_use_before_date = get_bits_16(block->data, 71, 13); //202. - card_blank_type = get_bits_16(block->data, 84, 10); //121. - uint16_t card_valid_to_date = get_bits_16(block->data, 94, 13); //311 - uint16_t card_activate_during = get_bits_16(block->data, 107, 9); //302 - uint16_t card_extension_counter = get_bits_16(block->data, 116, 10); //304 - uint32_t card_valid_for_minutes = get_bits_32(block->data, 128, 20); //314 - card_minutes_pass = get_bits(block->data, 158, 7); //412. - uint8_t card_transport_type_flag = get_bits(block->data, 178, 2); //421.0 - uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 - uint16_t card_remaining_trips = get_bits_16(block->data, 169, 10); //321 - card_validator = get_bits_16(block->data, 179, 16); //422 - uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 195, 20); //404 - uint8_t card_requires_activation = get_bits(block->data, 215, 1); //301 - card_blocked = get_bits(block->data, 216, 1); //303 - uint8_t card_extended = get_bits(block->data, 217, 1); //123 - card_hash = get_bits_32(block->data, 224, 32); //502 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %x %x %x %x %x %x %lx %x %x %x %x %x %x %x %x %lx %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_type_of_extended, - card_use_before_date, - card_blank_type, - card_valid_to_date, - card_activate_during, - card_extension_counter, - card_valid_for_minutes, - card_minutes_pass, - card_transport_type_flag, - card_transport_type1, - card_transport_type2, - card_transport_type3, - card_transport_type4, - card_remaining_trips, - card_validator, - card_start_trip_neg_minutes, - card_requires_activation, - card_blocked, - card_extended, - card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); - - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_use_before_date + 1) * 24 * 60 + card_valid_for_minutes - - card_start_trip_neg_minutes, - &card_start_trip_minutes_s, - 2011); //-time - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); - break; - } - case 0x1C5: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - card_use_before_date = get_bits_16(block->data, 61, 13); //202. - card_blank_type = get_bits_16(block->data, 74, 10); //121. - uint32_t card_valid_to_time = get_bits_32(block->data, 84, 23); //317 - uint16_t card_extension_counter = get_bits_16(block->data, 107, 10); //304 - card_start_trip_minutes = get_bits_32(block->data, 128, 23); //405 - uint8_t card_metro_ride_with = get_bits(block->data, 151, 7); //414 - card_minutes_pass = get_bits(block->data, 158, 7); //412. - card_remaining_funds = get_bits_32(block->data, 167, 19) / 100; //322 - card_validator = get_bits_16(block->data, 186, 16); //422 - card_blocked = get_bits(block->data, 202, 1); //303 - uint16_t card_route = get_bits_16(block->data, 204, 12); //424 - uint8_t card_passages_ground_transport = get_bits(block->data, 216, 7); //433 - card_hash = get_bits_32(block->data, 224, 32); //502 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %x %x %lx %x %lx %x %x %lx %x %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_use_before_date, - card_blank_type, - card_valid_to_time, - card_extension_counter, - card_start_trip_minutes, - card_metro_ride_with, - card_minutes_pass, - card_remaining_funds, - card_validator, - card_blocked, - card_route, - card_passages_ground_transport, - card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; - - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); - - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2019); - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nBalance: %ld rub\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_remaining_funds, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); - break; - } - case 0x1C6: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 - card_use_before_date = get_bits_16(block->data, 71, 13); //202. - card_blank_type = get_bits_16(block->data, 84, 10); //121. - uint32_t card_valid_from_date = get_bits_32(block->data, 94, 23); //311 - uint16_t card_extension_counter = get_bits_16(block->data, 117, 10); //304 - uint32_t card_valid_for_minutes = get_bits_32(block->data, 128, 20); //314 - uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 148, 20); //404 - uint8_t card_metro_ride_with = get_bits(block->data, 168, 7); //414 - card_minutes_pass = get_bits(block->data, 175, 7); //412. - uint16_t card_remaining_trips = get_bits_16(block->data, 182, 7); //321 - card_validator = get_bits_16(block->data, 189, 16); //422 - card_blocked = get_bits(block->data, 205, 1); //303 - uint8_t card_extended = get_bits(block->data, 206, 1); //123 - uint16_t card_route = get_bits_16(block->data, 212, 12); //424 - card_hash = get_bits_32(block->data, 224, 32); //502 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %x %x %x %lx %x %lx %lx %x %x %x %x %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_type_of_extended, - card_use_before_date, - card_blank_type, - card_valid_from_date, - card_extension_counter, - card_valid_for_minutes, - card_start_trip_neg_minutes, - card_metro_ride_with, - card_minutes_pass, - card_remaining_trips, - card_validator, - card_blocked, - card_extended, - card_route, - card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); - - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - card_valid_from_date + card_valid_for_minutes - card_start_trip_neg_minutes, - &card_start_trip_minutes_s, - 2019); //-time - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); - break; - } - case 0x3CCB: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - uint16_t card_tech_code = get_bits_32(block->data, 56, 10); //tech_code - uint16_t card_valid_to_minutes = get_bits_16(block->data, 66, 16); //311 - uint16_t card_valid_by_date = get_bits_16(block->data, 82, 16); //312 - uint8_t card_interval = get_bits(block->data, 98, 4); //interval - uint16_t card_app_code1 = get_bits_16(block->data, 102, 16); //app_code1 - uint16_t card_hash1 = get_bits_16(block->data, 112, 16); //502.1 - uint16_t card_type1 = get_bits_16(block->data, 128, 10); //type1 - uint16_t card_app_code2 = get_bits_16(block->data, 138, 10); //app_code2 - uint16_t card_type2 = get_bits_16(block->data, 148, 10); //type2 - uint16_t card_app_code3 = get_bits_16(block->data, 158, 10); //app_code3 - uint16_t card_type3 = get_bits_16(block->data, 148, 10); //type3 - uint16_t card_app_code4 = get_bits_16(block->data, 168, 10); //app_code4 - uint16_t card_type4 = get_bits_16(block->data, 178, 10); //type4 - card_hash = get_bits_32(block->data, 224, 32); //502.2 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_tech_code, - card_use_before_date, - card_blank_type, - card_valid_to_minutes, - card_valid_by_date, - card_interval, - card_app_code1, - card_hash1, - card_type1, - card_app_code2, - card_type2, - card_app_code3, - card_type3, - card_app_code4, - card_type4, - card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); - - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_validator); - break; - } - case 0x3C0B: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - uint16_t card_tech_code = get_bits_32(block->data, 56, 10); //tech_code - uint16_t card_valid_to_minutes = get_bits_16(block->data, 66, 16); //311 - uint16_t card_valid_by_date = get_bits_16(block->data, 82, 16); //312 - uint16_t card_hash = get_bits_16(block->data, 112, 16); //502.1 - - FURI_LOG_D( - TAG, - "%x %x %lx %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_layout, - card_tech_code, - card_use_before_date, - card_blank_type, - card_valid_to_minutes, - card_valid_by_date, - card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); - - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_validator); - break; - } - default: - return false; - } - - return true; -} - static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) { bool success = true; From de991f3199b966db427142c9ea1d0e6ae050f0fa Mon Sep 17 00:00:00 2001 From: assasinfil Date: Thu, 15 Feb 2024 11:37:32 +0300 Subject: [PATCH 04/39] Bitlib refactor --- .../main/nfc/helpers/mosgortrans_layouts_i.c | 410 ------------------ .../main/nfc/helpers/mosgortrans_layouts_i.h | 1 + 2 files changed, 1 insertion(+), 410 deletions(-) diff --git a/applications/main/nfc/helpers/mosgortrans_layouts_i.c b/applications/main/nfc/helpers/mosgortrans_layouts_i.c index 11fa9643bad..46d22db65c2 100644 --- a/applications/main/nfc/helpers/mosgortrans_layouts_i.c +++ b/applications/main/nfc/helpers/mosgortrans_layouts_i.c @@ -1,415 +1,5 @@ #include "mosgortrans_layouts_i.h" -#define TOPBIT(X) (1 << ((X)-1)) - -typedef enum { - BitLibParityEven, - BitLibParityOdd, - BitLibParityAlways0, - BitLibParityAlways1, -} BitLibParity; - -typedef struct { - const char mark; - const size_t start; - const size_t length; -} BitLibRegion; - -void push_bit(uint8_t* data, size_t data_size, bool bit) { - size_t last_index = data_size - 1; - - for(size_t i = 0; i < last_index; ++i) { - data[i] = (data[i] << 1) | ((data[i + 1] >> 7) & 1); - } - data[last_index] = (data[last_index] << 1) | bit; -} - -void set_bit(uint8_t* data, size_t position, bool bit) { - if(bit) { - data[position / 8] |= 1UL << (7 - (position % 8)); - } else { - data[position / 8] &= ~(1UL << (7 - (position % 8))); - } -} - -void set_bits(uint8_t* data, size_t position, uint8_t byte, uint8_t length) { - furi_check(length <= 8); - furi_check(length > 0); - - for(uint8_t i = 0; i < length; ++i) { - uint8_t shift = (length - 1) - i; - set_bit(data, position + i, (byte >> shift) & 1); //-V610 - } -} - -bool get_bit(const uint8_t* data, size_t position) { - return (data[position / 8] >> (7 - (position % 8))) & 1; -} - -uint8_t get_bits(const uint8_t* data, size_t position, uint8_t length) { - uint8_t shift = position % 8; - if(shift == 0) { - return data[position / 8] >> (8 - length); - } else { - // TODO fix read out of bounds - uint8_t value = (data[position / 8] << (shift)); - value |= data[position / 8 + 1] >> (8 - shift); - value = value >> (8 - length); - return value; - } -} - -uint16_t get_bits_16(const uint8_t* data, size_t position, uint8_t length) { - uint16_t value = 0; - if(length <= 8) { - value = get_bits(data, position, length); - } else { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, length - 8); - } - return value; -} - -uint32_t get_bits_32(const uint8_t* data, size_t position, uint8_t length) { - uint32_t value = 0; - if(length <= 8) { - value = get_bits(data, position, length); - } else if(length <= 16) { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, length - 8); - } else if(length <= 24) { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, 8) << (length - 16); - value |= get_bits(data, position + 16, length - 16); - } else { - value = (uint32_t)get_bits(data, position, 8) << (length - 8); - value |= (uint32_t)get_bits(data, position + 8, 8) << (length - 16); - value |= (uint32_t)get_bits(data, position + 16, 8) << (length - 24); - value |= get_bits(data, position + 24, length - 24); - } - - return value; -} - -uint64_t get_bits_64(const uint8_t* data, size_t position, uint8_t length) { - uint64_t value = 0; - if(length <= 8) { - value = get_bits(data, position, length); - } else if(length <= 16) { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, length - 8); - } else if(length <= 24) { - value = get_bits(data, position, 8) << (length - 8); - value |= get_bits(data, position + 8, 8) << (length - 16); - value |= get_bits(data, position + 16, length - 16); - } else if(length <= 32) { - value = (uint64_t)get_bits(data, position, 8) << (length - 8); - value |= (uint64_t)get_bits(data, position + 8, 8) << (length - 16); - value |= (uint64_t)get_bits(data, position + 16, 8) << (length - 24); - value |= get_bits(data, position + 24, length - 24); - } else { - value = (uint64_t)get_bits(data, position, 8) << (length - 8); - value |= (uint64_t)get_bits(data, position + 8, 8) << (length - 16); - value |= (uint64_t)get_bits(data, position + 16, 8) << (length - 24); - value |= (uint64_t)get_bits(data, position + 24, 8) << (length - 32); - value |= (uint64_t)get_bits(data, position + 32, 8) << (length - 40); - value |= (uint64_t)get_bits(data, position + 40, 8) << (length - 48); - value |= (uint64_t)get_bits(data, position + 48, 8) << (length - 56); - value |= (uint64_t)get_bits(data, position + 56, 8) << (length - 64); - value |= get_bits(data, position + 64, length - 64); - } - - return value; -} - -bool test_parity_32(uint32_t bits, BitLibParity parity) { -#if !defined __GNUC__ -#error Please, implement parity test for non-GCC compilers -#else - switch(parity) { - case BitLibParityEven: - return __builtin_parity(bits); - case BitLibParityOdd: - return !__builtin_parity(bits); - default: - furi_crash("Unknown parity"); - } -#endif -} - -bool bit_lib_test_parity( - const uint8_t* bits, - size_t position, - uint8_t length, - BitLibParity parity, - uint8_t parity_length) { - uint32_t parity_block; - bool result = true; - const size_t parity_blocks_count = length / parity_length; - - for(size_t i = 0; i < parity_blocks_count; ++i) { - switch(parity) { - case BitLibParityEven: - case BitLibParityOdd: - parity_block = get_bits_32(bits, position + i * parity_length, parity_length); - if(!test_parity_32(parity_block, parity)) { - result = false; - } - break; - case BitLibParityAlways0: - if(get_bit(bits, position + i * parity_length + parity_length - 1)) { - result = false; - } - break; - case BitLibParityAlways1: - if(!get_bit(bits, position + i * parity_length + parity_length - 1)) { - result = false; - } - break; - } - - if(!result) break; - } - return result; -} - -size_t bit_lib_add_parity( - const uint8_t* data, - size_t position, - uint8_t* dest, - size_t dest_position, - uint8_t source_length, - uint8_t parity_length, - BitLibParity parity) { - uint32_t parity_word = 0; - size_t j = 0, bit_count = 0; - for(int word = 0; word < source_length; word += parity_length - 1) { - for(int bit = 0; bit < parity_length - 1; bit++) { - parity_word = (parity_word << 1) | get_bit(data, position + word + bit); - set_bit( - dest, dest_position + j++, get_bit(data, position + word + bit)); - } - // if parity fails then return 0 - switch(parity) { - case BitLibParityAlways0: - set_bit(dest, dest_position + j++, 0); - break; // marker bit which should be a 0 - case BitLibParityAlways1: - set_bit(dest, dest_position + j++, 1); - break; // marker bit which should be a 1 - default: - set_bit( - dest, - dest_position + j++, - (test_parity_32(parity_word, BitLibParityOdd) ^ parity) ^ 1); - break; - } - bit_count += parity_length; - parity_word = 0; - } - // if we got here then all the parities passed - // return bit count - return bit_count; -} - -size_t bit_lib_remove_bit_every_nth(uint8_t* data, size_t position, uint8_t length, uint8_t n) { - size_t counter = 0; - size_t result_counter = 0; - uint8_t bit_buffer = 0; - uint8_t bit_counter = 0; - - while(counter < length) { - if((counter + 1) % n != 0) { - bit_buffer = (bit_buffer << 1) | get_bit(data, position + counter); - bit_counter++; - } - - if(bit_counter == 8) { - set_bits(data, position + result_counter, bit_buffer, 8); - bit_counter = 0; - bit_buffer = 0; - result_counter += 8; - } - counter++; - } - - if(bit_counter != 0) { - set_bits(data, position + result_counter, bit_buffer, bit_counter); - result_counter += bit_counter; - } - return result_counter; -} - -void bit_lib_copy_bits( - uint8_t* data, - size_t position, - size_t length, - const uint8_t* source, - size_t source_position) { - for(size_t i = 0; i < length; ++i) { - set_bit(data, position + i, get_bit(source, source_position + i)); - } -} - -void bit_lib_reverse_bits(uint8_t* data, size_t position, uint8_t length) { - size_t i = 0; - size_t j = length - 1; - - while(i < j) { - bool tmp = get_bit(data, position + i); - set_bit(data, position + i, get_bit(data, position + j)); - set_bit(data, position + j, tmp); - i++; - j--; - } -} - -uint8_t get_bit_count(uint32_t data) { -#if defined __GNUC__ - return __builtin_popcountl(data); -#else -#error Please, implement popcount for non-GCC compilers -#endif -} - -void bit_lib_print_bits(const uint8_t* data, size_t length) { - for(size_t i = 0; i < length; ++i) { - printf("%u", get_bit(data, i)); - } -} - -void bit_lib_print_regions( - const BitLibRegion* regions, - size_t region_count, - const uint8_t* data, - size_t length) { - // print data - bit_lib_print_bits(data, length); - printf("\r\n"); - - // print regions - for(size_t c = 0; c < length; ++c) { - bool print = false; - - for(size_t i = 0; i < region_count; i++) { - if(regions[i].start <= c && c < regions[i].start + regions[i].length) { - print = true; - printf("%c", regions[i].mark); - break; - } - } - - if(!print) { - printf(" "); - } - } - printf("\r\n"); - - // print regions data - for(size_t c = 0; c < length; ++c) { - bool print = false; - - for(size_t i = 0; i < region_count; i++) { - if(regions[i].start <= c && c < regions[i].start + regions[i].length) { - print = true; - printf("%u", get_bit(data, c)); - break; - } - } - - if(!print) { - printf(" "); - } - } - printf("\r\n"); -} - -uint16_t bit_lib_reverse_16_fast(uint16_t data) { - uint16_t result = 0; - result |= (data & 0x8000) >> 15; - result |= (data & 0x4000) >> 13; - result |= (data & 0x2000) >> 11; - result |= (data & 0x1000) >> 9; - result |= (data & 0x0800) >> 7; - result |= (data & 0x0400) >> 5; - result |= (data & 0x0200) >> 3; - result |= (data & 0x0100) >> 1; - result |= (data & 0x0080) << 1; - result |= (data & 0x0040) << 3; - result |= (data & 0x0020) << 5; - result |= (data & 0x0010) << 7; - result |= (data & 0x0008) << 9; - result |= (data & 0x0004) << 11; - result |= (data & 0x0002) << 13; - result |= (data & 0x0001) << 15; - return result; -} - -uint8_t bit_lib_reverse_8_fast(uint8_t byte) { - byte = (byte & 0xF0) >> 4 | (byte & 0x0F) << 4; - byte = (byte & 0xCC) >> 2 | (byte & 0x33) << 2; - byte = (byte & 0xAA) >> 1 | (byte & 0x55) << 1; - return byte; -} - -uint16_t bit_lib_crc8( - uint8_t const* data, - size_t data_size, - uint8_t polynom, - uint8_t init, - bool ref_in, - bool ref_out, - uint8_t xor_out) { - uint8_t crc = init; - - for(size_t i = 0; i < data_size; ++i) { - uint8_t byte = data[i]; - if(ref_in) bit_lib_reverse_bits(&byte, 0, 8); - crc ^= byte; - - for(size_t j = 8; j > 0; --j) { - if(crc & TOPBIT(8)) { - crc = (crc << 1) ^ polynom; - } else { - crc = (crc << 1); - } - } - } - - if(ref_out) bit_lib_reverse_bits(&crc, 0, 8); - crc ^= xor_out; - - return crc; -} - -uint16_t crc16( - uint8_t const* data, - size_t data_size, - uint16_t polynom, - uint16_t init, - bool ref_in, - bool ref_out, - uint16_t xor_out) { - uint16_t crc = init; - - for(size_t i = 0; i < data_size; ++i) { - uint8_t byte = data[i]; - if(ref_in) byte = bit_lib_reverse_16_fast(byte) >> 8; - - for(size_t j = 0; j < 8; ++j) { - bool c15 = (crc >> 15 & 1); - bool bit = (byte >> (7 - j) & 1); - crc <<= 1; - if(c15 ^ bit) crc ^= polynom; - } - } - - if(ref_out) crc = bit_lib_reverse_16_fast(crc); - crc ^= xor_out; - - return crc; -} - void from_days_to_datetime(uint16_t days, FuriHalRtcDateTime* datetime, uint16_t start_year) { uint32_t timestamp = days * 24 * 60 * 60; FuriHalRtcDateTime start_datetime = {0}; diff --git a/applications/main/nfc/helpers/mosgortrans_layouts_i.h b/applications/main/nfc/helpers/mosgortrans_layouts_i.h index 820b622558e..5595164061f 100644 --- a/applications/main/nfc/helpers/mosgortrans_layouts_i.h +++ b/applications/main/nfc/helpers/mosgortrans_layouts_i.h @@ -4,6 +4,7 @@ #include #include #include +#include #define TAG2 "Mosgortrans" From 029d86d345c960bf1cf92d3478c3522a4f1a11df Mon Sep 17 00:00:00 2001 From: assasinfil Date: Thu, 15 Feb 2024 11:49:40 +0300 Subject: [PATCH 05/39] Moved to API --- .../mosgortrans/mosgortrans_util.c} | 62 +++++++++---------- .../mosgortrans/mosgortrans_util.h} | 3 +- 2 files changed, 33 insertions(+), 32 deletions(-) rename applications/main/nfc/{helpers/mosgortrans_layouts_i.c => api/mosgortrans/mosgortrans_util.c} (95%) rename applications/main/nfc/{helpers/mosgortrans_layouts_i.h => api/mosgortrans/mosgortrans_util.h} (65%) diff --git a/applications/main/nfc/helpers/mosgortrans_layouts_i.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c similarity index 95% rename from applications/main/nfc/helpers/mosgortrans_layouts_i.c rename to applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 46d22db65c2..1ddfad7683b 100644 --- a/applications/main/nfc/helpers/mosgortrans_layouts_i.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -1,8 +1,8 @@ -#include "mosgortrans_layouts_i.h" +#include "mosgortrans_util.h" -void from_days_to_datetime(uint16_t days, FuriHalRtcDateTime* datetime, uint16_t start_year) { +void from_days_to_datetime(uint16_t days, DateTime* datetime, uint16_t start_year) { uint32_t timestamp = days * 24 * 60 * 60; - FuriHalRtcDateTime start_datetime = {0}; + DateTime start_datetime = {0}; start_datetime.year = start_year - 1; start_datetime.month = 12; start_datetime.day = 31; @@ -10,9 +10,9 @@ void from_days_to_datetime(uint16_t days, FuriHalRtcDateTime* datetime, uint16_t furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); } -void from_minutes_to_datetime(uint32_t minutes, FuriHalRtcDateTime* datetime, uint16_t start_year) { +void from_minutes_to_datetime(uint32_t minutes, DateTime* datetime, uint16_t start_year) { uint32_t timestamp = minutes * 60; - FuriHalRtcDateTime start_datetime = {0}; + DateTime start_datetime = {0}; start_datetime.year = start_year - 1; start_datetime.month = 12; start_datetime.day = 31; @@ -20,7 +20,7 @@ void from_minutes_to_datetime(uint32_t minutes, FuriHalRtcDateTime* datetime, ui furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); } -bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { +bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result) { uint16_t transport_departament = get_bits_16(block->data, 0, 10); FURI_LOG_I(TAG2, "Transport departament: %x", transport_departament); @@ -108,10 +108,10 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { if(card_valid_by_date == 0) { return false; } - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( (card_start_trip_date) * 24 * 60 + card_start_trip_time, &card_start_trip_minutes_s, @@ -185,10 +185,10 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_extended, card_crc16_2); card_validator = card_validator1 * 1024 + card_validator2; - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( (card_start_trip_date) * 24 * 60 + card_start_trip_time, &card_start_trip_minutes_s, @@ -247,7 +247,7 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_hash, card_valid_from_date, card_rfu3); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); furi_string_printf( @@ -300,10 +300,10 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_transport_type3, card_transport_type4, card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); furi_string_printf( result, @@ -360,9 +360,9 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_transport_type, card_rfu3, card_transfer_in_metro); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( (card_start_trip_date) * 24 * 60 + card_start_trip_time, &card_start_trip_minutes_s, @@ -441,9 +441,9 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_transport_type2, card_rfu5, card_transfer_in_metro); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( (card_start_trip_date) * 24 * 60 + card_start_trip_time, &card_start_trip_minutes_s, @@ -511,10 +511,10 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_blocked, card_zoo, card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 1992); furi_string_printf( result, @@ -580,10 +580,10 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_blocked, card_extended, card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( (card_valid_to_date) * 24 * 60 + card_valid_for_minutes - card_start_trip_neg_minutes, &card_start_trip_minutes_s, @@ -645,10 +645,10 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_transport_type3, card_transport_type4, card_blocked); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); furi_string_printf( result, @@ -721,10 +721,10 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_blocked, card_extended, card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( (card_use_before_date + 1) * 24 * 60 + card_valid_for_minutes - card_start_trip_neg_minutes, @@ -786,11 +786,11 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_route, card_passages_ground_transport, card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2019); furi_string_printf( result, @@ -853,10 +853,10 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_extended, card_route, card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); - FuriHalRtcDateTime card_start_trip_minutes_s = {0}; + DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( card_valid_from_date + card_valid_for_minutes - card_start_trip_neg_minutes, &card_start_trip_minutes_s, @@ -919,7 +919,7 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_app_code4, card_type4, card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); furi_string_printf( @@ -955,7 +955,7 @@ bool parse_transport_block(const MfClassicBlock* block, FuriString* result) { card_valid_to_minutes, card_valid_by_date, card_hash); - FuriHalRtcDateTime card_use_before_date_s = {0}; + DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); furi_string_printf( diff --git a/applications/main/nfc/helpers/mosgortrans_layouts_i.h b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h similarity index 65% rename from applications/main/nfc/helpers/mosgortrans_layouts_i.h rename to applications/main/nfc/api/mosgortrans/mosgortrans_util.h index 5595164061f..413729ce8ef 100644 --- a/applications/main/nfc/helpers/mosgortrans_layouts_i.h +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h @@ -5,7 +5,8 @@ #include #include #include +#include #define TAG2 "Mosgortrans" -bool parse_transport_block(const MfClassicBlock* block, FuriString* result); \ No newline at end of file +bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result); \ No newline at end of file From 2be5da0bf850c6ab4723d32daa6e0cbed476e215 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Thu, 15 Feb 2024 12:02:15 +0300 Subject: [PATCH 06/39] Rollback troyka parser --- .../main/nfc/plugins/supported_cards/troika.c | 179 +++--------------- 1 file changed, 22 insertions(+), 157 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index 799f8306d62..f18b503ce5d 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -6,6 +6,7 @@ #include #include #include +#include "../../api/mosgortrans/mosgortrans_util.h" #include "furi_hal_rtc.h" #define TAG "Troika" @@ -21,19 +22,6 @@ typedef struct { uint32_t data_sector; } TroikaCardConfig; -typedef enum { - TroikaLayoutUnknown = 0x0, - TroikaLayout2 = 0x2, - TroikaLayoutE = 0xE, -} TroikaLayout; - -typedef enum { - TroikaSublayoutUnknown = 0x0, - TroikaSublayout3 = 0x3, - TroikaSublayout5 = 0x5, - TroikaSublayout6 = 0x6, -} TroikaSubLayout; - static const MfClassicKeyPair troika_1k_keys[] = { {.s = 0, .a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58}, {.s = 1, .a = 0xa82607b01c0d, .b = 0x2910989b6880}, @@ -112,126 +100,6 @@ static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) return success; } -static TroikaLayout troika_get_layout(const MfClassicData* data, uint8_t start_block_num) { - furi_assert(data); - - // Layout is stored in byte 6 of block, length 4 bits (bits 52 - 55), second nibble. - const uint8_t* layout_ptr = &data->block[start_block_num].data[6]; - const uint8_t layout = (*layout_ptr & 0x0F); - - TroikaLayout result = TroikaLayoutUnknown; - switch(layout) { - case TroikaLayout2: - case TroikaLayoutE: - result = layout; - break; - default: - // If debug is enabled - pass the actual layout value for the debug text - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - return layout; - } else { - return TroikaLayoutUnknown; - } - } - - return result; -} - -static TroikaSubLayout troika_get_sub_layout(const MfClassicData* data, uint8_t start_block_num) { - furi_assert(data); - - // Sublayout is stored in byte 7 (bits 56 - 60) of block, length 5 bits (first nibble and one bit from second nibble) - const uint8_t* sub_layout_ptr = &data->block[start_block_num].data[7]; - const uint8_t sub_layout = (*sub_layout_ptr & 0x3F) >> 3; - - TroikaSubLayout result = TroikaSublayoutUnknown; - switch(sub_layout) { - case TroikaSublayout3: - case TroikaSublayout5: - case TroikaSublayout6: - result = sub_layout; - break; - default: - // If debug is enabled - pass the actual sublayout value for the debug text - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - return sub_layout; - } else { - return TroikaSublayoutUnknown; - } - } - - return result; -} - -static bool troika_has_balance(TroikaLayout layout, TroikaSubLayout sub_layout) { - UNUSED(sub_layout); - // Layout 0x2 has no balance - - if(layout == TroikaLayout2) { - return false; - } - - return true; -} - -static uint16_t troika_get_balance( - const MfClassicData* data, - uint8_t start_block_num, - TroikaLayout layout, - TroikaSubLayout sub_layout) { - furi_assert(data); - - // In layout 0x3 balance in bits 188:209 ( from sector start, length 22). - // In layout 0x5 balance in bits 165:185 ( from sector start, length 20). - - uint32_t balance = 0; - uint8_t balance_data_offset = 0; - bool supported_layout = false; - - if(layout == TroikaLayoutE && sub_layout == TroikaSublayout3) { - balance_data_offset = 7; - supported_layout = true; - } else if(layout == TroikaLayoutE && sub_layout == TroikaSublayout5) { - balance_data_offset = 4; - supported_layout = true; - } - - if(supported_layout) { - const uint8_t* temp_ptr = &data->block[start_block_num + 1].data[balance_data_offset]; - balance |= (temp_ptr[0] & 0x3) << 18; - balance |= temp_ptr[1] << 10; - balance |= temp_ptr[2] << 2; - balance |= (temp_ptr[3] & 0xC0) >> 6; - } - - return balance / 100; -} - -static uint32_t troika_get_number( - const MfClassicData* data, - uint8_t start_block_num, - TroikaLayout layout, - TroikaSubLayout sub_layout) { - furi_assert(data); - UNUSED(sub_layout); - - if(layout == TroikaLayoutE || layout == TroikaLayout2) { - const uint8_t* temp_ptr = &data->block[start_block_num].data[2]; - - uint32_t number = 0; - for(size_t i = 1; i < 5; i++) { - number <<= 8; - number |= temp_ptr[i]; - } - number >>= 4; - number |= (temp_ptr[0] & 0xf) << 28; - - return number; - } else { - return 0; - } -} - static bool troika_verify_type(Nfc* nfc, MfClassicType type) { bool verified = false; @@ -331,37 +199,34 @@ static bool troika_parse(const NfcDevice* device, FuriString* parsed_data) { // Get the block number of the block that contains the data const uint8_t start_block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); - // Get layout, sublayout, balance and number - TroikaLayout layout = troika_get_layout(data, start_block_num); - TroikaSubLayout sub_layout = troika_get_sub_layout(data, start_block_num); - - if(!furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - // If debug is enabled - proceed even if layout or sublayout is unknown, that will make collecting data easier - if(layout == TroikaLayoutUnknown || sub_layout == TroikaSublayoutUnknown) break; - } - - uint32_t number = troika_get_number(data, start_block_num, layout, sub_layout); + FuriString* metro_result = furi_string_alloc(); + FuriString* ground_result = furi_string_alloc(); + FuriString* tat_result = furi_string_alloc(); - furi_string_printf(parsed_data, "\e#Troika\nNum: %lu", number); + bool result1 = mosgortrans_parse_transport_block(&data->block[32], metro_result); + bool result2 = mosgortrans_parse_transport_block(&data->block[28], ground_result); + bool result3 = mosgortrans_parse_transport_block(&data->block[16], tat_result); - if(troika_has_balance(layout, sub_layout) || - furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { - uint16_t balance = troika_get_balance(data, start_block_num, layout, sub_layout); - furi_string_cat_printf(parsed_data, "\nBalance: %u RUR", balance); - } else { - furi_string_cat_printf(parsed_data, "\nBalance: Not available"); + furi_string_cat_printf(parsed_data, "\e#Troyka card\n"); + if(result1) { + furi_string_cat_printf( + parsed_data, "\e#Metro\n%s\n", furi_string_get_cstr(metro_result)); } - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + if(result2) { furi_string_cat_printf( - parsed_data, - "\nLayout: %02x\nSublayout: %02x\nData Block: %u", - layout, - sub_layout, - start_block_num); + parsed_data, "\e#Ediniy\n%s\n", furi_string_get_cstr(ground_result)); + } + + if(result3) { + furi_string_cat_printf(parsed_data, "\e#TAT\n%s\n", furi_string_get_cstr(tat_result)); } - parsed = true; + furi_string_free(tat_result); + furi_string_free(ground_result); + furi_string_free(metro_result); + + parsed = result1 || result2 || result3; } while(false); return parsed; From 3f1615589c0bf1d3108123a90be0c3df94e05cbb Mon Sep 17 00:00:00 2001 From: assasinfil Date: Thu, 15 Feb 2024 12:19:34 +0300 Subject: [PATCH 07/39] Fix functions --- .../nfc/api/mosgortrans/mosgortrans_util.c | 574 +++++++++--------- applications/main/nfc/application.fam | 2 +- .../main/nfc/plugins/supported_cards/troika.c | 3 - 3 files changed, 288 insertions(+), 291 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 1ddfad7683b..09fc80a9245 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -6,8 +6,8 @@ void from_days_to_datetime(uint16_t days, DateTime* datetime, uint16_t start_yea start_datetime.year = start_year - 1; start_datetime.month = 12; start_datetime.day = 31; - timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); - furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); + timestamp += datetime_datetime_to_timestamp(&start_datetime); + datetime_timestamp_to_datetime(timestamp, datetime); } void from_minutes_to_datetime(uint32_t minutes, DateTime* datetime, uint16_t start_year) { @@ -16,20 +16,20 @@ void from_minutes_to_datetime(uint32_t minutes, DateTime* datetime, uint16_t sta start_datetime.year = start_year - 1; start_datetime.month = 12; start_datetime.day = 31; - timestamp += furi_hal_rtc_datetime_to_timestamp(&start_datetime); - furi_hal_rtc_timestamp_to_datetime(timestamp, datetime); + timestamp += datetime_datetime_to_timestamp(&start_datetime); + datetime_timestamp_to_datetime(timestamp, datetime); } bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result) { - uint16_t transport_departament = get_bits_16(block->data, 0, 10); + uint16_t transport_departament = bit_lib_get_bits_16(block->data, 0, 10); FURI_LOG_I(TAG2, "Transport departament: %x", transport_departament); - uint16_t layout_type = get_bits_16(block->data, 52, 4); + uint16_t layout_type = bit_lib_get_bits_16(block->data, 52, 4); if(layout_type == 0xE) { - layout_type = get_bits_16(block->data, 52, 9); + layout_type = bit_lib_get_bits_16(block->data, 52, 9); } else if(layout_type == 0xF) { - layout_type = get_bits_16(block->data, 52, 14); + layout_type = bit_lib_get_bits_16(block->data, 52, 14); } FURI_LOG_I(TAG2, "Layout type %x", layout_type); @@ -50,32 +50,32 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* switch(layout_type) { case 0x02: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_use_before_date = get_bits_16(block->data, 56, 16); //202 - uint8_t card_benefit_code = get_bits(block->data, 72, 8); //124 - uint32_t card_rfu1 = get_bits_32(block->data, 80, 32); //rfu1 - uint16_t card_crc16 = get_bits_16(block->data, 112, 16); //501.1 - card_blocked = get_bits(block->data, 128, 1); //303 - uint16_t card_start_trip_time = get_bits_16(block->data, 177, 12); //403 - uint16_t card_start_trip_date = get_bits_16(block->data, 189, 16); //402 - uint16_t card_valid_from_date = get_bits_16(block->data, 157, 16); //311 - uint16_t card_valid_by_date = get_bits_16(block->data, 173, 16); //312 - uint8_t card_start_trip_seconds = get_bits(block->data, 189, 6); //406 - uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 - uint16_t card_use_with_date = get_bits_16(block->data, 189, 16); //205 - uint8_t card_route = get_bits(block->data, 205, 1); //424 - uint16_t card_validator1 = get_bits_16(block->data, 206, 15); //422.1 - card_validator = get_bits_16(block->data, 205, 16); //422 - uint16_t card_total_trips = get_bits_16(block->data, 221, 16); //331 - uint8_t card_write_enabled = get_bits(block->data, 237, 1); //write_enabled - uint8_t card_rfu2 = get_bits(block->data, 238, 2); //rfu2 - uint16_t card_crc16_2 = get_bits_16(block->data, 240, 16); //501.2 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + uint8_t card_benefit_code = bit_lib_get_bits(block->data, 72, 8); //124 + uint32_t card_rfu1 = bit_lib_get_bits_32(block->data, 80, 32); //rfu1 + uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 + card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 177, 12); //403 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 189, 16); //402 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 + uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 173, 16); //312 + uint8_t card_start_trip_seconds = bit_lib_get_bits(block->data, 189, 6); //406 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 + uint16_t card_use_with_date = bit_lib_get_bits_16(block->data, 189, 16); //205 + uint8_t card_route = bit_lib_get_bits(block->data, 205, 1); //424 + uint16_t card_validator1 = bit_lib_get_bits_16(block->data, 206, 15); //422.1 + card_validator = bit_lib_get_bits_16(block->data, 205, 16); //422 + uint16_t card_total_trips = bit_lib_get_bits_16(block->data, 221, 16); //331 + uint8_t card_write_enabled = bit_lib_get_bits(block->data, 237, 1); //write_enabled + uint8_t card_rfu2 = bit_lib_get_bits(block->data, 238, 2); //rfu2 + uint16_t card_crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 FURI_LOG_D( TAG2, @@ -133,30 +133,30 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x06: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_use_before_date = get_bits_16(block->data, 56, 16); //202 - uint8_t card_geozone_a = get_bits(block->data, 72, 4); //GeoZoneA - uint8_t card_geozone_b = get_bits(block->data, 76, 4); //GeoZoneB - card_blank_type = get_bits_16(block->data, 80, 10); //121. - uint16_t card_type_of_extended = get_bits_16(block->data, 90, 10); //122 - uint32_t card_rfu1 = get_bits_16(block->data, 100, 12); //rfu1 - uint16_t card_crc16 = get_bits_16(block->data, 112, 16); //501.1 - card_blocked = get_bits(block->data, 128, 1); //303 - uint16_t card_start_trip_time = get_bits_16(block->data, 129, 12); //403 - uint16_t card_start_trip_date = get_bits_16(block->data, 141, 16); //402 - uint16_t card_valid_from_date = get_bits_16(block->data, 157, 16); //311 - uint16_t card_valid_by_date = get_bits_16(block->data, 173, 16); //312 - uint16_t card_company = get_bits(block->data, 189, 4); //Company - uint8_t card_validator1 = get_bits(block->data, 193, 4); //422.1 - uint16_t card_remaining_trips = get_bits_16(block->data, 197, 10); //321 - uint8_t card_units = get_bits(block->data, 207, 6); //Units - uint16_t card_validator2 = get_bits_16(block->data, 213, 10); //422.2 - uint16_t card_total_trips = get_bits_16(block->data, 223, 16); //331 - uint8_t card_extended = get_bits(block->data, 239, 1); //123 - uint16_t card_crc16_2 = get_bits_16(block->data, 240, 16); //501.2 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + uint8_t card_geozone_a = bit_lib_get_bits(block->data, 72, 4); //GeoZoneA + uint8_t card_geozone_b = bit_lib_get_bits(block->data, 76, 4); //GeoZoneB + card_blank_type = bit_lib_get_bits_16(block->data, 80, 10); //121. + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 90, 10); //122 + uint32_t card_rfu1 = bit_lib_get_bits_16(block->data, 100, 12); //rfu1 + uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 + card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 129, 12); //403 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 141, 16); //402 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 + uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 173, 16); //312 + uint16_t card_company = bit_lib_get_bits(block->data, 189, 4); //Company + uint8_t card_validator1 = bit_lib_get_bits(block->data, 193, 4); //422.1 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 197, 10); //321 + uint8_t card_units = bit_lib_get_bits(block->data, 207, 6); //Units + uint16_t card_validator2 = bit_lib_get_bits_16(block->data, 213, 10); //422.2 + uint16_t card_total_trips = bit_lib_get_bits_16(block->data, 223, 16); //331 + uint8_t card_extended = bit_lib_get_bits(block->data, 239, 1); //123 + uint16_t card_crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 FURI_LOG_D( TAG2, @@ -211,22 +211,22 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x08: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_use_before_date = get_bits_16(block->data, 56, 16); //202 - uint64_t card_rfu1 = get_bits_64(block->data, 72, 56); //rfu1 - uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 - uint8_t card_rfu2 = get_bits(block->data, 153, 7); //rfu2 - uint8_t card_remaining_trips1 = get_bits(block->data, 160, 8); //321.1 - uint8_t card_remaining_trips = get_bits(block->data, 168, 8); //321 - uint8_t card_validator1 = get_bits(block->data, 193, 2); //422.1 - uint16_t card_validator = get_bits_16(block->data, 177, 15); //422 - card_hash = get_bits_32(block->data, 192, 32); //502 - uint32_t card_rfu3 = get_bits_32(block->data, 224, 32); //rfu3 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 + uint8_t card_rfu2 = bit_lib_get_bits(block->data, 153, 7); //rfu2 + uint8_t card_remaining_trips1 = bit_lib_get_bits(block->data, 160, 8); //321.1 + uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 168, 8); //321 + uint8_t card_validator1 = bit_lib_get_bits(block->data, 193, 2); //422.1 + uint16_t card_validator = bit_lib_get_bits_16(block->data, 177, 15); //422 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 + uint32_t card_rfu3 = bit_lib_get_bits_32(block->data, 224, 32); //rfu3 FURI_LOG_D( TAG2, @@ -262,23 +262,23 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x0A: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - uint16_t card_valid_from_date = get_bits_16(block->data, 64, 12); //311 - uint32_t card_valid_for_minutes = get_bits_32(block->data, 76, 19); //314 - uint8_t card_requires_activation = get_bits(block->data, 95, 1); //301 - card_start_trip_minutes = get_bits_32(block->data, 96, 19); //405 - card_minutes_pass = get_bits(block->data, 119, 7); //412 - uint8_t card_transport_type_flag = get_bits(block->data, 126, 2); //421.0 - uint8_t card_remaining_trips = get_bits(block->data, 128, 8); //321 - uint16_t card_validator = get_bits_16(block->data, 136, 16); //422 - uint8_t card_transport_type1 = get_bits(block->data, 152, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 154, 2); //421.2 - uint8_t card_transport_type3 = get_bits(block->data, 156, 2); //421.3 - uint8_t card_transport_type4 = get_bits(block->data, 158, 2); //421.4 - card_hash = get_bits_32(block->data, 192, 32); //502 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 64, 12); //311 + uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 76, 19); //314 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 95, 1); //301 + card_start_trip_minutes = bit_lib_get_bits_32(block->data, 96, 19); //405 + card_minutes_pass = bit_lib_get_bits(block->data, 119, 7); //412 + uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 126, 2); //421.0 + uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 128, 8); //321 + uint16_t card_validator = bit_lib_get_bits_16(block->data, 136, 16); //422 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 152, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 154, 2); //421.2 + uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 156, 2); //421.3 + uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 158, 2); //421.4 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 FURI_LOG_D( TAG2, @@ -322,24 +322,24 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x0C: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_use_before_date = get_bits_16(block->data, 56, 16); //202 - uint64_t card_rfu1 = get_bits_64(block->data, 72, 56); //rfu1 - uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 - uint16_t card_rfu2 = get_bits_16(block->data, 153, 13); //rfu2 - uint16_t card_remaining_trips = get_bits_16(block->data, 166, 10); //321 - uint16_t card_validator = get_bits_16(block->data, 176, 16); //422 - card_hash = get_bits_32(block->data, 192, 32); //502 - uint16_t card_start_trip_date = get_bits_16(block->data, 224, 16); //402 - uint16_t card_start_trip_time = get_bits_16(block->data, 240, 11); //403 - uint8_t card_transport_type = get_bits(block->data, 251, 2); //421 - uint8_t card_rfu3 = get_bits(block->data, 253, 2); //rfu3 - uint8_t card_transfer_in_metro = get_bits(block->data, 255, 1); //432 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 + uint16_t card_rfu2 = bit_lib_get_bits_16(block->data, 153, 13); //rfu2 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 + uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 + uint8_t card_transport_type = bit_lib_get_bits(block->data, 251, 2); //421 + uint8_t card_rfu3 = bit_lib_get_bits(block->data, 253, 2); //rfu3 + uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 255, 1); //432 FURI_LOG_D( TAG2, @@ -384,33 +384,33 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x0D: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - uint8_t card_rfu1 = get_bits(block->data, 56, 8); //rfu1 - card_use_before_date = get_bits_16(block->data, 64, 16); //202 - uint16_t card_valid_for_time = get_bits_16(block->data, 80, 11); //316 - uint8_t card_rfu2 = get_bits(block->data, 91, 5); //rfu2 - uint16_t card_use_before_date2 = get_bits_16(block->data, 96, 16); //202.2 - uint16_t card_valid_for_time2 = get_bits_16(block->data, 123, 11); //316.2 - uint8_t card_rfu3 = get_bits(block->data, 123, 5); //rfu3 - uint16_t card_valid_from_date = get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = get_bits(block->data, 152, 1); //301 - uint8_t card_rfu4 = get_bits(block->data, 153, 2); //rfu4 - uint8_t card_passage_5_minutes = get_bits(block->data, 155, 5); //413 - uint8_t card_transport_type1 = get_bits(block->data, 160, 2); //421.1 - uint8_t card_passage_in_metro = get_bits(block->data, 162, 1); //431 - uint8_t card_passages_ground_transport = get_bits(block->data, 163, 3); //433 - uint16_t card_remaining_trips = get_bits_16(block->data, 166, 10); //321 - uint16_t card_validator = get_bits_16(block->data, 176, 16); //422 - card_hash = get_bits_32(block->data, 192, 32); //502 - uint16_t card_start_trip_date = get_bits_16(block->data, 224, 16); //402 - uint16_t card_start_trip_time = get_bits_16(block->data, 240, 11); //403 - uint8_t card_transport_type2 = get_bits(block->data, 251, 2); //421.2 - uint8_t card_rfu5 = get_bits(block->data, 253, 2); //rfu5 - uint8_t card_transfer_in_metro = get_bits(block->data, 255, 1); //432 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + uint8_t card_rfu1 = bit_lib_get_bits(block->data, 56, 8); //rfu1 + card_use_before_date = bit_lib_get_bits_16(block->data, 64, 16); //202 + uint16_t card_valid_for_time = bit_lib_get_bits_16(block->data, 80, 11); //316 + uint8_t card_rfu2 = bit_lib_get_bits(block->data, 91, 5); //rfu2 + uint16_t card_use_before_date2 = bit_lib_get_bits_16(block->data, 96, 16); //202.2 + uint16_t card_valid_for_time2 = bit_lib_get_bits_16(block->data, 123, 11); //316.2 + uint8_t card_rfu3 = bit_lib_get_bits(block->data, 123, 5); //rfu3 + uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 + uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 + uint8_t card_rfu4 = bit_lib_get_bits(block->data, 153, 2); //rfu4 + uint8_t card_passage_5_minutes = bit_lib_get_bits(block->data, 155, 5); //413 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 160, 2); //421.1 + uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 162, 1); //431 + uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 163, 3); //433 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 + uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 251, 2); //421.2 + uint8_t card_rfu5 = bit_lib_get_bits(block->data, 253, 2); //rfu5 + uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 255, 1); //432 FURI_LOG_D( TAG2, @@ -465,27 +465,27 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x1C1: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - card_use_before_date = get_bits_16(block->data, 61, 16); //202. - card_blank_type = get_bits_16(block->data, 77, 10); //121. - card_validator = get_bits_16(block->data, 128, 16); //422 - uint16_t card_start_trip_date = get_bits_16(block->data, 144, 16); //402 - uint16_t card_start_trip_time = get_bits_16(block->data, 160, 11); //403 - uint8_t card_transport_type1 = get_bits(block->data, 171, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 173, 2); //421.2 - uint8_t card_transfer_in_metro = get_bits(block->data, 177, 1); //432 - uint8_t card_passage_in_metro = get_bits(block->data, 178, 1); //431 - uint8_t card_passages_ground_transport = get_bits(block->data, 179, 3); //433 - card_minutes_pass = get_bits(block->data, 185, 8); //412. - card_remaining_funds = get_bits_32(block->data, 196, 19) / 100; //322 - uint8_t card_fare_trip = get_bits(block->data, 215, 2); //441 - card_blocked = get_bits(block->data, 202, 1); //303 - uint8_t card_zoo = get_bits(block->data, 218, 1); //zoo - card_hash = get_bits_32(block->data, 224, 32); //502 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121. + card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 + uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 144, 16); //402 + uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 160, 11); //403 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 171, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 173, 2); //421.2 + uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 177, 1); //432 + uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 178, 1); //431 + uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 179, 3); //433 + card_minutes_pass = bit_lib_get_bits(block->data, 185, 8); //412. + card_remaining_funds = bit_lib_get_bits_32(block->data, 196, 19) / 100; //322 + uint8_t card_fare_trip = bit_lib_get_bits(block->data, 215, 2); //441 + card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 + uint8_t card_zoo = bit_lib_get_bits(block->data, 218, 1); //zoo + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -532,28 +532,28 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x1C2: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 - card_use_before_date = get_bits_16(block->data, 71, 16); //202. - card_blank_type = get_bits_16(block->data, 87, 10); //121. - uint16_t card_valid_to_date = get_bits_16(block->data, 97, 16); //311 - uint16_t card_activate_during = get_bits_16(block->data, 113, 9); //302 - uint32_t card_valid_for_minutes = get_bits_32(block->data, 131, 20); //314 - card_minutes_pass = get_bits(block->data, 154, 8); //412. - uint8_t card_transport_type = get_bits(block->data, 163, 2); //421 - uint8_t card_passage_in_metro = get_bits(block->data, 165, 1); //431 - uint8_t card_transfer_in_metro = get_bits(block->data, 166, 1); //432 - uint16_t card_remaining_trips = get_bits_16(block->data, 167, 10); //321 - card_validator = get_bits_16(block->data, 177, 16); //422 - uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 196, 20); //404 - uint8_t card_requires_activation = get_bits(block->data, 216, 1); //301 - card_blocked = get_bits(block->data, 217, 1); //303 - uint8_t card_extended = get_bits(block->data, 218, 1); //123 - card_hash = get_bits_32(block->data, 224, 32); //502 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 + card_use_before_date = bit_lib_get_bits_16(block->data, 71, 16); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 87, 10); //121. + uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 97, 16); //311 + uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 113, 9); //302 + uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 131, 20); //314 + card_minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412. + uint8_t card_transport_type = bit_lib_get_bits(block->data, 163, 2); //421 + uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 165, 1); //431 + uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 166, 1); //432 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 167, 10); //321 + card_validator = bit_lib_get_bits_16(block->data, 177, 16); //422 + uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 196, 20); //404 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 216, 1); //301 + card_blocked = bit_lib_get_bits(block->data, 217, 1); //303 + uint8_t card_extended = bit_lib_get_bits(block->data, 218, 1); //123 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -604,25 +604,25 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x1C3: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - card_use_before_date = get_bits_16(block->data, 61, 16); //202 - card_blank_type = get_bits_16(block->data, 77, 10); //121 - card_remaining_funds = get_bits_32(block->data, 188, 22) / 100; //322 - card_hash = get_bits_32(block->data, 224, 32); //502 - card_validator = get_bits_16(block->data, 128, 16); //422 - card_start_trip_minutes = get_bits_32(block->data, 144, 23); //405 - uint8_t card_fare_trip = get_bits(block->data, 210, 2); //441 - card_minutes_pass = get_bits(block->data, 171, 7); //412 - uint8_t card_transport_type_flag = get_bits(block->data, 178, 2); //421.0 - uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 - card_blocked = get_bits(block->data, 212, 1); //303 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 + card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121 + card_remaining_funds = bit_lib_get_bits_32(block->data, 188, 22) / 100; //322 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 + card_start_trip_minutes = bit_lib_get_bits_32(block->data, 144, 23); //405 + uint8_t card_fare_trip = bit_lib_get_bits(block->data, 210, 2); //441 + card_minutes_pass = bit_lib_get_bits(block->data, 171, 7); //412 + uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 + card_blocked = bit_lib_get_bits(block->data, 212, 1); //303 FURI_LOG_D( TAG2, "Card view: %x, type: %x, number: %lx, layout: %x, layout2: %x, use before date: %x, blank type: %x, remaining funds: %lx, hash: %lx, validator: %x, start trip minutes: %lx, fare trip: %x, minutes pass: %x, transport type flag: %x, transport type1: %x, transport type2: %x, transport type3: %x, transport type4: %x, blocked: %x", @@ -667,31 +667,31 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x1C4: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 - card_use_before_date = get_bits_16(block->data, 71, 13); //202. - card_blank_type = get_bits_16(block->data, 84, 10); //121. - uint16_t card_valid_to_date = get_bits_16(block->data, 94, 13); //311 - uint16_t card_activate_during = get_bits_16(block->data, 107, 9); //302 - uint16_t card_extension_counter = get_bits_16(block->data, 116, 10); //304 - uint32_t card_valid_for_minutes = get_bits_32(block->data, 128, 20); //314 - card_minutes_pass = get_bits(block->data, 158, 7); //412. - uint8_t card_transport_type_flag = get_bits(block->data, 178, 2); //421.0 - uint8_t card_transport_type1 = get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = get_bits(block->data, 186, 2); //421.4 - uint16_t card_remaining_trips = get_bits_16(block->data, 169, 10); //321 - card_validator = get_bits_16(block->data, 179, 16); //422 - uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 195, 20); //404 - uint8_t card_requires_activation = get_bits(block->data, 215, 1); //301 - card_blocked = get_bits(block->data, 216, 1); //303 - uint8_t card_extended = get_bits(block->data, 217, 1); //123 - card_hash = get_bits_32(block->data, 224, 32); //502 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 + card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. + uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 94, 13); //311 + uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 107, 9); //302 + uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 116, 10); //304 + uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 + card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. + uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 + uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 + uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 + uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 + uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 169, 10); //321 + card_validator = bit_lib_get_bits_16(block->data, 179, 16); //422 + uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 195, 20); //404 + uint8_t card_requires_activation = bit_lib_get_bits(block->data, 215, 1); //301 + card_blocked = bit_lib_get_bits(block->data, 216, 1); //303 + uint8_t card_extended = bit_lib_get_bits(block->data, 217, 1); //123 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -746,24 +746,24 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x1C5: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - card_use_before_date = get_bits_16(block->data, 61, 13); //202. - card_blank_type = get_bits_16(block->data, 74, 10); //121. - uint32_t card_valid_to_time = get_bits_32(block->data, 84, 23); //317 - uint16_t card_extension_counter = get_bits_16(block->data, 107, 10); //304 - card_start_trip_minutes = get_bits_32(block->data, 128, 23); //405 - uint8_t card_metro_ride_with = get_bits(block->data, 151, 7); //414 - card_minutes_pass = get_bits(block->data, 158, 7); //412. - card_remaining_funds = get_bits_32(block->data, 167, 19) / 100; //322 - card_validator = get_bits_16(block->data, 186, 16); //422 - card_blocked = get_bits(block->data, 202, 1); //303 - uint16_t card_route = get_bits_16(block->data, 204, 12); //424 - uint8_t card_passages_ground_transport = get_bits(block->data, 216, 7); //433 - card_hash = get_bits_32(block->data, 224, 32); //502 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + card_use_before_date = bit_lib_get_bits_16(block->data, 61, 13); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 74, 10); //121. + uint32_t card_valid_to_time = bit_lib_get_bits_32(block->data, 84, 23); //317 + uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 107, 10); //304 + card_start_trip_minutes = bit_lib_get_bits_32(block->data, 128, 23); //405 + uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 151, 7); //414 + card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. + card_remaining_funds = bit_lib_get_bits_32(block->data, 167, 19) / 100; //322 + card_validator = bit_lib_get_bits_16(block->data, 186, 16); //422 + card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 + uint16_t card_route = bit_lib_get_bits_16(block->data, 204, 12); //424 + uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 216, 7); //433 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -809,26 +809,26 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x1C6: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - card_layout2 = get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = get_bits_16(block->data, 61, 10); //122 - card_use_before_date = get_bits_16(block->data, 71, 13); //202. - card_blank_type = get_bits_16(block->data, 84, 10); //121. - uint32_t card_valid_from_date = get_bits_32(block->data, 94, 23); //311 - uint16_t card_extension_counter = get_bits_16(block->data, 117, 10); //304 - uint32_t card_valid_for_minutes = get_bits_32(block->data, 128, 20); //314 - uint32_t card_start_trip_neg_minutes = get_bits_32(block->data, 148, 20); //404 - uint8_t card_metro_ride_with = get_bits(block->data, 168, 7); //414 - card_minutes_pass = get_bits(block->data, 175, 7); //412. - uint16_t card_remaining_trips = get_bits_16(block->data, 182, 7); //321 - card_validator = get_bits_16(block->data, 189, 16); //422 - card_blocked = get_bits(block->data, 205, 1); //303 - uint8_t card_extended = get_bits(block->data, 206, 1); //123 - uint16_t card_route = get_bits_16(block->data, 212, 12); //424 - card_hash = get_bits_32(block->data, 224, 32); //502 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 + card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. + card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. + uint32_t card_valid_from_date = bit_lib_get_bits_32(block->data, 94, 23); //311 + uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 117, 10); //304 + uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 + uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 148, 20); //404 + uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 168, 7); //414 + card_minutes_pass = bit_lib_get_bits(block->data, 175, 7); //412. + uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 182, 7); //321 + card_validator = bit_lib_get_bits_16(block->data, 189, 16); //422 + card_blocked = bit_lib_get_bits(block->data, 205, 1); //303 + uint8_t card_extended = bit_lib_get_bits(block->data, 206, 1); //123 + uint16_t card_route = bit_lib_get_bits_16(block->data, 212, 12); //424 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -877,24 +877,24 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x3CCB: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - uint16_t card_tech_code = get_bits_32(block->data, 56, 10); //tech_code - uint16_t card_valid_to_minutes = get_bits_16(block->data, 66, 16); //311 - uint16_t card_valid_by_date = get_bits_16(block->data, 82, 16); //312 - uint8_t card_interval = get_bits(block->data, 98, 4); //interval - uint16_t card_app_code1 = get_bits_16(block->data, 102, 16); //app_code1 - uint16_t card_hash1 = get_bits_16(block->data, 112, 16); //502.1 - uint16_t card_type1 = get_bits_16(block->data, 128, 10); //type1 - uint16_t card_app_code2 = get_bits_16(block->data, 138, 10); //app_code2 - uint16_t card_type2 = get_bits_16(block->data, 148, 10); //type2 - uint16_t card_app_code3 = get_bits_16(block->data, 158, 10); //app_code3 - uint16_t card_type3 = get_bits_16(block->data, 148, 10); //type3 - uint16_t card_app_code4 = get_bits_16(block->data, 168, 10); //app_code4 - uint16_t card_type4 = get_bits_16(block->data, 178, 10); //type4 - card_hash = get_bits_32(block->data, 224, 32); //502.2 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code + uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 + uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 + uint8_t card_interval = bit_lib_get_bits(block->data, 98, 4); //interval + uint16_t card_app_code1 = bit_lib_get_bits_16(block->data, 102, 16); //app_code1 + uint16_t card_hash1 = bit_lib_get_bits_16(block->data, 112, 16); //502.1 + uint16_t card_type1 = bit_lib_get_bits_16(block->data, 128, 10); //type1 + uint16_t card_app_code2 = bit_lib_get_bits_16(block->data, 138, 10); //app_code2 + uint16_t card_type2 = bit_lib_get_bits_16(block->data, 148, 10); //type2 + uint16_t card_app_code3 = bit_lib_get_bits_16(block->data, 158, 10); //app_code3 + uint16_t card_type3 = bit_lib_get_bits_16(block->data, 148, 10); //type3 + uint16_t card_app_code4 = bit_lib_get_bits_16(block->data, 168, 10); //app_code4 + uint16_t card_type4 = bit_lib_get_bits_16(block->data, 178, 10); //type4 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502.2 FURI_LOG_D( TAG2, @@ -933,14 +933,14 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x3C0B: { - card_view = get_bits_16(block->data, 0, 10); //101 - card_type = get_bits_16(block->data, 10, 10); //102 - card_number = get_bits_32(block->data, 20, 32); //201 - card_layout = get_bits(block->data, 52, 4); //111 - uint16_t card_tech_code = get_bits_32(block->data, 56, 10); //tech_code - uint16_t card_valid_to_minutes = get_bits_16(block->data, 66, 16); //311 - uint16_t card_valid_by_date = get_bits_16(block->data, 82, 16); //312 - uint16_t card_hash = get_bits_16(block->data, 112, 16); //502.1 + card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 + card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 + card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 + card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code + uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 + uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 + uint16_t card_hash = bit_lib_get_bits_16(block->data, 112, 16); //502.1 FURI_LOG_D( TAG2, diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index ff5e8189548..4bcc798237c 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -89,7 +89,7 @@ App( entry_point="troika_plugin_ep", targets=["f7"], requires=["nfc"], - sources=["plugins/supported_cards/troika.c", "helpers/mosgortrans_layouts_i.c"], + sources=["plugins/supported_cards/troika.c"], ) App( diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index f18b503ce5d..3837214bbd9 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -196,9 +196,6 @@ static bool troika_parse(const NfcDevice* device, FuriString* parsed_data) { bit_lib_bytes_to_num_be(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data)); if(key != cfg.keys[cfg.data_sector].a) break; - // Get the block number of the block that contains the data - const uint8_t start_block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); - FuriString* metro_result = furi_string_alloc(); FuriString* ground_result = furi_string_alloc(); FuriString* tat_result = furi_string_alloc(); From 751ac9da13ba01c57366e763e84dcf7004caf37b Mon Sep 17 00:00:00 2001 From: assasinfil Date: Thu, 15 Feb 2024 12:47:50 +0300 Subject: [PATCH 08/39] Added MSK Social card parser --- applications/main/nfc/application.fam | 9 + .../plugins/supported_cards/social_moscow.c | 234 ++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 applications/main/nfc/plugins/supported_cards/social_moscow.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 4bcc798237c..66a0c1f2ec6 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -92,6 +92,15 @@ App( sources=["plugins/supported_cards/troika.c"], ) +App( + appid="social_moscow_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="social_moscow_plugin_ep", + targets=["f7"], + requires=["nfc"], + sources=["plugins/supported_cards/social_moscow.c"], +) + App( appid="washcity_parser", apptype=FlipperAppType.PLUGIN, diff --git a/applications/main/nfc/plugins/supported_cards/social_moscow.c b/applications/main/nfc/plugins/supported_cards/social_moscow.c new file mode 100644 index 00000000000..0f4cfd41763 --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/social_moscow.c @@ -0,0 +1,234 @@ +#include "nfc_supported_card_plugin.h" +#include + +#include + +#include +#include +#include +#include "../../api/mosgortrans/mosgortrans_util.h" +#include "furi_hal_rtc.h" + +#define TAG "Social_Moscow" + +typedef struct { + uint64_t a; + uint64_t b; +} MfClassicKeyPair; + +typedef struct { + const MfClassicKeyPair* keys; + uint32_t data_sector; +} SocialMoscowCardConfig; + +static const MfClassicKeyPair social_moscow_1k_keys[] = { + {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, + {.a = 0x2735fc181807, .b = 0xbf23a53c1f63}, + {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, + {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, + {.a = 0x73068f118c13, .b = 0x2b7f3253fac5}, + {.a = 0x186d8c4b93f9, .b = 0x9f131d8c2057}, + {.a = 0x3a4bba8adaf0, .b = 0x67362d90f973}, + {.a = 0x8765b17968a2, .b = 0x6202a38f69e2}, + {.a = 0x40ead80721ce, .b = 0x100533b89331}, + {.a = 0x0db5e6523f7c, .b = 0x653a87594079}, + {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, + {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, + {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, + {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, + {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, + {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}}; + +static const MfClassicKeyPair social_moscow_4k_keys[] = { + {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, {.a = 0x2735fc181807, .b = 0xbf23a53c1f63}, + {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, + {.a = 0x73068f118c13, .b = 0x2b7f3253fac5}, {.a = 0x186d8c4b93f9, .b = 0x9f131d8c2057}, + {.a = 0x3a4bba8adaf0, .b = 0x67362d90f973}, {.a = 0x8765b17968a2, .b = 0x6202a38f69e2}, + {.a = 0x40ead80721ce, .b = 0x100533b89331}, {.a = 0x0db5e6523f7c, .b = 0x653a87594079}, + {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, + {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, + {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, + {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, + {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, +}; + +static bool social_moscow_get_card_config(SocialMoscowCardConfig* config, MfClassicType type) { + bool success = true; + if(type == MfClassicType1k) { + config->data_sector = 15; + config->keys = social_moscow_1k_keys; + } else if(type == MfClassicType4k) { + config->data_sector = 15; + config->keys = social_moscow_4k_keys; + } else { + success = false; + } + + return success; +} + +static bool social_moscow_verify_type(Nfc* nfc, MfClassicType type) { + bool verified = false; + + do { + SocialMoscowCardConfig cfg = {}; + if(!social_moscow_get_card_config(&cfg, type)) break; + + const uint8_t block_num = mf_classic_get_first_block_num_of_sector(cfg.data_sector); + FURI_LOG_D(TAG, "Verifying sector %lu", cfg.data_sector); + + MfClassicKey key = {0}; + bit_lib_num_to_bytes_be(cfg.keys[cfg.data_sector].a, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_context; + MfClassicError error = + mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_context); + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); + break; + } + FURI_LOG_D(TAG, "Verify success!"); + verified = true; + } while(false); + + return verified; +} + +static bool social_moscow_verify(Nfc* nfc) { + return social_moscow_verify_type(nfc, MfClassicType1k) || + social_moscow_verify_type(nfc, MfClassicType4k); +} + +static bool social_moscow_read(Nfc* nfc, NfcDevice* device) { + furi_assert(nfc); + furi_assert(device); + + bool is_read = false; + + MfClassicData* data = mf_classic_alloc(); + nfc_device_copy_data(device, NfcProtocolMfClassic, data); + + do { + MfClassicType type = MfClassicType4k; + MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); + if(error != MfClassicErrorNone) break; + + data->type = type; + SocialMoscowCardConfig cfg = {}; + if(!social_moscow_get_card_config(&cfg, data->type)) break; + + MfClassicDeviceKeys keys = {}; + for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { + bit_lib_num_to_bytes_be(cfg.keys[i].a, sizeof(MfClassicKey), keys.key_a[i].data); + FURI_BIT_SET(keys.key_a_mask, i); + bit_lib_num_to_bytes_be(cfg.keys[i].b, sizeof(MfClassicKey), keys.key_b[i].data); + FURI_BIT_SET(keys.key_b_mask, i); + } + + error = mf_classic_poller_sync_read(nfc, &keys, data); + if(error == MfClassicErrorNotPresent) { + FURI_LOG_W(TAG, "Failed to read data"); + break; + } + + nfc_device_set_data(device, NfcProtocolMfClassic, data); + + is_read = (error == MfClassicErrorNone); + } while(false); + + mf_classic_free(data); + + return is_read; +} + +static bool social_moscow_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + bool parsed = false; + + do { + // Verify card type + SocialMoscowCardConfig cfg = {}; + if(!social_moscow_get_card_config(&cfg, data->type)) break; + + // Verify key + const MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(data, cfg.data_sector); + + const uint64_t key_a = + bit_lib_bytes_to_num_be(sec_tr->key_a.data, COUNT_OF(sec_tr->key_a.data)); + const uint64_t key_b = + bit_lib_bytes_to_num_be(sec_tr->key_b.data, COUNT_OF(sec_tr->key_b.data)); + if((key_a != cfg.keys[cfg.data_sector].a) || (key_b != cfg.keys[cfg.data_sector].b)) break; + + uint32_t card_code = bit_lib_get_bits_32(data->block[60].data, 8, 24); + uint8_t card_region = bit_lib_get_bits(data->block[60].data, 32, 8); + uint64_t card_number = bit_lib_get_bits_64(data->block[60].data, 40, 40); + uint8_t card_control = bit_lib_get_bits(data->block[60].data, 80, 4); + uint64_t omc_number = bit_lib_get_bits_64(data->block[21].data, 8, 64); + uint8_t year = data->block[60].data[11]; + uint8_t month = data->block[60].data[12]; + + FuriString* metro_result = furi_string_alloc(); + FuriString* ground_result = furi_string_alloc(); + bool result1 = mosgortrans_parse_transport_block(&data->block[4], metro_result); + bool result2 = mosgortrans_parse_transport_block(&data->block[16], ground_result); + furi_string_cat_printf( + parsed_data, + "\e#Social \ecard\nNumber: %lx %x %llx %x\nOMC: %llx\nValid for: %02x/%02x %02x%02x\n", + card_code, + card_region, + card_number, + card_control, + omc_number, + month, + year, + data->block[60].data[13], + data->block[60].data[14]); + if(result1) { + furi_string_cat_printf( + parsed_data, "\e#Metro\n%s\n", furi_string_get_cstr(metro_result)); + } + if(result2) { + furi_string_cat_printf( + parsed_data, "\e#Ground\n%s\n", furi_string_get_cstr(ground_result)); + } + furi_string_free(ground_result); + furi_string_free(metro_result); + parsed = result1 || result2; + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin social_moscow_plugin = { + .protocol = NfcProtocolMfClassic, + .verify = social_moscow_verify, + .read = social_moscow_read, + .parse = social_moscow_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor social_moscow_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &social_moscow_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* social_moscow_plugin_ep() { + return &social_moscow_plugin_descriptor; +} \ No newline at end of file From ba19f56771016c1e2b7f30af9952ba7feab1c7c2 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Sun, 18 Feb 2024 17:10:58 +0300 Subject: [PATCH 09/39] Parser func refactor start --- .../nfc/api/mosgortrans/mosgortrans_util.c | 279 +++++++++++++++--- 1 file changed, 237 insertions(+), 42 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 09fc80a9245..4c123a8b658 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -20,9 +20,198 @@ void from_minutes_to_datetime(uint32_t minutes, DateTime* datetime, uint16_t sta datetime_timestamp_to_datetime(timestamp, datetime); } +typedef struct { + uint16_t view; + uint16_t type; + uint32_t number; + uint8_t layout; + uint8_t layout2; + uint16_t use_before_date; + uint16_t blank_type; + uint32_t start_trip_minutes; + uint8_t minutes_pass; + uint32_t remaining_funds; + uint16_t validator; + uint8_t blocked; + uint32_t hash; +} BlockData; + +void parse_layout_2(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); + data_block->layout = bit_lib_get_bits(block->data, 52, 4); + data_block->use_before_date = bit_lib_get_bits_16(block->data, 56, 16); + data_block->validator = bit_lib_get_bits_16(block->data, 205, 16); + data_block->blocked = bit_lib_get_bits(block->data, 128, 1); +} + +void parse_layout_6(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 80, 10); + data_block->blocked = bit_lib_get_bits(block->data, 128, 1); +} + +void parse_layout_8(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + data_block->hash = bit_lib_get_bits_32(block->data, 192, 32); +} + +void parse_layout_A(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 96, 19); + data_block->minutes_pass = bit_lib_get_bits(block->data, 119, 7); + data_block->hash = bit_lib_get_bits_32(block->data, 192, 32); +} + +void parse_layout_C(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + data_block->hash = bit_lib_get_bits_32(block->data, 192, 32); +} + +void parse_layout_D(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 64, 16); //202 + data_block->hash = bit_lib_get_bits_32(block->data, 192, 32); +} + +void parse_layout_E1(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 77, 10); + data_block->validator = bit_lib_get_bits_16(block->data, 128, 16); + data_block->minutes_pass = bit_lib_get_bits(block->data, 185, 8); + data_block->remaining_funds = bit_lib_get_bits_32(block->data, 196, 19); + data_block->blocked = bit_lib_get_bits(block->data, 202, 1); + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); +} + +void parse_layout_E2(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 16); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 87, 10); + data_block->validator = bit_lib_get_bits_16(block->data, 177, 16); + data_block->minutes_pass = bit_lib_get_bits(block->data, 154, 8); + data_block->blocked = bit_lib_get_bits(block->data, 217, 1); + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); +} + +void parse_layout_E3(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 77, 10); + data_block->validator = bit_lib_get_bits_16(block->data, 128, 16); + data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 144, 23); + data_block->minutes_pass = bit_lib_get_bits(block->data, 171, 7); + data_block->remaining_funds = bit_lib_get_bits_32(block->data, 188, 22); + data_block->blocked = bit_lib_get_bits(block->data, 212, 1); + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); +} + +void parse_layout_E4(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 84, 10); + data_block->validator = bit_lib_get_bits_16(block->data, 179, 16); + data_block->minutes_pass = bit_lib_get_bits(block->data, 158, 7); + data_block->blocked = bit_lib_get_bits(block->data, 216, 1); + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); +} + +void parse_layout_E5(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 74, 10); + data_block->validator = bit_lib_get_bits_16(block->data, 186, 16); + data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 128, 23); + data_block->minutes_pass = bit_lib_get_bits(block->data, 158, 7); + data_block->remaining_funds = bit_lib_get_bits_32(block->data, 167, 19); + data_block->blocked = bit_lib_get_bits(block->data, 202, 1); + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); +} + +void parse_layout_E6(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 84, 10); + data_block->validator = bit_lib_get_bits_16(block->data, 189, 16); + data_block->minutes_pass = bit_lib_get_bits(block->data, 175, 7); + data_block->blocked = bit_lib_get_bits(block->data, 205, 1); + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); +} + +void parse_layout_FCB(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); +} + +void parse_layout_F0B(BlockData* data_block, const MfClassicBlock* block) { + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); + data_block->layout = bit_lib_get_bits(block->data, 52, 4); + data_block->hash = bit_lib_get_bits_32(block->data, 112, 16); +} + bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result) { + BlockData data_block = {}; + const uint16_t valid_departments[] = {0x106, 0x108, 0x10A, 0x10E, 0x110, 0x117}; uint16_t transport_departament = bit_lib_get_bits_16(block->data, 0, 10); - + bool departament_valid = false; + for(uint8_t i = 0; i < 6; i++) { + if(transport_departament == valid_departments[i]) { + departament_valid = true; + break; + } + } + if(!departament_valid) { + return false; + } FURI_LOG_I(TAG2, "Transport departament: %x", transport_departament); uint16_t layout_type = bit_lib_get_bits_16(block->data, 52, 4); @@ -55,10 +244,11 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + card_validator = bit_lib_get_bits_16(block->data, 205, 16); //422 + card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 uint8_t card_benefit_code = bit_lib_get_bits(block->data, 72, 8); //124 uint32_t card_rfu1 = bit_lib_get_bits_32(block->data, 80, 32); //rfu1 uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 - card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 177, 12); //403 uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 189, 16); //402 uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 @@ -71,7 +261,6 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* uint16_t card_use_with_date = bit_lib_get_bits_16(block->data, 189, 16); //205 uint8_t card_route = bit_lib_get_bits(block->data, 205, 1); //424 uint16_t card_validator1 = bit_lib_get_bits_16(block->data, 206, 15); //422.1 - card_validator = bit_lib_get_bits_16(block->data, 205, 16); //422 uint16_t card_total_trips = bit_lib_get_bits_16(block->data, 221, 16); //331 uint8_t card_write_enabled = bit_lib_get_bits(block->data, 237, 1); //write_enabled uint8_t card_rfu2 = bit_lib_get_bits(block->data, 238, 2); //rfu2 @@ -138,13 +327,13 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + card_blank_type = bit_lib_get_bits_16(block->data, 80, 10); //121. + card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 uint8_t card_geozone_a = bit_lib_get_bits(block->data, 72, 4); //GeoZoneA uint8_t card_geozone_b = bit_lib_get_bits(block->data, 76, 4); //GeoZoneB - card_blank_type = bit_lib_get_bits_16(block->data, 80, 10); //121. uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 90, 10); //122 uint32_t card_rfu1 = bit_lib_get_bits_16(block->data, 100, 12); //rfu1 uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 - card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 129, 12); //403 uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 141, 16); //402 uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 @@ -216,6 +405,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 @@ -225,7 +415,6 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 168, 8); //321 uint8_t card_validator1 = bit_lib_get_bits(block->data, 193, 2); //422.1 uint16_t card_validator = bit_lib_get_bits_16(block->data, 177, 15); //422 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 uint32_t card_rfu3 = bit_lib_get_bits_32(block->data, 224, 32); //rfu3 FURI_LOG_D( @@ -266,11 +455,12 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_start_trip_minutes = bit_lib_get_bits_32(block->data, 96, 19); //405 + card_minutes_pass = bit_lib_get_bits(block->data, 119, 7); //412 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 64, 12); //311 uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 76, 19); //314 uint8_t card_requires_activation = bit_lib_get_bits(block->data, 95, 1); //301 - card_start_trip_minutes = bit_lib_get_bits_32(block->data, 96, 19); //405 - card_minutes_pass = bit_lib_get_bits(block->data, 119, 7); //412 uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 126, 2); //421.0 uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 128, 8); //321 uint16_t card_validator = bit_lib_get_bits_16(block->data, 136, 16); //422 @@ -278,7 +468,6 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 154, 2); //421.2 uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 156, 2); //421.3 uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 158, 2); //421.4 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 FURI_LOG_D( TAG2, @@ -327,6 +516,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 @@ -334,7 +524,6 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* uint16_t card_rfu2 = bit_lib_get_bits_16(block->data, 153, 13); //rfu2 uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 uint8_t card_transport_type = bit_lib_get_bits(block->data, 251, 2); //421 @@ -388,8 +577,9 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - uint8_t card_rfu1 = bit_lib_get_bits(block->data, 56, 8); //rfu1 card_use_before_date = bit_lib_get_bits_16(block->data, 64, 16); //202 + card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 + uint8_t card_rfu1 = bit_lib_get_bits(block->data, 56, 8); //rfu1 uint16_t card_valid_for_time = bit_lib_get_bits_16(block->data, 80, 11); //316 uint8_t card_rfu2 = bit_lib_get_bits(block->data, 91, 5); //rfu2 uint16_t card_use_before_date2 = bit_lib_get_bits_16(block->data, 96, 16); //202.2 @@ -405,7 +595,6 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 163, 3); //433 uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 251, 2); //421.2 @@ -464,6 +653,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_validator); break; } + case 0xE1: case 0x1C1: { card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 @@ -473,6 +663,10 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202. card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121. card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 + card_minutes_pass = bit_lib_get_bits(block->data, 185, 8); //412. + card_remaining_funds = bit_lib_get_bits_32(block->data, 196, 19) / 100; //322 + card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 144, 16); //402 uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 160, 11); //403 uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 171, 2); //421.1 @@ -480,12 +674,8 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 177, 1); //432 uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 178, 1); //431 uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 179, 3); //433 - card_minutes_pass = bit_lib_get_bits(block->data, 185, 8); //412. - card_remaining_funds = bit_lib_get_bits_32(block->data, 196, 19) / 100; //322 uint8_t card_fare_trip = bit_lib_get_bits(block->data, 215, 2); //441 - card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 uint8_t card_zoo = bit_lib_get_bits(block->data, 218, 1); //zoo - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -531,29 +721,30 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_validator); break; } + case 0xE2: case 0x1C2: { card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 card_use_before_date = bit_lib_get_bits_16(block->data, 71, 16); //202. card_blank_type = bit_lib_get_bits_16(block->data, 87, 10); //121. + card_validator = bit_lib_get_bits_16(block->data, 177, 16); //422 + card_minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412. + card_blocked = bit_lib_get_bits(block->data, 217, 1); //303 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 97, 16); //311 uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 113, 9); //302 uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 131, 20); //314 - card_minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412. uint8_t card_transport_type = bit_lib_get_bits(block->data, 163, 2); //421 uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 165, 1); //431 uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 166, 1); //432 uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 167, 10); //321 - card_validator = bit_lib_get_bits_16(block->data, 177, 16); //422 uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 196, 20); //404 uint8_t card_requires_activation = bit_lib_get_bits(block->data, 216, 1); //301 - card_blocked = bit_lib_get_bits(block->data, 217, 1); //303 uint8_t card_extended = bit_lib_get_bits(block->data, 218, 1); //123 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -603,6 +794,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_validator); break; } + case 0xE3: case 0x1C3: { card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 @@ -611,18 +803,18 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121 - card_remaining_funds = bit_lib_get_bits_32(block->data, 188, 22) / 100; //322 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 card_start_trip_minutes = bit_lib_get_bits_32(block->data, 144, 23); //405 - uint8_t card_fare_trip = bit_lib_get_bits(block->data, 210, 2); //441 card_minutes_pass = bit_lib_get_bits(block->data, 171, 7); //412 + card_remaining_funds = bit_lib_get_bits_32(block->data, 188, 22) / 100; //322 + card_blocked = bit_lib_get_bits(block->data, 212, 1); //303 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + uint8_t card_fare_trip = bit_lib_get_bits(block->data, 210, 2); //441 uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 - card_blocked = bit_lib_get_bits(block->data, 212, 1); //303 FURI_LOG_D( TAG2, "Card view: %x, type: %x, number: %lx, layout: %x, layout2: %x, use before date: %x, blank type: %x, remaining funds: %lx, hash: %lx, validator: %x, start trip minutes: %lx, fare trip: %x, minutes pass: %x, transport type flag: %x, transport type1: %x, transport type2: %x, transport type3: %x, transport type4: %x, blocked: %x", @@ -666,32 +858,33 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_validator); break; } + case 0xE4: case 0x1C4: { card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. + card_validator = bit_lib_get_bits_16(block->data, 179, 16); //422 + card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. + card_blocked = bit_lib_get_bits(block->data, 216, 1); //303 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 94, 13); //311 uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 107, 9); //302 uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 116, 10); //304 uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 - card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 169, 10); //321 - card_validator = bit_lib_get_bits_16(block->data, 179, 16); //422 uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 195, 20); //404 uint8_t card_requires_activation = bit_lib_get_bits(block->data, 215, 1); //301 - card_blocked = bit_lib_get_bits(block->data, 216, 1); //303 uint8_t card_extended = bit_lib_get_bits(block->data, 217, 1); //123 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -745,6 +938,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_validator); break; } + case 0xE5: case 0x1C5: { card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 @@ -753,17 +947,17 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 card_use_before_date = bit_lib_get_bits_16(block->data, 61, 13); //202. card_blank_type = bit_lib_get_bits_16(block->data, 74, 10); //121. - uint32_t card_valid_to_time = bit_lib_get_bits_32(block->data, 84, 23); //317 - uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 107, 10); //304 + card_validator = bit_lib_get_bits_16(block->data, 186, 16); //422 card_start_trip_minutes = bit_lib_get_bits_32(block->data, 128, 23); //405 - uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 151, 7); //414 card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. card_remaining_funds = bit_lib_get_bits_32(block->data, 167, 19) / 100; //322 - card_validator = bit_lib_get_bits_16(block->data, 186, 16); //422 card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + uint32_t card_valid_to_time = bit_lib_get_bits_32(block->data, 84, 23); //317 + uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 107, 10); //304 + uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 151, 7); //414 uint16_t card_route = bit_lib_get_bits_16(block->data, 204, 12); //424 uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 216, 7); //433 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -808,27 +1002,28 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_validator); break; } + case 0xE6: case 0x1C6: { card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. + card_validator = bit_lib_get_bits_16(block->data, 189, 16); //422 + card_minutes_pass = bit_lib_get_bits(block->data, 175, 7); //412. + card_blocked = bit_lib_get_bits(block->data, 205, 1); //303 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 uint32_t card_valid_from_date = bit_lib_get_bits_32(block->data, 94, 23); //311 uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 117, 10); //304 uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 148, 20); //404 uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 168, 7); //414 - card_minutes_pass = bit_lib_get_bits(block->data, 175, 7); //412. uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 182, 7); //321 - card_validator = bit_lib_get_bits_16(block->data, 189, 16); //422 - card_blocked = bit_lib_get_bits(block->data, 205, 1); //303 uint8_t card_extended = bit_lib_get_bits(block->data, 206, 1); //123 uint16_t card_route = bit_lib_get_bits_16(block->data, 212, 12); //424 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 FURI_LOG_D( TAG2, @@ -881,6 +1076,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502.2 uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 @@ -894,7 +1090,6 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* uint16_t card_type3 = bit_lib_get_bits_16(block->data, 148, 10); //type3 uint16_t card_app_code4 = bit_lib_get_bits_16(block->data, 168, 10); //app_code4 uint16_t card_type4 = bit_lib_get_bits_16(block->data, 178, 10); //type4 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502.2 FURI_LOG_D( TAG2, @@ -937,10 +1132,10 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 card_layout = bit_lib_get_bits(block->data, 52, 4); //111 + uint16_t card_hash = bit_lib_get_bits_16(block->data, 112, 16); //502.1 uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 - uint16_t card_hash = bit_lib_get_bits_16(block->data, 112, 16); //502.1 FURI_LOG_D( TAG2, From dd9c7a692f25502d5dbdd7b783be7908a900e1d0 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Sun, 18 Feb 2024 23:46:14 +0300 Subject: [PATCH 10/39] Layout E3 refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 256 +++++++++++------- .../nfc/api/mosgortrans/mosgortrans_util.h | 10 +- .../main/nfc/api/nfc_app_api_table_i.h | 7 +- 3 files changed, 171 insertions(+), 102 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 4c123a8b658..e4faac8e119 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -21,19 +21,37 @@ void from_minutes_to_datetime(uint32_t minutes, DateTime* datetime, uint16_t sta } typedef struct { - uint16_t view; - uint16_t type; - uint32_t number; - uint8_t layout; - uint8_t layout2; - uint16_t use_before_date; - uint16_t blank_type; - uint32_t start_trip_minutes; - uint8_t minutes_pass; - uint32_t remaining_funds; - uint16_t validator; - uint8_t blocked; - uint32_t hash; + uint16_t view; //101 + uint16_t type; //102 + uint32_t number; //201 + uint8_t layout; //111 + uint8_t layout2; //112 + uint16_t use_before_date; //202 + uint16_t blank_type; //121 + uint32_t remaining_funds; //322 + uint32_t hash; //502 + uint16_t validator; //422 + uint32_t start_trip_minutes; //405 + uint8_t fare_trip; //441 + uint8_t minutes_pass; //412 + uint8_t transport_type_flag; //421.0 + uint8_t transport_type1; //421.1 + uint8_t transport_type2; //421.2 + uint8_t transport_type3; //421.3 + uint8_t transport_type4; //421.4 + uint8_t blocked; //303 + uint16_t type_of_extended; //122 + uint16_t valid_to_date; //311 + uint16_t activate_during; //302 + uint32_t valid_for_minutes; //314 + uint8_t transport_type; //421 + uint8_t passage_in_metro; //431 + uint8_t transfer_in_metro; //432 + uint16_t remaining_trips; //321 + uint32_t start_trip_neg_minutes; //404 + uint8_t requires_activation; //301 + uint8_t extended; //123 + uint16_t hash1; //501.1 } BlockData; void parse_layout_2(BlockData* data_block, const MfClassicBlock* block) { @@ -115,11 +133,22 @@ void parse_layout_E2(BlockData* data_block, const MfClassicBlock* block) { data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 16); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 87, 10); - data_block->validator = bit_lib_get_bits_16(block->data, 177, 16); - data_block->minutes_pass = bit_lib_get_bits(block->data, 154, 8); - data_block->blocked = bit_lib_get_bits(block->data, 217, 1); - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); + data_block->blank_type = bit_lib_get_bits_16(block->data, 87, 10); //121 + data_block->validator = bit_lib_get_bits_16(block->data, 177, 16); //422 + data_block->minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412 + data_block->blocked = bit_lib_get_bits(block->data, 217, 1); //303 + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + data_block->type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 + data_block->valid_to_date = bit_lib_get_bits_16(block->data, 97, 16); //311 + data_block->activate_during = bit_lib_get_bits_16(block->data, 113, 9); //302 + data_block->valid_for_minutes = bit_lib_get_bits_32(block->data, 131, 20); //314 + data_block->transport_type = bit_lib_get_bits(block->data, 163, 2); //421 + data_block->passage_in_metro = bit_lib_get_bits(block->data, 165, 1); //431 + data_block->transfer_in_metro = bit_lib_get_bits(block->data, 166, 1); //432 + data_block->remaining_trips = bit_lib_get_bits_16(block->data, 167, 10); //321 + data_block->start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 196, 20); //404 + data_block->requires_activation = bit_lib_get_bits(block->data, 216, 1); //301 + data_block->extended = bit_lib_get_bits(block->data, 218, 1); //123 } void parse_layout_E3(BlockData* data_block, const MfClassicBlock* block) { @@ -129,13 +158,19 @@ void parse_layout_E3(BlockData* data_block, const MfClassicBlock* block) { data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 data_block->use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 77, 10); - data_block->validator = bit_lib_get_bits_16(block->data, 128, 16); - data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 144, 23); - data_block->minutes_pass = bit_lib_get_bits(block->data, 171, 7); - data_block->remaining_funds = bit_lib_get_bits_32(block->data, 188, 22); - data_block->blocked = bit_lib_get_bits(block->data, 212, 1); - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); + data_block->blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121 + data_block->remaining_funds = bit_lib_get_bits_32(block->data, 188, 22); //322 + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + data_block->validator = bit_lib_get_bits_16(block->data, 128, 16); //422 + data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 144, 23); //405 + data_block->fare_trip = bit_lib_get_bits(block->data, 210, 2); //441 + data_block->minutes_pass = bit_lib_get_bits(block->data, 171, 7); //412 + data_block->transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 + data_block->transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 + data_block->transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 + data_block->transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 + data_block->transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 + data_block->blocked = bit_lib_get_bits(block->data, 212, 1); //303 } void parse_layout_E4(BlockData* data_block, const MfClassicBlock* block) { @@ -145,11 +180,11 @@ void parse_layout_E4(BlockData* data_block, const MfClassicBlock* block) { data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 84, 10); - data_block->validator = bit_lib_get_bits_16(block->data, 179, 16); - data_block->minutes_pass = bit_lib_get_bits(block->data, 158, 7); - data_block->blocked = bit_lib_get_bits(block->data, 216, 1); - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); + data_block->blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121 + data_block->validator = bit_lib_get_bits_16(block->data, 179, 16); //422 + data_block->minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412 + data_block->blocked = bit_lib_get_bits(block->data, 216, 1); //303 + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 } void parse_layout_E5(BlockData* data_block, const MfClassicBlock* block) { @@ -159,13 +194,13 @@ void parse_layout_E5(BlockData* data_block, const MfClassicBlock* block) { data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 data_block->use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 74, 10); - data_block->validator = bit_lib_get_bits_16(block->data, 186, 16); - data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 128, 23); - data_block->minutes_pass = bit_lib_get_bits(block->data, 158, 7); - data_block->remaining_funds = bit_lib_get_bits_32(block->data, 167, 19); - data_block->blocked = bit_lib_get_bits(block->data, 202, 1); - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); + data_block->blank_type = bit_lib_get_bits_16(block->data, 74, 10); //121 + data_block->validator = bit_lib_get_bits_16(block->data, 186, 16); //422 + data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 128, 23); //405 + data_block->minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412 + data_block->remaining_funds = bit_lib_get_bits_32(block->data, 167, 19); //322 + data_block->blocked = bit_lib_get_bits(block->data, 202, 1); //303 + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 } void parse_layout_E6(BlockData* data_block, const MfClassicBlock* block) { @@ -175,11 +210,11 @@ void parse_layout_E6(BlockData* data_block, const MfClassicBlock* block) { data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 84, 10); - data_block->validator = bit_lib_get_bits_16(block->data, 189, 16); - data_block->minutes_pass = bit_lib_get_bits(block->data, 175, 7); - data_block->blocked = bit_lib_get_bits(block->data, 205, 1); - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); + data_block->blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121 + data_block->validator = bit_lib_get_bits_16(block->data, 189, 16); //422 + data_block->minutes_pass = bit_lib_get_bits(block->data, 175, 7); //412 + data_block->blocked = bit_lib_get_bits(block->data, 205, 1); //303 + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 } void parse_layout_FCB(BlockData* data_block, const MfClassicBlock* block) { @@ -187,15 +222,15 @@ void parse_layout_FCB(BlockData* data_block, const MfClassicBlock* block) { data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 } void parse_layout_F0B(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); - data_block->layout = bit_lib_get_bits(block->data, 52, 4); - data_block->hash = bit_lib_get_bits_32(block->data, 112, 16); + data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 + data_block->hash1 = bit_lib_get_bits_32(block->data, 112, 16); //501.1 } bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result) { @@ -796,66 +831,87 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* } case 0xE3: case 0x1C3: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 - card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121 - card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 - card_start_trip_minutes = bit_lib_get_bits_32(block->data, 144, 23); //405 - card_minutes_pass = bit_lib_get_bits(block->data, 171, 7); //412 - card_remaining_funds = bit_lib_get_bits_32(block->data, 188, 22) / 100; //322 - card_blocked = bit_lib_get_bits(block->data, 212, 1); //303 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 - uint8_t card_fare_trip = bit_lib_get_bits(block->data, 210, 2); //441 - uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 - FURI_LOG_D( - TAG2, - "Card view: %x, type: %x, number: %lx, layout: %x, layout2: %x, use before date: %x, blank type: %x, remaining funds: %lx, hash: %lx, validator: %x, start trip minutes: %lx, fare trip: %x, minutes pass: %x, transport type flag: %x, transport type1: %x, transport type2: %x, transport type3: %x, transport type4: %x, blocked: %x", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_use_before_date, - card_blank_type, - card_remaining_funds, - card_hash, - card_validator, - card_start_trip_minutes, - card_fare_trip, - card_minutes_pass, - card_transport_type_flag, - card_transport_type1, - card_transport_type2, - card_transport_type3, - card_transport_type4, - card_blocked); + parse_layout_E3(&data_block, block); + // number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + // use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - - DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); - furi_string_printf( + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nBalance: %ld rub\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, + "Valid for: %02d.%02d.%04d\n", card_use_before_date_s.day, card_use_before_date_s.month, - card_use_before_date_s.year, - card_remaining_funds, + card_use_before_date_s.year); + // remaining_funds + furi_string_cat_printf(result, "Balance: %ld rub\n", data_block.remaining_funds); + // start_trip_minutes + DateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(data_block.start_trip_minutes, &card_start_trip_minutes_s, 2016); + furi_string_cat_printf( + result, + "Trip from: %02d.%02d.%04d %02d:%02d\n", card_start_trip_minutes_s.day, card_start_trip_minutes_s.month, card_start_trip_minutes_s.year, card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); + card_start_trip_minutes_s.minute); + // transport + FuriString* transport = furi_string_alloc(); + switch(data_block.transport_type_flag) { + case 0: + furi_string_cat(transport, ""); + break; + case 1: + uint8_t transport_type = + (data_block.transport_type1 || data_block.transport_type2 || + data_block.transport_type3 || data_block.transport_type4); + switch(transport_type) { + case 0: + furi_string_cat(transport, ""); + break; + case 1: + furi_string_cat(transport, "Metro"); + break; + case 2: + furi_string_cat(transport, "Monorail"); + break; + case 3: + furi_string_cat(transport, "MCC"); + break; + default: + break; + } + break; + case 2: + furi_string_cat(transport, "Ground"); + break; + default: + furi_string_cat(transport, "Unknown"); + break; + } + furi_string_cat_printf(result, "Transport: %s\n", furi_string_get_cstr(transport)); + // validator + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); + // fare + FuriString* fare = furi_string_alloc(); + switch(data_block.fare_trip) { + case 0: + furi_string_cat(fare, ""); + break; + case 1: + furi_string_cat(fare, "Single"); + break; + case 2: + furi_string_cat(fare, "90 minutes"); + break; + default: + furi_string_cat(fare, "Unknown"); + break; + } + furi_string_cat_printf(result, "\nFare: %s", furi_string_get_cstr(fare)); + furi_string_free(fare); + furi_string_free(transport); break; } case 0xE4: diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.h b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h index 413729ce8ef..b364e0e8111 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.h +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h @@ -7,6 +7,14 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #define TAG2 "Mosgortrans" -bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result); \ No newline at end of file +bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/applications/main/nfc/api/nfc_app_api_table_i.h b/applications/main/nfc/api/nfc_app_api_table_i.h index 08bff072eae..bf0e926ee67 100644 --- a/applications/main/nfc/api/nfc_app_api_table_i.h +++ b/applications/main/nfc/api/nfc_app_api_table_i.h @@ -1,4 +1,5 @@ #include "gallagher/gallagher_util.h" +#include "mosgortrans/mosgortrans_util.h" /* * A list of app's private functions and objects to expose for plugins. @@ -10,4 +11,8 @@ static constexpr auto nfc_app_api_table = sort(create_array_t( gallagher_deobfuscate_and_parse_credential, void, (GallagherCredential * credential, const uint8_t* cardholder_data_obfuscated)), - API_VARIABLE(GALLAGHER_CARDAX_ASCII, const uint8_t*))); + API_VARIABLE(GALLAGHER_CARDAX_ASCII, const uint8_t*), + API_METHOD( + mosgortrans_parse_transport_block, + bool, + (const MfClassicBlock* block, FuriString* result)))); From a31ba574c58f1a79f89b2bf7666d2b450921fb03 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 00:52:07 +0300 Subject: [PATCH 11/39] Layout E4 refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 222 +++++++++--------- 1 file changed, 113 insertions(+), 109 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index e4faac8e119..082811a1829 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -42,6 +42,7 @@ typedef struct { uint8_t blocked; //303 uint16_t type_of_extended; //122 uint16_t valid_to_date; //311 + uint16_t valid_from_date; //311 uint16_t activate_during; //302 uint32_t valid_for_minutes; //314 uint8_t transport_type; //421 @@ -52,6 +53,8 @@ typedef struct { uint8_t requires_activation; //301 uint8_t extended; //123 uint16_t hash1; //501.1 + uint16_t extension_counter; //304 + uint8_t card_extended; //123 } BlockData; void parse_layout_2(BlockData* data_block, const MfClassicBlock* block) { @@ -132,23 +135,23 @@ void parse_layout_E2(BlockData* data_block, const MfClassicBlock* block) { data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + data_block->type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 16); //202 data_block->blank_type = bit_lib_get_bits_16(block->data, 87, 10); //121 - data_block->validator = bit_lib_get_bits_16(block->data, 177, 16); //422 - data_block->minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412 - data_block->blocked = bit_lib_get_bits(block->data, 217, 1); //303 - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 - data_block->type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 - data_block->valid_to_date = bit_lib_get_bits_16(block->data, 97, 16); //311 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 97, 16); //311 data_block->activate_during = bit_lib_get_bits_16(block->data, 113, 9); //302 data_block->valid_for_minutes = bit_lib_get_bits_32(block->data, 131, 20); //314 + data_block->minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412 data_block->transport_type = bit_lib_get_bits(block->data, 163, 2); //421 data_block->passage_in_metro = bit_lib_get_bits(block->data, 165, 1); //431 data_block->transfer_in_metro = bit_lib_get_bits(block->data, 166, 1); //432 data_block->remaining_trips = bit_lib_get_bits_16(block->data, 167, 10); //321 + data_block->validator = bit_lib_get_bits_16(block->data, 177, 16); //422 data_block->start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 196, 20); //404 data_block->requires_activation = bit_lib_get_bits(block->data, 216, 1); //301 + data_block->blocked = bit_lib_get_bits(block->data, 217, 1); //303 data_block->extended = bit_lib_get_bits(block->data, 218, 1); //123 + data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 } void parse_layout_E3(BlockData* data_block, const MfClassicBlock* block) { @@ -179,11 +182,25 @@ void parse_layout_E4(BlockData* data_block, const MfClassicBlock* block) { data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + data_block->type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202 data_block->blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121 - data_block->validator = bit_lib_get_bits_16(block->data, 179, 16); //422 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 94, 13); //311 + data_block->activate_during = bit_lib_get_bits_16(block->data, 107, 9); //302 + data_block->extension_counter = bit_lib_get_bits_16(block->data, 116, 10); //304 + data_block->valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 data_block->minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412 + data_block->transport_type_flag = bit_lib_get_bits(block->data, 159, 2); //421.0 + data_block->transport_type1 = bit_lib_get_bits(block->data, 161, 2); //421.1 + data_block->transport_type2 = bit_lib_get_bits(block->data, 163, 2); //421.2 + data_block->transport_type3 = bit_lib_get_bits(block->data, 165, 2); //421.3 + data_block->transport_type4 = bit_lib_get_bits(block->data, 167, 2); //421.4 + data_block->remaining_trips = bit_lib_get_bits_16(block->data, 169, 10); //321 + data_block->validator = bit_lib_get_bits_16(block->data, 179, 16); //422 + data_block->start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 195, 20); //404 + data_block->requires_activation = bit_lib_get_bits(block->data, 215, 1); //301 data_block->blocked = bit_lib_get_bits(block->data, 216, 1); //303 + data_block->card_extended = bit_lib_get_bits(block->data, 217, 1); //123 data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 } @@ -233,6 +250,41 @@ void parse_layout_F0B(BlockData* data_block, const MfClassicBlock* block) { data_block->hash1 = bit_lib_get_bits_32(block->data, 112, 16); //501.1 } +void parse_transport_type(BlockData* data_block, FuriString* transport) { + switch(data_block->transport_type_flag) { + case 0: + furi_string_cat(transport, ""); + break; + case 1: + uint8_t transport_type = + (data_block->transport_type1 || data_block->transport_type2 || + data_block->transport_type3 || data_block->transport_type4); + switch(transport_type) { + case 0: + furi_string_cat(transport, ""); + break; + case 1: + furi_string_cat(transport, "Metro"); + break; + case 2: + furi_string_cat(transport, "Monorail"); + break; + case 3: + furi_string_cat(transport, "MCC"); + break; + default: + break; + } + break; + case 2: + furi_string_cat(transport, "Ground"); + break; + default: + furi_string_cat(transport, "Unknown"); + break; + } +} + bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result) { BlockData data_block = {}; const uint16_t valid_departments[] = {0x106, 0x108, 0x10A, 0x10E, 0x110, 0x117}; @@ -858,38 +910,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_start_trip_minutes_s.minute); // transport FuriString* transport = furi_string_alloc(); - switch(data_block.transport_type_flag) { - case 0: - furi_string_cat(transport, ""); - break; - case 1: - uint8_t transport_type = - (data_block.transport_type1 || data_block.transport_type2 || - data_block.transport_type3 || data_block.transport_type4); - switch(transport_type) { - case 0: - furi_string_cat(transport, ""); - break; - case 1: - furi_string_cat(transport, "Metro"); - break; - case 2: - furi_string_cat(transport, "Monorail"); - break; - case 3: - furi_string_cat(transport, "MCC"); - break; - default: - break; - } - break; - case 2: - furi_string_cat(transport, "Ground"); - break; - default: - furi_string_cat(transport, "Unknown"); - break; - } + parse_transport_type(&data_block, transport); furi_string_cat_printf(result, "Transport: %s\n", furi_string_get_cstr(transport)); // validator furi_string_cat_printf(result, "Validator: %05d", data_block.validator); @@ -916,82 +937,65 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* } case 0xE4: case 0x1C4: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. - card_validator = bit_lib_get_bits_16(block->data, 179, 16); //422 - card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. - card_blocked = bit_lib_get_bits(block->data, 216, 1); //303 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 - uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 94, 13); //311 - uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 107, 9); //302 - uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 116, 10); //304 - uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 - uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 169, 10); //321 - uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 195, 20); //404 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 215, 1); //301 - uint8_t card_extended = bit_lib_get_bits(block->data, 217, 1); //123 + parse_layout_E4(&data_block, block); - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %x %x %x %x %x %x %lx %x %x %x %x %x %x %x %x %lx %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_type_of_extended, - card_use_before_date, - card_blank_type, - card_valid_to_date, - card_activate_during, - card_extension_counter, - card_valid_for_minutes, - card_minutes_pass, - card_transport_type_flag, - card_transport_type1, - card_transport_type2, - card_transport_type3, - card_transport_type4, - card_remaining_trips, - card_validator, - card_start_trip_neg_minutes, - card_requires_activation, - card_blocked, - card_extended, - card_hash); + // number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + // use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 2016); + furi_string_cat_printf( + result, + "Valid for: %02d.%02d.%04d\n", + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year); + // remaining_funds + furi_string_cat_printf(result, "Remaining trips: %ld\n", data_block.remaining_funds); + // valid_from_date + DateTime card_use_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_use_from_date_s, 2016); + furi_string_cat_printf( + result, + "Valid from: %02d.%02d.%04d\n", + card_use_from_date_s.day, + card_use_from_date_s.month, + card_use_from_date_s.year); + // valid_to_date + DateTime card_use_to_date_s = {0}; + if(data_block.requires_activation) { + from_days_to_datetime( + data_block.valid_from_date + data_block.activate_during, + &card_use_to_date_s, + 2016); + } else { + from_minutes_to_datetime( + data_block.valid_from_date * 24 * 60 + data_block.valid_for_minutes, + &card_use_to_date_s, + 2016); + } + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_use_to_date_s.day, + card_use_to_date_s.month, + card_use_to_date_s.year); + // trip_number + // furi_string_cat_printf(result, "Trips left: %d", data_block.remaining_trips); + // trip_from DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( - (card_use_before_date + 1) * 24 * 60 + card_valid_for_minutes - - card_start_trip_neg_minutes, + data_block.valid_from_date * 24 * 60 + data_block.valid_for_minutes - + data_block.start_trip_neg_minutes, &card_start_trip_minutes_s, - 2011); //-time - furi_string_printf( - result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); + 2016); + //transport + FuriString* transport = furi_string_alloc(); + parse_transport_type(&data_block, transport); + furi_string_cat_printf(result, "Transport: %s\n", furi_string_get_cstr(transport)); + // validator + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); break; } case 0xE5: From 9aa93cf9f7f029d3c8b276e379d7fd19a5d6bba8 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 12:03:37 +0300 Subject: [PATCH 12/39] Layout 6 refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 187 +++++++++--------- 1 file changed, 96 insertions(+), 91 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 082811a1829..87e8afb10ab 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -23,38 +23,50 @@ void from_minutes_to_datetime(uint32_t minutes, DateTime* datetime, uint16_t sta typedef struct { uint16_t view; //101 uint16_t type; //102 - uint32_t number; //201 uint8_t layout; //111 uint8_t layout2; //112 - uint16_t use_before_date; //202 uint16_t blank_type; //121 + uint16_t type_of_extended; //122 + uint8_t extended; //123 + uint32_t number; //201 + uint16_t use_before_date; //202 + uint8_t requires_activation; //301 + uint16_t activate_during; //302 + uint16_t extension_counter; //304 + uint8_t blocked; //303 + uint16_t valid_from_date; //311 + uint16_t valid_to_date; //312 + uint32_t valid_for_minutes; //314 + uint16_t remaining_trips; //321 uint32_t remaining_funds; //322 - uint32_t hash; //502 - uint16_t validator; //422 + uint16_t total_trips; //331 + uint16_t start_trip_date; //402 + uint16_t start_trip_time; //403 + uint32_t start_trip_neg_minutes; //404 uint32_t start_trip_minutes; //405 - uint8_t fare_trip; //441 uint8_t minutes_pass; //412 + uint8_t transport_type; //421 uint8_t transport_type_flag; //421.0 uint8_t transport_type1; //421.1 uint8_t transport_type2; //421.2 uint8_t transport_type3; //421.3 uint8_t transport_type4; //421.4 - uint8_t blocked; //303 - uint16_t type_of_extended; //122 - uint16_t valid_to_date; //311 - uint16_t valid_from_date; //311 - uint16_t activate_during; //302 - uint32_t valid_for_minutes; //314 - uint8_t transport_type; //421 + uint16_t validator; //422 + uint8_t validator1; //422.1 + uint16_t validator2; //422.2 uint8_t passage_in_metro; //431 uint8_t transfer_in_metro; //432 - uint16_t remaining_trips; //321 - uint32_t start_trip_neg_minutes; //404 - uint8_t requires_activation; //301 - uint8_t extended; //123 - uint16_t hash1; //501.1 - uint16_t extension_counter; //304 - uint8_t card_extended; //123 + uint8_t fare_trip; //441 + uint16_t crc16; //501.1 + uint16_t crc16_2; //501.2 + uint32_t hash; //502 + uint16_t hash1; //502.1 + uint8_t geozone_a; //GeoZoneA + uint8_t geozone_b; //GeoZoneB + uint8_t company; //Company + uint8_t units; //Units + uint16_t rfu1; //rfu1 + } BlockData; void parse_layout_2(BlockData* data_block, const MfClassicBlock* block) { @@ -73,8 +85,25 @@ void parse_layout_6(BlockData* data_block, const MfClassicBlock* block) { data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 data_block->use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 80, 10); - data_block->blocked = bit_lib_get_bits(block->data, 128, 1); + data_block->geozone_a = bit_lib_get_bits(block->data, 72, 4); //GeoZoneA + data_block->geozone_b = bit_lib_get_bits(block->data, 76, 4); //GeoZoneB + data_block->blank_type = bit_lib_get_bits_16(block->data, 80, 10); //121 + data_block->type_of_extended = bit_lib_get_bits_16(block->data, 90, 10); //122 + data_block->rfu1 = bit_lib_get_bits_16(block->data, 100, 12); //rfu1 + data_block->crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 + data_block->blocked = bit_lib_get_bits(block->data, 128, 1); //303 + data_block->start_trip_time = bit_lib_get_bits_16(block->data, 129, 12); //403 + data_block->start_trip_date = bit_lib_get_bits_16(block->data, 141, 16); //402 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 + data_block->valid_to_date = bit_lib_get_bits_16(block->data, 173, 16); //312 + data_block->company = bit_lib_get_bits(block->data, 189, 4); //Company + data_block->validator1 = bit_lib_get_bits(block->data, 193, 4); //422.1 + data_block->remaining_trips = bit_lib_get_bits_16(block->data, 197, 10); //321 + data_block->units = bit_lib_get_bits(block->data, 207, 6); //Units + data_block->validator2 = bit_lib_get_bits_16(block->data, 213, 10); //422.2 + data_block->total_trips = bit_lib_get_bits_16(block->data, 223, 16); //331 + data_block->extended = bit_lib_get_bits(block->data, 239, 1); //123 + data_block->crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 } void parse_layout_8(BlockData* data_block, const MfClassicBlock* block) { @@ -200,7 +229,7 @@ void parse_layout_E4(BlockData* data_block, const MfClassicBlock* block) { data_block->start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 195, 20); //404 data_block->requires_activation = bit_lib_get_bits(block->data, 215, 1); //301 data_block->blocked = bit_lib_get_bits(block->data, 216, 1); //303 - data_block->card_extended = bit_lib_get_bits(block->data, 217, 1); //123 + data_block->extended = bit_lib_get_bits(block->data, 217, 1); //123 data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 } @@ -247,7 +276,7 @@ void parse_layout_F0B(BlockData* data_block, const MfClassicBlock* block) { data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->hash1 = bit_lib_get_bits_32(block->data, 112, 16); //501.1 + data_block->hash1 = bit_lib_get_bits_32(block->data, 112, 16); //502.1 } void parse_transport_type(BlockData* data_block, FuriString* transport) { @@ -409,81 +438,57 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x06: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - card_blank_type = bit_lib_get_bits_16(block->data, 80, 10); //121. - card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 - uint8_t card_geozone_a = bit_lib_get_bits(block->data, 72, 4); //GeoZoneA - uint8_t card_geozone_b = bit_lib_get_bits(block->data, 76, 4); //GeoZoneB - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 90, 10); //122 - uint32_t card_rfu1 = bit_lib_get_bits_16(block->data, 100, 12); //rfu1 - uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 129, 12); //403 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 141, 16); //402 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 - uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 173, 16); //312 - uint16_t card_company = bit_lib_get_bits(block->data, 189, 4); //Company - uint8_t card_validator1 = bit_lib_get_bits(block->data, 193, 4); //422.1 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 197, 10); //321 - uint8_t card_units = bit_lib_get_bits(block->data, 207, 6); //Units - uint16_t card_validator2 = bit_lib_get_bits_16(block->data, 213, 10); //422.2 - uint16_t card_total_trips = bit_lib_get_bits_16(block->data, 223, 16); //331 - uint8_t card_extended = bit_lib_get_bits(block->data, 239, 1); //123 - uint16_t card_crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %x %x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_use_before_date, - card_geozone_a, - card_geozone_b, - card_blank_type, - card_type_of_extended, - card_rfu1, - card_crc16, - card_blocked, - card_start_trip_time, - card_start_trip_date, - card_valid_from_date, - card_valid_by_date, - card_company, - card_validator1, - card_remaining_trips, - card_units, - card_validator2, - card_total_trips, - card_extended, - card_crc16_2); - card_validator = card_validator1 * 1024 + card_validator2; + parse_layout_6(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); - + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); + furi_string_cat_printf( + result, + "Use before: %02d.%02d.%04d\n", + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year); + //remaining_trips + furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + //valid_from_date + DateTime card_valid_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); + furi_string_cat_printf( + result, + "Valid from: %02d.%02d.%04d\n", + card_valid_from_date_s.day, + card_valid_from_date_s.month, + card_valid_from_date_s.year); + //valid_to_date + DateTime card_valid_to_date_s = {0}; + from_days_to_datetime(data_block.valid_to_date, &card_valid_to_date_s, 1992); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_valid_to_date_s.day, + card_valid_to_date_s.month, + card_valid_to_date_s.year); + //trip_number + furi_string_cat_printf(result, "Trip number: %d\n", data_block.total_trips); + //trip_from DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( - (card_start_trip_date) * 24 * 60 + card_start_trip_time, + (data_block.start_trip_date) * 24 * 60 + data_block.start_trip_time, &card_start_trip_minutes_s, 1992); - furi_string_printf( + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips left: %d of %d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_remaining_trips, - card_total_trips, + "Trip from: %02d.%02d.%04d %02d:%02d\n", card_start_trip_minutes_s.day, card_start_trip_minutes_s.month, card_start_trip_minutes_s.year, card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); + card_start_trip_minutes_s.minute); + //validator + furi_string_cat_printf( + result, "Validator: %05d", data_block.validator1 * 1024 + data_block.validator2); break; } case 0x08: { @@ -891,7 +896,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); furi_string_cat_printf( result, - "Valid for: %02d.%02d.%04d\n", + "Use before: %02d.%02d.%04d\n", card_use_before_date_s.day, card_use_before_date_s.month, card_use_before_date_s.year); @@ -946,7 +951,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 2016); furi_string_cat_printf( result, - "Valid for: %02d.%02d.%04d\n", + "Use before: %02d.%02d.%04d\n", card_use_before_date_s.day, card_use_before_date_s.month, card_use_before_date_s.year); @@ -970,7 +975,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* 2016); } else { from_minutes_to_datetime( - data_block.valid_from_date * 24 * 60 + data_block.valid_for_minutes, + data_block.valid_from_date * 24 * 60 + data_block.valid_for_minutes - 1, &card_use_to_date_s, 2016); } From c5b1a0f0b5d908d99b94cacb5002a5f25daa6462 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 12:50:26 +0300 Subject: [PATCH 13/39] Layout E5 refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 321 +++++++++--------- 1 file changed, 156 insertions(+), 165 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 87e8afb10ab..f024c013518 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -37,6 +37,7 @@ typedef struct { uint16_t valid_from_date; //311 uint16_t valid_to_date; //312 uint32_t valid_for_minutes; //314 + uint32_t valid_to_time; //317 uint16_t remaining_trips; //321 uint32_t remaining_funds; //322 uint16_t total_trips; //331 @@ -45,6 +46,7 @@ typedef struct { uint32_t start_trip_neg_minutes; //404 uint32_t start_trip_minutes; //405 uint8_t minutes_pass; //412 + uint8_t metro_ride_with; //414 uint8_t transport_type; //421 uint8_t transport_type_flag; //421.0 uint8_t transport_type1; //421.1 @@ -54,8 +56,10 @@ typedef struct { uint16_t validator; //422 uint8_t validator1; //422.1 uint16_t validator2; //422.2 + uint16_t route; //424 uint8_t passage_in_metro; //431 uint8_t transfer_in_metro; //432 + uint8_t passages_ground_transport; //433 uint8_t fare_trip; //441 uint16_t crc16; //501.1 uint16_t crc16_2; //501.2 @@ -80,30 +84,30 @@ void parse_layout_2(BlockData* data_block, const MfClassicBlock* block) { } void parse_layout_6(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - data_block->geozone_a = bit_lib_get_bits(block->data, 72, 4); //GeoZoneA - data_block->geozone_b = bit_lib_get_bits(block->data, 76, 4); //GeoZoneB - data_block->blank_type = bit_lib_get_bits_16(block->data, 80, 10); //121 - data_block->type_of_extended = bit_lib_get_bits_16(block->data, 90, 10); //122 - data_block->rfu1 = bit_lib_get_bits_16(block->data, 100, 12); //rfu1 - data_block->crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 - data_block->blocked = bit_lib_get_bits(block->data, 128, 1); //303 - data_block->start_trip_time = bit_lib_get_bits_16(block->data, 129, 12); //403 - data_block->start_trip_date = bit_lib_get_bits_16(block->data, 141, 16); //402 - data_block->valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 - data_block->valid_to_date = bit_lib_get_bits_16(block->data, 173, 16); //312 - data_block->company = bit_lib_get_bits(block->data, 189, 4); //Company - data_block->validator1 = bit_lib_get_bits(block->data, 193, 4); //422.1 - data_block->remaining_trips = bit_lib_get_bits_16(block->data, 197, 10); //321 - data_block->units = bit_lib_get_bits(block->data, 207, 6); //Units - data_block->validator2 = bit_lib_get_bits_16(block->data, 213, 10); //422.2 - data_block->total_trips = bit_lib_get_bits_16(block->data, 223, 16); //331 - data_block->extended = bit_lib_get_bits(block->data, 239, 1); //123 - data_block->crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x38, 16); //202 + data_block->geozone_a = bit_lib_get_bits(block->data, 0x48, 4); //GeoZoneA + data_block->geozone_b = bit_lib_get_bits(block->data, 0x4C, 4); //GeoZoneB + data_block->blank_type = bit_lib_get_bits_16(block->data, 0x50, 10); //121 + data_block->type_of_extended = bit_lib_get_bits_16(block->data, 0x5A, 10); //122 + data_block->rfu1 = bit_lib_get_bits_16(block->data, 0x64, 12); //rfu1 + data_block->crc16 = bit_lib_get_bits_16(block->data, 0x70, 16); //501.1 + data_block->blocked = bit_lib_get_bits(block->data, 0x80, 1); //303 + data_block->start_trip_time = bit_lib_get_bits_16(block->data, 0x81, 12); //403 + data_block->start_trip_date = bit_lib_get_bits_16(block->data, 0x8D, 16); //402 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x9D, 16); //311 + data_block->valid_to_date = bit_lib_get_bits_16(block->data, 0xAD, 16); //312 + data_block->company = bit_lib_get_bits(block->data, 0xBD, 4); //Company + data_block->validator1 = bit_lib_get_bits(block->data, 0xC1, 4); //422.1 + data_block->remaining_trips = bit_lib_get_bits_16(block->data, 0xC5, 10); //321 + data_block->units = bit_lib_get_bits(block->data, 0xCF, 6); //Units + data_block->validator2 = bit_lib_get_bits_16(block->data, 0xD5, 10); //422.2 + data_block->total_trips = bit_lib_get_bits_16(block->data, 0xDF, 16); //331 + data_block->extended = bit_lib_get_bits(block->data, 0xEF, 1); //123 + data_block->crc16_2 = bit_lib_get_bits_16(block->data, 0xF0, 16); //501.2 } void parse_layout_8(BlockData* data_block, const MfClassicBlock* block) { @@ -144,109 +148,114 @@ void parse_layout_D(BlockData* data_block, const MfClassicBlock* block) { } void parse_layout_E1(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - data_block->use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 77, 10); - data_block->validator = bit_lib_get_bits_16(block->data, 128, 16); - data_block->minutes_pass = bit_lib_get_bits(block->data, 185, 8); - data_block->remaining_funds = bit_lib_get_bits_32(block->data, 196, 19); - data_block->blocked = bit_lib_get_bits(block->data, 202, 1); - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 0x38, 5); //112 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x3D, 16); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 0x4D, 10); //121 + data_block->validator = bit_lib_get_bits_16(block->data, 0x80, 16); //422 + data_block->minutes_pass = bit_lib_get_bits(block->data, 0xB9, 8); //412 + data_block->remaining_funds = bit_lib_get_bits_32(block->data, 0x4C, 19); //322 + data_block->blocked = bit_lib_get_bits(block->data, 0x9D, 1); //303 + data_block->hash = bit_lib_get_bits_32(block->data, 0xE0, 32); //502 } void parse_layout_E2(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - data_block->type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 - data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 16); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 87, 10); //121 - data_block->valid_from_date = bit_lib_get_bits_16(block->data, 97, 16); //311 - data_block->activate_during = bit_lib_get_bits_16(block->data, 113, 9); //302 - data_block->valid_for_minutes = bit_lib_get_bits_32(block->data, 131, 20); //314 - data_block->minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412 - data_block->transport_type = bit_lib_get_bits(block->data, 163, 2); //421 - data_block->passage_in_metro = bit_lib_get_bits(block->data, 165, 1); //431 - data_block->transfer_in_metro = bit_lib_get_bits(block->data, 166, 1); //432 - data_block->remaining_trips = bit_lib_get_bits_16(block->data, 167, 10); //321 - data_block->validator = bit_lib_get_bits_16(block->data, 177, 16); //422 - data_block->start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 196, 20); //404 - data_block->requires_activation = bit_lib_get_bits(block->data, 216, 1); //301 - data_block->blocked = bit_lib_get_bits(block->data, 217, 1); //303 - data_block->extended = bit_lib_get_bits(block->data, 218, 1); //123 - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 0x38, 5); //112 + data_block->type_of_extended = bit_lib_get_bits_16(block->data, 0x3D, 10); //122 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x47, 16); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 0x57, 10); //121 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x61, 16); //311 + data_block->activate_during = bit_lib_get_bits_16(block->data, 0x71, 9); //302 + data_block->valid_for_minutes = bit_lib_get_bits_32(block->data, 0x83, 20); //314 + data_block->minutes_pass = bit_lib_get_bits(block->data, 0x9A, 8); //412 + data_block->transport_type = bit_lib_get_bits(block->data, 0xA3, 2); //421 + data_block->passage_in_metro = bit_lib_get_bits(block->data, 0xA5, 1); //431 + data_block->transfer_in_metro = bit_lib_get_bits(block->data, 0xA6, 1); //432 + data_block->remaining_trips = bit_lib_get_bits_16(block->data, 0xA7, 10); //321 + data_block->validator = bit_lib_get_bits_16(block->data, 0xB1, 16); //422 + data_block->start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 0xC4, 20); //404 + data_block->requires_activation = bit_lib_get_bits(block->data, 0xD8, 1); //301 + data_block->blocked = bit_lib_get_bits(block->data, 0xD9, 1); //303 + data_block->extended = bit_lib_get_bits(block->data, 0xDA, 1); //123 + data_block->hash = bit_lib_get_bits_32(block->data, 0xE0, 32); //502 } void parse_layout_E3(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 0x38, 5); //112 data_block->use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121 - data_block->remaining_funds = bit_lib_get_bits_32(block->data, 188, 22); //322 + data_block->blank_type = bit_lib_get_bits_16(block->data, 0x4D, 10); //121 + data_block->remaining_funds = bit_lib_get_bits_32(block->data, 0xBC, 22); //322 data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 - data_block->validator = bit_lib_get_bits_16(block->data, 128, 16); //422 - data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 144, 23); //405 - data_block->fare_trip = bit_lib_get_bits(block->data, 210, 2); //441 - data_block->minutes_pass = bit_lib_get_bits(block->data, 171, 7); //412 - data_block->transport_type_flag = bit_lib_get_bits(block->data, 178, 2); //421.0 - data_block->transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 - data_block->transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 - data_block->transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 - data_block->transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 - data_block->blocked = bit_lib_get_bits(block->data, 212, 1); //303 + data_block->validator = bit_lib_get_bits_16(block->data, 0x80, 16); //422 + data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 0x90, 23); //405 + data_block->fare_trip = bit_lib_get_bits(block->data, 0xD2, 2); //441 + data_block->minutes_pass = bit_lib_get_bits(block->data, 0xAB, 7); //412 + data_block->transport_type_flag = bit_lib_get_bits(block->data, 0xB2, 2); //421.0 + data_block->transport_type1 = bit_lib_get_bits(block->data, 0xB4, 2); //421.1 + data_block->transport_type2 = bit_lib_get_bits(block->data, 0xB6, 2); //421.2 + data_block->transport_type3 = bit_lib_get_bits(block->data, 0xB8, 2); //421.3 + data_block->transport_type4 = bit_lib_get_bits(block->data, 0xBA, 2); //421.4 + data_block->blocked = bit_lib_get_bits(block->data, 0xD4, 1); //303 } void parse_layout_E4(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - data_block->type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 - data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121 - data_block->valid_from_date = bit_lib_get_bits_16(block->data, 94, 13); //311 - data_block->activate_during = bit_lib_get_bits_16(block->data, 107, 9); //302 - data_block->extension_counter = bit_lib_get_bits_16(block->data, 116, 10); //304 - data_block->valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 - data_block->minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412 - data_block->transport_type_flag = bit_lib_get_bits(block->data, 159, 2); //421.0 - data_block->transport_type1 = bit_lib_get_bits(block->data, 161, 2); //421.1 - data_block->transport_type2 = bit_lib_get_bits(block->data, 163, 2); //421.2 - data_block->transport_type3 = bit_lib_get_bits(block->data, 165, 2); //421.3 - data_block->transport_type4 = bit_lib_get_bits(block->data, 167, 2); //421.4 - data_block->remaining_trips = bit_lib_get_bits_16(block->data, 169, 10); //321 - data_block->validator = bit_lib_get_bits_16(block->data, 179, 16); //422 - data_block->start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 195, 20); //404 - data_block->requires_activation = bit_lib_get_bits(block->data, 215, 1); //301 - data_block->blocked = bit_lib_get_bits(block->data, 216, 1); //303 - data_block->extended = bit_lib_get_bits(block->data, 217, 1); //123 - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 0x38, 5); //112 + data_block->type_of_extended = bit_lib_get_bits_16(block->data, 0x3D, 10); //122 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x47, 13); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 0x54, 10); //121 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x5E, 13); //311 + data_block->activate_during = bit_lib_get_bits_16(block->data, 0x6B, 9); //302 + data_block->extension_counter = bit_lib_get_bits_16(block->data, 0x74, 10); //304 + data_block->valid_for_minutes = bit_lib_get_bits_32(block->data, 0x80, 20); //314 + data_block->minutes_pass = bit_lib_get_bits(block->data, 0x98, 7); //412 + data_block->transport_type_flag = bit_lib_get_bits(block->data, 0x9F, 2); //421.0 + data_block->transport_type1 = bit_lib_get_bits(block->data, 0xA1, 2); //421.1 + data_block->transport_type2 = bit_lib_get_bits(block->data, 0xA3, 2); //421.2 + data_block->transport_type3 = bit_lib_get_bits(block->data, 0xA5, 2); //421.3 + data_block->transport_type4 = bit_lib_get_bits(block->data, 0xA7, 2); //421.4 + data_block->remaining_trips = bit_lib_get_bits_16(block->data, 0xA9, 10); //321 + data_block->validator = bit_lib_get_bits_16(block->data, 0xB3, 16); //422 + data_block->start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 0xC3, 20); //404 + data_block->requires_activation = bit_lib_get_bits(block->data, 0xD7, 1); //301 + data_block->blocked = bit_lib_get_bits(block->data, 0xD8, 1); //303 + data_block->extended = bit_lib_get_bits(block->data, 0xD9, 1); //123 + data_block->hash = bit_lib_get_bits_32(block->data, 0xE0, 32); //502 } void parse_layout_E5(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - data_block->use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 74, 10); //121 - data_block->validator = bit_lib_get_bits_16(block->data, 186, 16); //422 - data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 128, 23); //405 - data_block->minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412 - data_block->remaining_funds = bit_lib_get_bits_32(block->data, 167, 19); //322 - data_block->blocked = bit_lib_get_bits(block->data, 202, 1); //303 - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 0x38, 5); //112 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x3D, 13); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 0x4A, 10); //121 + data_block->valid_to_time = bit_lib_get_bits_32(block->data, 0x54, 23); //317 + data_block->extension_counter = bit_lib_get_bits_16(block->data, 0x6B, 10); //304 + data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 0x80, 23); //405 + data_block->metro_ride_with = bit_lib_get_bits(block->data, 0x97, 7); //414 + data_block->minutes_pass = bit_lib_get_bits(block->data, 0x9E, 7); //412 + data_block->remaining_funds = bit_lib_get_bits_32(block->data, 0xA7, 19); //322 + data_block->validator = bit_lib_get_bits_16(block->data, 0xBA, 16); //422 + data_block->blocked = bit_lib_get_bits(block->data, 0xCA, 1); //303 + data_block->route = bit_lib_get_bits_16(block->data, 0xCC, 12); //424 + data_block->passages_ground_transport = bit_lib_get_bits(block->data, 0xD8, 7); //433 + data_block->hash = bit_lib_get_bits_32(block->data, 0xE0, 32); //502 } void parse_layout_E6(BlockData* data_block, const MfClassicBlock* block) { @@ -1005,66 +1014,48 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* } case 0xE5: case 0x1C5: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - card_use_before_date = bit_lib_get_bits_16(block->data, 61, 13); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 74, 10); //121. - card_validator = bit_lib_get_bits_16(block->data, 186, 16); //422 - card_start_trip_minutes = bit_lib_get_bits_32(block->data, 128, 23); //405 - card_minutes_pass = bit_lib_get_bits(block->data, 158, 7); //412. - card_remaining_funds = bit_lib_get_bits_32(block->data, 167, 19) / 100; //322 - card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 - uint32_t card_valid_to_time = bit_lib_get_bits_32(block->data, 84, 23); //317 - uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 107, 10); //304 - uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 151, 7); //414 - uint16_t card_route = bit_lib_get_bits_16(block->data, 204, 12); //424 - uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 216, 7); //433 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %x %x %lx %x %lx %x %x %lx %x %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_use_before_date, - card_blank_type, - card_valid_to_time, - card_extension_counter, - card_start_trip_minutes, - card_metro_ride_with, - card_minutes_pass, - card_remaining_funds, - card_validator, - card_blocked, - card_route, - card_passages_ground_transport, - card_hash); + parse_layout_E5(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date DateTime card_use_before_date_s = {0}; - - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); - - DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2019); - furi_string_printf( + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 2019); + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nBalance: %ld rub\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, + "Use before: %02d.%02d.%04d\n", card_use_before_date_s.day, card_use_before_date_s.month, - card_use_before_date_s.year, - card_remaining_funds, + card_use_before_date_s.year); + //remaining_funds + furi_string_cat_printf(result, "Balance: %ld rub\n", data_block.remaining_funds); + //start_trip_minutes + DateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime(data_block.start_trip_minutes, &card_start_trip_minutes_s, 2019); + furi_string_cat_printf( + result, + "Trip from: %02d.%02d.%04d %02d:%02d\n", card_start_trip_minutes_s.day, card_start_trip_minutes_s.month, card_start_trip_minutes_s.year, card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); + card_start_trip_minutes_s.minute); + //start_m_trip_minutes + DateTime card_start_m_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.start_trip_minutes + data_block.metro_ride_with, + &card_start_m_trip_minutes_s, + 2019); + furi_string_cat_printf( + result, + "(M) from: %02d.%02d.%04d %02d:%02d\n", + card_start_m_trip_minutes_s.day, + card_start_m_trip_minutes_s.month, + card_start_m_trip_minutes_s.year, + card_start_m_trip_minutes_s.hour, + card_start_m_trip_minutes_s.minute); + //transport + //validator + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); break; } case 0xE6: From 2f5e654c53d1ba34c4bd3d832b61ef9703696b9f Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 13:14:26 +0300 Subject: [PATCH 14/39] Layout 2 refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 162 +++++++++--------- 1 file changed, 85 insertions(+), 77 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index f024c013518..706f9931c72 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -20,6 +20,16 @@ void from_minutes_to_datetime(uint32_t minutes, DateTime* datetime, uint16_t sta datetime_timestamp_to_datetime(timestamp, datetime); } +void from_seconds_to_datetime(uint32_t seconds, DateTime* datetime, uint16_t start_year) { + uint32_t timestamp = seconds; + DateTime start_datetime = {0}; + start_datetime.year = start_year - 1; + start_datetime.month = 12; + start_datetime.day = 31; + timestamp += datetime_datetime_to_timestamp(&start_datetime); + datetime_timestamp_to_datetime(timestamp, datetime); +} + typedef struct { uint16_t view; //101 uint16_t type; //102 @@ -28,8 +38,10 @@ typedef struct { uint16_t blank_type; //121 uint16_t type_of_extended; //122 uint8_t extended; //123 + uint8_t benefit_code; //124 uint32_t number; //201 uint16_t use_before_date; //202 + uint16_t use_with_date; //205 uint8_t requires_activation; //301 uint16_t activate_during; //302 uint16_t extension_counter; //304 @@ -45,6 +57,7 @@ typedef struct { uint16_t start_trip_time; //403 uint32_t start_trip_neg_minutes; //404 uint32_t start_trip_minutes; //405 + uint8_t start_trip_seconds; //406 uint8_t minutes_pass; //412 uint8_t metro_ride_with; //414 uint8_t transport_type; //421 @@ -70,17 +83,38 @@ typedef struct { uint8_t company; //Company uint8_t units; //Units uint16_t rfu1; //rfu1 + uint8_t rfu2; //rfu2 + uint8_t write_enabled; //write_enabled } BlockData; void parse_layout_2(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); - data_block->layout = bit_lib_get_bits(block->data, 52, 4); - data_block->use_before_date = bit_lib_get_bits_16(block->data, 56, 16); - data_block->validator = bit_lib_get_bits_16(block->data, 205, 16); - data_block->blocked = bit_lib_get_bits(block->data, 128, 1); + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x38, 16); //202 + data_block->benefit_code = bit_lib_get_bits(block->data, 0x48, 8); //124 + data_block->rfu1 = bit_lib_get_bits_32(block->data, 0x50, 32); //rfu1 + data_block->crc16 = bit_lib_get_bits_16(block->data, 0x70, 16); //501.1 + data_block->blocked = bit_lib_get_bits(block->data, 0x80, 1); //303 + data_block->start_trip_time = bit_lib_get_bits_16(block->data, 0x81, 12); //403 + data_block->start_trip_date = bit_lib_get_bits_16(block->data, 0x8D, 16); //402 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x9D, 16); //311 + data_block->valid_to_date = bit_lib_get_bits_16(block->data, 0xAD, 16); //312 + data_block->start_trip_seconds = bit_lib_get_bits(block->data, 0xDB, 6); //406 + data_block->transport_type1 = bit_lib_get_bits(block->data, 0xC3, 2); //421.1 + data_block->transport_type2 = bit_lib_get_bits(block->data, 0xC5, 2); //421.2 + data_block->transport_type3 = bit_lib_get_bits(block->data, 0xC7, 2); //421.3 + data_block->transport_type4 = bit_lib_get_bits(block->data, 0xC9, 2); //421.4 + data_block->use_with_date = bit_lib_get_bits_16(block->data, 0xBD, 16); //205 + data_block->route = bit_lib_get_bits(block->data, 0xCD, 1); //424 + data_block->validator1 = bit_lib_get_bits_16(block->data, 0xCE, 15); //422.1 + data_block->validator = bit_lib_get_bits_16(block->data, 0xCD, 16); + data_block->total_trips = bit_lib_get_bits_16(block->data, 0xDD, 16); //331 + data_block->write_enabled = bit_lib_get_bits(block->data, 0xED, 1); //write_enabled + data_block->rfu2 = bit_lib_get_bits(block->data, 0xEE, 2); //rfu2 + data_block->crc16_2 = bit_lib_get_bits_16(block->data, 0xF0, 16); //501.2 } void parse_layout_6(BlockData* data_block, const MfClassicBlock* block) { @@ -364,86 +398,60 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* switch(layout_type) { case 0x02: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - card_validator = bit_lib_get_bits_16(block->data, 205, 16); //422 - card_blocked = bit_lib_get_bits(block->data, 128, 1); //303 - uint8_t card_benefit_code = bit_lib_get_bits(block->data, 72, 8); //124 - uint32_t card_rfu1 = bit_lib_get_bits_32(block->data, 80, 32); //rfu1 - uint16_t card_crc16 = bit_lib_get_bits_16(block->data, 112, 16); //501.1 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 177, 12); //403 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 189, 16); //402 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 157, 16); //311 - uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 173, 16); //312 - uint8_t card_start_trip_seconds = bit_lib_get_bits(block->data, 189, 6); //406 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 180, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 182, 2); //421.2 - uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 184, 2); //421.3 - uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 186, 2); //421.4 - uint16_t card_use_with_date = bit_lib_get_bits_16(block->data, 189, 16); //205 - uint8_t card_route = bit_lib_get_bits(block->data, 205, 1); //424 - uint16_t card_validator1 = bit_lib_get_bits_16(block->data, 206, 15); //422.1 - uint16_t card_total_trips = bit_lib_get_bits_16(block->data, 221, 16); //331 - uint8_t card_write_enabled = bit_lib_get_bits(block->data, 237, 1); //write_enabled - uint8_t card_rfu2 = bit_lib_get_bits(block->data, 238, 2); //rfu2 - uint16_t card_crc16_2 = bit_lib_get_bits_16(block->data, 240, 16); //501.2 + parse_layout_2(&data_block, block); - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_use_before_date, - card_benefit_code, - card_rfu1, - card_crc16, - card_blocked, - card_start_trip_time, - card_start_trip_date, - card_valid_from_date, - card_valid_by_date, - card_start_trip_seconds, - card_transport_type1, - card_transport_type2, - card_transport_type3, - card_transport_type4, - card_use_with_date, - card_route, - card_validator1, - card_validator, - card_total_trips, - card_write_enabled, - card_rfu2, - card_crc16_2); - if(card_valid_by_date == 0) { + if(data_block.valid_from_date == 0 || data_block.valid_to_date == 0) { return false; } - DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date + DateTime card_use_before_date_s = {0}; + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); + furi_string_cat_printf( + result, + "Use before: %02d.%02d.%04d\n", + card_use_before_date_s.day, + card_use_before_date_s.month, + card_use_before_date_s.year); + //remaining_trips + furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.total_trips); + //valid_from_date + DateTime card_valid_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); + furi_string_cat_printf( + result, + "Valid from: %02d.%02d.%04d\n", + card_valid_from_date_s.day, + card_valid_from_date_s.month, + card_valid_from_date_s.year); + //valid_to_date + DateTime card_valid_to_date_s = {0}; + from_days_to_datetime(data_block.valid_to_date, &card_valid_to_date_s, 1992); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_valid_to_date_s.day, + card_valid_to_date_s.month, + card_valid_to_date_s.year); + //trip_number + furi_string_cat_printf(result, "Trip number: %d\n", data_block.total_trips); + //trip_from DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_start_trip_date) * 24 * 60 + card_start_trip_time, + from_seconds_to_datetime( + data_block.start_trip_date * 24 * 60 * 60 + data_block.start_trip_time * 60 + + data_block.start_trip_seconds, &card_start_trip_minutes_s, 1992); - furi_string_printf( + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips: %d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_total_trips, + "Trip from: %02d.%02d.%04d %02d:%02d", card_start_trip_minutes_s.day, card_start_trip_minutes_s.month, card_start_trip_minutes_s.year, card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); + card_start_trip_minutes_s.minute); break; } case 0x06: { @@ -927,7 +935,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* parse_transport_type(&data_block, transport); furi_string_cat_printf(result, "Transport: %s\n", furi_string_get_cstr(transport)); // validator - furi_string_cat_printf(result, "Validator: %05d", data_block.validator); + furi_string_cat_printf(result, "Validator: %05d\n", data_block.validator); // fare FuriString* fare = furi_string_alloc(); switch(data_block.fare_trip) { @@ -944,7 +952,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* furi_string_cat(fare, "Unknown"); break; } - furi_string_cat_printf(result, "\nFare: %s", furi_string_get_cstr(fare)); + furi_string_cat_printf(result, "Fare: %s", furi_string_get_cstr(fare)); furi_string_free(fare); furi_string_free(transport); break; From 4d52d9f3d171b53fcfb564dfb14ae946c42e4142 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 13:42:11 +0300 Subject: [PATCH 15/39] Layout E5 fix --- .../nfc/api/mosgortrans/mosgortrans_util.c | 81 ++++++++++++------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 706f9931c72..7002af96cca 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -400,10 +400,6 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* case 0x02: { parse_layout_2(&data_block, block); - if(data_block.valid_from_date == 0 || data_block.valid_to_date == 0) { - return false; - } - //number furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); //use_before_date @@ -415,6 +411,11 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.day, card_use_before_date_s.month, card_use_before_date_s.year); + + if(data_block.valid_from_date == 0 || data_block.valid_to_date == 0) { + furi_string_cat(result, "\e#No ticket\n"); + return true; + } //remaining_trips furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.total_trips); //valid_from_date @@ -1035,35 +1036,57 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.month, card_use_before_date_s.year); //remaining_funds - furi_string_cat_printf(result, "Balance: %ld rub\n", data_block.remaining_funds); + furi_string_cat_printf(result, "Balance: %ld rub\n", data_block.remaining_funds / 100); //start_trip_minutes - DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime(data_block.start_trip_minutes, &card_start_trip_minutes_s, 2019); - furi_string_cat_printf( - result, - "Trip from: %02d.%02d.%04d %02d:%02d\n", - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute); + if(data_block.start_trip_minutes) { + DateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.start_trip_minutes, &card_start_trip_minutes_s, 2019); + furi_string_cat_printf( + result, + "Trip from: %02d.%02d.%04d %02d:%02d\n", + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute); + } //start_m_trip_minutes - DateTime card_start_m_trip_minutes_s = {0}; - from_minutes_to_datetime( - data_block.start_trip_minutes + data_block.metro_ride_with, - &card_start_m_trip_minutes_s, - 2019); - furi_string_cat_printf( - result, - "(M) from: %02d.%02d.%04d %02d:%02d\n", - card_start_m_trip_minutes_s.day, - card_start_m_trip_minutes_s.month, - card_start_m_trip_minutes_s.year, - card_start_m_trip_minutes_s.hour, - card_start_m_trip_minutes_s.minute); + if(data_block.metro_ride_with) { + DateTime card_start_m_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.start_trip_minutes + data_block.metro_ride_with, + &card_start_m_trip_minutes_s, + 2019); + furi_string_cat_printf( + result, + "(M) from: %02d.%02d.%04d %02d:%02d\n", + card_start_m_trip_minutes_s.day, + card_start_m_trip_minutes_s.month, + card_start_m_trip_minutes_s.year, + card_start_m_trip_minutes_s.hour, + card_start_m_trip_minutes_s.minute); + } + if(data_block.minutes_pass) { + DateTime card_start_change_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.start_trip_minutes + data_block.minutes_pass, + &card_start_change_trip_minutes_s, + 2019); + furi_string_cat_printf( + result, + "Trip edit: %02d.%02d.%04d %02d:%02d\n", + card_start_change_trip_minutes_s.day, + card_start_change_trip_minutes_s.month, + card_start_change_trip_minutes_s.year, + card_start_change_trip_minutes_s.hour, + card_start_change_trip_minutes_s.minute); + } //transport //validator - furi_string_cat_printf(result, "Validator: %05d", data_block.validator); + if(data_block.validator) { + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); + } break; } case 0xE6: From 3a727ec7746c3d107324ff55a14b418ca1697c79 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 14:36:38 +0300 Subject: [PATCH 16/39] Layout E6 refactored, valid_date need fix --- .../nfc/api/mosgortrans/mosgortrans_util.c | 166 ++++++++++-------- 1 file changed, 92 insertions(+), 74 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 7002af96cca..5efd3669f2e 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -1,6 +1,6 @@ #include "mosgortrans_util.h" -void from_days_to_datetime(uint16_t days, DateTime* datetime, uint16_t start_year) { +void from_days_to_datetime(uint32_t days, DateTime* datetime, uint16_t start_year) { uint32_t timestamp = days * 24 * 60 * 60; DateTime start_datetime = {0}; start_datetime.year = start_year - 1; @@ -46,7 +46,7 @@ typedef struct { uint16_t activate_during; //302 uint16_t extension_counter; //304 uint8_t blocked; //303 - uint16_t valid_from_date; //311 + uint32_t valid_from_date; //311 uint16_t valid_to_date; //312 uint32_t valid_for_minutes; //314 uint32_t valid_to_time; //317 @@ -293,17 +293,26 @@ void parse_layout_E5(BlockData* data_block, const MfClassicBlock* block) { } void parse_layout_E6(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - data_block->use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202 - data_block->blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121 - data_block->validator = bit_lib_get_bits_16(block->data, 189, 16); //422 - data_block->minutes_pass = bit_lib_get_bits(block->data, 175, 7); //412 - data_block->blocked = bit_lib_get_bits(block->data, 205, 1); //303 - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->layout2 = bit_lib_get_bits(block->data, 0x38, 5); //112 + data_block->type_of_extended = bit_lib_get_bits_16(block->data, 0x3D, 10); //122 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x47, 13); //202 + data_block->blank_type = bit_lib_get_bits_16(block->data, 0x54, 10); //121 + data_block->valid_from_date = bit_lib_get_bits_32(block->data, 0x5E, 23); //311 + data_block->extension_counter = bit_lib_get_bits_16(block->data, 0x75, 10); //304 + data_block->valid_for_minutes = bit_lib_get_bits_32(block->data, 0x80, 20); //314 + data_block->start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 0x94, 20); //404 + data_block->metro_ride_with = bit_lib_get_bits(block->data, 0xA8, 7); //414 + data_block->minutes_pass = bit_lib_get_bits(block->data, 0xAF, 7); //412 + data_block->remaining_trips = bit_lib_get_bits(block->data, 0xB6, 7); //321 + data_block->validator = bit_lib_get_bits_16(block->data, 0xDB, 16); //422 + data_block->blocked = bit_lib_get_bits(block->data, 0xCD, 1); //303 + data_block->extended = bit_lib_get_bits(block->data, 0xCE, 1); //123 + data_block->route = bit_lib_get_bits_16(block->data, 0xD4, 12); //424 + data_block->hash = bit_lib_get_bits_32(block->data, 0xE0, 32); //502 } void parse_layout_FCB(BlockData* data_block, const MfClassicBlock* block) { @@ -1091,71 +1100,80 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* } case 0xE6: case 0x1C6: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - card_use_before_date = bit_lib_get_bits_16(block->data, 71, 13); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 84, 10); //121. - card_validator = bit_lib_get_bits_16(block->data, 189, 16); //422 - card_minutes_pass = bit_lib_get_bits(block->data, 175, 7); //412. - card_blocked = bit_lib_get_bits(block->data, 205, 1); //303 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 - uint32_t card_valid_from_date = bit_lib_get_bits_32(block->data, 94, 23); //311 - uint16_t card_extension_counter = bit_lib_get_bits_16(block->data, 117, 10); //304 - uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 128, 20); //314 - uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 148, 20); //404 - uint8_t card_metro_ride_with = bit_lib_get_bits(block->data, 168, 7); //414 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 182, 7); //321 - uint8_t card_extended = bit_lib_get_bits(block->data, 206, 1); //123 - uint16_t card_route = bit_lib_get_bits_16(block->data, 212, 12); //424 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %x %x %x %lx %x %lx %lx %x %x %x %x %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_type_of_extended, - card_use_before_date, - card_blank_type, - card_valid_from_date, - card_extension_counter, - card_valid_for_minutes, - card_start_trip_neg_minutes, - card_metro_ride_with, - card_minutes_pass, - card_remaining_trips, - card_validator, - card_blocked, - card_extended, - card_route, - card_hash); + parse_layout_E6(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2019); - - DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - card_valid_from_date + card_valid_for_minutes - card_start_trip_neg_minutes, - &card_start_trip_minutes_s, - 2019); //-time - furi_string_printf( + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 2019); + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, + "Use before: %02d.%02d.%04d\n", card_use_before_date_s.day, card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); + card_use_before_date_s.year); + //remaining_trips + furi_string_cat_printf(result, "Trips left: %d\n", data_block.remaining_trips); + //valid_from_date + DateTime card_use_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_use_from_date_s, 2019); + furi_string_cat_printf( + result, + "Valid from: %02d.%02d.%04d\n", + card_use_from_date_s.day, + card_use_from_date_s.month, + card_use_from_date_s.year); + //valid_to_date + DateTime card_use_to_date_s = {0}; + from_minutes_to_datetime( + data_block.valid_from_date * 24 * 60 + data_block.valid_for_minutes - 1, + &card_use_to_date_s, + 2019); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_use_to_date_s.day, + card_use_to_date_s.month, + card_use_to_date_s.year); + //start_trip_minutes + if(data_block.start_trip_neg_minutes) { + DateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.valid_from_date + data_block.valid_for_minutes - + data_block.start_trip_neg_minutes, + &card_start_trip_minutes_s, + 2019); //-time + furi_string_cat_printf( + result, + "Trip from: %02d.%02d.%04d %02d:%02d\n", + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute); + } + //start_trip_m_minutes + if(data_block.metro_ride_with) { + DateTime card_start_trip_m_minutes_s = {0}; + from_minutes_to_datetime( + data_block.valid_from_date + data_block.valid_for_minutes - + data_block.start_trip_neg_minutes + data_block.metro_ride_with, + &card_start_trip_m_minutes_s, + 2019); + furi_string_cat_printf( + result, + "(M) from: %02d.%02d.%04d %02d:%02d\n", + card_start_trip_m_minutes_s.day, + card_start_trip_m_minutes_s.month, + card_start_trip_m_minutes_s.year, + card_start_trip_m_minutes_s.hour, + card_start_trip_m_minutes_s.minute); + } + //transport + //validator + if(data_block.validator) { + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); + } break; } case 0x3CCB: { From 9408f9176367c95e6aaa7ef054667ea14205d61b Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 14:57:41 +0300 Subject: [PATCH 17/39] Layout E6 fix --- applications/main/nfc/api/mosgortrans/mosgortrans_util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 5efd3669f2e..da99c6e283b 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -308,7 +308,7 @@ void parse_layout_E6(BlockData* data_block, const MfClassicBlock* block) { data_block->metro_ride_with = bit_lib_get_bits(block->data, 0xA8, 7); //414 data_block->minutes_pass = bit_lib_get_bits(block->data, 0xAF, 7); //412 data_block->remaining_trips = bit_lib_get_bits(block->data, 0xB6, 7); //321 - data_block->validator = bit_lib_get_bits_16(block->data, 0xDB, 16); //422 + data_block->validator = bit_lib_get_bits_16(block->data, 0xBD, 16); //422 data_block->blocked = bit_lib_get_bits(block->data, 0xCD, 1); //303 data_block->extended = bit_lib_get_bits(block->data, 0xCE, 1); //123 data_block->route = bit_lib_get_bits_16(block->data, 0xD4, 12); //424 @@ -1116,7 +1116,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* furi_string_cat_printf(result, "Trips left: %d\n", data_block.remaining_trips); //valid_from_date DateTime card_use_from_date_s = {0}; - from_days_to_datetime(data_block.valid_from_date, &card_use_from_date_s, 2019); + from_minutes_to_datetime(data_block.valid_from_date, &card_use_from_date_s, 2019); furi_string_cat_printf( result, "Valid from: %02d.%02d.%04d\n", @@ -1126,7 +1126,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* //valid_to_date DateTime card_use_to_date_s = {0}; from_minutes_to_datetime( - data_block.valid_from_date * 24 * 60 + data_block.valid_for_minutes - 1, + data_block.valid_from_date + data_block.valid_for_minutes - 1, &card_use_to_date_s, 2019); furi_string_cat_printf( From 40d2aa483a726c98340f66d1575b5233107d4b71 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 15:29:42 +0300 Subject: [PATCH 18/39] Layout FCB refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 106 ++++++++---------- 1 file changed, 49 insertions(+), 57 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index da99c6e283b..a960ab69bbf 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -78,6 +78,7 @@ typedef struct { uint16_t crc16_2; //501.2 uint32_t hash; //502 uint16_t hash1; //502.1 + uint32_t hash2; //502.2 uint8_t geozone_a; //GeoZoneA uint8_t geozone_b; //GeoZoneB uint8_t company; //Company @@ -85,6 +86,16 @@ typedef struct { uint16_t rfu1; //rfu1 uint8_t rfu2; //rfu2 uint8_t write_enabled; //write_enabled + uint32_t tech_code; //TechCode + uint8_t interval; //Interval + uint16_t app_code1; //AppCode1 + uint16_t app_code2; //AppCode2 + uint16_t app_code3; //AppCode3 + uint16_t app_code4; //AppCode4 + uint16_t type1; //Type1 + uint16_t type2; //Type2 + uint16_t type3; //Type3 + uint16_t type4; //Type4 } BlockData; @@ -316,11 +327,24 @@ void parse_layout_E6(BlockData* data_block, const MfClassicBlock* block) { } void parse_layout_FCB(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->hash = bit_lib_get_bits_32(block->data, 224, 32); //502 + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->tech_code = bit_lib_get_bits_32(block->data, 0x38, 10); //tech_code + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x42, 16); //311 + data_block->valid_to_date = bit_lib_get_bits_16(block->data, 0x52, 16); //312 + data_block->interval = bit_lib_get_bits(block->data, 0x62, 4); //interval + data_block->app_code1 = bit_lib_get_bits_16(block->data, 0x66, 10); //app_code1 + data_block->hash1 = bit_lib_get_bits_16(block->data, 0x70, 16); //502.1 + data_block->type1 = bit_lib_get_bits_16(block->data, 0x80, 10); //type1 + data_block->app_code2 = bit_lib_get_bits_16(block->data, 0x8A, 10); //app_code2 + data_block->type2 = bit_lib_get_bits_16(block->data, 0x94, 10); //type2 + data_block->app_code3 = bit_lib_get_bits_16(block->data, 0x9E, 10); //app_code3 + data_block->type3 = bit_lib_get_bits_16(block->data, 0xA8, 10); //type3 + data_block->app_code4 = bit_lib_get_bits_16(block->data, 0xB2, 10); //app_code4 + data_block->type4 = bit_lib_get_bits_16(block->data, 0xBC, 10); //type4 + data_block->hash2 = bit_lib_get_bits_32(block->data, 0xE0, 32); //502.2 } void parse_layout_F0B(BlockData* data_block, const MfClassicBlock* block) { @@ -1177,59 +1201,27 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x3CCB: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502.2 - uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code - uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 - uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 - uint8_t card_interval = bit_lib_get_bits(block->data, 98, 4); //interval - uint16_t card_app_code1 = bit_lib_get_bits_16(block->data, 102, 16); //app_code1 - uint16_t card_hash1 = bit_lib_get_bits_16(block->data, 112, 16); //502.1 - uint16_t card_type1 = bit_lib_get_bits_16(block->data, 128, 10); //type1 - uint16_t card_app_code2 = bit_lib_get_bits_16(block->data, 138, 10); //app_code2 - uint16_t card_type2 = bit_lib_get_bits_16(block->data, 148, 10); //type2 - uint16_t card_app_code3 = bit_lib_get_bits_16(block->data, 158, 10); //app_code3 - uint16_t card_type3 = bit_lib_get_bits_16(block->data, 148, 10); //type3 - uint16_t card_app_code4 = bit_lib_get_bits_16(block->data, 168, 10); //app_code4 - uint16_t card_type4 = bit_lib_get_bits_16(block->data, 178, 10); //type4 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_tech_code, - card_use_before_date, - card_blank_type, - card_valid_to_minutes, - card_valid_by_date, - card_interval, - card_app_code1, - card_hash1, - card_type1, - card_app_code2, - card_type2, - card_app_code3, - card_type3, - card_app_code4, - card_type4, - card_hash); - DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); - - furi_string_printf( + parse_layout_FCB(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //valid_from_date + DateTime card_use_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_use_from_date_s, 1992); + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_validator); + "Valid from: %02d.%02d.%04d\n", + card_use_from_date_s.day, + card_use_from_date_s.month, + card_use_from_date_s.year); + //valid_to_date + DateTime card_use_to_date_s = {0}; + from_days_to_datetime(data_block.valid_to_date, &card_use_to_date_s, 1992); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_use_to_date_s.day, + card_use_to_date_s.month, + card_use_to_date_s.year); break; } case 0x3C0B: { From ba60283cce12c77f66709e16ab41289fd7280c07 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 15:58:21 +0300 Subject: [PATCH 19/39] Layout F0B refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 64 ++++++++----------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index a960ab69bbf..4d61e986fb3 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -348,11 +348,14 @@ void parse_layout_FCB(BlockData* data_block, const MfClassicBlock* block) { } void parse_layout_F0B(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->hash1 = bit_lib_get_bits_32(block->data, 112, 16); //502.1 + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->tech_code = bit_lib_get_bits_32(block->data, 0x38, 10); //tech_code + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x42, 16); //311 + data_block->valid_to_date = bit_lib_get_bits_16(block->data, 0x52, 16); //312 + data_block->hash1 = bit_lib_get_bits_32(block->data, 0x70, 16); //502.1 } void parse_transport_type(BlockData* data_block, FuriString* transport) { @@ -1225,39 +1228,26 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x3C0B: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - uint16_t card_hash = bit_lib_get_bits_16(block->data, 112, 16); //502.1 - uint16_t card_tech_code = bit_lib_get_bits_32(block->data, 56, 10); //tech_code - uint16_t card_valid_to_minutes = bit_lib_get_bits_16(block->data, 66, 16); //311 - uint16_t card_valid_by_date = bit_lib_get_bits_16(block->data, 82, 16); //312 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_layout, - card_tech_code, - card_use_before_date, - card_blank_type, - card_valid_to_minutes, - card_valid_by_date, - card_hash); - DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_valid_by_date, &card_use_before_date_s, 1992); - - furi_string_printf( + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //valid_from_date + DateTime card_use_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_use_from_date_s, 1992); + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_validator); + "Valid from: %02d.%02d.%04d\n", + card_use_from_date_s.day, + card_use_from_date_s.month, + card_use_from_date_s.year); + //valid_to_date + DateTime card_use_to_date_s = {0}; + from_days_to_datetime(data_block.valid_to_date, &card_use_to_date_s, 1992); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_use_to_date_s.day, + card_use_to_date_s.month, + card_use_to_date_s.year); break; } default: From beb6d83bf56fa05337098f66fa8cf38c06f7f448 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 19:58:04 +0300 Subject: [PATCH 20/39] Layout 8 refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 96 +++++++++---------- 1 file changed, 44 insertions(+), 52 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 4d61e986fb3..13e37094a41 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -48,9 +48,11 @@ typedef struct { uint8_t blocked; //303 uint32_t valid_from_date; //311 uint16_t valid_to_date; //312 + uint8_t valid_for_days; //313 uint32_t valid_for_minutes; //314 uint32_t valid_to_time; //317 uint16_t remaining_trips; //321 + uint8_t remaining_trips1; //321.1 uint32_t remaining_funds; //322 uint16_t total_trips; //331 uint16_t start_trip_date; //402 @@ -85,6 +87,7 @@ typedef struct { uint8_t units; //Units uint16_t rfu1; //rfu1 uint8_t rfu2; //rfu2 + uint32_t rfu3; //rfu3 uint8_t write_enabled; //write_enabled uint32_t tech_code; //TechCode uint8_t interval; //Interval @@ -156,12 +159,22 @@ void parse_layout_6(BlockData* data_block, const MfClassicBlock* block) { } void parse_layout_8(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - data_block->hash = bit_lib_get_bits_32(block->data, 192, 32); + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x38, 16); //202 + data_block->rfu1 = bit_lib_get_bits_64(block->data, 0x48, 56); //rfu1 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x80, 16); //311 + data_block->valid_for_days = bit_lib_get_bits(block->data, 0x90, 8); //313 + data_block->requires_activation = bit_lib_get_bits(block->data, 0x98, 1); //301 + data_block->rfu2 = bit_lib_get_bits(block->data, 0x99, 7); //rfu2 + data_block->remaining_trips1 = bit_lib_get_bits(block->data, 0xA0, 8); //321.1 + data_block->remaining_trips = bit_lib_get_bits(block->data, 0xA8, 8); //321 + data_block->validator1 = bit_lib_get_bits(block->data, 0xB0, 2); //422.1 + data_block->validator = bit_lib_get_bits_16(block->data, 0xB1, 15); //422 + data_block->hash = bit_lib_get_bits_32(block->data, 0xC0, 32); //502 + data_block->rfu3 = bit_lib_get_bits_32(block->data, 0xE0, 32); //rfu3 } void parse_layout_A(BlockData* data_block, const MfClassicBlock* block) { @@ -546,54 +559,33 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x08: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 - uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 - uint8_t card_rfu2 = bit_lib_get_bits(block->data, 153, 7); //rfu2 - uint8_t card_remaining_trips1 = bit_lib_get_bits(block->data, 160, 8); //321.1 - uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 168, 8); //321 - uint8_t card_validator1 = bit_lib_get_bits(block->data, 193, 2); //422.1 - uint16_t card_validator = bit_lib_get_bits_16(block->data, 177, 15); //422 - uint32_t card_rfu3 = bit_lib_get_bits_32(block->data, 224, 32); //rfu3 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %llx %x %x %x %x %x %x %x %x %lx %x %lx", - card_view, - card_type, - card_number, - card_use_before_date, - card_rfu1, - card_valid_from_date, - card_valid_for_days, - card_requires_activation, - card_rfu2, - card_remaining_trips1, - card_remaining_trips, - card_validator1, - card_validator, - card_hash, - card_valid_from_date, - card_rfu3); + parse_layout_8(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - - furi_string_printf( + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); + //remaining_trips + furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + //valid_from_date + DateTime card_valid_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrips left: %d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_remaining_trips, - card_validator); + "Valid from: %02d.%02d.%04d\n", + card_valid_from_date_s.day, + card_valid_from_date_s.month, + card_valid_from_date_s.year); + //valid_to_date + DateTime card_valid_to_date_s = {0}; + from_days_to_datetime( + data_block.valid_from_date + data_block.valid_for_days, &card_valid_to_date_s, 1992); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_valid_to_date_s.day, + card_valid_to_date_s.month, + card_valid_to_date_s.year); break; } case 0x0A: { From 92ad9cb1f837b7c702fa52eb7ce3d96d58545789 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 20:21:47 +0300 Subject: [PATCH 21/39] Layout A refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 147 +++++++++++------- 1 file changed, 88 insertions(+), 59 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 13e37094a41..bc6c74bfb29 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -178,13 +178,23 @@ void parse_layout_8(BlockData* data_block, const MfClassicBlock* block) { } void parse_layout_A(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 96, 19); - data_block->minutes_pass = bit_lib_get_bits(block->data, 119, 7); - data_block->hash = bit_lib_get_bits_32(block->data, 192, 32); + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x40, 12); //311 + data_block->valid_for_minutes = bit_lib_get_bits_32(block->data, 0x4C, 19); //314 + data_block->requires_activation = bit_lib_get_bits(block->data, 0x5F, 1); //301 + data_block->start_trip_minutes = bit_lib_get_bits_32(block->data, 0x60, 19); //405 + data_block->minutes_pass = bit_lib_get_bits(block->data, 0x77, 7); //412 + data_block->transport_type_flag = bit_lib_get_bits(block->data, 0x7E, 2); //421.0 + data_block->remaining_trips = bit_lib_get_bits(block->data, 0x80, 8); //321 + data_block->validator = bit_lib_get_bits_16(block->data, 0x88, 16); //422 + data_block->transport_type1 = bit_lib_get_bits(block->data, 0x98, 2); //421.1 + data_block->transport_type2 = bit_lib_get_bits(block->data, 0x9A, 2); //421.2 + data_block->transport_type3 = bit_lib_get_bits(block->data, 0x9C, 2); //421.3 + data_block->transport_type4 = bit_lib_get_bits(block->data, 0x9E, 2); //421.4 + data_block->hash = bit_lib_get_bits_32(block->data, 0xC0, 32); //502 } void parse_layout_C(BlockData* data_block, const MfClassicBlock* block) { @@ -589,63 +599,82 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x0A: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_start_trip_minutes = bit_lib_get_bits_32(block->data, 96, 19); //405 - card_minutes_pass = bit_lib_get_bits(block->data, 119, 7); //412 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 64, 12); //311 - uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 76, 19); //314 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 95, 1); //301 - uint8_t card_transport_type_flag = bit_lib_get_bits(block->data, 126, 2); //421.0 - uint8_t card_remaining_trips = bit_lib_get_bits(block->data, 128, 8); //321 - uint16_t card_validator = bit_lib_get_bits_16(block->data, 136, 16); //422 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 152, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 154, 2); //421.2 - uint8_t card_transport_type3 = bit_lib_get_bits(block->data, 156, 2); //421.3 - uint8_t card_transport_type4 = bit_lib_get_bits(block->data, 158, 2); //421.4 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %lx %x %lx %x %x %x %x %x %x %x %x %lx", - card_view, - card_type, - card_number, - card_use_before_date, - card_valid_from_date, - card_valid_for_minutes, - card_requires_activation, - card_start_trip_minutes, - card_minutes_pass, - card_transport_type_flag, - card_remaining_trips, - card_validator, - card_transport_type1, - card_transport_type2, - card_transport_type3, - card_transport_type4, - card_hash); + parse_layout_A(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); - - DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 2016); - furi_string_printf( + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", - card_number, + "Use before: %02d.%02d.%04d\n", card_use_before_date_s.day, card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_remaining_trips, - card_validator); + card_use_before_date_s.year); + //remaining_trips + furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + //valid_from_date + DateTime card_valid_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 2016); + furi_string_cat_printf( + result, + "Valid from: %02d.%02d.%04d\n", + card_valid_from_date_s.day, + card_valid_from_date_s.month, + card_valid_from_date_s.year); + //valid_to_date + DateTime card_valid_to_date_s = {0}; + from_minutes_to_datetime( + data_block.valid_from_date * 24 * 60 + data_block.valid_for_minutes - 1, + &card_valid_to_date_s, + 2016); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_valid_to_date_s.day, + card_valid_to_date_s.month, + card_valid_to_date_s.year); + //trip_from + if(data_block.start_trip_minutes) { + DateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.valid_from_date * 24 * 60 + data_block.start_trip_minutes, + &card_start_trip_minutes_s, + 2016); + furi_string_cat_printf( + result, + "Trip from: %02d.%02d.%04d %02d:%02d\n", + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute); + } + //trip_switch + if(data_block.minutes_pass) { + DateTime card_start_switch_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.valid_from_date * 24 * 60 + data_block.start_trip_minutes + + data_block.minutes_pass, + &card_start_switch_trip_minutes_s, + 2016); + furi_string_cat_printf( + result, + "Trip switch: %02d.%02d.%04d %02d:%02d\n", + card_start_switch_trip_minutes_s.day, + card_start_switch_trip_minutes_s.month, + card_start_switch_trip_minutes_s.year, + card_start_switch_trip_minutes_s.hour, + card_start_switch_trip_minutes_s.minute); + } + //transport + FuriString* transport = furi_string_alloc(); + parse_transport_type(&data_block, transport); + furi_string_cat_printf(result, "Transport: %s\n", furi_string_get_cstr(transport)); + //validator + if(data_block.validator) { + furi_string_cat_printf(result, "Validator: %05d\n", data_block.validator); + } break; } case 0x0C: { From 218bf032171c6d0196788bd2f2a64f6cd52efbdc Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 20:38:40 +0300 Subject: [PATCH 22/39] Layout C refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 124 +++++++++--------- 1 file changed, 59 insertions(+), 65 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index bc6c74bfb29..ce4cbbe1813 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -85,8 +85,8 @@ typedef struct { uint8_t geozone_b; //GeoZoneB uint8_t company; //Company uint8_t units; //Units - uint16_t rfu1; //rfu1 - uint8_t rfu2; //rfu2 + uint64_t rfu1; //rfu1 + uint16_t rfu2; //rfu2 uint32_t rfu3; //rfu3 uint8_t write_enabled; //write_enabled uint32_t tech_code; //TechCode @@ -198,12 +198,24 @@ void parse_layout_A(BlockData* data_block, const MfClassicBlock* block) { } void parse_layout_C(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - data_block->hash = bit_lib_get_bits_32(block->data, 192, 32); + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x38, 16); //202 + data_block->rfu1 = bit_lib_get_bits_64(block->data, 0x48, 56); //rfu1 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x80, 16); //311 + data_block->valid_for_days = bit_lib_get_bits(block->data, 0x90, 8); //313 + data_block->requires_activation = bit_lib_get_bits(block->data, 0x98, 1); //301 + data_block->rfu2 = bit_lib_get_bits_16(block->data, 0x99, 13); //rfu2 + data_block->remaining_trips = bit_lib_get_bits_16(block->data, 0xA6, 10); //321 + data_block->validator = bit_lib_get_bits_16(block->data, 0xB0, 16); //422 + data_block->hash = bit_lib_get_bits_32(block->data, 0xC0, 32); //502 + data_block->start_trip_date = bit_lib_get_bits_16(block->data, 0xE0, 16); //402 + data_block->start_trip_time = bit_lib_get_bits_16(block->data, 0xF0, 11); //403 + data_block->transport_type = bit_lib_get_bits(block->data, 0xFB, 2); //421 + data_block->rfu3 = bit_lib_get_bits(block->data, 0xFD, 2); //rfu3 + data_block->transfer_in_metro = bit_lib_get_bits(block->data, 0xFF, 1); //432 } void parse_layout_D(BlockData* data_block, const MfClassicBlock* block) { @@ -678,65 +690,47 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x0C: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_use_before_date = bit_lib_get_bits_16(block->data, 56, 16); //202 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 - uint64_t card_rfu1 = bit_lib_get_bits_64(block->data, 72, 56); //rfu1 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 - uint16_t card_rfu2 = bit_lib_get_bits_16(block->data, 153, 13); //rfu2 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 - uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 - uint8_t card_transport_type = bit_lib_get_bits(block->data, 251, 2); //421 - uint8_t card_rfu3 = bit_lib_get_bits(block->data, 253, 2); //rfu3 - uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 255, 1); //432 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %llx %x %x %x %x %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_use_before_date, - card_rfu1, - card_valid_from_date, - card_valid_for_days, - card_requires_activation, - card_rfu2, - card_remaining_trips, - card_validator, - card_start_trip_date, - card_start_trip_time, - card_transport_type, - card_rfu3, - card_transfer_in_metro); + parse_layout_C(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_start_trip_date) * 24 * 60 + card_start_trip_time, - &card_start_trip_minutes_s, - 1992); - furi_string_printf( + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); + //remaining_trips + furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + //valid_from_date + DateTime card_valid_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", - card_number, - card_use_before_date_s.day, - card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_remaining_trips, - card_validator); + "Valid from: %02d.%02d.%04d\n", + card_valid_from_date_s.day, + card_valid_from_date_s.month, + card_valid_from_date_s.year); + //valid_to_date + DateTime card_valid_to_date_s = {0}; + from_days_to_datetime( + data_block.valid_from_date + data_block.valid_for_days, &card_valid_to_date_s, 1992); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_valid_to_date_s.day, + card_valid_to_date_s.month, + card_valid_to_date_s.year); + //remaining_trips + furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + //trip_from + if(data_block.start_trip_date) { + DateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.start_trip_date * 24 * 60 + data_block.start_trip_time, + &card_start_trip_minutes_s, + 1992); + } + //validator + if(data_block.validator) { + furi_string_cat_printf(result, "Validator: %05d\n", data_block.validator); + } break; } case 0x0D: { From b61063f307f06418d933621009d4c440aa370d22 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 20:58:01 +0300 Subject: [PATCH 23/39] Layout D refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 161 +++++++++--------- 1 file changed, 82 insertions(+), 79 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index ce4cbbe1813..db351fef348 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -41,6 +41,7 @@ typedef struct { uint8_t benefit_code; //124 uint32_t number; //201 uint16_t use_before_date; //202 + uint16_t use_before_date2; //202.2 uint16_t use_with_date; //205 uint8_t requires_activation; //301 uint16_t activate_during; //302 @@ -50,6 +51,8 @@ typedef struct { uint16_t valid_to_date; //312 uint8_t valid_for_days; //313 uint32_t valid_for_minutes; //314 + uint16_t valid_for_time; //316 + uint16_t valid_for_time2; //316.2 uint32_t valid_to_time; //317 uint16_t remaining_trips; //321 uint8_t remaining_trips1; //321.1 @@ -61,6 +64,7 @@ typedef struct { uint32_t start_trip_minutes; //405 uint8_t start_trip_seconds; //406 uint8_t minutes_pass; //412 + uint8_t passage_5_minutes; //413 uint8_t metro_ride_with; //414 uint8_t transport_type; //421 uint8_t transport_type_flag; //421.0 @@ -88,6 +92,8 @@ typedef struct { uint64_t rfu1; //rfu1 uint16_t rfu2; //rfu2 uint32_t rfu3; //rfu3 + uint8_t rfu4; //rfu4 + uint8_t rfu5; //rfu5 uint8_t write_enabled; //write_enabled uint32_t tech_code; //TechCode uint8_t interval; //Interval @@ -219,12 +225,33 @@ void parse_layout_C(BlockData* data_block, const MfClassicBlock* block) { } void parse_layout_D(BlockData* data_block, const MfClassicBlock* block) { - data_block->view = bit_lib_get_bits_16(block->data, 0, 10); //101 - data_block->type = bit_lib_get_bits_16(block->data, 10, 10); //102 - data_block->number = bit_lib_get_bits_32(block->data, 20, 32); //201 - data_block->layout = bit_lib_get_bits(block->data, 52, 4); //111 - data_block->use_before_date = bit_lib_get_bits_16(block->data, 64, 16); //202 - data_block->hash = bit_lib_get_bits_32(block->data, 192, 32); + data_block->view = bit_lib_get_bits_16(block->data, 0x00, 10); //101 + data_block->type = bit_lib_get_bits_16(block->data, 0x0A, 10); //102 + data_block->number = bit_lib_get_bits_32(block->data, 0x14, 32); //201 + data_block->layout = bit_lib_get_bits(block->data, 0x34, 4); //111 + data_block->rfu1 = bit_lib_get_bits(block->data, 0x38, 8); //rfu1 + data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x40, 16); //202 + data_block->valid_for_time = bit_lib_get_bits_16(block->data, 0x50, 11); //316 + data_block->rfu2 = bit_lib_get_bits(block->data, 0x5B, 5); //rfu2 + data_block->use_before_date2 = bit_lib_get_bits_16(block->data, 0x60, 16); //202.2 + data_block->valid_for_time2 = bit_lib_get_bits_16(block->data, 0x70, 11); //316.2 + data_block->rfu3 = bit_lib_get_bits(block->data, 0x7B, 5); //rfu3 + data_block->valid_from_date = bit_lib_get_bits_16(block->data, 0x80, 16); //311 + data_block->valid_for_days = bit_lib_get_bits(block->data, 0x90, 8); //313 + data_block->requires_activation = bit_lib_get_bits(block->data, 0x98, 1); //301 + data_block->rfu4 = bit_lib_get_bits(block->data, 0x99, 2); //rfu4 + data_block->passage_5_minutes = bit_lib_get_bits(block->data, 0x9B, 5); //413 + data_block->transport_type1 = bit_lib_get_bits(block->data, 0xA0, 2); //421.1 + data_block->passage_in_metro = bit_lib_get_bits(block->data, 0xA2, 1); //431 + data_block->passages_ground_transport = bit_lib_get_bits(block->data, 0xA3, 3); //433 + data_block->remaining_trips = bit_lib_get_bits_16(block->data, 0xA6, 10); //321 + data_block->validator = bit_lib_get_bits_16(block->data, 0xB0, 16); //422 + data_block->hash = bit_lib_get_bits_32(block->data, 0xC0, 32); //502 + data_block->start_trip_date = bit_lib_get_bits_16(block->data, 0xE0, 16); //402 + data_block->start_trip_time = bit_lib_get_bits_16(block->data, 0xF0, 11); //403 + data_block->transport_type2 = bit_lib_get_bits(block->data, 0xFB, 2); //421.2 + data_block->rfu5 = bit_lib_get_bits(block->data, 0xFD, 2); //rfu5 + data_block->transfer_in_metro = bit_lib_get_bits(block->data, 0xFF, 1); //432 } void parse_layout_E1(BlockData* data_block, const MfClassicBlock* block) { @@ -734,84 +761,60 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* break; } case 0x0D: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_use_before_date = bit_lib_get_bits_16(block->data, 64, 16); //202 - card_hash = bit_lib_get_bits_32(block->data, 192, 32); //502 - uint8_t card_rfu1 = bit_lib_get_bits(block->data, 56, 8); //rfu1 - uint16_t card_valid_for_time = bit_lib_get_bits_16(block->data, 80, 11); //316 - uint8_t card_rfu2 = bit_lib_get_bits(block->data, 91, 5); //rfu2 - uint16_t card_use_before_date2 = bit_lib_get_bits_16(block->data, 96, 16); //202.2 - uint16_t card_valid_for_time2 = bit_lib_get_bits_16(block->data, 123, 11); //316.2 - uint8_t card_rfu3 = bit_lib_get_bits(block->data, 123, 5); //rfu3 - uint16_t card_valid_from_date = bit_lib_get_bits_16(block->data, 128, 16); //311 - uint8_t card_valid_for_days = bit_lib_get_bits(block->data, 144, 8); //313 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 152, 1); //301 - uint8_t card_rfu4 = bit_lib_get_bits(block->data, 153, 2); //rfu4 - uint8_t card_passage_5_minutes = bit_lib_get_bits(block->data, 155, 5); //413 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 160, 2); //421.1 - uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 162, 1); //431 - uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 163, 3); //433 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 166, 10); //321 - uint16_t card_validator = bit_lib_get_bits_16(block->data, 176, 16); //422 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 224, 16); //402 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 240, 11); //403 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 251, 2); //421.2 - uint8_t card_rfu5 = bit_lib_get_bits(block->data, 253, 2); //rfu5 - uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 255, 1); //432 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", - card_view, - card_type, - card_number, - card_layout, - card_rfu1, - card_use_before_date, - card_valid_for_time, - card_rfu2, - card_use_before_date2, - card_valid_for_time2, - card_rfu3, - card_valid_from_date, - card_valid_for_days, - card_requires_activation, - card_rfu4, - card_passage_5_minutes, - card_transport_type1, - card_passage_in_metro, - card_passages_ground_transport, - card_remaining_trips, - card_validator, - card_start_trip_date, - card_start_trip_time, - card_transport_type2, - card_rfu5, - card_transfer_in_metro); + parse_layout_D(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date DateTime card_use_before_date_s = {0}; from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_start_trip_date) * 24 * 60 + card_start_trip_time, - &card_start_trip_minutes_s, - 1992); - furi_string_printf( + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nTrips left: %d\nValidator: %05d", - card_number, + "Use before: %02d.%02d.%04d\n", card_use_before_date_s.day, card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_remaining_trips, - card_validator); + card_use_before_date_s.year); + //remaining_trips + furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + //valid_from_date + DateTime card_valid_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); + furi_string_cat_printf( + result, + "Valid from: %02d.%02d.%04d\n", + card_valid_from_date_s.day, + card_valid_from_date_s.month, + card_valid_from_date_s.year); + //valid_to_date + DateTime card_valid_to_date_s = {0}; + from_days_to_datetime( + data_block.valid_from_date + data_block.valid_for_days, &card_valid_to_date_s, 1992); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_valid_to_date_s.day, + card_valid_to_date_s.month, + card_valid_to_date_s.year); + //trip_from + if(data_block.start_trip_date) { + DateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.start_trip_date * 24 * 60 + data_block.start_trip_time, + &card_start_trip_minutes_s, + 1992); + } + //trip_switch + if(data_block.passage_5_minutes) { + DateTime card_start_switch_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.start_trip_date * 24 * 60 + data_block.start_trip_time + + data_block.passage_5_minutes, + &card_start_switch_trip_minutes_s, + 1992); + } + //validator + if(data_block.validator) { + furi_string_cat_printf(result, "Validator: %05d\n", data_block.validator); + } break; } case 0xE1: From e4ef65fa3bdf481e01270da88eea7ed3a512deff Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 21:22:43 +0300 Subject: [PATCH 24/39] Layout E1 refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index db351fef348..8bc6923420c 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -105,7 +105,7 @@ typedef struct { uint16_t type2; //Type2 uint16_t type3; //Type3 uint16_t type4; //Type4 - + uint8_t zoo; //zoo } BlockData; void parse_layout_2(BlockData* data_block, const MfClassicBlock* block) { @@ -263,9 +263,18 @@ void parse_layout_E1(BlockData* data_block, const MfClassicBlock* block) { data_block->use_before_date = bit_lib_get_bits_16(block->data, 0x3D, 16); //202 data_block->blank_type = bit_lib_get_bits_16(block->data, 0x4D, 10); //121 data_block->validator = bit_lib_get_bits_16(block->data, 0x80, 16); //422 + data_block->start_trip_date = bit_lib_get_bits_16(block->data, 0x90, 16); //402 + data_block->start_trip_time = bit_lib_get_bits_16(block->data, 0xA0, 11); //403 + data_block->transport_type1 = bit_lib_get_bits(block->data, 0xAB, 2); //421.1 + data_block->transport_type2 = bit_lib_get_bits(block->data, 0xAD, 2); //421.2 + data_block->transfer_in_metro = bit_lib_get_bits(block->data, 0xB1, 1); //432 + data_block->passage_in_metro = bit_lib_get_bits(block->data, 0xB2, 1); //431 + data_block->passages_ground_transport = bit_lib_get_bits(block->data, 0xB3, 3); //433 data_block->minutes_pass = bit_lib_get_bits(block->data, 0xB9, 8); //412 data_block->remaining_funds = bit_lib_get_bits_32(block->data, 0x4C, 19); //322 + data_block->fare_trip = bit_lib_get_bits(block->data, 0xD7, 2); //441 data_block->blocked = bit_lib_get_bits(block->data, 0x9D, 1); //303 + data_block->zoo = bit_lib_get_bits(block->data, 0xDA, 1); //zoo data_block->hash = bit_lib_get_bits_32(block->data, 0xE0, 32); //502 } @@ -422,17 +431,11 @@ void parse_layout_F0B(BlockData* data_block, const MfClassicBlock* block) { void parse_transport_type(BlockData* data_block, FuriString* transport) { switch(data_block->transport_type_flag) { - case 0: - furi_string_cat(transport, ""); - break; case 1: uint8_t transport_type = (data_block->transport_type1 || data_block->transport_type2 || data_block->transport_type3 || data_block->transport_type4); switch(transport_type) { - case 0: - furi_string_cat(transport, ""); - break; case 1: furi_string_cat(transport, "Metro"); break; @@ -443,6 +446,7 @@ void parse_transport_type(BlockData* data_block, FuriString* transport) { furi_string_cat(transport, "MCC"); break; default: + furi_string_cat(transport, "Unknown"); break; } break; @@ -450,7 +454,7 @@ void parse_transport_type(BlockData* data_block, FuriString* transport) { furi_string_cat(transport, "Ground"); break; default: - furi_string_cat(transport, "Unknown"); + furi_string_cat(transport, ""); break; } } @@ -819,70 +823,66 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* } case 0xE1: case 0x1C1: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - card_use_before_date = bit_lib_get_bits_16(block->data, 61, 16); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 77, 10); //121. - card_validator = bit_lib_get_bits_16(block->data, 128, 16); //422 - card_minutes_pass = bit_lib_get_bits(block->data, 185, 8); //412. - card_remaining_funds = bit_lib_get_bits_32(block->data, 196, 19) / 100; //322 - card_blocked = bit_lib_get_bits(block->data, 202, 1); //303 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 - uint16_t card_start_trip_date = bit_lib_get_bits_16(block->data, 144, 16); //402 - uint16_t card_start_trip_time = bit_lib_get_bits_16(block->data, 160, 11); //403 - uint8_t card_transport_type1 = bit_lib_get_bits(block->data, 171, 2); //421.1 - uint8_t card_transport_type2 = bit_lib_get_bits(block->data, 173, 2); //421.2 - uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 177, 1); //432 - uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 178, 1); //431 - uint8_t card_passages_ground_transport = bit_lib_get_bits(block->data, 179, 3); //433 - uint8_t card_fare_trip = bit_lib_get_bits(block->data, 215, 2); //441 - uint8_t card_zoo = bit_lib_get_bits(block->data, 218, 1); //zoo - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %x %x %x %x %x %x %x %x %x %x %x %lx %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_use_before_date, - card_blank_type, - card_validator, - card_start_trip_date, - card_start_trip_time, - card_transport_type1, - card_transport_type2, - card_transfer_in_metro, - card_passage_in_metro, - card_passages_ground_transport, - card_minutes_pass, - card_remaining_funds, - card_fare_trip, - card_blocked, - card_zoo, - card_hash); + parse_layout_E1(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); - - DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime(card_start_trip_minutes, &card_start_trip_minutes_s, 1992); - furi_string_printf( + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, + "Use before: %02d.%02d.%04d\n", card_use_before_date_s.day, card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); + card_use_before_date_s.year); + //remaining_funds + furi_string_cat_printf(result, "Balance: %d rub\n", data_block.remaining_funds / 100); + //trip_from + if(data_block.start_trip_date) { + DateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.start_trip_date * 24 * 60 + data_block.start_trip_time, + &card_start_trip_minutes_s, + 1992); + furi_string_cat_printf( + result, + "Trip from: %02d.%02d.%04d %02d:%02d\n", + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute); + } + //transport + FuriString* transport = furi_string_alloc(); + switch(data_block.transport_type1) { + case 1: + switch(data_block.transport_type2) { + case 1: + furi_string_cat(transport, "Metro"); + break; + case 2: + furi_string_cat(transport, "Monorail"); + break; + default: + furi_string_cat(transport, "Unknown"); + break; + } + case 2: + furi_string_cat(transport, "Ground"); + break; + case 3: + furi_string_cat(transport, "MCC"); + break; + default: + furi_string_cat(transport, ""); + break; + } + furi_string_cat_printf(result, "Transport: %s\n", furi_string_get_cstr(transport)); + //validator + if(data_block.validator) { + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); + } break; } case 0xE2: From 6e31a899aecd5654f3e2a2848aa87536df6a972b Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 21:34:58 +0300 Subject: [PATCH 25/39] Layout E2 refactored --- .../nfc/api/mosgortrans/mosgortrans_util.c | 180 +++++++++++------- 1 file changed, 107 insertions(+), 73 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 8bc6923420c..8601d63469e 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -519,7 +519,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* return true; } //remaining_trips - furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.total_trips); + furi_string_cat_printf(result, "Trips left: %d\n", data_block.total_trips); //valid_from_date DateTime card_valid_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); @@ -571,7 +571,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.month, card_use_before_date_s.year); //remaining_trips - furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + furi_string_cat_printf(result, "Trips left: %d\n", data_block.remaining_trips); //valid_from_date DateTime card_valid_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); @@ -619,7 +619,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* DateTime card_use_before_date_s = {0}; from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); //remaining_trips - furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + furi_string_cat_printf(result, "Trips left: %d\n", data_block.remaining_trips); //valid_from_date DateTime card_valid_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); @@ -655,7 +655,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.month, card_use_before_date_s.year); //remaining_trips - furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + furi_string_cat_printf(result, "Trips left: %d\n", data_block.remaining_trips); //valid_from_date DateTime card_valid_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 2016); @@ -728,7 +728,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* DateTime card_use_before_date_s = {0}; from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); //remaining_trips - furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + furi_string_cat_printf(result, "Trips left: %d\n", data_block.remaining_trips); //valid_from_date DateTime card_valid_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); @@ -749,7 +749,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_valid_to_date_s.month, card_valid_to_date_s.year); //remaining_trips - furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + furi_string_cat_printf(result, "Trips left: %d\n", data_block.remaining_trips); //trip_from if(data_block.start_trip_date) { DateTime card_start_trip_minutes_s = {0}; @@ -778,7 +778,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.month, card_use_before_date_s.year); //remaining_trips - furi_string_cat_printf(result, "Remaining trips: %d\n", data_block.remaining_trips); + furi_string_cat_printf(result, "Trips left: %d\n", data_block.remaining_trips); //valid_from_date DateTime card_valid_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); @@ -887,75 +887,109 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* } case 0xE2: case 0x1C2: { - card_view = bit_lib_get_bits_16(block->data, 0, 10); //101 - card_type = bit_lib_get_bits_16(block->data, 10, 10); //102 - card_number = bit_lib_get_bits_32(block->data, 20, 32); //201 - card_layout = bit_lib_get_bits(block->data, 52, 4); //111 - card_layout2 = bit_lib_get_bits(block->data, 56, 5); //112 - card_use_before_date = bit_lib_get_bits_16(block->data, 71, 16); //202. - card_blank_type = bit_lib_get_bits_16(block->data, 87, 10); //121. - card_validator = bit_lib_get_bits_16(block->data, 177, 16); //422 - card_minutes_pass = bit_lib_get_bits(block->data, 154, 8); //412. - card_blocked = bit_lib_get_bits(block->data, 217, 1); //303 - card_hash = bit_lib_get_bits_32(block->data, 224, 32); //502 - uint16_t card_type_of_extended = bit_lib_get_bits_16(block->data, 61, 10); //122 - uint16_t card_valid_to_date = bit_lib_get_bits_16(block->data, 97, 16); //311 - uint16_t card_activate_during = bit_lib_get_bits_16(block->data, 113, 9); //302 - uint32_t card_valid_for_minutes = bit_lib_get_bits_32(block->data, 131, 20); //314 - uint8_t card_transport_type = bit_lib_get_bits(block->data, 163, 2); //421 - uint8_t card_passage_in_metro = bit_lib_get_bits(block->data, 165, 1); //431 - uint8_t card_transfer_in_metro = bit_lib_get_bits(block->data, 166, 1); //432 - uint16_t card_remaining_trips = bit_lib_get_bits_16(block->data, 167, 10); //321 - uint32_t card_start_trip_neg_minutes = bit_lib_get_bits_32(block->data, 196, 20); //404 - uint8_t card_requires_activation = bit_lib_get_bits(block->data, 216, 1); //301 - uint8_t card_extended = bit_lib_get_bits(block->data, 218, 1); //123 - - FURI_LOG_D( - TAG2, - "%x %x %lx %x %x %x %x %x %x %x %lx %x %x %x %x %x %x %lx %x %x %x %lx", - card_view, - card_type, - card_number, - card_layout, - card_layout2, - card_type_of_extended, - card_use_before_date, - card_blank_type, - card_valid_to_date, - card_activate_during, - card_valid_for_minutes, - card_minutes_pass, - card_transport_type, - card_passage_in_metro, - card_transfer_in_metro, - card_remaining_trips, - card_validator, - card_start_trip_neg_minutes, - card_requires_activation, - card_blocked, - card_extended, - card_hash); + parse_layout_E2(&data_block, block); + //number + furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); + //use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); - - DateTime card_start_trip_minutes_s = {0}; - from_minutes_to_datetime( - (card_valid_to_date) * 24 * 60 + card_valid_for_minutes - card_start_trip_neg_minutes, - &card_start_trip_minutes_s, - 2016); //-time - furi_string_printf( + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); + furi_string_cat_printf( result, - "Number: %010lu\nValid for: %02d.%02d.%04d\nTrip from: %02d.%02d.%04d %02d:%02d\nValidator: %05d", - card_number, + "Use before: %02d.%02d.%04d\n", card_use_before_date_s.day, card_use_before_date_s.month, - card_use_before_date_s.year, - card_start_trip_minutes_s.day, - card_start_trip_minutes_s.month, - card_start_trip_minutes_s.year, - card_start_trip_minutes_s.hour, - card_start_trip_minutes_s.minute, - card_validator); + card_use_before_date_s.year); + //remaining_trips + furi_string_cat_printf(result, "Trips left: %d\n", data_block.remaining_trips); + //valid_from_date + DateTime card_valid_from_date_s = {0}; + from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); + furi_string_cat_printf( + result, + "Valid from: %02d.%02d.%04d\n", + card_valid_from_date_s.day, + card_valid_from_date_s.month, + card_valid_from_date_s.year); + //valid_to_date + if(data_block.activate_during) { + DateTime card_valid_to_date_s = {0}; + from_days_to_datetime( + data_block.valid_from_date + data_block.activate_during, + &card_valid_to_date_s, + 1992); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_valid_to_date_s.day, + card_valid_to_date_s.month, + card_valid_to_date_s.year); + } else { + DateTime card_valid_to_date_s = {0}; + from_minutes_to_datetime( + data_block.valid_from_date * 24 * 60 + data_block.valid_for_minutes - 1, + &card_valid_to_date_s, + 1992); + furi_string_cat_printf( + result, + "Valid to: %02d.%02d.%04d\n", + card_valid_to_date_s.day, + card_valid_to_date_s.month, + card_valid_to_date_s.year); + } + //trip_from + if(data_block.start_trip_neg_minutes) { + DateTime card_start_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.valid_to_date * 24 * 60 + data_block.valid_for_minutes - + data_block.start_trip_neg_minutes, + &card_start_trip_minutes_s, + 1992); //-time + furi_string_cat_printf( + result, + "Trip from: %02d.%02d.%04d %02d:%02d\n", + card_start_trip_minutes_s.day, + card_start_trip_minutes_s.month, + card_start_trip_minutes_s.year, + card_start_trip_minutes_s.hour, + card_start_trip_minutes_s.minute); + } + //trip_switch + if(data_block.minutes_pass) { + DateTime card_start_switch_trip_minutes_s = {0}; + from_minutes_to_datetime( + data_block.valid_from_date * 24 * 60 + data_block.valid_for_minutes - + data_block.start_trip_neg_minutes + data_block.minutes_pass, + &card_start_switch_trip_minutes_s, + 1992); + furi_string_cat_printf( + result, + "Trip switch: %02d.%02d.%04d %02d:%02d\n", + card_start_switch_trip_minutes_s.day, + card_start_switch_trip_minutes_s.month, + card_start_switch_trip_minutes_s.year, + card_start_switch_trip_minutes_s.hour, + card_start_switch_trip_minutes_s.minute); + } + //transport + FuriString* transport = furi_string_alloc(); + switch(data_block.transport_type) { + case 1: + furi_string_cat(transport, "Metro"); + break; + case 2: + furi_string_cat(transport, "Monorail"); + break; + case 3: + furi_string_cat(transport, "Ground"); + break; + default: + furi_string_cat(transport, "Unknown"); + break; + } + //validator + if(data_block.validator) { + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); + } break; } case 0xE3: @@ -1028,7 +1062,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.month, card_use_before_date_s.year); // remaining_funds - furi_string_cat_printf(result, "Remaining trips: %ld\n", data_block.remaining_funds); + furi_string_cat_printf(result, "Trips left: %ld\n", data_block.remaining_funds); // valid_from_date DateTime card_use_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_use_from_date_s, 2016); From 3c8d54a5690fdcf534a54c8a222d44d07f75aea5 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 21:37:16 +0300 Subject: [PATCH 26/39] Fixes --- .../nfc/api/mosgortrans/mosgortrans_util.c | 22 +++---------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 8601d63469e..9dfdf7843c5 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -474,30 +474,13 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* return false; } FURI_LOG_I(TAG2, "Transport departament: %x", transport_departament); - uint16_t layout_type = bit_lib_get_bits_16(block->data, 52, 4); if(layout_type == 0xE) { layout_type = bit_lib_get_bits_16(block->data, 52, 9); } else if(layout_type == 0xF) { layout_type = bit_lib_get_bits_16(block->data, 52, 14); } - FURI_LOG_I(TAG2, "Layout type %x", layout_type); - - uint16_t card_view = 0; - uint16_t card_type = 0; - uint32_t card_number = 0; - uint8_t card_layout = 0; - uint8_t card_layout2 = 0; - uint16_t card_use_before_date = 0; - uint16_t card_blank_type = 0; - uint32_t card_start_trip_minutes = 0; - uint8_t card_minutes_pass = 0; - uint32_t card_remaining_funds = 0; - uint16_t card_validator = 0; - uint8_t card_blocked = 0; - uint32_t card_hash = 0; - switch(layout_type) { case 0x02: { parse_layout_2(&data_block, block); @@ -836,7 +819,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.month, card_use_before_date_s.year); //remaining_funds - furi_string_cat_printf(result, "Balance: %d rub\n", data_block.remaining_funds / 100); + furi_string_cat_printf(result, "Balance: %ld rub\n", data_block.remaining_funds / 100); //trip_from if(data_block.start_trip_date) { DateTime card_start_trip_minutes_s = {0}; @@ -868,6 +851,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* furi_string_cat(transport, "Unknown"); break; } + break; case 2: furi_string_cat(transport, "Ground"); break; @@ -1062,7 +1046,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.month, card_use_before_date_s.year); // remaining_funds - furi_string_cat_printf(result, "Trips left: %ld\n", data_block.remaining_funds); + furi_string_cat_printf(result, "Balance: %ld rub\n", data_block.remaining_funds); // valid_from_date DateTime card_use_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_use_from_date_s, 2016); From c15825e2b8c2b891c13fcf417b832dfefd1e2467 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 21:38:15 +0300 Subject: [PATCH 27/39] Old code cleanup --- applications/main/nfc/api/mosgortrans/mosgortrans_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 9dfdf7843c5..72e45f06bf7 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -630,7 +630,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); //use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 2016); + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 2016); furi_string_cat_printf( result, "Use before: %02d.%02d.%04d\n", @@ -753,7 +753,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); //use_before_date DateTime card_use_before_date_s = {0}; - from_days_to_datetime(card_use_before_date, &card_use_before_date_s, 1992); + from_days_to_datetime(data_block.use_before_date, &card_use_before_date_s, 1992); furi_string_cat_printf( result, "Use before: %02d.%02d.%04d\n", From 5c0db22f8e352e3063ad816c78332b5d484e1b60 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 21:44:34 +0300 Subject: [PATCH 28/39] Memory cleanup --- .../main/nfc/api/mosgortrans/mosgortrans_util.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 72e45f06bf7..822e1ac6fd4 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -484,7 +484,6 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* switch(layout_type) { case 0x02: { parse_layout_2(&data_block, block); - //number furi_string_cat_printf(result, "Number: %010lu\n", data_block.number); //use_before_date @@ -701,6 +700,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* if(data_block.validator) { furi_string_cat_printf(result, "Validator: %05d\n", data_block.validator); } + furi_string_free(transport); break; } case 0x0C: { @@ -743,7 +743,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* } //validator if(data_block.validator) { - furi_string_cat_printf(result, "Validator: %05d\n", data_block.validator); + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); } break; } @@ -800,7 +800,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* } //validator if(data_block.validator) { - furi_string_cat_printf(result, "Validator: %05d\n", data_block.validator); + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); } break; } @@ -867,6 +867,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* if(data_block.validator) { furi_string_cat_printf(result, "Validator: %05d", data_block.validator); } + furi_string_free(transport); break; } case 0xE2: @@ -974,6 +975,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* if(data_block.validator) { furi_string_cat_printf(result, "Validator: %05d", data_block.validator); } + furi_string_free(transport); break; } case 0xE3: @@ -1090,7 +1092,10 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* parse_transport_type(&data_block, transport); furi_string_cat_printf(result, "Transport: %s\n", furi_string_get_cstr(transport)); // validator - furi_string_cat_printf(result, "Validator: %05d", data_block.validator); + if(data_block.validator) { + furi_string_cat_printf(result, "Validator: %05d", data_block.validator); + } + furi_string_free(transport); break; } case 0xE5: @@ -1257,7 +1262,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* from_days_to_datetime(data_block.valid_to_date, &card_use_to_date_s, 1992); furi_string_cat_printf( result, - "Valid to: %02d.%02d.%04d\n", + "Valid to: %02d.%02d.%04d", card_use_to_date_s.day, card_use_to_date_s.month, card_use_to_date_s.year); @@ -1280,7 +1285,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* from_days_to_datetime(data_block.valid_to_date, &card_use_to_date_s, 1992); furi_string_cat_printf( result, - "Valid to: %02d.%02d.%04d\n", + "Valid to: %02d.%02d.%04d", card_use_to_date_s.day, card_use_to_date_s.month, card_use_to_date_s.year); From bdf466e6a1aa990506fb46cca7d92ded8af726ed Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 22:11:05 +0300 Subject: [PATCH 29/39] Unused imports cleanup --- applications/main/nfc/api/mosgortrans/mosgortrans_util.c | 6 ++++-- applications/main/nfc/api/mosgortrans/mosgortrans_util.h | 8 ++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 822e1ac6fd4..4d32103da33 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -1,5 +1,7 @@ #include "mosgortrans_util.h" +#define TAG "Mosgortrans" + void from_days_to_datetime(uint32_t days, DateTime* datetime, uint16_t start_year) { uint32_t timestamp = days * 24 * 60 * 60; DateTime start_datetime = {0}; @@ -473,14 +475,14 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* if(!departament_valid) { return false; } - FURI_LOG_I(TAG2, "Transport departament: %x", transport_departament); + FURI_LOG_I(TAG, "Transport departament: %x", transport_departament); uint16_t layout_type = bit_lib_get_bits_16(block->data, 52, 4); if(layout_type == 0xE) { layout_type = bit_lib_get_bits_16(block->data, 52, 9); } else if(layout_type == 0xF) { layout_type = bit_lib_get_bits_16(block->data, 52, 14); } - FURI_LOG_I(TAG2, "Layout type %x", layout_type); + FURI_LOG_I(TAG, "Layout type %x", layout_type); switch(layout_type) { case 0x02: { parse_layout_2(&data_block, block); diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.h b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h index b364e0e8111..495056b8dce 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.h +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h @@ -1,18 +1,14 @@ #pragma once +#include +#include #include #include -#include -#include -#include -#include #ifdef __cplusplus extern "C" { #endif -#define TAG2 "Mosgortrans" - bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result); #ifdef __cplusplus From 35b074a9a5598ef4c9ce8a6143bf31f68d8e3fb7 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 22:38:39 +0300 Subject: [PATCH 30/39] Keys struct refactor --- .../main/nfc/plugins/supported_cards/troika.c | 113 +++++++++--------- 1 file changed, 56 insertions(+), 57 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index 3837214bbd9..50806e137d3 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -12,7 +12,6 @@ #define TAG "Troika" typedef struct { - uint8_t s; uint64_t a; uint64_t b; } MfClassicKeyPair; @@ -23,65 +22,65 @@ typedef struct { } TroikaCardConfig; static const MfClassicKeyPair troika_1k_keys[] = { - {.s = 0, .a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58}, - {.s = 1, .a = 0xa82607b01c0d, .b = 0x2910989b6880}, - {.s = 2, .a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, - {.s = 3, .a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, - {.s = 4, .a = 0x73068f118c13, .b = 0x2b7f3253fac5}, - {.s = 5, .a = 0xfbc2793d540b, .b = 0xd3a297dc2698}, - {.s = 6, .a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, - {.s = 7, .a = 0xae3d65a3dad4, .b = 0x0f1c63013dba}, - {.s = 8, .a = 0xa73f5dc1d333, .b = 0xe35173494a81}, - {.s = 9, .a = 0x69a32f1c2f19, .b = 0x6b8bd9860763}, - {.s = 10, .a = 0x9becdf3d9273, .b = 0xf8493407799d}, - {.s = 11, .a = 0x08b386463229, .b = 0x5efbaecef46b}, - {.s = 12, .a = 0xcd4c61c26e3d, .b = 0x31c7610de3b0}, - {.s = 13, .a = 0xa82607b01c0d, .b = 0x2910989b6880}, - {.s = 14, .a = 0x0e8f64340ba4, .b = 0x4acec1205d75}, - {.s = 15, .a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0xa0a1a2a3a4a5, .b = 0xfbf225dc5d58}, + {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0x73068f118c13, .b = 0x2b7f3253fac5}, + {.a = 0xfbc2793d540b, .b = 0xd3a297dc2698}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, + {.a = 0xae3d65a3dad4, .b = 0x0f1c63013dba}, + {.a = 0xa73f5dc1d333, .b = 0xe35173494a81}, + {.a = 0x69a32f1c2f19, .b = 0x6b8bd9860763}, + {.a = 0x9becdf3d9273, .b = 0xf8493407799d}, + {.a = 0x08b386463229, .b = 0x5efbaecef46b}, + {.a = 0xcd4c61c26e3d, .b = 0x31c7610de3b0}, + {.a = 0xa82607b01c0d, .b = 0x2910989b6880}, + {.a = 0x0e8f64340ba4, .b = 0x4acec1205d75}, + {.a = 0x2aa05ed1856f, .b = 0xeaac88e5dc99}, }; static const MfClassicKeyPair troika_4k_keys[] = { - {.s = 0, .a = 0xEC29806D9738, .b = 0xFBF225DC5D58}, - {.s = 1, .a = 0xA0A1A2A3A4A5, .b = 0x7DE02A7F6025}, - {.s = 2, .a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, - {.s = 3, .a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, - {.s = 4, .a = 0x73068F118C13, .b = 0x2B7F3253FAC5}, - {.s = 5, .a = 0xFBC2793D540B, .b = 0xD3A297DC2698}, - {.s = 6, .a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, - {.s = 7, .a = 0xAE3D65A3DAD4, .b = 0x0F1C63013DBA}, - {.s = 8, .a = 0xA73F5DC1D333, .b = 0xE35173494A81}, - {.s = 9, .a = 0x69A32F1C2F19, .b = 0x6B8BD9860763}, - {.s = 10, .a = 0x9BECDF3D9273, .b = 0xF8493407799D}, - {.s = 11, .a = 0x08B386463229, .b = 0x5EFBAECEF46B}, - {.s = 12, .a = 0xCD4C61C26E3D, .b = 0x31C7610DE3B0}, - {.s = 13, .a = 0xA82607B01C0D, .b = 0x2910989B6880}, - {.s = 14, .a = 0x0E8F64340BA4, .b = 0x4ACEC1205D75}, - {.s = 15, .a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, - {.s = 16, .a = 0x6B02733BB6EC, .b = 0x7038CD25C408}, - {.s = 17, .a = 0x403D706BA880, .b = 0xB39D19A280DF}, - {.s = 18, .a = 0xC11F4597EFB5, .b = 0x70D901648CB9}, - {.s = 19, .a = 0x0DB520C78C1C, .b = 0x73E5B9D9D3A4}, - {.s = 20, .a = 0x3EBCE0925B2F, .b = 0x372CC880F216}, - {.s = 21, .a = 0x16A27AF45407, .b = 0x9868925175BA}, - {.s = 22, .a = 0xABA208516740, .b = 0xCE26ECB95252}, - {.s = 23, .a = 0xCD64E567ABCD, .b = 0x8F79C4FD8A01}, - {.s = 24, .a = 0x764CD061F1E6, .b = 0xA74332F74994}, - {.s = 25, .a = 0x1CC219E9FEC1, .b = 0xB90DE525CEB6}, - {.s = 26, .a = 0x2FE3CB83EA43, .b = 0xFBA88F109B32}, - {.s = 27, .a = 0x07894FFEC1D6, .b = 0xEFCB0E689DB3}, - {.s = 28, .a = 0x04C297B91308, .b = 0xC8454C154CB5}, - {.s = 29, .a = 0x7A38E3511A38, .b = 0xAB16584C972A}, - {.s = 30, .a = 0x7545DF809202, .b = 0xECF751084A80}, - {.s = 31, .a = 0x5125974CD391, .b = 0xD3EAFB5DF46D}, - {.s = 32, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, - {.s = 33, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, - {.s = 34, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, - {.s = 35, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, - {.s = 36, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, - {.s = 37, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, - {.s = 38, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, - {.s = 39, .a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, + {.a = 0xEC29806D9738, .b = 0xFBF225DC5D58}, //1 + {.a = 0xA0A1A2A3A4A5, .b = 0x7DE02A7F6025}, //2 + {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //3 + {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //4 + {.a = 0x73068F118C13, .b = 0x2B7F3253FAC5}, //5 + {.a = 0xFBC2793D540B, .b = 0xD3A297DC2698}, //6 + {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //7 + {.a = 0xAE3D65A3DAD4, .b = 0x0F1C63013DBA}, //8 + {.a = 0xA73F5DC1D333, .b = 0xE35173494A81}, //9 + {.a = 0x69A32F1C2F19, .b = 0x6B8BD9860763}, //10 + {.a = 0x9BECDF3D9273, .b = 0xF8493407799D}, //11 + {.a = 0x08B386463229, .b = 0x5EFBAECEF46B}, //12 + {.a = 0xCD4C61C26E3D, .b = 0x31C7610DE3B0}, //13 + {.a = 0xA82607B01C0D, .b = 0x2910989B6880}, //14 + {.a = 0x0E8F64340BA4, .b = 0x4ACEC1205D75}, //15 + {.a = 0x2AA05ED1856F, .b = 0xEAAC88E5DC99}, //16 + {.a = 0x6B02733BB6EC, .b = 0x7038CD25C408}, //17 + {.a = 0x403D706BA880, .b = 0xB39D19A280DF}, //18 + {.a = 0xC11F4597EFB5, .b = 0x70D901648CB9}, //19 + {.a = 0x0DB520C78C1C, .b = 0x73E5B9D9D3A4}, //20 + {.a = 0x3EBCE0925B2F, .b = 0x372CC880F216}, //21 + {.a = 0x16A27AF45407, .b = 0x9868925175BA}, //22 + {.a = 0xABA208516740, .b = 0xCE26ECB95252}, //23 + {.a = 0xCD64E567ABCD, .b = 0x8F79C4FD8A01}, //24 + {.a = 0x764CD061F1E6, .b = 0xA74332F74994}, //25 + {.a = 0x1CC219E9FEC1, .b = 0xB90DE525CEB6}, //26 + {.a = 0x2FE3CB83EA43, .b = 0xFBA88F109B32}, //27 + {.a = 0x07894FFEC1D6, .b = 0xEFCB0E689DB3}, //28 + {.a = 0x04C297B91308, .b = 0xC8454C154CB5}, //29 + {.a = 0x7A38E3511A38, .b = 0xAB16584C972A}, //30 + {.a = 0x7545DF809202, .b = 0xECF751084A80}, //31 + {.a = 0x5125974CD391, .b = 0xD3EAFB5DF46D}, //32 + {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, //33 + {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, //34 + {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, //35 + {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, //36 + {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, //37 + {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, //38 + {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, //39 + {.a = 0xFFFFFFFFFFFF, .b = 0xFFFFFFFFFFFF}, //40 }; static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) { From 395884e10a4e29bd225ecc5c38b9a02119baadd7 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 22:41:30 +0300 Subject: [PATCH 31/39] Keys struct refactor --- .../plugins/supported_cards/social_moscow.c | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/social_moscow.c b/applications/main/nfc/plugins/supported_cards/social_moscow.c index 0f4cfd41763..e544d1b3289 100644 --- a/applications/main/nfc/plugins/supported_cards/social_moscow.c +++ b/applications/main/nfc/plugins/supported_cards/social_moscow.c @@ -40,26 +40,46 @@ static const MfClassicKeyPair social_moscow_1k_keys[] = { {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}}; static const MfClassicKeyPair social_moscow_4k_keys[] = { - {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, {.a = 0x2735fc181807, .b = 0xbf23a53c1f63}, - {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, - {.a = 0x73068f118c13, .b = 0x2b7f3253fac5}, {.a = 0x186d8c4b93f9, .b = 0x9f131d8c2057}, - {.a = 0x3a4bba8adaf0, .b = 0x67362d90f973}, {.a = 0x8765b17968a2, .b = 0x6202a38f69e2}, - {.a = 0x40ead80721ce, .b = 0x100533b89331}, {.a = 0x0db5e6523f7c, .b = 0x653a87594079}, - {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, - {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, - {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, - {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, - {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, - {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, + {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, //1 + {.a = 0x2735fc181807, .b = 0xbf23a53c1f63}, //2 + {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, //3 + {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, //4 + {.a = 0x73068f118c13, .b = 0x2b7f3253fac5}, //5 + {.a = 0x186d8c4b93f9, .b = 0x9f131d8c2057}, //6 + {.a = 0x3a4bba8adaf0, .b = 0x67362d90f973}, //7 + {.a = 0x8765b17968a2, .b = 0x6202a38f69e2}, //8 + {.a = 0x40ead80721ce, .b = 0x100533b89331}, //9 + {.a = 0x0db5e6523f7c, .b = 0x653a87594079}, //10 + {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, //11 + {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, //12 + {.a = 0x51119dae5216, .b = 0xd8a274b2e026}, //13 + {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, //14 + {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, //15 + {.a = 0xa0a1a2a3a4a5, .b = 0x7de02a7f6025}, //16 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //17 + {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, //18 + {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, //19 + {.a = 0x2aba9519f574, .b = 0xcb9a1f2d7368}, //20 + {.a = 0x84fd7f7a12b6, .b = 0xc7c0adb3284f}, //21 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //22 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //23 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //24 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //25 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //26 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //27 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //28 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //29 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //30 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //31 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //32 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //33 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //34 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //35 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //36 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //37 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //38 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //39 + {.a = 0xa229e68ad9e5, .b = 0x49c2b5296ef4}, //40 }; static bool social_moscow_get_card_config(SocialMoscowCardConfig* config, MfClassicType type) { From 9a4b4215f4d94de8f2a562022772c3c935427988 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 19 Feb 2024 23:38:04 +0300 Subject: [PATCH 32/39] Layout E1 fix --- applications/main/nfc/api/mosgortrans/mosgortrans_util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 4d32103da33..edbf5737868 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -273,7 +273,7 @@ void parse_layout_E1(BlockData* data_block, const MfClassicBlock* block) { data_block->passage_in_metro = bit_lib_get_bits(block->data, 0xB2, 1); //431 data_block->passages_ground_transport = bit_lib_get_bits(block->data, 0xB3, 3); //433 data_block->minutes_pass = bit_lib_get_bits(block->data, 0xB9, 8); //412 - data_block->remaining_funds = bit_lib_get_bits_32(block->data, 0x4C, 19); //322 + data_block->remaining_funds = bit_lib_get_bits_32(block->data, 0xC4, 19); //322 data_block->fare_trip = bit_lib_get_bits(block->data, 0xD7, 2); //441 data_block->blocked = bit_lib_get_bits(block->data, 0x9D, 1); //303 data_block->zoo = bit_lib_get_bits(block->data, 0xDA, 1); //zoo @@ -503,7 +503,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* return true; } //remaining_trips - furi_string_cat_printf(result, "Trips left: %d\n", data_block.total_trips); + furi_string_cat_printf(result, "Trips: %d\n", data_block.total_trips); //valid_from_date DateTime card_valid_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_valid_from_date_s, 1992); @@ -523,7 +523,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_valid_to_date_s.month, card_valid_to_date_s.year); //trip_number - furi_string_cat_printf(result, "Trip number: %d\n", data_block.total_trips); + furi_string_cat_printf(result, "Trips: %d\n", data_block.total_trips); //trip_from DateTime card_start_trip_minutes_s = {0}; from_seconds_to_datetime( @@ -575,7 +575,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_valid_to_date_s.month, card_valid_to_date_s.year); //trip_number - furi_string_cat_printf(result, "Trip number: %d\n", data_block.total_trips); + furi_string_cat_printf(result, "Trips: %d\n", data_block.total_trips); //trip_from DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime( From e615b52dd15b9b418c8ec283dc68638d3c5b2602 Mon Sep 17 00:00:00 2001 From: assasinfil Date: Mon, 4 Mar 2024 13:25:12 +0300 Subject: [PATCH 33/39] Added debug info for layout and department --- .../main/nfc/api/mosgortrans/mosgortrans_util.c | 10 ++++++++-- .../main/nfc/api/mosgortrans/mosgortrans_util.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index edbf5737868..86c749c3043 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -465,6 +465,9 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* BlockData data_block = {}; const uint16_t valid_departments[] = {0x106, 0x108, 0x10A, 0x10E, 0x110, 0x117}; uint16_t transport_departament = bit_lib_get_bits_16(block->data, 0, 10); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + furi_string_cat_printf(result, "Transport departament: %x\n", transport_departament); + } bool departament_valid = false; for(uint8_t i = 0; i < 6; i++) { if(transport_departament == valid_departments[i]) { @@ -475,14 +478,17 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* if(!departament_valid) { return false; } - FURI_LOG_I(TAG, "Transport departament: %x", transport_departament); + FURI_LOG_D(TAG, "Transport departament: %x", transport_departament); uint16_t layout_type = bit_lib_get_bits_16(block->data, 52, 4); if(layout_type == 0xE) { layout_type = bit_lib_get_bits_16(block->data, 52, 9); } else if(layout_type == 0xF) { layout_type = bit_lib_get_bits_16(block->data, 52, 14); } - FURI_LOG_I(TAG, "Layout type %x", layout_type); + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + furi_string_cat_printf(result, "Layout: %x\n", layout_type); + } + FURI_LOG_D(TAG, "Layout type %x", layout_type); switch(layout_type) { case 0x02: { parse_layout_2(&data_block, block); diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.h b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h index 495056b8dce..e5da8ddeb44 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.h +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h @@ -4,6 +4,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { From 2f6ea2847c87a44766bd4f3a2a6505e78c708a18 Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Tue, 5 Mar 2024 11:40:42 +0900 Subject: [PATCH 34/39] Fix PVS warnings --- applications/main/nfc/plugins/supported_cards/bip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/bip.c b/applications/main/nfc/plugins/supported_cards/bip.c index 211c27cb56c..f6fed6774b1 100644 --- a/applications/main/nfc/plugins/supported_cards/bip.c +++ b/applications/main/nfc/plugins/supported_cards/bip.c @@ -296,8 +296,8 @@ static bool bip_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_printf( parsed_data, "\e#Tarjeta Bip!\n" - "Card Number: %ld\n" - "Balance: $%d (flags %x)\n" + "Card Number: %lu\n" + "Balance: $%hu (flags %hu)\n" "Current Trip Window Ends:\n @", bip_data.card_id, bip_data.balance, From 7797276982488ab937a8a4b8cabb4785f114c9e3 Mon Sep 17 00:00:00 2001 From: Aleksandr Kutuzov Date: Tue, 5 Mar 2024 11:51:23 +0900 Subject: [PATCH 35/39] Fix more PVS warnings --- applications/main/nfc/api/mosgortrans/mosgortrans_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 86c749c3043..f2484a2af56 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -1001,7 +1001,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.month, card_use_before_date_s.year); // remaining_funds - furi_string_cat_printf(result, "Balance: %ld rub\n", data_block.remaining_funds); + furi_string_cat_printf(result, "Balance: %lu rub\n", data_block.remaining_funds); // start_trip_minutes DateTime card_start_trip_minutes_s = {0}; from_minutes_to_datetime(data_block.start_trip_minutes, &card_start_trip_minutes_s, 2016); @@ -1056,7 +1056,7 @@ bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* card_use_before_date_s.month, card_use_before_date_s.year); // remaining_funds - furi_string_cat_printf(result, "Balance: %ld rub\n", data_block.remaining_funds); + furi_string_cat_printf(result, "Balance: %lu rub\n", data_block.remaining_funds); // valid_from_date DateTime card_use_from_date_s = {0}; from_days_to_datetime(data_block.valid_from_date, &card_use_from_date_s, 2016); From 4b9a3f4cd12f43f4fa11a9029f060399e92c0e3c Mon Sep 17 00:00:00 2001 From: assasinfil Date: Wed, 18 Sep 2024 23:33:51 +0300 Subject: [PATCH 36/39] Fix social card parse validation --- applications/main/nfc/plugins/supported_cards/social_moscow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/main/nfc/plugins/supported_cards/social_moscow.c b/applications/main/nfc/plugins/supported_cards/social_moscow.c index e544d1b3289..a899c0005d7 100644 --- a/applications/main/nfc/plugins/supported_cards/social_moscow.c +++ b/applications/main/nfc/plugins/supported_cards/social_moscow.c @@ -227,7 +227,7 @@ static bool social_moscow_parse(const NfcDevice* device, FuriString* parsed_data } furi_string_free(ground_result); furi_string_free(metro_result); - parsed = result1 || result2; + parsed = card_code != 0; } while(false); return parsed; From f4c3f079651d49d0f1ddcc0f9c77f4278233322d Mon Sep 17 00:00:00 2001 From: assasinfil Date: Fri, 20 Sep 2024 12:15:58 +0300 Subject: [PATCH 37/39] Added card number validation --- .../plugins/supported_cards/social_moscow.c | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/social_moscow.c b/applications/main/nfc/plugins/supported_cards/social_moscow.c index a899c0005d7..5838955b4a8 100644 --- a/applications/main/nfc/plugins/supported_cards/social_moscow.c +++ b/applications/main/nfc/plugins/supported_cards/social_moscow.c @@ -171,6 +171,44 @@ static bool social_moscow_read(Nfc* nfc, NfcDevice* device) { return is_read; } +static uint8_t calculate_luhn(uint64_t number) { + // https://en.wikipedia.org/wiki/Luhn_algorithm + // Drop existing check digit to form payload + uint64_t payload = number / 10; + int sum = 0; + int position = 0; + + while(payload > 0) { + int digit = payload % 10; + if(position % 2 == 0) { + digit *= 2; + } + if(digit > 9) { + digit = (digit / 10) + (digit % 10); + } + sum += digit; + payload /= 10; + position++; + } + + return (10 - (sum % 10)) % 10; +} + +static uint64_t hex_num(uint64_t hex) { + uint64_t result = 0; + for(uint8_t i = 0; i < 8; ++i) { + uint8_t half_byte = hex & 0x0F; + uint64_t num = 0; + for(uint8_t j = 0; j < 4; ++j) { + num += (half_byte & 0x1) * (1 << j); + half_byte = half_byte >> 1; + } + result += num * pow(10, i); + hex = hex >> 4; + } + return result; +} + static bool social_moscow_parse(const NfcDevice* device, FuriString* parsed_data) { furi_assert(device); @@ -201,10 +239,19 @@ static bool social_moscow_parse(const NfcDevice* device, FuriString* parsed_data uint8_t year = data->block[60].data[11]; uint8_t month = data->block[60].data[12]; + uint64_t number = hex_num(card_control) + hex_num(card_number) * 10 + + hex_num(card_region) * 10 * 10000000000 + + hex_num(card_code) * 10 * 10000000000 * 100; + + uint8_t luhn = calculate_luhn(number); + if(luhn != card_control) break; + FuriString* metro_result = furi_string_alloc(); FuriString* ground_result = furi_string_alloc(); - bool result1 = mosgortrans_parse_transport_block(&data->block[4], metro_result); - bool result2 = mosgortrans_parse_transport_block(&data->block[16], ground_result); + bool is_metro_data_present = + mosgortrans_parse_transport_block(&data->block[4], metro_result); + bool is_ground_data_present = + mosgortrans_parse_transport_block(&data->block[16], ground_result); furi_string_cat_printf( parsed_data, "\e#Social \ecard\nNumber: %lx %x %llx %x\nOMC: %llx\nValid for: %02x/%02x %02x%02x\n", @@ -217,17 +264,17 @@ static bool social_moscow_parse(const NfcDevice* device, FuriString* parsed_data year, data->block[60].data[13], data->block[60].data[14]); - if(result1) { + if(is_metro_data_present) { furi_string_cat_printf( parsed_data, "\e#Metro\n%s\n", furi_string_get_cstr(metro_result)); } - if(result2) { + if(is_ground_data_present) { furi_string_cat_printf( parsed_data, "\e#Ground\n%s\n", furi_string_get_cstr(ground_result)); } furi_string_free(ground_result); furi_string_free(metro_result); - parsed = card_code != 0; + parsed = true; } while(false); return parsed; @@ -251,4 +298,4 @@ static const FlipperAppPluginDescriptor social_moscow_plugin_descriptor = { /* Plugin entry point - must return a pointer to const descriptor */ const FlipperAppPluginDescriptor* social_moscow_plugin_ep() { return &social_moscow_plugin_descriptor; -} \ No newline at end of file +} From a68bd339739c151d7ac293bd5cd0e769a05a273f Mon Sep 17 00:00:00 2001 From: assasinfil Date: Sat, 21 Sep 2024 22:33:52 +0300 Subject: [PATCH 38/39] Added transport data ui improvements from Astrrra's troyka render func. --- .../nfc/api/mosgortrans/mosgortrans_util.c | 14 ++++++++ .../nfc/api/mosgortrans/mosgortrans_util.h | 5 +++ .../main/nfc/api/nfc_app_api_table_i.h | 7 +++- .../plugins/supported_cards/social_moscow.c | 12 +++---- .../main/nfc/plugins/supported_cards/troika.c | 36 +++++++------------ 5 files changed, 43 insertions(+), 31 deletions(-) diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c index 3138d790b3e..261f24ce00c 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.c +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.c @@ -2,6 +2,20 @@ #define TAG "Mosgortrans" +void render_section_header( + FuriString* str, + const char* name, + uint8_t prefix_separator_cnt, + uint8_t suffix_separator_cnt) { + for(uint8_t i = 0; i < prefix_separator_cnt; i++) { + furi_string_cat_printf(str, ":"); + } + furi_string_cat_printf(str, "[ %s ]", name); + for(uint8_t i = 0; i < suffix_separator_cnt; i++) { + furi_string_cat_printf(str, ":"); + } +} + void from_days_to_datetime(uint32_t days, DateTime* datetime, uint16_t start_year) { uint32_t timestamp = days * 24 * 60 * 60; DateTime start_datetime = {0}; diff --git a/applications/main/nfc/api/mosgortrans/mosgortrans_util.h b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h index 2dc469c45cc..e8cbd7a37d3 100644 --- a/applications/main/nfc/api/mosgortrans/mosgortrans_util.h +++ b/applications/main/nfc/api/mosgortrans/mosgortrans_util.h @@ -10,6 +10,11 @@ extern "C" { #endif +void render_section_header( + FuriString* str, + const char* name, + uint8_t prefix_separator_cnt, + uint8_t suffix_separator_cnt); bool mosgortrans_parse_transport_block(const MfClassicBlock* block, FuriString* result); #ifdef __cplusplus diff --git a/applications/main/nfc/api/nfc_app_api_table_i.h b/applications/main/nfc/api/nfc_app_api_table_i.h index bf0e926ee67..1c79b3c2755 100644 --- a/applications/main/nfc/api/nfc_app_api_table_i.h +++ b/applications/main/nfc/api/nfc_app_api_table_i.h @@ -15,4 +15,9 @@ static constexpr auto nfc_app_api_table = sort(create_array_t( API_METHOD( mosgortrans_parse_transport_block, bool, - (const MfClassicBlock* block, FuriString* result)))); + (const MfClassicBlock* block, FuriString* result)), + API_METHOD( + render_section_header, + void, + (FuriString* str, const char* name, uint8_t prefix_separator_cnt, uint8_t suffix_separator_cnt)) +)); diff --git a/applications/main/nfc/plugins/supported_cards/social_moscow.c b/applications/main/nfc/plugins/supported_cards/social_moscow.c index 5838955b4a8..ed2ee6c1d4e 100644 --- a/applications/main/nfc/plugins/supported_cards/social_moscow.c +++ b/applications/main/nfc/plugins/supported_cards/social_moscow.c @@ -264,13 +264,13 @@ static bool social_moscow_parse(const NfcDevice* device, FuriString* parsed_data year, data->block[60].data[13], data->block[60].data[14]); - if(is_metro_data_present) { - furi_string_cat_printf( - parsed_data, "\e#Metro\n%s\n", furi_string_get_cstr(metro_result)); + if(is_metro_data_present && !furi_string_empty(metro_result)) { + render_section_header(parsed_data, "Metro", 22, 21); + furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(metro_result)); } - if(is_ground_data_present) { - furi_string_cat_printf( - parsed_data, "\e#Ground\n%s\n", furi_string_get_cstr(ground_result)); + if(is_ground_data_present && !furi_string_empty(ground_result)) { + render_section_header(parsed_data, "Ground", 21, 20); + furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(ground_result)); } furi_string_free(ground_result); furi_string_free(metro_result); diff --git a/applications/main/nfc/plugins/supported_cards/troika.c b/applications/main/nfc/plugins/supported_cards/troika.c index 0c93fa59ae0..bd36d40e5bd 100644 --- a/applications/main/nfc/plugins/supported_cards/troika.c +++ b/applications/main/nfc/plugins/supported_cards/troika.c @@ -82,20 +82,6 @@ static const MfClassicKeyPair troika_4k_keys[] = { {.a = 0xBB52F8CCE07F, .b = 0x6B6119752C70}, //40 }; -static void troika_render_section_header( - FuriString* str, - const char* name, - uint8_t prefix_separator_cnt, - uint8_t suffix_separator_cnt) { - for(uint8_t i = 0; i < prefix_separator_cnt; i++) { - furi_string_cat_printf(str, ":"); - } - furi_string_cat_printf(str, "[ %s ]", name); - for(uint8_t i = 0; i < suffix_separator_cnt; i++) { - furi_string_cat_printf(str, ":"); - } -} - static bool troika_get_card_config(TroikaCardConfig* config, MfClassicType type) { bool success = true; @@ -212,23 +198,25 @@ static bool troika_parse(const NfcDevice* device, FuriString* parsed_data) { FuriString* ground_result = furi_string_alloc(); FuriString* tat_result = furi_string_alloc(); - bool result1 = mosgortrans_parse_transport_block(&data->block[32], metro_result); - bool result2 = mosgortrans_parse_transport_block(&data->block[28], ground_result); - bool result3 = mosgortrans_parse_transport_block(&data->block[16], tat_result); + bool is_metro_data_present = + mosgortrans_parse_transport_block(&data->block[32], metro_result); + bool is_ground_data_present = + mosgortrans_parse_transport_block(&data->block[28], ground_result); + bool is_tat_data_present = mosgortrans_parse_transport_block(&data->block[16], tat_result); furi_string_cat_printf(parsed_data, "\e#Troyka card\n"); - if(result1 && !furi_string_empty(metro_result)) { - troika_render_section_header(parsed_data, "Metro", 22, 21); + if(is_metro_data_present && !furi_string_empty(metro_result)) { + render_section_header(parsed_data, "Metro", 22, 21); furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(metro_result)); } - if(result2 && !furi_string_empty(ground_result)) { - troika_render_section_header(parsed_data, "Ediny", 22, 22); + if(is_ground_data_present && !furi_string_empty(ground_result)) { + render_section_header(parsed_data, "Ediny", 22, 22); furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(ground_result)); } - if(result3 && !furi_string_empty(tat_result)) { - troika_render_section_header(parsed_data, "TAT", 24, 23); + if(is_tat_data_present && !furi_string_empty(tat_result)) { + render_section_header(parsed_data, "TAT", 24, 23); furi_string_cat_printf(parsed_data, "%s\n", furi_string_get_cstr(tat_result)); } @@ -236,7 +224,7 @@ static bool troika_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_free(ground_result); furi_string_free(metro_result); - parsed = result1 || result2 || result3; + parsed = is_metro_data_present || is_ground_data_present || is_tat_data_present; } while(false); return parsed; From d5985160c0ad0ff857f333c9f7784604d517899a Mon Sep 17 00:00:00 2001 From: assasinfil Date: Thu, 3 Oct 2024 13:13:20 +0300 Subject: [PATCH 39/39] fbt format --- applications/main/nfc/api/nfc_app_api_table_i.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/applications/main/nfc/api/nfc_app_api_table_i.h b/applications/main/nfc/api/nfc_app_api_table_i.h index 1c79b3c2755..790fa576644 100644 --- a/applications/main/nfc/api/nfc_app_api_table_i.h +++ b/applications/main/nfc/api/nfc_app_api_table_i.h @@ -17,7 +17,9 @@ static constexpr auto nfc_app_api_table = sort(create_array_t( bool, (const MfClassicBlock* block, FuriString* result)), API_METHOD( - render_section_header, - void, - (FuriString* str, const char* name, uint8_t prefix_separator_cnt, uint8_t suffix_separator_cnt)) -)); + render_section_header, + void, + (FuriString * str, + const char* name, + uint8_t prefix_separator_cnt, + uint8_t suffix_separator_cnt))));