def parse_args(): """Parses arguments, returns (options, args).""" from argparse import ArgumentParser available_ports = list(get_serial_ports()) parser = ArgumentParser(description='Upload AVR `.hex` to ' 'Arduino-compatible board.') parser.add_argument('board_name', help='Arduino board name (e.g., `uno`, ' '`mega2560`).') parser.add_argument('-V', '--disable-verify', action='store_true', help='Disable automatic verify check when uploading ' 'data.') parser.add_argument('hex', type=path, help='Path to `.hex` file.') parser.add_argument('port', help='Serial port.', nargs='+', default=None, choices=available_ports) args = parser.parse_args() if args.port is None: # No serial port was specified. if len(available_ports) == 1: # There is only one serial port available, so select it # automatically. args.port = available_ports[0] else: parser.error('No serial port was specified. Please select at ' 'least one of the following ports: %s' % available_ports) return args
def test_nanopb_encode_decode(): port = list(serial_device.get_serial_ports())[0] i2c_local = I2CBoard(port=port) i2c_devices = np.fromstring(i2c_local.i2c_scan(), dtype=np.uint8).astype(int) assert(len(i2c_devices) == 1) remote_address = i2c_devices[0] # Test `int` and `uint` for 8, 16, and 32-bit widths. for signedness in ('u', ''): for width in (8, 32): if not signedness and 8: # Skip signed 8-bit integers, since we do not have enough # memory on the device to add the method for testing. continue upper = (1 << width) - 1 if signedness else (1 << (width - 1)) - 1 values = np.linspace(0, upper, num=100).astype(int) for value in values: yield (_test_nanopb_encode_echo_integral, signedness, width, i2c_local, remote_address, value) values = np.linspace(0, 100) for value in values: yield (_test_nanopb_encode_echo_float, i2c_local, remote_address, value)
def upload_firmware(firmware_path, board_name, port=None, arduino_install_home=None, **kwargs): ''' Upload the specified firmware file to the specified board. ''' if arduino_install_home is None: context = auto_context() else: context = ArduinoContext(arduino_install_home) board = Board(context, board_name) uploader = Uploader(board) available_ports = list(get_serial_ports()) if port is None: # No serial port was specified. if len(available_ports) == 1: # There is only one serial port available, so select it # automatically. port = available_ports[0] else: raise IOError('No serial port was specified. Please select one of' ' the following ports: %s' % available_ports) return uploader.upload(firmware_path, port, **kwargs)
def echo_test(): port = list(serial_device.get_serial_ports())[0] i2c_local = I2CBoard(port=port) i2c_devices = np.fromstring(i2c_local.i2c_scan(), dtype=np.uint8).astype(int) assert(len(i2c_devices) == 1) i2c_remote = RemoteI2CBoard(i2c_local, i2c_devices[0]) # Test `float`. yield _test_echo_float, i2c_remote # Test `int` and `uint` for 8, 16, and 32-bit widths. for signedness in ('u', ''): for width in (8, 16, 32): yield _test_echo_integral, i2c_remote, signedness, width # Construct a string of characters spanning the range of values # representable by a byte. msg = np.linspace(0, 255, 10).astype(np.uint8).tostring() yield _test_echo_str, i2c_remote, msg # Construct a string of characters spanning the range of values # representable by a byte in reverse order, ending with a zero. msg = np.linspace(0, 255, 10).astype(np.uint8).tostring() yield _test_echo_str, i2c_remote, msg
def connect(self, port=None, baudrate=115200, debug=False, timeout=None): # Attempt to connect to the board. If no port was specified, try each # available serial port until a successful connection is established. self._board = None if not debug: request_manager = CommandRequestManager(REQUEST_TYPES, CommandRequest, CommandResponse, CommandType) else: request_manager = CommandRequestManagerDebug(REQUEST_TYPES, CommandRequest, CommandResponse, CommandType) if port is not None: ports = [port] else: ports = get_serial_ports() for port in ports: stream = SerialStream(port, baudrate=baudrate) if timeout is not None: proxy = NodeProxy(request_manager, stream, timeout=timeout) else: proxy = NodeProxy(request_manager, stream) stream._serial.setDTR(False) time.sleep(.2) stream._serial.setDTR(True) time.sleep(1.0) if self._test_connection(proxy): break if not self.connected: raise IOError('Could not connect to control board.') self.calibration = self.create_feedback_calibration()
def AppFields(self): serial_ports = list(get_serial_ports()) if len(serial_ports): default_port = serial_ports[0] else: default_port = None return Form.of( Enum.named('serial_port').using( default=default_port, optional=True).valued(*serial_ports), Float.named('default_duration').using(default=1000, optional=True), Float.named('default_voltage').using(default=80, optional=True), Float.named('default_frequency').using(default=10e3, optional=True), Boolean.named('Auto-run diagnostic tests').using(default=True, optional=True))
def upload_firmware(firmware_path, board_name, port=None, arduino_install_home=None, **kwargs): ''' Upload the specified firmware file to the specified board. ''' if arduino_install_home is None: context = auto_context() else: context = ArduinoContext(arduino_install_home) board = Board(context, board_name) uploader = Uploader(board) available_ports = list(get_serial_ports()) if port is None: # No serial port was specified. if len(available_ports) == 1: # There is only one serial port available, so select it # automatically. port = available_ports[0] else: raise IOError('No serial port was specified. Please select one of' ' the following ports: %s' % available_ports) uploader.upload(firmware_path, port, **kwargs)
def connect(self, serial_port=None, baud_rate=115200): if serial_port is None or serial_port == 'None': # check if we're reconnecting (i.e., already have a port number) serial_port = self.port # if not, try connecting to the first available port if serial_port is None: serial_port = [port for port in get_serial_ports()][0] # if there's no port to try, return if serial_port is None: return if not (self.port == serial_port and self.baud_rate == baud_rate): self.serial_device = Serial(serial_port, baudrate=baud_rate) self.proxy = Proxy(self.serial_device) # wait for board to initialize time.sleep(2) # initialize the digital pins 2-18 as an outputs for pin in range(2, 19): self.proxy.pin_mode(pin, OUTPUT) self.clear_all_channels()
class DropBotDxPlugin(Plugin, StepOptionsController, AppDataController): """ This class is automatically registered with the PluginManager. """ implements(IPlugin) implements(IWaveformGenerator) serial_ports_ = [port for port in get_serial_ports()] if len(serial_ports_): default_port_ = serial_ports_[0] else: default_port_ = None AppFields = Form.of( Enum.named('serial_port').using(default=default_port_, optional=True).valued(*serial_ports_), Float.named('default_duration').using(default=1000, optional=True), Float.named('default_voltage').using(default=80, optional=True), Float.named('default_frequency').using(default=10e3, optional=True), ) version = get_plugin_info(path(__file__).parent).version @property def StepFields(self): """ Expose StepFields as a property to avoid breaking code that accesses the StepFields member (vs through the get_step_form_class method). """ return self.get_step_form_class() def __init__(self): self.control_board = None self.name = get_plugin_info(path(__file__).parent).plugin_name self.connection_status = "Not connected" self.current_frequency = None self.timeout_id = None self.channel_states = pd.Series() self.plugin = None self.plugin_timeout_id = None def get_step_form_class(self): """ Override to set default values based on their corresponding app options. """ app = get_app() app_values = self.get_app_values() return Form.of( Integer.named('duration').using( default=app_values['default_duration'], optional=True, validators=[ ValueAtLeast(minimum=0), ]), Float.named('voltage').using( default=app_values['default_voltage'], optional=True, validators=[ValueAtLeast(minimum=0), max_voltage]), Float.named('frequency').using( default=app_values['default_frequency'], optional=True, validators=[ValueAtLeast(minimum=0), check_frequency]), ) def update_channel_states(self, channel_states): # Update locally cached channel states with new modified states. try: self.channel_states = channel_states.combine_first( self.channel_states) except ValueError: logging.info('channel_states: %s', channel_states) logging.info('self.channel_states: %s', self.channel_states) logging.info('', exc_info=True) else: app = get_app() connected = self.control_board != None if connected and (app.realtime_mode or app.running): self.on_step_run() def cleanup_plugin(self): if self.plugin_timeout_id is not None: gobject.source_remove(self.plugin_timeout_id) if self.plugin is not None: self.plugin = None def on_plugin_enable(self): super(DropBotDxPlugin, self).on_plugin_enable() self.cleanup_plugin() # Initialize 0MQ hub plugin and subscribe to hub messages. self.plugin = DmfZmqPlugin(self, self.name, get_hub_uri(), subscribe_options={zmq.SUBSCRIBE: ''}) # Initialize sockets. self.plugin.reset() # Periodically process outstanding message received on plugin sockets. self.plugin_timeout_id = gtk.timeout_add(10, self.plugin.check_sockets) self.check_device_name_and_version() if get_app().protocol: self.on_step_run() self._update_protocol_grid() def on_plugin_disable(self): self.cleanup_plugin() if get_app().protocol: self.on_step_run() self._update_protocol_grid() def on_app_exit(self): """ Handler called just before the Microdrop application exits. """ self.cleanup_plugin() try: self.control_board.hv_output_enabled = False except: # ignore any exceptions (e.g., if the board is not connected) pass def on_protocol_swapped(self, old_protocol, protocol): self._update_protocol_grid() def _update_protocol_grid(self): pgc = get_service_instance(ProtocolGridController, env='microdrop') if pgc.enabled_fields: pgc.update_grid() def on_app_options_changed(self, plugin_name): app = get_app() if plugin_name == self.name: app_values = self.get_app_values() reconnect = False if self.control_board: for k, v in app_values.items(): if k == 'serial_port' and self.control_board.port != v: reconnect = True if reconnect: self.connect() self._update_protocol_grid() elif plugin_name == app.name: # Turn off all electrodes if we're not in realtime mode and not # running a protocol. if (self.control_board and not app.realtime_mode and not app.running): logger.info('Turning off all electrodes.') self.control_board.hv_output_enabled = False def connect(self): """ Try to connect to the control board at the default serial port selected in the Microdrop application options. If unsuccessful, try to connect to the control board on any available serial port, one-by-one. """ self.current_frequency = None if len(DropBotDxPlugin.serial_ports_): app_values = self.get_app_values() # try to connect to the last successful port try: self.control_board = SerialProxy( port=str(app_values['serial_port'])) except: logger.warning( 'Could not connect to control board on port %s.' ' Checking other ports...', app_values['serial_port'], exc_info=True) self.control_board = SerialProxy() self.control_board.initialize_switching_boards() app_values['serial_port'] = self.control_board.port self.set_app_values(app_values) else: raise Exception("No serial ports available.") def check_device_name_and_version(self): """ Check to see if: a) The connected device is a OpenDrop b) The device firmware matches the host driver API version In the case where the device firmware version does not match, display a dialog offering to flash the device with the firmware version that matches the host driver API version. """ try: self.connect() name = self.control_board.properties['package_name'] if name != self.control_board.host_package_name: raise Exception("Device is not a DropBot DX") host_software_version = self.control_board.host_software_version remote_software_version = self.control_board.remote_software_version # Reflash the firmware if it is not the right version. if host_software_version != remote_software_version: response = yesno( "The DropBot DX firmware version (%s) " "does not match the driver version (%s). " "Update firmware?" % (remote_software_version, host_software_version)) if response == gtk.RESPONSE_YES: self.on_flash_firmware() except Exception, why: logger.warning("%s" % why) self.update_connection_status()
class SyringePumpPlugin(Plugin, AppDataController, StepOptionsController): """ This class is automatically registered with the PluginManager. """ implements(IPlugin) version = get_plugin_info(path(__file__).parent).version plugin_name = get_plugin_info(path(__file__).parent).plugin_name serial_ports_ = [port for port in get_serial_ports()] if len(serial_ports_): default_port_ = serial_ports_[0] else: default_port_ = None ''' AppFields --------- A flatland Form specifying application options for the current plugin. Note that nested Form objects are not supported. Since we subclassed AppDataController, an API is available to access and modify these attributes. This API also provides some nice features automatically: -all fields listed here will be included in the app options dialog (unless properties=dict(show_in_gui=False) is used) -the values of these fields will be stored persistently in the microdrop config file, in a section named after this plugin's name attribute ''' AppFields = Form.of( Enum.named('serial_port').using(default=default_port_, optional=True).valued(*serial_ports_), Float.named('steps_per_microliter').using(optional=True, default=1.0), ) ''' StepFields --------- A flatland Form specifying the per step options for the current plugin. Note that nested Form objects are not supported. Since we subclassed StepOptionsController, an API is available to access and modify these attributes. This API also provides some nice features automatically: -all fields listed here will be included in the protocol grid view (unless properties=dict(show_in_gui=False) is used) -the values of these fields will be stored persistently for each step ''' StepFields = Form.of( Float.named('microliters_per_min').using( optional=True, default=60, #validators= #[ValueAtLeast(minimum=0), # ValueAtMost(maximum=100000)] ), Float.named('microliters').using( optional=True, default=10, #validators= #[ValueAtLeast(minimum=0), # ValueAtMost(maximum=100000)] ), ) def __init__(self): self.name = self.plugin_name self.proxy = None self.initialized = False # Latch to, e.g., config menus, only once def connect(self): """ Try to connect to the syring pump at the default serial port selected in the Microdrop application options. If unsuccessful, try to connect to the proxy on any available serial port, one-by-one. """ from stepper_motor_controller import SerialProxy if len(SyringePumpPlugin.serial_ports_): app_values = self.get_app_values() # try to connect to the last successful port try: self.proxy = SerialProxy(port=str(app_values['serial_port'])) except: logger.warning( 'Could not connect to the syringe pump on port %s. ' 'Checking other ports...', app_values['serial_port'], exc_info=True) self.proxy = SerialProxy() app_values['serial_port'] = self.proxy.port self.set_app_values(app_values) else: raise Exception("No serial ports available.") def check_device_name_and_version(self): """ Check to see if: a) The connected device is a what we are expecting b) The device firmware matches the host driver API version In the case where the device firmware version does not match, display a dialog offering to flash the device with the firmware version that matches the host driver API version. """ try: self.connect() properties = self.proxy.properties package_name = properties['package_name'] display_name = properties['display_name'] if package_name != self.proxy.host_package_name: raise Exception("Device is not a %s" % properties['display_name']) host_software_version = self.proxy.host_software_version remote_software_version = self.proxy.remote_software_version # Reflash the firmware if it is not the right version. if host_software_version != remote_software_version: response = yesno("The %s firmware version (%s) " "does not match the driver version (%s). " "Update firmware?" % (display_name, remote_software_version, host_software_version)) if response == gtk.RESPONSE_YES: self.on_flash_firmware() except Exception, why: logger.warning("%s" % why)
class TestPlugin(Plugin, AppDataController, StepOptionsController): """ This class is automatically registered with the PluginManager. """ implements(IPlugin) version = get_plugin_info(path(__file__).parent).version plugins_name = get_plugin_info(path(__file__).parent).plugin_name ''' AppFields --------- A flatland Form specifying application options for the current plugin. Note that nested Form objects are not supported. Since we subclassed AppDataController, an API is available to access and modify these attributes. This API also provides some nice features automatically: -all fields listed here will be included in the app options dialog (unless properties=dict(show_in_gui=False) is used) -the values of these fields will be stored persistently in the microdrop config file, in a section named after this plugin's name attribute ''' serial_ports_ = [port for port in serial_device.get_serial_ports()] if len(serial_ports_): default_port_ = serial_ports_[0] else: default_port_ = None AppFields = Form.of( Enum.named('serial_port').using(default=default_port_, optional=True)\ .valued(*serial_ports_), ) ''' StepFields --------- A flatland Form specifying the per step options for the current plugin. Note that nested Form objects are not supported. Since we subclassed StepOptionsController, an API is available to access and modify these attributes. This API also provides some nice features automatically: -all fields listed here will be included in the protocol grid view (unless properties=dict(show_in_gui=False) is used) -the values of these fields will be stored persistently for each step ''' StepFields = Form.of( Boolean.named('led_on').using(default=False, optional=True), ) def __init__(self): self.name = self.plugins_name self.proxy = None def on_plugin_enable(self): # We need to call AppDataController's on_plugin_enable() to update the # application options data. AppDataController.on_plugin_enable(self) self.on_app_init() app_values = self.get_app_values() try: self.proxy = SerialProxy(port=app_values['serial_port']) self.proxy.pin_mode(pin=13, mode=1) logger.info('Connected to %s on port %s', self.proxy.properties.display_name, app_values['serial_port']) except Exception, e: logger.error('Could not connect to base-node-rpc on port %s: %s.', app_values['serial_port'], e) if get_app().protocol: pgc = get_service_instance(ProtocolGridController, env='microdrop') pgc.update_grid()