Пример #1
0
 def __init__(self, i2c, signal_source, range_ctrl_pin, ipcore, eeprom_dev_addr, sensor_dev_addr):
     if not i2c and not signal_source and not range_ctrl_pin and not ipcore:
         self.signal_source = MIXSignalSourceSGEmulator('mix_signalsource_sg_emulator')
         self.range_ctrl_pin = GPIOEmulator('gpio_emulator')
     elif i2c and signal_source and range_ctrl_pin and not ipcore:
         if isinstance(signal_source, basestring):
             axi4_bus = AXI4LiteBus(signal_source, IcemanDef.REG_SIZE)
             self.signal_source = MIXSignalSourceSG(axi4_bus)
         else:
             self.signal_source = signal_source
         self.range_ctrl_pin = range_ctrl_pin
     elif i2c and not signal_source and ipcore:
         if isinstance(ipcore, basestring):
             axi4_bus = AXI4LiteBus(ipcore, IcemanDef.MIX_SGT1_REG_SIZE)
             use_gpio = False if range_ctrl_pin else True
             self.ipcore = MIXSGT1SGR(axi4_bus, use_gpio)
         else:
             self.ipcore = ipcore
         self.signal_source = self.ipcore.signal_source
         self.range_ctrl_pin = range_ctrl_pin or Pin(self.ipcore.gpio, IcemanDef.RANGE_CTRL_PIN)
     else:
         raise IcemanException("Please check init parameters.")
     if i2c:
         eeprom = CAT24C32(eeprom_dev_addr, i2c)
         nct75 = NCT75(sensor_dev_addr, i2c)
     else:
         eeprom = None
         nct75 = None
     super(IcemanBase, self).__init__(eeprom, nct75, cal_table=iceman_calibration, range_table=iceman_range_table)
Пример #2
0
    def __init__(self, firmware_path, pl_uart_drv_ko_file, i2c, pull_up_pin,
                 pull_down_pin, tx_en_pin, removal_det_pin, connect_det_pin,
                 a0_pin, a1_pin, a2_pin, elaod_en_pin, eeprom_devaddr, gpio):
        self.path = firmware_path
        self.process = None
        self.pl_uart_drv_ko_file = pl_uart_drv_ko_file
        if (firmware_path == '' and pl_uart_drv_ko_file == '' and i2c is None
                and pull_up_pin is None and pull_down_pin is None
                and tx_en_pin is None and removal_det_pin is None
                and connect_det_pin is None):
            self.eeprom = EepromEmulator('eeprom_emulator')
            self.pull_up_pin = GPIOEmulator('pull_up_pin')
            self.pull_down_pin = GPIOEmulator('pull_down_pin')
            self.tx_en_pin = GPIOEmulator('tx_en_pin')
            self.removal_det_pin = GPIOEmulator('removal_det_pin')
            self.connect_det_pin = GPIOEmulator('connect_det_pin')
        elif (firmware_path != '' and pl_uart_drv_ko_file != ''
              and i2c is not None and pull_up_pin is not None
              and pull_down_pin is not None and tx_en_pin is not None
              and removal_det_pin is not None and connect_det_pin is not None):
            self.eeprom = CAT24C02(eeprom_devaddr, i2c)
            self.pull_up_pin = pull_up_pin
            self.pull_down_pin = pull_down_pin
            self.tx_en_pin = tx_en_pin
            self.removal_det_pin = removal_det_pin
            self.connect_det_pin = connect_det_pin
        else:
            raise DarkBeastException(
                '__init__ error! Please check the parameters!')
        self.gpio = gpio
        if (a0_pin is None and a1_pin is None and a2_pin is None
                and elaod_en_pin is None):
            self.a0_pin = Pin(None, DarkBeastDef.A0_PIN_ID)
            self.a1_pin = Pin(None, DarkBeastDef.A1_PIN_ID)
            self.a2_pin = Pin(None, DarkBeastDef.A2_PIN_ID)
            self.elaod_en_pin = Pin(None, DarkBeastDef.ELAOD_EN_PIN_ID)
        elif (a0_pin is not None and a1_pin is not None and a2_pin is not None
              and elaod_en_pin is not None):
            self.a0_pin = a0_pin
            self.a1_pin = a1_pin
            self.a2_pin = a2_pin
            self.elaod_en_pin = elaod_en_pin
        else:
            raise DarkBeastException(
                '__init__ error! Please check the parameters!')

        super(DarkBeastBase, self).__init__(self.eeprom, None)
        self.pin_def = {
            'PULL_UP': self.pull_up_pin,
            'PULL_DOWN': self.pull_down_pin,
            'TX_EN': self.tx_en_pin,
            'REMOVAL_DETECTION': self.removal_det_pin,
            'CONNECT_DETECTION': self.connect_det_pin,
            'A0': self.a0_pin,
            'A1': self.a1_pin,
            'A2': self.a2_pin,
            'ELAOD_EN': self.elaod_en_pin
        }
Пример #3
0
    def __init__(self,
                 i2c=None,
                 spi=None,
                 ad7608=None,
                 gpio=None,
                 volt_ch1=2,
                 volt_ch2=3,
                 curr_ch1=0,
                 curr_ch2=1,
                 eeprom_dev_addr=None,
                 sensor_dev_addr=None,
                 ipcore=None):

        self.ipcore = ipcore
        if (i2c is not None and spi is not None and ad7608 is not None
                and gpio is not None):
            spi.set_mode('MODE2')
            self.cat9555 = CAT9555(ElektraDef.CAT9555_ADDR, i2c)
            self.eeprom = CAT24C32(eeprom_dev_addr, i2c)
            self.sensor = NCT75(sensor_dev_addr, i2c)
            self.ad5663 = AD5663R(spi, ElektraDef.DAC_MV_REF,
                                  ElektraDef.DAC_MODE_REF)
            self.ad7608 = ad7608
            self.gpio = gpio
        elif (ipcore is not None and i2c is not None):
            self.spi = ipcore.spi
            self.spi.set_mode('MODE2')
            self.ad5663 = AD5663R(ipcore.spi, ElektraDef.DAC_MV_REF,
                                  ElektraDef.DAC_MODE_REF)
            self.gpio = None
            self.cat9555 = CAT9555(ElektraDef.CAT9555_ADDR, i2c)
            self.eeprom = CAT24C32(ElektraDef.EEPROM_DEV_ADDR, i2c)
            self.sensor = NCT75(ElektraDef.SENSOR_DEV_ADDR, i2c)
            self.ad7608 = ad7608 or MIXAD760XSGEmulator(
                "mix_ad760x_sg_emulator")
        elif (i2c is None and spi is None and ad7608 is None and gpio is None):
            self.cat9555 = CAT9555Emulator(ElektraDef.CAT9555_ADDR, None, None)
            self.eeprom = None
            self.sensor = None
            self.ad5663 = AD5663R(spi, ElektraDef.DAC_MV_REF,
                                  ElektraDef.DAC_MODE_REF)
            self.ad7608 = MIXAD760XSGEmulator("mix_ad760x_sg_emulator")
            self.gpio = GPIOEmulator("gpio_emulator")
        else:
            raise ElektraException(
                '__init__ error! Please check the parameters!')
        super(ElektraBase, self).__init__(self.eeprom,
                                          self.sensor,
                                          cal_table=elektra_calibration_info,
                                          range_table=elektra_range_table)
        self.adc_voltage_channel = {'ch1': volt_ch1, 'ch2': volt_ch2}
        self.adc_current_channel = {'ch1': curr_ch1, 'ch2': curr_ch2}
