1use crate::conversion::*;
2use crate::en1545date::{from_en1545_date, from_en1545_date_and_time};
3use crate::eticket::*;
4use crate::history::*;
5use crate::models::*;
6use chrono::prelude::*;
7
8#[derive(Debug)]
9pub struct TravelCard {
10 pub application_version: u8,
12 pub application_key_version: u8,
13 pub application_instance_id: String,
14 pub platform_type: u8,
15 pub is_mac_protected: bool,
16
17 pub application_issuing_date: DateTime<Utc>,
19 pub application_status: bool,
20 pub application_unblocking_number: u8,
21 pub application_transaction_counter: u32,
22 pub action_list_counter: u32,
23
24 pub period_pass: PeriodPass,
26
27 pub stored_value_cents: u32,
29 pub last_load_datetime: DateTime<Utc>,
30 pub last_load_value: u32,
31 pub last_load_organization_id: u16,
32 pub last_load_device_num: u16,
33
34 pub e_ticket: ETicket,
36
37 pub history: Vec<History>,
39}
40
41#[derive(Debug)]
42pub struct PeriodPass {
43 pub product_code_1: ProductCode,
44 pub validity_area_1: ValidityArea,
45 pub period_start_date_1: Date<Utc>,
46 pub period_end_date_1: Date<Utc>,
47
48 pub product_code_2: ProductCode,
51 pub validity_area_2: ValidityArea,
52 pub period_start_date_2: Date<Utc>,
53 pub period_end_date_2: Date<Utc>,
54
55 pub loaded_period_product: ProductCode,
57 pub loaded_period_datetime: DateTime<Utc>,
58 pub loaded_period_length: u16,
59 pub loaded_period_price: u32, pub loading_organization: u16,
61 pub loading_device_number: u16,
62
63 pub last_board_datetime: DateTime<Utc>,
65 pub last_board_vehicle_number: u16,
66 pub last_board_location: BoardingLocation,
67 pub last_board_direction: BoardingDirection,
68 pub last_board_area: BoardingArea,
69}
70
71pub fn create_travel_card(
72 app_info: &[u8],
73 control_info: &[u8],
74 period_pass: &[u8],
75 stored_value: &[u8],
76 e_ticket: &[u8],
77 history: &[u8],
78) -> TravelCard {
79 println!(
80 "Lengths: app_info: {:?}, period_pass: {:?}, history: {:?}",
81 app_info.len(),
82 period_pass.len(),
83 history.len()
84 );
85
86 let (app_version, app_key_version, app_instance_id, platform, is_protected) =
87 read_application_info(app_info);
88 let (issue_date, app_status, unblock_number, transaction_counter, action_counter) =
89 read_control_info(control_info);
90 let period_pass = read_period_pass(period_pass);
91 let stored_value = read_stored_value(stored_value);
92 let e_ticket = create_e_ticket(e_ticket);
93 let history = create_history_entries(history);
94
95 TravelCard {
96 application_version: app_version,
97 application_key_version: app_key_version,
98 application_instance_id: app_instance_id,
99 platform_type: platform,
100 is_mac_protected: is_protected,
101
102 application_issuing_date: issue_date,
103 application_status: app_status,
104 application_unblocking_number: unblock_number,
105 application_transaction_counter: transaction_counter,
106 action_list_counter: action_counter,
107
108 period_pass,
109
110 stored_value_cents: stored_value.cents,
111 last_load_datetime: stored_value.last_load_datetime,
112 last_load_value: stored_value.last_load_value,
113 last_load_organization_id: stored_value.last_load_organization_id,
114 last_load_device_num: stored_value.last_load_device_num,
115
116 e_ticket,
117 history,
118 }
119}
120
121fn read_application_info(app_info: &[u8]) -> (u8, u8, String, u8, bool) {
125 (
126 get_bits_as_u8(app_info, 0, 4), get_bits_as_u8(app_info, 4, 4), as_hex_string(&app_info[1..10]), get_bits_as_u8(app_info, 80, 3), get_bits_as_u8(app_info, 83, 1) != 0, )
132}
133
134fn read_control_info(control_info: &[u8]) -> (DateTime<Utc>, bool, u8, u32, u32) {
135 let issuing_date = get_bits_as_u16(control_info, 0, 14);
136 (
137 from_en1545_date(issuing_date),
138 get_bits_as_u8(control_info, 14, 1) != 0, get_bits_as_u8(control_info, 16, 8), get_bits_as_u32(control_info, 24, 24), get_bits_as_u32(control_info, 48, 32), )
144}
145
146fn read_period_pass(period_pass: &[u8]) -> PeriodPass {
147 let product_code_type_1 = get_bits_as_u8(period_pass, 0, 1);
148 let product_code_1 = get_bits_as_u16(period_pass, 1, 14);
149 let validity_area_type_1 = get_bits_as_u8(period_pass, 15, 2);
150 let validity_area_1 = get_bits_as_u8(period_pass, 17, 6);
151 let start_date_1 = get_bits_as_u16(period_pass, 23, 14);
152 let end_date_1 = get_bits_as_u16(period_pass, 37, 14);
153 let product_code_type_2 = get_bits_as_u8(period_pass, 56, 1);
154 let product_code_2 = get_bits_as_u16(period_pass, 57, 14);
155 let validity_area_type_2 = get_bits_as_u8(period_pass, 71, 2);
156 let validity_area_2 = get_bits_as_u8(period_pass, 73, 6);
157 let start_date_2 = get_bits_as_u16(period_pass, 79, 14);
158 let end_date_2 = get_bits_as_u16(period_pass, 93, 14);
159
160 let loaded_period_product_type = get_bits_as_u8(period_pass, 112, 1);
161 let loaded_period_product = get_bits_as_u16(period_pass, 113, 14);
162 let loaded_period_date = get_bits_as_u16(period_pass, 127, 14);
163 let loaded_period_time = get_bits_as_u16(period_pass, 141, 11);
164 let loaded_period_length = get_bits_as_u16(period_pass, 152, 9);
165 let loaded_period_price = get_bits_as_u32(period_pass, 161, 20);
166 let loading_organization = get_bits_as_u16(period_pass, 181, 14);
167 let loading_device_number = get_bits_as_u16(period_pass, 195, 13);
168
169 let last_board_date = get_bits_as_u16(period_pass, 208, 14);
170 let last_board_time = get_bits_as_u16(period_pass, 222, 11);
171 let last_board_vehicle_number = get_bits_as_u16(period_pass, 233, 14);
172 let last_board_location_num_type = get_bits_as_u8(period_pass, 247, 2);
173 let last_board_location_num = get_bits_as_u16(period_pass, 249, 14);
174 let last_board_direction = get_bits_as_u8(period_pass, 263, 1);
175 let last_board_area_type = get_bits_as_u8(period_pass, 264, 2);
176 let last_board_area = get_bits_as_u8(period_pass, 266, 6);
177 PeriodPass {
178 product_code_1: ProductCode::new(product_code_type_1, product_code_1),
179 validity_area_1: ValidityArea::new(validity_area_type_1, validity_area_1),
180 period_start_date_1: from_en1545_date(start_date_1).date(),
181 period_end_date_1: from_en1545_date(end_date_1).date(),
182
183 product_code_2: ProductCode::new(product_code_type_2, product_code_2),
184 validity_area_2: ValidityArea::new(validity_area_type_2, validity_area_2),
185 period_start_date_2: from_en1545_date(start_date_2).date(),
186 period_end_date_2: from_en1545_date(end_date_2).date(),
187
188 loaded_period_product: ProductCode::new(loaded_period_product_type, loaded_period_product),
189 loaded_period_datetime: from_en1545_date_and_time(loaded_period_date, loaded_period_time),
190 loaded_period_length,
191 loaded_period_price,
192 loading_organization,
193 loading_device_number,
194
195 last_board_datetime: from_en1545_date_and_time(last_board_date, last_board_time),
196 last_board_vehicle_number,
197 last_board_location: BoardingLocation::new(
198 last_board_location_num_type,
199 last_board_location_num,
200 ),
201 last_board_direction: BoardingDirection::from(last_board_direction),
202 last_board_area: BoardingArea::new(last_board_area_type, last_board_area),
203 }
204}
205
206fn read_stored_value(stored_value: &[u8]) -> StoredValue {
207 let last_load_date = get_bits_as_u16(stored_value, 20, 14);
208 let last_load_time = get_bits_as_u16(stored_value, 34, 11);
209
210 StoredValue {
211 cents: get_bits_as_u32(stored_value, 0, 20),
212 last_load_datetime: from_en1545_date_and_time(last_load_date, last_load_time),
213 last_load_value: get_bits_as_u32(stored_value, 45, 20),
214 last_load_organization_id: get_bits_as_u16(stored_value, 65, 14),
215 last_load_device_num: get_bits_as_u16(stored_value, 79, 14),
216 }
217}
218
219struct StoredValue {
220 cents: u32,
221 last_load_datetime: DateTime<Utc>,
222 last_load_value: u32,
223 last_load_organization_id: u16,
224 last_load_device_num: u16,
225}