summaryrefslogtreecommitdiff
diff options
authorPMR <pmr@pmr-lander>2020-03-06 11:35:53 +0000
committerPMR <pmr@pmr-lander>2020-03-06 11:35:53 +0000
commit5e0bc581943e241ebf58f63d242f9b5eebd7a477 (patch)
tree17f6b4794da750a1923e8790f60aa3cf6d8ec4af
parentafd9daaaba7b8b8131f738bc770c7fadb6ebdd35 (diff)
parenta9a32710e1d401a30ef2cdfe1132d6b5258b95c5 (diff)
Merge #379349 from ~jocave/plainbox-provider-checkbox:tty-qrcode-roundtrip
-rwxr-xr-xbin/roundtrip_qr.py121
-rw-r--r--units/camera/jobs.pxu31
-rw-r--r--units/camera/packaging.pxu15
-rw-r--r--units/camera/test-plan.pxu1
4 files changed, 167 insertions, 1 deletions
diff --git a/bin/roundtrip_qr.py b/bin/roundtrip_qr.py
new file mode 100755
index 0000000..e2eb5b5
--- /dev/null
+++ b/bin/roundtrip_qr.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+# This file is part of Checkbox.
+#
+# Copyright 2020 Canonical Ltd.
+# Written by:
+# Jonathan Cave <jonathan.cave@canonical.com>
+#
+# Checkbox is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3,
+# as published by the Free Software Foundation.
+#
+# Checkbox 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 Checkbox. If not, see <http://www.gnu.org/licenses/>.
+
+
+import os
+import random
+import string
+import time
+import subprocess as sp
+import sys
+
+import pyqrcode
+import zbar
+from PIL import Image
+
+
+def capture_rpi(name):
+ import picamera
+ file = os.path.join(os.path.expandvars(
+ '$PLAINBOX_SESSION_SHARE'), '{}_qrcapture.png'.format(name))
+ with picamera.PiCamera() as camera:
+ time.sleep(2)
+ camera.capture(file)
+ return file
+
+
+def capture_webcam(name):
+ file = os.path.join(os.path.expandvars(
+ '$PLAINBOX_SESSION_SHARE'), '{}_qrcapture.jpg'.format(name))
+ cmd = ('gst-launch-1.0 v4l2src device=/dev/{} num-buffers=1 ! jpegenc !'
+ 'filesink location={}').format(name, file)
+ try:
+ sp.check_call(cmd, shell=True)
+ except (sp.CalledProcessError, OSError) as e:
+ print(e)
+ raise SystemExit('ERROR: failed to capture image')
+ return file
+
+
+def generate_data():
+ return ''.join(random.choice(string.ascii_letters) for i in range(20))
+
+
+def generate_qr_code(data):
+ return pyqrcode.create(data)
+
+
+def display_code(qr):
+ with open('/dev/tty1', 'wb+', buffering=0) as term:
+ # clear the tty so the qr is always printed at the top of the sceen
+ term.write(str.encode('\033c'))
+ # print the qr code
+ term.write(qr.terminal(quiet_zone=5).encode())
+
+
+def decode_image(filename):
+ scanner = zbar.ImageScanner()
+ scanner.parse_config('enable')
+ pil = Image.open(filename).convert('L')
+ width, height = pil.size
+ raw = pil.tobytes()
+ image = zbar.Image(width, height, 'Y800', raw)
+ scanner.scan(image)
+ result = None
+ for code in image:
+ result = code.data
+ del(image)
+ if result is None:
+ raise SystemExit('ERROR: no qrcodes decoded')
+ return result
+
+
+def main():
+ if len(sys.argv) != 2:
+ raise SystemExit('ERROR: expected a device name')
+ name = sys.argv[1]
+ print('Testing device name: {}\n'.format(name))
+
+ test_str = generate_data()
+ print('Input string: {}'.format(test_str), flush=True)
+
+ print('Generating QR code...', flush=True)
+ qr = generate_qr_code(test_str)
+
+ print('Displaying on screen', flush=True)
+ display_code(qr)
+
+ print('Capture image of screen', flush=True)
+ if name == 'vchiq':
+ file = capture_rpi(name)
+ else:
+ file = capture_webcam(name)
+ print('Image {} captured'.format(file))
+
+ print('Decoding image file', flush=True)
+ result = decode_image(file)
+ print('Decoded data: {}'.format(result))
+
+ if result != test_str:
+ raise SystemExit('FAIL: decoded data does not match input')
+ print('PASS: decoded data and input match')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/units/camera/jobs.pxu b/units/camera/jobs.pxu
index 331f2db..c9f2451 100644
--- a/units/camera/jobs.pxu
+++ b/units/camera/jobs.pxu
@@ -131,4 +131,33 @@ command:
_description:
Takes multiple pictures based on the resolutions supported by the camera and
validates their size and that they are of a valid format.
-user: root \ No newline at end of file
+user: root
+
+unit: template
+template-engine: jinja2
+template-resource: device
+template-filter: device.category in ('CAPTURE', 'MMAL') and device.name != ''
+template-unit: job
+plugin: shell
+category_id: com.canonical.plainbox::camera
+id: camera/roundtrip-qrcode_{{ name }}
+_summary: Test video output and camera {{ name }} by displaying and reading a qrcode
+estimated_duration: 5.0
+requires:
+ {%- if __on_ubuntucore__ %}
+ lsb.release >= '19.1'
+ {%- else %}
+ lsb.release >= '19.1'
+ package.name == 'python3-zbar'
+ package.name == 'python3-pyqrcode'
+ package.name == 'python3-pil'
+ {% endif -%}
+command:
+ roundtrip_qr.py {{ name }}
+_description:
+ Generates a QRcode representing a random string of ascii letters. This is
+ written to tty1 using ascii escape codes. Either the PiCamera python module or
+ a gstreamer pipeline is used to capture an image of the display. An attempt
+ to decode a QRcode in the image is then made and data compared against the
+ random string.
+user: root
diff --git a/units/camera/packaging.pxu b/units/camera/packaging.pxu
new file mode 100644
index 0000000..0b90c61
--- /dev/null
+++ b/units/camera/packaging.pxu
@@ -0,0 +1,15 @@
+# For camera/roundtrip-qrcode_.*
+unit: packaging meta-data
+os-id: ubuntu
+Depends: python3-zbar
+
+# For camera/roundtrip-qrcode_.*
+unit: packaging meta-data
+os-id: ubuntu
+Depends: python3-pil
+
+# For camera/roundtrip-qrcode_.*
+unit: packaging meta-data
+os-id: ubuntu
+Depends: python3-pyqrcode
+
diff --git a/units/camera/test-plan.pxu b/units/camera/test-plan.pxu
index c3b8378..d69706c 100644
--- a/units/camera/test-plan.pxu
+++ b/units/camera/test-plan.pxu
@@ -84,5 +84,6 @@ estimated_duration: 1h30m
include:
camera/multiple-resolution-images-_.*
camera/multiple-resolution-images-rpi_.*
+ camera/roundtrip-qrcode_.*
bootstrap_include:
device