Пример #4
0
    def __init__(self, i2c=None, spi=None, ad7175=None, gpio=None, ipcore=None):
        super(EL004002A, self).__init__(None, None, None, None, ElektraDef.VLOT_CH1, ElektraDef.VLOT_CH2,
                                        ElektraDef.CURR_CH1, ElektraDef.CURR_CH2,
                                        ElektraDef.EEPROM_DEV_ADDR, ElektraDef.SENSOR_DEV_ADDR)
        if ipcore:
            self.ad7175 = ipcore.ad717x
            self.spi = ipcore.spi
            self.ad5663 = AD5663R(ipcore.spi, ElektraDef.DAC_MV_REF, ElektraDef.DAC_MODE_REF)
            self.gpio = None
        else:
            self.spi = spi or MIXQSPISGEmulator("mix_qspi_sg_emulator", ElektraDef.PLSPIBUS_EMULATOR_REG_SIZE)
            self.ad7175 = ad7175 or MIXAd7175SGEmulator("mix_ad7175_sg_emulator", ElektraDef.AD7175_EMULATOR_REG_SIZE)
            self.ad5663 = AD5663R(spi, ElektraDef.DAC_MV_REF, ElektraDef.DAC_MODE_REF)
            self.gpio = gpio or GPIOEmulator("gpio_emulator")

        if i2c:
            self.cat9555 = CAT9555(ElektraDef.CAT9555_ADDR, i2c)
            self.eeprom = CAT24C32(ElektraDef.EEPROM_DEV_ADDR, i2c)
            self.sensor = NCT75(ElektraDef.SENSOR_DEV_ADDR, i2c)
        else:
            self.cat9555 = CAT9555Emulator(ElektraDef.CAT9555_ADDR, None, None)
            self.eeprom = None
            self.sensor = None

        super(ElektraBase, self).__init__(self.eeprom, self.sensor,
                                          cal_table=elektra_calibration_info, range_table=elektra_range_table)

        self.ad7175.config = {
            "ch0": {"P": "AIN0", "N": "AIN4"},
            "ch1": {"P": "AIN1", "N": "AIN4"},
            "ch2": {"P": "AIN2", "N": "AIN4"},
            "ch3": {"P": "AIN3", "N": "AIN4"}
        }

        self.spi.set_mode('MODE2')
