This patch is only a proof of concept but links in QR encode and renders
the URLs for stderror.c to the console for a smartphone to scan for
additional context.

A few considerations:
  Additional Memory requirements
  License for the library
  Readability from non-console screens
  stability
  Dynamic memory requirements (malloc) for the library
  memory optimizations in the library - bit array instead of bytes?

I don't warent that this is production ready, but mearly trying to show
that this could provide additional value.

-Jim
From cfe6fca6748d1abaf57c6456c9eacfbe94807ec2 Mon Sep 17 00:00:00 2001
From: Jim Hanley <[email protected]>
Date: Wed, 8 Jan 2020 16:15:26 -0500
Subject: [PATCH] Added QR Code for bootup to easy scan errors from console.

---
 .gitmodules           |   3 +
 src/Makefile          |   4 +-
 src/hci/strerror.c    |  28 ++++++---
 src/hci/urlqrencode.c | 132 ++++++++++++++++++++++++++++++++++++++++++
 src/libqrencode       |   1 +
 5 files changed, 160 insertions(+), 8 deletions(-)
 create mode 100644 .gitmodules
 create mode 100644 src/hci/urlqrencode.c
 create mode 160000 src/libqrencode

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..330e39d6
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "src/libqrencode"]
+	path = src/libqrencode
+	url = https://github.com/fukuchi/libqrencode.git
diff --git a/src/Makefile b/src/Makefile
index c0bc45fa..dc96d8e9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -4,7 +4,7 @@
 #
 
 CLEANUP		:=
-CFLAGS		:=
+CFLAGS		:= -DHAVE_CONFIG_H
 ASFLAGS		:=
 LDFLAGS		:=
 HOST_CFLAGS	:=
@@ -100,6 +100,7 @@ SRCDIRS		+= hci/mucurses hci/mucurses/widgets
 SRCDIRS		+= hci/keymap
 SRCDIRS		+= usr
 SRCDIRS		+= config
+SRCDIRS		+= libqrencode
 
 # These directories contain code that is not eligible for UEFI Secure
 # Boot signing.
@@ -117,6 +118,7 @@ SRCDIRS_INSEC	+= drivers/net/ath/ath9k
 NON_AUTO_SRCS	:=
 NON_AUTO_SRCS	+= core/version.c
 NON_AUTO_SRCS	+= drivers/net/prism2.c
+NON_AUTO_SRCS	+= libqrencode/qrenc.c
 
 # INCDIRS lists the include path
 #
