commit f6533b68a9fc14936fa9f892b2fad47231febfe7
parent 285b884edfab8d63d9fd8ffd5a2118a9c3728ae0
Author: Tellenbach Reto <tellr1@bfh.ch>
Date: Tue, 2 Jun 2026 16:03:25 +0200
[new] thinker_QRCode: draft show qrcode
Diffstat:
8 files changed, 603 insertions(+), 21 deletions(-)
diff --git a/README.md b/README.md
@@ -4,6 +4,24 @@ This software is meant for use on a system which is designed, to allow users to
**Note:
This software is currently under developpement. Do not attempt to use it on a system with real customers!**
+# Config
+Get a Token for the bank account which transfers money to the User.
+The following example is with the demo bank to get a valid token for one day (86400000000 qs).
+One has to write its own username and password from the demobank account https://bank.demo.taler.net/webui/ instead of `$USERNAME` and `$PASSWORD`.
+```
+curl -X POST https://bank.demo.taler.net/$USERNAME/bank_acc_tellr/token \\
+ -H "Content-Type: application/json" \
+ -H "Authorization: Basic $(echo -n '$USERNAME:$PASSWORD' | base64)" \
+ -d '{
+ "scope": "readwrite",
+ "duration": { "d_us": 86400000000 },
+ "refreshable": false,
+ "description": "test token"
+ }'
+```
+The recived token is the token for the config.
+The token has an expiration date and needs to be renewed.
+
# Building
`export TALER_DIGITIZER_PREFIX=<installation_path>`
\ No newline at end of file
diff --git a/src/taler-digitizer.c b/src/taler-digitizer.c
@@ -31,7 +31,7 @@
/**
* Time unit for PERSON_WITHDRAL_PERIOD config.
- * Normal in Days but can be changed for testing
+ * Normaly in Days but, can be changed for testing
*/
#define DIGITIZER_PERSON_WITHDRAWL_PERIOD_TIME_UNIT GNUNET_TIME_UNIT_DAYS
@@ -63,12 +63,12 @@ static unsigned long long cfg_backend_min_balance;
/**
* Per-person withdrawal limit read from configuration file
*/
-static unsigned long long cfg_person_withdrawllimit;
+static unsigned long long cfg_user_withdrawllimit;
/**
* Per-person withdrawal period read from configuration file
*/
-static struct GNUNET_TIME_Relative cfg_person_withdrawl_period;
+static struct GNUNET_TIME_Relative cfg_user_withdrawl_period;
/**
* KYC functionality flag read from configuration file
@@ -91,6 +91,11 @@ static struct GNUNET_CURL_RescheduleContext *reschedule_ctx;
static struct TALER_BANK_GetConfigHandle *get_config_handle;
+static enum DIGITIZER_
+
+typedef void (*DIGITIZER_State)(enum)
+
+
static void
on_config_received (void *cls,
const struct TALER_BANK_ConfigResponse *vr)
@@ -195,32 +200,32 @@ run (void *cls,
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (cfg,
"taler-digitizer",
- "PERSON_WITHDRAWLLIMIT",
- &cfg_person_withdrawllimit))
+ "USER_WITHDRAWLLIMIT",
+ &cfg_user_withdrawllimit))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"taler-digitizer",
- "PERSON_WITHDRAWLLIMIT");
+ "USER_WITHDRAWLLIMIT");
global_ret = EXIT_FAILURE;
return;
}
- unsigned long long person_withdrawl_period_number;
+ unsigned long long user_withdrawl_period_number;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (cfg,
"taler-digitizer",
- "PERSON_WITHDRAL_PERIOD",
- &person_withdrawl_period_number))
+ "USER_WITHDRAL_PERIOD",
+ &user_withdrawl_period_number))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"taler-digitizer",
- "PERSON_WITHDRAL_PERIOD");
+ "USER_WITHDRAL_PERIOD");
global_ret = EXIT_FAILURE;
return;
}
- cfg_person_withdrawl_period = GNUNET_TIME_relative_multiply (
+ cfg_user_withdrawl_period = GNUNET_TIME_relative_multiply (
DIGITIZER_PERSON_WITHDRAWL_PERIOD_TIME_UNIT,
- person_withdrawl_period_number);
+ user_withdrawl_period_number);
cfg_kyc_functionality = GNUNET_CONFIGURATION_get_value_yesno (cfg,
"taler-digitizer",
diff --git a/taler-digitizer.conf b/taler-digitizer.conf
@@ -1,16 +1,14 @@
[taler-digitizer]
-BACKEND_BASE_URL = https://exchange.demo.taler.net/
+BACKEND_BASE_URL = https://bank.demo.taler.net/
CURRENCY = KUDOS
-#BANK_ACCOUNT = sdflksdflsdkjf
-
-# Balance required to start a Transaction
-BANK_MIN_BALANCE = 1000
+BANK_ACCOUNT = bank_acc_tellr
+BANK_TOKEN = 4NA4S6GKGCRBB65M99QKPKD29K2HTRBDZRJYTTVZ0K6QEYBQPHH0
# Withdrawl limitation per person, for a limited time period.
# This can only be enforced with KYC functionality
-PERSON_WITHDRAWLLIMIT = 200
-PERSON_WITHDRAL_PERIOD = 10
+USER_WITHDRAWLLIMIT = 200
+USER_WITHDRAL_PERIOD = 10
#BACKEND_AUTHORIZATION = Bearer secret-token:sandbox
@@ -26,9 +24,11 @@ FRAMEBUFFER_BACKLIGHT = /sys/class/backlight/soc:backlight/brightness
ENABLE = YES
GPIO_CHIP = /dev/gpiochip0
GPIO_PIN = 16
-bigest_denomination = 5
+MAX_DENOMINATION = 5
+MIN_DENOMINATION = 0.1
[bill-acceptor]
ENABLE = NO
-bigest_denomination = 100
+MAX_DENOMINATION = 100
+MIN_DENOMINATION = 10
diff --git a/thinker/qr_code/CMakeLists.txt b/thinker/qr_code/CMakeLists.txt
@@ -0,0 +1,17 @@
+#Project Config
+cmake_minimum_required(VERSION 3.13)
+project(QRshow LANGUAGES C )
+
+#Compiler Settings
+set(CMAKE_C_STANDARD 17)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_C_EXTENSIONS ON)
+
+# Librarys
+## Defining Librarys
+##add_library(gpiod gpiod_wrapper.c)
+add_executable(QRshow taler-mdb-qr-show.c)
+
+## Linking Targets
+target_link_libraries(QRshow PUBLIC gnunetutil talerutil
+ PRIVATE qrencode)
diff --git a/thinker/qr_code/CMakePresets.json b/thinker/qr_code/CMakePresets.json
@@ -0,0 +1,14 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "debug",
+ "binaryDir": "${sourceDir}/build/debug",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Debug",
+ "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
+ "CMAKE_C_FLAGS": "-Wall -Wextra -g"
+ }
+ }
+ ]
+}
+\ No newline at end of file
diff --git a/thinker/qr_code/taler-digitizer.conf b/thinker/qr_code/taler-digitizer.conf
@@ -0,0 +1,34 @@
+[taler-digitizer]
+BACKEND_BASE_URL = https://exchange.demo.taler.net/
+CURRENCY = KUDOS
+
+#BANK_ACCOUNT = sdflksdflsdkjf
+
+# Balance required to start a Transaction
+BANK_MIN_BALANCE = 1000
+
+# Withdrawl limitation per person, for a limited time period.
+# This can only be enforced with KYC functionality
+PERSON_WITHDRAWLLIMIT = 200
+PERSON_WITHDRAL_PERIOD = 10
+
+
+#BACKEND_AUTHORIZATION = Bearer secret-token:sandbox
+KYC_FUNCTIONALITY = NO
+
+# Name of the framebuffer to use for the QR code.
+FRAMEBUFFER_DEVICE = /dev/fb0
+
+# Name of the backlight file for the framebuffer
+FRAMEBUFFER_BACKLIGHT = /sys/class/backlight/10-0045/brightness
+
+[coin-acceptor]
+ENABLE = YES
+GPIO_CHIP = /dev/gpiochip0
+GPIO_PIN = 16
+bigest_denomination = 5
+
+
+[bill-acceptor]
+ENABLE = NO
+bigest_denomination = 100
diff --git a/thinker/qr_code/taler-mdb-qr-show.c b/thinker/qr_code/taler-mdb-qr-show.c
@@ -0,0 +1,437 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2019 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more
+details.
+
+ You should have received a copy of the GNU General Public License
+along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+* @file taler-mdb-qr-show.c
+* @brief shows a QR code on the display for a defined amount of time
+* @author Boss Marco
+* @author Christian Grothoff
+*/
+
+#include <errno.h>
+#include <qrencode.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <linux/fb.h>
+#include "taler_digitizer_util.h"
+
+
+/**
+ * Disable i18n support.
+ */
+#define _(s) (s)
+
+/**
+ * Handle for the Framebuffer device
+ */
+struct Display
+{
+ /**
+ * File descriptor for the screen
+ */
+ int devicefd;
+
+ /**
+ * File descriptor to set backlight information
+ */
+ int backlightfd;
+
+ /**
+ * The display memory to set the pixel information
+ */
+ uint16_t *memory;
+
+ /**
+ * Original screen information
+ */
+ struct fb_var_screeninfo orig_vinfo;
+
+ /**
+ * Variable screen information (color depth ...)
+ */
+ struct fb_var_screeninfo var_info;
+
+ /**
+ * Fixed screen informtaion
+ */
+ struct fb_fix_screeninfo fix_info;
+};
+
+
+/**
+ * Next program to launch.
+ */
+static char *const *arg_next;
+
+static struct GNUNET_TIME_Relative delay;
+
+/**
+ * Reference to the delay task
+ */
+static struct GNUNET_SCHEDULER_Task *delay_task;
+
+/**
+ * Name of the framebuffer device (i.e. /dev/fb1).
+ */
+static char *framebuffer_device_filename;
+
+/**
+ * Name of the backlight file of @e framebuffer_device_filename (i.e. /sys/class/backlight/soc:backlight/brightness).
+ */
+static char *framebuffer_backlight_filename;
+
+/**
+ * Global option '-i' to invert backlight on/off values
+ */
+static int backlight_invert;
+
+/**
+ * Standard backlight on value
+ */
+static char backlight_on = '1';
+
+/**
+ * Standard backlight off value
+ */
+static char backlight_off = '0';
+
+/**
+ * Handle for the framebuffer device
+ */
+static struct Display qrDisplay;
+
+
+/**
+ * @brief Create the QR code to pay and display it on screen
+ *
+ * @param uri what text to show in the QR code
+ */
+static void
+show_qrcode (const char *uri)
+{
+ QRinput *qri;
+ QRcode *qrc;
+ unsigned int size;
+ size_t xOff;
+ size_t yOff;
+ unsigned int nwidth;
+
+ if (0 > qrDisplay.devicefd)
+ return; /* no display, no dice */
+ qri = QRinput_new2 (0, QR_ECLEVEL_L);
+ if (NULL == qri)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "QRinput_new2");
+ return;
+ }
+ /* first try encoding as uppercase-only alpha-numerical
+ QR code (much smaller encoding); if that fails, also
+ try using binary encoding (in case nick contains
+ special characters). */
+ if ( (0 !=
+ QRinput_append (qri,
+ QR_MODE_AN,
+ strlen (uri),
+ (unsigned char *) uri)) &&
+ (0 !=
+ QRinput_append (qri,
+ QR_MODE_8,
+ strlen (uri),
+ (unsigned char *) uri)))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "QRinput_append");
+ return;
+ }
+ qrc = QRcode_encodeInput (qri);
+ if (NULL == qrc)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "QRcode_encodeInput");
+ QRinput_free (qri);
+ return;
+ }
+
+ /* +8 for 4-pixels border */
+ size = GNUNET_MIN (qrDisplay.var_info.xres,
+ qrDisplay.var_info.yres);
+ nwidth = qrc->width + 8; /* 4 pixel border */
+ xOff = 4 * size / nwidth;
+ yOff = 4 * size / nwidth;
+ if (qrDisplay.var_info.xres < qrDisplay.var_info.yres)
+ yOff += (qrDisplay.var_info.yres - qrDisplay.var_info.xres) / 2;
+ else
+ xOff += (qrDisplay.var_info.xres - qrDisplay.var_info.yres) / 2;
+ for (unsigned int x = 0; x < qrDisplay.var_info.xres - 2 * xOff; x++)
+ for (unsigned int y = 0; y < qrDisplay.var_info.yres - 2 * yOff; y++)
+ {
+ unsigned int xoff = x * nwidth / size;
+ unsigned int yoff = y * nwidth / size;
+ unsigned int off = xoff + yoff * qrc->width;
+ if ( (xoff >= (unsigned) qrc->width) ||
+ (yoff >= (unsigned) qrc->width) )
+ continue;
+ qrDisplay.memory[(y + yOff) * qrDisplay.var_info.xres + (x + xOff)] =
+ (0 == (qrc->data[off] & 1)) ? 0xFFFF : 0x0000;
+ }
+
+ QRcode_free (qrc);
+ QRinput_free (qri);
+
+ if (0 < qrDisplay.backlightfd)
+ (void) ! write (qrDisplay.backlightfd,
+ &backlight_on,
+ 1);
+}
+
+
+static void
+stop_task (void *cls)
+{
+ (void) cls;
+ delay_task = NULL;
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+static void
+shutdown_task (void *cls)
+{
+ (void) cls;
+ if (NULL != delay_task)
+ {
+ GNUNET_SCHEDULER_cancel (delay_task);
+ delay_task = NULL;
+ }
+ if (NULL != qrDisplay.memory)
+ memset (qrDisplay.memory,
+ 0xFF,
+ qrDisplay.var_info.xres
+ * qrDisplay.var_info.yres
+ * sizeof (uint16_t));
+ if (0 < qrDisplay.backlightfd)
+ (void) ! write (qrDisplay.backlightfd,
+ &backlight_off,
+ 1);
+ if (NULL != qrDisplay.memory)
+ {
+ /* free the display data */
+ munmap (qrDisplay.memory,
+ qrDisplay.fix_info.smem_len);
+ qrDisplay.memory = NULL;
+ /* reset original state */
+ if (0 > ioctl (qrDisplay.devicefd,
+ FBIOPUT_VSCREENINFO,
+ &qrDisplay.orig_vinfo))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "failed to reset original display state\n");
+ }
+ /* close device */
+ GNUNET_break (0 == close (qrDisplay.devicefd));
+ qrDisplay.devicefd = -1;
+ if (0 < qrDisplay.backlightfd)
+ GNUNET_break (0 == close (qrDisplay.backlightfd));
+ qrDisplay.backlightfd = -1;
+ }
+}
+
+
+/**
+ * @brief Start the application
+ *
+ * @param cls closure
+ * @param args arguments left
+ * @param cfgfile config file name
+ * @param cfg handle for the configuration file
+ */
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ (void) cls;
+ (void) cfgfile;
+
+ if (NULL == args[0])
+ return;
+ arg_next = args + 1;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (
+ cfg,
+ "taler-digitizer",
+ "FRAMEBUFFER_DEVICE",
+ &framebuffer_device_filename))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "taler-digitizer",
+ "FRAMEBUFFER_DEVICE");
+ framebuffer_device_filename = GNUNET_strdup ("/dev/fb1");
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (
+ cfg,
+ "taler-digitizer",
+ "FRAMEBUFFER_BACKLIGHT",
+ &framebuffer_backlight_filename))
+ {
+ GNUNET_log_config_missing (
+ GNUNET_ERROR_TYPE_ERROR,
+ "taler-digitizer",
+ "FRAMEBUFFER_BACKLIGHT");
+ framebuffer_backlight_filename = GNUNET_strdup (
+ "/sys/class/backlight/*/brightness");
+ }
+ /* open the framebuffer device */
+ qrDisplay.devicefd = open (framebuffer_device_filename,
+ O_RDWR);
+ if (0 < qrDisplay.devicefd)
+ {
+ /* read information about the screen */
+ ioctl (qrDisplay.devicefd,
+ FBIOGET_VSCREENINFO,
+ &qrDisplay.var_info);
+
+ /* store current screeninfo for reset */
+ qrDisplay.orig_vinfo = qrDisplay.var_info;
+
+ if (16 != qrDisplay.var_info.bits_per_pixel)
+ {
+ /* Change variable info to 16 bit per pixel */
+ qrDisplay.var_info.bits_per_pixel = 16;
+ if (0 > ioctl (qrDisplay.devicefd,
+ FBIOPUT_VSCREENINFO,
+ &qrDisplay.var_info))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "ioctl(FBIOPUT_VSCREENINFO)");
+ return;
+ }
+ }
+
+ /* Get fixed screen information */
+ if (0 > ioctl (qrDisplay.devicefd,
+ FBIOGET_FSCREENINFO,
+ &qrDisplay.fix_info))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "ioctl(FBIOGET_FSCREENINFO)");
+ return;
+ }
+
+ /* get pointer onto frame buffer */
+ qrDisplay.memory
+ = mmap (NULL,
+ qrDisplay.fix_info.smem_len,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ qrDisplay.devicefd,
+ 0);
+
+ /* open backlight file to turn display backlight on and off */
+ if (0 > qrDisplay.devicefd)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "mmap");
+ return;
+ }
+
+ memset (qrDisplay.memory,
+ 0xFF,
+ qrDisplay.var_info.xres * qrDisplay.var_info.yres
+ * sizeof (uint16_t));
+
+ qrDisplay.backlightfd = open (
+ framebuffer_backlight_filename, O_WRONLY);
+ if (0 > qrDisplay.backlightfd)
+ {
+ GNUNET_log_strerror_file (
+ GNUNET_ERROR_TYPE_WARNING,
+ "open",
+ framebuffer_backlight_filename);
+ }
+ else
+ {
+ if (backlight_invert)
+ {
+ backlight_on = '0';
+ backlight_off = '1';
+ }
+ (void) ! write (qrDisplay.backlightfd,
+ &backlight_off,
+ 1);
+ }
+ }
+ else
+ {
+ GNUNET_log_strerror_file (
+ GNUNET_ERROR_TYPE_WARNING,
+ "open",
+ framebuffer_device_filename);
+ }
+ GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+ NULL);
+ show_qrcode (args[0]);
+ delay_task = GNUNET_SCHEDULER_add_delayed (delay,
+ &stop_task,
+ NULL);
+}
+
+
+int
+main (int argc,
+ char*const*argv)
+{
+ int ret;
+ /* the available command line options */
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_option_relative_time ('d',
+ "delay",
+ "DELAY",
+ "how long should we display the QR code before exiting",
+ &delay),
+ GNUNET_GETOPT_option_flag ('i',
+ "backlight-invert",
+ "invert the backlight on/off values (standard on = 1)",
+ &backlight_invert),
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ ret = GNUNET_PROGRAM_run (TALER_DIGITIZER_project_data (),
+ argc,
+ argv,
+ "taler-digitizer-qr-show",
+ "This is an application to show a QR code for a defined period of time before starting another program.\n",
+ options,
+ &run,
+ NULL);
+ if (GNUNET_OK != ret)
+ return 1;
+ if ( (NULL == arg_next) ||
+ (NULL == arg_next[0]) )
+ return 0;
+ execvp (arg_next[0],
+ arg_next);
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "execvp",
+ arg_next[0]);
+ return 1;
+}
diff --git a/thinker/qr_code/taler_digitizer_util.h b/thinker/qr_code/taler_digitizer_util.h
@@ -0,0 +1,56 @@
+/*
+ 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 taler-digitizer_util.h
+ * @brief Interface for common utility functions, and base project settings
+ * @author Reto Tellenbach
+ */
+#ifndef TALER_DIGITIZER_UTIL_H
+#define TALER_DIGITIZER_UTIL_H
+
+#include <gnunet/gnunet_util_lib.h>
+
+/**
+ * Default project data. When shipping use a seperate os_installation.c which sets values at installation.
+ */
+static const struct GNUNET_OS_ProjectData digitizer_pd = {
+ .base_config_varname = "TALER_DIGITIZER_PREFIX",
+ .bug_email = "taler@lists.gnu.org",
+ .homepage = "http://www.gnu.org/s/taler/",
+ .config_file = "taler-digitizer.conf",
+ .user_config_file = "~/.config/taler-digitizer.conf",
+ .version = "0.1.0",
+ .is_gnu = 0,
+ .gettext_domain = NULL,
+ .gettext_path = NULL,
+};
+
+/**
+ * Return default project data.
+ */
+const struct GNUNET_OS_ProjectData *
+TALER_DIGITIZER_project_data (void)
+{
+ return &digitizer_pd;
+}
+
+
+
+#endif