Пример #5
0
class IcemanBase(MIXBoard):
    '''
    Base class of Iceman and IcemanCompatible,Providing common Iceman methods.

    Args:
        i2c:             instance(I2C)/None,            i2c bus which is used to access CAT24C32 and NCT75.
        signal_source:   instance(MIXSignalSourceSG)/None, MIXSignalSourceSG used to control DAC output.
        range_ctrl_pin:  instance(GPIO)/None,           GPIO or Pin, which is used to control output range.
        ipcore:          instance(MIXSGT1SGR)/None,        MIXSGT1SGR which include MIXSignalSource and PLGPIO IP.
        eeprom_dev_addr: int,                           Eeprom device address.
        sensor_dev_addr: int,                           NCT75 device address.
    '''

    rpc_public_api = ['module_init', 'get_range', 'set_sampling_rate', 'output_volt', 'output_sine',
                      'output_square', 'output_triangle', 'output_sawtooth', 'output_stop'] + MIXBoard.rpc_public_api

    def __init__(self, i2c, signal_source, range_ctrl_pin, ipcore, eeprom_dev_addr, sensor_dev_addr):
        if not i2c and not signal_source and not range_ctrl_pin and not ipcore:
            self.signal_source = MIXSignalSourceSGEmulator('mix_signalsource_sg_emulator')
            self.range_ctrl_pin = GPIOEmulator('gpio_emulator')
        elif i2c and signal_source and range_ctrl_pin and not ipcore:
            if isinstance(signal_source, basestring):
                axi4_bus = AXI4LiteBus(signal_source, IcemanDef.REG_SIZE)
                self.signal_source = MIXSignalSourceSG(axi4_bus)
            else:
                self.signal_source = signal_source
            self.range_ctrl_pin = range_ctrl_pin
        elif i2c and not signal_source and ipcore:
            if isinstance(ipcore, basestring):
                axi4_bus = AXI4LiteBus(ipcore, IcemanDef.MIX_SGT1_REG_SIZE)
                use_gpio = False if range_ctrl_pin else True
                self.ipcore = MIXSGT1SGR(axi4_bus, use_gpio)
            else:
                self.ipcore = ipcore
            self.signal_source = self.ipcore.signal_source
            self.range_ctrl_pin = range_ctrl_pin or Pin(self.ipcore.gpio, IcemanDef.RANGE_CTRL_PIN)
        else:
            raise IcemanException("Please check init parameters.")
        if i2c:
            eeprom = CAT24C32(eeprom_dev_addr, i2c)
            nct75 = NCT75(sensor_dev_addr, i2c)
        else:
            eeprom = None
            nct75 = None
        super(IcemanBase, self).__init__(eeprom, nct75, cal_table=iceman_calibration, range_table=iceman_range_table)

    def module_init(self):
        '''
        init module, range ctrl pin will be set to output.

        Examples:
            iceman.module_init()

        '''
        self.load_calibration()
        self.range_ctrl_pin.set_dir('output')
        self._select_range('1V')
        self.set_sampling_rate()

    def _check_range(self, range):
        '''
        check signal range if is valid.

        Returns:
            string, convert range string to upper.

        Raise:
            IcemanException:  Parameter 'range' is invalid.

        '''
        if range.upper() == IcemanDef.RANGE_1V:
            return IcemanDef.RANGE_1V
        elif range.upper() == IcemanDef.RANGE_10V:
            return IcemanDef.RANGE_10V
        else:
            raise IcemanException("Parameter 'range' is invalid")

    def _select_range(self, range):
        '''
        Select output range.

        Args:
            range:      string, ['1V', '10V'], signal output range.

        Returns:
            string, "done", api execution successful.

        '''
        range = self._check_range(range)
        if hasattr(self, 'range') and range == self.range:
            return "done"
        if range == IcemanDef.RANGE_1V:
            self.range_ctrl_pin.set_level(0)
        else:
            self.range_ctrl_pin.set_level(1)
        self.range = range
        return "done"

    def get_range(self):
        '''
        Get current range.

        Returns:
            string, ['1V', '10V'], current range.

        '''
        return self.range

    def set_sampling_rate(self, sampling_rate=IcemanDef.SAMPLE_RATE):
        '''
        Iceman set dac sample rate.

        Args:
            sampling_rate:    float,    [5~50000000], unit Hz, default value is 50000000Hz.
        Returns:
            strings, "done", api execution successful.

        '''
        assert 5 <= sampling_rate <= 50000000
        if hasattr(self, 'sampling_rate') and sampling_rate == self.sampling_rate:
            return "done"

        self.sampling_rate = sampling_rate
        return "done"

    def output_volt(self, mvolt, range=IcemanDef.RANGE_1V):
        '''
        Output DC voltage in mV.

        Args:
            mvolt:   float, if range is 1V, -500 mV <= mvolt <= 500 mV,
                            if range is 10V, -5000 mV <= mvolt <= 5000 mV.
            range:   string, ['1V', '10V'], signal output range.

        Returns:
            string, "done", api execution successful.

        '''
        range = self._check_range(range)
        assert mvolt >= iceman_config[range]['offset']['min']
        assert mvolt <= iceman_config[range]['offset']['max']
        self.output_stop()
        self._select_range(range)
        self.signal_source.open()
        mvolt = self.calibrate('DC_{}'.format(self.range), mvolt)

        if self.range == IcemanDef.RANGE_10V:
            mvolt = mvolt * 1.0 / IcemanDef.RANGE_10V_GAIN

        # the volt should be reversed according to hardware
        mvolt = 0 - mvolt

        # get the offset scale
        mvolt = mvolt / (IcemanDef.MAX_MVPP / 2.0)

        if mvolt > IcemanDef.SIGNAL_SOURCE_SCALE_MAX:
            mvolt = IcemanDef.SIGNAL_SOURCE_SCALE_MAX
        elif mvolt < IcemanDef.SIGNAL_SOURCE_SCALE_MIN:
            mvolt = IcemanDef.SIGNAL_SOURCE_SCALE_MIN
        step = [[mvolt, mvolt, IcemanDef.AWG_DC_DURATION]]
        self.signal_source.set_signal_time(IcemanDef.OUTPUT_DURATION)
        self.signal_source.set_signal_type('AWG')
        self.signal_source.set_awg_parameter(self.sampling_rate, step)
        self.signal_source.output_signal()
        return "done"

    def output_sine(self, freq, rms, offset=0, range=IcemanDef.RANGE_1V):
        '''
        Output sine waveform with frequency, rms and offset. offset default is 0.

        Args:
            freq:    int, [1~4000000], unit Hz, output signal frequency in Hz.
            rms:     float, output signal rms. If range is 1V, 0 mVrms <= rms <= 366.1 mVrms.
                                               If range is 10V, 0 mVrms <= rms <= 3661 mVrms.
            offset:  float, signal offset voltage. If range is 1V, -500 mV <= offset <= 500 mV.
            range:   string, ['1V', '10V'], signal output range.

        Returns:
            string, "done", api execution successful.

        '''
        range = self._check_range(range)
        assert IcemanDef.FREQ_MIN <= freq <= IcemanDef.FREQ_MAX
        assert 0 <= rms <= iceman_config[range]['rms']['max']
        assert offset >= iceman_config[range]['offset']['min']
        assert offset <= iceman_config[range]['offset']['max']
        self.output_stop()
        self._select_range(range)
        self.signal_source.open()
        rms = self.calibrate('SINE_VPP_{}'.format(self.range), rms)
        offset = self.calibrate('DC_{}'.format(self.range), offset)
        if self.range == IcemanDef.RANGE_10V:
            rms /= IcemanDef.RANGE_10V_GAIN
            offset /= IcemanDef.RANGE_10V_GAIN
        vpp = 2 * math.sqrt(2) * rms
        vpp = vpp / IcemanDef.MAX_MVPP
        offset = offset / (IcemanDef.MAX_MVPP / 2.0)
        offset = -offset
        if vpp > IcemanDef.SIGNAL_SOURCE_VPP_MAX:
            vpp = IcemanDef.SIGNAL_SOURCE_SCALE_MAX
        if vpp < 0:
            vpp = 0.0
        self.signal_source.set_signal_time(IcemanDef.OUTPUT_DURATION)
        self.signal_source.set_signal_type('sine')
        self.signal_source.set_swg_paramter(self.sampling_rate, freq, vpp, 0, offset)
        self.signal_source.output_signal()
        return "done"

    def output_square(self, freq, vpp, duty, offset=0, range=IcemanDef.RANGE_1V):
        '''
        Ouptut square waveform with frequency, vpp, duty and offset. default offset is 0

        Args:
            freq:     int, [1~4000000], unit Hz, square waveform output frquency in Hz.
            vpp:      float, square waveform output vpp. If range is 1V,
                                                         0 <= vpp <= 1000 mV. If range is 10V,
                                                         0 <= vpp <= 10000 mV.
            duty:     float, [0~100], square waveform output duty.
            offset:   float, default 0,  square waveform offset voltage. If range is 1V,
                                         -500 mV <= offset <= 500 mV. If range is 10V,
                                         -5000 mV <= offset <= 5000 mV.
            range:   string, ['1V', '10V'], signal output range.

        Returns:
            string, "done", api execution successful.

        '''
        range = self._check_range(range)
        assert freq >= IcemanDef.FREQ_MIN and freq <= IcemanDef.FREQ_MAX
        assert vpp >= iceman_config[range]['vpp']['min']
        assert vpp <= iceman_config[range]['vpp']['max']
        assert offset >= iceman_config[range]['offset']['min']
        assert offset <= iceman_config[range]['offset']['max']
        assert duty >= 0 and duty <= 100

        self.output_stop()
        self._select_range(range)
        self.signal_source.open()
        vpp = self.calibrate('SQUARE_VPP_{}'.format(self.range), vpp)
        offset = self.calibrate('DC_{}'.format(self.range), offset)
        if self.range == IcemanDef.RANGE_10V:
            vpp /= IcemanDef.RANGE_10V_GAIN
            offset /= IcemanDef.RANGE_10V_GAIN

        vpp = vpp / IcemanDef.MAX_MVPP
        offset = offset / (IcemanDef.MAX_MVPP / 2.0)
        # the voltage should be reversed according to hardware
        offset = -offset
        if vpp > IcemanDef.SIGNAL_SOURCE_VPP_MAX:
            vpp = IcemanDef.SIGNAL_SOURCE_SCALE_MAX
        if vpp < 0:
            vpp = 0.0
        self.signal_source.set_signal_time(IcemanDef.OUTPUT_DURATION)
        self.signal_source.set_signal_type('square')
        self.signal_source.set_swg_paramter(self.sampling_rate, freq, vpp, 1 - duty / 100.0, offset)
        self.signal_source.output_signal()
        return "done"

    def output_triangle(self, freq, vpp, delay_ms=0, offset=0, range=IcemanDef.RANGE_1V):
        '''
        Output triangle waveform with frequency, vpp, delay_ms and offset.

        Args:
            freq:     int, [1~4000000], unit Hz, triangle waveform output frquency in Hz.
            vpp:      float, square waveform output vpp. If range is 1V,
                                                         0 <= vpp <= 1000 mV. If range is 10V,
                                                         0 <= vpp <= 10000 mV.
            delay_ms:    float, default 0, unit ms,  triangle waveform start delay time.
            offset:   float, default 0,  square waveform offset voltage. If range is 1V,
                                         -500 mV <= offset <= 500 mV. If range is 10V,
                                         -5000 mV <= offset <= 5000 mV.
            range:   string, ['1V', '10V'], signal output range.

        Returns:
            string, "done", api execution successful.

        '''
        range = self._check_range(range)
        assert IcemanDef.FREQ_MIN <= freq <= IcemanDef.FREQ_MAX
        assert vpp >= iceman_config[range]['vpp']['min']
        assert vpp <= iceman_config[range]['vpp']['max']
        assert delay_ms >= 0
        assert offset >= iceman_config[range]['offset']['min']
        assert offset <= iceman_config[range]['offset']['max']

        self.output_stop()
        self._select_range(range)
        self.signal_source.open()
        vpp = self.calibrate('TRIANGLE_VPP_{}'.format(self.range), vpp)
        offset = self.calibrate('DC_{}'.format(self.range), offset)
        if self.range == IcemanDef.RANGE_10V:
            vpp /= IcemanDef.RANGE_10V_GAIN
            offset /= IcemanDef.RANGE_10V_GAIN
        # the voltage should be reversed according to hardware
        v1 = 0 - (vpp / 2.0 + offset)
        v2 = 0 - (offset - vpp / 2.0)
        # get the period in ms
        period = 1000.0 / freq - delay_ms
        if period <= 0:
            raise IcemanException('Iceman board parameter delay_ms out of range')

        v1 = v1 / (IcemanDef.MAX_MVPP / 2.0)
        v2 = v2 / (IcemanDef.MAX_MVPP / 2.0)
        if v1 > IcemanDef.SIGNAL_SOURCE_SCALE_MAX:
            v1 = IcemanDef.SIGNAL_SOURCE_SCALE_MAX
        elif v1 < IcemanDef.SIGNAL_SOURCE_SCALE_MIN:
            v1 = IcemanDef.SIGNAL_SOURCE_SCALE_MIN
        if v2 > IcemanDef.SIGNAL_SOURCE_SCALE_MAX:
            v2 = IcemanDef.SIGNAL_SOURCE_SCALE_MAX
        elif v2 < IcemanDef.SIGNAL_SOURCE_SCALE_MIN:
            v2 = IcemanDef.SIGNAL_SOURCE_SCALE_MIN
        self.signal_source.set_signal_time(IcemanDef.OUTPUT_DURATION)
        self.signal_source.set_signal_type('AWG')

        # FPGA can resolve the minimum processing time for AWG.
        if (period / 2.0) > IcemanDef.AWG_MIN_TIME_RESOLUTION:
            wave_data = [[v2, v1, period / 2.0], [v1, v2, period / 2.0]]
        if delay_ms > IcemanDef.AWG_MIN_TIME_RESOLUTION:
            wave_data.append([v2, v2, delay_ms])
        self.signal_source.set_awg_parameter(self.sampling_rate, wave_data)
        self.signal_source.output_signal()
        return "done"

    def output_sawtooth(self, freq, vpp, trise, delay_ms=0, offset=0, range=IcemanDef.RANGE_1V):
        '''
        Output sawtooth waveform with frequency, vpp, trise, delay_ms and offset.

        Args:
            freq:     float, [1~4000000], unit Hz, sawtooth waveform output frquency in Hz.
            vpp:      float, sawtooth waveform output vpp. If range is 1V,
                                                         0 <= vpp <= 1000 mV. If range is 10V,
                                                         0 <= vpp <= 10000 mV.
            trise:    float,   [0~1000], unit ms, sawtooth waveform rise time.
            delay_ms:    float, default 0, unit ms, sawtooth waveform start delay time.
            offset:   float, default 0,  sawtooth waveform offset voltage. If range is 1V,
                                         -500 mV <= offset <= 500 mV. If range is 10V,
                                         -5000 mV <= offset <= 5000 mV.
            range:   string, ['1V', '10V'], signal output range.

        Returns:
            string, "done", api execution successful.

        '''
        range = self._check_range(range)
        assert IcemanDef.FREQ_MIN <= freq <= IcemanDef.FREQ_MAX
        assert vpp >= iceman_config[range]['vpp']['min']
        assert vpp <= iceman_config[range]['vpp']['max']
        assert 0 <= (trise + delay_ms) <= (1000 / freq)
        assert offset >= iceman_config[range]['offset']['min']
        assert offset <= iceman_config[range]['offset']['max']

        self.output_stop()
        self._select_range(range)
        self.signal_source.open()
        vpp = self.calibrate('SAWTOOTH_VPP_{}'.format(self.range), vpp)
        offset = self.calibrate('DC_{}'.format(self.range), offset)
        if self.range == IcemanDef.RANGE_10V:
            vpp /= IcemanDef.RANGE_10V_GAIN
            offset /= IcemanDef.RANGE_10V_GAIN
        # the voltage should be reversed according to hardware
        v1 = 0 - (vpp / 2.0 + offset)
        v2 = 0 - (offset - vpp / 2.0)
        # get the period in ms
        period = 1000.0 / freq - delay_ms
        if period <= 0:
            raise IcemanException('Iceman board parameter delay_ms out of range')

        v1 = v1 / (IcemanDef.MAX_MVPP / 2.0)
        v2 = v2 / (IcemanDef.MAX_MVPP / 2.0)
        if v1 > IcemanDef.SIGNAL_SOURCE_SCALE_MAX:
            v1 = IcemanDef.SIGNAL_SOURCE_SCALE_MAX
        elif v1 < IcemanDef.SIGNAL_SOURCE_SCALE_MIN:
            v1 = IcemanDef.SIGNAL_SOURCE_SCALE_MIN
        if v2 > IcemanDef.SIGNAL_SOURCE_SCALE_MAX:
            v2 = IcemanDef.SIGNAL_SOURCE_SCALE_MAX
        elif v2 < IcemanDef.SIGNAL_SOURCE_SCALE_MIN:
            v2 = IcemanDef.SIGNAL_SOURCE_SCALE_MIN
        self.signal_source.set_signal_time(IcemanDef.OUTPUT_DURATION)
        self.signal_source.set_signal_type('AWG')

        wave_data = []
        fall_edge = round(period - trise, 6)
        # FPGA can resolve the minimum processing time for AWG.
        if trise > IcemanDef.AWG_MIN_TIME_RESOLUTION:
            wave_data.append([v2, v1, trise])
        if fall_edge > IcemanDef.AWG_MIN_TIME_RESOLUTION:
            wave_data.append([v1, v2, fall_edge])
        if delay_ms > IcemanDef.AWG_MIN_TIME_RESOLUTION:
            wave_data.append([v2, v2, delay_ms])
        self.signal_source.set_awg_parameter(self.sampling_rate, wave_data)
        self.signal_source.output_signal()
        return "done"

    def output_stop(self):
        '''
        Stop output signal.
        '''
        self.signal_source.close()
        return "done"
