taler-digitizer.c (45663B)
1 /* 2 This file is part of TALER cash2ecash 3 Copyright (C) 2026 GNUnet e.V. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU Affero General Public License as 7 published by the Free Software Foundation, either version 3 of the 8 License, or (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <https://www.gnu.org/licenses/>. 18 */ 19 20 /** 21 * @file taler-digitizer.c 22 * @brief runs the logic for the embeded Cash Digitizer machine 23 * @author Reto Tellenbach 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <signal.h> 29 #include <gnunet/gnunet_util_lib.h> 30 #include "taler_digitizer_util.h" 31 #include "taler/taler_digitizer_service.h" 32 #include "lib/bank_api_get_config.h" 33 #include "lib/bank_api_get_accounts.h" 34 #include "lib/bank_api_post_accounts_withdrawals.h" 35 #include "lib/bank_api_get_withdrawals.h" 36 #include "lib/bank_api_post_accounts_withdrawals_confirm.h" 37 #include "digitizer_display.h" 38 #include "gpio/gpiod_wrapper.h" 39 #include "uart/ca_uart.h" 40 #include <termios.h> 41 #include <sys/ioctl.h> 42 #include <stdio.h> 43 44 /** 45 * Time unit for PERSON_WITHDRAL_PERIOD config. 46 * Normaly in Days but, can be changed for testing 47 */ 48 #define DIGITIZER_PERSON_WITHDRAWAL_PERIOD_TIME_UNIT GNUNET_TIME_UNIT_DAYS 49 50 #define FRAMEBUFFER_SIZE 256 51 #define PATH_QR_SHOW "/ext/QRshow" 52 53 #define SCAN_QR_TIMEOUT_SECONDS 60 54 #define SCAN_QR_CHECK_STATUS_INTERVAL_MILISECONDS 200 55 56 #define ACCEPT_CASH_TIMEOUT_SECONDS 60 57 58 #define CASHUP_TIMEOUT_SECONDS 60 59 #define CASHUP_CHECK_BALANCE_INTERVAL_MILISECONDS 200 60 61 #define DISPLAY_BLOCK_SIZE 1024 62 #define DISPLAY_COUNT 750 63 64 /** 65 * Global return value 66 */ 67 static int global_ret; 68 69 /** 70 * Global option '-d' to enable diagnostics set. 71 */ 72 static int enable_diagnostics; 73 74 /** 75 * Taler bank backend url read from configuration file 76 */ 77 static char *cfg_bank_base_url; 78 79 /** 80 * Taler bank account username 81 */ 82 static char *cfg_bank_account_username; 83 84 /** 85 * Taler bank authentication 86 * method and according data 87 */ 88 static struct DIGITIZER_BankAuthenticationData *cfg_bank_authentication; 89 90 /** 91 * Taler exchange backend url read from configuration file 92 */ 93 static char *cfg_exchange_base_url; 94 95 /** 96 * Currency read from configuration file 97 */ 98 static char *cfg_currency; 99 100 /** 101 * Per-person withdrawal limit read from configuration file 102 */ 103 static struct TALER_Amount cfg_user_withdrawallimit; 104 105 /** 106 * Per-person withdrawal period read from configuration file 107 */ 108 static struct GNUNET_TIME_Relative cfg_user_withdrawal_period; 109 110 /** 111 * KYC functionality flag read from configuration file 112 */ 113 static enum GNUNET_GenericReturnValue cfg_kyc_functionality; 114 115 /** 116 * device path to display framebuffer. 117 * usualy in /dev/fbX. 118 */ 119 static char *cfg_framebuffer_device; 120 121 /** 122 * device path to display backlight. 123 * usualy in /sys/class/backlight/<XX>/brightness 124 */ 125 static char *cfg_framebuffer_backlight; 126 127 /** 128 * Coin Acceptor installed 129 */ 130 static enum GNUNET_GenericReturnValue cfg_ca_enable; 131 132 /** 133 * device path to coin acceptor interface 134 */ 135 static char *cfg_ca_inhibit_device; 136 137 /** 138 * Pin to enable Accepting coins 139 */ 140 static unsigned long long cfg_ca_inhibit_pin; 141 142 /** 143 * Pin to recive inserted amount signal 144 */ 145 static char *cfg_ca_sig_device; 146 147 /** 148 * Biggest value of one coin insertion 149 */ 150 static struct TALER_Amount cfg_ca_max_denomination; 151 152 /** 153 * Smallest value of one coin insertion 154 */ 155 static struct TALER_Amount cfg_ca_min_denomination; 156 157 /** 158 * Bill Acceptor installed 159 */ 160 static enum GNUNET_GenericReturnValue cfg_ba_enable; 161 162 /** 163 * device path to bill acceptor interface 164 */ 165 static char *cfg_ba_inhibit_device; 166 167 /** 168 * Biggest value of one bill insertion 169 */ 170 static struct TALER_Amount cfg_ba_max_denomination; 171 172 /** 173 * Smallest value of one bill insertion 174 */ 175 static struct TALER_Amount cfg_ba_min_denomination; 176 177 /** 178 * Handle to the context for http requests 179 */ 180 static struct GNUNET_CURL_Context *curl_ctx; 181 182 /** 183 * Scheduler context for running the @e ctx. 184 */ 185 static struct GNUNET_CURL_RescheduleContext *reschedule_ctx; 186 187 /** 188 * Handle for get_config request 189 */ 190 static struct TALER_BANK_GetConfigHandle *get_config_handle; 191 192 /** 193 * Handle for get_accounts request 194 */ 195 static struct TALER_BANK_GetAccountsHandle *get_accounts_handle; 196 197 /** 198 * Handle for get_accounts request 199 */ 200 static struct TALER_BANK_GetWithdrawalHandle *get_withdrawal_handle; 201 202 /** 203 * Handle for post_accounts_withdrawal request 204 */ 205 static struct TALER_BANK_PostCreateWithdrawalHandle *post_accounts_withdrawal_handle; 206 207 /** 208 * Handle for post_accounts_withdrawal_confirm request 209 */ 210 static struct TALER_BANK_PostWithdrawalConfirmHandle *post_withdrawal_confirm_handle; 211 212 /** 213 * used to init gpio 214 */ 215 static struct gpiod_line_settings *gpio_settings; 216 217 /** 218 * gpio request to enable coin acceping 219 */ 220 static struct gpiod_line_request *rl_ca_inhibit; 221 222 /** 223 * uart handle for Coin Acceptor signals 224 */ 225 static struct GNUNET_NETWORK_Handle *filestream_ca; 226 227 228 229 enum 230 DIGITIZER_states 231 { 232 /** 233 * Init by loading configs 234 */ 235 DIGITIZER_STATE_INIT, 236 237 /** 238 * 239 */ 240 DIGITIZER_STATE_IDLE, 241 242 /** 243 * 244 */ 245 DIGITIZER_STATE_CREATE_QR, 246 247 /** 248 * 249 */ 250 DIGITIZER_STATE_SCAN_QR, 251 252 /** 253 * 254 */ 255 DIGITIZER_STATE_IDENTIFICATION, 256 /** 257 * 258 */ 259 DIGITIZER_STATE_COUNT_MONEY, 260 /** 261 * 262 */ 263 DIGITIZER_STATE_ACCEPT_CASH, 264 /** 265 * 266 */ 267 DIGITIZER_STATE_CASHING_UP, 268 /** 269 * 270 */ 271 DIGITIZER_STATE_WITHDRAWAL_STATUS, 272 /** 273 * 274 */ 275 DIGITIZER_STATE_CANCEL_WITHDRAWAL, 276 /** 277 * 278 */ 279 DIGITIZER_STATE_WITHDRAWAL_ERROR, 280 /** 281 * 282 */ 283 DIGITIZER_STATE_TERMINAL_ERROR, 284 285 /** 286 * count used to initialise state table with size 287 */ 288 DIGITIZER_STATE_NUMBER_OF_STATES 289 }; 290 291 /** 292 * Data moved between states 293 */ 294 struct DIGITIZER_StateContext 295 { 296 enum TALER_BANK_VersionCompatibility version_compa; 297 298 enum TALLER_BANK_CurrencyCompatibility currency_compa; 299 300 /** 301 * digitizer defined max amount for one insertion action, 302 * sum from bill- and coin-acceptor 303 */ 304 struct TALER_Amount max_insertion_amount; 305 306 /** 307 * digitizer defined min amount for one insertion action, 308 * min from bill-/coin-acceptor 309 */ 310 struct TALER_Amount min_insertion_amount; 311 312 /** 313 * max_wire_transfer_amount of bank config 314 */ 315 struct TALER_Amount bank_max_wire_transfer_amount; 316 317 /** 318 * amount avaliable for current withdrawal process 319 * is updated according to bank balance and bank withdrawal-limits 320 * in init state of each withdrawal process 321 */ 322 struct TALER_Amount withdrawal_limit; 323 324 /** 325 * withdrawal operation information 326 * url and id 327 */ 328 struct TALER_BANK_CreateWithdrawalInformatio wi; 329 330 /** 331 * amount of current prozessing withdrawal 332 */ 333 struct TALER_Amount digitizer_user_balance; 334 }; 335 336 static enum DIGITIZER_states state; 337 338 struct DIGITIZER_StateContext *state_ctx; 339 340 struct DIGITIZER_DisplayContext *display_ctx; 341 342 static void state_controller_task(void *cls); 343 344 345 void 346 start_qr_show(int showtime) 347 { 348 //char buffer[FRAMEBUFFER_SIZE]; 349 char *command; 350 char *url; 351 char *path; 352 353 const char *prefix = getenv("TALER_DIGITIZER_PREFIX"); 354 if (NULL != prefix) 355 GNUNET_asprintf (&path, "%s%s", prefix,PATH_QR_SHOW); 356 else 357 path = GNUNET_strdup ("/usr/local/bin/taler-digitizer-qr-show"); 358 url = TALER_url_join(state_ctx->wi.taler_withdraw_uri, 359 "", 360 "external-confirmation", 361 "1", 362 NULL); 363 GNUNET_asprintf(&command, 364 "%s -c taler-digitizer.conf -d \"%d s\" %s &\n", 365 path, 366 showtime, 367 url); 368 GNUNET_free(url); 369 TALER_LOG_DEBUG("Command for QRshow: %s\n",command); 370 system(command); 371 372 GNUNET_free(command); 373 GNUNET_free(path); 374 } 375 376 void 377 clear_screen(void) 378 { 379 char *command; 380 GNUNET_asprintf(&command, 381 "dd if=/dev/zero of=%s bs=%d count=%d\n", 382 cfg_framebuffer_device, 383 DISPLAY_BLOCK_SIZE, 384 DISPLAY_COUNT); 385 system(command); 386 GNUNET_free(command); 387 } 388 389 /** 390 * Joinn currency and V.F format value string to TALER amount". 391 * 392 * @param currency currency string 393 * @param value_fraction value string format "Value.Fraction" 394 * @param[out] amount amount to write the result to 395 * @return #GNUNET_OK if the string is a valid monetary amount specification, 396 * #GNUNET_SYSERR if it is invalid. 397 */ 398 enum GNUNET_GenericReturnValue 399 join_strings_to_amount(const char *currency, 400 const char *value_fraction, 401 struct TALER_Amount *amount) 402 { 403 enum GNUNET_GenericReturnValue ret; 404 char *str; 405 GNUNET_asprintf (&str, 406 "%s:%s", 407 currency, 408 value_fraction); 409 ret = TALER_string_to_amount(str, 410 amount); 411 GNUNET_free(str); 412 return ret; 413 } 414 415 416 static void 417 on_get_config_done (void *cls, 418 const struct TALER_BANK_ConfigResponse *vr) 419 { 420 TALER_LOG_DEBUG ("Callback of GET /config\n"); 421 (void) cls; 422 get_config_handle = NULL; 423 424 state_ctx->version_compa = vr->details.ok.version_compa; 425 state_ctx->currency_compa = strcmp(vr->details.ok.configi.currency, 426 cfg_currency); 427 if(TALER_BANK_CC_MATCH != state_ctx->currency_compa) 428 { 429 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 430 "taler-digitizer", 431 "CURRENCY", 432 "not compatible with bank currency"); 433 state = DIGITIZER_STATE_TERMINAL_ERROR; 434 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 435 return; 436 } 437 if(-1 == TALER_amount_cmp(&(vr->details.ok.configi.max_wire_transfer_amount), 438 &(state_ctx->max_insertion_amount))) 439 { 440 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 441 "taler-digitizer", 442 "BANK_BASE_URL or MAX_DENOMINATION", 443 "max denominations not compatible with bank max_wire_transfer_amount"); 444 state = DIGITIZER_STATE_TERMINAL_ERROR; 445 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 446 return; 447 } 448 state_ctx->bank_max_wire_transfer_amount = vr->details.ok.configi.max_wire_transfer_amount; 449 if(1 == TALER_amount_cmp(&(vr->details.ok.configi.min_wire_transfer_amount), 450 &(state_ctx->min_insertion_amount))) 451 { 452 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 453 "taler-digitizer", 454 "BANK_BASE_URL or MAX_DENOMINATION", 455 "min denominations not compatible with bank min_wire_transfer_amount"); 456 state = DIGITIZER_STATE_TERMINAL_ERROR; 457 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 458 return; 459 } 460 461 462 state = DIGITIZER_STATE_IDLE; 463 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 464 return; 465 } 466 467 /** 468 * callback of accounts request 469 * used in the Idle state 470 */ 471 static void 472 on_get_accounts_done(void *cls, 473 const struct TALER_BANK_AccountsResponse *vr) 474 { 475 TALER_LOG_DEBUG ("Callback of accounts/$USERNAME\n"); 476 477 (void) cls; 478 get_accounts_handle = NULL; 479 struct TALER_Amount account_max_withdrawal; 480 481 if(0 != strcmp("active", 482 vr->details.ok.acc.status)) 483 { 484 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 485 "taler-digitizer", 486 "BANK_ACCOUNT", 487 "bank account is not in active state"); 488 state = DIGITIZER_STATE_TERMINAL_ERROR; 489 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 490 return; 491 } 492 TALER_amount_min (&account_max_withdrawal, 493 &vr->details.ok.acc.balance.amount, 494 &vr->details.ok.acc.debit_threshold); 495 if(-1 == TALER_amount_cmp (&account_max_withdrawal, 496 &state_ctx->max_insertion_amount)) 497 { 498 TALER_LOG_ERROR("bank account does not have enough balance or whithdrawal limit to withdrawal the biggest denomination"); 499 state = DIGITIZER_STATE_TERMINAL_ERROR; 500 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 501 return; 502 } 503 TALER_amount_min(&state_ctx->withdrawal_limit,&account_max_withdrawal,&state_ctx->bank_max_wire_transfer_amount); 504 TALER_amount_min(&state_ctx->withdrawal_limit,&state_ctx->withdrawal_limit,&cfg_user_withdrawallimit); 505 506 507 508 state = DIGITIZER_STATE_CREATE_QR; 509 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 510 return; 511 } 512 513 514 /** 515 * Timeout when Money is not sent in 516 * CASHUP_TIMEOUT_SECONDS 517 */ 518 static void 519 timeout_CashingUp_task(void *cls) 520 { 521 TALER_LOG_DEBUG ("Timeout of Cashing Up\n"); 522 523 (void) cls; 524 525 state = DIGITIZER_STATE_TERMINAL_ERROR; 526 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 527 return; 528 } 529 530 531 /** 532 * callback of accounts withdrawal request 533 * used in the QR Create state 534 */ 535 static void 536 on_post_accounts_withdrawal_done(void *cls, 537 const struct TALER_BANK_CreateWithdrawalResponse *vr) 538 { 539 TALER_LOG_DEBUG ("Callback of accounts/$USERNAME/withdrawal\n"); 540 541 (void) cls; 542 post_accounts_withdrawal_handle = NULL; 543 544 state_ctx->wi.taler_withdraw_uri = GNUNET_strdup(vr->details.ok.wopd.taler_withdraw_uri); 545 state_ctx->wi.withdrawal_id = GNUNET_strdup(vr->details.ok.wopd.withdrawal_id); 546 547 state = DIGITIZER_STATE_SCAN_QR; 548 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 549 return; 550 } 551 552 553 /** 554 * callback of accounts withdrawal request 555 * used in the QR Create state 556 */ 557 static void 558 on_post_withdrawal_confirm_done(void *cls, 559 const struct TALER_BANK_WithdrawalConfirmResponse *vr) 560 { 561 TALER_LOG_DEBUG ("Callback of accounts/$USERNAME/withdrawal/$WOPID/confirm\n"); 562 (void) cls; 563 (void) vr; 564 //struct GNUNET_SCHEDULER_Task *timeout_handle; 565 struct GNUNET_TIME_Relative delay; 566 //struct GNUNET_TIME_Relative poll; 567 568 post_withdrawal_confirm_handle = NULL; 569 delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 570 CASHUP_TIMEOUT_SECONDS); 571 //get reserve 572 //poll = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 573 // CASHUP_CHECK_BALANCE_INTERVAL_MILISECONDS); 574 //timeout_handle = 575 GNUNET_SCHEDULER_add_delayed(delay, 576 timeout_CashingUp_task, 577 NULL); 578 state = DIGITIZER_STATE_TERMINAL_ERROR; 579 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 580 return; 581 } 582 583 584 /** 585 * When UART signal from Coin Acceptor 586 * recived, or timeout of ACCEPT_CASH_TIMEOUT_SECONDS 587 */ 588 static void 589 on_coin_recived(void *cls) 590 { 591 (void) cls; 592 struct TALER_Amount inserted; 593 ssize_t n; 594 uint8_t buff[32] = {0}; //only on byte read per accept cycle, but check if more than one was read 595 state = TALER_amount_is_zero(&state_ctx->digitizer_user_balance)? 596 DIGITIZER_STATE_CANCEL_WITHDRAWAL:DIGITIZER_STATE_CASHING_UP; 597 if (GNUNET_SCHEDULER_REASON_TIMEOUT == 598 GNUNET_SCHEDULER_get_task_context()->reason) 599 { 600 TALER_LOG_DEBUG ("Timeout of Accept Coin\n"); 601 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 602 return; 603 } 604 n = read (GNUNET_NETWORK_get_fd (filestream_ca), buff, sizeof (buff)); 605 TALER_LOG_DEBUG ("read n=%zd",n); 606 if(0 < n) 607 { 608 for(ssize_t i=0;i<n;i++) 609 { 610 TALER_LOG_DEBUG ("Coin byte received: 0x%02x (%d)\n", buff[i], buff[i]); 611 if(i>0) 612 TALER_LOG_WARNING("Multiple Coins inserted!\n"); 613 strcpy(inserted.currency,cfg_currency); 614 inserted.value = buff[i] / 10; 615 inserted.fraction = (buff[i] % 10) * (TALER_AMOUNT_FRAC_BASE/10); 616 if(0 > TALER_amount_add(&state_ctx->digitizer_user_balance, 617 &state_ctx->digitizer_user_balance, 618 &inserted)) 619 { 620 TALER_LOG_ERROR("adding amount failed\n"); 621 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 622 return; 623 } 624 } 625 state = DIGITIZER_STATE_COUNT_MONEY; 626 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 627 return; 628 } 629 else if(n == 0) 630 { 631 TALER_LOG_INFO("No Coin inserted in time\n"); 632 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 633 return; 634 } 635 else 636 { 637 perror ("read uart"); 638 TALER_LOG_INFO("Signal Error UART Coin Acceptor\n"); 639 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 640 return; 641 } 642 return; 643 } 644 645 646 /** 647 * Get withdrawal request for repeated requesting 648 */ 649 static void 650 get_withdrawal_task(void *cls); 651 652 653 /** 654 * callback of accounts withdrawal request 655 * used in the QR Create state 656 */ 657 static void 658 on_get_withdrawal_status_done(void *cls, 659 const struct TALER_BANK_WithdrawalResponse *vr) 660 { 661 TALER_LOG_DEBUG ("Callback of withdrawal/$WITHDRAWAL_ID\n"); 662 struct GNUNET_SCHEDULER_Task *timeout_handle; 663 timeout_handle = cls; 664 get_withdrawal_handle = NULL; 665 if(0 == strcasecmp("selected", vr->details.ok.acc.status)) 666 { 667 GNUNET_SCHEDULER_cancel(timeout_handle); 668 clear_screen(); 669 state = DIGITIZER_STATE_COUNT_MONEY; 670 // give context for non terminal errors! 671 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 672 } 673 else 674 { 675 struct GNUNET_TIME_Relative poll; 676 poll = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS,200); 677 GNUNET_SCHEDULER_add_delayed(poll,get_withdrawal_task,timeout_handle); 678 } 679 680 return; 681 } 682 683 /** 684 * Get withdrawal request for repeated requesting 685 */ 686 static void 687 get_withdrawal_task(void *cls) 688 { 689 struct GNUNET_SCHEDULER_Task *timeout_handle; 690 timeout_handle = cls; 691 692 get_withdrawal_handle = 693 TALER_BANK_get_withdrawal(curl_ctx, 694 cfg_bank_base_url, 695 state_ctx->wi.withdrawal_id, 696 on_get_withdrawal_status_done, 697 timeout_handle, 698 NULL); 699 return; 700 } 701 702 703 /** 704 * Timeout when QR is shown 705 * SCAN_QR_TIMEOUT_SECONDS without been scanned 706 * used in the ScanQR state 707 */ 708 static void 709 timeout_ScanQR_task(void *cls) 710 { 711 TALER_LOG_DEBUG ("Timeout of ScanQR\n"); 712 713 (void) cls; 714 715 state = DIGITIZER_STATE_CANCEL_WITHDRAWAL; 716 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 717 return; 718 } 719 720 721 /** 722 * @brief Cleanup when no task is scheduled anymore 723 * 724 * @param cls closure 725 */ 726 static void 727 shutdown_task (void *cls) 728 { 729 (void)cls; 730 gpiod_line_request_release(rl_ca_inhibit); 731 GNUNET_NETWORK_socket_close (filestream_ca); 732 filestream_ca = NULL; 733 734 if (NULL != get_withdrawal_handle) 735 { 736 TALER_BANK_get_withdrawal_cancel (get_withdrawal_handle); 737 get_withdrawal_handle = NULL; 738 } 739 if (NULL != get_config_handle) 740 { 741 TALER_BANK_get_config_cancel (get_config_handle); 742 get_config_handle = NULL; 743 } 744 if (NULL != post_accounts_withdrawal_handle) 745 { 746 TALER_BANK_post_withdrawal_create_cancel(post_accounts_withdrawal_handle); 747 post_accounts_withdrawal_handle = NULL; 748 } 749 if (NULL != post_withdrawal_confirm_handle) 750 { 751 TALER_BANK_post_withdrawal_confirm_cancel(post_withdrawal_confirm_handle); 752 post_withdrawal_confirm_handle = NULL; 753 } 754 if (NULL != reschedule_ctx) 755 { 756 GNUNET_CURL_gnunet_rc_destroy (reschedule_ctx); 757 reschedule_ctx = NULL; 758 } 759 if (NULL != curl_ctx) 760 { 761 GNUNET_CURL_fini (curl_ctx); 762 curl_ctx = NULL; 763 } 764 DIGITIZER_bank_auth_free (cfg_bank_authentication); 765 GNUNET_free(cfg_bank_authentication); 766 GNUNET_free(state_ctx); 767 GNUNET_free(display_ctx); 768 } 769 770 /** 771 * Initialising state 772 * Init: Digitizer config, Bank config, Screen task, Touch task 773 */ 774 static void Init_state_task(void *cls) 775 { 776 TALER_LOG_DEBUG ("INIT state\n"); 777 778 const struct GNUNET_CONFIGURATION_Handle *cfg = cls; 779 780 if (GNUNET_OK != 781 GNUNET_CONFIGURATION_get_value_string (cfg, 782 "taler-digitizer", 783 "BANK_BASE_URL", 784 &cfg_bank_base_url)) 785 { 786 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 787 "taler-digitizer", 788 "BANK_BASE_URL"); 789 global_ret = EXIT_FAILURE; 790 return; 791 } 792 if (GNUNET_OK != 793 GNUNET_CONFIGURATION_get_value_string (cfg, 794 "taler-digitizer", 795 "BANK_ACCOUNT", 796 &cfg_bank_account_username)) 797 { 798 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 799 "taler-digitizer", 800 "BANK_ACCOUNT"); 801 global_ret = EXIT_FAILURE; 802 return; 803 } 804 if (GNUNET_OK != 805 DIGITIZER_bank_auth_parse_cfg (cfg, 806 "bank-authentication", 807 cfg_bank_authentication)) 808 { 809 global_ret = EXIT_FAILURE; 810 return; 811 } 812 if (GNUNET_OK != 813 GNUNET_CONFIGURATION_get_value_string (cfg, 814 "taler-digitizer", 815 "EXCHANGE_BASE_URL", 816 &cfg_exchange_base_url)) 817 { 818 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 819 "taler-digitizer", 820 "EXCHANGE_BASE_URL"); 821 global_ret = EXIT_FAILURE; 822 return; 823 } 824 if (GNUNET_OK != 825 GNUNET_CONFIGURATION_get_value_string (cfg, 826 "taler-digitizer", 827 "CURRENCY", 828 &cfg_currency)) 829 { 830 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 831 "taler-digitizer", 832 "CURRENCY"); 833 global_ret = EXIT_FAILURE; 834 return; 835 } 836 if(GNUNET_OK != TALER_check_currency(cfg_currency)) 837 { 838 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 839 "taler-digitizer", 840 "CURRENCY", 841 "malformed currency"); 842 global_ret = EXIT_FAILURE; 843 return; 844 } 845 char *limit_value; 846 if (GNUNET_OK != 847 GNUNET_CONFIGURATION_get_value_string (cfg, 848 "taler-digitizer", 849 "USER_WITHDRAWALLIMIT", 850 &limit_value)) 851 { 852 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 853 "taler-digitizer", 854 "USER_WITHDRAWALLIMIT"); 855 GNUNET_free(limit_value); 856 global_ret = EXIT_FAILURE; 857 return; 858 } 859 if (GNUNET_OK != 860 join_strings_to_amount(cfg_currency, 861 limit_value, 862 &cfg_user_withdrawallimit)) 863 { 864 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 865 "taler-digitizer", 866 "USER_WITHDRAWALLIMIT", 867 "malformed denomination"); 868 GNUNET_free(limit_value); 869 global_ret = EXIT_FAILURE; 870 return; 871 } 872 GNUNET_free(limit_value); 873 874 unsigned long long user_withdrawal_period_number; 875 if (GNUNET_OK != 876 GNUNET_CONFIGURATION_get_value_number (cfg, 877 "taler-digitizer", 878 "USER_WITHDRAWAL_PERIOD", 879 &user_withdrawal_period_number)) 880 { 881 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 882 "taler-digitizer", 883 "USER_WITHDRAWAL_PERIOD"); 884 global_ret = EXIT_FAILURE; 885 return; 886 } 887 cfg_user_withdrawal_period = GNUNET_TIME_relative_multiply ( 888 DIGITIZER_PERSON_WITHDRAWAL_PERIOD_TIME_UNIT, 889 user_withdrawal_period_number); 890 891 cfg_kyc_functionality = GNUNET_CONFIGURATION_get_value_yesno (cfg, 892 "taler-digitizer", 893 "KYC_FUNCTIONALITY"); 894 if (GNUNET_SYSERR == cfg_kyc_functionality) 895 { 896 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 897 "taler-digitizer", 898 "KYC_FUNCTIONALITY"); 899 global_ret = EXIT_FAILURE; 900 return; 901 } 902 if (GNUNET_OK != 903 GNUNET_CONFIGURATION_get_value_filename (cfg, 904 "taler-digitizer", 905 "FRAMEBUFFER_DEVICE", 906 &cfg_framebuffer_device)) 907 { 908 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 909 "taler-digitizer", 910 "FRAMEBUFFER_DEVICE"); 911 global_ret = EXIT_FAILURE; 912 return; 913 } 914 if (GNUNET_OK != 915 GNUNET_CONFIGURATION_get_value_filename (cfg, 916 "taler-digitizer", 917 "FRAMEBUFFER_BACKLIGHT", 918 &cfg_framebuffer_backlight)) 919 { 920 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 921 "taler-digitizer", 922 "FRAMEBUFFER_BACKLIGHT"); 923 global_ret = EXIT_FAILURE; 924 return; 925 } 926 cfg_ca_enable = GNUNET_CONFIGURATION_get_value_yesno (cfg, 927 "coin-acceptor", 928 "ENABLE"); 929 cfg_ba_enable = GNUNET_CONFIGURATION_get_value_yesno (cfg, 930 "bill-acceptor", 931 "ENABLE"); 932 if(GNUNET_OK != cfg_ba_enable) 933 { 934 cfg_ba_enable = GNUNET_NO; 935 join_strings_to_amount(cfg_currency, 936 "0", 937 &cfg_ba_max_denomination); 938 join_strings_to_amount(cfg_currency, 939 "0", 940 &cfg_ba_min_denomination); 941 if(GNUNET_OK != cfg_ca_enable) 942 { 943 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 944 "coin-acceptor or bill-acceptor", 945 "ENABLE"); 946 global_ret = EXIT_FAILURE; 947 return; 948 } 949 } 950 else 951 { 952 if (GNUNET_OK != 953 GNUNET_CONFIGURATION_get_value_filename (cfg, 954 "bill-acceptor", 955 "INHIBIT_DEVICE", 956 &cfg_ba_inhibit_device)) 957 { 958 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 959 "bill-acceptor", 960 "INHIBIT_DEVICE"); 961 global_ret = EXIT_FAILURE; 962 return; 963 } 964 char *denomination_value; 965 if (GNUNET_OK != 966 GNUNET_CONFIGURATION_get_value_string (cfg, 967 "bill-acceptor", 968 "MAX_DENOMINATION", 969 &denomination_value)) 970 { 971 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 972 "bill-acceptor", 973 "MAX_DENOMINATION"); 974 GNUNET_free(denomination_value); 975 global_ret = EXIT_FAILURE; 976 return; 977 } 978 if (GNUNET_OK != 979 join_strings_to_amount(cfg_currency, 980 denomination_value, 981 &cfg_ba_max_denomination)) 982 { 983 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 984 "bill-acceptor", 985 "MAX_DENOMINATION", 986 "malformed denomination"); 987 GNUNET_free(denomination_value); 988 global_ret = EXIT_FAILURE; 989 return; 990 } 991 GNUNET_free(denomination_value); 992 if (GNUNET_OK != 993 GNUNET_CONFIGURATION_get_value_string (cfg, 994 "bill-acceptor", 995 "MIN_DENOMINATION", 996 &denomination_value)) 997 { 998 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 999 "bill-acceptor", 1000 "MIN_DENOMINATION"); 1001 GNUNET_free(denomination_value); 1002 global_ret = EXIT_FAILURE; 1003 return; 1004 } 1005 if (GNUNET_OK != 1006 join_strings_to_amount(cfg_currency, 1007 denomination_value, 1008 &cfg_ba_min_denomination)) 1009 { 1010 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 1011 "bill-acceptor", 1012 "MIN_DENOMINATION", 1013 "malformed denomination"); 1014 GNUNET_free(denomination_value); 1015 global_ret = EXIT_FAILURE; 1016 return; 1017 } 1018 GNUNET_free(denomination_value); 1019 } 1020 if(GNUNET_OK != cfg_ca_enable) 1021 { 1022 cfg_ca_enable = GNUNET_NO; 1023 join_strings_to_amount(cfg_currency, 1024 "0", 1025 &cfg_ca_max_denomination); 1026 join_strings_to_amount(cfg_currency, 1027 "0", 1028 &cfg_ca_min_denomination); 1029 } 1030 else 1031 { 1032 char *denomination_value; 1033 if (GNUNET_OK != 1034 GNUNET_CONFIGURATION_get_value_string (cfg, 1035 "coin-acceptor", 1036 "MAX_DENOMINATION", 1037 &denomination_value)) 1038 { 1039 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1040 "coin-acceptor", 1041 "MAX_DENOMINATION"); 1042 GNUNET_free(denomination_value); 1043 global_ret = EXIT_FAILURE; 1044 return; 1045 } 1046 if (GNUNET_OK != 1047 join_strings_to_amount(cfg_currency, 1048 denomination_value, 1049 &cfg_ca_max_denomination)) 1050 { 1051 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 1052 "coin-acceptor", 1053 "MAX_DENOMINATION", 1054 "malformed denomination"); 1055 GNUNET_free(denomination_value); 1056 global_ret = EXIT_FAILURE; 1057 return; 1058 } 1059 if (GNUNET_OK != 1060 GNUNET_CONFIGURATION_get_value_string (cfg, 1061 "coin-acceptor", 1062 "MIN_DENOMINATION", 1063 &denomination_value)) 1064 { 1065 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1066 "coin-acceptor", 1067 "MIN_DENOMINATION"); 1068 GNUNET_free(denomination_value); 1069 global_ret = EXIT_FAILURE; 1070 return; 1071 } 1072 if (GNUNET_OK != 1073 join_strings_to_amount(cfg_currency, 1074 denomination_value, 1075 &cfg_ca_min_denomination)) 1076 { 1077 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 1078 "coin-acceptor", 1079 "MIN_DENOMINATION", 1080 "malformed denomination"); 1081 GNUNET_free(denomination_value); 1082 global_ret = EXIT_FAILURE; 1083 return; 1084 } 1085 GNUNET_free(denomination_value); 1086 if (GNUNET_OK != 1087 GNUNET_CONFIGURATION_get_value_filename (cfg, 1088 "coin-acceptor", 1089 "INHIBIT_DEVICE", 1090 &cfg_ca_inhibit_device)) 1091 { 1092 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1093 "coin-acceptor", 1094 "INHIBIT_DEVICE"); 1095 global_ret = EXIT_FAILURE; 1096 return; 1097 } 1098 if (GNUNET_OK != 1099 GNUNET_CONFIGURATION_get_value_number (cfg, 1100 "coin-acceptor", 1101 "INHIBIT_PIN", 1102 &cfg_ca_inhibit_pin)) 1103 { 1104 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1105 "coin-acceptor", 1106 "INHIBIT_PIN"); 1107 global_ret = EXIT_FAILURE; 1108 return; 1109 } 1110 if (GNUNET_OK != 1111 GNUNET_CONFIGURATION_get_value_string (cfg, 1112 "coin-acceptor", 1113 "SIGNAL_DEVICE", 1114 &cfg_ca_sig_device)) 1115 { 1116 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1117 "coin-acceptor", 1118 "SIGNAL_DEVICE"); 1119 global_ret = EXIT_FAILURE; 1120 return; 1121 } 1122 //CA Init 1123 gpio_settings = gpiod_make_settings(GPIOD_LINE_DIRECTION_OUTPUT, 1124 GPIOD_LINE_BIAS_PULL_UP, 1125 GPIOD_LINE_DRIVE_OPEN_DRAIN,1); 1126 if (NULL == gpio_settings) 1127 { 1128 TALER_LOG_ERROR("GPIO Init failed"); 1129 gpiod_line_settings_free(gpio_settings); 1130 global_ret = EXIT_FAILURE; 1131 return; 1132 } 1133 rl_ca_inhibit = gpiod_make_line_request(cfg_ca_inhibit_device, 1134 cfg_ca_inhibit_pin, 1135 gpio_settings); 1136 if (NULL == rl_ca_inhibit) 1137 { 1138 TALER_LOG_ERROR("GPIO Init failed"); 1139 gpiod_line_request_release(rl_ca_inhibit); 1140 global_ret = EXIT_FAILURE; 1141 return; 1142 } 1143 if(0 != gpiod_line_request_set_value(rl_ca_inhibit, 1144 (unsigned int)cfg_ca_inhibit_pin, 1145 GPIOD_LINE_VALUE_INACTIVE)) 1146 { 1147 TALER_LOG_ERROR("failed to set GPIO active"); 1148 global_ret = EXIT_FAILURE; 1149 return; 1150 } 1151 int fd = ca_uart_init (cfg_ca_sig_device); 1152 if (-1 == fd) 1153 { 1154 TALER_LOG_ERROR ("UART init failed\n"); 1155 global_ret = EXIT_FAILURE; 1156 return; 1157 } 1158 filestream_ca = GNUNET_NETWORK_socket_box_native (fd); 1159 } 1160 1161 1162 state_ctx->min_insertion_amount = 1163 ((1 == TALER_amount_cmp(&cfg_ba_min_denomination, 1164 &cfg_ca_min_denomination))? 1165 cfg_ca_min_denomination : cfg_ba_min_denomination); 1166 1167 if(TALER_AAR_INVALID_NEGATIVE_RESULT == TALER_amount_add(&state_ctx->max_insertion_amount, 1168 &cfg_ba_max_denomination, 1169 &cfg_ca_max_denomination)) 1170 { 1171 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 1172 "coin-acceptor", 1173 "XXX_DENOMINATION", 1174 "could not determine min insertion amount"); 1175 global_ret = EXIT_FAILURE; 1176 return; 1177 } 1178 1179 //Screen INIT 1180 1181 //Touch INIT 1182 1183 //BA Init 1184 1185 1186 curl_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, 1187 &reschedule_ctx); 1188 reschedule_ctx = GNUNET_CURL_gnunet_rc_create (curl_ctx); 1189 1190 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1191 NULL); 1192 1193 get_config_handle = TALER_BANK_get_config (curl_ctx, 1194 cfg_bank_base_url, 1195 &on_get_config_done, 1196 NULL); 1197 } 1198 1199 /** 1200 * Terminal Error state 1201 * When error accures due to config issues, or unrecoverable errors 1202 */ 1203 static void TerminalError_state_task(void *cls) 1204 { 1205 (void)cls; 1206 TALER_LOG_DEBUG ("start TerminalError state task\n"); 1207 global_ret = EXIT_FAILURE; 1208 GNUNET_SCHEDULER_shutdown(); 1209 } 1210 1211 /** 1212 * Idle state 1213 * prepare for new withdrawal process and 1214 * check for start signal from UI 1215 */ 1216 static void Idle_state_task(void *cls) 1217 { 1218 TALER_LOG_DEBUG("Idle state\n"); 1219 clear_screen(); 1220 (void)cls; 1221 TALER_amount_set_zero(cfg_currency,&state_ctx->digitizer_user_balance); 1222 get_accounts_handle = TALER_BANK_get_accounts (curl_ctx, 1223 cfg_bank_base_url, 1224 cfg_bank_account_username, 1225 cfg_bank_authentication, 1226 &on_get_accounts_done, 1227 NULL); 1228 } 1229 1230 /** 1231 * Create QR state 1232 * create QR code with a new WOPID 1233 * check for cancle from UI 1234 */ 1235 static void CreateQR_state_task(void *cls) 1236 { 1237 TALER_LOG_DEBUG("CreateQR state\n"); 1238 (void)cls; 1239 struct TALER_BANK_AccountCreateWithdrawalRequest *acwr; 1240 acwr = GNUNET_new(struct TALER_BANK_AccountCreateWithdrawalRequest); 1241 acwr->no_amount_to_wallet = true; 1242 1243 post_accounts_withdrawal_handle = 1244 TALER_BANK_post_accounts_withdrawal_create (curl_ctx, 1245 cfg_bank_base_url, 1246 cfg_bank_account_username, 1247 cfg_bank_authentication); 1248 if(GNUNET_OK != 1249 TALER_BANK_post_accounts_withdrawal(post_accounts_withdrawal_handle, 1250 acwr, 1251 on_post_accounts_withdrawal_done, 1252 NULL)) 1253 { 1254 TALER_LOG_ERROR("TALER_BANK_post_accounts_withdrawal canceled\n"); 1255 state = DIGITIZER_STATE_CANCEL_WITHDRAWAL; 1256 // give context for non terminal errors! 1257 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1258 } 1259 GNUNET_free(acwr); 1260 return; 1261 } 1262 1263 /** 1264 * Show QR state 1265 * show QR code on display 1266 * check for cancle from UI 1267 */ 1268 static void ScanQR_state_task(void *cls) 1269 { 1270 TALER_LOG_DEBUG ("ScanQR state\n"); 1271 (void)cls; 1272 1273 struct GNUNET_SCHEDULER_Task *timeout_handle; 1274 struct GNUNET_TIME_Relative delay; 1275 struct GNUNET_TIME_Relative poll; 1276 1277 delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1278 SCAN_QR_TIMEOUT_SECONDS); 1279 poll = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 1280 SCAN_QR_CHECK_STATUS_INTERVAL_MILISECONDS); 1281 timeout_handle = GNUNET_SCHEDULER_add_delayed(delay, 1282 timeout_ScanQR_task, 1283 NULL); 1284 start_qr_show(SCAN_QR_TIMEOUT_SECONDS); 1285 1286 //char *buf; 1287 //GNUNET_asprintf(&buf,"%d",SCAN_QR_TIMEOUT_SECONDS*1000); 1288 1289 GNUNET_SCHEDULER_add_delayed(poll, 1290 get_withdrawal_task, 1291 timeout_handle); 1292 return; 1293 } 1294 1295 static void CountMoney_state_task(void *cls) 1296 { 1297 char* balance_str; 1298 struct TALER_Amount *temp_amount; 1299 temp_amount = GNUNET_new(struct TALER_Amount); 1300 balance_str = TALER_amount_to_string(&state_ctx->digitizer_user_balance); 1301 TALER_LOG_DEBUG ("CountMoney: %s\n",balance_str); 1302 GNUNET_free(balance_str); 1303 (void)cls; 1304 if(0 != gpiod_line_request_set_value(rl_ca_inhibit, 1305 (unsigned int)cfg_ca_inhibit_pin, 1306 GPIOD_LINE_VALUE_INACTIVE)) 1307 { 1308 GNUNET_free(temp_amount); 1309 if(TALER_amount_is_zero(&state_ctx->digitizer_user_balance)) 1310 { 1311 TALER_LOG_ERROR("failed to set GPIO inactive"); 1312 state = DIGITIZER_STATE_CANCEL_WITHDRAWAL; 1313 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1314 } 1315 else 1316 { 1317 TALER_LOG_ERROR("failed to set GPIO active"); 1318 state = DIGITIZER_STATE_CASHING_UP; 1319 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1320 } 1321 } 1322 if (1 != TALER_amount_cmp (&state_ctx->withdrawal_limit, 1323 &state_ctx->digitizer_user_balance)) 1324 { 1325 state = DIGITIZER_STATE_CASHING_UP; 1326 GNUNET_SCHEDULER_add_now (state_controller_task, NULL); 1327 return; 1328 } 1329 TALER_amount_subtract(temp_amount, 1330 &state_ctx->withdrawal_limit, 1331 &state_ctx->digitizer_user_balance); 1332 if(-1 == TALER_amount_cmp(temp_amount, 1333 &state_ctx->max_insertion_amount)) 1334 { 1335 GNUNET_free(temp_amount); 1336 TALER_LOG_INFO("withdrawal limit reached"); 1337 state = DIGITIZER_STATE_CASHING_UP; 1338 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1339 }else 1340 { 1341 GNUNET_free(temp_amount); 1342 if(0 != gpiod_line_request_set_value(rl_ca_inhibit, 1343 (unsigned int)cfg_ca_inhibit_pin, 1344 GPIOD_LINE_VALUE_ACTIVE)) 1345 { 1346 TALER_LOG_ERROR("failed to set GPIO active"); 1347 state = DIGITIZER_STATE_CASHING_UP; 1348 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1349 } 1350 tcflush (GNUNET_NETWORK_get_fd (filestream_ca), TCIFLUSH); 1351 state = DIGITIZER_STATE_ACCEPT_CASH; 1352 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1353 } 1354 } 1355 1356 1357 static void AcceptCash_state_task(void *cls) 1358 { 1359 TALER_LOG_DEBUG("AcceptingCash state"); 1360 (void)cls; 1361 struct GNUNET_TIME_Relative delay; 1362 delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1363 ACCEPT_CASH_TIMEOUT_SECONDS); 1364 GNUNET_SCHEDULER_add_read_net(delay,filestream_ca,on_coin_recived,NULL); 1365 } 1366 1367 1368 static void CashingUP_state_task(void *cls) 1369 { 1370 TALER_LOG_DEBUG("CashingUP state"); 1371 (void)cls; 1372 struct TALER_BANK_AccountWithdrawalConfirmRequest *wcr; 1373 wcr = GNUNET_new(struct TALER_BANK_AccountWithdrawalConfirmRequest); 1374 wcr->amount = state_ctx->digitizer_user_balance; 1375 char* balance_str; 1376 balance_str = TALER_amount_to_string(&state_ctx->digitizer_user_balance); 1377 TALER_LOG_DEBUG ("CashingUP: %s\n",balance_str); 1378 gpiod_line_request_set_value(rl_ca_inhibit, 1379 (unsigned int)cfg_ca_inhibit_pin, 1380 GPIOD_LINE_VALUE_INACTIVE); 1381 post_withdrawal_confirm_handle = 1382 TALER_BANK_post_withdrawal_confirm_create (curl_ctx, 1383 cfg_bank_base_url, 1384 cfg_bank_account_username, 1385 state_ctx->wi.withdrawal_id, 1386 cfg_bank_authentication); 1387 if(GNUNET_OK != 1388 TALER_BANK_post_withdrawal_confirm(post_withdrawal_confirm_handle, 1389 wcr, 1390 on_post_withdrawal_confirm_done, 1391 NULL)) 1392 { 1393 TALER_LOG_ERROR("TALER_BANK_post_withdrawal_confirm canceled\n"); 1394 state = DIGITIZER_STATE_TERMINAL_ERROR; 1395 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1396 GNUNET_free(wcr); 1397 } 1398 GNUNET_free(wcr); 1399 } 1400 1401 1402 /** 1403 * Switch between State tasks 1404 */ 1405 static void state_controller_task(void *cls) 1406 { 1407 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 1408 1409 switch (state) 1410 { 1411 case DIGITIZER_STATE_INIT: 1412 { 1413 GNUNET_SCHEDULER_add_now(Init_state_task,cfg); 1414 return; 1415 } 1416 case DIGITIZER_STATE_IDLE: 1417 { 1418 GNUNET_SCHEDULER_add_now(Idle_state_task,NULL); 1419 return; 1420 } 1421 case DIGITIZER_STATE_TERMINAL_ERROR: 1422 { 1423 GNUNET_SCHEDULER_add_now(TerminalError_state_task,NULL); 1424 return; 1425 } 1426 case DIGITIZER_STATE_CREATE_QR: 1427 { 1428 GNUNET_SCHEDULER_add_now(CreateQR_state_task,NULL); 1429 return; 1430 } 1431 case DIGITIZER_STATE_SCAN_QR: 1432 { 1433 GNUNET_SCHEDULER_add_now(ScanQR_state_task,NULL); 1434 return; 1435 } 1436 case DIGITIZER_STATE_COUNT_MONEY: 1437 { 1438 GNUNET_SCHEDULER_add_now(CountMoney_state_task,NULL); 1439 return; 1440 } 1441 case DIGITIZER_STATE_ACCEPT_CASH: 1442 { 1443 GNUNET_SCHEDULER_add_now(AcceptCash_state_task,NULL); 1444 return; 1445 } 1446 case DIGITIZER_STATE_CASHING_UP: 1447 { 1448 GNUNET_SCHEDULER_add_now(CashingUP_state_task,NULL); 1449 return; 1450 } 1451 1452 default: 1453 { 1454 TALER_LOG_ERROR("Gost-State in state machine\n"); 1455 global_ret = EXIT_FAILURE; 1456 GNUNET_SCHEDULER_shutdown (); 1457 } 1458 1459 } 1460 } 1461 1462 1463 /** 1464 * @brief Start the application 1465 * 1466 * @param cls closure 1467 * @param args arguments left 1468 * @param cfgfile config file name 1469 * @param cfg handle for the configuration 1470 */ 1471 static void 1472 run (void *cls, 1473 char *const *args, 1474 const char *cfgfile, 1475 const struct GNUNET_CONFIGURATION_Handle *cfg) 1476 { 1477 (void) cls; 1478 (void) args; 1479 (void) cfgfile; 1480 1481 state = DIGITIZER_STATE_INIT; 1482 state_ctx = GNUNET_new(struct DIGITIZER_StateContext); 1483 display_ctx = GNUNET_new(struct DIGITIZER_DisplayContext); 1484 cfg_bank_authentication = GNUNET_new(struct DIGITIZER_BankAuthenticationData); 1485 1486 GNUNET_SCHEDULER_add_now(state_controller_task,(void *) cfg); 1487 1488 return; 1489 } 1490 1491 1492 int 1493 main (int argc, 1494 char *const *argv) 1495 { 1496 int ret; 1497 1498 struct GNUNET_GETOPT_CommandLineOption options[] = { 1499 GNUNET_GETOPT_option_flag ('d', 1500 "enable-diagnostics", 1501 "enable diagnostics for debuging", 1502 &enable_diagnostics), 1503 GNUNET_GETOPT_OPTION_END 1504 }; 1505 1506 ret = GNUNET_PROGRAM_run (TALER_DIGITIZER_project_data (), 1507 argc, 1508 argv, 1509 "taler-digitizer", 1510 "This is an application for the Cash Digitizer." 1511 " It accepts cash and transfers it to the Taler Wallet.\n", 1512 options, 1513 &run, 1514 NULL); 1515 1516 if (GNUNET_NO == ret) 1517 return 0; 1518 if (GNUNET_OK != ret) 1519 return 1; 1520 return global_ret; 1521 }