def configure(self, polarity=None, presc=None, filter=None, msec=None, confirm=True): """ Re-configure some capture parameters. None = unchanged polarity: 0,1 active level presc: 1,2,4,8 pulse counter prescaller filter: 0-15 digital input filter msec: <65535 milliseconds for direct capture """ if polarity is not None: pb = gex.PayloadBuilder() pb.u8(polarity) # 0,1 self._send(CMD_SET_POLARITY, pld=pb.close(), confirm=confirm) if presc is not None: pb = gex.PayloadBuilder() pb.u8(presc) self._send(CMD_SET_DIR_PRESC, pld=pb.close(), confirm=confirm) if filter is not None: pb = gex.PayloadBuilder() pb.u8(filter) self._send(CMD_SET_INPUT_FILTER, pld=pb.close(), confirm=confirm) if msec is not None: pb = gex.PayloadBuilder() pb.u16(msec) self._send(CMD_SET_DIR_MSEC, pld=pb.close(), confirm=confirm)
def indirect_burst(self, count, timeout=5): """ Perform a burst measure with averaging (sum/count) """ pb = gex.PayloadBuilder() pb.u16(count) resp = self._query(CMD_INDIRECT_BURST_START, pld=pb.close(), timeout=timeout) pp = gex.PayloadParser(resp.data) mhz = pp.u16() nsamp = pp.u16() period = pp.u64() ontime = pp.u64() rp = FCAP_Report() rp.period = period / (nsamp * mhz * 1e6) # to seconds rp.frequency = 1 / rp.period rp.ontime = ontime / (nsamp * mhz * 1e6) # in seconds rp.duty = rp.ontime / rp.period rp.clock_freq = mhz * 1e6 rp.sample_count = 1 rp.period_raw = period rp.ontime_raw = ontime return rp
def waveform(self, channel, waveform, confirm=True): """ Set a waveform. For DC or rectangle, use the dedicated functions with extra parameters channel: 1,2 (3 = both) waveform: - None - leave unchanged - SINE - TRIANGLE - SAW_UP - SAW_DOWN """ lookup = { 'SINE': CMD_WAVE_SINE, 'SIN': CMD_WAVE_SINE, 'TRI': CMD_WAVE_TRIANGLE, 'TRIANGLE': CMD_WAVE_TRIANGLE, 'SAW': CMD_WAVE_SAWTOOTH_UP, 'RAMP': CMD_WAVE_SAWTOOTH_UP, 'RAMP_UP': CMD_WAVE_SAWTOOTH_UP, 'SAW_UP': CMD_WAVE_SAWTOOTH_UP, 'SAW_DOWN': CMD_WAVE_SAWTOOTH_DOWN, 'RAMP_DOWN': CMD_WAVE_SAWTOOTH_DOWN, } if channel != 1 and channel != 2 and channel != 3: raise Exception("Bad channel arg: %s" % channel) pb = gex.PayloadBuilder() pb.u8(channel) # 0b01 or 0b10 self._send(lookup[waveform], pld=pb.close(), confirm=confirm)
def set_button_thresholds(self, thresholds, confirm=True): """ Set binary report thresholds """ pb = gex.PayloadBuilder() for t in thresholds: pb.u16(t) self._send(CMD_SET_BIN_THR, pb.close(), confirm=confirm)
def write(self, payload, addr=0, confirm=True): """ Write to a device """ pb = gex.PayloadBuilder() pb.u64(addr) pb.blob(payload) self._send(10, pb.close(), confirm=confirm)
def pulse_ms(self, ms, pins=0b01, active=True, confirm=True): """ Send a pulse with length 1-65535 ms on selected pins """ pb = gex.PayloadBuilder() pb.u16(self.pins2int(pins)) pb.bool(active) pb.bool(False) pb.u16(ms) self._send(CMD_PULSE, pb.close(), confirm=confirm)
def pulse_us(self, us, pins=1, active=True, confirm=True): """ Send a pulse of 1-999 us on selected pins """ pb = gex.PayloadBuilder() pb.u16(self.pins2int(pins)) pb.bool(active) pb.bool(True) pb.u16(us) self._send(CMD_PULSE, pb.close(), confirm=confirm)
def gw_add_nodes(self, nodes): pb = gex.PayloadBuilder() pb.u8(ord('n')) pb.u8(len(nodes)) for n in nodes: pb.u8(n) self.gw_write_raw(pb)
def arm(self, pins, auto: bool = False, confirm: bool = False): """ Arm pins for single shot event generation pins - array of pin indices to arm auto - use auto trigger (auto re-arm after hold-off) """ pb = gex.PayloadBuilder() pb.u16(self.pins2int(pins)) self._send(0x02 if auto else 0x01, pb.close())
def disarm(self, pins, confirm: bool = False): """ DisArm pins pins - array of pin indices to arm """ pb = gex.PayloadBuilder() pb.u16(self.pins2int(pins)) self._send(0x03, pb.close())
def ini_write(self, buffer): """ Read the settings INI file """ if type(buffer) == str: buffer = buffer.encode('utf-8') pb = gex.PayloadBuilder() pb.u32(len(buffer)) self.bulk_write(cs=None, pld=pb.close(), cmd=gex.MSG_INI_WRITE, bulk=buffer)
def set_duty(self, duty_dict, confirm=True): """ Set duty (dict - number1234 -> duty 0-1000) """ pb = gex.PayloadBuilder() for (k, v) in enumerate(duty_dict): pb.u8(k - 1) pb.u16(v) self._send(CMD_SET_DUTY, pb.close(), confirm=confirm)
def dc_dual(self, ch1, ch2, confirm=True): """ Set DC levels, 0-4095 """ pb = gex.PayloadBuilder() pb.u8(0b11) pb.u16(ch1) pb.u16(ch2) self._send(CMD_WAVE_DC, pld=pb.close(), confirm=confirm)
def set_active_channels(self, channels, confirm=True): """ Set which channels should be active. """ pb = gex.PayloadBuilder() pb.u32(self.pins2int(channels)) self._send(cmd=CMD_ENABLE_CHANNELS, pld=pb.close(), confirm=confirm) self.channels = self.pins2list(channels)
def query(self, request, rcount, addr=0, verify=True, as_array=False): """ Query a device """ pb = gex.PayloadBuilder() pb.u64(addr) pb.u16(rcount) pb.bool(verify) pb.blob(request) resp = self._query(11, pb.close()) return resp.data if not as_array else list(resp.data)
def set_frequency_dual(self, freq1, freq2, confirm=True): """ Set frequency of both channels using float in Hz """ pb = gex.PayloadBuilder() pb.u8(0b11) pb.float(freq1) pb.float(freq2) self._send(CMD_SET_FREQUENCY, pld=pb.close(), confirm=confirm)
def load(self, colors, reverse=True, confirm=True): """ Load colors to the strip. The numbers are normally 0xRRGGBB If 'reverse' is false, they're treated as little-endian: 0xBBGGRR. """ pb = gex.PayloadBuilder(endian='big' if reverse else 'little') for c in colors: pb.u24(c) self._send(1, pb.close(), confirm=confirm)
def set_phase_dual(self, phase1, phase2, confirm=True): """ Set phase for both channels at once """ pb = gex.PayloadBuilder() pb.u8(0b11) pb.u16((phase1 / 360) * LUT_LEN) pb.u16((phase2 / 360) * LUT_LEN) self._send(CMD_SET_PHASE, pld=pb.close(), confirm=confirm)
def gw_get_net_id(self): if self._address is not None: # lazy load return self._address pb = gex.PayloadBuilder() pb.u8(ord('i')) self.gw_write_raw(pb) self.poll(0.5, lambda: self._address is not None) return self._address
def load(self, buffers, end=0x0000, confirm=True): """ Load data - buffers is a list of lists or byte arrays """ if type(buffers[0]) == int: buffers = [buffers] pb = gex.PayloadBuilder() pb.u16(end) for b in buffers: pb.blob(b) self._send(CMD_WRITE, pb.close(), confirm=confirm)
def write(self, payload, sync=False, confirm=True): """ Write bytes. If 'sync' is True, wait for completion. sync implies confirm """ if type(payload) is str: payload = payload.encode('utf-8') pb = gex.PayloadBuilder() pb.blob(payload) # payload to write self._send(0x01 if sync else 0x00, pb.close(), confirm=confirm or sync)
def direct_burst(self, msec=1000, presc=None): """ Perform direct burst measurement """ pb = gex.PayloadBuilder() pb.u16(msec) pb.u8(presc or 0) resp = self._query(CMD_DIRECT_BURST_START, pld=pb.close(), timeout=(msec / 1000) + 1) return self._process_direct_resp(resp)
def write(self, buffer): # multipart sending pb = gex.PayloadBuilder() pb.u8(ord('m')) pb.u8(self._slaveAddr) pb.u16(len(buffer)) ck = 0 for c in buffer: ck ^= c ck = 0xFF & ~ck pb.u8(ck) start = 0 spaceused = len(pb.buf) fits = min(64 - spaceused, len(buffer)) pb.blob(buffer[start:fits]) # TODO rewrite this to send_raw if (spaceused + fits) < 64: pb.zeros(64 - (spaceused + fits)) start += fits buf = pb.close() self._transport.write(buf) while start < len(buffer): pb = gex.PayloadBuilder() fits = min(64, len(buffer) - start) pb.blob(buffer[start:start + fits]) start += fits if fits < 64: pb.zeros(64 - fits) buf = pb.close() self._transport.write(buf)
def set_sample_rate(self, freq: int): """ Set sample rate in Hz. Returns the real achieved frequency as float. """ pb = gex.PayloadBuilder() pb.u32(freq) msg = self._query(CMD_SET_SAMPLE_RATE, pld=pb.close()) pp = gex.PayloadParser(msg.data) req = pp.u32() real = pp.float() self.sample_rate = real return real
def direct_start(self, msec=None, presc=None, confirm=True): """ Start continuous PWM measurement msec - measurement time (ms), <65535 presc - pre-divider, 1,2,4,8. arg None = unchanged """ pb = gex.PayloadBuilder() pb.u16(msec or 0) pb.u8(presc or 0) self._send(CMD_DIRECT_CONT_START, pld=pb.close(), confirm=confirm)
def arm(self, auto=None, confirm=True): """ ARM for trigger. The trigger must be configured first. if auto is True or False, it sets the auto-rearm flag. """ pb = gex.PayloadBuilder() if auto is None: pb.u8(255) else: pb.u8(1 if auto else 0) self._send(cmd=CMD_ARM, pld=pb.close(), confirm=confirm)
def set_frequency(self, channel, freq, confirm=True): """ Set frequency using float in Hz """ if channel != 1 and channel != 2 and channel != 3: raise Exception("Bad channel arg: %s" % channel) pb = gex.PayloadBuilder() pb.u8(channel) pb.float(freq) if channel == 3: pb.float(freq) self._send(CMD_SET_FREQUENCY, pld=pb.close(), confirm=confirm)
def setup_trigger(self, channel, level, count, edge='rising', pretrigger=0, holdoff=100, auto=False, confirm=True, handler=None): """ Configure a trigger. channel - 0-17 (16-tsense, 17-vrefint) level - triggering threshold, raw (0-4095) count - nbr of samples to capture after trigger edge - "rising", "falling" or "both" pretrigger - nbr of samples to capture before the trigger occurred. Limited by the internal buffer. holdoff - hold-off time (trigger also can't fire while the capture is ongoing, and if it's not armed) auto - auto re-arm after completing the capture. Normally the state switches to IDLE. handler - attaches a callback handler for the received data """ nedge = 0 if edge == 'rising' or edge == 'up': nedge = 1 elif edge == 'falling' or edge == 'down': nedge = 2 elif edge == 'both': nedge = 3 else: raise Exception("Bad edge arg") pb = gex.PayloadBuilder() pb.u8(channel) pb.u16(level) pb.u8(nedge) pb.u32(pretrigger) pb.u32(count) pb.u16(holdoff) pb.bool(auto) self._send(cmd=CMD_SETUP_TRIGGER, pld=pb.close(), confirm=confirm) if handler is not None: self._trig_listener = handler
def set_phase(self, channel, phase360, confirm=True): """ Set channel phase relative to it's "base phase". If both channels use the same frequency, this could be used for drawing XY figures. """ if channel != 1 and channel != 2 and channel != 3: raise Exception("Bad channel arg: %s" % channel) pb = gex.PayloadBuilder() pb.u8(channel) pb.u16(round((phase360 / 360) * LUT_LEN)) if channel == 3: pb.u16(round((phase360 / 360) * LUT_LEN)) self._send(CMD_SET_PHASE, pld=pb.close(), confirm=confirm)
def rectangle(self, channel, duty=None, high=None, low=None, confirm=True): """ Enter rectangle gen mode (duty 0..1000) """ if channel != 1 and channel != 2 and channel != 3: raise Exception("Bad channel arg: %s" % channel) pb = gex.PayloadBuilder() pb.u8(channel) # 0b01 or 0b10 for i in range(0, 1 if channel != 3 else 2): # repeat if dual pb.u16( round(duty * LUT_LEN) if duty is not None # todo ?? else 0xFFFF) pb.u16(high if high is not None else 0xFFFF) pb.u16(low if low is not None else 0xFFFF) self._send(CMD_WAVE_RECTANGLE, pld=pb.close(), confirm=confirm)