diff --git a/src/hci/strerror.c b/src/hci/strerror.c
index 1bba8c62..d147ad70 100644
--- a/src/hci/strerror.c
+++ b/src/hci/strerror.c
@@ -21,6 +21,8 @@
 
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
+int uriqrencode(const char * URI, char *outbuff, size_t outbuff_sz);
+
 /**
  * Find error description
  *
@@ -76,7 +78,13 @@ static struct errortab * find_closest_error ( int errno ) {
  *
  */
 char * strerror ( int errno ) {
-	static char errbuf[64];
+	#define SQUARE 46
+
+	static char errbuf[(((SQUARE/2)+1)*SQUARE)];
+//	static char errbuf[64];
+	char errURL[32];
+	int offset = 0;
+
 	struct errortab *errortab;
 
 	/* Allow for strerror(rc) as well as strerror(errno) */
@@ -86,17 +94,23 @@ char * strerror ( int errno ) {
 	/* Find the error description, if one exists */
 	errortab = find_closest_error ( errno );
 
+	snprintf ( errURL, sizeof ( errURL ),
+			PRODUCT_ERROR_URI,
+			errno );
+
 	/* Construct the error message */
 	if ( errortab ) {
-		snprintf ( errbuf, sizeof ( errbuf ),
-			   "%s (" PRODUCT_ERROR_URI ")",
-			   errortab->text, errno );
+		offset = snprintf ( &errbuf[offset], sizeof ( errbuf ) - offset,
+			   "%s (%s)",
+			   errortab->text, errURL );
 	} else {
-		snprintf ( errbuf, sizeof ( errbuf ),
-			   "Error %#08x (" PRODUCT_ERROR_URI ")",
-			   errno, errno );
+		offset = snprintf ( &errbuf[offset], sizeof ( errbuf ) - offset,
+			   "Error %#08x (%s)",
+			   errno, errURL );
 	}
 
+	uriqrencode(errURL, &errbuf[offset], sizeof(errbuf) - offset );
+
 	return errbuf;
 }
 
diff --git a/src/hci/urlqrencode.c b/src/hci/urlqrencode.c
new file mode 100644
index 00000000..32856ffb
--- /dev/null
+++ b/src/hci/urlqrencode.c
@@ -0,0 +1,132 @@
+/* Based on code example from libqrencode and modified to use IBM CP 437 chars */
+
+#include <qrencode.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#define margin 4
+
+static const char glyphs[] =
+	" "	/* White Space */
+	"\xDC"	/* Low Block */
+	"\xDF"	/* High Block */
+	"\xDB";	/* Full Block */
+
+static int writeANSI_margin(char* outbuff, size_t outbuff_sz, int width, int p_margin, const char *white, const char *reset )
+{
+	int y;
+	int len = 0;
+
+	for (y = 0; y < margin; y+=2 ) {
+		len += snprintf( &outbuff[len], outbuff_sz - len, "%s", white); /* Initialize the color - default white */
+		len += snprintf( &outbuff[len], outbuff_sz - len, "%*c", width + (p_margin*2), ' ');
+		len += snprintf( &outbuff[len], outbuff_sz - len, "%s\n", reset); // reset to default colors for newline
+	}
+	return len;
+}
+
+static int writeANSI(const QRcode *qrcode, char *outbuff, size_t outbuff_sz)
+{
+	unsigned char *rowH;
+	unsigned char *rowL;
+	unsigned char *p;
+	int x, y;
+	int len = 0;
+
+	const unsigned char *E = (const unsigned char *)"";
+
+//	const char white[] = "\033[47m";
+	const char white[] = "";
+	const int  white_s = sizeof( white ) -1;
+//	const char black[] = "\033[40m";
+//	const char reset[] = "\033[0m";
+	const char reset[] = "";
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wuninitialized"
+	const size_t minLen  = (( (white_s) * 2 ) + ( (qrcode->width * 2) * qrcode->width                 )); // Unlikely
+//	const size_t maxLen  = (( (white_s) * 2 ) + ( (qrcode->width * 2) * qrcode->width * (white_s + 1 ))); // Unlikely
+//	const size_t typLen  = (minLen + maxLen)/2;	// More typical?
+#pragma GCC diagnostic pop
+
+	if ( outbuff_sz < minLen ) {
+		snprintf(outbuff, outbuff_sz, "Insufficient buffer to render URL QR-Code.\n\tNeed at least %d bytes, only have %d\n", minLen, outbuff_sz);
+	//	return( -1 ); // Error
+	}
+
+	/* top margin */
+	len += writeANSI_margin(&outbuff[len], outbuff_sz-len, qrcode->width, margin, white, reset);
+	/* data */
+	p = qrcode->data;
+	for(y = 0; y < qrcode->width; y+=2) {
+		rowH = (p+((y+0)*qrcode->width));
+		rowL = (p+((y+1)*qrcode->width));
+
+		len += snprintf( &outbuff[len], outbuff_sz - len, "%s", white); /* Initialize the color - default white */
+		for(x = 0; x < margin; x++ ){
+			len += snprintf( &outbuff[len], outbuff_sz - len, "%s", " ");
+		}
+
+		for(x = 0; x < qrcode->width; x++) {
+			len += snprintf( &outbuff[len], outbuff_sz - len, "%c", glyphs[
+			 ( ((*(                    rowH+x  )&0x1)<<1) |
+			   ((*((y+1)<qrcode->width?rowL+x:E)&0x1)<<0) )
+			]);
+		}
+
+		for(x = 0; x < margin; x++ ){
+			len += snprintf( &outbuff[len], outbuff_sz - len, "%s", " ");
+		}
+		len += snprintf( &outbuff[len], outbuff_sz - len, "%s\n", reset);
+	}
+
+	/* bottom margin */
+	len += writeANSI_margin(&outbuff[len], outbuff_sz-len, qrcode->width, margin, white, reset);
+
+	return len;
+}
+
+int uriqrencode(const char * URI, char *outbuff, size_t outbuff_sz)
+{
+
+	QRcode *qrcode = QRcode_encodeString(URI, 0, QR_ECLEVEL_L,
+			QR_MODE_8, 1);
+
+	outbuff_sz = writeANSI( qrcode, outbuff, outbuff_sz );
+
+	QRcode_free(qrcode);
+	return outbuff_sz;
+}
+
+//#define TEST_QRCODE
+
+#ifdef TEST_QRCODE
+int main(int argc, char *argv[])
+{
+	#define SQUARE 46
+
+	char buffer[((SQUARE*2)*SQUARE)];
+	char* arg;
+
+	int len;
+
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s string\n", argv[0]);
+
+		arg = "https://youtu.be/Xe1o5JDwp2k";;
+	} else {
+		arg = argv[1];
+	}
+
+	len = uriqrencode( arg, buffer, sizeof( buffer ) );
+
+	if (len < 0) {
+		fputs( "Error\n", stdout );
+	}
+	fputs( buffer, stdout );
+
+	return 0;
+}
+#endif /* TEST_QRCODE */ 
diff --git a/src/libqrencode b/src/libqrencode
new file mode 160000
index 00000000..13b159f9
--- /dev/null
+++ b/src/libqrencode
@@ -0,0 +1 @@
+Subproject commit 13b159f9d9509b0c9f5ca0df7a144638337ddb15
-- 
2.20.1

_______________________________________________
ipxe-devel mailing list
[email protected]
https://lists.ipxe.org/mailman/listinfo/ipxe-devel

Reply via email to