Пример #6
0
class DarkBeastBase(MIXBoard):
    '''
    Base class of DarkBeast and DarkBeastCompatible.

    Providing common DarkBeast methods

    Args:
        firmware_path:       string,           DarkBeast firmware absolute path
        pl_uart_drv_ko_file: string,           DarkBeast pl_uart_drv.ko drive absolute path
                                               if None creating emulator.
        i2c:             instance(I2C)/None,   Class instance of PLI2CBus, which is used to control cat9555,
                                               eeprom and AD5667 sensor.
        gpio:            instance(GPIO)/None,  Class instance of PLGPIO, UART RX connect AID to enable or disable.
                                               if None creating emulator.
        pull_up_pin:     instance(GPIO)/None,  Class instance of GPIO, data line pull-up control, Provider mode.
                                               if None creating emulator.
        pull_down_pin:   instance(GPIO)/None,  Class instance of GPIO, data line pull-down control, Consumer mode.
                                               if None creating emulator.
        tx_en_pin:       instance(GPIO)/None,  Class instance of GPIO, UART_TX buffer enable control.
                                               if None creating emulator.
        connect_det_pin: instance(GPIO)/None,  Class instance of GPIO, input pin control, detects whether
                                               the DUT is connected. if None creating emulator.
        removal_det_pin: instance(GPIO)/None,  Class instance of GPIO, Input pin control, detect disconnection
                                               from DUT. if None creating emulator.
        a0_pin:          instance(GPIO)/None,  Class instance of Pin, if None creating emulator.
        a1_pin:          instance(GPIO)/None,  Class instance of Pin, if None creating emulator.
        a2_pin:          instance(GPIO)/None,  Class instance of Pin, if None creating emulator.
        elaod_en_pin:    instance(GPIO)/None,  Class instance of Pin, if None creating emulator.
        eeprom_devaddr:  int,                  Eeprom device address.

    '''

    rpc_public_api = [
        'module_init', 'close', 'open', 'communicate', 'aid_connect_set',
        'io_set', 'io_get'
    ] + MIXBoard.rpc_public_api

    def __init__(self, firmware_path, pl_uart_drv_ko_file, i2c, pull_up_pin,
                 pull_down_pin, tx_en_pin, removal_det_pin, connect_det_pin,
                 a0_pin, a1_pin, a2_pin, elaod_en_pin, eeprom_devaddr, gpio):
        self.path = firmware_path
        self.process = None
        self.pl_uart_drv_ko_file = pl_uart_drv_ko_file
        if (firmware_path == '' and pl_uart_drv_ko_file == '' and i2c is None
                and pull_up_pin is None and pull_down_pin is None
                and tx_en_pin is None and removal_det_pin is None
                and connect_det_pin is None):
            self.eeprom = EepromEmulator('eeprom_emulator')
            self.pull_up_pin = GPIOEmulator('pull_up_pin')
            self.pull_down_pin = GPIOEmulator('pull_down_pin')
            self.tx_en_pin = GPIOEmulator('tx_en_pin')
            self.removal_det_pin = GPIOEmulator('removal_det_pin')
            self.connect_det_pin = GPIOEmulator('connect_det_pin')
        elif (firmware_path != '' and pl_uart_drv_ko_file != ''
              and i2c is not None and pull_up_pin is not None
              and pull_down_pin is not None and tx_en_pin is not None
              and removal_det_pin is not None and connect_det_pin is not None):
            self.eeprom = CAT24C02(eeprom_devaddr, i2c)
            self.pull_up_pin = pull_up_pin
            self.pull_down_pin = pull_down_pin
            self.tx_en_pin = tx_en_pin
            self.removal_det_pin = removal_det_pin
            self.connect_det_pin = connect_det_pin
        else:
            raise DarkBeastException(
                '__init__ error! Please check the parameters!')
        self.gpio = gpio
        if (a0_pin is None and a1_pin is None and a2_pin is None
                and elaod_en_pin is None):
            self.a0_pin = Pin(None, DarkBeastDef.A0_PIN_ID)
            self.a1_pin = Pin(None, DarkBeastDef.A1_PIN_ID)
            self.a2_pin = Pin(None, DarkBeastDef.A2_PIN_ID)
            self.elaod_en_pin = Pin(None, DarkBeastDef.ELAOD_EN_PIN_ID)
        elif (a0_pin is not None and a1_pin is not None and a2_pin is not None
              and elaod_en_pin is not None):
            self.a0_pin = a0_pin
            self.a1_pin = a1_pin
            self.a2_pin = a2_pin
            self.elaod_en_pin = elaod_en_pin
        else:
            raise DarkBeastException(
                '__init__ error! Please check the parameters!')

        super(DarkBeastBase, self).__init__(self.eeprom, None)
        self.pin_def = {
            'PULL_UP': self.pull_up_pin,
            'PULL_DOWN': self.pull_down_pin,
            'TX_EN': self.tx_en_pin,
            'REMOVAL_DETECTION': self.removal_det_pin,
            'CONNECT_DETECTION': self.connect_det_pin,
            'A0': self.a0_pin,
            'A1': self.a1_pin,
            'A2': self.a2_pin,
            'ELAOD_EN': self.elaod_en_pin
        }

    def __del__(self):
        self.close()

    def _capture_by_flag(self):
        '''
        capture end flag of result.
        '''
        last_time = time.time()
        data_str = ""
        while (time.time() - last_time < DarkBeastDef.DEFAULT_TIMEOUT):
            read_str = self.process.stdout.read(1)
            data_str = data_str + read_str
            if read_str == DarkBeastDef.RESULT_CHECK_FLAG:
                if data_str.endswith(DarkBeastDef.RESULT_END_FLAG):
                    break
        if time.time() - last_time >= DarkBeastDef.DEFAULT_TIMEOUT:
            raise DarkBeastException('process read wait timeout!')

        return data_str.strip(DarkBeastDef.RESULT_END_FLAG)

    def _update_linux_driver(self):
        ''' update pl_uart_drv.ko if exist '''
        if os.path.isfile(self.pl_uart_drv_ko_file):
            os.system('rmmod ' + self.pl_uart_drv_ko_file)
            os.system('insmod ' + self.pl_uart_drv_ko_file)

    def module_init(self):
        '''
        DarkBeast module init, initialize ad5592r channel mode and open DarkBeast process.

        Returns:
            string, str, return open information.

        Examples:
            DarkBeast.module_init()

        '''
        self._update_linux_driver()
        ret_str = 'done'
        if os.path.isfile(self.path):
            ret_str = self.open()

        # set plgpio init
        if self.gpio:
            self.gpio.set_dir('output')
            self.gpio.set_level(DarkBeastDef.LOWE_LEVEL)

        # set gpio init
        self.pull_up_pin.set_dir('output')
        self.pull_up_pin.set_level(DarkBeastDef.LOWE_LEVEL)
        self.pull_down_pin.set_dir('output')
        self.pull_down_pin.set_level(DarkBeastDef.LOWE_LEVEL)
        self.tx_en_pin.set_dir('output')
        self.tx_en_pin.set_level(DarkBeastDef.LOWE_LEVEL)
        self.connect_det_pin.set_dir('input')
        self.removal_det_pin.set_dir('input')

        # set pin init
        self.a0_pin.set_dir('output')
        self.a0_pin.set_level(DarkBeastDef.LOWE_LEVEL)
        self.a1_pin.set_dir('output')
        self.a1_pin.set_level(DarkBeastDef.LOWE_LEVEL)
        self.a2_pin.set_dir('output')
        self.a2_pin.set_level(DarkBeastDef.LOWE_LEVEL)
        self.elaod_en_pin.set_dir('output')
        self.elaod_en_pin.set_level(DarkBeastDef.LOWE_LEVEL)

        return ret_str

    def close(self):
        '''
        close the DarkBeast process.

        Returns:
            string, "done", api execution successful.

        '''
        if self.process is not None:
            string_list = []
            pid_list = []
            pgid = os.getpgid(self.process.pid)

            command = 'ps -C {}'.format(os.path.basename(self.path))
            progress = Popen(command, shell=True, stdin=PIPE, stdout=PIPE)
            string = progress.communicate()[0]
            string_list = string.split("\n")
            for line in string_list:
                pid = re.findall("\d+", line)
                if len(pid) != 0:
                    pid_list.append(pid[0])

            for pid in pid_list:
                if os.getpgid(int(pid)) == pgid:
                    command = "kill " + pid
                    os.system(command)
            self.process = None

        return 'done'

    def open(self):
        '''
        open DarkBeast process by Popen, and return open information or faild raising Exception

        Returns:
            string, str, return open information.

        '''
        assert os.access(self.path, os.F_OK
                         | os.X_OK), 'path <{}> not exist or execute'.format(
                             self.path)
        if self.process is not None:
            return 'done'

        command = 'cd {};./{}'.format(os.path.dirname(self.path),
                                      os.path.basename(self.path))

        # stderr is standard error output, can be file descriptors and STDOUT. None means no output
        self.process = Popen([command, ""],
                             shell=True,
                             stdin=PIPE,
                             stdout=PIPE,
                             stderr=STDOUT)

        return self._capture_by_flag()

    def communicate(self, command):
        '''
        communicate with DarkBeast process. if process not open, raise DarkBeastException

        Args:
            command:  string, command string.

        Returns:
            string, str, return information.

        Examples:
            cmd_string = "SWITCH2HS"
            print DarkBeast.communicate(cmd_string)

        Raise:
            DarkBeastException:  process not open, communicate error!

        '''
        if self.process is not None:
            self.process.stdin.write(command + "\n")
            self.process.stdin.flush()
            if DarkBeastCMDDef.EXIT == command:
                self.process = None
                return DarkBeastDef.EXIT_STRING
            else:
                return self._capture_by_flag()

        raise DarkBeastException('process not open, communicate error!')

    def aid_connect_set(self, status):
        '''
        AID connect to dut enable or disable

        Args:
            status:  string, ['enable', 'disable'].

        Returns:
            string, "done", api execution successful.

        Examples:
            DarkBeast.aid_connect_set(1)

        '''
        assert status in ('enable', 'disable')
        if status == 'enable':
            level = 1
        else:
            level = 0
        if self.gpio:
            self.gpio.set_level(level)

        return 'done'

    def io_set(self, io_name, level):
        '''
        DarkBeast io control.

        Args:
            io_name:  string, ['PULL_UP', 'PULL_DOWN', 'TX_EN', 'CONNECT_DETECTION', 'REMOVAL_DETECTION',
                               'A0', 'A1', 'A2', 'ELAOD_EN'], io_name can be found in the table below.

                +---------------------+----------------------------------+
                |     io  name        |            io  meaning           |
                +=====================+==================================+
                |  PULL_UP            |  Data line pull-up control,      |
                |                     |  Provider mode.                  |
                +---------------------+----------------------------------+
                |  PULL_DOWN          |  Data line pull-down control,    |
                |                     |  Consumer mode.                  |
                +---------------------+----------------------------------+
                |  TX_EN              |  UART_TX buffer enable control   |
                +---------------------+----------------------------------+
                |  CONNECT_DETECTION  |  input pin control, detect       |
                |                     |  whether the DUT is connected.   |
                +---------------------+----------------------------------+
                |  REMOVAL_DETECTION  |  Input pin control, detect       |
                |                     |  disconnection from DUT.         |
                +--------------------------------------------------------+
                |       A0            |  ORION_COMM_CONN connect         |
                |                     |  PPVBUS_ORION_CONN.              |
                +---------------------+----------------------------------+
                |       A1            |  GND connect ORION_COMM_CONN     |
                +---------------------+----------------------------------+
                |       A2            |  GND connect PPVBUS_ORION_CONN   |
                +---------------------+----------------------------------+
                |       ELAOD_EN      |  A0, A1, A2 control1 disabled or |
                |                     |  enabled  (1/disabled  0/enabled)|
                +---------------------+----------------------------------+

            level:  int, [0, 1], 0/1 means lower/high

        Returns:
            string, "done", api execution successful.

        Examples:
            darkbeast.io_set("PULL_UP", 1)

        '''
        assert io_name in [
            "PULL_UP", "PULL_DOWN", "TX_EN", "CONNECT_DETECTION",
            "REMOVAL_DETECTION", "A0", "A1", "A2", "ELAOD_EN"
        ]

        device = self.pin_def[io_name]
        device.set_level(level)

        return 'done'

    def io_get(self, io_name):
        '''
        DarkBeast io level get

        Args:
            io_name:  string, ['PULL_UP', 'PULL_DOWN', 'TX_EN', 'CONNECT_DETECTION', 'REMOVAL_DETECTION',
                               'A0', 'A1', 'A2', 'ELAOD_EN'], io_name can be found in the table below.

                +---------------------+----------------------------------+
                |     io  name        |            io  meaning           |
                +=====================+==================================+
                |  PULL_UP            |  Data line pull-up control,      |
                |                     |  Provider mode.                  |
                +---------------------+----------------------------------+
                |  PULL_DOWN          |  Data line pull-down control,    |
                |                     |  Consumer mode.                  |
                +---------------------+----------------------------------+
                |  TX_EN              |  UART_TX buffer enable control   |
                +---------------------+----------------------------------+
                |  CONNECT_DETECTION  |  input pin control, detect       |
                |                     |  whether the DUT is connected.   |
                +---------------------+----------------------------------+
                |  REMOVAL_DETECTION  |  Input pin control, detect       |
                |                     |  disconnection from DUT.         |
                +--------------------------------------------------------+
                |       A0            |  ORION_COMM_CONN connect         |
                |                     |  PPVBUS_ORION_CONN.              |
                +---------------------+----------------------------------+
                |       A1            |  GND connect ORION_COMM_CONN     |
                +---------------------+----------------------------------+
                |       A2            |  GND connect PPVBUS_ORION_CONN   |
                +---------------------+----------------------------------+
                |       ELAOD_EN      |  A0, A1, A2 control1 disabled or |
                |                     |  enabled  (1/disabled  0/enabled)|
                +---------------------+----------------------------------+

        Returns:
            int, [0, 1], io level.

        Examples:
            level = darkbeast.io_get("PULL_UP")
            print(level)

        '''
        assert io_name in [
            "PULL_UP", "PULL_DOWN", "TX_EN", "CONNECT_DETECTION",
            "REMOVAL_DETECTION", "A0", "A1", "A2", "ELAOD_EN"
        ]

        device = self.pin_def[io_name]

        return device.get_level()
