cash2ecash

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

commit 2d71353b4e9a7276755b217c1e7e17462bcb78cb
parent 4ffba69d998544b302751e576d5c89399c9a9960
Author: Tellenbach Reto <tellr1@bfh.ch>
Date:   Thu,  4 Jun 2026 14:17:37 +0200

[new] State-logic: implemented state machine logic with controll task

Diffstat:
Asrc/digitizer_display.h | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/digitizer_error_codes.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/error_codes.h | 46----------------------------------------------
Msrc/taler-digitizer.c | 267++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/taler/taler_digitizer_service.h | 16++++++++++++++++
Mtaler-digitizer.conf | 1+
6 files changed, 356 insertions(+), 89 deletions(-)

diff --git a/src/digitizer_display.h b/src/digitizer_display.h @@ -0,0 +1,62 @@ +/* + This file is part of TALER cash2ecash + Copyright (C) 2026 GNUnet e.V. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +/** + * @file digitizer_display.c + * @brief runs screen and touch + * @author Reto Tellenbach + */ + +#ifndef DIGITIZER_DISPLAY_H +#define DIGITIZER_DISPLAY_H +/** + * Button state used to recognise presses shoe user + * input feedback + */ +enum DIGITIZER_ButtonState +{ + /** + * Button is not pressable, + * therfor grayed out + */ + DIGITIZER_BUTTON_UNACCESSABLE, + + /** + * Button ready to be pressed + */ + DIGITIZER_BUTTON_READY, + + /** + * Button is currently pressed, + * shown in a darker tone + */ + DIGITIZER_BUTTON_PRESSED, +}; + +struct DIGITIZER_DisplayContext +{ + char *status_text; + + char *help_text; + + enum DIGITIZER_ButtonState digitizing_btn; + + enum DIGITIZER_ButtonState cancle_btn; +}; +#endif +\ No newline at end of file diff --git a/src/digitizer_error_codes.h b/src/digitizer_error_codes.h @@ -0,0 +1,51 @@ +/* + This file is part of TALER cash2ecash + Copyright (C) 2026 GNUnet e.V. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +/** + * @file error_codes.h + * @brief error codes for Cash Digitizer + * @author Reto Tellenbach + */ + +#ifndef ERROR_CODES_H +#define ERROR_CODES_H + +/** + * Taler client Cash Digitizer errors. + */ +enum DIGITIZER_ErrorCode +{ + /** + * indicate success (no error) + */ + DIGITIZER_EC_NONE = 0, + + /** + * non specific fail + */ + DIGITIZER_EC_GENERIC = 1, + + /** + * Termina Error + * Incompatible currency, from Digitizer and Bank + */ + DIGITIZER_EC_TERMINAL_INCOMPATIBLE_CURRENCY = 10000 +}; + +#endif +\ No newline at end of file diff --git a/src/error_codes.h b/src/error_codes.h @@ -1,45 +0,0 @@ -/* - This file is part of TALER cash2ecash - Copyright (C) 2026 GNUnet e.V. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -/** - * @file error_codes.h - * @brief error codes for Cash Digitizer - * @author Reto Tellenbach - */ - -#ifndef ERROR_CODES_H -#define ERROR_CODES_H - -/** - * Taler client Cash Digitizer errors. - */ -enum DIGITIZER_ErrorCode -{ - /** - * indicate success (no error) - */ - DIGITIZER_EC_NONE = 0, - - /** - * non specific fail - */ - DIGITIZER_EC_GENERIC = 1, -}; - -#endif -\ No newline at end of file diff --git a/src/taler-digitizer.c b/src/taler-digitizer.c @@ -27,6 +27,7 @@ #include <gnunet/gnunet_util_lib.h> #include "taler_digitizer_util.h" #include "lib/bank_api_get_config.h" +#include "digitizer_display.h" /** @@ -46,9 +47,14 @@ static int global_ret; static int enable_diagnostics; /** - * Taler Backend url read from configuration file + * Taler bank backend url read from configuration file */ -static char *cfg_backend_base_url; +static char *cfg_bank_base_url; + +/** + * Taler exchange backend url read from configuration file + */ +static char *cfg_exchange_base_url; /** * Currency read from configuration file @@ -150,15 +156,95 @@ static struct GNUNET_CURL_RescheduleContext *reschedule_ctx; static struct TALER_BANK_GetConfigHandle *get_config_handle; -/** - * State-Machine state of Cash Digitizer - */ -typedef void (*DIGITIZER_State)(void); +enum +DIGITIZER_states +{ + /** + * Init by loading configs + */ + DIGITIZER_STATE_INIT, + /** + * + */ + DIGITIZER_STATE_IDLE, + /** + * + */ + DIGITIZER_STATE_SCAN_QR, + /** + * + */ + DIGITIZER_STATE_IDENTIFICATION, + /** + * + */ + DIGITIZER_STATE_COUNT_MONEY, + /** + * + */ + DIGITIZER_STATE_ACCEPT_CASH, + /** + * + */ + DIGITIZER_STATE_CASHING_UP, + /** + * + */ + DIGITIZER_STATE_WITHDRAWAL_STATUS, + /** + * + */ + DIGITIZER_STATE_CANCEL_WITHDRAWAL, + /** + * + */ + DIGITIZER_STATE_WITHDRAWAL_ERROR, + /** + * + */ + DIGITIZER_STATE_TERMINAL_ERROR, + + /** + * count used to initialise state table with size + */ + DIGITIZER_STATE_NUMBER_OF_STATES +}; /** - * keeps the current state and is used to change states + * Data moved between states */ -static DIGITIZER_State current_state; +struct DIGITIZER_StateContext +{ + enum TALER_BANK_VersionCompatibility version_compa; + + enum TALLER_BANK_CurrencyCompatibility currency_compa; + + /** + * digitizer defined min transaction amount, + * sum from bill- and coin-acceptor + */ + struct TALER_Amount max_insertion_amount; + + /** + * digitizer defined min transaction amount, + * min from bill-/coin-acceptor + */ + struct TALER_Amount min_insertion_amount; + + /** + * balance updated in each Idle state, + * at the befor of each withdrawal + */ + struct TALER_Amount bank_balance_befor_withdrawal; +}; + +static enum DIGITIZER_states state; + +struct DIGITIZER_StateContext *state_ctx; + +struct DIGITIZER_DisplayContext *display_ctx; + +static void state_controller_task(void *cls); /** @@ -171,7 +257,7 @@ static DIGITIZER_State current_state; * #GNUNET_SYSERR if it is invalid. */ enum GNUNET_GenericReturnValue -TALER_join_strings_to_amount(const char *currency, +join_strings_to_amount(const char *currency, const char *value_fraction, struct TALER_Amount *amount) { @@ -193,14 +279,25 @@ on_get_config_done (void *cls, const struct TALER_BANK_ConfigResponse *vr) { (void) cls; - (void) vr; - get_config_handle = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Config Callback\n"); - - GNUNET_SCHEDULER_shutdown (); + state_ctx->version_compa = vr->details.ok.version_compa; + state_ctx->currency_compa = strcmp(vr->details.ok.configi.currency, + cfg_currency); + if(TALER_BANK_CC_MATCH != state_ctx->currency_compa) + { + GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR, + "taler-digitizer", + "CURRENCY", + "not compatible with bank currency"); + state = DIGITIZER_STATE_TERMINAL_ERROR; + GNUNET_SCHEDULER_add_now(state_controller_task,NULL); + return; + } + + state = DIGITIZER_STATE_SCAN_QR; + GNUNET_SCHEDULER_add_now(state_controller_task,NULL); + return; } @@ -213,6 +310,8 @@ static void shutdown_task (void *cls) { (void)cls; + GNUNET_free(state_ctx); + GNUNET_free(display_ctx); if (NULL != get_config_handle) { @@ -231,33 +330,20 @@ shutdown_task (void *cls) } } - /** - * @brief Start the application - * - * @param cls closure - * @param args arguments left - * @param cfgfile config file name - * @param cfg handle for the configuration + * */ -static void -run (void *cls, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) +static void Init_state_task(void *cls) { - (void) cls; - (void) args; - (void) cfgfile; + TALER_LOG_DEBUG ("start INIT state task\n"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Parse Configuration\n"); + const struct GNUNET_CONFIGURATION_Handle *cfg = cls; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "taler-digitizer", "BACKEND_BASE_URL", - &cfg_backend_base_url)) + &cfg_bank_base_url)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "taler-digitizer", @@ -268,6 +354,18 @@ run (void *cls, if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "taler-digitizer", + "EXCHANGE_BASE_URL", + &cfg_exchange_base_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "taler-digitizer", + "EXCHANGE_BASE_URL"); + global_ret = EXIT_FAILURE; + return; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "taler-digitizer", "CURRENCY", &cfg_currency)) { @@ -296,11 +394,12 @@ run (void *cls, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "taler-digitizer", "USER_WITHDRAWALLIMIT"); + GNUNET_free(limit_value); global_ret = EXIT_FAILURE; return; } if (GNUNET_OK != - TALER_join_strings_to_amount(cfg_currency, + join_strings_to_amount(cfg_currency, limit_value, &cfg_user_withdrawallimit)) { @@ -308,9 +407,11 @@ run (void *cls, "taler-digitizer", "USER_WITHDRAWALLIMIT", "malformed denomination"); + GNUNET_free(limit_value); global_ret = EXIT_FAILURE; return; } + GNUNET_free(limit_value); unsigned long long user_withdrawal_period_number; if (GNUNET_OK != @@ -406,11 +507,12 @@ run (void *cls, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "bill-acceptor", "MAX_DENOMINATION"); + GNUNET_free(denomination_value); global_ret = EXIT_FAILURE; return; } if (GNUNET_OK != - TALER_join_strings_to_amount(cfg_currency, + join_strings_to_amount(cfg_currency, denomination_value, &cfg_ba_max_denomination)) { @@ -418,9 +520,11 @@ run (void *cls, "bill-acceptor", "MAX_DENOMINATION", "malformed denomination"); + GNUNET_free(denomination_value); global_ret = EXIT_FAILURE; return; } + GNUNET_free(denomination_value); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "bill-acceptor", @@ -430,11 +534,12 @@ run (void *cls, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "bill-acceptor", "MIN_DENOMINATION"); + GNUNET_free(denomination_value); global_ret = EXIT_FAILURE; return; } if (GNUNET_OK != - TALER_join_strings_to_amount(cfg_currency, + join_strings_to_amount(cfg_currency, denomination_value, &cfg_ba_min_denomination)) { @@ -442,9 +547,11 @@ run (void *cls, "bill-acceptor", "MIN_DENOMINATION", "malformed denomination"); + GNUNET_free(denomination_value); global_ret = EXIT_FAILURE; return; } + GNUNET_free(denomination_value); } if(GNUNET_OK != cfg_ca_enable) { @@ -462,11 +569,12 @@ run (void *cls, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "coin-acceptor", "MAX_DENOMINATION"); + GNUNET_free(denomination_value); global_ret = EXIT_FAILURE; return; } if (GNUNET_OK != - TALER_join_strings_to_amount(cfg_currency, + join_strings_to_amount(cfg_currency, denomination_value, &cfg_ca_max_denomination)) { @@ -474,6 +582,7 @@ run (void *cls, "coin-acceptor", "MAX_DENOMINATION", "malformed denomination"); + GNUNET_free(denomination_value); global_ret = EXIT_FAILURE; return; } @@ -486,11 +595,12 @@ run (void *cls, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "coin-acceptor", "MIN_DENOMINATION"); + GNUNET_free(denomination_value); global_ret = EXIT_FAILURE; return; } if (GNUNET_OK != - TALER_join_strings_to_amount(cfg_currency, + join_strings_to_amount(cfg_currency, denomination_value, &cfg_ca_min_denomination)) { @@ -498,9 +608,11 @@ run (void *cls, "coin-acceptor", "MIN_DENOMINATION", "malformed denomination"); + GNUNET_free(denomination_value); global_ret = EXIT_FAILURE; return; } + GNUNET_free(denomination_value); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "coin-acceptor", @@ -539,10 +651,13 @@ run (void *cls, } } + //Screen INIT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Config URL: %s\n", - cfg_backend_base_url); + //Touch INIT + + //BA Init + + //CA Init curl_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, &reschedule_ctx); @@ -550,12 +665,78 @@ run (void *cls, GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); - + get_config_handle = TALER_BANK_get_config (curl_ctx, - cfg_backend_base_url, + cfg_bank_base_url, &on_get_config_done, NULL); +} + +/** + * + */ +static void TerminalError_state_task(void *cls) +{ + (void)cls; + TALER_LOG_DEBUG ("start TerminalErroe state task\n"); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown(); +} + +/** + * + */ +static void state_controller_task(void *cls) +{ + struct GNUNET_CONFIGURATION_Handle *cfg = cls; + + switch (state) + { + case DIGITIZER_STATE_INIT: + { + GNUNET_SCHEDULER_add_now(Init_state_task,cfg); + return; + } + case DIGITIZER_STATE_TERMINAL_ERROR: + { + GNUNET_SCHEDULER_add_now(TerminalError_state_task,NULL); + return; + } + default: + { + TALER_LOG_ERROR("Gost-State in state machine\n"); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + } + + } +} + + +/** + * @brief Start the application + * + * @param cls closure + * @param args arguments left + * @param cfgfile config file name + * @param cfg handle for the configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + (void) cls; + (void) args; + (void) cfgfile; + + state = DIGITIZER_STATE_INIT; + state_ctx = GNUNET_new(struct DIGITIZER_StateContext); + display_ctx = GNUNET_new(struct DIGITIZER_DisplayContext); + + GNUNET_SCHEDULER_add_now(state_controller_task,(void *) cfg); return; } diff --git a/src/taler/taler_digitizer_service.h b/src/taler/taler_digitizer_service.h @@ -82,6 +82,22 @@ enum TALER_BANK_VersionCompatibility }; +/** + * Bank has runs with the same currency as the Digitizer. + */ +enum TALLER_BANK_CurrencyCompatibility +{ + /** + * They have the same currency + */ + TALER_BANK_CC_MATCH = 0, + + /** + * They are not the same currency + */ + TALER_BANK_CC_MISSMATCH = 1, +}; + /** * General information about the HTTP response we obtained diff --git a/taler-digitizer.conf b/taler-digitizer.conf @@ -12,6 +12,7 @@ USER_WITHDRAWAL_PERIOD = 10 KYC_FUNCTIONALITY = NO +EXCHANGE_BASE_URL = https://exchange.demo.taler.net/ # Name of the framebuffer to use for the QR code. FRAMEBUFFER_DEVICE = /dev/fb1