-
-
Notifications
You must be signed in to change notification settings - Fork 240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NFC MBTA CharlieCard parsing plugin #62
Merged
Merged
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5be873f
NFC MBTA CharlieCard parsing plugin
zacharyweiss 270bd27
Fix lazy comment to make earlier version compile
zacharyweiss 5a471e0
Comment cruft cleanup, one edge case, TODO list
zacharyweiss 2f064a0
Follow date format convention
Willy-JL 91cb48e
Key B parse check, minor cleanup
zacharyweiss File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,35 @@ | |
* — Scott Campbell; josephscottcampbell.com <[email protected]> | ||
* — Noah Gibson; <[email protected]> | ||
* Talk available at: https://www.youtube.com/watch?v=1JT_lTfK69Q | ||
* | ||
* TODOs: | ||
* — Reverse engineer passes (sectors 4 & 5?), impl. | ||
* — Infer transaction flag meanings | ||
* — Infer remaining unknown bytes in the balance sectors (2 & 3) | ||
* – ASCII art &/or unified read function for the balance sectors, | ||
* to improve readability / interpretability by others? | ||
* — Improve string output formatting, esp. of transaction log | ||
* — Continually gather data on fare gate ID mappings, update as collected; | ||
* check locations this might be scrapable / inferrable from: | ||
* [X] MBTA GTFS spec (https://www.mbta.com/developers/gtfs) features & IDs | ||
* seem too-coarse-grained & uncorrelated | ||
* [X] MBTA ArcGIS (https://mbta-massdot.opendata.arcgis.com/) & Tableau (https://public.tableau.com/app/profile/mbta.office.of.performance.management.and.innovation/vizzes) | ||
* files don't seem to have anything of that resolution (only down to ridership by station) | ||
* [X] (skim of) MBTA public GitHub (https://github.com/mbta) repos make no reference to fare-gate-level data | ||
* [X] (skim of) MBTA public engineering docs (https://www.mbta.com/engineering) unfruitful; | ||
* Closest mention spotted is 2014 "Ridership and Service Statistics" (https://cdn.mbta.com/sites/default/files/fmcb-meeting-docs/reports-policies/2014-07-mbta-bluebook-ed14.pdf) | ||
* where on pg.40, "Equipment at Stations" is enumerated, and fare gates counts are given, | ||
* listed as "AFC Gates" (presumably standing for "Automated Fare Control") | ||
* [X] Josiah Zachery criminal trial public evidence — convicted partially on | ||
* data on his CharlieCard, appeals partially on basis of legality of this search. | ||
* Prev. court case (gag order mentioned in preamble) leaked some data in the files | ||
* entered into evidence. Seemingly did not happen here; fare gate IDs unmentioned, | ||
* only ever the nature of stored/saved data and methods of retrieval. | ||
* Appelate case dockets 2019-P-0401, SJC-12952, SJ-2017-0390 (https://www.ma-appellatecourts.org/party) | ||
* Trial court case 04/02/2015 #1584CR10265 @Suffolk County Criminal Superior Court (https://www.masscourts.org/eservices/home.page.16) | ||
* [ ] FOIA / public records request? (https://massachusettsdot.mycusthelp.com/WEBAPP/_rs/(S(tbcygdlm0oojy35p1wv0y2y5))/supporthome.aspx) | ||
* [ ] MBTA data blog? (https://www.massdottracker.com/datablog/) | ||
* [ ] Other? | ||
* | ||
* This program is free software: you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License as published by | ||
|
@@ -809,16 +838,17 @@ static enum CharlieActiveSector get_active_sector(const MfClassicData* data) { | |
*/ | ||
|
||
// active sector based on trip counters | ||
const bool active_trip = n_uses(data, CHARLIE_ACTIVE_SECTOR_2) < | ||
const bool active_trip = n_uses(data, CHARLIE_ACTIVE_SECTOR_2) <= | ||
n_uses(data, CHARLIE_ACTIVE_SECTOR_3); | ||
|
||
// active sector based on transaction date | ||
DateTime ds2 = date_parse(data, 2, 0, 1); | ||
DateTime ds3 = date_parse(data, 3, 0, 1); | ||
const bool active_date = datetime_datetime_to_timestamp(&ds2) > | ||
const bool active_date = datetime_datetime_to_timestamp(&ds2) >= | ||
datetime_datetime_to_timestamp(&ds3); | ||
|
||
// with all tested cards so far, this has been true | ||
// cf. type_parse() assertion comments | ||
furi_assert(active_trip == active_date); | ||
|
||
return active_trip ? CHARLIE_ACTIVE_SECTOR_2 : CHARLIE_ACTIVE_SECTOR_3; | ||
|
@@ -833,6 +863,9 @@ static uint16_t type_parse(const MfClassicData* data) { | |
// bitshift (2bytes = 16 bits) by 6bits for just first 10bits | ||
const uint16_t type1 = pos_to_num(data, 2, 1, 0, 2) >> 6; | ||
const uint16_t type2 = pos_to_num(data, 3, 1, 0, 2) >> 6; | ||
// might be wise to remove the assertion; then again, it's an effective way | ||
// to crowdsource research, as hopefully if this isn't universally true, | ||
// someone will come running when their app crashes — probably not a best practice though haha. | ||
furi_assert(type1 == type2); | ||
|
||
return type1; | ||
|
@@ -871,10 +904,9 @@ static DateTime expiry(DateTime iss) { | |
}*/ | ||
|
||
static bool expired(DateTime expiry, DateTime last_trip) { | ||
// if a card has sat unused for >2 years, expired | ||
// if a card has sat unused for >2 years, expired (verify this claim?) | ||
// else expired if current date > expiry date | ||
|
||
// TODO: end validity field? | ||
uint32_t ts_exp = datetime_datetime_to_timestamp(&expiry); | ||
uint32_t ts_last = datetime_datetime_to_timestamp(&last_trip); | ||
uint32_t ts_now = time_now(); | ||
|
@@ -930,7 +962,6 @@ void trip_format_cat(FuriString* out, Trip trip) { | |
furi_string_cat_printf(out, "%s%u", sep, trip.gate); | ||
} | ||
// print flags for debugging purposes | ||
// TODO: set up as debug-mode-only? | ||
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { | ||
furi_string_cat_printf(out, "%s%u%s%u", sep, trip.g_flag, sep, trip.f_flag); | ||
} | ||
|
@@ -968,7 +999,6 @@ static bool charliecard_parse(const NfcDevice* device, FuriString* parsed_data) | |
uint32_t card_number = bit_lib_bytes_to_num_be(uid, 4); | ||
furi_string_cat_printf(parsed_data, "\nSerial: 5-%lu", card_number); | ||
|
||
// Money fare = money_parse(data, active_sector, 0, 4); | ||
Money bal = money_parse(data, active_sector, 1, 5); | ||
furi_string_cat_printf(parsed_data, "\nBal: "); | ||
money_format_cat(parsed_data, bal); | ||
|
@@ -988,11 +1018,6 @@ static bool charliecard_parse(const NfcDevice* device, FuriString* parsed_data) | |
furi_string_cat_printf(parsed_data, "\nExpiry: "); | ||
locale_format_dt_cat(parsed_data, &e_v); | ||
|
||
/* | ||
const DateTime exp = expiry(iss); | ||
furi_string_cat_printf(parsed_data, "\nExp: "); | ||
locale_format_dt_cat(parsed_data, &exp);*/ | ||
|
||
DateTime last = date_parse(data, active_sector, 0, 1); | ||
furi_string_cat_printf(parsed_data, "\nExpired: %s", expired(e_v, last) ? "Yes" : "No"); | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
furi_assert() is compiled only when DEBUG=1 is enabled, which it is not by default, nor for production builds in Momentum, you'd need to compile with
./fbt <command> DEBUG=1
, so assert should be fine here! if you want to enforce it in all builds, regardless of DEBUG flag, you can usefuri_check()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to know! For my own education: does that mean compiling without DEBUG strips that, and is independent of the debug setting on the flipper? Or is the check kept in the compiled fap regardless, and the DEBUG compile arg simply sets the debug mode flag (locally or globally) on the flipper after flashing/launching?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DEBUG=1
refers to the compiler options, withDEBUG=0
(default)furi_assert()
will be stripped completely. theDebug
option in flipper settings allows to attacha live debugger, and to access some extra hidden functionality (raw reads, debug info in some parsers...), but will not bring back the strippedfuri_assert()
calls