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 __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 __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 __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')
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"
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()
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"