diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-12-10 15:24:39 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-12-10 15:24:39 +0100 |
commit | 742ae057b9ad85644a1c6621f92e9b710d416beb (patch) | |
tree | f8c41f715047d0c87ddca80fc80b52cbd8284848 /src/qr-show.c | |
parent | 8841dfec1ad670fc584fd5d47c1f157108888976 (diff) | |
download | taler-mdb-742ae057b9ad85644a1c6621f92e9b710d416beb.tar.gz taler-mdb-742ae057b9ad85644a1c6621f92e9b710d416beb.tar.bz2 taler-mdb-742ae057b9ad85644a1c6621f92e9b710d416beb.zip |
implement process to just show QR code for some time
Diffstat (limited to 'src/qr-show.c')
-rw-r--r-- | src/qr-show.c | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/src/qr-show.c b/src/qr-show.c new file mode 100644 index 0000000..c96dab1 --- /dev/null +++ b/src/qr-show.c @@ -0,0 +1,425 @@ +/* + 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 qr-show.c +* @brief shows a QR code on the display for a defined amount of time +* @author Boss Marco +* @author Christian Grothoff +*/ +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#if HAVE_SYS_UN_H +#include <sys/un.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_NETINET_IP_H +#include <netinet/ip.h> /* superset of previous */ +#endif +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> +#include <termios.h> +#include <nfc/nfc.h> +#include <microhttpd.h> +#include <gnunet/gnunet_util_lib.h> +#include <qrencode.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <fcntl.h> +/* for adafruit pitft display */ +#include <linux/fb.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; + +/** + * Refenence 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; + +static int backlight_invert; +static char backlight_on = '1'; +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; + + 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); + unsigned int 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 originial display state\n"); + } + /* close device */ + close (qrDisplay.devicefd); + qrDisplay.devicefd = -1; + if (0 < qrDisplay.backlightfd) + 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 configuation 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-mdb", + "FRAMEBUFFER_DEVICE", + &framebuffer_device_filename)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "taler-mdb", + "FRAMEBUFFER_DEVICE"); + framebuffer_device_filename = GNUNET_strdup ("/dev/fb1"); + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "taler-mdb", + "FRAMEBUFFER_BACKLIGHT", + &framebuffer_backlight_filename)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "taler-mdb", + "FRAMEBUFFER_BACKLIGHT"); + framebuffer_backlight_filename = GNUNET_strdup ( + "/sys/class/backlight/soc: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 text before continuing", + &delay), + GNUNET_GETOPT_OPTION_END + }; + + ret = GNUNET_PROGRAM_run (argc, + argv, + "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; +} |