metroflip_scene_calypso.c 122 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361
  1. #include "metroflip_scene_calypso.h"
  2. #include "../metroflip_i.h"
  3. #include <datetime.h>
  4. #include <dolphin/dolphin.h>
  5. #include <notification/notification_messages.h>
  6. #include <locale/locale.h>
  7. #include <nfc/protocols/iso14443_4b/iso14443_4b_poller.h>
  8. #define TAG "Metroflip:Scene:Calypso"
  9. int select_new_app(
  10. int new_app_directory,
  11. int new_app,
  12. BitBuffer* tx_buffer,
  13. BitBuffer* rx_buffer,
  14. Iso14443_4bPoller* iso14443_4b_poller,
  15. Metroflip* app,
  16. MetroflipPollerEventType* stage) {
  17. select_app[5] = new_app_directory;
  18. select_app[6] = new_app;
  19. bit_buffer_reset(tx_buffer);
  20. bit_buffer_append_bytes(tx_buffer, select_app, sizeof(select_app));
  21. FURI_LOG_D(
  22. TAG,
  23. "SEND %02x %02x %02x %02x %02x %02x %02x %02x",
  24. select_app[0],
  25. select_app[1],
  26. select_app[2],
  27. select_app[3],
  28. select_app[4],
  29. select_app[5],
  30. select_app[6],
  31. select_app[7]);
  32. int error = iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  33. if(error != Iso14443_4bErrorNone) {
  34. FURI_LOG_I(TAG, "Select File: iso14443_4b_poller_send_block error %d", error);
  35. *stage = MetroflipPollerEventTypeFail;
  36. view_dispatcher_send_custom_event(app->view_dispatcher, MetroflipCustomEventPollerFail);
  37. return error;
  38. }
  39. return 0;
  40. }
  41. int read_new_file(
  42. int new_file,
  43. BitBuffer* tx_buffer,
  44. BitBuffer* rx_buffer,
  45. Iso14443_4bPoller* iso14443_4b_poller,
  46. Metroflip* app,
  47. MetroflipPollerEventType* stage) {
  48. read_file[2] = new_file;
  49. bit_buffer_reset(tx_buffer);
  50. bit_buffer_append_bytes(tx_buffer, read_file, sizeof(read_file));
  51. FURI_LOG_D(
  52. TAG,
  53. "SEND %02x %02x %02x %02x %02x",
  54. read_file[0],
  55. read_file[1],
  56. read_file[2],
  57. read_file[3],
  58. read_file[4]);
  59. Iso14443_4bError error =
  60. iso14443_4b_poller_send_block(iso14443_4b_poller, tx_buffer, rx_buffer);
  61. if(error != Iso14443_4bErrorNone) {
  62. FURI_LOG_I(TAG, "Read File: iso14443_4b_poller_send_block error %d", error);
  63. *stage = MetroflipPollerEventTypeFail;
  64. view_dispatcher_send_custom_event(app->view_dispatcher, MetroflipCustomEventPollerFail);
  65. return error;
  66. }
  67. return 0;
  68. }
  69. int check_response(
  70. BitBuffer* rx_buffer,
  71. Metroflip* app,
  72. MetroflipPollerEventType* stage,
  73. size_t* response_length) {
  74. *response_length = bit_buffer_get_size_bytes(rx_buffer);
  75. if(bit_buffer_get_byte(rx_buffer, *response_length - 2) != apdu_success[0] ||
  76. bit_buffer_get_byte(rx_buffer, *response_length - 1) != apdu_success[1]) {
  77. int error_code_1 = bit_buffer_get_byte(rx_buffer, *response_length - 2);
  78. int error_code_2 = bit_buffer_get_byte(rx_buffer, *response_length - 1);
  79. FURI_LOG_E(TAG, "Select profile app/file failed: %02x%02x", error_code_1, error_code_2);
  80. if(error_code_1 == 0x6a && error_code_2 == 0x82) {
  81. FURI_LOG_E(TAG, "Wrong parameter(s) P1-P2 - File not found");
  82. } else if(error_code_1 == 0x69 && error_code_2 == 0x82) {
  83. FURI_LOG_E(TAG, "Command not allowed - Security status not satisfied");
  84. }
  85. *stage = MetroflipPollerEventTypeFail;
  86. view_dispatcher_send_custom_event(
  87. app->view_dispatcher, MetroflipCustomEventPollerFileNotFound);
  88. return 1;
  89. }
  90. return 0;
  91. }
  92. void update_page_info(void* context, FuriString* parsed_data) {
  93. Metroflip* app = context;
  94. CalypsoContext* ctx = app->calypso_context;
  95. if(ctx->card->card_type != CALYPSO_CARD_NAVIGO && ctx->card->card_type != CALYPSO_CARD_OPUS &&
  96. ctx->card->card_type != CALYPSO_CARD_RAVKAV) {
  97. furi_string_cat_printf(
  98. parsed_data,
  99. "\e#%s %u:\n",
  100. get_network_string(ctx->card->card_type),
  101. ctx->card->card_number);
  102. return;
  103. }
  104. if(ctx->page_id == 0) {
  105. switch(ctx->card->card_type) {
  106. case CALYPSO_CARD_NAVIGO: {
  107. furi_string_cat_printf(parsed_data, "\e#Navigo %u:\n", ctx->card->card_number);
  108. furi_string_cat_printf(parsed_data, "\e#Environment:\n");
  109. show_navigo_environment_info(
  110. &ctx->card->navigo->environment, &ctx->card->navigo->holder, parsed_data);
  111. break;
  112. }
  113. case CALYPSO_CARD_OPUS: {
  114. furi_string_cat_printf(parsed_data, "\e#Opus %u:\n", ctx->card->card_number);
  115. furi_string_cat_printf(parsed_data, "\e#Environment:\n");
  116. show_opus_environment_info(&ctx->card->opus->environment, parsed_data);
  117. break;
  118. }
  119. case CALYPSO_CARD_RAVKAV: {
  120. if(ctx->card->card_number == 0) {
  121. furi_string_cat_printf(parsed_data, "\e#Anonymous Rav-Kav:\n");
  122. } else {
  123. furi_string_cat_printf(parsed_data, "\e#RavKav %u:\n", ctx->card->card_number);
  124. }
  125. furi_string_cat_printf(parsed_data, "\e#Environment:\n");
  126. show_ravkav_environment_info(&ctx->card->ravkav->environment, parsed_data);
  127. break;
  128. }
  129. default: {
  130. furi_string_cat_printf(parsed_data, "\e#Unknown %u:\n", ctx->card->card_number);
  131. furi_string_cat_printf(
  132. parsed_data, "Country: %s\n", get_country_string(ctx->card->country_num));
  133. if(guess_card_type(ctx->card->country_num, ctx->card->network_num) !=
  134. CALYPSO_CARD_UNKNOWN) {
  135. furi_string_cat_printf(
  136. parsed_data,
  137. "Network: %s\n",
  138. get_network_string(
  139. guess_card_type(ctx->card->country_num, ctx->card->network_num)));
  140. } else {
  141. furi_string_cat_printf(parsed_data, "Network: %d\n", ctx->card->network_num);
  142. }
  143. break;
  144. }
  145. }
  146. } else if(ctx->page_id == 1 || ctx->page_id == 2 || ctx->page_id == 3 || ctx->page_id == 4) {
  147. furi_string_cat_printf(parsed_data, "\e#Contract %d:\n", ctx->page_id);
  148. switch(ctx->card->card_type) {
  149. case CALYPSO_CARD_NAVIGO: {
  150. show_navigo_contract_info(
  151. &ctx->card->navigo->contracts[ctx->page_id - 1], parsed_data);
  152. break;
  153. }
  154. case CALYPSO_CARD_OPUS: {
  155. show_opus_contract_info(&ctx->card->opus->contracts[ctx->page_id - 1], parsed_data);
  156. break;
  157. }
  158. case CALYPSO_CARD_RAVKAV: {
  159. show_ravkav_contract_info(
  160. &ctx->card->ravkav->contracts[ctx->page_id - 1], parsed_data);
  161. break;
  162. }
  163. default: {
  164. break;
  165. }
  166. }
  167. } else if(ctx->page_id >= 5) {
  168. furi_string_cat_printf(parsed_data, "\e#Event %d:\n", ctx->page_id - 4);
  169. switch(ctx->card->card_type) {
  170. case CALYPSO_CARD_NAVIGO: {
  171. show_navigo_event_info(
  172. &ctx->card->navigo->events[ctx->page_id - 5],
  173. ctx->card->navigo->contracts,
  174. parsed_data);
  175. break;
  176. }
  177. case CALYPSO_CARD_OPUS: {
  178. show_opus_event_info(
  179. &ctx->card->opus->events[ctx->page_id - 5],
  180. ctx->card->opus->contracts,
  181. parsed_data);
  182. break;
  183. }
  184. case CALYPSO_CARD_RAVKAV: {
  185. show_ravkav_event_info(&ctx->card->ravkav->events[ctx->page_id - 5], parsed_data);
  186. break;
  187. }
  188. default: {
  189. break;
  190. }
  191. }
  192. } else if(ctx->page_id == 8 || ctx->page_id == 9 || ctx->page_id == 10) {
  193. furi_string_cat_printf(parsed_data, "\e#Special Event %d:\n", ctx->page_id - 7);
  194. switch(ctx->card->card_type) {
  195. case CALYPSO_CARD_NAVIGO: {
  196. show_navigo_special_event_info(
  197. &ctx->card->navigo->special_events[ctx->page_id - 8], parsed_data);
  198. break;
  199. }
  200. case CALYPSO_CARD_OPUS: {
  201. break;
  202. }
  203. default: {
  204. break;
  205. }
  206. }
  207. }
  208. }
  209. void update_widget_elements(void* context) {
  210. Metroflip* app = context;
  211. CalypsoContext* ctx = app->calypso_context;
  212. Widget* widget = app->widget;
  213. if(ctx->card->card_type != CALYPSO_CARD_NAVIGO && ctx->card->card_type != CALYPSO_CARD_OPUS &&
  214. ctx->card->card_type != CALYPSO_CARD_RAVKAV) {
  215. widget_add_button_element(
  216. widget, GuiButtonTypeRight, "Exit", metroflip_next_button_widget_callback, context);
  217. return;
  218. }
  219. if(ctx->page_id < 10) {
  220. widget_add_button_element(
  221. widget, GuiButtonTypeRight, "Next", metroflip_next_button_widget_callback, context);
  222. } else {
  223. widget_add_button_element(
  224. widget, GuiButtonTypeRight, "Exit", metroflip_next_button_widget_callback, context);
  225. }
  226. if(ctx->page_id > 0) {
  227. widget_add_button_element(
  228. widget, GuiButtonTypeLeft, "Back", metroflip_back_button_widget_callback, context);
  229. }
  230. }
  231. void metroflip_back_button_widget_callback(GuiButtonType result, InputType type, void* context) {
  232. Metroflip* app = context;
  233. CalypsoContext* ctx = app->calypso_context;
  234. UNUSED(result);
  235. Widget* widget = app->widget;
  236. if(type == InputTypePress) {
  237. widget_reset(widget);
  238. FURI_LOG_I(TAG, "Page ID: %d -> %d", ctx->page_id, ctx->page_id - 1);
  239. if(ctx->page_id > 0) {
  240. if(ctx->page_id == 10 && ctx->card->special_events_count < 2) {
  241. ctx->page_id -= 1;
  242. }
  243. if(ctx->page_id == 9 && ctx->card->special_events_count < 1) {
  244. ctx->page_id -= 1;
  245. }
  246. if(ctx->page_id == 8 && ctx->card->events_count < 3) {
  247. ctx->page_id -= 1;
  248. }
  249. if(ctx->page_id == 7 && ctx->card->events_count < 2) {
  250. ctx->page_id -= 1;
  251. }
  252. if(ctx->page_id == 6 && ctx->card->events_count < 1) {
  253. ctx->page_id -= 1;
  254. }
  255. if(ctx->page_id == 5 && ctx->card->contracts_count < 4) {
  256. ctx->page_id -= 1;
  257. }
  258. if(ctx->page_id == 4 && ctx->card->contracts_count < 3) {
  259. ctx->page_id -= 1;
  260. }
  261. if(ctx->page_id == 3 && ctx->card->contracts_count < 2) {
  262. ctx->page_id -= 1;
  263. }
  264. ctx->page_id -= 1;
  265. }
  266. FuriString* parsed_data = furi_string_alloc();
  267. // Ensure no nested mutexes
  268. furi_mutex_acquire(ctx->mutex, FuriWaitForever);
  269. update_page_info(app, parsed_data);
  270. furi_mutex_release(ctx->mutex);
  271. widget_add_text_scroll_element(widget, 0, 0, 128, 64, furi_string_get_cstr(parsed_data));
  272. // widget_add_icon_element(widget, 0, 0, &I_RFIDDolphinReceive_97x61);
  273. // Ensure no nested mutexes
  274. furi_mutex_acquire(ctx->mutex, FuriWaitForever);
  275. update_widget_elements(app);
  276. furi_mutex_release(ctx->mutex);
  277. furi_string_free(parsed_data);
  278. }
  279. }
  280. void metroflip_next_button_widget_callback(GuiButtonType result, InputType type, void* context) {
  281. Metroflip* app = context;
  282. CalypsoContext* ctx = app->calypso_context;
  283. UNUSED(result);
  284. Widget* widget = app->widget;
  285. if(type == InputTypePress) {
  286. widget_reset(widget);
  287. FURI_LOG_I(TAG, "Page ID: %d -> %d", ctx->page_id, ctx->page_id + 1);
  288. if(ctx->card->card_type != CALYPSO_CARD_NAVIGO &&
  289. ctx->card->card_type != CALYPSO_CARD_OPUS &&
  290. ctx->card->card_type != CALYPSO_CARD_RAVKAV) {
  291. ctx->page_id = 0;
  292. scene_manager_search_and_switch_to_previous_scene(
  293. app->scene_manager, MetroflipSceneStart);
  294. return;
  295. }
  296. if(ctx->page_id < 10) {
  297. if(ctx->page_id == 1 && ctx->card->contracts_count < 2) {
  298. ctx->page_id += 1;
  299. }
  300. if(ctx->page_id == 2 && ctx->card->contracts_count < 3) {
  301. ctx->page_id += 1;
  302. }
  303. if(ctx->page_id == 3 && ctx->card->contracts_count < 4) {
  304. ctx->page_id += 1;
  305. }
  306. if(ctx->page_id == 4 && ctx->card->events_count < 1) {
  307. ctx->page_id += 1;
  308. }
  309. if(ctx->page_id == 5 && ctx->card->events_count < 2) {
  310. ctx->page_id += 1;
  311. }
  312. if(ctx->page_id == 6 && ctx->card->events_count < 3) {
  313. ctx->page_id += 1;
  314. }
  315. if(ctx->page_id == 7 && ctx->card->special_events_count < 1) {
  316. ctx->page_id += 1;
  317. }
  318. if(ctx->page_id == 8 && ctx->card->special_events_count < 2) {
  319. ctx->page_id += 1;
  320. }
  321. if(ctx->page_id == 9 && ctx->card->special_events_count < 3) {
  322. ctx->page_id = 0;
  323. scene_manager_search_and_switch_to_previous_scene(
  324. app->scene_manager, MetroflipSceneStart);
  325. return;
  326. }
  327. ctx->page_id += 1;
  328. } else {
  329. ctx->page_id = 0;
  330. scene_manager_search_and_switch_to_previous_scene(
  331. app->scene_manager, MetroflipSceneStart);
  332. return;
  333. }
  334. FuriString* parsed_data = furi_string_alloc();
  335. // Ensure no nested mutexes
  336. furi_mutex_acquire(ctx->mutex, FuriWaitForever);
  337. update_page_info(app, parsed_data);
  338. furi_mutex_release(ctx->mutex);
  339. widget_add_text_scroll_element(widget, 0, 0, 128, 64, furi_string_get_cstr(parsed_data));
  340. // Ensure no nested mutexes
  341. furi_mutex_acquire(ctx->mutex, FuriWaitForever);
  342. update_widget_elements(app);
  343. furi_mutex_release(ctx->mutex);
  344. furi_string_free(parsed_data);
  345. }
  346. }
  347. void delay(int milliseconds) {
  348. furi_thread_flags_wait(0, FuriFlagWaitAny, milliseconds);
  349. }
  350. static NfcCommand metroflip_scene_calypso_poller_callback(NfcGenericEvent event, void* context) {
  351. furi_assert(event.protocol == NfcProtocolIso14443_4b);
  352. NfcCommand next_command = NfcCommandContinue;
  353. MetroflipPollerEventType stage = MetroflipPollerEventTypeStart;
  354. Metroflip* app = context;
  355. FuriString* parsed_data = furi_string_alloc();
  356. Widget* widget = app->widget;
  357. furi_string_reset(app->text_box_store);
  358. const Iso14443_4bPollerEvent* iso14443_4b_event = event.event_data;
  359. Iso14443_4bPoller* iso14443_4b_poller = event.instance;
  360. BitBuffer* tx_buffer = bit_buffer_alloc(Metroflip_POLLER_MAX_BUFFER_SIZE);
  361. BitBuffer* rx_buffer = bit_buffer_alloc(Metroflip_POLLER_MAX_BUFFER_SIZE);
  362. if(iso14443_4b_event->type == Iso14443_4bPollerEventTypeReady) {
  363. if(stage == MetroflipPollerEventTypeStart) {
  364. // Start Flipper vibration
  365. NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
  366. notification_message(notification, &sequence_set_vibro_on);
  367. delay(50);
  368. notification_message(notification, &sequence_reset_vibro);
  369. nfc_device_set_data(
  370. app->nfc_device, NfcProtocolIso14443_4b, nfc_poller_get_data(app->poller));
  371. Iso14443_4bError error;
  372. size_t response_length = 0;
  373. do {
  374. // Initialize the card data
  375. CalypsoCardData* card = malloc(sizeof(CalypsoCardData));
  376. // Select app ICC
  377. error = select_new_app(
  378. 0x00, 0x02, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  379. if(error != 0) {
  380. break;
  381. }
  382. // Check the response after selecting app
  383. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  384. break;
  385. }
  386. // Now send the read command for ICC
  387. error = read_new_file(0x01, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  388. if(error != 0) {
  389. break;
  390. }
  391. // Check the response after reading the file
  392. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  393. break;
  394. }
  395. char icc_bit_representation[response_length * 8 + 1];
  396. icc_bit_representation[0] = '\0';
  397. for(size_t i = 0; i < response_length; i++) {
  398. char bits[9];
  399. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  400. byte_to_binary(byte, bits);
  401. strlcat(icc_bit_representation, bits, sizeof(icc_bit_representation));
  402. }
  403. icc_bit_representation[response_length * 8] = '\0';
  404. int start = 128, end = 159;
  405. card->card_number = bit_slice_to_dec(icc_bit_representation, start, end);
  406. // Select app for ticketing
  407. error = select_new_app(
  408. 0x20, 0x00, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  409. if(error != 0) {
  410. FURI_LOG_E(TAG, "Failed to select app for ticketing");
  411. break;
  412. }
  413. // Check the response after selecting app
  414. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  415. FURI_LOG_E(TAG, "Failed to check response after selecting app for ticketing");
  416. break;
  417. }
  418. // Select app for environment
  419. error = select_new_app(
  420. 0x20, 0x1, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  421. if(error != 0) {
  422. break;
  423. }
  424. // Check the response after selecting app
  425. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  426. break;
  427. }
  428. // read file 1
  429. error = read_new_file(1, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  430. if(error != 0) {
  431. break;
  432. }
  433. // Check the response after reading the file
  434. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  435. break;
  436. }
  437. char environment_bit_representation[response_length * 8 + 1];
  438. environment_bit_representation[0] = '\0';
  439. for(size_t i = 0; i < response_length; i++) {
  440. char bits[9];
  441. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  442. byte_to_binary(byte, bits);
  443. strlcat(
  444. environment_bit_representation,
  445. bits,
  446. sizeof(environment_bit_representation));
  447. }
  448. // FURI_LOG_I(
  449. // TAG, "Environment bit_representation: %s", environment_bit_representation);
  450. start = 13;
  451. end = 16;
  452. card->country_num =
  453. bit_slice_to_dec(environment_bit_representation, start, end) * 100 +
  454. bit_slice_to_dec(environment_bit_representation, start + 4, end + 4) * 10 +
  455. bit_slice_to_dec(environment_bit_representation, start + 8, end + 8);
  456. start = 25;
  457. end = 28;
  458. card->network_num =
  459. bit_slice_to_dec(environment_bit_representation, start, end) * 100 +
  460. bit_slice_to_dec(environment_bit_representation, start + 4, end + 4) * 10 +
  461. bit_slice_to_dec(environment_bit_representation, start + 8, end + 8);
  462. card->card_type = guess_card_type(card->country_num, card->network_num);
  463. switch(card->card_type) {
  464. case CALYPSO_CARD_NAVIGO: {
  465. card->navigo = malloc(sizeof(NavigoCardData));
  466. card->navigo->environment.country_num = card->country_num;
  467. card->navigo->environment.network_num = card->network_num;
  468. CalypsoApp* IntercodeEnvHolderStructure = get_intercode_structure_env_holder();
  469. // EnvApplicationVersionNumber
  470. const char* env_key = "EnvApplicationVersionNumber";
  471. int positionOffset = get_calypso_node_offset(
  472. environment_bit_representation, env_key, IntercodeEnvHolderStructure);
  473. int start = positionOffset,
  474. end = positionOffset +
  475. get_calypso_node_size(env_key, IntercodeEnvHolderStructure) - 1;
  476. card->navigo->environment.app_version =
  477. bit_slice_to_dec(environment_bit_representation, start, end);
  478. // EnvApplicationValidityEndDate
  479. env_key = "EnvApplicationValidityEndDate";
  480. positionOffset = get_calypso_node_offset(
  481. environment_bit_representation, env_key, IntercodeEnvHolderStructure);
  482. start = positionOffset,
  483. end = positionOffset +
  484. get_calypso_node_size(env_key, IntercodeEnvHolderStructure) - 1;
  485. float decimal_value =
  486. bit_slice_to_dec(environment_bit_representation, start, end);
  487. uint64_t end_validity_timestamp =
  488. (decimal_value * 24 * 3600) + (float)epoch + 3600;
  489. datetime_timestamp_to_datetime(
  490. end_validity_timestamp, &card->navigo->environment.end_dt);
  491. // HolderDataCardStatus
  492. env_key = "HolderDataCardStatus";
  493. positionOffset = get_calypso_node_offset(
  494. environment_bit_representation, env_key, IntercodeEnvHolderStructure);
  495. start = positionOffset,
  496. end = positionOffset +
  497. get_calypso_node_size(env_key, IntercodeEnvHolderStructure) - 1;
  498. card->navigo->holder.card_status =
  499. bit_slice_to_dec(environment_bit_representation, start, end);
  500. // HolderDataCommercialID
  501. env_key = "HolderDataCommercialID";
  502. positionOffset = get_calypso_node_offset(
  503. environment_bit_representation, env_key, IntercodeEnvHolderStructure);
  504. start = positionOffset,
  505. end = positionOffset +
  506. get_calypso_node_size(env_key, IntercodeEnvHolderStructure) - 1;
  507. card->navigo->holder.commercial_id =
  508. bit_slice_to_dec(environment_bit_representation, start, end);
  509. // Free the calypso structure
  510. free_calypso_structure(IntercodeEnvHolderStructure);
  511. // Select app for contracts
  512. error = select_new_app(
  513. 0x20, 0x20, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  514. if(error != 0) {
  515. FURI_LOG_E(TAG, "Failed to select app for contracts");
  516. break;
  517. }
  518. // Check the response after selecting app
  519. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  520. FURI_LOG_E(
  521. TAG, "Failed to check response after selecting app for contracts");
  522. break;
  523. }
  524. // Prepare calypso structure
  525. CalypsoApp* IntercodeContractStructure = get_intercode_structure_contract();
  526. if(!IntercodeContractStructure) {
  527. FURI_LOG_E(TAG, "Failed to load Intercode Contract structure");
  528. break;
  529. }
  530. // Now send the read command for contracts
  531. for(size_t i = 1; i < 5; i++) {
  532. error = read_new_file(
  533. i, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  534. if(error != 0) {
  535. FURI_LOG_E(TAG, "Failed to read contract %d", i);
  536. break;
  537. }
  538. // Check the response after reading the file
  539. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  540. FURI_LOG_E(
  541. TAG, "Failed to check response after reading contract %d", i);
  542. break;
  543. }
  544. char bit_representation[response_length * 8 + 1];
  545. bit_representation[0] = '\0';
  546. for(size_t i = 0; i < response_length; i++) {
  547. char bits[9];
  548. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  549. byte_to_binary(byte, bits);
  550. strlcat(bit_representation, bits, sizeof(bit_representation));
  551. }
  552. bit_representation[response_length * 8] = '\0';
  553. if(bit_slice_to_dec(
  554. bit_representation,
  555. 0,
  556. IntercodeContractStructure->container->elements[0].bitmap->size -
  557. 1) == 0) {
  558. break;
  559. }
  560. card->navigo->contracts[i - 1].present = 1;
  561. card->contracts_count++;
  562. // 2. ContractTariff
  563. const char* contract_key = "ContractTariff";
  564. if(is_calypso_node_present(
  565. bit_representation, contract_key, IntercodeContractStructure)) {
  566. int positionOffset = get_calypso_node_offset(
  567. bit_representation, contract_key, IntercodeContractStructure);
  568. int start = positionOffset,
  569. end = positionOffset +
  570. get_calypso_node_size(
  571. contract_key, IntercodeContractStructure) -
  572. 1;
  573. card->navigo->contracts[i - 1].tariff =
  574. bit_slice_to_dec(bit_representation, start, end);
  575. }
  576. // 3. ContractSerialNumber
  577. contract_key = "ContractSerialNumber";
  578. if(is_calypso_node_present(
  579. bit_representation, contract_key, IntercodeContractStructure)) {
  580. int positionOffset = get_calypso_node_offset(
  581. bit_representation, contract_key, IntercodeContractStructure);
  582. int start = positionOffset,
  583. end = positionOffset +
  584. get_calypso_node_size(
  585. contract_key, IntercodeContractStructure) -
  586. 1;
  587. card->navigo->contracts[i - 1].serial_number =
  588. bit_slice_to_dec(bit_representation, start, end);
  589. card->navigo->contracts[i - 1].serial_number_available = true;
  590. }
  591. // 8. ContractPayMethod
  592. contract_key = "ContractPayMethod";
  593. if(is_calypso_node_present(
  594. bit_representation, contract_key, IntercodeContractStructure)) {
  595. int positionOffset = get_calypso_node_offset(
  596. bit_representation, contract_key, IntercodeContractStructure);
  597. int start = positionOffset,
  598. end = positionOffset +
  599. get_calypso_node_size(
  600. contract_key, IntercodeContractStructure) -
  601. 1;
  602. card->navigo->contracts[i - 1].pay_method =
  603. bit_slice_to_dec(bit_representation, start, end);
  604. card->navigo->contracts[i - 1].pay_method_available = true;
  605. }
  606. // 10. ContractPriceAmount
  607. contract_key = "ContractPriceAmount";
  608. if(is_calypso_node_present(
  609. bit_representation, contract_key, IntercodeContractStructure)) {
  610. int positionOffset = get_calypso_node_offset(
  611. bit_representation, contract_key, IntercodeContractStructure);
  612. int start = positionOffset,
  613. end = positionOffset +
  614. get_calypso_node_size(
  615. contract_key, IntercodeContractStructure) -
  616. 1;
  617. card->navigo->contracts[i - 1].price_amount =
  618. bit_slice_to_dec(bit_representation, start, end) / 100.0;
  619. card->navigo->contracts[i - 1].price_amount_available = true;
  620. }
  621. // 13.0. ContractValidityStartDate
  622. contract_key = "ContractValidityStartDate";
  623. if(is_calypso_node_present(
  624. bit_representation, contract_key, IntercodeContractStructure)) {
  625. int positionOffset = get_calypso_node_offset(
  626. bit_representation, contract_key, IntercodeContractStructure);
  627. int start = positionOffset,
  628. end = positionOffset +
  629. get_calypso_node_size(
  630. contract_key, IntercodeContractStructure) -
  631. 1;
  632. float decimal_value =
  633. bit_slice_to_dec(bit_representation, start, end) * 24 * 3600;
  634. uint64_t start_validity_timestamp =
  635. (decimal_value + (float)epoch) + 3600;
  636. datetime_timestamp_to_datetime(
  637. start_validity_timestamp,
  638. &card->navigo->contracts[i - 1].start_date);
  639. }
  640. // 13.2. ContractValidityEndDate
  641. contract_key = "ContractValidityEndDate";
  642. if(is_calypso_node_present(
  643. bit_representation, contract_key, IntercodeContractStructure)) {
  644. int positionOffset = get_calypso_node_offset(
  645. bit_representation, contract_key, IntercodeContractStructure);
  646. int start = positionOffset,
  647. end = positionOffset +
  648. get_calypso_node_size(
  649. contract_key, IntercodeContractStructure) -
  650. 1;
  651. float decimal_value =
  652. bit_slice_to_dec(bit_representation, start, end) * 24 * 3600;
  653. uint64_t end_validity_timestamp =
  654. (decimal_value + (float)epoch) + 3600;
  655. datetime_timestamp_to_datetime(
  656. end_validity_timestamp, &card->navigo->contracts[i - 1].end_date);
  657. card->navigo->contracts[i - 1].end_date_available = true;
  658. }
  659. // 13.6. ContractValidityZones
  660. contract_key = "ContractValidityZones";
  661. if(is_calypso_node_present(
  662. bit_representation, contract_key, IntercodeContractStructure)) {
  663. int start = get_calypso_node_offset(
  664. bit_representation, contract_key, IntercodeContractStructure);
  665. // binary form is 00011111 for zones 5, 4, 3, 2, 1
  666. for(int j = 0; j < 5; j++) {
  667. card->navigo->contracts[i - 1].zones[j] = bit_slice_to_dec(
  668. bit_representation, start + 3 + j, start + 3 + j);
  669. }
  670. card->navigo->contracts[i - 1].zones_available = true;
  671. }
  672. // 13.7. ContractValidityJourneys
  673. contract_key = "ContractValidityJourneys";
  674. if(is_calypso_node_present(
  675. bit_representation, contract_key, IntercodeContractStructure)) {
  676. int positionOffset = get_calypso_node_offset(
  677. bit_representation, contract_key, IntercodeContractStructure);
  678. int start = positionOffset,
  679. end = positionOffset +
  680. get_calypso_node_size(
  681. contract_key, IntercodeContractStructure) -
  682. 1;
  683. int decimal_value = bit_slice_to_dec(bit_representation, start, end);
  684. // first 5 bits -> CounterStructureNumber
  685. // last 8 bits -> CounterLastLoad
  686. // other bits -> RFU
  687. card->navigo->contracts[i - 1].counter.struct_number = decimal_value >>
  688. 11;
  689. card->navigo->contracts[i - 1].counter.last_load = decimal_value &
  690. 0xFF;
  691. card->navigo->contracts[i - 1].counter_present = true;
  692. }
  693. // 15.0. ContractValiditySaleDate
  694. contract_key = "ContractValiditySaleDate";
  695. if(is_calypso_node_present(
  696. bit_representation, contract_key, IntercodeContractStructure)) {
  697. int positionOffset = get_calypso_node_offset(
  698. bit_representation, contract_key, IntercodeContractStructure);
  699. int start = positionOffset,
  700. end = positionOffset +
  701. get_calypso_node_size(
  702. contract_key, IntercodeContractStructure) -
  703. 1;
  704. float decimal_value =
  705. bit_slice_to_dec(bit_representation, start, end) * 24 * 3600;
  706. uint64_t sale_timestamp = (decimal_value + (float)epoch) + 3600;
  707. datetime_timestamp_to_datetime(
  708. sale_timestamp, &card->navigo->contracts[i - 1].sale_date);
  709. }
  710. // 15.2. ContractValiditySaleAgent - FIX NEEDED
  711. contract_key = "ContractValiditySaleAgent";
  712. /* if(is_calypso_node_present(
  713. bit_representation, contract_key, NavigoContractStructure)) { */
  714. int positionOffset = get_calypso_node_offset(
  715. bit_representation, contract_key, IntercodeContractStructure);
  716. int start = positionOffset,
  717. end = positionOffset +
  718. get_calypso_node_size(contract_key, IntercodeContractStructure) -
  719. 1;
  720. card->navigo->contracts[i - 1].sale_agent =
  721. bit_slice_to_dec(bit_representation, start, end);
  722. // }
  723. // 15.3. ContractValiditySaleDevice
  724. contract_key = "ContractValiditySaleDevice";
  725. if(is_calypso_node_present(
  726. bit_representation, contract_key, IntercodeContractStructure)) {
  727. int positionOffset = get_calypso_node_offset(
  728. bit_representation, contract_key, IntercodeContractStructure);
  729. int start = positionOffset,
  730. end = positionOffset +
  731. get_calypso_node_size(
  732. contract_key, IntercodeContractStructure) -
  733. 1;
  734. card->navigo->contracts[i - 1].sale_device =
  735. bit_slice_to_dec(bit_representation, start, end);
  736. }
  737. // 16. ContractStatus -- 0x1 ou 0xff
  738. contract_key = "ContractStatus";
  739. if(is_calypso_node_present(
  740. bit_representation, contract_key, IntercodeContractStructure)) {
  741. int positionOffset = get_calypso_node_offset(
  742. bit_representation, contract_key, IntercodeContractStructure);
  743. int start = positionOffset,
  744. end = positionOffset +
  745. get_calypso_node_size(
  746. contract_key, IntercodeContractStructure) -
  747. 1;
  748. card->navigo->contracts[i - 1].status =
  749. bit_slice_to_dec(bit_representation, start, end);
  750. }
  751. // 18. ContractAuthenticator
  752. contract_key = "ContractAuthenticator";
  753. if(is_calypso_node_present(
  754. bit_representation, contract_key, IntercodeContractStructure)) {
  755. int positionOffset = get_calypso_node_offset(
  756. bit_representation, contract_key, IntercodeContractStructure);
  757. int start = positionOffset,
  758. end = positionOffset +
  759. get_calypso_node_size(
  760. contract_key, IntercodeContractStructure) -
  761. 1;
  762. card->navigo->contracts[i - 1].authenticator =
  763. bit_slice_to_dec(bit_representation, start, end);
  764. }
  765. }
  766. // Free the calypso structure
  767. free_calypso_structure(IntercodeContractStructure);
  768. // Select app for counters (remaining tickets on Navigo Easy)
  769. error = select_new_app(
  770. 0x20, 0x69, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  771. if(error != 0) {
  772. break;
  773. }
  774. // Check the response after selecting app
  775. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  776. break;
  777. }
  778. // read file 1
  779. error =
  780. read_new_file(1, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  781. if(error != 0) {
  782. break;
  783. }
  784. // Check the response after reading the file
  785. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  786. break;
  787. }
  788. char counter_bit_representation[response_length * 8 + 1];
  789. counter_bit_representation[0] = '\0';
  790. for(size_t i = 0; i < response_length; i++) {
  791. char bits[9];
  792. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  793. byte_to_binary(byte, bits);
  794. strlcat(
  795. counter_bit_representation, bits, sizeof(counter_bit_representation));
  796. }
  797. // FURI_LOG_I(TAG, "Counter bit_representation: %s", counter_bit_representation);
  798. // Ticket counts (contracts 1-4)
  799. for(int i = 0; i < 4; i++) {
  800. if(card->navigo->contracts[i].present == 0) {
  801. continue;
  802. }
  803. if(card->navigo->contracts[i].counter_present == 0) {
  804. continue;
  805. }
  806. start = 0;
  807. end = 5;
  808. card->navigo->contracts[i].counter.count = bit_slice_to_dec(
  809. counter_bit_representation, 24 * i + start, 24 * i + end);
  810. start = 6;
  811. end = 23;
  812. card->navigo->contracts[i].counter.relative_first_stamp_15mn =
  813. bit_slice_to_dec(
  814. counter_bit_representation, 24 * i + start, 24 * i + end);
  815. }
  816. // Select app for events
  817. error = select_new_app(
  818. 0x20, 0x10, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  819. if(error != 0) {
  820. break;
  821. }
  822. // Check the response after selecting app
  823. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  824. break;
  825. }
  826. // Load the calypso structure for events
  827. CalypsoApp* IntercodeEventStructure = get_intercode_structure_event();
  828. if(!IntercodeEventStructure) {
  829. FURI_LOG_E(TAG, "Failed to load Intercode Event structure");
  830. break;
  831. }
  832. // furi_string_cat_printf(parsed_data, "\e#Events :\n");
  833. // Now send the read command for events
  834. for(size_t i = 1; i < 4; i++) {
  835. error = read_new_file(
  836. i, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  837. if(error != 0) {
  838. break;
  839. }
  840. // Check the response after reading the file
  841. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  842. break;
  843. }
  844. char event_bit_representation[response_length * 8 + 1];
  845. event_bit_representation[0] = '\0';
  846. for(size_t i = 0; i < response_length; i++) {
  847. char bits[9];
  848. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  849. byte_to_binary(byte, bits);
  850. strlcat(
  851. event_bit_representation, bits, sizeof(event_bit_representation));
  852. }
  853. // 2. EventCode
  854. const char* event_key = "EventCode";
  855. if(is_calypso_node_present(
  856. event_bit_representation, event_key, IntercodeEventStructure)) {
  857. int positionOffset = get_calypso_node_offset(
  858. event_bit_representation, event_key, IntercodeEventStructure);
  859. int start = positionOffset,
  860. end = positionOffset +
  861. get_calypso_node_size(event_key, IntercodeEventStructure) -
  862. 1;
  863. int decimal_value =
  864. bit_slice_to_dec(event_bit_representation, start, end);
  865. card->navigo->events[i - 1].transport_type = decimal_value >> 4;
  866. card->navigo->events[i - 1].transition = decimal_value & 15;
  867. }
  868. // 4. EventServiceProvider
  869. event_key = "EventServiceProvider";
  870. if(is_calypso_node_present(
  871. event_bit_representation, event_key, IntercodeEventStructure)) {
  872. int positionOffset = get_calypso_node_offset(
  873. event_bit_representation, event_key, IntercodeEventStructure);
  874. start = positionOffset,
  875. end = positionOffset +
  876. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  877. card->navigo->events[i - 1].service_provider =
  878. bit_slice_to_dec(event_bit_representation, start, end);
  879. }
  880. // 8. EventLocationId
  881. event_key = "EventLocationId";
  882. if(is_calypso_node_present(
  883. event_bit_representation, event_key, IntercodeEventStructure)) {
  884. int positionOffset = get_calypso_node_offset(
  885. event_bit_representation, event_key, IntercodeEventStructure);
  886. start = positionOffset,
  887. end = positionOffset +
  888. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  889. int decimal_value =
  890. bit_slice_to_dec(event_bit_representation, start, end);
  891. card->navigo->events[i - 1].station_group_id = decimal_value >> 9;
  892. card->navigo->events[i - 1].station_id = (decimal_value >> 4) & 31;
  893. card->navigo->events[i - 1].station_sub_id = decimal_value & 15;
  894. }
  895. // 9. EventLocationGate
  896. event_key = "EventLocationGate";
  897. if(is_calypso_node_present(
  898. event_bit_representation, event_key, IntercodeEventStructure)) {
  899. int positionOffset = get_calypso_node_offset(
  900. event_bit_representation, event_key, IntercodeEventStructure);
  901. start = positionOffset,
  902. end = positionOffset +
  903. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  904. card->navigo->events[i - 1].location_gate =
  905. bit_slice_to_dec(event_bit_representation, start, end);
  906. card->navigo->events[i - 1].location_gate_available = true;
  907. }
  908. // 10. EventDevice
  909. event_key = "EventDevice";
  910. if(is_calypso_node_present(
  911. event_bit_representation, event_key, IntercodeEventStructure)) {
  912. int positionOffset = get_calypso_node_offset(
  913. event_bit_representation, event_key, IntercodeEventStructure);
  914. start = positionOffset,
  915. end = positionOffset +
  916. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  917. int decimal_value =
  918. bit_slice_to_dec(event_bit_representation, start, end);
  919. card->navigo->events[i - 1].device = decimal_value;
  920. int bus_device = decimal_value >> 8;
  921. card->navigo->events[i - 1].door = bus_device / 2 + 1;
  922. card->navigo->events[i - 1].side = bus_device % 2;
  923. card->navigo->events[i - 1].device_available = true;
  924. }
  925. // 11. EventRouteNumber
  926. event_key = "EventRouteNumber";
  927. if(is_calypso_node_present(
  928. event_bit_representation, event_key, IntercodeEventStructure)) {
  929. int positionOffset = get_calypso_node_offset(
  930. event_bit_representation, event_key, IntercodeEventStructure);
  931. start = positionOffset,
  932. end = positionOffset +
  933. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  934. card->navigo->events[i - 1].route_number =
  935. bit_slice_to_dec(event_bit_representation, start, end);
  936. card->navigo->events[i - 1].route_number_available = true;
  937. }
  938. // 13. EventJourneyRun
  939. event_key = "EventJourneyRun";
  940. if(is_calypso_node_present(
  941. event_bit_representation, event_key, IntercodeEventStructure)) {
  942. int positionOffset = get_calypso_node_offset(
  943. event_bit_representation, event_key, IntercodeEventStructure);
  944. start = positionOffset,
  945. end = positionOffset +
  946. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  947. card->navigo->events[i - 1].mission =
  948. bit_slice_to_dec(event_bit_representation, start, end);
  949. card->navigo->events[i - 1].mission_available = true;
  950. }
  951. // 14. EventVehicleId
  952. event_key = "EventVehicleId";
  953. if(is_calypso_node_present(
  954. event_bit_representation, event_key, IntercodeEventStructure)) {
  955. int positionOffset = get_calypso_node_offset(
  956. event_bit_representation, event_key, IntercodeEventStructure);
  957. start = positionOffset,
  958. end = positionOffset +
  959. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  960. card->navigo->events[i - 1].vehicle_id =
  961. bit_slice_to_dec(event_bit_representation, start, end);
  962. card->navigo->events[i - 1].vehicle_id_available = true;
  963. }
  964. // 25. EventContractPointer
  965. event_key = "EventContractPointer";
  966. if(is_calypso_node_present(
  967. event_bit_representation, event_key, IntercodeEventStructure)) {
  968. int positionOffset = get_calypso_node_offset(
  969. event_bit_representation, event_key, IntercodeEventStructure);
  970. start = positionOffset,
  971. end = positionOffset +
  972. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  973. card->navigo->events[i - 1].used_contract =
  974. bit_slice_to_dec(event_bit_representation, start, end);
  975. card->navigo->events[i - 1].used_contract_available = true;
  976. if(card->navigo->events[i - 1].used_contract > 0) {
  977. card->events_count++;
  978. }
  979. }
  980. // EventDateStamp
  981. event_key = "EventDateStamp";
  982. int positionOffset = get_calypso_node_offset(
  983. event_bit_representation, event_key, IntercodeEventStructure);
  984. start = positionOffset,
  985. end = positionOffset +
  986. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  987. int decimal_value = bit_slice_to_dec(event_bit_representation, start, end);
  988. uint64_t date_timestamp = (decimal_value * 24 * 3600) + epoch + 3600;
  989. datetime_timestamp_to_datetime(
  990. date_timestamp, &card->navigo->events[i - 1].date);
  991. // EventTimeStamp
  992. event_key = "EventTimeStamp";
  993. positionOffset = get_calypso_node_offset(
  994. event_bit_representation, event_key, IntercodeEventStructure);
  995. start = positionOffset,
  996. end = positionOffset +
  997. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  998. decimal_value = bit_slice_to_dec(event_bit_representation, start, end);
  999. card->navigo->events[i - 1].date.hour = (decimal_value * 60) / 3600;
  1000. card->navigo->events[i - 1].date.minute =
  1001. ((decimal_value * 60) % 3600) / 60;
  1002. card->navigo->events[i - 1].date.second =
  1003. ((decimal_value * 60) % 3600) % 60;
  1004. }
  1005. // Select app for special events
  1006. error = select_new_app(
  1007. 0x20, 0x40, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1008. if(error != 0) {
  1009. break;
  1010. }
  1011. // Check the response after selecting app
  1012. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1013. break;
  1014. }
  1015. // Now send the read command for special events
  1016. for(size_t i = 1; i < 4; i++) {
  1017. error = read_new_file(
  1018. i, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1019. if(error != 0) {
  1020. break;
  1021. }
  1022. // Check the response after reading the file
  1023. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1024. break;
  1025. }
  1026. char event_bit_representation[response_length * 8 + 1];
  1027. event_bit_representation[0] = '\0';
  1028. for(size_t i = 0; i < response_length; i++) {
  1029. char bits[9];
  1030. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  1031. byte_to_binary(byte, bits);
  1032. strlcat(
  1033. event_bit_representation, bits, sizeof(event_bit_representation));
  1034. }
  1035. if(bit_slice_to_dec(
  1036. event_bit_representation,
  1037. 0,
  1038. IntercodeEventStructure->container->elements[0].bitmap->size - 1) ==
  1039. 0) {
  1040. break;
  1041. } else {
  1042. card->special_events_count++;
  1043. }
  1044. // 2. EventCode
  1045. const char* event_key = "EventCode";
  1046. if(is_calypso_node_present(
  1047. event_bit_representation, event_key, IntercodeEventStructure)) {
  1048. int positionOffset = get_calypso_node_offset(
  1049. event_bit_representation, event_key, IntercodeEventStructure);
  1050. int start = positionOffset,
  1051. end = positionOffset +
  1052. get_calypso_node_size(event_key, IntercodeEventStructure) -
  1053. 1;
  1054. int decimal_value =
  1055. bit_slice_to_dec(event_bit_representation, start, end);
  1056. card->navigo->special_events[i - 1].transport_type = decimal_value >>
  1057. 4;
  1058. card->navigo->special_events[i - 1].transition = decimal_value & 15;
  1059. }
  1060. // 3. EventResult
  1061. event_key = "EventResult";
  1062. if(is_calypso_node_present(
  1063. event_bit_representation, event_key, IntercodeEventStructure)) {
  1064. int positionOffset = get_calypso_node_offset(
  1065. event_bit_representation, event_key, IntercodeEventStructure);
  1066. int start = positionOffset,
  1067. end = positionOffset +
  1068. get_calypso_node_size(event_key, IntercodeEventStructure) -
  1069. 1;
  1070. card->navigo->special_events[i - 1].result =
  1071. bit_slice_to_dec(event_bit_representation, start, end);
  1072. }
  1073. // 4. EventServiceProvider
  1074. event_key = "EventServiceProvider";
  1075. if(is_calypso_node_present(
  1076. event_bit_representation, event_key, IntercodeEventStructure)) {
  1077. int positionOffset = get_calypso_node_offset(
  1078. event_bit_representation, event_key, IntercodeEventStructure);
  1079. int start = positionOffset,
  1080. end = positionOffset +
  1081. get_calypso_node_size(event_key, IntercodeEventStructure) -
  1082. 1;
  1083. card->navigo->special_events[i - 1].service_provider =
  1084. bit_slice_to_dec(event_bit_representation, start, end);
  1085. }
  1086. // 8. EventLocationId
  1087. event_key = "EventLocationId";
  1088. if(is_calypso_node_present(
  1089. event_bit_representation, event_key, IntercodeEventStructure)) {
  1090. int positionOffset = get_calypso_node_offset(
  1091. event_bit_representation, event_key, IntercodeEventStructure);
  1092. int start = positionOffset,
  1093. end = positionOffset +
  1094. get_calypso_node_size(event_key, IntercodeEventStructure) -
  1095. 1;
  1096. int decimal_value =
  1097. bit_slice_to_dec(event_bit_representation, start, end);
  1098. card->navigo->special_events[i - 1].station_group_id = decimal_value >>
  1099. 9;
  1100. card->navigo->special_events[i - 1].station_id = (decimal_value >> 4) &
  1101. 31;
  1102. card->navigo->special_events[i - 1].station_sub_id = decimal_value &
  1103. 15;
  1104. }
  1105. // 10. EventDevice
  1106. event_key = "EventDevice";
  1107. if(is_calypso_node_present(
  1108. event_bit_representation, event_key, IntercodeEventStructure)) {
  1109. int positionOffset = get_calypso_node_offset(
  1110. event_bit_representation, event_key, IntercodeEventStructure);
  1111. int start = positionOffset,
  1112. end = positionOffset +
  1113. get_calypso_node_size(event_key, IntercodeEventStructure) -
  1114. 1;
  1115. int decimal_value =
  1116. bit_slice_to_dec(event_bit_representation, start, end);
  1117. card->navigo->special_events[i - 1].device = decimal_value;
  1118. }
  1119. // 11. EventRouteNumber
  1120. event_key = "EventRouteNumber";
  1121. if(is_calypso_node_present(
  1122. event_bit_representation, event_key, IntercodeEventStructure)) {
  1123. int positionOffset = get_calypso_node_offset(
  1124. event_bit_representation, event_key, IntercodeEventStructure);
  1125. int start = positionOffset,
  1126. end = positionOffset +
  1127. get_calypso_node_size(event_key, IntercodeEventStructure) -
  1128. 1;
  1129. card->navigo->special_events[i - 1].route_number =
  1130. bit_slice_to_dec(event_bit_representation, start, end);
  1131. card->navigo->special_events[i - 1].route_number_available = true;
  1132. }
  1133. // EventDateStamp
  1134. event_key = "EventDateStamp";
  1135. int positionOffset = get_calypso_node_offset(
  1136. event_bit_representation, event_key, IntercodeEventStructure);
  1137. int start = positionOffset,
  1138. end = positionOffset +
  1139. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  1140. int decimal_value = bit_slice_to_dec(event_bit_representation, start, end);
  1141. uint64_t date_timestamp = (decimal_value * 24 * 3600) + epoch + 3600;
  1142. datetime_timestamp_to_datetime(
  1143. date_timestamp, &card->navigo->special_events[i - 1].date);
  1144. // EventTimeStamp
  1145. event_key = "EventTimeStamp";
  1146. positionOffset = get_calypso_node_offset(
  1147. event_bit_representation, event_key, IntercodeEventStructure);
  1148. start = positionOffset,
  1149. end = positionOffset +
  1150. get_calypso_node_size(event_key, IntercodeEventStructure) - 1;
  1151. decimal_value = bit_slice_to_dec(event_bit_representation, start, end);
  1152. card->navigo->special_events[i - 1].date.hour =
  1153. (decimal_value * 60) / 3600;
  1154. card->navigo->special_events[i - 1].date.minute =
  1155. ((decimal_value * 60) % 3600) / 60;
  1156. card->navigo->special_events[i - 1].date.second =
  1157. ((decimal_value * 60) % 3600) % 60;
  1158. }
  1159. // Free the calypso structure
  1160. free_calypso_structure(IntercodeEventStructure);
  1161. break;
  1162. }
  1163. case CALYPSO_CARD_OPUS: {
  1164. card->opus = malloc(sizeof(OpusCardData));
  1165. card->opus->environment.country_num = card->country_num;
  1166. card->opus->environment.network_num = card->network_num;
  1167. CalypsoApp* OpusEnvHolderStructure = get_opus_env_holder_structure();
  1168. // EnvApplicationVersionNumber
  1169. const char* env_key = "EnvApplicationVersionNumber";
  1170. int positionOffset = get_calypso_node_offset(
  1171. environment_bit_representation, env_key, OpusEnvHolderStructure);
  1172. int start = positionOffset,
  1173. end = positionOffset +
  1174. get_calypso_node_size(env_key, OpusEnvHolderStructure) - 1;
  1175. card->opus->environment.app_version =
  1176. bit_slice_to_dec(environment_bit_representation, start, end);
  1177. // EnvApplicationValidityEndDate
  1178. env_key = "EnvApplicationValidityEndDate";
  1179. positionOffset = get_calypso_node_offset(
  1180. environment_bit_representation, env_key, OpusEnvHolderStructure);
  1181. start = positionOffset,
  1182. end = positionOffset + get_calypso_node_size(env_key, OpusEnvHolderStructure) -
  1183. 1;
  1184. float decimal_value =
  1185. bit_slice_to_dec(environment_bit_representation, start, end);
  1186. uint64_t end_validity_timestamp =
  1187. (decimal_value * 24 * 3600) + (float)epoch + 3600;
  1188. datetime_timestamp_to_datetime(
  1189. end_validity_timestamp, &card->opus->environment.end_dt);
  1190. // HolderDataCardStatus
  1191. env_key = "HolderDataCardStatus";
  1192. positionOffset = get_calypso_node_offset(
  1193. environment_bit_representation, env_key, OpusEnvHolderStructure);
  1194. start = positionOffset,
  1195. end = positionOffset + get_calypso_node_size(env_key, OpusEnvHolderStructure) -
  1196. 1;
  1197. card->opus->holder.card_status =
  1198. bit_slice_to_dec(environment_bit_representation, start, end);
  1199. // HolderDataCommercialID
  1200. env_key = "HolderDataCommercialID";
  1201. positionOffset = get_calypso_node_offset(
  1202. environment_bit_representation, env_key, OpusEnvHolderStructure);
  1203. start = positionOffset,
  1204. end = positionOffset + get_calypso_node_size(env_key, OpusEnvHolderStructure) -
  1205. 1;
  1206. card->opus->holder.commercial_id =
  1207. bit_slice_to_dec(environment_bit_representation, start, end);
  1208. // Free the calypso structure
  1209. free_calypso_structure(OpusEnvHolderStructure);
  1210. // Select app for contracts
  1211. error = select_new_app(
  1212. 0x20, 0x20, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1213. if(error != 0) {
  1214. FURI_LOG_E(TAG, "Failed to select app for contracts");
  1215. break;
  1216. }
  1217. // Check the response after selecting app
  1218. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1219. FURI_LOG_E(
  1220. TAG, "Failed to check response after selecting app for contracts");
  1221. break;
  1222. }
  1223. // Prepare calypso structure
  1224. CalypsoApp* OpusContractStructure = get_opus_contract_structure();
  1225. if(!OpusContractStructure) {
  1226. FURI_LOG_E(TAG, "Failed to load Opus Contract structure");
  1227. break;
  1228. }
  1229. // Now send the read command for contracts
  1230. for(size_t i = 1; i < 5; i++) {
  1231. error = read_new_file(
  1232. i, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1233. if(error != 0) {
  1234. FURI_LOG_E(TAG, "Failed to read contract %d", i);
  1235. break;
  1236. }
  1237. // Check the response after reading the file
  1238. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1239. FURI_LOG_E(
  1240. TAG, "Failed to check response after reading contract %d", i);
  1241. break;
  1242. }
  1243. char bit_representation[response_length * 8 + 1];
  1244. bit_representation[0] = '\0';
  1245. for(size_t i = 0; i < response_length; i++) {
  1246. char bits[9];
  1247. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  1248. byte_to_binary(byte, bits);
  1249. strlcat(bit_representation, bits, sizeof(bit_representation));
  1250. }
  1251. bit_representation[response_length * 8] = '\0';
  1252. if(bit_slice_to_dec(
  1253. bit_representation,
  1254. 0,
  1255. OpusContractStructure->container->elements[1].bitmap->size - 1) ==
  1256. 0) {
  1257. break;
  1258. }
  1259. card->opus->contracts[i - 1].present = 1;
  1260. card->contracts_count++;
  1261. // ContractProvider
  1262. const char* contract_key = "ContractProvider";
  1263. if(is_calypso_node_present(
  1264. bit_representation, contract_key, OpusContractStructure)) {
  1265. int positionOffset = get_calypso_node_offset(
  1266. bit_representation, contract_key, OpusContractStructure);
  1267. int start = positionOffset,
  1268. end = positionOffset +
  1269. get_calypso_node_size(contract_key, OpusContractStructure) -
  1270. 1;
  1271. card->opus->contracts[i - 1].provider =
  1272. bit_slice_to_dec(bit_representation, start, end);
  1273. }
  1274. // ContractTariff
  1275. contract_key = "ContractTariff";
  1276. if(is_calypso_node_present(
  1277. bit_representation, contract_key, OpusContractStructure)) {
  1278. int positionOffset = get_calypso_node_offset(
  1279. bit_representation, contract_key, OpusContractStructure);
  1280. int start = positionOffset,
  1281. end = positionOffset +
  1282. get_calypso_node_size(contract_key, OpusContractStructure) -
  1283. 1;
  1284. card->opus->contracts[i - 1].tariff =
  1285. bit_slice_to_dec(bit_representation, start, end);
  1286. }
  1287. // ContractStartDate
  1288. contract_key = "ContractStartDate";
  1289. if(is_calypso_node_present(
  1290. bit_representation, contract_key, OpusContractStructure)) {
  1291. int positionOffset = get_calypso_node_offset(
  1292. bit_representation, contract_key, OpusContractStructure);
  1293. int start = positionOffset,
  1294. end = positionOffset +
  1295. get_calypso_node_size(contract_key, OpusContractStructure) -
  1296. 1;
  1297. float decimal_value =
  1298. bit_slice_to_dec(bit_representation, start, end) * 24 * 3600;
  1299. uint64_t start_validity_timestamp =
  1300. (decimal_value + (float)epoch) + 3600;
  1301. datetime_timestamp_to_datetime(
  1302. start_validity_timestamp,
  1303. &card->opus->contracts[i - 1].start_date);
  1304. }
  1305. // ContractEndDate
  1306. contract_key = "ContractEndDate";
  1307. if(is_calypso_node_present(
  1308. bit_representation, contract_key, OpusContractStructure)) {
  1309. int positionOffset = get_calypso_node_offset(
  1310. bit_representation, contract_key, OpusContractStructure);
  1311. int start = positionOffset,
  1312. end = positionOffset +
  1313. get_calypso_node_size(contract_key, OpusContractStructure) -
  1314. 1;
  1315. float decimal_value =
  1316. bit_slice_to_dec(bit_representation, start, end) * 24 * 3600;
  1317. uint64_t end_validity_timestamp =
  1318. (decimal_value + (float)epoch) + 3600;
  1319. datetime_timestamp_to_datetime(
  1320. end_validity_timestamp, &card->opus->contracts[i - 1].end_date);
  1321. }
  1322. // ContractStatus
  1323. contract_key = "ContractStatus";
  1324. if(is_calypso_node_present(
  1325. bit_representation, contract_key, OpusContractStructure)) {
  1326. int positionOffset = get_calypso_node_offset(
  1327. bit_representation, contract_key, OpusContractStructure);
  1328. int start = positionOffset,
  1329. end = positionOffset +
  1330. get_calypso_node_size(contract_key, OpusContractStructure) -
  1331. 1;
  1332. card->opus->contracts[i - 1].status =
  1333. bit_slice_to_dec(bit_representation, start, end);
  1334. }
  1335. // ContractSaleDate + ContractSaleTime
  1336. contract_key = "ContractSaleDate";
  1337. int positionOffset = get_calypso_node_offset(
  1338. bit_representation, contract_key, OpusContractStructure);
  1339. int start = positionOffset,
  1340. end = positionOffset +
  1341. get_calypso_node_size(contract_key, OpusContractStructure) - 1;
  1342. uint64_t sale_date_timestamp =
  1343. (bit_slice_to_dec(bit_representation, start, end) + (float)epoch) +
  1344. 3600;
  1345. datetime_timestamp_to_datetime(
  1346. sale_date_timestamp, &card->opus->contracts[i - 1].sale_date);
  1347. contract_key = "ContractSaleTime";
  1348. positionOffset = get_calypso_node_offset(
  1349. bit_representation, contract_key, OpusContractStructure);
  1350. start = positionOffset,
  1351. end = positionOffset +
  1352. get_calypso_node_size(contract_key, OpusContractStructure) - 1;
  1353. int decimal_value = bit_slice_to_dec(bit_representation, start, end);
  1354. card->opus->contracts[i - 1].sale_date.hour = (decimal_value * 60) / 3600;
  1355. card->opus->contracts[i - 1].sale_date.minute =
  1356. ((decimal_value * 60) % 3600) / 60;
  1357. card->opus->contracts[i - 1].sale_date.second =
  1358. ((decimal_value * 60) % 3600) % 60;
  1359. }
  1360. // Free the calypso structure
  1361. free_calypso_structure(OpusContractStructure);
  1362. // Select app for events
  1363. error = select_new_app(
  1364. 0x20, 0x10, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1365. if(error != 0) {
  1366. break;
  1367. }
  1368. // Check the response after selecting app
  1369. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1370. break;
  1371. }
  1372. // Load the calypso structure for events
  1373. CalypsoApp* OpusEventStructure = get_opus_event_structure();
  1374. if(!OpusEventStructure) {
  1375. FURI_LOG_E(TAG, "Failed to load Opus Event structure");
  1376. break;
  1377. }
  1378. // Now send the read command for events
  1379. for(size_t i = 1; i < 4; i++) {
  1380. error = read_new_file(
  1381. i, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1382. if(error != 0) {
  1383. break;
  1384. }
  1385. // Check the response after reading the file
  1386. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1387. break;
  1388. }
  1389. char event_bit_representation[response_length * 8 + 1];
  1390. event_bit_representation[0] = '\0';
  1391. for(size_t i = 0; i < response_length; i++) {
  1392. char bits[9];
  1393. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  1394. byte_to_binary(byte, bits);
  1395. strlcat(
  1396. event_bit_representation, bits, sizeof(event_bit_representation));
  1397. }
  1398. // EventServiceProvider
  1399. const char* event_key = "EventServiceProvider";
  1400. if(is_calypso_node_present(
  1401. event_bit_representation, event_key, OpusEventStructure)) {
  1402. int positionOffset = get_calypso_node_offset(
  1403. event_bit_representation, event_key, OpusEventStructure);
  1404. int start = positionOffset,
  1405. end = positionOffset +
  1406. get_calypso_node_size(event_key, OpusEventStructure) - 1;
  1407. card->opus->events[i - 1].service_provider =
  1408. bit_slice_to_dec(event_bit_representation, start, end);
  1409. }
  1410. // EventRouteNumber
  1411. event_key = "EventRouteNumber";
  1412. if(is_calypso_node_present(
  1413. event_bit_representation, event_key, OpusEventStructure)) {
  1414. int positionOffset = get_calypso_node_offset(
  1415. event_bit_representation, event_key, OpusEventStructure);
  1416. int start = positionOffset,
  1417. end = positionOffset +
  1418. get_calypso_node_size(event_key, OpusEventStructure) - 1;
  1419. card->opus->events[i - 1].route_number =
  1420. bit_slice_to_dec(event_bit_representation, start, end);
  1421. card->opus->events[i - 1].route_number_available = true;
  1422. }
  1423. // EventContractPointer
  1424. event_key = "EventContractPointer";
  1425. if(is_calypso_node_present(
  1426. event_bit_representation, event_key, OpusEventStructure)) {
  1427. int positionOffset = get_calypso_node_offset(
  1428. event_bit_representation, event_key, OpusEventStructure);
  1429. int start = positionOffset,
  1430. end = positionOffset +
  1431. get_calypso_node_size(event_key, OpusEventStructure) - 1;
  1432. card->opus->events[i - 1].used_contract =
  1433. bit_slice_to_dec(event_bit_representation, start, end);
  1434. card->opus->events[i - 1].used_contract_available = true;
  1435. if(card->opus->events[i - 1].used_contract > 0) {
  1436. card->events_count++;
  1437. }
  1438. }
  1439. // EventDateStamp
  1440. event_key = "EventDateStamp";
  1441. int positionOffset = get_calypso_node_offset(
  1442. event_bit_representation, event_key, OpusEventStructure);
  1443. int start = positionOffset,
  1444. end = positionOffset +
  1445. get_calypso_node_size(event_key, OpusEventStructure) - 1;
  1446. int decimal_value = bit_slice_to_dec(event_bit_representation, start, end);
  1447. uint64_t date_timestamp = (decimal_value * 24 * 3600) + epoch + 3600;
  1448. datetime_timestamp_to_datetime(
  1449. date_timestamp, &card->opus->events[i - 1].date);
  1450. // EventTimeStamp
  1451. event_key = "EventTimeStamp";
  1452. positionOffset = get_calypso_node_offset(
  1453. event_bit_representation, event_key, OpusEventStructure);
  1454. start = positionOffset,
  1455. end = positionOffset +
  1456. get_calypso_node_size(event_key, OpusEventStructure) - 1;
  1457. decimal_value = bit_slice_to_dec(event_bit_representation, start, end);
  1458. card->opus->events[i - 1].date.hour = (decimal_value * 60) / 3600;
  1459. card->opus->events[i - 1].date.minute = ((decimal_value * 60) % 3600) / 60;
  1460. card->opus->events[i - 1].date.second = ((decimal_value * 60) % 3600) % 60;
  1461. }
  1462. // Free the calypso structure
  1463. free_calypso_structure(OpusEventStructure);
  1464. break;
  1465. }
  1466. case CALYPSO_CARD_UNKNOWN: {
  1467. start = 3;
  1468. end = 6;
  1469. int country_num =
  1470. bit_slice_to_dec(environment_bit_representation, start, end) * 100 +
  1471. bit_slice_to_dec(environment_bit_representation, start + 4, end + 4) * 10 +
  1472. bit_slice_to_dec(environment_bit_representation, start + 8, end + 8);
  1473. start = 15;
  1474. end = 18;
  1475. int network_num =
  1476. bit_slice_to_dec(environment_bit_representation, start, end) * 100 +
  1477. bit_slice_to_dec(environment_bit_representation, start + 4, end + 4) * 10 +
  1478. bit_slice_to_dec(environment_bit_representation, start + 8, end + 8);
  1479. card->card_type = guess_card_type(country_num, network_num);
  1480. if(card->card_type == CALYPSO_CARD_RAVKAV) {
  1481. card->ravkav = malloc(sizeof(RavKavCardData));
  1482. error = select_new_app(
  1483. 0x20, 0x20, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1484. if(error != 0) {
  1485. FURI_LOG_E(TAG, "Failed to select app for contracts");
  1486. break;
  1487. }
  1488. // Check the response after selecting app
  1489. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1490. FURI_LOG_E(
  1491. TAG, "Failed to check response after selecting app for contracts");
  1492. break;
  1493. }
  1494. // Prepare calypso structure
  1495. CalypsoApp* RavKavContractStructure = get_ravkav_contract_structure();
  1496. if(!RavKavContractStructure) {
  1497. FURI_LOG_E(TAG, "Failed to load RavKav Contract structure");
  1498. break;
  1499. }
  1500. // Now send the read command for contracts
  1501. for(size_t i = 1; i < 2; i++) {
  1502. error = read_new_file(
  1503. i, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1504. if(error != 0) {
  1505. FURI_LOG_E(TAG, "Failed to read contract %d", i);
  1506. break;
  1507. }
  1508. // Check the response after reading the file
  1509. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1510. FURI_LOG_E(
  1511. TAG, "Failed to check response after reading contract %d", i);
  1512. break;
  1513. }
  1514. char bit_representation[response_length * 8 + 1];
  1515. bit_representation[0] = '\0';
  1516. for(size_t i = 0; i < response_length; i++) {
  1517. char bits[9];
  1518. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  1519. byte_to_binary(byte, bits);
  1520. strlcat(bit_representation, bits, sizeof(bit_representation));
  1521. }
  1522. bit_representation[response_length * 8] = '\0';
  1523. card->ravkav->contracts[i - 1].present = 1;
  1524. card->events_count = 3;
  1525. card->contracts_count++;
  1526. // ContractVersion
  1527. const char* contract_key = "ContractVersion";
  1528. if(is_calypso_node_present(
  1529. bit_representation, contract_key, RavKavContractStructure)) {
  1530. int positionOffset = get_calypso_node_offset(
  1531. bit_representation, contract_key, RavKavContractStructure);
  1532. int start = positionOffset,
  1533. end = positionOffset +
  1534. get_calypso_node_size(
  1535. contract_key, RavKavContractStructure) -
  1536. 1;
  1537. card->ravkav->contracts[i - 1].version =
  1538. bit_slice_to_dec(bit_representation, start, end);
  1539. }
  1540. // ContractStartDate
  1541. contract_key = "ContractStartDate";
  1542. if(is_calypso_node_present(
  1543. bit_representation, contract_key, RavKavContractStructure)) {
  1544. int positionOffset = get_calypso_node_offset(
  1545. bit_representation, contract_key, RavKavContractStructure);
  1546. int start = positionOffset,
  1547. end = positionOffset +
  1548. get_calypso_node_size(
  1549. contract_key, RavKavContractStructure) -
  1550. 1;
  1551. int decimal_value =
  1552. bit_slice_to_dec(bit_representation, start, end);
  1553. uint32_t invertedDays = decimal_value ^ 0x3FFF;
  1554. int start_validity_timestamp =
  1555. (invertedDays * 3600 * 24) + epoch + 3600;
  1556. datetime_timestamp_to_datetime(
  1557. start_validity_timestamp,
  1558. &card->ravkav->contracts[i - 1].start_date);
  1559. }
  1560. // ContractProvider
  1561. contract_key = "ContractProvider";
  1562. if(is_calypso_node_present(
  1563. bit_representation, contract_key, RavKavContractStructure)) {
  1564. int positionOffset = get_calypso_node_offset(
  1565. bit_representation, contract_key, RavKavContractStructure);
  1566. int start = positionOffset,
  1567. end = positionOffset +
  1568. get_calypso_node_size(
  1569. contract_key, RavKavContractStructure) -
  1570. 1;
  1571. card->ravkav->contracts[i - 1].provider =
  1572. bit_slice_to_dec(bit_representation, start, end);
  1573. FURI_LOG_I(
  1574. TAG,
  1575. "issuer number: %d",
  1576. card->ravkav->contracts[i - 1].provider);
  1577. }
  1578. // ContractTariff
  1579. contract_key = "ContractTariff";
  1580. if(is_calypso_node_present(
  1581. bit_representation, contract_key, RavKavContractStructure)) {
  1582. int positionOffset = get_calypso_node_offset(
  1583. bit_representation, contract_key, RavKavContractStructure);
  1584. int start = positionOffset,
  1585. end = positionOffset +
  1586. get_calypso_node_size(
  1587. contract_key, RavKavContractStructure) -
  1588. 1;
  1589. card->ravkav->contracts[i - 1].tariff =
  1590. bit_slice_to_dec(bit_representation, start, end);
  1591. }
  1592. // ContractSaleDate
  1593. contract_key = "ContractSaleDate";
  1594. int positionOffset = get_calypso_node_offset(
  1595. bit_representation, contract_key, RavKavContractStructure);
  1596. int start = positionOffset,
  1597. end =
  1598. positionOffset +
  1599. get_calypso_node_size(contract_key, RavKavContractStructure) -
  1600. 1;
  1601. uint64_t sale_date_timestamp =
  1602. (bit_slice_to_dec(bit_representation, start, end) * 3600 * 24) +
  1603. (float)epoch + 3600;
  1604. datetime_timestamp_to_datetime(
  1605. sale_date_timestamp, &card->ravkav->contracts[i - 1].sale_date);
  1606. // ContractSaleDevice
  1607. contract_key = "ContractSaleDevice";
  1608. if(is_calypso_node_present(
  1609. bit_representation, contract_key, RavKavContractStructure)) {
  1610. int positionOffset = get_calypso_node_offset(
  1611. bit_representation, contract_key, RavKavContractStructure);
  1612. int start = positionOffset,
  1613. end = positionOffset +
  1614. get_calypso_node_size(
  1615. contract_key, RavKavContractStructure) -
  1616. 1;
  1617. card->ravkav->contracts[i - 1].sale_device =
  1618. bit_slice_to_dec(bit_representation, start, end);
  1619. }
  1620. // ContractSaleNumber
  1621. contract_key = "ContractSaleNumber";
  1622. if(is_calypso_node_present(
  1623. bit_representation, contract_key, RavKavContractStructure)) {
  1624. int positionOffset = get_calypso_node_offset(
  1625. bit_representation, contract_key, RavKavContractStructure);
  1626. int start = positionOffset,
  1627. end = positionOffset +
  1628. get_calypso_node_size(
  1629. contract_key, RavKavContractStructure) -
  1630. 1;
  1631. card->ravkav->contracts[i - 1].sale_number =
  1632. bit_slice_to_dec(bit_representation, start, end);
  1633. }
  1634. // ContractInterchange
  1635. contract_key = "ContractInterchange";
  1636. if(is_calypso_node_present(
  1637. bit_representation, contract_key, RavKavContractStructure)) {
  1638. int positionOffset = get_calypso_node_offset(
  1639. bit_representation, contract_key, RavKavContractStructure);
  1640. int start = positionOffset,
  1641. end = positionOffset +
  1642. get_calypso_node_size(
  1643. contract_key, RavKavContractStructure) -
  1644. 1;
  1645. card->ravkav->contracts[i - 1].interchange =
  1646. bit_slice_to_dec(bit_representation, start, end);
  1647. }
  1648. // ContractInterchange
  1649. contract_key = "ContractRestrictCode";
  1650. if(is_calypso_node_present(
  1651. bit_representation, contract_key, RavKavContractStructure)) {
  1652. int positionOffset = get_calypso_node_offset(
  1653. bit_representation, contract_key, RavKavContractStructure);
  1654. int start = positionOffset,
  1655. end = positionOffset +
  1656. get_calypso_node_size(
  1657. contract_key, RavKavContractStructure) -
  1658. 1;
  1659. card->ravkav->contracts[i - 1].restrict_code_available = true;
  1660. card->ravkav->contracts[i - 1].restrict_code =
  1661. bit_slice_to_dec(bit_representation, start, end);
  1662. }
  1663. // ContractRestrictDuration
  1664. contract_key = "ContractRestrictDuration";
  1665. if(is_calypso_node_present(
  1666. bit_representation, contract_key, RavKavContractStructure)) {
  1667. int positionOffset = get_calypso_node_offset(
  1668. bit_representation, contract_key, RavKavContractStructure);
  1669. int start = positionOffset,
  1670. end = positionOffset +
  1671. get_calypso_node_size(
  1672. contract_key, RavKavContractStructure) -
  1673. 1;
  1674. card->ravkav->contracts[i - 1].restrict_duration_available = true;
  1675. if(card->ravkav->contracts[i - 1].restrict_code == 16) {
  1676. card->ravkav->contracts[i - 1].restrict_duration =
  1677. bit_slice_to_dec(bit_representation, start, end) * 5;
  1678. } else {
  1679. card->ravkav->contracts[i - 1].restrict_duration =
  1680. bit_slice_to_dec(bit_representation, start, end) * 30;
  1681. }
  1682. }
  1683. // ContractEndDate
  1684. contract_key = "ContractEndDate";
  1685. if(is_calypso_node_present(
  1686. bit_representation, contract_key, RavKavContractStructure)) {
  1687. int positionOffset = get_calypso_node_offset(
  1688. bit_representation, contract_key, RavKavContractStructure);
  1689. int start = positionOffset,
  1690. end = positionOffset +
  1691. get_calypso_node_size(
  1692. contract_key, RavKavContractStructure) -
  1693. 1;
  1694. card->ravkav->contracts[i - 1].end_date_available = true;
  1695. int end_date_timestamp =
  1696. (bit_slice_to_dec(bit_representation, start, end) * 3600 *
  1697. 24) +
  1698. epoch + 3600;
  1699. datetime_timestamp_to_datetime(
  1700. end_date_timestamp, &card->ravkav->contracts[i - 1].end_date);
  1701. }
  1702. }
  1703. // Free the calypso structure
  1704. free_calypso_structure(RavKavContractStructure);
  1705. error = select_new_app(
  1706. 0x20, 0x01, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1707. if(error != 0) {
  1708. FURI_LOG_E(TAG, "Failed to select app for environment");
  1709. break;
  1710. }
  1711. // Check the response after selecting app
  1712. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1713. FURI_LOG_E(
  1714. TAG,
  1715. "Failed to check response after selecting app for environment");
  1716. break;
  1717. }
  1718. // Prepare calypso structure
  1719. CalypsoApp* RavKavEnvStructure = get_ravkav_env_holder_structure();
  1720. if(!RavKavEnvStructure) {
  1721. FURI_LOG_E(TAG, "Failed to load RavKav environment structure");
  1722. break;
  1723. }
  1724. // Now send the read command for environment
  1725. error = read_new_file(
  1726. 1, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1727. if(error != 0) {
  1728. FURI_LOG_E(TAG, "Failed to read environment");
  1729. break;
  1730. }
  1731. // Check the response after reading the file
  1732. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1733. FURI_LOG_E(TAG, "Failed to check response after reading environment");
  1734. break;
  1735. }
  1736. char env_bit_representation[response_length * 8 + 1];
  1737. env_bit_representation[0] = '\0';
  1738. for(size_t i = 0; i < response_length; i++) {
  1739. char bits[9];
  1740. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  1741. byte_to_binary(byte, bits);
  1742. strlcat(env_bit_representation, bits, sizeof(env_bit_representation));
  1743. }
  1744. env_bit_representation[response_length * 8] = '\0';
  1745. // EnvApplicationVersionNumber
  1746. char* env_key = "EnvApplicationVersionNumber";
  1747. if(is_calypso_node_present(
  1748. env_bit_representation, env_key, RavKavEnvStructure)) {
  1749. int positionOffset = get_calypso_node_offset(
  1750. env_bit_representation, env_key, RavKavEnvStructure);
  1751. int start = positionOffset,
  1752. end = positionOffset +
  1753. get_calypso_node_size(env_key, RavKavEnvStructure) - 1;
  1754. card->ravkav->environment.app_num =
  1755. bit_slice_to_dec(env_bit_representation, start, end);
  1756. }
  1757. // EnvApplicationNumber
  1758. env_key = "EnvApplicationNumber";
  1759. if(is_calypso_node_present(
  1760. env_bit_representation, env_key, RavKavEnvStructure)) {
  1761. int positionOffset = get_calypso_node_offset(
  1762. env_bit_representation, env_key, RavKavEnvStructure);
  1763. int start = positionOffset,
  1764. end = positionOffset +
  1765. get_calypso_node_size(env_key, RavKavEnvStructure) - 1;
  1766. card->ravkav->environment.app_num =
  1767. bit_slice_to_dec(env_bit_representation, start, end);
  1768. }
  1769. // EnvDateOfIssue
  1770. env_key = "EnvDateOfIssue";
  1771. if(is_calypso_node_present(
  1772. env_bit_representation, env_key, RavKavEnvStructure)) {
  1773. int positionOffset = get_calypso_node_offset(
  1774. env_bit_representation, env_key, RavKavEnvStructure);
  1775. int start = positionOffset,
  1776. end = positionOffset +
  1777. get_calypso_node_size(env_key, RavKavEnvStructure) - 1;
  1778. uint64_t issue_date_timestamp =
  1779. (bit_slice_to_dec(env_bit_representation, start, end) * 3600 *
  1780. 24) +
  1781. (float)epoch + 3600;
  1782. datetime_timestamp_to_datetime(
  1783. issue_date_timestamp, &card->ravkav->environment.issue_dt);
  1784. }
  1785. // EnvEndValidity
  1786. env_key = "EnvEndValidity";
  1787. if(is_calypso_node_present(
  1788. env_bit_representation, env_key, RavKavEnvStructure)) {
  1789. int positionOffset = get_calypso_node_offset(
  1790. env_bit_representation, env_key, RavKavEnvStructure);
  1791. int start = positionOffset,
  1792. end = positionOffset +
  1793. get_calypso_node_size(env_key, RavKavEnvStructure) - 1;
  1794. uint64_t end_date_timestamp =
  1795. (bit_slice_to_dec(env_bit_representation, start, end) * 3600 *
  1796. 24) +
  1797. (float)epoch + 3600;
  1798. datetime_timestamp_to_datetime(
  1799. end_date_timestamp, &card->ravkav->environment.end_dt);
  1800. }
  1801. // EnvPayMethod
  1802. env_key = "EnvPayMethod";
  1803. if(is_calypso_node_present(
  1804. env_bit_representation, env_key, RavKavEnvStructure)) {
  1805. int positionOffset = get_calypso_node_offset(
  1806. env_bit_representation, env_key, RavKavEnvStructure);
  1807. int start = positionOffset,
  1808. end = positionOffset +
  1809. get_calypso_node_size(env_key, RavKavEnvStructure) - 1;
  1810. card->ravkav->environment.pay_method =
  1811. bit_slice_to_dec(env_bit_representation, start, end);
  1812. }
  1813. free_calypso_structure(RavKavEnvStructure);
  1814. // Select app for events
  1815. error = select_new_app(
  1816. 0x20, 0x10, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1817. if(error != 0) {
  1818. break;
  1819. }
  1820. // Check the response after selecting app
  1821. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1822. break;
  1823. }
  1824. // Load the calypso structure for events
  1825. CalypsoApp* RavKavEventStructure = get_ravkav_event_structure();
  1826. if(!RavKavEventStructure) {
  1827. FURI_LOG_E(TAG, "Failed to load Opus Event structure");
  1828. break;
  1829. }
  1830. // Now send the read command for events
  1831. for(size_t i = 1; i < 4; i++) {
  1832. error = read_new_file(
  1833. i, tx_buffer, rx_buffer, iso14443_4b_poller, app, &stage);
  1834. if(error != 0) {
  1835. break;
  1836. }
  1837. // Check the response after reading the file
  1838. if(check_response(rx_buffer, app, &stage, &response_length) != 0) {
  1839. break;
  1840. }
  1841. char event_bit_representation[response_length * 8 + 1];
  1842. event_bit_representation[0] = '\0';
  1843. for(size_t i = 0; i < response_length; i++) {
  1844. char bits[9];
  1845. uint8_t byte = bit_buffer_get_byte(rx_buffer, i);
  1846. byte_to_binary(byte, bits);
  1847. strlcat(
  1848. event_bit_representation,
  1849. bits,
  1850. sizeof(event_bit_representation));
  1851. }
  1852. FURI_LOG_I(TAG, "event bit repr %s", event_bit_representation);
  1853. // EventVersion
  1854. const char* event_key = "EventVersion";
  1855. if(is_calypso_node_present(
  1856. event_bit_representation, event_key, RavKavEventStructure)) {
  1857. int positionOffset = get_calypso_node_offset(
  1858. event_bit_representation, event_key, RavKavEventStructure);
  1859. int start = positionOffset,
  1860. end = positionOffset +
  1861. get_calypso_node_size(event_key, RavKavEventStructure) -
  1862. 1;
  1863. card->ravkav->events[i - 1].event_version =
  1864. bit_slice_to_dec(event_bit_representation, start, end);
  1865. }
  1866. // EventServiceProvider
  1867. event_key = "EventServiceProvider";
  1868. if(is_calypso_node_present(
  1869. event_bit_representation, event_key, RavKavEventStructure)) {
  1870. int positionOffset = get_calypso_node_offset(
  1871. event_bit_representation, event_key, RavKavEventStructure);
  1872. int start = positionOffset,
  1873. end = positionOffset +
  1874. get_calypso_node_size(event_key, RavKavEventStructure) -
  1875. 1;
  1876. FURI_LOG_I(TAG, "service provider: start: %d, end %d", start, end);
  1877. card->ravkav->events[i - 1].service_provider =
  1878. bit_slice_to_dec(event_bit_representation, start, end);
  1879. }
  1880. // EventContractID
  1881. event_key = "EventContractID";
  1882. if(is_calypso_node_present(
  1883. event_bit_representation, event_key, RavKavEventStructure)) {
  1884. int positionOffset = get_calypso_node_offset(
  1885. event_bit_representation, event_key, RavKavEventStructure);
  1886. int start = positionOffset,
  1887. end = positionOffset +
  1888. get_calypso_node_size(event_key, RavKavEventStructure) -
  1889. 1;
  1890. card->ravkav->events[i - 1].contract_id =
  1891. bit_slice_to_dec(event_bit_representation, start, end);
  1892. FURI_LOG_I(TAG, "2: start: %d, end %d", start, end);
  1893. }
  1894. // EventAreaID
  1895. event_key = "EventAreaID";
  1896. if(is_calypso_node_present(
  1897. event_bit_representation, event_key, RavKavEventStructure)) {
  1898. int positionOffset = get_calypso_node_offset(
  1899. event_bit_representation, event_key, RavKavEventStructure);
  1900. int start = positionOffset,
  1901. end = positionOffset +
  1902. get_calypso_node_size(event_key, RavKavEventStructure) -
  1903. 1;
  1904. card->ravkav->events[i - 1].area_id =
  1905. bit_slice_to_dec(event_bit_representation, start, end);
  1906. FURI_LOG_I(TAG, "3: start: %d, end %d", start, end);
  1907. }
  1908. // EventType
  1909. event_key = "EventType";
  1910. if(is_calypso_node_present(
  1911. event_bit_representation, event_key, RavKavEventStructure)) {
  1912. int positionOffset = get_calypso_node_offset(
  1913. event_bit_representation, event_key, RavKavEventStructure);
  1914. int start = positionOffset,
  1915. end = positionOffset +
  1916. get_calypso_node_size(event_key, RavKavEventStructure) -
  1917. 1;
  1918. card->ravkav->events[i - 1].type =
  1919. bit_slice_to_dec(event_bit_representation, start, end);
  1920. FURI_LOG_I(TAG, "4: start: %d, end %d", start, end);
  1921. }
  1922. // EventRouteNumber
  1923. event_key = "EventExtension";
  1924. if(is_calypso_node_present(
  1925. event_bit_representation, event_key, RavKavEventStructure)) {
  1926. int positionOffset = get_calypso_node_offset(
  1927. event_bit_representation, event_key, RavKavEventStructure);
  1928. int start = positionOffset,
  1929. end = positionOffset +
  1930. get_calypso_node_size(event_key, RavKavEventStructure) -
  1931. 1;
  1932. FURI_LOG_I(TAG, "event extension : start: %d, end %d", start, end);
  1933. FURI_LOG_I(
  1934. TAG,
  1935. "event extension bitmap: %d",
  1936. bit_slice_to_dec(event_bit_representation, start, end));
  1937. }
  1938. // EventTime
  1939. event_key = "EventTime";
  1940. if(is_calypso_node_present(
  1941. event_bit_representation, event_key, RavKavEventStructure)) {
  1942. int positionOffset = get_calypso_node_offset(
  1943. event_bit_representation, event_key, RavKavEventStructure);
  1944. int start = positionOffset,
  1945. end = positionOffset +
  1946. get_calypso_node_size(event_key, RavKavEventStructure) -
  1947. 1;
  1948. uint64_t event_timestamp =
  1949. bit_slice_to_dec(event_bit_representation, start, end) +
  1950. (float)epoch + 3600;
  1951. datetime_timestamp_to_datetime(
  1952. event_timestamp, &card->ravkav->events[i - 1].time);
  1953. FURI_LOG_I(TAG, "5: start: %d, end %d", start, end);
  1954. }
  1955. // EventInterchangeFlag
  1956. event_key = "EventInterchangeFlag";
  1957. if(is_calypso_node_present(
  1958. event_bit_representation, event_key, RavKavEventStructure)) {
  1959. int positionOffset = get_calypso_node_offset(
  1960. event_bit_representation, event_key, RavKavEventStructure);
  1961. int start = positionOffset,
  1962. end = positionOffset +
  1963. get_calypso_node_size(event_key, RavKavEventStructure) -
  1964. 1;
  1965. card->ravkav->events[i - 1].interchange_flag =
  1966. bit_slice_to_dec(event_bit_representation, start, end);
  1967. FURI_LOG_I(TAG, "6: start: %d, end %d", start, end);
  1968. }
  1969. // EventRouteNumber
  1970. event_key = "EventRouteNumber";
  1971. if(is_calypso_node_present(
  1972. event_bit_representation, event_key, RavKavEventStructure)) {
  1973. int positionOffset = get_calypso_node_offset(
  1974. event_bit_representation, event_key, RavKavEventStructure);
  1975. int start = positionOffset,
  1976. end = positionOffset +
  1977. get_calypso_node_size(event_key, RavKavEventStructure) -
  1978. 1;
  1979. card->ravkav->events[i - 1].route_number =
  1980. bit_slice_to_dec(event_bit_representation, start, end);
  1981. card->ravkav->events[i - 1].route_number_available = true;
  1982. FURI_LOG_I(TAG, "7: start: %d, end %d", start, end);
  1983. }
  1984. // EventRouteNumber
  1985. event_key = "EventfareCode";
  1986. if(is_calypso_node_present(
  1987. event_bit_representation, event_key, RavKavEventStructure)) {
  1988. int positionOffset = get_calypso_node_offset(
  1989. event_bit_representation, event_key, RavKavEventStructure);
  1990. int start = positionOffset,
  1991. end = positionOffset +
  1992. get_calypso_node_size(event_key, RavKavEventStructure) -
  1993. 1;
  1994. card->ravkav->events[i - 1].fare_code =
  1995. bit_slice_to_dec(event_bit_representation, start, end);
  1996. card->ravkav->events[i - 1].fare_code = true;
  1997. FURI_LOG_I(TAG, "8: start: %d, end %d", start, end);
  1998. }
  1999. // EventRouteNumber
  2000. event_key = "EventDebitAmount";
  2001. if(is_calypso_node_present(
  2002. event_bit_representation, event_key, RavKavEventStructure)) {
  2003. int positionOffset = get_calypso_node_offset(
  2004. event_bit_representation, event_key, RavKavEventStructure);
  2005. int start = positionOffset,
  2006. end = positionOffset +
  2007. get_calypso_node_size(event_key, RavKavEventStructure) -
  2008. 1;
  2009. card->ravkav->events[i - 1].debit_amount =
  2010. bit_slice_to_dec(event_bit_representation, start, end) / 100.0;
  2011. card->ravkav->events[i - 1].debit_amount_available = true;
  2012. FURI_LOG_I(TAG, "9: start: %d, end %d", start, end);
  2013. }
  2014. // EventRouteNumber
  2015. event_key = "Location";
  2016. if(is_calypso_node_present(
  2017. event_bit_representation, event_key, RavKavEventStructure)) {
  2018. int positionOffset = get_calypso_node_offset(
  2019. event_bit_representation, event_key, RavKavEventStructure);
  2020. int start = positionOffset,
  2021. end = positionOffset +
  2022. get_calypso_node_size(event_key, RavKavEventStructure) -
  2023. 1;
  2024. FURI_LOG_I(TAG, "location : start: %d, end %d", start, end);
  2025. FURI_LOG_I(
  2026. TAG,
  2027. "locatrion bitmap: %d",
  2028. bit_slice_to_dec(event_bit_representation, start, end));
  2029. }
  2030. }
  2031. // Free the calypso structure
  2032. free_calypso_structure(RavKavEventStructure);
  2033. break;
  2034. }
  2035. }
  2036. default:
  2037. break;
  2038. }
  2039. widget_add_text_scroll_element(
  2040. widget, 0, 0, 128, 64, furi_string_get_cstr(parsed_data));
  2041. CalypsoContext* context = malloc(sizeof(CalypsoContext));
  2042. context->card = card;
  2043. context->page_id = 0;
  2044. context->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  2045. app->calypso_context = context;
  2046. // Ensure no nested mutexes
  2047. furi_mutex_acquire(context->mutex, FuriWaitForever);
  2048. update_page_info(app, parsed_data);
  2049. furi_mutex_release(context->mutex);
  2050. widget_add_text_scroll_element(
  2051. widget, 0, 0, 128, 64, furi_string_get_cstr(parsed_data));
  2052. // Ensure no nested mutexes
  2053. furi_mutex_acquire(context->mutex, FuriWaitForever);
  2054. update_widget_elements(app);
  2055. furi_mutex_release(context->mutex);
  2056. furi_string_free(parsed_data);
  2057. view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewWidget);
  2058. metroflip_app_blink_stop(app);
  2059. stage = MetroflipPollerEventTypeSuccess;
  2060. next_command = NfcCommandStop;
  2061. } while(false);
  2062. if(stage != MetroflipPollerEventTypeSuccess) {
  2063. next_command = NfcCommandStop;
  2064. }
  2065. }
  2066. }
  2067. bit_buffer_free(tx_buffer);
  2068. bit_buffer_free(rx_buffer);
  2069. return next_command;
  2070. }
  2071. void metroflip_scene_calypso_on_enter(void* context) {
  2072. Metroflip* app = context;
  2073. dolphin_deed(DolphinDeedNfcRead);
  2074. // Setup view
  2075. Popup* popup = app->popup;
  2076. popup_set_header(popup, "Apply\n card to\nthe back", 68, 30, AlignLeft, AlignTop);
  2077. popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
  2078. // Start worker
  2079. view_dispatcher_switch_to_view(app->view_dispatcher, MetroflipViewPopup);
  2080. nfc_scanner_alloc(app->nfc);
  2081. app->poller = nfc_poller_alloc(app->nfc, NfcProtocolIso14443_4b);
  2082. nfc_poller_start(app->poller, metroflip_scene_calypso_poller_callback, app);
  2083. metroflip_app_blink_start(app);
  2084. }
  2085. bool metroflip_scene_calypso_on_event(void* context, SceneManagerEvent event) {
  2086. Metroflip* app = context;
  2087. bool consumed = false;
  2088. if(event.type == SceneManagerEventTypeCustom) {
  2089. if(event.event == MetroflipPollerEventTypeCardDetect) {
  2090. Popup* popup = app->popup;
  2091. popup_set_header(popup, "Scanning..", 68, 30, AlignLeft, AlignTop);
  2092. consumed = true;
  2093. } else if(event.event == MetroflipCustomEventPollerFileNotFound) {
  2094. Popup* popup = app->popup;
  2095. popup_set_header(popup, "Read Error,\n wrong card", 68, 30, AlignLeft, AlignTop);
  2096. consumed = true;
  2097. } else if(event.event == MetroflipCustomEventPollerFail) {
  2098. Popup* popup = app->popup;
  2099. popup_set_header(popup, "Error, try\n again", 68, 30, AlignLeft, AlignTop);
  2100. consumed = true;
  2101. }
  2102. } else if(event.type == SceneManagerEventTypeBack) {
  2103. scene_manager_search_and_switch_to_previous_scene(app->scene_manager, MetroflipSceneStart);
  2104. consumed = true;
  2105. }
  2106. return consumed;
  2107. }
  2108. void metroflip_scene_calypso_on_exit(void* context) {
  2109. Metroflip* app = context;
  2110. if(app->poller) {
  2111. nfc_poller_stop(app->poller);
  2112. nfc_poller_free(app->poller);
  2113. }
  2114. metroflip_app_blink_stop(app);
  2115. widget_reset(app->widget);
  2116. // Clear view
  2117. popup_reset(app->popup);
  2118. if(app->calypso_context) {
  2119. CalypsoContext* ctx = app->calypso_context;
  2120. free(ctx->card->navigo);
  2121. free(ctx->card->opus);
  2122. free(ctx->card);
  2123. furi_mutex_free(ctx->mutex);
  2124. free(ctx);
  2125. app->calypso_context = NULL;
  2126. }
  2127. }