Source code for chipshouter.chipshouter

#
# This file is part of the ChipSHOUTER Python API.
# Copyright NewAE Technology Inc., 2017-2018.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# ChipSHOUTER is a registered trademark of NewAE Technology Inc.
#

'''
    ChipSHOUTER API Documentation
    =============================
    
    PyChipSHOUTER allows you to / get options / set options via this API.
    
    Using the ChipSHOUTER requires you to:
       (a) configure settings:
             (1) Capacitor bank voltage
             (2) Pulse widths, settings (if using internal pulse generator)
       (b) arm the device using:
             (1) front-panel button, or
             (2) sending arm command, or
             (3) external IO pin on RJ12
       (c)  Triggering the pulse using:
             (1) the pulse front-panel button, or
             (2) the pulse command, or
             (3) external IO pin on RJ12, or
             (4) external hardware trigger

    This API allows you to fine-tune the pulse settings, generate special waveforms,
    change voltage between 150-500V, and more!

    Example
    -------
    Below is an example of arming / pulse and then disarm.

    >>> from chipshouter import ChipSHOUTER
    >>> cs = ChipSHOUTER('COM12')
    >>> print cs #get all values of device
    >>> cs.voltage = 500
    >>> cs.pulse.width = 180
    >>> cs.armed = 1
    >>> cs.pulse = 1
    >>> cs.pat_wave = [0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0]
    >>> cs.pat_enable = 1 #Turn on special pattern trigger
    >>> cs.pulse = 1
    >>> cs.armed = False #Can use true/false or 1/0
    
    Scripting
    ---------
    
    Scripting ChipSHOUTER is recommended to deal with the expected error conditions. In
    particular, the ChipSHOUTER may reset during use due to the EMFI events. This can
    be detected as shown here::
    
        from chipshouter import ChipSHOUTER
        from chipshouter.com_tools import Reset_Exception
        cs = ChipSHOUTER('COM4')

        def setup_device:
            #Set any defaults you want
            cs.pulse.repeat = 1

            #Arm - add some delay for next stuff
            cs.armed = 1
            time.sleep(0.5)
            
            #Turn off sound if you want
            #cs.mute = True

        while True:
            try:
                old = cs.voltage.set
                cs.voltage = random.randint(200, 500)
                cs.pulse = 1
            except Reset_Exception:
                print("Device rebooted!")
                time.sleep(5) #Need to wait after reboot!
                setup_device()

'''
from collections import OrderedDict
import re
import logging
from .com_tools import Bin_API
from .com_tools import Reset_Exception
from .com_tools import Max_Retry_Exception
from .console.serial_interface import Serial_interface
from .console.console import Console
import time

firmware_version = '2.0.2'

api_version = '0.0.0'

class DisableNewAttr(object):
    """Provides an ability to disable setting new attributes in a class, useful to prevent typos.

    Usage:
    1. Make a class that inherits this class:
    >>> class MyClass(DisableNewAttr):
    >>>     # Your class definition here

    2. After setting up all attributes that your object needs, call disable_newattr():
    >>>     def __init__(self):
    >>>         self.my_attr = 123
    >>>         self.disable_newattr()

    3. Subclasses raise an AttributeError when trying to make a new attribute:
    >>> obj = MyClass()
    >>> #obj.my_new_attr = 456   <-- Raises AttributeError

    """

    def __init__(self):
        self.disable_newattr()

    def disable_newattr(self):
        self._new_attributes_disabled = True

    def __does_attr_exist(self, obj, var):
        y = getattr(obj, var, None)
        if y is not None:
            return True
        else:
            return False

    def enable_newattr(self):
        self._new_attributes_disabled = False

    def __setattr__(self, name, value):
        if hasattr(self, '_new_attributes_disabled') and self._new_attributes_disabled and not hasattr(self, name):  # would this create a new attribute?
            raise AttributeError("Attempt to set unknown attribute in %s"%self.__class__, name)
        super(DisableNewAttr, self).__setattr__(name, value)

