cash2ecash

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

show-qr.c (8238B)


      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  * @brief coppied/edited from taler-mdb
     22  */
     23 
     24 #include <stdio.h>
     25 #include <sys/ioctl.h>
     26 #include <gnunet/gnunet_util_lib.h>
     27 #include <linux/fb.h>
     28 #include <sys/mman.h>
     29 #include <errno.h>
     30 #include <fcntl.h>
     31 #include <qrencode.h>
     32 
     33 #define BACKLIGHT_INVERTER false
     34 
     35 /**
     36  * Standard backlight on value
     37  */
     38 static char backlight_on;
     39 
     40 /**
     41  * Standard backlight off value
     42  */
     43 static char backlight_off;
     44 
     45 /**
     46  * Handle for the Framebuffer device
     47  */
     48 struct Display
     49 {
     50   /**
     51    * File descriptor for the screen
     52    */
     53   int devicefd;
     54 
     55   /**
     56    * File descriptor to set backlight information
     57    */
     58   int backlightfd;
     59 
     60   /**
     61    * The display memory to set the pixel information
     62    */
     63   uint16_t *memory;
     64 
     65   /**
     66    * Original screen information
     67    */
     68   struct fb_var_screeninfo orig_vinfo;
     69 
     70   /**
     71    * Variable screen information (color depth ...)
     72    */
     73   struct fb_var_screeninfo var_info;
     74 
     75   /**
     76    * Fixed screen informtaion
     77    */
     78   struct fb_fix_screeninfo fix_info;
     79 };
     80 
     81 void show_qr_init(struct Display *dp ,char *fb_device_file, char *backlight_device_file)
     82 {
     83 
     84 /* open the framebuffer device */
     85   dp->devicefd = open (fb_device_file,
     86                              O_RDWR);
     87   if (-1 != dp->devicefd)
     88   {
     89     /* read information about the screen */
     90     ioctl (dp->devicefd,
     91            FBIOGET_VSCREENINFO,
     92            &dp->var_info);
     93 
     94     /* store current screeninfo for reset */
     95     dp->orig_vinfo = dp->var_info;
     96 
     97     if (16 != dp->var_info.bits_per_pixel)
     98     {
     99       /* Change variable info to 16 bit per pixel */
    100       dp->var_info.bits_per_pixel = 16;
    101       if (0 > ioctl (dp->devicefd,
    102                      FBIOPUT_VSCREENINFO,
    103                      &dp->var_info))
    104       {
    105         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,"ioctl(FBIOPUT_VSCREENINFO)");
    106         return;
    107       }
    108     }
    109 
    110     /* Get fixed screen information */
    111     if (0 > ioctl (dp->devicefd,
    112                    FBIOGET_FSCREENINFO,
    113                    &dp->fix_info))
    114     {
    115       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    116                            "ioctl(FBIOGET_FSCREENINFO)");
    117       return;
    118     }
    119 
    120     /* get pointer onto frame buffer */
    121     dp->memory = mmap (NULL,
    122                              dp->fix_info.smem_len,
    123                              PROT_READ | PROT_WRITE, MAP_SHARED,
    124                              dp->devicefd,
    125                              0);
    126     if (MAP_FAILED == dp->memory)
    127     {
    128       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    129                            "mmap");
    130       return;
    131     }
    132 
    133     /* set the screen to white */
    134     memset (dp->memory,
    135             0xFF,
    136             dp->var_info.xres * dp->var_info.yres
    137             * sizeof (uint16_t));
    138 
    139     /* open backlight file to turn display backlight on and off */
    140     dp->backlightfd = open (
    141       backlight_device_file, O_WRONLY);
    142     if (0 > dp->backlightfd)
    143     {
    144       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    145                                 "open",
    146                                 backlight_device_file);
    147     }
    148     else
    149     {
    150       if (BACKLIGHT_INVERTER)
    151       {
    152         backlight_on = '0';
    153         backlight_off = '1';
    154       }
    155       else
    156       {
    157         backlight_off = '0';
    158         backlight_on = '1';
    159       }
    160       /* turn off the backlight */
    161       (void) ! write (dp->backlightfd,
    162                       &backlight_off,
    163                       1);
    164       }
    165    }
    166    else
    167    {
    168     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    169                             "open",
    170                             fb_device_file);
    171    } 
    172 };
    173 
    174 /**
    175  * @brief Create the QR code to pay and display it on screen
    176  *
    177  * @param uri what text to show in the QR code
    178  */
    179 static void
    180 show_qrcode (const char *uri)
    181 {
    182   QRinput *qri;
    183   QRcode *qrc;
    184   unsigned int size;
    185   char *upper;
    186   char *base;
    187   char *ubase;
    188   size_t xOff;
    189   size_t yOff;
    190   const char *dddash;
    191   unsigned int nwidth;
    192 
    193   stop_advertising ();
    194   hide_error ();
    195   if (0 > qrDisplay.devicefd)
    196     return; /* no display, no dice */
    197   /* find the fourth '/' in the payto://pay/hostname/-uri */
    198   dddash = strchr (uri, '/');
    199   if (NULL != dddash)
    200     dddash = strchr (dddash + 1, '/');
    201   if (NULL != dddash)
    202     dddash = strchr (dddash + 1, '/');
    203   if (NULL != dddash)
    204     dddash = strchr (dddash + 1, '/');
    205   if (NULL == dddash)
    206   {
    207     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    208                 "taler://pay/-URI malformed: `%s'\n",
    209                 uri);
    210     return;
    211   }
    212 
    213   qri = QRinput_new2 (0, QR_ECLEVEL_L);
    214   if (NULL == qri)
    215   {
    216     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    217                          "QRinput_new2");
    218     return;
    219   }
    220   /* convert all characters until the fourth '/' to upper
    221      case. The rest _should_ be upper case in a NICE setup,
    222      but we can't warrant it and must not touch those. */
    223   base = GNUNET_strndup (uri,
    224                          dddash - uri);
    225 
    226   ubase = GNUNET_STRINGS_utf8_toupper (base);
    227   GNUNET_free (base);
    228   GNUNET_asprintf (&upper,
    229                    "%s%s",
    230                    ubase,
    231                    dddash);
    232   GNUNET_free (ubase);
    233   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    234               "Showing QR code for `%s'\n",
    235               upper);
    236   /* first try encoding as uppercase-only alpha-numerical
    237      QR code (much smaller encoding); if that fails, also
    238      try using binary encoding (in case nick contains
    239      special characters). */
    240   if ( (0 !=
    241         QRinput_append (qri,
    242                         QR_MODE_AN,
    243                         strlen (upper),
    244                         (unsigned char *) upper)) &&
    245        (0 !=
    246         QRinput_append (qri,
    247                         QR_MODE_8,
    248                         strlen (upper),
    249                         (unsigned char *) upper)))
    250   {
    251     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    252                          "QRinput_append");
    253     GNUNET_free (upper);
    254     return;
    255   }
    256   GNUNET_free (upper);
    257   qrc = QRcode_encodeInput (qri);
    258   if (NULL == qrc)
    259   {
    260     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    261                          "QRcode_encodeInput");
    262     QRinput_free (qri);
    263     return;
    264   }
    265 
    266   /* set QR-code border */
    267   memset (qrDisplay.memory,
    268           0xFF,
    269           qrDisplay.var_info.xres * qrDisplay.var_info.yres
    270           * sizeof (uint16_t));
    271   size = GNUNET_MIN (qrDisplay.var_info.xres,
    272                      qrDisplay.var_info.yres);
    273 
    274   nwidth = qrc->width + 8; /* +8 for 4 pixel border */
    275   xOff = 4 * size / nwidth;
    276   yOff = 4 * size / nwidth;
    277 
    278   /* calculate offset to show the code centered */
    279   if (qrDisplay.var_info.xres < qrDisplay.var_info.yres)
    280     yOff += (qrDisplay.var_info.yres - qrDisplay.var_info.xres) / 2;
    281   else
    282     xOff += (qrDisplay.var_info.xres - qrDisplay.var_info.yres) / 2;
    283   for (unsigned int x = 0; x < qrDisplay.var_info.xres - 2 * xOff; x++)
    284     for (unsigned int y = 0; y < qrDisplay.var_info.yres - 2 * yOff; y++)
    285     {
    286       unsigned int xoff = x * nwidth / size;
    287       unsigned int yoff = y * nwidth / size;
    288       unsigned int off = xoff + yoff * qrc->width;
    289       if ( (xoff >= (unsigned) qrc->width) ||
    290            (yoff >= (unsigned) qrc->width) )
    291         continue;
    292       /* set the pixels in the display memory */
    293       qrDisplay.memory[(y + yOff) * qrDisplay.var_info.xres + (x + xOff)] =
    294         (0 == (qrc->data[off] & 1)) ? 0xFFFF : 0x0000;
    295     }
    296 
    297   QRcode_free (qrc);
    298   QRinput_free (qri);
    299 
    300   /* Turn on backlight if supported */
    301   if (0 < qrDisplay.backlightfd)
    302     (void) ! write (qrDisplay.backlightfd,
    303                     &backlight_on,
    304                     1);
    305 }