taler-digitizer.c (45792B)
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 = (0 == strcasecmp(vr->details.ok.configi.currency, 426 cfg_currency)) 427 ? TALER_BANK_CC_MATCH 428 : TALER_BANK_CC_MISSMATCH; 429 if(TALER_BANK_CC_MATCH != state_ctx->currency_compa) 430 { 431 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 432 "taler-digitizer", 433 "CURRENCY", 434 "not compatible with bank currency"); 435 state = DIGITIZER_STATE_TERMINAL_ERROR; 436 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 437 return; 438 } 439 if(-1 == TALER_amount_cmp(&(vr->details.ok.configi.max_wire_transfer_amount), 440 &(state_ctx->max_insertion_amount))) 441 { 442 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 443 "taler-digitizer", 444 "BANK_BASE_URL or MAX_DENOMINATION", 445 "max denominations not compatible with bank max_wire_transfer_amount"); 446 state = DIGITIZER_STATE_TERMINAL_ERROR; 447 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 448 return; 449 } 450 state_ctx->bank_max_wire_transfer_amount = vr->details.ok.configi.max_wire_transfer_amount; 451 if(1 == TALER_amount_cmp(&(vr->details.ok.configi.min_wire_transfer_amount), 452 &(state_ctx->min_insertion_amount))) 453 { 454 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 455 "taler-digitizer", 456 "BANK_BASE_URL or MAX_DENOMINATION", 457 "min denominations not compatible with bank min_wire_transfer_amount"); 458 state = DIGITIZER_STATE_TERMINAL_ERROR; 459 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 460 return; 461 } 462 463 464 state = DIGITIZER_STATE_IDLE; 465 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 466 return; 467 } 468 469 /** 470 * callback of accounts request 471 * used in the Idle state 472 */ 473 static void 474 on_get_accounts_done(void *cls, 475 const struct TALER_BANK_AccountsResponse *vr) 476 { 477 TALER_LOG_DEBUG ("Callback of accounts/$USERNAME\n"); 478 479 (void) cls; 480 get_accounts_handle = NULL; 481 struct TALER_Amount account_max_withdrawal; 482 483 if(0 != strcmp("active", 484 vr->details.ok.acc.status)) 485 { 486 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 487 "taler-digitizer", 488 "BANK_ACCOUNT", 489 "bank account is not in active state"); 490 state = DIGITIZER_STATE_TERMINAL_ERROR; 491 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 492 return; 493 } 494 TALER_amount_min (&account_max_withdrawal, 495 &vr->details.ok.acc.balance.amount, 496 &vr->details.ok.acc.debit_threshold); 497 if(-1 == TALER_amount_cmp (&account_max_withdrawal, 498 &state_ctx->max_insertion_amount)) 499 { 500 TALER_LOG_ERROR("bank account does not have enough balance or whithdrawal limit to withdrawal the biggest denomination"); 501 state = DIGITIZER_STATE_TERMINAL_ERROR; 502 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 503 return; 504 } 505 TALER_amount_min(&state_ctx->withdrawal_limit,&account_max_withdrawal,&state_ctx->bank_max_wire_transfer_amount); 506 TALER_amount_min(&state_ctx->withdrawal_limit,&state_ctx->withdrawal_limit,&cfg_user_withdrawallimit); 507 508 509 510 state = DIGITIZER_STATE_CREATE_QR; 511 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 512 return; 513 } 514 515 516 /** 517 * Timeout when Money is not sent in 518 * CASHUP_TIMEOUT_SECONDS 519 */ 520 static void 521 timeout_CashingUp_task(void *cls) 522 { 523 TALER_LOG_DEBUG ("Timeout of Cashing Up\n"); 524 525 (void) cls; 526 527 state = DIGITIZER_STATE_TERMINAL_ERROR; 528 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 529 return; 530 } 531 532 533 /** 534 * callback of accounts withdrawal request 535 * used in the QR Create state 536 */ 537 static void 538 on_post_accounts_withdrawal_done(void *cls, 539 const struct TALER_BANK_CreateWithdrawalResponse *vr) 540 { 541 TALER_LOG_DEBUG ("Callback of accounts/$USERNAME/withdrawal\n"); 542 543 (void) cls; 544 post_accounts_withdrawal_handle = NULL; 545 546 state_ctx->wi.taler_withdraw_uri = GNUNET_strdup(vr->details.ok.wopd.taler_withdraw_uri); 547 state_ctx->wi.withdrawal_id = GNUNET_strdup(vr->details.ok.wopd.withdrawal_id); 548 549 state = DIGITIZER_STATE_SCAN_QR; 550 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 551 return; 552 } 553 554 555 /** 556 * callback of accounts withdrawal request 557 * used in the QR Create state 558 */ 559 static void 560 on_post_withdrawal_confirm_done(void *cls, 561 const struct TALER_BANK_WithdrawalConfirmResponse *vr) 562 { 563 TALER_LOG_DEBUG ("Callback of accounts/$USERNAME/withdrawal/$WOPID/confirm\n"); 564 (void) cls; 565 (void) vr; 566 //struct GNUNET_SCHEDULER_Task *timeout_handle; 567 struct GNUNET_TIME_Relative delay; 568 //struct GNUNET_TIME_Relative poll; 569 570 post_withdrawal_confirm_handle = NULL; 571 delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 572 CASHUP_TIMEOUT_SECONDS); 573 //get reserve 574 //poll = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 575 // CASHUP_CHECK_BALANCE_INTERVAL_MILISECONDS); 576 //timeout_handle = 577 GNUNET_SCHEDULER_add_delayed(delay, 578 timeout_CashingUp_task, 579 NULL); 580 state = DIGITIZER_STATE_TERMINAL_ERROR; 581 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 582 return; 583 } 584 585 586 /** 587 * When UART signal from Coin Acceptor 588 * recived, or timeout of ACCEPT_CASH_TIMEOUT_SECONDS 589 */ 590 static void 591 on_coin_recived(void *cls) 592 { 593 (void) cls; 594 struct TALER_Amount inserted; 595 ssize_t n; 596 uint8_t buff[32] = {0}; //only on byte read per accept cycle, but check if more than one was read 597 state = TALER_amount_is_zero(&state_ctx->digitizer_user_balance)? 598 DIGITIZER_STATE_CANCEL_WITHDRAWAL:DIGITIZER_STATE_CASHING_UP; 599 if (GNUNET_SCHEDULER_REASON_TIMEOUT == 600 GNUNET_SCHEDULER_get_task_context()->reason) 601 { 602 TALER_LOG_DEBUG ("Timeout of Accept Coin\n"); 603 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 604 return; 605 } 606 n = read (GNUNET_NETWORK_get_fd (filestream_ca), buff, sizeof (buff)); 607 TALER_LOG_DEBUG ("read n=%zd",n); 608 if(0 < n) 609 { 610 for(ssize_t i=0;i<n;i++) 611 { 612 TALER_LOG_DEBUG ("Coin byte received: 0x%02x (%d)\n", buff[i], buff[i]); 613 if(i>0) 614 TALER_LOG_WARNING("Multiple Coins inserted!\n"); 615 strcpy(inserted.currency,cfg_currency); 616 inserted.value = buff[i] / 10; 617 inserted.fraction = (buff[i] % 10) * (TALER_AMOUNT_FRAC_BASE/10); 618 if(0 > TALER_amount_add(&state_ctx->digitizer_user_balance, 619 &state_ctx->digitizer_user_balance, 620 &inserted)) 621 { 622 TALER_LOG_ERROR("adding amount failed\n"); 623 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 624 return; 625 } 626 } 627 state = DIGITIZER_STATE_COUNT_MONEY; 628 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 629 return; 630 } 631 else if(n == 0) 632 { 633 TALER_LOG_INFO("No Coin inserted in time\n"); 634 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 635 return; 636 } 637 else 638 { 639 perror ("read uart"); 640 TALER_LOG_INFO("Signal Error UART Coin Acceptor\n"); 641 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 642 return; 643 } 644 return; 645 } 646 647 648 /** 649 * Get withdrawal request for repeated requesting 650 */ 651 static void 652 get_withdrawal_task(void *cls); 653 654 655 /** 656 * callback of accounts withdrawal request 657 * used in the QR Create state 658 */ 659 static void 660 on_get_withdrawal_status_done(void *cls, 661 const struct TALER_BANK_WithdrawalResponse *vr) 662 { 663 TALER_LOG_DEBUG ("Callback of withdrawal/$WITHDRAWAL_ID\n"); 664 struct GNUNET_SCHEDULER_Task *timeout_handle; 665 timeout_handle = cls; 666 get_withdrawal_handle = NULL; 667 if(0 == strcasecmp("selected", vr->details.ok.acc.status)) 668 { 669 GNUNET_SCHEDULER_cancel(timeout_handle); 670 clear_screen(); 671 state = DIGITIZER_STATE_COUNT_MONEY; 672 // give context for non terminal errors! 673 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 674 } 675 else 676 { 677 struct GNUNET_TIME_Relative poll; 678 poll = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS,200); 679 GNUNET_SCHEDULER_add_delayed(poll,get_withdrawal_task,timeout_handle); 680 } 681 682 return; 683 } 684 685 /** 686 * Get withdrawal request for repeated requesting 687 */ 688 static void 689 get_withdrawal_task(void *cls) 690 { 691 struct GNUNET_SCHEDULER_Task *timeout_handle; 692 timeout_handle = cls; 693 694 get_withdrawal_handle = 695 TALER_BANK_get_withdrawal(curl_ctx, 696 cfg_bank_base_url, 697 state_ctx->wi.withdrawal_id, 698 on_get_withdrawal_status_done, 699 timeout_handle, 700 NULL); 701 return; 702 } 703 704 705 /** 706 * Timeout when QR is shown 707 * SCAN_QR_TIMEOUT_SECONDS without been scanned 708 * used in the ScanQR state 709 */ 710 static void 711 timeout_ScanQR_task(void *cls) 712 { 713 TALER_LOG_DEBUG ("Timeout of ScanQR\n"); 714 715 (void) cls; 716 717 state = DIGITIZER_STATE_CANCEL_WITHDRAWAL; 718 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 719 return; 720 } 721 722 723 /** 724 * @brief Cleanup when no task is scheduled anymore 725 * 726 * @param cls closure 727 */ 728 static void 729 shutdown_task (void *cls) 730 { 731 (void)cls; 732 gpiod_line_request_release(rl_ca_inhibit); 733 GNUNET_NETWORK_socket_close (filestream_ca); 734 filestream_ca = NULL; 735 736 if (NULL != get_withdrawal_handle) 737 { 738 TALER_BANK_get_withdrawal_cancel (get_withdrawal_handle); 739 get_withdrawal_handle = NULL; 740 } 741 if (NULL != get_config_handle) 742 { 743 TALER_BANK_get_config_cancel (get_config_handle); 744 get_config_handle = NULL; 745 } 746 if (NULL != post_accounts_withdrawal_handle) 747 { 748 TALER_BANK_post_withdrawal_create_cancel(post_accounts_withdrawal_handle); 749 post_accounts_withdrawal_handle = NULL; 750 } 751 if (NULL != post_withdrawal_confirm_handle) 752 { 753 TALER_BANK_post_withdrawal_confirm_cancel(post_withdrawal_confirm_handle); 754 post_withdrawal_confirm_handle = NULL; 755 } 756 if (NULL != reschedule_ctx) 757 { 758 GNUNET_CURL_gnunet_rc_destroy (reschedule_ctx); 759 reschedule_ctx = NULL; 760 } 761 if (NULL != curl_ctx) 762 { 763 GNUNET_CURL_fini (curl_ctx); 764 curl_ctx = NULL; 765 } 766 DIGITIZER_bank_auth_free (cfg_bank_authentication); 767 GNUNET_free(cfg_bank_authentication); 768 GNUNET_free(state_ctx); 769 GNUNET_free(display_ctx); 770 } 771 772 /** 773 * Initialising state 774 * Init: Digitizer config, Bank config, Screen task, Touch task 775 */ 776 static void Init_state_task(void *cls) 777 { 778 TALER_LOG_DEBUG ("INIT state\n"); 779 780 const struct GNUNET_CONFIGURATION_Handle *cfg = cls; 781 782 if (GNUNET_OK != 783 GNUNET_CONFIGURATION_get_value_string (cfg, 784 "taler-digitizer", 785 "BANK_BASE_URL", 786 &cfg_bank_base_url)) 787 { 788 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 789 "taler-digitizer", 790 "BANK_BASE_URL"); 791 global_ret = EXIT_FAILURE; 792 return; 793 } 794 if (GNUNET_OK != 795 GNUNET_CONFIGURATION_get_value_string (cfg, 796 "taler-digitizer", 797 "BANK_ACCOUNT", 798 &cfg_bank_account_username)) 799 { 800 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 801 "taler-digitizer", 802 "BANK_ACCOUNT"); 803 global_ret = EXIT_FAILURE; 804 return; 805 } 806 if (GNUNET_OK != 807 DIGITIZER_bank_auth_parse_cfg (cfg, 808 "bank-authentication", 809 cfg_bank_authentication)) 810 { 811 global_ret = EXIT_FAILURE; 812 return; 813 } 814 if (GNUNET_OK != 815 GNUNET_CONFIGURATION_get_value_string (cfg, 816 "taler-digitizer", 817 "EXCHANGE_BASE_URL", 818 &cfg_exchange_base_url)) 819 { 820 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 821 "taler-digitizer", 822 "EXCHANGE_BASE_URL"); 823 global_ret = EXIT_FAILURE; 824 return; 825 } 826 if (GNUNET_OK != 827 GNUNET_CONFIGURATION_get_value_string (cfg, 828 "taler-digitizer", 829 "CURRENCY", 830 &cfg_currency)) 831 { 832 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 833 "taler-digitizer", 834 "CURRENCY"); 835 global_ret = EXIT_FAILURE; 836 return; 837 } 838 if(GNUNET_OK != TALER_check_currency(cfg_currency)) 839 { 840 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 841 "taler-digitizer", 842 "CURRENCY", 843 "malformed currency"); 844 global_ret = EXIT_FAILURE; 845 return; 846 } 847 char *limit_value; 848 if (GNUNET_OK != 849 GNUNET_CONFIGURATION_get_value_string (cfg, 850 "taler-digitizer", 851 "USER_WITHDRAWALLIMIT", 852 &limit_value)) 853 { 854 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 855 "taler-digitizer", 856 "USER_WITHDRAWALLIMIT"); 857 GNUNET_free(limit_value); 858 global_ret = EXIT_FAILURE; 859 return; 860 } 861 if (GNUNET_OK != 862 join_strings_to_amount(cfg_currency, 863 limit_value, 864 &cfg_user_withdrawallimit)) 865 { 866 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 867 "taler-digitizer", 868 "USER_WITHDRAWALLIMIT", 869 "malformed denomination"); 870 GNUNET_free(limit_value); 871 global_ret = EXIT_FAILURE; 872 return; 873 } 874 GNUNET_free(limit_value); 875 876 unsigned long long user_withdrawal_period_number; 877 if (GNUNET_OK != 878 GNUNET_CONFIGURATION_get_value_number (cfg, 879 "taler-digitizer", 880 "USER_WITHDRAWAL_PERIOD", 881 &user_withdrawal_period_number)) 882 { 883 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 884 "taler-digitizer", 885 "USER_WITHDRAWAL_PERIOD"); 886 global_ret = EXIT_FAILURE; 887 return; 888 } 889 cfg_user_withdrawal_period = GNUNET_TIME_relative_multiply ( 890 DIGITIZER_PERSON_WITHDRAWAL_PERIOD_TIME_UNIT, 891 user_withdrawal_period_number); 892 893 cfg_kyc_functionality = GNUNET_CONFIGURATION_get_value_yesno (cfg, 894 "taler-digitizer", 895 "KYC_FUNCTIONALITY"); 896 if (GNUNET_SYSERR == cfg_kyc_functionality) 897 { 898 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 899 "taler-digitizer", 900 "KYC_FUNCTIONALITY"); 901 global_ret = EXIT_FAILURE; 902 return; 903 } 904 if (GNUNET_OK != 905 GNUNET_CONFIGURATION_get_value_filename (cfg, 906 "taler-digitizer", 907 "FRAMEBUFFER_DEVICE", 908 &cfg_framebuffer_device)) 909 { 910 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 911 "taler-digitizer", 912 "FRAMEBUFFER_DEVICE"); 913 global_ret = EXIT_FAILURE; 914 return; 915 } 916 if (GNUNET_OK != 917 GNUNET_CONFIGURATION_get_value_filename (cfg, 918 "taler-digitizer", 919 "FRAMEBUFFER_BACKLIGHT", 920 &cfg_framebuffer_backlight)) 921 { 922 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 923 "taler-digitizer", 924 "FRAMEBUFFER_BACKLIGHT"); 925 global_ret = EXIT_FAILURE; 926 return; 927 } 928 cfg_ca_enable = GNUNET_CONFIGURATION_get_value_yesno (cfg, 929 "coin-acceptor", 930 "ENABLE"); 931 cfg_ba_enable = GNUNET_CONFIGURATION_get_value_yesno (cfg, 932 "bill-acceptor", 933 "ENABLE"); 934 if(GNUNET_OK != cfg_ba_enable) 935 { 936 cfg_ba_enable = GNUNET_NO; 937 join_strings_to_amount(cfg_currency, 938 "0", 939 &cfg_ba_max_denomination); 940 join_strings_to_amount(cfg_currency, 941 "0", 942 &cfg_ba_min_denomination); 943 if(GNUNET_OK != cfg_ca_enable) 944 { 945 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 946 "coin-acceptor or bill-acceptor", 947 "ENABLE"); 948 global_ret = EXIT_FAILURE; 949 return; 950 } 951 } 952 else 953 { 954 if (GNUNET_OK != 955 GNUNET_CONFIGURATION_get_value_filename (cfg, 956 "bill-acceptor", 957 "INHIBIT_DEVICE", 958 &cfg_ba_inhibit_device)) 959 { 960 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 961 "bill-acceptor", 962 "INHIBIT_DEVICE"); 963 global_ret = EXIT_FAILURE; 964 return; 965 } 966 char *denomination_value; 967 if (GNUNET_OK != 968 GNUNET_CONFIGURATION_get_value_string (cfg, 969 "bill-acceptor", 970 "MAX_DENOMINATION", 971 &denomination_value)) 972 { 973 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 974 "bill-acceptor", 975 "MAX_DENOMINATION"); 976 GNUNET_free(denomination_value); 977 global_ret = EXIT_FAILURE; 978 return; 979 } 980 if (GNUNET_OK != 981 join_strings_to_amount(cfg_currency, 982 denomination_value, 983 &cfg_ba_max_denomination)) 984 { 985 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 986 "bill-acceptor", 987 "MAX_DENOMINATION", 988 "malformed denomination"); 989 GNUNET_free(denomination_value); 990 global_ret = EXIT_FAILURE; 991 return; 992 } 993 GNUNET_free(denomination_value); 994 if (GNUNET_OK != 995 GNUNET_CONFIGURATION_get_value_string (cfg, 996 "bill-acceptor", 997 "MIN_DENOMINATION", 998 &denomination_value)) 999 { 1000 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1001 "bill-acceptor", 1002 "MIN_DENOMINATION"); 1003 GNUNET_free(denomination_value); 1004 global_ret = EXIT_FAILURE; 1005 return; 1006 } 1007 if (GNUNET_OK != 1008 join_strings_to_amount(cfg_currency, 1009 denomination_value, 1010 &cfg_ba_min_denomination)) 1011 { 1012 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 1013 "bill-acceptor", 1014 "MIN_DENOMINATION", 1015 "malformed denomination"); 1016 GNUNET_free(denomination_value); 1017 global_ret = EXIT_FAILURE; 1018 return; 1019 } 1020 GNUNET_free(denomination_value); 1021 } 1022 if(GNUNET_OK != cfg_ca_enable) 1023 { 1024 cfg_ca_enable = GNUNET_NO; 1025 join_strings_to_amount(cfg_currency, 1026 "0", 1027 &cfg_ca_max_denomination); 1028 join_strings_to_amount(cfg_currency, 1029 "0", 1030 &cfg_ca_min_denomination); 1031 } 1032 else 1033 { 1034 char *denomination_value; 1035 if (GNUNET_OK != 1036 GNUNET_CONFIGURATION_get_value_string (cfg, 1037 "coin-acceptor", 1038 "MAX_DENOMINATION", 1039 &denomination_value)) 1040 { 1041 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1042 "coin-acceptor", 1043 "MAX_DENOMINATION"); 1044 GNUNET_free(denomination_value); 1045 global_ret = EXIT_FAILURE; 1046 return; 1047 } 1048 if (GNUNET_OK != 1049 join_strings_to_amount(cfg_currency, 1050 denomination_value, 1051 &cfg_ca_max_denomination)) 1052 { 1053 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 1054 "coin-acceptor", 1055 "MAX_DENOMINATION", 1056 "malformed denomination"); 1057 GNUNET_free(denomination_value); 1058 global_ret = EXIT_FAILURE; 1059 return; 1060 } 1061 if (GNUNET_OK != 1062 GNUNET_CONFIGURATION_get_value_string (cfg, 1063 "coin-acceptor", 1064 "MIN_DENOMINATION", 1065 &denomination_value)) 1066 { 1067 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1068 "coin-acceptor", 1069 "MIN_DENOMINATION"); 1070 GNUNET_free(denomination_value); 1071 global_ret = EXIT_FAILURE; 1072 return; 1073 } 1074 if (GNUNET_OK != 1075 join_strings_to_amount(cfg_currency, 1076 denomination_value, 1077 &cfg_ca_min_denomination)) 1078 { 1079 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 1080 "coin-acceptor", 1081 "MIN_DENOMINATION", 1082 "malformed denomination"); 1083 GNUNET_free(denomination_value); 1084 global_ret = EXIT_FAILURE; 1085 return; 1086 } 1087 GNUNET_free(denomination_value); 1088 if (GNUNET_OK != 1089 GNUNET_CONFIGURATION_get_value_filename (cfg, 1090 "coin-acceptor", 1091 "INHIBIT_DEVICE", 1092 &cfg_ca_inhibit_device)) 1093 { 1094 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1095 "coin-acceptor", 1096 "INHIBIT_DEVICE"); 1097 global_ret = EXIT_FAILURE; 1098 return; 1099 } 1100 if (GNUNET_OK != 1101 GNUNET_CONFIGURATION_get_value_number (cfg, 1102 "coin-acceptor", 1103 "INHIBIT_PIN", 1104 &cfg_ca_inhibit_pin)) 1105 { 1106 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1107 "coin-acceptor", 1108 "INHIBIT_PIN"); 1109 global_ret = EXIT_FAILURE; 1110 return; 1111 } 1112 if (GNUNET_OK != 1113 GNUNET_CONFIGURATION_get_value_string (cfg, 1114 "coin-acceptor", 1115 "SIGNAL_DEVICE", 1116 &cfg_ca_sig_device)) 1117 { 1118 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 1119 "coin-acceptor", 1120 "SIGNAL_DEVICE"); 1121 global_ret = EXIT_FAILURE; 1122 return; 1123 } 1124 //CA Init 1125 gpio_settings = gpiod_make_settings(GPIOD_LINE_DIRECTION_OUTPUT, 1126 GPIOD_LINE_BIAS_PULL_UP, 1127 GPIOD_LINE_DRIVE_OPEN_DRAIN,1); 1128 if (NULL == gpio_settings) 1129 { 1130 TALER_LOG_ERROR("GPIO Init failed"); 1131 gpiod_line_settings_free(gpio_settings); 1132 global_ret = EXIT_FAILURE; 1133 return; 1134 } 1135 rl_ca_inhibit = gpiod_make_line_request(cfg_ca_inhibit_device, 1136 cfg_ca_inhibit_pin, 1137 gpio_settings); 1138 if (NULL == rl_ca_inhibit) 1139 { 1140 TALER_LOG_ERROR("GPIO Init failed"); 1141 gpiod_line_request_release(rl_ca_inhibit); 1142 global_ret = EXIT_FAILURE; 1143 return; 1144 } 1145 if(0 != gpiod_line_request_set_value(rl_ca_inhibit, 1146 (unsigned int)cfg_ca_inhibit_pin, 1147 GPIOD_LINE_VALUE_INACTIVE)) 1148 { 1149 TALER_LOG_ERROR("failed to set GPIO active"); 1150 global_ret = EXIT_FAILURE; 1151 return; 1152 } 1153 int fd = ca_uart_init (cfg_ca_sig_device); 1154 if (-1 == fd) 1155 { 1156 TALER_LOG_ERROR ("UART init failed\n"); 1157 global_ret = EXIT_FAILURE; 1158 return; 1159 } 1160 filestream_ca = GNUNET_NETWORK_socket_box_native (fd); 1161 } 1162 1163 1164 state_ctx->min_insertion_amount = 1165 ((1 == TALER_amount_cmp(&cfg_ba_min_denomination, 1166 &cfg_ca_min_denomination))? 1167 cfg_ca_min_denomination : cfg_ba_min_denomination); 1168 1169 if(TALER_AAR_INVALID_NEGATIVE_RESULT == TALER_amount_add(&state_ctx->max_insertion_amount, 1170 &cfg_ba_max_denomination, 1171 &cfg_ca_max_denomination)) 1172 { 1173 GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, 1174 "coin-acceptor", 1175 "XXX_DENOMINATION", 1176 "could not determine min insertion amount"); 1177 global_ret = EXIT_FAILURE; 1178 return; 1179 } 1180 1181 //Screen INIT 1182 1183 //Touch INIT 1184 1185 //BA Init 1186 1187 1188 curl_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, 1189 &reschedule_ctx); 1190 reschedule_ctx = GNUNET_CURL_gnunet_rc_create (curl_ctx); 1191 1192 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 1193 NULL); 1194 1195 get_config_handle = TALER_BANK_get_config (curl_ctx, 1196 cfg_bank_base_url, 1197 &on_get_config_done, 1198 NULL); 1199 } 1200 1201 /** 1202 * Terminal Error state 1203 * When error accures due to config issues, or unrecoverable errors 1204 */ 1205 static void TerminalError_state_task(void *cls) 1206 { 1207 (void)cls; 1208 TALER_LOG_DEBUG ("start TerminalError state task\n"); 1209 global_ret = EXIT_FAILURE; 1210 GNUNET_SCHEDULER_shutdown(); 1211 } 1212 1213 /** 1214 * Idle state 1215 * prepare for new withdrawal process and 1216 * check for start signal from UI 1217 */ 1218 static void Idle_state_task(void *cls) 1219 { 1220 TALER_LOG_DEBUG("Idle state\n"); 1221 clear_screen(); 1222 (void)cls; 1223 TALER_amount_set_zero(cfg_currency,&state_ctx->digitizer_user_balance); 1224 get_accounts_handle = TALER_BANK_get_accounts (curl_ctx, 1225 cfg_bank_base_url, 1226 cfg_bank_account_username, 1227 cfg_bank_authentication, 1228 &on_get_accounts_done, 1229 NULL); 1230 } 1231 1232 /** 1233 * Create QR state 1234 * create QR code with a new WOPID 1235 * check for cancle from UI 1236 */ 1237 static void CreateQR_state_task(void *cls) 1238 { 1239 TALER_LOG_DEBUG("CreateQR state\n"); 1240 (void)cls; 1241 struct TALER_BANK_AccountCreateWithdrawalRequest *acwr; 1242 acwr = GNUNET_new(struct TALER_BANK_AccountCreateWithdrawalRequest); 1243 acwr->no_amount_to_wallet = true; 1244 1245 post_accounts_withdrawal_handle = 1246 TALER_BANK_post_accounts_withdrawal_create (curl_ctx, 1247 cfg_bank_base_url, 1248 cfg_bank_account_username, 1249 cfg_bank_authentication); 1250 if(GNUNET_OK != 1251 TALER_BANK_post_accounts_withdrawal(post_accounts_withdrawal_handle, 1252 acwr, 1253 on_post_accounts_withdrawal_done, 1254 NULL)) 1255 { 1256 TALER_LOG_ERROR("TALER_BANK_post_accounts_withdrawal canceled\n"); 1257 state = DIGITIZER_STATE_CANCEL_WITHDRAWAL; 1258 // give context for non terminal errors! 1259 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1260 } 1261 GNUNET_free(acwr); 1262 return; 1263 } 1264 1265 /** 1266 * Show QR state 1267 * show QR code on display 1268 * check for cancle from UI 1269 */ 1270 static void ScanQR_state_task(void *cls) 1271 { 1272 TALER_LOG_DEBUG ("ScanQR state\n"); 1273 (void)cls; 1274 1275 struct GNUNET_SCHEDULER_Task *timeout_handle; 1276 struct GNUNET_TIME_Relative delay; 1277 struct GNUNET_TIME_Relative poll; 1278 1279 delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1280 SCAN_QR_TIMEOUT_SECONDS); 1281 poll = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 1282 SCAN_QR_CHECK_STATUS_INTERVAL_MILISECONDS); 1283 timeout_handle = GNUNET_SCHEDULER_add_delayed(delay, 1284 timeout_ScanQR_task, 1285 NULL); 1286 start_qr_show(SCAN_QR_TIMEOUT_SECONDS); 1287 1288 //char *buf; 1289 //GNUNET_asprintf(&buf,"%d",SCAN_QR_TIMEOUT_SECONDS*1000); 1290 1291 GNUNET_SCHEDULER_add_delayed(poll, 1292 get_withdrawal_task, 1293 timeout_handle); 1294 return; 1295 } 1296 1297 static void CountMoney_state_task(void *cls) 1298 { 1299 char* balance_str; 1300 struct TALER_Amount *temp_amount; 1301 temp_amount = GNUNET_new(struct TALER_Amount); 1302 balance_str = TALER_amount_to_string(&state_ctx->digitizer_user_balance); 1303 TALER_LOG_DEBUG ("CountMoney: %s\n",balance_str); 1304 GNUNET_free(balance_str); 1305 (void)cls; 1306 if(0 != gpiod_line_request_set_value(rl_ca_inhibit, 1307 (unsigned int)cfg_ca_inhibit_pin, 1308 GPIOD_LINE_VALUE_INACTIVE)) 1309 { 1310 GNUNET_free(temp_amount); 1311 if(TALER_amount_is_zero(&state_ctx->digitizer_user_balance)) 1312 { 1313 TALER_LOG_ERROR("failed to set GPIO inactive"); 1314 state = DIGITIZER_STATE_CANCEL_WITHDRAWAL; 1315 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1316 } 1317 else 1318 { 1319 TALER_LOG_ERROR("failed to set GPIO active"); 1320 state = DIGITIZER_STATE_CASHING_UP; 1321 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1322 } 1323 } 1324 if (1 != TALER_amount_cmp (&state_ctx->withdrawal_limit, 1325 &state_ctx->digitizer_user_balance)) 1326 { 1327 state = DIGITIZER_STATE_CASHING_UP; 1328 GNUNET_SCHEDULER_add_now (state_controller_task, NULL); 1329 return; 1330 } 1331 TALER_amount_subtract(temp_amount, 1332 &state_ctx->withdrawal_limit, 1333 &state_ctx->digitizer_user_balance); 1334 if(-1 == TALER_amount_cmp(temp_amount, 1335 &state_ctx->max_insertion_amount)) 1336 { 1337 GNUNET_free(temp_amount); 1338 TALER_LOG_INFO("withdrawal limit reached"); 1339 state = DIGITIZER_STATE_CASHING_UP; 1340 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1341 }else 1342 { 1343 GNUNET_free(temp_amount); 1344 if(0 != gpiod_line_request_set_value(rl_ca_inhibit, 1345 (unsigned int)cfg_ca_inhibit_pin, 1346 GPIOD_LINE_VALUE_ACTIVE)) 1347 { 1348 TALER_LOG_ERROR("failed to set GPIO active"); 1349 state = DIGITIZER_STATE_CASHING_UP; 1350 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1351 } 1352 tcflush (GNUNET_NETWORK_get_fd (filestream_ca), TCIFLUSH); 1353 state = DIGITIZER_STATE_ACCEPT_CASH; 1354 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1355 } 1356 } 1357 1358 1359 static void AcceptCash_state_task(void *cls) 1360 { 1361 TALER_LOG_DEBUG("AcceptingCash state"); 1362 (void)cls; 1363 struct GNUNET_TIME_Relative delay; 1364 delay = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 1365 ACCEPT_CASH_TIMEOUT_SECONDS); 1366 GNUNET_SCHEDULER_add_read_net(delay,filestream_ca,on_coin_recived,NULL); 1367 } 1368 1369 1370 static void CashingUP_state_task(void *cls) 1371 { 1372 TALER_LOG_DEBUG("CashingUP state"); 1373 (void)cls; 1374 struct TALER_BANK_AccountWithdrawalConfirmRequest *wcr; 1375 wcr = GNUNET_new(struct TALER_BANK_AccountWithdrawalConfirmRequest); 1376 wcr->amount = state_ctx->digitizer_user_balance; 1377 char* balance_str; 1378 balance_str = TALER_amount_to_string(&state_ctx->digitizer_user_balance); 1379 TALER_LOG_DEBUG ("CashingUP: %s\n",balance_str); 1380 gpiod_line_request_set_value(rl_ca_inhibit, 1381 (unsigned int)cfg_ca_inhibit_pin, 1382 GPIOD_LINE_VALUE_INACTIVE); 1383 post_withdrawal_confirm_handle = 1384 TALER_BANK_post_withdrawal_confirm_create (curl_ctx, 1385 cfg_bank_base_url, 1386 cfg_bank_account_username, 1387 state_ctx->wi.withdrawal_id, 1388 cfg_bank_authentication); 1389 if(GNUNET_OK != 1390 TALER_BANK_post_withdrawal_confirm(post_withdrawal_confirm_handle, 1391 wcr, 1392 on_post_withdrawal_confirm_done, 1393 NULL)) 1394 { 1395 TALER_LOG_ERROR("TALER_BANK_post_withdrawal_confirm canceled\n"); 1396 state = DIGITIZER_STATE_TERMINAL_ERROR; 1397 GNUNET_SCHEDULER_add_now(state_controller_task,NULL); 1398 GNUNET_free(wcr); 1399 } 1400 GNUNET_free(wcr); 1401 } 1402 1403 1404 /** 1405 * Switch between State tasks 1406 */ 1407 static void state_controller_task(void *cls) 1408 { 1409 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 1410 1411 switch (state) 1412 { 1413 case DIGITIZER_STATE_INIT: 1414 { 1415 GNUNET_SCHEDULER_add_now(Init_state_task,cfg); 1416 return; 1417 } 1418 case DIGITIZER_STATE_IDLE: 1419 { 1420 GNUNET_SCHEDULER_add_now(Idle_state_task,NULL); 1421 return; 1422 } 1423 case DIGITIZER_STATE_TERMINAL_ERROR: 1424 { 1425 GNUNET_SCHEDULER_add_now(TerminalError_state_task,NULL); 1426 return; 1427 } 1428 case DIGITIZER_STATE_CREATE_QR: 1429 { 1430 GNUNET_SCHEDULER_add_now(CreateQR_state_task,NULL); 1431 return; 1432 } 1433 case DIGITIZER_STATE_SCAN_QR: 1434 { 1435 GNUNET_SCHEDULER_add_now(ScanQR_state_task,NULL); 1436 return; 1437 } 1438 case DIGITIZER_STATE_COUNT_MONEY: 1439 { 1440 GNUNET_SCHEDULER_add_now(CountMoney_state_task,NULL); 1441 return; 1442 } 1443 case DIGITIZER_STATE_ACCEPT_CASH: 1444 { 1445 GNUNET_SCHEDULER_add_now(AcceptCash_state_task,NULL); 1446 return; 1447 } 1448 case DIGITIZER_STATE_CASHING_UP: 1449 { 1450 GNUNET_SCHEDULER_add_now(CashingUP_state_task,NULL); 1451 return; 1452 } 1453 1454 default: 1455 { 1456 TALER_LOG_ERROR("Gost-State in state machine\n"); 1457 global_ret = EXIT_FAILURE; 1458 GNUNET_SCHEDULER_shutdown (); 1459 } 1460 1461 } 1462 } 1463 1464 1465 /** 1466 * @brief Start the application 1467 * 1468 * @param cls closure 1469 * @param args arguments left 1470 * @param cfgfile config file name 1471 * @param cfg handle for the configuration 1472 */ 1473 static void 1474 run (void *cls, 1475 char *const *args, 1476 const char *cfgfile, 1477 const struct GNUNET_CONFIGURATION_Handle *cfg) 1478 { 1479 (void) cls; 1480 (void) args; 1481 (void) cfgfile; 1482 1483 state = DIGITIZER_STATE_INIT; 1484 state_ctx = GNUNET_new(struct DIGITIZER_StateContext); 1485 display_ctx = GNUNET_new(struct DIGITIZER_DisplayContext); 1486 cfg_bank_authentication = GNUNET_new(struct DIGITIZER_BankAuthenticationData); 1487 1488 GNUNET_SCHEDULER_add_now(state_controller_task,(void *) cfg); 1489 1490 return; 1491 } 1492 1493 1494 int 1495 main (int argc, 1496 char *const *argv) 1497 { 1498 int ret; 1499 1500 struct GNUNET_GETOPT_CommandLineOption options[] = { 1501 GNUNET_GETOPT_option_flag ('d', 1502 "enable-diagnostics", 1503 "enable diagnostics for debuging", 1504 &enable_diagnostics), 1505 GNUNET_GETOPT_OPTION_END 1506 }; 1507 1508 ret = GNUNET_PROGRAM_run (TALER_DIGITIZER_project_data (), 1509 argc, 1510 argv, 1511 "taler-digitizer", 1512 "This is an application for the Cash Digitizer." 1513 " It accepts cash and transfers it to the Taler Wallet.\n", 1514 options, 1515 &run, 1516 NULL); 1517 1518 if (GNUNET_NO == ret) 1519 return 0; 1520 if (GNUNET_OK != ret) 1521 return 1; 1522 return global_ret; 1523 }