From acf027ac98cd775e533cc0a0eb208754ba900576 Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Wed, 2 Mar 2016 09:31:57 +0100 Subject: [PATCH] [IMP] hw_scale: allow third party USB to serial interfaces We support the Mettler Toledo scales which have their own built-in USB to serial interface. Due to continuing issues with that built-in interface we will also support the scale configured in raw RS-232 mode which seems to be more reliable. This means that in order to connect the scale you'll need a third party USB to serial interface (unless you have built-in serial interfaces, but the POSBox doesn't). The main difficulty this poses is that using this approach we cannot use the name of the interface to find the device. When using the built-in interface of the scale the interface would identify with an ID containing 'mettler' and 'toledo'. When using a third party interface the ID will instead contain information about the third party interface. To fix this we use a probe-based approach, probing every available serial interface until we find one that returns a response to our probe. This approach will work with both third party interfaces and the built-in interface of the scale. Contrary to probe-based approach used in hw_blackbox_be this one is slightly more complicated because hw_scale is written in such a way that it is 'plug and play', which means that as long as the module is running it will continually try to find a scale. This is fine, but we don't want to keep sending probes to eg. Fiscal Data Modules, which could lead to issues. Therefore we will only probe every device once. When we lose an existing, confirmed connection to a scale we will however keep retrying to connect to that particular device. --- addons/hw_scale/controllers/main.py | 58 +++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/addons/hw_scale/controllers/main.py b/addons/hw_scale/controllers/main.py index b03fbc0ae97..68ec1126c01 100644 --- a/addons/hw_scale/controllers/main.py +++ b/addons/hw_scale/controllers/main.py @@ -33,6 +33,8 @@ class Scale(Thread): self.weight = 0 self.weight_info = 'ok' self.device = None + self.probed_device_paths = [] + self.path_to_scale = '' def lockedstart(self): with self.lock: @@ -61,27 +63,53 @@ class Scale(Thread): elif status == 'disconnected' and message: _logger.warning('Disconnected Scale: '+message) + def _get_raw_response(self, connection): + response = "" + while True: + byte = connection.read(1) + + if byte: + response += byte + else: + return response + def get_device(self): try: if not os.path.exists(self.input_dir): self.set_status('disconnected','Scale Not Found') return None devices = [ device for device in listdir(self.input_dir)] - scales = [ device for device in devices if ('mettler' in device.lower()) or ('toledo' in device.lower()) ] - if len(scales) > 0: - print join(self.input_dir,scales[0]) - self.set_status('connected','Connected to '+scales[0]) - return serial.Serial(join(self.input_dir,scales[0]), - baudrate = 9600, - bytesize = serial.SEVENBITS, - stopbits = serial.STOPBITS_ONE, - parity = serial.PARITY_EVEN, - #xonxoff = serial.XON, - timeout = 0.02, - writeTimeout= 0.02) - else: - self.set_status('disconnected','Scale Not Found') - return None + + if len(devices) > 0: + for device in devices: + path = self.input_dir + device + + # don't keep probing devices that are not a scale, + # only keep probing if in the past the device was + # confirmed to be a scale + if path not in self.probed_device_paths or path == self.path_to_scale: + _logger.debug('Probing: ' + path) + connection = serial.Serial(path, + baudrate = 9600, + bytesize = serial.SEVENBITS, + stopbits = serial.STOPBITS_ONE, + parity = serial.PARITY_EVEN, + timeout = 0.02, + writeTimeout= 0.02) + + connection.write("W") + self.probed_device_paths.append(path) + + if self._get_raw_response(connection): + _logger.debug(path + ' is scale') + self.path_to_scale = path + self.set_status('connected','Connected to '+device) + return connection + else: + _logger.debug('Already probed: ' + path) + + self.set_status('disconnected','Scale Not Found') + return None except Exception as e: self.set_status('error',str(e)) return None