Пример #7
0
class ElektraBase(MIXBoard):
    '''
    Base class of Elektra and ElektraCompatible.

    Args:
        i2c:              instance(I2C)/None,  If not given, PLI2CBus emulator will be created.
        spi:              instance(QSPI)/None, if not given, PLSPIBus emulator will be created.
        ad7608:           instance(ADC)/None,  If not given, AD760X emulator will be created.
        gpio:             instance(GPIO)/None, If not given, PinEmulator emulator will be created.
        volt_ch1:         int, ADC channel id for read voltage ch1.
        volt_ch2:         int, ADC channel id for read voltage ch2.
        curr_ch1:         int, ADC channel id for read current ch1.
        curr_ch2:         int, ADC channel id for read current ch2.
        eeprom_dev_addr:  int, Eeprom device address.
        sensor_dev_addr:  int, NCT75 device address.
        ipcore:           instance(MIXDAQT1SGR), MIXDAQT1SGR IP driver instance, provide QSPI, ad717x
                                                 and gpio function.

    '''

    rpc_public_api = [
        'module_init', 'read_voltage', 'read_current', 'set_cc', 'set_cv',
        'set_cr', 'channel_enable', 'channel_disable', 'reset_board'
    ] + MIXBoard.rpc_public_api

    def __init__(self,
                 i2c=None,
                 spi=None,
                 ad7608=None,
                 gpio=None,
                 volt_ch1=2,
                 volt_ch2=3,
                 curr_ch1=0,
                 curr_ch2=1,
                 eeprom_dev_addr=None,
                 sensor_dev_addr=None,
                 ipcore=None):

        self.ipcore = ipcore
        if (i2c is not None and spi is not None and ad7608 is not None
                and gpio is not None):
            spi.set_mode('MODE2')
            self.cat9555 = CAT9555(ElektraDef.CAT9555_ADDR, i2c)
            self.eeprom = CAT24C32(eeprom_dev_addr, i2c)
            self.sensor = NCT75(sensor_dev_addr, i2c)
            self.ad5663 = AD5663R(spi, ElektraDef.DAC_MV_REF,
                                  ElektraDef.DAC_MODE_REF)
            self.ad7608 = ad7608
            self.gpio = gpio
        elif (ipcore is not None and i2c is not None):
            self.spi = ipcore.spi
            self.spi.set_mode('MODE2')
            self.ad5663 = AD5663R(ipcore.spi, ElektraDef.DAC_MV_REF,
                                  ElektraDef.DAC_MODE_REF)
            self.gpio = None
            self.cat9555 = CAT9555(ElektraDef.CAT9555_ADDR, i2c)
            self.eeprom = CAT24C32(ElektraDef.EEPROM_DEV_ADDR, i2c)
            self.sensor = NCT75(ElektraDef.SENSOR_DEV_ADDR, i2c)
            self.ad7608 = ad7608 or MIXAD760XSGEmulator(
                "mix_ad760x_sg_emulator")
        elif (i2c is None and spi is None and ad7608 is None and gpio is None):
            self.cat9555 = CAT9555Emulator(ElektraDef.CAT9555_ADDR, None, None)
            self.eeprom = None
            self.sensor = None
            self.ad5663 = AD5663R(spi, ElektraDef.DAC_MV_REF,
                                  ElektraDef.DAC_MODE_REF)
            self.ad7608 = MIXAD760XSGEmulator("mix_ad760x_sg_emulator")
            self.gpio = GPIOEmulator("gpio_emulator")
        else:
            raise ElektraException(
                '__init__ error! Please check the parameters!')
        super(ElektraBase, self).__init__(self.eeprom,
                                          self.sensor,
                                          cal_table=elektra_calibration_info,
                                          range_table=elektra_range_table)
        self.adc_voltage_channel = {'ch1': volt_ch1, 'ch2': volt_ch2}
        self.adc_current_channel = {'ch1': curr_ch1, 'ch2': curr_ch2}

    def module_init(self):
        '''
        Configure GPIO pin default direction and values, initial ad5663 and reset ad7608

        Returns:
            string, "done", api execution successful.

        Examples:
            elektrabase.module_init()

        '''
        self.load_calibration()

        if self.gpio is not None:
            self.gpio.set_dir('output')
            self.gpio.set_level(ElektraDef.AD5663R_PIN_LEVEL)

        self.cat9555.set_pins_dir(ElektraDef.IO_INIT_DIR)
        self.cat9555.set_ports(ElektraDef.IO_INIT_VALUE)

        self.cat9555.set_pin(ElektraDef.CAT9555_BIT['SYNC_AD5663R'],
                             ElektraDef.LOWE_LEVEL)
        self.ad5663.initial()
        self.cat9555.set_pin(ElektraDef.CAT9555_BIT['SYNC_AD5663R'],
                             ElektraDef.HIGH_LEVEL)

        self.ad7608.reset()

        # board reset
        self.reset_board('ch1')
        self.reset_board('ch2')

        return 'done'

    def _read_adc(self, channel):
        '''
        read Ad7608 average value

        Args:
            channel:  int, [0~7], adc channel num.

        Returns:
            float, value, unit mV.

        Examples:
            elektrabase._read_adc(0)

        '''
        assert channel >= 0 and channel <= 7
        COUNT = 30
        STRIP = 5

        # get average value
        value_list = [
            self.ad7608.single_sampling(0, '5V')[channel] for _ in range(COUNT)
        ]
        value_list.sort()
        avg = reduce((lambda x, y: x + y), value_list[STRIP:-STRIP],
                     0) / (COUNT - 2 * STRIP)

        return avg

    def read_voltage(self, channel):
        '''
        Ad7608 voltage read

        Args:
            channel:  string, ['ch1', 'ch2'], adc channel name.

        Returns:
            float, value, unit mV.

        Examples:
            elektrabase.read_voltage('ch1')

        '''
        assert channel in {'ch1', 'ch2'}

        value = self._read_adc(self.adc_voltage_channel[channel])
        value = value / ElektraDef.VOLTAGE_COEFFICIENT

        value = self.calibrate('%s_read_voltage' % channel, value)

        return value

    def read_current(self, channel):
        '''
        Ad7608 current read

        Args:
            channel:  string, ['ch1', 'ch2'], adc channel name.

        Returns:
            float, value, unit mV.

        Examples:
            elektrabase.read_current('ch1')

        '''
        assert channel in {'ch1', 'ch2'}
        value = self._read_adc(self.adc_current_channel[channel])
        value = value / ElektraDef.CURRENT_COEFFICIENT

        value = self.calibrate('%s_read_current' % channel, value)

        return value

    def _output_voltage(self, channel, value):
        '''
        DAC ad5663r output.

        Args:
            channel:  string, ['ch1', 'ch2'], adc channel name.
            value:    float, [0~5000], dac output value unit 'mV', eg.1000.

        Returns:
            string, "done", api execution successful.

        Examples:
            elektrabase._output_voltage(1, 1000)

        '''
        assert channel in {'ch1', 'ch2'}
        assert value <= 5000
        DAC_CHANEL = {'ch1': 0, 'ch2': 1}

        if value < 0:
            value = 0

        if self.gpio is not None:
            self.gpio.set_level(ElektraDef.AD5663R_PIN_LEVEL)

        self.cat9555.set_pin(ElektraDef.CAT9555_BIT['SYNC_AD5663R'],
                             ElektraDef.HIGH_LEVEL)
        self.cat9555.set_pin(ElektraDef.CAT9555_BIT['SYNC_AD5663R'],
                             ElektraDef.LOWE_LEVEL)
        self.ad5663.output_volt_dc(DAC_CHANEL[channel], value)
        self.cat9555.set_pin(ElektraDef.CAT9555_BIT['SYNC_AD5663R'],
                             ElektraDef.HIGH_LEVEL)

        return "done"

    def set_cc(self, channel, value):
        '''
        CC(constant-current) mode set

        Args:
            channel:  string, ['ch1', 'ch2'], adc channel name.
            value:    float, [1~3500], unit mA, CC mode current.

        Returns:
            string, "done", api execution successful.

        Examples:
            elektrabase.set_cc('ch1', 10)

        '''
        assert channel in {'ch1', 'ch2'}
        assert isinstance(value, (int, float))

        value = self.calibrate('%s_set_cc' % channel, value)

        # Iset = a * value + offset, a is coefficent
        Iset = value * ElektraDef.CURRENT_COEFFICIENT + ElektraDef.CURRENT_OFFSET
        io_set = ElektraDef.CAT9555_BIT['Mode_Select' + channel[2:3]]

        self.cat9555.set_pin(io_set, ElektraDef.LOWE_LEVEL)

        self._output_voltage(channel, Iset)

        return "done"

    def set_cv(self, channel, value):
        '''
        CV(constant-voltage) mode set

        Args:
            channel:  string, ['ch1', 'ch2'], adc channel name.
            value:    float, [500~5500], unit mV, CV mode voltage, eg.1000.

        Returns:
            string, "done", api execution successful.

        Examples:
            elektrabase.set_cv('ch1', 10)

        '''
        assert channel in {'ch1', 'ch2'}
        assert isinstance(value, (int, float))

        value = self.calibrate('%s_set_cv' % channel, value)

        # Vset = a * value + offset, a is coefficent
        Vset = value * ElektraDef.VOLTAGE_COEFFICIENT + ElektraDef.VOLTAGE_OFFSET
        io_set = ElektraDef.CAT9555_BIT['Mode_Select' + channel[2:3]]
        self.cat9555.set_pin(io_set, ElektraDef.HIGH_LEVEL)

        self._output_voltage(channel, Vset)

        return "done"

    def set_cr(self, channel, value):
        '''
        CR(constant-resistance) mode set, just set one time not loop

        Args:
            channel:  string, ['ch1', 'ch2'], adc channel name.
            value:    float, [1.6~500], unit Ohm, CR mode resistance, eg.100.

        Returns:
            string, "done", api execution successful.

        Examples:
            elektrabase.set_cr('ch1', 10)

        '''
        assert channel in {'ch1', 'ch2'}
        assert isinstance(value, (int, float))

        voltage = self.read_voltage(channel)
        # I = U / R
        current = voltage / value

        # Iset = a * current + offset, a is coefficent
        Iset = current * ElektraDef.CURRENT_COEFFICIENT + ElektraDef.CURRENT_OFFSET

        Iset = self.calibrate('%s_set_cc' % channel, Iset)

        io_set = ElektraDef.CAT9555_BIT['Mode_Select' + channel[2:3]]
        self.cat9555.set_pin(io_set, ElektraDef.LOWE_LEVEL)

        self._output_voltage(channel, Iset)

        return "done"

    def channel_enable(self, channel):
        '''
        channel enable, Gate_switch and E-load_switch ON

        Args:
            channel:  string, ['ch1', 'ch2'], adc channel name.

        Returns:
            string, "done", api execution successful.

        Examples:
            elektrabase.channel_enable('ch1')

        '''
        assert channel in {'ch1', 'ch2'}

        self.channel_disable(channel)
        io_set = ElektraDef.CAT9555_BIT['ON/OFF' + channel[2:3]]
        self.cat9555.set_pin(io_set, ElektraDef.HIGH_LEVEL)
        io_set = ElektraDef.CAT9555_BIT['E-LOAD_ON/OFF' + channel[2:3]]
        self.cat9555.set_pin(io_set, ElektraDef.HIGH_LEVEL)

        return "done"

    def channel_disable(self, channel):
        '''
        channel disable, Gate_switch and E-load_switch OFF

        Args:
            channel:  string, ['ch1', 'ch2'], adc channel name.

        Returns:
            string, "done", api execution successful.

        Examples:
            elektrabase.channel_disable('ch1')

        '''
        assert channel in {'ch1', 'ch2'}

        io_set = ElektraDef.CAT9555_BIT['ON/OFF' + channel[2:3]]
        self.cat9555.set_pin(io_set, ElektraDef.LOWE_LEVEL)
        io_set = ElektraDef.CAT9555_BIT['E-LOAD_ON/OFF' + channel[2:3]]
        self.cat9555.set_pin(io_set, ElektraDef.LOWE_LEVEL)
        io_set = ElektraDef.CAT9555_BIT['Mode_Select' + channel[2:3]]
        self.cat9555.set_pin(io_set, ElektraDef.LOWE_LEVEL)
        self._output_voltage(channel, 0)

        return "done"

    def reset_board(self, channel):
        '''
        board reset, clear over protect state and disable

        Args:
            channel:  string, ['ch1', 'ch2'], adc channel name.

        Returns:
            string, "done", api execution successful.

        Examples:
            elektrabase.reset_board('ch1')

        '''
        assert channel in {'ch1', 'ch2'}

        self.channel_disable(channel)
        io_set = ElektraDef.CAT9555_BIT['RST' + channel[2:3]]
        self.cat9555.set_pin(io_set, ElektraDef.LOWE_LEVEL)
        self.cat9555.set_pin(io_set, ElektraDef.HIGH_LEVEL)

        return "done"

    def load_legacy_ici_calibration(self):
        '''
        Load ICI calibration data.
        Refactoring mix_board load_legacy_ici_calibration function
        (get item count address, use little endian byte order)

        This function is used to load calibration data defined by ICI Spec 2.7

        '''
        self._calibration_table = {}
        # get calibration base address
        try:
            base_addr = self.read_legacy_ici_cal_start_addr(
            ) + ICIDef.CAL_VERSION_SIZE
        except Exception as e:
            self._cal_common_error = e
            return "done"

        for range_name, index in self._range_table.items():
            self._calibration_table[range_name] = []
            # get range address
            addr = base_addr + index * ICIDef.CAL_RANGE_LEN
            if addr < ICIDef.CAL_AREA_ADDR + ICIDef.CAL_VERSION_SIZE or \
               addr >= ICIDef.CAL_AREA_ADDR + ICIDef.CAL_AREA_SIZE:
                continue
            data = self.read_eeprom(addr, ICIDef.CAL_RANGE_LEN)
            # get item count address, use little endian byte order
            addr = (data[1] << 8) | data[0]
            if addr < ICIDef.CAL_AREA_ADDR + ICIDef.CAL_VERSION_SIZE or \
               addr >= ICIDef.CAL_AREA_ADDR + ICIDef.CAL_AREA_SIZE:
                continue
            count = self.read_eeprom(addr, 1)[0]
            # get cal cell address
            addr += ICIDef.CAL_COUNT_LEN
            if addr < ICIDef.CAL_AREA_ADDR + ICIDef.CAL_VERSION_SIZE or \
               addr >= ICIDef.CAL_AREA_ADDR + ICIDef.CAL_AREA_SIZE:
                self._cal_common_error = ICIException(
                    "Range {} cell address 0x{:x} "
                    "is invalid".format(range_name, addr))
                continue
            if addr + count > ICIDef.CAL_AREA_ADDR + ICIDef.CAL_AREA_SIZE:
                self._cal_common_error = ICIException(
                    "Range {} cell count {} is invalid".format(
                        range_name, count))
                continue

            for i in range(count):
                data = self.read_eeprom(addr, ICIDef.CAL_CELL_LEN)
                addr = addr + ICIDef.CAL_CELL_LEN
                s = struct.Struct('16B')
                pack_data = s.pack(*data)

                s = struct.Struct('3f4B')
                result = s.unpack(pack_data)
                if result[3] != ICIDef.CAL_SAVE_FLAG:
                    self._calibration_table[range_name].append({
                        'gain': 1.0,
                        "offset": 0.0,
                        "threshold": 0.0,
                        "is_use": False
                    })
                else:
                    self._calibration_table[range_name].append({
                        "gain":
                        result[0],
                        "offset":
                        result[1],
                        "threshold":
                        result[2],
                        "is_use":
                        True
                    })
        return "done"