diff options
author | PMR <pmr@pmr-lander> | 2020-03-06 11:35:53 +0000 |
---|---|---|
committer | PMR <pmr@pmr-lander> | 2020-03-06 11:35:53 +0000 |
commit | 5e0bc581943e241ebf58f63d242f9b5eebd7a477 (patch) | |
tree | 17f6b4794da750a1923e8790f60aa3cf6d8ec4af | |
parent | afd9daaaba7b8b8131f738bc770c7fadb6ebdd35 (diff) | |
parent | a9a32710e1d401a30ef2cdfe1132d6b5258b95c5 (diff) |
Merge #379349 from ~jocave/plainbox-provider-checkbox:tty-qrcode-roundtrip
-rwxr-xr-x | bin/roundtrip_qr.py | 121 | ||||
-rw-r--r-- | units/camera/jobs.pxu | 31 | ||||
-rw-r--r-- | units/camera/packaging.pxu | 15 | ||||
-rw-r--r-- | units/camera/test-plan.pxu | 1 |
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 |