#-----------------------------------------------------------------------------------------
# Below is another way of catching the attribute error without throwing away the exception
# - Does not work wit type of 'None' it assumes that it means it does not exist.
#-----------------------------------------------------------------------------------------
#    def __setattr__(self, name, value):
#        if self.__does_attr_exist(self, '_new_attributes_disabled') and self._new_attributes_disabled and not self.__does_attr_exist(self, name):  # would this create a new attribute?
#            raise AttributeError("Attempt to set unknown attribute in %s"%self.__class__, name)
#        super(DisableNewAttr, self).__setattr__(name, value)


def dict_to_str(input_dict, indent=""):
    """Turn a dictionary of attributes/status values into a pretty-printed
    string for use on the command line. Recursively pretty-prints dictionaries.

    This function is most useful with OrderedDicts as it keeps the same
    printing order.

    """

    # Find minimum width that fits all names
    min_width = 0
    for n in input_dict:
        min_width = max(min_width, len(str(n)))

    # Build string
    ret = ""
    for n in input_dict:
        if type(input_dict[n]) in (dict, OrderedDict):
            ret += indent + str(n) + ' = '
            ret += '\n' + dict_to_str(input_dict[n], indent+"    ")
        else:
            ret += indent + str(n).ljust(min_width) + ' = '
            ret += str(input_dict[n]) + '\n'

    return ret


class VoltageSettings(DisableNewAttr):

    def __init__(self, api):
        self.api = api
        self.disable_newattr()

    @property
    def set(self):
        """Requested capacitor bank voltage"""
        rval = self.api.get_voltage(5)
        return rval

    @set.setter
    def set(self, volt):
        rval = self.api.set_voltage(volt, 5)
        return rval

    @property
    def measured(self):
        """Measured capacitor bank voltage"""

        rval = self.api.get_voltage_measured(5)
        return rval

    def _dict_repr(self):
        dict = OrderedDict()
        dict['set'] = self.set
        dict['measured'] = self.measured
        return dict

    def __repr__(self):
        return dict_to_str(self._dict_repr())

    def __str__(self):
        return self.__repr__()


class PulseSettings(DisableNewAttr):
    """
    Pulse settings:

    """
    def __init__(self, api):
        self.api = api
        self.disable_newattr()

    @property
    def set(self):
        """Requested to see if the unit is pulsing. """
        rval = self.api.get_voltage(5)
        return rval

    @set.setter
    def set(self, state):
        """ Pulse the unit if the state is True """
        if state:
            self.api.cmd_pulse()

    @property
    def width(self):
        """ Basic pulse generator: Requested pulse width in nS,
        check the measured result to see actual possible setting"""
        rval = self.api.get_pulse_width(5)
        return rval

    @width.setter
    def width(self, width):
        rval = self.api.set_pulse_width(width)
        return rval

    @property
    def repeat(self):
        """Number of pulses per trigger, the trigger being
        the `pulse` command, the front-panel button, or the
        RJ12 firmware pulse pin when enabled.
        """
        rval = self.api.get_pulse_repeat(5)
        return rval

    @property
    def measured(self):
        """Basic pulse generator: actual pulse width in nS"""

        rval = self.api.get_pulse_width_measured(1)
        return rval

    @repeat.setter
    def repeat(self, repeat):
        rval = self.api.set_pulse_repeat(repeat)
        return repeat

    @property
    def deadtime(self):
        """ Time between pulses in mS """
        rval = self.api.get_pulse_deadtime(5)
        return rval

    @deadtime.setter
    def deadtime(self, deadtime):
        #self.api.dosomething(repeat)
        rval = self.api.set_pulse_deadtime(deadtime)
        return rval

    def _dict_repr(self):
        dict = OrderedDict()
        dict['width']        = self.width
        dict['repeat']       = self.repeat
        dict['deadtime']     = self.deadtime
        dict['actual width'] = self.measured
        return dict

    def __repr__(self):
        return dict_to_str(self._dict_repr())

    def __str__(self):
        return self.__repr__()

