cash2ecash

cash2ecash: cash acceptor that issues digital cash (experimental)
Log | Files | Refs | README | LICENSE

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 }