cash2ecash

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

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 }