[docs]class ChipSHOUTER(DisableNewAttr): """ ChipSHOUTER object. The ChipSHOUTER will attempt to connect when initialzed. This Object will contain all the status of the ChipSHOUTER connected. You will be able probe for status and control the status of the ChipSHOUTER. :param comport: (String): The serial port that the ChipSHOUTER is connected. """ _name = "ChipSHOUTER" def __init__(self, comport): self.com_api = Bin_API(comport) self.com_api.refresh() self.__connected = True #Example where we have multiple subsettings self._pulse = PulseSettings(self.com_api) #_voltage is used as this will be an odd example self._voltage = VoltageSettings(self.com_api) self.disable_newattr() self._check_fw_version()
[docs] def status(self): """ This will indicate the status of the connection to the ChipSHOUTER. :returns: (bool): True if connected successfully. False if not. """ return self.__connected
[docs] def run_console(self): """ Runs the serial interface console in text mode. """ self.com_api.run_console() return
[docs] def ready_for_commands(self, retries = 3): """ ready_for_commands is a function to wait for the firmware to be ready to communicate """ return self.com_api.ready_for_commands()
def wait_for_arm(self, timeout = 3): while timeout: timeout -= 1 if self.state == 'armed': return True time.sleep(1) return False
[docs] def get_pat_length(self): """ This will get the length of the pattern wave programmed in the ChipSHOUTER firmware. :returns: (int): The length of the programmed pattern wave in the ChipSHOUTER. """ return self.com_api.get_pat_length()
[docs] def connect(self): """ This will disconnect the connection from the ChipSHOUTER. :returns: (bool): Status of the connection, True if connected successfully. False if not. """ self.com_api.ctl_connect()
[docs] def disconnect(self): """ This will disconnect the connection from the ChipSHOUTER. :returns: (bool): Status of the connection, True if connected successfully. False if not. """ self.com_api.ctl_disconnect()
#The following shows an "asymetric" setter, where we want to #make 'set' call some specific function @property def voltage(self): """ Sets the voltage or reads the voltage :param voltage: (int): The voltage level you wish to set. *Note* This is between 150 and 500 Volts :returns: This will return both members of the voltage: set and measured. :Member: .set - This is the voltage that is targeted to be set. :returns: The set voltage :Member (Read only): .measured - This is the actual voltage that is put out of the ChipSHOUTER. :returns: The measured voltage :Example: >>> from chipshouter import ChipSHOUTER >>> cs = ChipSHOUTER('COM10') Serial Interface Started Shouter API Started >>> cs.voltage set = 200 measured = 209 >>> cs.voltage.set 200 >>> cs.voltage.measured 210 >>> >>> cs.voltage = 300 >>> cs.voltage set = 300 measured = 298 """ return self._voltage @voltage.setter def voltage(self, voltage): self._voltage.set = voltage return voltage @property def pulse(self): r""" Sets parameters for the pulse generator and causes the pulse to be triggered. :param pulse: (bool): When set to True causes a pulse to occur. The settings of the basic pulse generator is done as follows:: _________________________________________ repeat (3) | | | v v v ____ ____ ____ __| |_____________| |_____________| |____________ ^ ^ | \__ Dead time |___ pulse width :Member: .deadtime: (int): - Time between pulses in mS :Member: .repeat: (int): - Number of pulses per trigger, the trigger being the `pulse` command, the front-panel button, or the RJ12 firmware pulse pin when enabled. :Member: .width: (int): - Basic pulse generator: Requested pulse width in nS, check the measured result to see actual possible setting. :Member: .measured: (int): - Basic pulse generator: actual pulse width in nS. :Example: >>> cs = ChipSHOUTER('COM10') # Connect to shouter >>> cs.pulse.width = 120 #120 nS pulse width >>> cs.pulse.repeat = 5 #5 pulses >>> cs.pulse.deadtime = 15 #15mS deadtime >>> cs.pulse = 1 #Trigger a pulse """ return self._pulse @pulse.setter def pulse(self, state): self._pulse.set = state @property def faults_current(self): """ This will get the current faults that are on the system. :Returns (list): This will return a list of dictionaries containing the list of faults. The list will be empty if none exist. :param fault: (int): When 0 it will attempt to clear the faults. Clearing the faults is need in order to arm after a fault has occured during the arm period. :Types: - **fault_probe** - Probe connection is not connected properly. - **fault_overtemp** - One of the temperature sensors has gone over 80C **Note:** *This will not recover until temperature goes below 70C.* - **fault_panel_open** - The case is open. - **fault_high_voltage** - Measured high voltage disagrees with requested by too much. - **fault_ram_crc** - RAM corrution has occured. - **fault_eeprom_crc** - EEPROM corruption has occured. - **fault_gpio_error** - GPIO mismatch between a requested value and actual. - **fault_charge** - Charge circuit error, or 19V input out-of-range (including brown-out). - **fault_trigger_error** - Trigger occured while disarmed or external hardware trigger help active for too long (More than 10msec) - **fault_hardware_exc** - Hardware monitor detected unspecified hardware fault. - **faults_trig_glitch** - Trigger was attempted while device disarmed. - **faults_overvoltage** - Charge circuit error, over-voltage on HV output detected. - **faults_temp_sensor** - Temperature sensor has failed to read correctly for too long. :Example: >>> cs = ChipSHOUTER('COM10') # Connect to shouter Serial Interface Started Shouter API Started >>> cs.state # Check the state of the shouter. 'disarmed' >>> cs.armed = 1 # Arm the shouter. >>> cs.state 'armed' >>> cs.state # Cause fault... and check state. 'fault' >>> cs.faults_current # List the faults. ['fault_probe'] >>> cs.faults_current = 0 # After fault fixed, Clear it. >>> cs.state # Check the state 'disarmed' >>> """ return self.com_api.get_faults_current() @faults_current.setter def faults_current(self, value): if value == 0: self.com_api.cmd_clear_faults() return self.com_api.get_faults_current() @property def faults_latched(self): """ This will get the latched faults that had occured on the system. An example of needing the finding issues when a fault occured for a short period of time, and is cleared by the time you look at the current faults. More information is documented with faults_current. :Returns (list): This will return a list of dictionaries containing the list of faults. The list will be empty if none exist. :Example: >>> cs = ChipSHOUTER('COM10') # Connect to shouter Serial Interface Started Shouter API Started >>> cs.state # Check the state of the shouter. 'disarmed' # I heard an error tone cs.faults_current # What was it??? [] # Funny nothing wrong here. >>> cs.faults_latched # Anything latched??? [{'fault': 1, 'name': 'trigger'}, {'fault': 1, 'name': 'trig_g'}] >>> # Ahhhh... flakey trigger. """ return self.com_api.get_faults_latched() @property def state(self): rval = self.com_api.get_state(timeout = 3) return rval @property def trigger_safe(self): """ Informs the ChipShouter that it is safe to read sensors. Typically, the ChipShouter will read a temperature sensors every few hundred ms. This can fail during a discharge event. Calling trigger_safe while the ChipShouter is armed will do an immediate sensor read, then disable temperature sensor reads. This must be called periodically, determined by absent_temp, to read the temperature sensor. If absent_temp elapses without a temperature read, the ChipShouter will fault. This manual temperature read mode will be disabled upon disarming the scope. :Returns (bool): - The sensors have been read and trigger_safe is enabled - False if the system is not armed or in fault. """ rval = self.com_api.get_trigger_safe(3) if(rval): return True else: return False @property def clr_armed(self): """ Clear faults and then arm in one command. :Returns (bool): - When read it will show True when armed, False if not. :param state (bool): Attempt to arm when True is passed in. Attempt to disarm when False is passed in. """ state = self.com_api.get_state(3) if(state == 'armed'): return True else: return False @property def api_version(self): """ This is the control of the armed status. :Returns (bool): - When read it will show True when armed, False if not. :param state (bool): Attempt to arm when True is passed in. Attempt to disarm when False is passed in. """ return api_version; @clr_armed.setter def clr_armed(self, status): if status: self.com_api.cmd_clear_arm() else: self.com_api.cmd_disarm() return status @property def armed(self): """ This is the control of the armed status. :Returns (bool): - When read it will show True when armed, False if not. :param state (bool): Attempt to arm when True is passed in. Attempt to disarm when False is passed in. """ state = self.com_api.get_state(3) if(state == 'armed'): return True else: return False @armed.setter def armed(self, status): if status: self.com_api.cmd_arm() else: self.com_api.cmd_disarm() return status @property def temperature_mosfet(self): """ Read the temperature of the MOSFET. """ return self.com_api.get_temperature_mosfet() @property def temperature_diode(self): """ Read the temperature of the catch diode. :Returns (int): temperature """ return self.com_api.get_temperature_diode() @property def temperature_xformer(self): """ Read the temperature of the transformer. :Returns (int): temperature """ return self.com_api.get_temperature_xformer() @property def id(self): """ Read the board id. This board id is needed for firmware updates to get the encrypted/signed firmware file. :Returns (string): The string id of the ChipSHOUTER. """ return self.com_api.get_id() def _check_fw_version(self): cs_id = self.id cs_ver = re.search(r"[0-9]\.[0-9]\.[0-9]", cs_id).group(0) if cs_ver < firmware_version: logging.warning("-------------------------------------------------------") logging.warning("New firmware update available (cur: {}) (new: {})".format(cs_ver, firmware_version)) logging.warning("Please contact support@newae.com for updated firmware") logging.warning("-------------------------------------------------------") @property def arm_timeout(self): """ Arm timeout For safety reasons and to reduce heat generation, the ChipSHOUTER will automatically disarm after a specific number of minutes. If the time out occurs, the ChipSHOUTER will disarm and disable the high voltage circuitry. The arm timer will be reset on every pulse trigger (internal or external). Thus if you are actively using the ChipSHOUTER it should not disarm on you. **NOTE** Valid range is between 1 - 60 minutes :param state: (int): time in minutes for the timeout. :Returns (int): The arm timeout without triggering. """ return self.com_api.get_arm_timeout() @arm_timeout.setter def arm_timeout(self, value): return self.com_api.set_arm_timeout(value) @property def hwtrig_term(self): """ Hardware Trigger Input termination mode. Configure hardware trigger (SMB connector) as high impedance ('False') or 50-ohm ('True'). The 50-Ohm impedance option puts a 50R resistor to ground. If you are not using the hardware trigger it is suggested to set this True, as it will reduce potential noise on the hardware trigger causing glitches. :param value: (bool): True (50-ohm) or False (approx 1.8K-ohm) impedance. :Returns (bool): State of the termination. """ return self.com_api.get_hwtrig_term() @hwtrig_term.setter def hwtrig_term(self, value): return self.com_api.set_hwtrig_term(value) @property def hwtrig_mode(self): """ Trigger Polarity (Active-high vs Active-low) Configure hardware trigger (SMB connector) as active high or active low. When configured as active low ensure the pin is externally driven high during operation to prevent false triggers. This command switches the entire internal trigger logic. When switching hwtrig_mode and using the pattern trigger, you will need to invert the pattern trigger logic. :param value: (bool): True (active-high) or False (active-low) mode. :Returns (bool): State of the termination. """ return self.com_api.get_hwtrig_mode() @hwtrig_mode.setter def hwtrig_mode(self, value): return self.com_api.set_hwtrig_mode(value) @property def emode(self): """ Pin 12 (external enable input) on the RJ12 connector can be 'arm' or 'fire'. In 'arm' mode: When the external IO is set to high it will attempt arm the system. **Note:** The system may not be armed because of a fault. The status Led on the connector will indicate the arm status. When the external IO is set to low it will disarm the system. The External IO reacts to the state change and not the static state. If the System fails to arm, to attempt again it needs to pull the line low and then high once again. In 'pulse' mode: When external IO is set high the pulse command is executed. This is equivalent to hitting the pulse button on the front panel. Note this is NOT the hardware trigger, as it is only executing the pulse command and not directly driving the MOSFET itself. :param state: (bool): True (firmware trigger mode) or False (arm mode) :Returns: The state of the emode. """ return self.com_api.get_emode() @emode.setter def emode(self, value): return self.com_api.set_emode(value) @property def mute(self): """ Mute the audio output, preventing beeping and fault tones. :param state: (bool): True (mute = On, thus no noise) or False """ return self.com_api.get_mute() @mute.setter def mute(self, value): return self.com_api.set_mute(value) @property def absent_temp(self): """Configure maximum time the temperature sensors can be skipped for during trigger_safe mode. The temperature sensors cannot be read during pulse events, and the ChipSHOUTER keeps a timer of how old the last temperature reading is. The timer is reset during routine self-checks (if triggers are not coming in quickly), or in response to the triggersafe command. :param value: (int) Time in seconds """ return self.com_api.get_absentTemp() @absent_temp.setter def absent_temp(self, value): return self.com_api.set_absentTemp(value) @property def pat_enable(self): """Enable the pattern trigger, if not set to True then the basic trigger is used instead. """ return self.com_api.get_pat_enable() @pat_enable.setter def pat_enable(self, value): return self.com_api.set_pat_enable(value) @property def pat_wave(self): r"""The wave used for the pattern trigger when pat_enable is 'True'. When reading the This will return the string up to 96 bits. If the length is more than 96 bits the string will append '... ( 4904 more )' >>> cs.pat_wave '11111111111111111111111111111111111111...111111111111111 ... ( 4904 more )' >>> **NOTE**: To get pattern waves that are longer than 96 use the get_pat_wave function. example: >>> cs.pat_wave = '11001' >>> cs.pat_wave '11001' >>> cs.pat_wave = '1'*97 >>> cs.pat_wave '111111111111111111111111111111111111111...11111111111111111 ... ( 1 more )' >>> cs.get_pat_wave() '111111111111111111111111111111111111111...11111111111111111' >>> **NOTE**: You **MUST** end the pattern with an inactive value, which will depend on the setting of hwtrig_mode . Normally this means ensuring you end with a '0' or 'False'. For example, setting a pattern of 11100011110000:: Pattern 1 1 1 0 0 0 1 1 1 1 0 0 0 0 _ _ _ _ _ _ _ Trigger | |_ _ _| |_ _ _ _ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ | | | | | | | | | | | | | | | Time: 20 60 00 40 80 20 60 (nS) 40 80 20 60 00 40 80 See the ChipSHOUTER manual specifications for details of the maximum wave length and exact time-step size. """ length = self.com_api.get_pat_length() if length > 96: wave = self.com_api.get_pat_wave(short_wave = True) wave += ' ... ( ' + str( length - 96) + ' more )' return wave return self.com_api.get_pat_wave()
[docs] def get_pat_wave(self): """The wave used for the pattern trigger when pat_enable is 'True'. **NOTE**: You **MUST** end the pattern with an inactive value, which will depend on the setting of hwtrig_mode . Normally this means ensuring you end with a '0' or 'False'. For example, setting a pattern of '11100011110000':: Pattern 1 1 1 0 0 0 1 1 1 1 0 0 0 0 _ _ _ _ _ _ _ Trigger | |_ _ _| |_ _ _ _ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ | | | | | | | | | | | | | | | Time: 20 60 00 40 80 20 60 (nS) 40 80 20 60 00 40 80 See the ChipSHOUTER manual specifications for details of the maximum wave length and exact time-step size. """ return self.com_api.get_pat_wave()
@pat_wave.setter def pat_wave(self, value): return self.com_api.set_pat_wave(value) @property def reset(self): """Set to True causes a hardware reset.""" return self.com_api.get_is_reset() @reset.setter def reset(self, value): if value: self.com_api.cmd_reset() return
[docs] def eeprom_write(self): """Write settings to EEPROM Originally, everytime config was changed, it was written to EEPROM, which could destroy EEPROM after a while. Now only saves to EEPROM if this is called """ self.com_api.cmd_eeprom_write()
@property def boot_enable(self): return 0 @boot_enable.setter def boot_enable(self, value): if value: self.com_api.set_boot_bits(0) return @property def reset_config(self): """Set to 'True' resets all configuration values to default (pulse width etc).""" return 0 @reset_config.setter def reset_config(self, value): if self.state == 'armed': raise ValueError('Error Cannot default when armed.') if value: self.com_api.cmd_default_options() return @property def board_id(self): return self.com_api.get_board_id()
[docs] def update_firmware(self, file, comport=None): """Updates the firmware of the connected ChipSHOUTER Supports both .fup and .bin files. If a .fup file is used, will verify that the firmware and ChipSHOUTER board IDs match. Args: file (str): Path to the firmware file comport (str): Optional if using function stand-alone, specify comport """ if comport is None: apid = True comport = self.com_api.comport self.com_api.ctl_disconnect() else: apid = False serial = Serial_interface(use_threads = False) if serial.s_open(comport, timeout=0.01): print("Connection successful") else: raise OSError("Unable to open serial port") my_console = Console(serial, threads=False, sendfile=file) my_console.download() my_console.quit() serial.s_close() if apid: self.com_api.ctl_connect() try: time.sleep(5.5) print(self.board_id) except (Reset_Exception, Max_Retry_Exception) as e: pass
def _dict_repr(self): dict = OrderedDict() dict['api_version'] = self.api_version dict['armed'] = self.armed dict['voltage'] = self.voltage._dict_repr() dict['pulse'] = self.pulse._dict_repr() dict['state'] = self.state #dict['trigger_safe'] = self.trigger_safe dict['faults_current'] = self.faults_current dict['faults_latched'] = self.faults_latched dict['temperature_mosfet'] = self.temperature_mosfet dict['temperature_diode'] = self.temperature_diode dict['temperature_xformer'] = self.temperature_xformer dict['arm_timeout'] = self.arm_timeout dict['hwtrig_term'] = self.hwtrig_term dict['hwtrig_mode'] = self.hwtrig_mode dict['emode'] = self.emode dict['mute'] = self.mute dict['absent_temp'] = self.absent_temp dict['pat_enable'] = self.pat_enable dict['pat_wave'] = self.pat_wave dict['reset_config'] = self.reset_config dict['reset'] = self.reset dict['board_id'] = self.board_id dict['boot_enable'] = self.boot_enable return dict def __repr__(self): # Add some extra information about ChipWhisperer type here if self.__connected: return dict_to_str(self._dict_repr()) else: ret = "ChipSHOUTER is not connected" return ret def __str__(self): return self.__repr__()
def main(): import time """ This is the main entry for the console.""" cs = ChipSHOUTER('COM10') print(cs.status()) print(cs.voltage) print('Arming!') cs.mute = False cs.armed = True print(cs.voltage.set) print(cs.voltage.measured) time.sleep(1) if cs.status(): print(cs.voltage) print('-'*40) print(cs.voltage.set) print(cs.voltage.measured) cs.voltage.set = 205 print('And... ' + str(cs.voltage)) cs.voltage = 206 print(cs.voltage.set) print(cs.voltage) cs.armed = False time.sleep(1) cs.disconnect() ################################################################################ if __name__ == "__main__": main()