def __init__(self, callback: UpdaterEvents): self.model = ConnectedDeviceModel( self) # the device model using this instance as the view # we pass in the proxy because the device model runs on a separate thread, but we want updates to fire on the main controller thread. self.callback = callback self.scan_thread = None self.updater_state = UpdaterState() self.updater_state.on_change += lambda source: self._updater_state_changed( self.updater_state.state) self.updater_state.on_change += lambda source: callback.updater_state_changed( self.updater_state.state) self.updater_state.notify() # trigger initial update
class UpdaterController: def __init__(self, callback: UpdaterEvents): self.model = ConnectedDeviceModel( self) # the device model using this instance as the view # we pass in the proxy because the device model runs on a separate thread, but we want updates to fire on the main controller thread. self.callback = callback self.scan_thread = None self.updater_state = UpdaterState() self.updater_state.on_change += lambda source: self._updater_state_changed( self.updater_state.state) self.updater_state.on_change += lambda source: callback.updater_state_changed( self.updater_state.state) self.updater_state.notify() # trigger initial update def _set_thread_proxy(self, proxy): # rather than using self to handle updates, use the proxy so updates are processed on the controller thraed rather than # the background scanner thread self.model.view = proxy def _updater_state_changed(self, state): if state not in [FlashState.in_progress, FlashState.error]: self.start_scan(0.25) else: self.stop_scan() def update(self, device): self.callback.connected_device_changed(device) self.updater_state.set_state( FlashState.not_started if device else FlashState.not_connected) def scan(self): self.model.update() def flash(self, connected): try: self.updater_state.set_state(FlashState.in_progress) if connected is None: raise ValueError("No device connected") connection = USBDeviceConnection(*connected) progress = ProgressSpan() def progress_update(current): self.callback.progress(progress.min, progress.max, progress.current) progress.on_change += progress_update Updater().start(progress, connection, connection.device) self.updater_state.set_state(FlashState.complete) except: self.updater_state.set_state(FlashState.error) raise def start_scan(self, period): self.stop_scan() event = Event() scan_thread = Thread(name="usb scan", target=self._background_scan, args=[period, event], daemon=True) scan_thread.event = event self.scan_thread = scan_thread scan_thread.start() def stop_scan(self): t = self.scan_thread if t: t.event.set() t.join() def _background_scan(self, period, stop_event: Event): while not stop_event.is_set(): self.scan() stop_event.wait(period) self.scan_thread = None