From 4f8fb27ef473445b53140ada5494deb3f85044e2 Mon Sep 17 00:00:00 2001 From: Martin Guthrie Date: Tue, 17 Feb 2026 16:21:54 -0500 Subject: [PATCH 1/5] wip working at cli --- public/VERSION | 8 +- public/prism/drivers/scanners/Scanners.py | 49 +++++++ .../prism/drivers/scanners/hwdrv_scanners.py | 130 ++++++++++++++++++ public/prism/drivers/scanners/stublogger.py | 16 +++ .../example/barcode_count_v0/count_01.scr | 35 +++++ .../example/barcode_count_v0/tst00xx.py | 68 +++++++++ 6 files changed, 302 insertions(+), 4 deletions(-) create mode 100644 public/prism/drivers/scanners/Scanners.py create mode 100644 public/prism/drivers/scanners/hwdrv_scanners.py create mode 100644 public/prism/drivers/scanners/stublogger.py create mode 100644 public/prism/scripts/example/barcode_count_v0/count_01.scr create mode 100644 public/prism/scripts/example/barcode_count_v0/tst00xx.py diff --git a/public/VERSION b/public/VERSION index 5ba4891c..8ec28a98 100644 --- a/public/VERSION +++ b/public/VERSION @@ -1,4 +1,4 @@ -prev_commit=c3b6918ed24a5dab3fd1fec5fa949caf2cd63b69 -date=2026-01-09 16:09:55 -0500 -branch=36-lente-failing-to-run-on-vm -version=0.8-23-gc3b6918e +prev_commit=8eb26cfe690a1f29bd8fc723d5a6e6356f3f58af +date=2026-01-12 11:18:45 -0500 +branch=41-create-counting-example-with-barcode-scanner +version=0.8-28-g8eb26cfe diff --git a/public/prism/drivers/scanners/Scanners.py b/public/prism/drivers/scanners/Scanners.py new file mode 100644 index 00000000..68f8f96b --- /dev/null +++ b/public/prism/drivers/scanners/Scanners.py @@ -0,0 +1,49 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +""" +Sistemi Corporation, copyright, all rights reserved, 2026 +Martin Guthrie + +""" +try: + # run locally + from stublogger import StubLogger +except: + # run from prism + from public.prism.drivers.common.stublogger import StubLogger + + +# this is the (example) version of the remote hardware +VERSION = "0.2.0" +DRIVER_TYPE = "SCANNER" + + +class Scanner(object): + """ Scanners HW Driver + - this driver actually does nothing + + """ + + def __init__(self, loggerIn=None): + if loggerIn: self.logger = loggerIn + else: self.logger = StubLogger() + + def version(self): + """ Version of this driver. Typically this would be coming + from the remote hardware. The version of remote software/hardware + should be something that is expected. + + :return: + """ + return VERSION + + def close(self): + """ Always called at the end of a test sequence by Prism + - perform any reset, or closing of the hardware if the testing is done, or ended + - note the result state (Pass|Fail) of the DUT is not known and should not be assumed, + meaning that this hardware may be in an unknown state. This close() function + allows you to get back to a known state, if required. + + :return: None + """ + self.logger.info("closing") diff --git a/public/prism/drivers/scanners/hwdrv_scanners.py b/public/prism/drivers/scanners/hwdrv_scanners.py new file mode 100644 index 00000000..337def8a --- /dev/null +++ b/public/prism/drivers/scanners/hwdrv_scanners.py @@ -0,0 +1,130 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +""" +Sistemi Corporation, copyright, all rights reserved, 2026 +Martin Guthrie + +""" +import os +import pyudev +import logging +from core.sys_log import pub_notice + +# import your hardware driver class, and details +from public.prism.drivers.scanners.Scanners import Scanner, VERSION, DRIVER_TYPE + +class HWDriver(object): + """ + HWDriver is a class that installs a HW driver into the shared state. + This is not the HW driver itself, just an installer. + + When a script is loaded, there is a config section that lists all the HWDriver + to call, for example, + + "config": { + # drivers: list of code to initialize the test environment, must be specified + "drivers": ["public.prism.drivers.fake.hwdrv_fake"] + }, + + drivers is a list, so multiple HWDriver can be installed. + + This is a fake HW driver to simulate and show what a HWDriver is required to do. + """ + SFN = os.path.basename(__file__) # for logging path + + # add as required + SCANNER_MANUFACTURERS = ["Datalogic", ] + + def __init__(self): + self.logger = logging.getLogger("{}".format(self.SFN)) + self.logger.info("Start") + self._num_chan = 0 + self.scanners = [] + + def discover_channels(self): + """ determine the number of channels, and popultae hw drivers into shared state + + [ {"id": i, # ~slot number of the channel (see Note 1) + "version": , # version of the driver + "hwdrv": , # instance of your hardware driver + + # optional + "close": None, # register a callback on closing the channel, or None + "play": jig_closed_detect # function for detecting jig closed + "show_pass_fail": jig_led # function for indicating pass/fail (like LED) + "show_msg": jig_display # function for indicating test status (like display) + + # not part of the required block + "unique_id": , # unique id of the hardware (for tracking purposes) + ... + }, ... + ] + + Note: + 1) The hw driver objects are expected to have an 'slot' field, the lowest + id is assigned to channel 0, the next highest to channel 1, etc + + :return: <#>, (use Zero for a device shared across all channels) + where #: >0 number of channels, + 0 does not indicate num channels, like a shared hardware driver + <0 error + + list of drivers + """ + sender = "{}.{}".format(self.SFN, __class__.__name__) # for debug purposes + + # ------------------------------------------------------------------ + # Your specific driver discovery code goes here + # + # Scan attached USB devices and look for scanners + context = pyudev.Context() + for device in context.list_devices(): + _manu = str(device.attributes.get("manufacturer")) + if _manu == "None": continue + + self.logger.info(_manu) + for m in self.SCANNER_MANUFACTURERS: + if m in str(device.attributes.get("manufacturer")): + _scanner = {"id": 0} # this will get re-indexed below + _scanner['hwdrv'] = Scanner() + _scanner['version'] = _scanner['hwdrv'].version() + _scanner['close'] = None + _scanner['play'] = None + _scanner['show_pass_fail'] = None + _scanner['show_msg'] = None + _scanner['usb_path'] = device.device_path + self.scanners.append(_scanner) + + # sort based on USB path, slot 0, 1, 2, etc + self.scanners = sorted(self.scanners, key=lambda d: d['usb_path']) + + # fix the slot IDs as the slot order set by the USB path + for idx, t in enumerate(self.scanners): + t["id"] = idx + + self.logger.info(self.scanners) + self._num_chan = len(self.scanners) + + pub_notice("HWDriver:{}: Found {}!".format(self.SFN, self._num_chan), sender=sender) + self.logger.info("Done: {} channels".format(self._num_chan)) + return self._num_chan, DRIVER_TYPE, self.scanners + + def num_channels(self): + return self._num_chan + + +# =============================================================================================== +# Debugging code +# - Test your hardware discover here by running this file from PyCharm (be sure to set the working +# directory as ~/git/scripts, else imports will fail) +# - the purpose is to valid discover_channels() is working +if __name__ == '__main__': + logging.basicConfig() + logger = logging.getLogger() + logger.setLevel(logging.INFO) + + d = HWDriver() + num_channels, driver_type, drivers = d.discover_channels() + logger.info("discover_channels: num channels {}, type {}, drivers {}".format(num_channels, + driver_type, + drivers)) diff --git a/public/prism/drivers/scanners/stublogger.py b/public/prism/drivers/scanners/stublogger.py new file mode 100644 index 00000000..2aaffc62 --- /dev/null +++ b/public/prism/drivers/scanners/stublogger.py @@ -0,0 +1,16 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +""" +Sistemi Corporation, copyright, all rights reserved, 2019 +Martin Guthrie + +""" + +class StubLogger(object): + """ stubb out logger if none is provided""" + # TODO: support print to console. + def info(self, *args, **kwargs): pass + def error(self, *args, **kwargs): pass + def debug(self, *args, **kwargs): pass + def warning(self, *args, **kwargs): pass + def critical(self, *args, **kwargs): pass \ No newline at end of file diff --git a/public/prism/scripts/example/barcode_count_v0/count_01.scr b/public/prism/scripts/example/barcode_count_v0/count_01.scr new file mode 100644 index 00000000..3bb1dffd --- /dev/null +++ b/public/prism/scripts/example/barcode_count_v0/count_01.scr @@ -0,0 +1,35 @@ +// Example: Count barcoded items +// Barcode string looks like: P###-S##### +// Multiple Scanners into One Prism PC is supported +{ + "subs$": { + "Lot": { + "title": "Lot (format #####)", + "type" : "str", "widget": "textinput", "regex": "\\d{5}", "default": "95035" + }, + "Loc": { + "title": "Location", + "type" : "str", "widget": "select", "choices": ["canada/ontario/milton", "us/newyork/bufalo"] + } + }, + "info": { + "product": "N/A", + "bom": "N/A", + "lot": "%%Lot", + "location": "%%Loc" + }, + "config": { + "fail_fast": true, + "drivers": ["public.prism.drivers.scanners.hwdrv_scanners"] + }, + "tests": [ + { + "module": "public.prism.scripts.example.barcode_count_v0.tst00xx", + "options": { "fail_fast": false }, + "items": [ + {"id": "TST000_scan", "enable": true, "regex": "^P\\d{3}-S\\d{5}$", "timeout": 10 }, + {"id": "TST0xxTEARDOWN", "enable": true } + ] + } + ] +} \ No newline at end of file diff --git a/public/prism/scripts/example/barcode_count_v0/tst00xx.py b/public/prism/scripts/example/barcode_count_v0/tst00xx.py new file mode 100644 index 00000000..38f5b0d8 --- /dev/null +++ b/public/prism/scripts/example/barcode_count_v0/tst00xx.py @@ -0,0 +1,68 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +""" +Sistemi Corporation, copyright, all rights reserved, 2026 +Martin Guthrie + +""" +import re +import logging +from core.test_item import TestItem +from public.prism.api import ResultAPI + +#from public.prism.drivers.fake.Fake import DRIVER_TYPE + + +# file and class name must match +class tst00xx(TestItem): + + def __init__(self, controller, chan, shared_state): + super().__init__(controller, chan, shared_state) + self.logger = logging.getLogger("tst00xx.{}".format(self.chan)) + + def TST0xxTEARDOWN(self): + """ Always called at the end of testing + - process any cleanup, closing, etc + + {"id": "TST0xxTEARDOWN", "enable": true }, + + """ + ctx = self.item_start() # always first line of test + self.item_end() # always last line of test + + def TST000_scan(self): + """ Scan barcode + - a regex is supplied to confirm barcode format + + {"id": "TST000_scan, "enable": true, "regex": "^P\d{3}-S\d{5}$", "timeout": 10 }, + + """ + ctx = self.item_start() # always first line of test + + self.log_bullet("Scan barcode") + + user_text = self.input_textbox("Scan:", "change") + if user_text["success"]: + self.log_bullet(f"SCAN: {user_text['textbox']}") + + # qualify the text here + if re.match(ctx.item.regex, user_text["textbox"]): + # Note: ResultAPI.UNIT_STRING is used to format the measurement correctly in JSON + _, _result, _bullet = ctx.record.measurement("input", user_text["textbox"], ResultAPI.UNIT_STRING) + + # Here, code could reach out to a dB and do some other kind of work + + else: + _result = ResultAPI.RECORD_RESULT_FAIL + _, _result, _bullet = ctx.record.measurement("input", + user_text["textbox"], + ResultAPI.UNIT_STRING, + force_fail=True) + self.log_bullet(_bullet) + + else: + # operator probably times out... + _result = ResultAPI.RECORD_RESULT_FAIL + self.log_bullet(user_text.get("err", "UNKNOWN ERROR")) + + self.item_end(_result) # always last line of test From d0eb775fbc6ab1a72efb2b49db8e9310089ca631 Mon Sep 17 00:00:00 2001 From: Martin Guthrie Date: Tue, 17 Feb 2026 17:33:51 -0500 Subject: [PATCH 2/5] working example --- public/VERSION | 6 ++-- public/prism/drivers/scanners/Scanners.py | 34 +++++++++---------- .../prism/drivers/scanners/hwdrv_scanners.py | 4 +-- .../example/barcode_count_v0/count_01.scr | 4 +-- .../example/barcode_count_v0/tst00xx.py | 16 ++++++++- 5 files changed, 39 insertions(+), 25 deletions(-) diff --git a/public/VERSION b/public/VERSION index 8ec28a98..e057b9db 100644 --- a/public/VERSION +++ b/public/VERSION @@ -1,4 +1,4 @@ -prev_commit=8eb26cfe690a1f29bd8fc723d5a6e6356f3f58af -date=2026-01-12 11:18:45 -0500 +prev_commit=4f8fb27ef473445b53140ada5494deb3f85044e2 +date=2026-02-17 16:21:54 -0500 branch=41-create-counting-example-with-barcode-scanner -version=0.8-28-g8eb26cfe +version=0.8-29-g4f8fb27e diff --git a/public/prism/drivers/scanners/Scanners.py b/public/prism/drivers/scanners/Scanners.py index 68f8f96b..1e9aa40a 100644 --- a/public/prism/drivers/scanners/Scanners.py +++ b/public/prism/drivers/scanners/Scanners.py @@ -20,30 +20,30 @@ class Scanner(object): """ Scanners HW Driver - - this driver actually does nothing + - this driver actually does nothing (very little) """ - def __init__(self, loggerIn=None): if loggerIn: self.logger = loggerIn else: self.logger = StubLogger() - def version(self): - """ Version of this driver. Typically this would be coming - from the remote hardware. The version of remote software/hardware - should be something that is expected. + self._stop_prism_player = False + self._close = False + + def stop_prism_player(self): + self._stop_prism_player = True + self.logger.info("stop_prism_player") - :return: + def jig_closed_always(self): + """ Always closed + - this is a stub implementation that always returns True which + causes the script to ALWAYS re-run the test sequence. """ - return VERSION + if self._stop_prism_player: + self.logger.info(False) + return False - def close(self): - """ Always called at the end of a test sequence by Prism - - perform any reset, or closing of the hardware if the testing is done, or ended - - note the result state (Pass|Fail) of the DUT is not known and should not be assumed, - meaning that this hardware may be in an unknown state. This close() function - allows you to get back to a known state, if required. + temp = self._close + self._close = not temp - :return: None - """ - self.logger.info("closing") + return temp diff --git a/public/prism/drivers/scanners/hwdrv_scanners.py b/public/prism/drivers/scanners/hwdrv_scanners.py index 337def8a..92b9ba0a 100644 --- a/public/prism/drivers/scanners/hwdrv_scanners.py +++ b/public/prism/drivers/scanners/hwdrv_scanners.py @@ -87,9 +87,9 @@ def discover_channels(self): if m in str(device.attributes.get("manufacturer")): _scanner = {"id": 0} # this will get re-indexed below _scanner['hwdrv'] = Scanner() - _scanner['version'] = _scanner['hwdrv'].version() + _scanner['version'] = None _scanner['close'] = None - _scanner['play'] = None + _scanner['play'] = _scanner['hwdrv'].jig_closed_always _scanner['show_pass_fail'] = None _scanner['show_msg'] = None _scanner['usb_path'] = device.device_path diff --git a/public/prism/scripts/example/barcode_count_v0/count_01.scr b/public/prism/scripts/example/barcode_count_v0/count_01.scr index 3bb1dffd..302b920f 100644 --- a/public/prism/scripts/example/barcode_count_v0/count_01.scr +++ b/public/prism/scripts/example/barcode_count_v0/count_01.scr @@ -2,7 +2,7 @@ // Barcode string looks like: P###-S##### // Multiple Scanners into One Prism PC is supported { - "subs$": { + "subs": { "Lot": { "title": "Lot (format #####)", "type" : "str", "widget": "textinput", "regex": "\\d{5}", "default": "95035" @@ -27,7 +27,7 @@ "module": "public.prism.scripts.example.barcode_count_v0.tst00xx", "options": { "fail_fast": false }, "items": [ - {"id": "TST000_scan", "enable": true, "regex": "^P\\d{3}-S\\d{5}$", "timeout": 10 }, + {"id": "TST000_scan", "enable": true, "regex": "^P\\d{3}-S\\d{5}$", "timeout": 100 }, {"id": "TST0xxTEARDOWN", "enable": true } ] } diff --git a/public/prism/scripts/example/barcode_count_v0/tst00xx.py b/public/prism/scripts/example/barcode_count_v0/tst00xx.py index 38f5b0d8..a4316d0f 100644 --- a/public/prism/scripts/example/barcode_count_v0/tst00xx.py +++ b/public/prism/scripts/example/barcode_count_v0/tst00xx.py @@ -10,7 +10,7 @@ from core.test_item import TestItem from public.prism.api import ResultAPI -#from public.prism.drivers.fake.Fake import DRIVER_TYPE +from public.prism.drivers.scanners.Scanners import DRIVER_TYPE as DRIVER_TYPE_SCANNER # file and class name must match @@ -42,11 +42,25 @@ def TST000_scan(self): self.log_bullet("Scan barcode") user_text = self.input_textbox("Scan:", "change") + # Note input_textbox also has a timeout parameter which should be set to + # something just lower than the test item timeout. If input_textbox + # has a timeout, then we should probably STOP Prism player just like below. + if user_text["success"]: self.log_bullet(f"SCAN: {user_text['textbox']}") + # STOPPING - use a scanned "cookie" to indicate stop + if user_text["textbox"] == "P999-STOP": + # Stop Prism Player + self.log_bullet("STOPPING PRISM PLAYER") + drivers = self.shared_state.get_drivers(self.chan, type=DRIVER_TYPE_SCANNER) + drivers[0]["obj"]["hwdrv"].stop_prism_player() + self.item_end(ResultAPI.RECORD_RESULT_DISABLED) + return + # qualify the text here if re.match(ctx.item.regex, user_text["textbox"]): + # Note: ResultAPI.UNIT_STRING is used to format the measurement correctly in JSON _, _result, _bullet = ctx.record.measurement("input", user_text["textbox"], ResultAPI.UNIT_STRING) From 587079abfd47654517137173d4a8b07dc7118a01 Mon Sep 17 00:00:00 2001 From: Martin Guthrie Date: Tue, 17 Feb 2026 17:37:19 -0500 Subject: [PATCH 3/5] barcodes --- public/VERSION | 6 +++--- .../barcode_count_v0/barcode_test_01.pdf | Bin 0 -> 48027 bytes .../example/barcode_count_v0/count_01.scr | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 public/prism/scripts/example/barcode_count_v0/barcode_test_01.pdf diff --git a/public/VERSION b/public/VERSION index e057b9db..dae5317f 100644 --- a/public/VERSION +++ b/public/VERSION @@ -1,4 +1,4 @@ -prev_commit=4f8fb27ef473445b53140ada5494deb3f85044e2 -date=2026-02-17 16:21:54 -0500 +prev_commit=d0eb775fbc6ab1a72efb2b49db8e9310089ca631 +date=2026-02-17 17:33:51 -0500 branch=41-create-counting-example-with-barcode-scanner -version=0.8-29-g4f8fb27e +version=0.8-30-gd0eb775f diff --git a/public/prism/scripts/example/barcode_count_v0/barcode_test_01.pdf b/public/prism/scripts/example/barcode_count_v0/barcode_test_01.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4f67049317cc38005b80e4c5f368cdff074eedaa GIT binary patch literal 48027 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 <&T+9J;nuf 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 Date: Tue, 17 Feb 2026 19:10:06 -0500 Subject: [PATCH 4/5] update info and use key0 --- public/VERSION | 6 +++--- public/prism/drivers/scanners/Scanners.py | 8 +++++--- .../scripts/example/barcode_count_v0/count_01.scr | 4 +++- .../scripts/example/barcode_count_v0/tst00xx.py | 14 +++++++++++++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/public/VERSION b/public/VERSION index dae5317f..256a9575 100644 --- a/public/VERSION +++ b/public/VERSION @@ -1,4 +1,4 @@ -prev_commit=d0eb775fbc6ab1a72efb2b49db8e9310089ca631 -date=2026-02-17 17:33:51 -0500 +prev_commit=587079abfd47654517137173d4a8b07dc7118a01 +date=2026-02-17 17:37:19 -0500 branch=41-create-counting-example-with-barcode-scanner -version=0.8-30-gd0eb775f +version=0.8-31-g587079ab diff --git a/public/prism/drivers/scanners/Scanners.py b/public/prism/drivers/scanners/Scanners.py index 1e9aa40a..27ee5dfd 100644 --- a/public/prism/drivers/scanners/Scanners.py +++ b/public/prism/drivers/scanners/Scanners.py @@ -35,14 +35,16 @@ def stop_prism_player(self): self.logger.info("stop_prism_player") def jig_closed_always(self): - """ Always closed - - this is a stub implementation that always returns True which - causes the script to ALWAYS re-run the test sequence. + """ "Auto" Jig Open/Close + - NOTE: because Prism calls here every 1sec and because Prism needs to + see the Jig Open/Close, it can take up to 2sec before Prism + is ready to Scan again """ if self._stop_prism_player: self.logger.info(False) return False + # toggle response so that Prism thinks the jig is opening and closing. temp = self._close self._close = not temp diff --git a/public/prism/scripts/example/barcode_count_v0/count_01.scr b/public/prism/scripts/example/barcode_count_v0/count_01.scr index 0a85149c..093afdf0 100644 --- a/public/prism/scripts/example/barcode_count_v0/count_01.scr +++ b/public/prism/scripts/example/barcode_count_v0/count_01.scr @@ -1,5 +1,7 @@ // Example: Count barcoded items // Barcode string looks like: P###-S##### +// info:product is filled in from the barcode +// dB key0 is used for the serial number // Multiple Scanners into One Prism PC is supported. // See example barcode_test_01.pdf for example barcodes used in this test. // NOTE: To STOP the test, use the STOP Barcode @@ -34,4 +36,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/public/prism/scripts/example/barcode_count_v0/tst00xx.py b/public/prism/scripts/example/barcode_count_v0/tst00xx.py index a4316d0f..c7ecf502 100644 --- a/public/prism/scripts/example/barcode_count_v0/tst00xx.py +++ b/public/prism/scripts/example/barcode_count_v0/tst00xx.py @@ -61,8 +61,20 @@ def TST000_scan(self): # qualify the text here if re.match(ctx.item.regex, user_text["textbox"]): + # update the product from the scanned item + product = user_text["textbox"].split("-")[0] + _info = {"product": product,} + ctx.record.record_info_set(_info) + + sn = user_text["textbox"].split("-")[1] + ctx.record.add_key("sn", sn, slot=0) + _result = ResultAPI.RECORD_RESULT_PASS + + _bullet = f"Barcode: {user_text['textbox']}" + + # Or could make a measurement # Note: ResultAPI.UNIT_STRING is used to format the measurement correctly in JSON - _, _result, _bullet = ctx.record.measurement("input", user_text["textbox"], ResultAPI.UNIT_STRING) + #_, _result, _bullet = ctx.record.measurement("input", user_text["textbox"], ResultAPI.UNIT_STRING) # Here, code could reach out to a dB and do some other kind of work From 0f6e3f81ba05ff84841035b2cd9334913a5a5116 Mon Sep 17 00:00:00 2001 From: Martin Guthrie Date: Tue, 17 Feb 2026 19:13:44 -0500 Subject: [PATCH 5/5] add todo --- public/VERSION | 6 +++--- public/prism/drivers/scanners/Scanners.py | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/public/VERSION b/public/VERSION index 256a9575..82d222bd 100644 --- a/public/VERSION +++ b/public/VERSION @@ -1,4 +1,4 @@ -prev_commit=587079abfd47654517137173d4a8b07dc7118a01 -date=2026-02-17 17:37:19 -0500 +prev_commit=714b6725edffd1832edd40bc79cc8738de06fbc9 +date=2026-02-17 19:10:06 -0500 branch=41-create-counting-example-with-barcode-scanner -version=0.8-31-g587079ab +version=0.8-32-g714b6725 diff --git a/public/prism/drivers/scanners/Scanners.py b/public/prism/drivers/scanners/Scanners.py index 27ee5dfd..4b30cd7d 100644 --- a/public/prism/drivers/scanners/Scanners.py +++ b/public/prism/drivers/scanners/Scanners.py @@ -30,6 +30,10 @@ def __init__(self, loggerIn=None): self._stop_prism_player = False self._close = False + # TODO: function to send a command to the scanner to alert the User + # that prism is ready for the user to scan. Scanners + # support this feature. + def stop_prism_player(self): self._stop_prism_player = True self.logger.info("stop_prism_player")