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:
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