class HWSPI(SPI): """ Hardware SPI """ def __init__(self, device, ce, config): """ Args: device (int): the number of SPI device ce (int): the number of chip select of SPI device config (SPIConfig): """ self._device = device self._ce = ce self._config = config self._spi = SpiDev() def open(self): logger.info("Open SPI(%d,%d)", self._device, self._ce) self._spi.open(self._device, self._ce) self._spi.mode = self._config.mode self._spi.max_speed_hz = self._config.speed def close(self): logger.info("Close SPI(%d,%d)", self._device, self._ce) self._spi.close() def transfer(self, writedata, readsize): buf = self._spi.xfer(writedata + [0] * readsize) return buf[len(writedata):]
def read_touch_screen(channel): """Read the HackPack touchscreen coordinates.""" spi = SpiDev() spi.open(1, 0) spi.no_cs = True spi.max_speed_hz = 2000000 # Manual chip select GPIO.output(CS_TOUCH, 1) GPIO.output(CS_TOUCH, 0) responseData = spi.xfer([channel, 0, 0]) GPIO.output(CS_TOUCH, 1) spi.close() return (responseData[1] << 5) | (responseData[2] >> 3)
class MCP3008: def __init__(self, bus=0, device=0): self.bus, self.device = bus, device self.spi = SpiDev() self.open() def open(self): self.spi.open(self.bus, self.device) self.spi.max_speed_hz = 1350000 def read(self, channel=0): adc = self.spi.xfer([1, (8 + channel) << 4, 0]) #print (adc) data = ((adc[1] & 3) << 8) + adc[2] return data def close(self): self.spi.close()
class SPI2ADC: def __init__(self, bus=0, device=0): self.bus = bus self.device = device self.spi = SpiDev() self.open() def open(self): self.spi.open(self.bus, self.device) self.spi.max_speed_hz = 1000000 def read(self, channel = 0): adc = self.spi.xfer([0xbe, 0xef]) #adc = self.spi.xfer2([0x01, 0x08, 0]) #data = ((adc[1] & 3) << 8) + adc[2] return adc #return data def close(self): self.spi.close()
class PiFaceGpioDigital(PiFaceGPIO): """PiFace GPIO pin implementing SPI.""" ADDR_0 = 0x01000000 # 0x40 [0100 0000] ADDR_1 = 0x01000010 # 0x42 [0100 0010] ADDR_2 = 0x01000100 # 0x44 [0100 0100] ADDR_3 = 0x01000110 # 0x46 [0100 0110] DEF_ADDR = ADDR_0 REGISTER_IODIR_A = 0x00 REGISTER_IODIR_B = 0x01 REGISTER_GPINTEN_A = 0x04 REGISTER_GPINTEN_B = 0x05 REGISTER_DEFVAL_A = 0x06 REGISTER_DEFVAL_B = 0x07 REGISTER_INTCON_A = 0x08 REGISTER_INTCON_B = 0x09 REGISTER_IOCON_A = 0x0A REGISTER_IOCON_B = 0x0B REGISTER_GPPU_A = 0x0C REGISTER_GPPU_B = 0x0D REGISTER_INTF_A = 0x0E REGISTER_INTF_B = 0x0F REGISTER_INTCAP_A = 0x10 REGISTER_INTCAP_B = 0x11 REGISTER_GPIO_A = 0x12 REGISTER_GPIO_B = 0x13 GPIO_A_OFFSET = 0 GPIO_B_OFFSET = 1000 IOCON_UNUSED = 0x01 IOCON_INTPOL = 0x02 IOCON_ODR = 0x04 IOCON_HAEN = 0x08 IOCON_DISSLW = 0x10 IOCON_SEQOP = 0x20 IOCON_MIRROR = 0x40 IOCON_BANK_MODE = 0x80 BUS_SPEED = 1000000 WRT_FLAG = 0x00 RD_FLAG = 0x01 def __init__(self, pn, initial_val, spi_address, spi_speed): """Initialize a new instance of the raspy.io.pi_face_gpio_digital.PiFaceGpioDigital class. :param raspy.io.pi_face_pins.PiFacePin pn: The PiFace pin to control. :param int initial_val: The initial value (state) to set the pin to. Default is PinState.LOW. :param int spi_address: The SPI address to use. (Should be ADDRESS_0, ADDRESS_1, ADDRESS_2, or ADDRESS_3). :param int spi_speed: The clock speed to set the bus to. Can be powers of 2 (500KHz minimum up to 32MHz maximum). If not specified, the default of SPI_SPEED (1MHz) will be used. :raises: raspy.io.io_exception.IOException if unable to read or write to the SPI bus. """ PiFaceGPIO.__init__(self, pn, initial_val, pn.name) if spi_speed is None or not isinstance(spi_speed, (int, long)): spi_speed = self.BUS_SPEED self.__speed = spi_speed self.__spi = SpiDev() try: self.__spi.open(0, 0) except Exception: raise IOException("Unable to open SPI device 0 on bus 0.") self.__spi.max_speed_hz = self.__speed self.__address = self.DEF_ADDR if spi_address is not None: self.__address = spi_address self.__currentStatesA = 0x00000000 self.__currentStatesB = 0x11111111 self.__currentDirectionA = 0x00000000 self.__currentDirectionB = 0x11111111 self.__currentPullupA = 0x00000000 self.__currentPullupB = 0x11111111 self.__oldState = pin_state.LOW self.__pullResistance = pin_pull_resistance.Off self.__pollThread = None self.__pollRunning = False self.__stopEvent = threading.Event() self.__stopEvent.set() # IOCON - I/O EXPANDER CONFIGURATION REGISTER # # bit 7 BANK: Controls how the registers are addressed # 1 = The registers associated with each port are separated into # different banks # 0 = The registers are in the same bank (addresses are sequential) # bit 6 MIRROR: INT Pins Mirror bit # 1 = The INT pins are internally connected # 0 = The INT pins are not connected. INTA is associated with PortA and # INTB is associated with PortB # bit 5 SEQOP: Sequential Operation mode bit. # 1 = Sequential operation disabled, address pointer does not # increment. # 0 = Sequential operation enabled, address pointer increments. # bit 4 DISSLW: Slew Rate control bit for SDA output. # 1 = Slew rate disabled. # 0 = Slew rate enabled. # bit 3 HAEN: Hardware Address Enable bit (MCP23S17 only). # Address pins are always enabled on MCP23017. # 1 = Enables the MCP23S17 address pins. # 0 = Disables the MCP23S17 address pins. # bit 2 ODR: This bit configures the INT pin as an open-drain output. # 1 = Open-drain output (overrides the INTPOL bit). # 0 = Active driver output (INTPOL bit sets the polarity). # bit 1 INTPOL: This bit sets the polarity of the INT output pin. # 1 = Active-high. # 0 = Active-low. # bit 0 Unimplemented: Read as '0'. # # write io configuration. enable hardware address. self.__write(self.REGISTER_IOCON_A, self.IOCON_SEQOP | self.IOCON_HAEN) self.__write(self.REGISTER_IOCON_B, self.IOCON_SEQOP | self.IOCON_HAEN) # read initial GPIO pin states self.__currentStatesA = self.__read(self.REGISTER_GPIO_A) self.__currentStatesB = self.__read(self.REGISTER_GPIO_B) # set all default pin pull up resistors # (1 = Pull-up enabled.) # (0 = Pull-up disabled.) self.__write(self.REGISTER_IODIR_A, self.__currentDirectionA) self.__write(self.REGISTER_IODIR_B, self.__currentDirectionB) # set all default pin states self.__write(self.REGISTER_GPIO_A, self.__currentStatesA) self.__write(self.REGISTER_GPIO_B, self.__currentStatesB) # set all default pin pull up resistors # (1 = Pull-up enabled.) # (0 = Pull-up disabled.) self.__write(self.REGISTER_GPPU_A, self.__currentPullupA) self.__write(self.REGISTER_GPPU_B, self.__currentPullupB) # set all default pin interrupts # (if pin direction is input (1), then enable interrupt for pin) # (1 = Enable GPIO input pin for interrupt-on-change event.) # (0 = Disable GPIO input pin for interrupt-on-change event.) self.__write(self.REGISTER_GPINTEN_A, self.__currentDirectionA) self.__write(self.REGISTER_GPINTEN_B, self.__currentDirectionB) # set all default pin interrupt default values # (comparison value registers are not used in this implementation) self.__write(self.REGISTER_DEFVAL_A, 0x00) self.__write(self.REGISTER_DEFVAL_B, 0x00) # set all default pin interrupt comparison behaviors # (1 = Controls how the associated pin value is compared for # interrupt-on-change.) # (0 = Pin value is compared against the previous pin value.) self.__write(self.REGISTER_INTCON_A, 0x00) self.__write(self.REGISTER_INTCON_B, 0x00) # reset/clear interrupt flags if self.__currentDirectionA > 0: self.__read(self.REGISTER_INTCAP_A) if self.__currentDirectionB > 0: self.__read(self.REGISTER_INTCAP_B) def __write(self, register, data): """Write the specified byte to the specified register. :param int register: The register to write to. This should be one of the register constants. :param int data: A single byte to write to the register. :raises: raspy.io.io_exception.IOException if unable to write to the SPI bus. """ # create packet in data buffer. packet = [ self.__address | self.WRT_FLAG, # address byte register, # register byte data # data byte ] try: self.__spi.writebytes(packet) except (IOError, SystemError, RuntimeError) as ex: err_msg = "Failed to write to SPI bus device at address " err_msg += str(self.__address) + " on channel /dev/spidev0.0" err_msg += str(ex) raise IOException(err_msg) def __read(self, register): """Read a single byte from the specified register. :param int register: The register to write to. This should be one of the register constants. :returns: The byte read. :rtype: int :raises: raspy.io.io_exception.IOException if unable to read from the SPI bus. """ # create packet in data buffer. packet = [ self.__address | self.RD_FLAG, # address byte register, # register byte 0x00000000 # data byte ] result = 0 try: temp = self.__spi.xfer(packet, self.__speed) if temp is not None: result = temp[2] & 0xFF except (IOError, SystemError, RuntimeError) as ex: err_msg = "Failed to write to SPI bus device at address " err_msg += str(self.__address) + " on channel /dev/spidev0.0" err_msg += str(ex) raise IOException(err_msg) return result def __set_state_a(self, state): """Set the state of this pin if on Port A (outputs). :param int state: The state to set. :raises: raspy.io.io_exception.IOException if unable to write to the SPI port. """ # determine pin address. pin_address = self.inner_pin.value - self.GPIO_A_OFFSET # determine state value for pin bit if state == pin_state.HIGH: self.__currentStatesA |= pin_address else: self.__currentStatesA &= ~pin_address # update state value. self.__write(self.REGISTER_GPIO_A, self.__currentStatesA) def __set_state_b(self, state): """Set the state of this pin if on Port B (inputs). :param int state: The state to set. :raises: raspy.io.io_exception.IOException if unable to write to the SPI port. """ # determine pin address pin_address = self.inner_pin.value - self.GPIO_B_OFFSET # determine state value for pin bit if state == pin_state.HIGH: self.__currentStatesB |= pin_address else: self.__currentStatesB &= ~pin_address # update state value. self.__write(self.REGISTER_GPIO_B, self.__currentStatesB) def __set_state(self, state): """Set the state of this pin. :param int state: The state to set. :raises: raspy.io.io_exception.IOException if unable to write to the SPI port. """ if self.state == state: return self.__oldState = self.state PiFaceGPIO.write(self, state) # determine A or B port based on pin address. if self.inner_pin.value == self.GPIO_B_OFFSET: self.__set_state_a(state) else: self.__set_state_b(state) def write(self, state): """Write a value to the pin. :param int state: The pin state value to write to the pin. :raises: raspy.ObjectDisposedException if this instance has been disposed. """ if self.is_disposed: raise ObjectDisposedException("PiFaceGpioDigital") PiFaceGPIO.write(self, state) self.__set_state(state) def __evaluate_pin_for_change_a(self, state): """Evaluate Port A for pin change. If the state is different compared to the specified state, then emits a raspy.io.gpio.EVENT_GPIO_STATE_CHANGED event. :param int state: The state to check against. """ # determine pin address. pin_address = self.inner_pin.value - self.GPIO_A_OFFSET # determine if state changed. if (state & pin_address) != (self.__currentStatesA & pin_address): # Determine new state value for pin bit. new_state = pin_state.LOW if (state & pin_address) == pin_address: new_state = pin_state.HIGH if new_state == pin_state.HIGH: self.__currentStatesA |= pin_address else: self.__currentStatesA &= ~pin_address # change detected for pin. evt = PinStateChangeEvent(self.__oldState, new_state, pin_address) self.on_pin_state_change(evt) def __evaluate_pin_for_change_b(self, state): """Evaluate Port B for pin change. If the state is different compared to the specified state, then emits a raspy.io.Gpio.EVENT_GPIO_STATE_CHANGED event. :param int state: The state to check against. """ # determine pin address. pin_address = self.inner_pin.value - self.GPIO_B_OFFSET # determine if state changed. if (state & pin_address) != (self.__currentStatesB & pin_address): # Determine new state value for pin bit. new_state = pin_state.LOW if (state & pin_address) == pin_address: new_state = pin_state.HIGH if new_state == pin_state.HIGH: self.__currentStatesB |= pin_address else: self.__currentStatesB &= ~pin_address # change detected for pin. evt = PinStateChangeEvent(self.__oldState, new_state, pin_address) self.on_pin_state_change(evt) def __set_mode_a(self, mode): """Set the mode of this pin on Port A. :param int mode: The pin mode to set. :raises: raspy.io.io_exception.IOException if unable to write to the SPI bus. """ pin_address = self.inner_pin.value - self.GPIO_A_OFFSET if mode == pin_mode.IN: self.__currentDirectionA |= pin_address elif mode == pin_mode.OUT: self.__currentDirectionA &= ~pin_address self.__write(self.REGISTER_IODIR_A, self.__currentDirectionA) self.__write(self.REGISTER_GPINTEN_A, self.__currentDirectionA) def __set_mode_b(self, mode): """Set the mode of this pin on Port B. :param int mode: The pin mode to set. :raises: raspy.io.io_exception.IOException if unable to write to the SPI bus. """ pin_address = self.inner_pin.value - self.GPIO_B_OFFSET if mode == pin_mode.IN: self.__currentDirectionB |= pin_address elif mode == pin_mode.OUT: self.__currentDirectionB &= ~pin_address self.__write(self.REGISTER_IODIR_B, self.__currentDirectionB) self.__write(self.REGISTER_GPINTEN_B, self.__currentDirectionB) def __background_poll(self): """The background (asynchronous) poll cycle routine. This is the callback executed by the poll thread. :raises: raspy.io.IOException if unable to write to the SPI bus. """ while not self.__stopEvent.is_set(): # only process for interrupts if a pin on port A is configured as # an input pin. pin_interrupt_state = -1 if self.__currentDirectionA > 0: # process interrupts for port A. pin_interrupt_a = self.__read(self.REGISTER_INTF_A) # validate that there is at least one interrupt active on port # A. if pin_interrupt_a > 0: # read the current pin states on port A. pin_interrupt_state = self.__read(self.REGISTER_GPIO_A) # is there an interrupt flag on this pin? self.__evaluate_pin_for_change_a(pin_interrupt_state) # only process for interrupts if a pin on port B is configured as # an input pin. if self.__currentDirectionB > 0: # process interrupts for port B. pin_interrupt_b = self.__read(self.REGISTER_INTF_B) # validate that there is at least one interrupt active on port # B. if pin_interrupt_b > 0: # read the current pin states on port B. pin_interrupt_state = self.__read(self.REGISTER_GPIO_B) # is there an interrupt flag on this pin? self.__evaluate_pin_for_change_b(pin_interrupt_state) def cancel_poll(self): """Cancel an input poll cycle (if running) started by poll().""" if self.is_disposed: return if self.__stopEvent.is_set() or self.__pollThread is None: return self.__stopEvent.set() self.__pollRunning = False def poll(self): """Start a pin poll cycle. This will monitor the pin and check for state changes. If a state change is detected, the raspy.io.Gpio.EVENT_GPIO_STATE_CHANGED event will be emitted. The poll cycle runs asynchronously until stopped by the cancel_poll() method or when this object instance is disposed. :raises: raspy.object_disposed_exception.ObjectDisposedException if this instance has been disposed. :raises: raspy.invalid_operation_exception.InvalidOperationException if the poll thread is already running. """ if self.is_disposed: raise ObjectDisposedException("PiFaceGpioDigital") if self.__pollRunning: raise InvalidOperationException("Poll thread already running.") self.__stopEvent.clear() self.__pollThread = threading.Thread(target=self.__background_poll) self.__pollThread.name = "PiFaceGpioPoller" self.__pollThread.daemon = True self.__pollThread.start() self.__pollRunning = True @property def mode(self): """Get the pin mode. :returns: The pin mode. :rtype: int """ return super(PiFaceGPIO, self).mode @mode.setter def mode(self, p_mode): """Set the pin mode. :param int p_mode: The pin mode to set. :raises: raspy.object_disposed_exception.ObjectDisposedException if this instance has been disposed. """ if self.is_disposed: raise ObjectDisposedException("PiFaceGpioDigital") if p_mode is None: p_mode = p_mode.TRI PiFaceGPIO.mode.fset(self, p_mode) # determine A or B port based on pin address if self.inner_pin.value < self.GPIO_B_OFFSET: self.__set_mode_a(p_mode) else: self.__set_mode_b(p_mode) # if any pins are configured as input pins, then we need to start the # interrupt monitoring poll timer. if self.__currentDirectionA > 0 or self.__currentDirectionB > 0: self.poll() else: self.cancel_poll() def provision(self): """Provision this pin. :raises: raspy.ObjectDisposedException if this instance has been disposed. """ self.write(PiFaceGPIO.get_initial_pin_value(self)) def __set_pull_resistance_a(self, resistance): """Set the pin pull-up/down resistance for port A. :param raspy.io.pin_pull_resistance.PinPullResistance resistance: The pin pull resistance flag to set. Can enable the internal pull-up or pull-down resistor, or disable it. :raises: raspy.io.io_exception.IOException if unable to write to the SPI port. """ pin_address = self.inner_pin.value - self.GPIO_A_OFFSET if resistance.value == pin_pull_resistance.PullUp.value: self.__currentPullupA |= pin_address else: self.__currentPullupA &= ~pin_address self.__write(self.REGISTER_GPPU_A, self.__currentPullupA) def __set_pull_resistance_b(self, resistance): """Set the pin pull-up/down resistance for port B. :param raspy.io.pin_pull_resistance.PinPullResistance resistance: The pin pull resistance flag to set. Can enable the internal pull-up or pull-down resistor, or disable it. :raises: raspy.io.io_exception.IOException if unable to write to the SPI port. """ pin_address = self.inner_pin.value - self.GPIO_B_OFFSET if resistance.value == pin_pull_resistance.PullUp.value: self.__currentPullupB |= pin_address else: self.__currentPullupB &= ~pin_address self.__write(self.REGISTER_GPPU_B, self.__currentPullupB) @property def pull_resistance(self): """Get the pin pull-up/down resistance. :returns: The pin pull resistance. :rtype: raspy.io.pin_pull_resistance.PinPullResistance """ return self.__pullResistance @pull_resistance.setter def pull_resistance(self, resistance): """Set the pin pull-up/down resistance. :param raspy.io.pin_pull_resistance.PinPullResistance resistance: The pin pull resistance. :raises: raspy.object_disposed_exception.ObjectDisposedException if this instance has been disposed. :raises: raspy.io.io_exception.IOException if unable to write to the SPI port. """ if self.__pullResistance.value == resistance.value: return if self.is_disposed: raise ObjectDisposedException("PiFaceGpioDigital") self.__pullResistance = resistance if self.inner_pin.value > self.GPIO_B_OFFSET: self.__set_pull_resistance_a(resistance) else: self.__set_pull_resistance_b(resistance) def read(self): """Read a value from the pin. :returns: The state (value) of the pin. :rtype: int :raises: raspy.object_disposed_exception.ObjectDisposedException if this instance has been disposed. :raises: raspy.io.io_exception.IOException if unable to read from the SPI port. """ if self.is_disposed: raise ObjectDisposedException("PiFaceGpioDigital") if self.inner_pin.value < self.GPIO_B_OFFSET: return self.__read(self.REGISTER_GPIO_A) return self.__read(self.REGISTER_GPIO_B) def __get_state_a(self): """Get the state of the pin if on Port A. :returns: The state of the pin. :rtype: int :raises: raspy.io.io_exception.IOException if unable to write to the SPI port. """ pin_address = self.inner_pin.value - self.GPIO_A_OFFSET temp_state = (self.__currentStatesA & pin_address) my_state = pin_state.LOW if temp_state == pin_address: my_state = pin_state.HIGH super(PiFaceGPIO, self).write(my_state) return my_state def __get_state_b(self): """Get the state of the pin if on Port B. :returns: The state of the pin. :rtype: int :raises: raspy.io.io_exception.IOException if unable to write to the SPI port. """ pin_address = self.inner_pin.value - self.GPIO_B_OFFSET temp_state = (self.__currentStatesB & pin_address) my_state = pin_state.LOW if temp_state == pin_address: my_state = pin_state.HIGH super(PiFaceGPIO, self).write(my_state) return my_state @property def state(self): """Get the state of the pin. :returns: The pin state. :rtype: int :raises: raspy.object_disposed_exception.ObjectDisposedException if this instance has been disposed. :raises: raspy.io.io_exception.IOException if unable to read from the SPI port. """ if self.is_disposed: raise ObjectDisposedException("PiFaceGpioDigital") if self.inner_pin.value < self.GPIO_B_OFFSET: result = self.__get_state_a() else: result = self.__get_state_b() return result def dispose(self): """Dispose managed resources. Performs application-defined tasks associated with freeing, releasing, or resetting resources. """ if self.is_disposed: return self.cancel_poll() self.__spi = None super(PiFaceGPIO, self).dispose()
class Lora: def __init__(self, reset_pin, spi_channel=0): gpio.setmode(gpio.BCM) gpio.setup(reset_pin, gpio.OUT) self.reset_pin = reset_pin self.reset() self.spi = SpiDev() self.spi.open(0, spi_channel) self.spi.max_speed_hz = 1000000 atexit.register(self.cleanup) self.settings_cache = {} self.mode = 'SLEEP' self.long_range_mode = 'LoRa' self.fifo_tx_base_addr = 0 self.fifo_rx_base_addr = 0 self.mode = 'STDBY' self.clear_irqs() def cleanup(self): gpio.cleanup() self.spi.close() def connected(self): return self.long_range_mode == 'LoRa' def reset(self): gpio.output(self.reset_pin, 0) time.sleep(0.001) gpio.output(self.reset_pin, 1) time.sleep(0.005) def xfer(self, reg, data=[0]): if type(data) is not list: data = [data] output = self.spi.xfer([reg] + data) time.sleep(0.001) return output def read_reg(self, reg): return self.xfer(reg)[1] def write_reg(self, reg, value): self.xfer(reg | WRITE_BIT, value) def read_data(self, reg, n): return self.xfer(reg, [0] * n)[1:] def _get_setting(self, setting): if setting.num_bytes == 1: reg_value = self.read_reg(setting.reg) v = (reg_value & setting.mask) >> setting.shift else: data = self.read_data(setting.reg, setting.num_bytes) v = int.from_bytes(data, 'big') return setting.decode(v) def _write_setting(self, setting, value): v = setting.encode(value) self.settings_cache[setting.id()] = v if setting.mask != 0xff: r = self.read_reg(setting.reg) & (setting.mask ^ 0xff) self.write_reg(setting.reg, r | v << setting.shift) elif setting.num_bytes == 1: self.write_reg(setting.reg, v) elif setting.num_bytes > 1: vs = list(v.to_bytes(setting.num_bytes, 'big')) self.write_reg(setting.reg, vs) def __getattr__(self, name): setting_class = settings.options.get(name) if setting_class: return self._get_setting(setting_class) return self.__dict__[name] def __setattr__(self, name, value): setting_class = settings.options.get(name) if setting_class: return self._write_setting(setting_class, value) self.__dict__[name] = value @property def irq_flags(self): return IrqFlags(self.read_reg(regs.IRQ_FLAGS)) def clear_irqs(self, flags=IrqFlags(0xff)): self.write_reg(regs.IRQ_FLAGS, flags) def adjust_rssi(self, v): # default freq is 434MHz freq = self.settings_cache.get('carrier_frequency', 434e6) adj = 157 if freq >= 779e6 else 164 return v - adj @property def rx_ready(self): return IrqFlags.RX_DONE in self.irq_flags def read_rx(self): rx_addr = self.read_reg(regs.FIFO_RX_CURRENT_ADDR) self.fifo_addr_ptr = rx_addr n_bytes = self.read_reg(regs.RX_NB_BYTES) payload = self.read_data(regs.FIFO, n_bytes) rssi = self.adjust_rssi(self.read_reg(regs.PKT_RSSI_VALUE)) self.clear_irqs(IrqFlags.RX_DONE) return list(payload), rssi def on_rx(self, pin, func): def callback(*args): data, rssi = self.read_rx() func(data, rssi) gpio.setup(pin, gpio.IN) gpio.add_event_detect(pin, gpio.RISING, callback=callback) # if we're ready now, go for it! if gpio.input(pin): callback() def send(self, data): if not data: return mode_before = self.mode self.mode = 'STDBY' self.fifo_addr_ptr = 0 self.write_reg(regs.FIFO, data) self.write_reg(regs.PAYLOAD_LENGTH, len(data)) self.mode = 'TX' while True: if IrqFlags.TX_DONE in self.irq_flags: self.clear_irqs(IrqFlags.TX_DONE) break time.sleep(0.01) self.mode = mode_before def __repr__(self): lines = [] for name, cls in settings.options.items(): lines.append(f'{cls.__name__}: {getattr(self, name)}') return '\n'.join(lines)
class InputsOutputs: def __init__(self, _HandleShotmachine, _ToMainQueue, _ToIOQueue): # Start logger self.logger = logging.getLogger(__name__) self.logger.info('Starting IO program') # store given variables self.HandleShotmachine = _HandleShotmachine self.ToMainQueue = _ToMainQueue self.ToIOQueue = _ToIOQueue # Get needed settings from settings struct self.HendelSwitch = self.HandleShotmachine["Hardware"]["HendelSwitch"] self.FotoSwitch = self.HandleShotmachine["Hardware"]["FotoSwitch"] self.EnableI2COutputPin = self.HandleShotmachine["Hardware"]["EnableI2COutput"] self.EnableI2COutput = self.HandleShotmachine["Settings"]["EnableI2C"] self.EnableBarcodeScanner = self.HandleShotmachine["Settings"]["EnableBarcodeScanner"] self.EnableSPI = self.HandleShotmachine["Settings"]["EnableSPI"] self.ConfigSwitchPin = self.HandleShotmachine["Hardware"]["ConfigSwitch"] self.ResetArduinoPin = self.HandleShotmachine["Hardware"]["ResetArduino"] self.SPISSPin = self.HandleShotmachine["Hardware"]["SPISSPin"] #self.party_id = self.HandleShotmachine["Settings"]["PartyId"] # import required libraries depending on the current platform if self.HandleShotmachine["Settings"]["OnRaspberry"]: from Functions.MCP230XX.MCP230XX import MCP230XX import RPi.GPIO as GPIO from spidev import SpiDev from smbus import SMBus self.OnRaspberry = True else: from Functions.GPIOEmulator.ShotmachineIOEmulator import GPIO from Functions.GPIOEmulator.ShotmachineIOEmulator import MCP230XX from Functions.GPIOEmulator.ShotmachineIOEmulator import SpiDev from Functions.GPIOEmulator.ShotmachineIOEmulator import SMBus from Functions.GPIOEmulator.ShotmachineIOEmulator import usb_core_emu self.OnRaspberry = False # prepare general variables self.makeshot = False self.shotnumber = 0 self.shotglass = False self.CheckShotglass = True self.ShotHendelState = False self.ShotHendelSend = False self.FotoKnopState = False self.FotoKnopSend = False self.ConfigSwitchState = False self.ConfigSwitchStateSend = False self.flashlightState = 1 self.setflashlight = True self.SetShotLeds = True self.shotLedsState = 0 self.FlushPump = False self.flushnumber = 0 self.busy = False self.run = True self.recievebuffer = '' #Barcode scanner settings self.barcode_vencor_id = 0xac90 self.barcode_product_id = 0x3003 # init GPIO GPIO.setmode(GPIO.BCM) self.GPIO = GPIO self.GPIO.setwarnings(False) self.GPIO.setup(self.EnableI2COutputPin, GPIO.OUT) self.GPIO.setup(self.ResetArduinoPin, GPIO.OUT) self.GPIO.setup(self.SPISSPin, GPIO.OUT) self.GPIO.setup(self.HendelSwitch, GPIO.IN) self.GPIO.setup(self.FotoSwitch, GPIO.IN) self.GPIO.setup(self.ConfigSwitchPin, GPIO.IN) # set GPIO pins self.GPIO.output(self.EnableI2COutputPin, 0) self.GPIO.output(self.ResetArduinoPin, 0) self.GPIO.output(self.SPISSPin, 0) time.sleep(0.1) # init MCP IO extender if self.EnableI2COutput: i2cAddress = 0x20 self.MCP = MCP230XX('MCP23017', i2cAddress, '16bit') self.MCP.set_mode(0, 'output') self.MCP.output(0, 1) time.sleep(0.1) self.MCP.set_mode(1, 'output') self.MCP.output(1, 1) time.sleep(0.1) self.MCP.set_mode(2, 'output') self.MCP.output(2, 1) time.sleep(0.1) self.MCP.set_mode(3, 'output') self.MCP.output(3, 1) time.sleep(0.1) self.MCP.set_mode(4, 'output') self.MCP.output(4, 1) # init I2C bus if self.EnableI2COutput: self.bus = SMBus(1) self.shotdetectorAddress = 0x70 # init SPI if self.EnableSPI: self.spi = SpiDev() self.spi.open(0, 0) self.spi.max_speed_hz = 390000 # start threads self.mainThread = threading.Thread(target=self.main_IO_interface, name='IO_main') self.mainThread.start() #self.queueThread = threading.Thread(target=self.queue_watcher, name='IO_watcher') #self.queueThread.start() self.queueThread = threading.Thread(target=self.checkshotglas, name='Shotglass_watcher') self.queueThread.start() if self.EnableBarcodeScanner: self.queueThread = threading.Thread(target=self.barcodeReaderThreat, name='Barcode_reader') self.queueThread.start() # wrap up init self.logger.info('Input Output program started') def queue_watcher(self): # Watch queue from interface and process commands #self.run = True #while self.run: #if self.recievebuffer == '': try: self.recievebuffer = self.ToIOQueue.get(block=True, timeout=0.1) if self.recievebuffer == "Quit": self.run = False self.logger.info("IO quit") elif "MakeShot" in self.recievebuffer: self.shotnumber = int(self.recievebuffer[-1:]) self.makeshot = True elif "ShotLeds" in self.recievebuffer: self.shotLedsState = int(self.recievebuffer[-1:]) self.SetShotLeds = True elif "Flush" in self.recievebuffer: self.flushnumber = int(self.recievebuffer[-1:]) self.FlushPump = True elif "Flashlight" in self.recievebuffer: self.flashlightState = int(self.recievebuffer[-1:]) self.setflashlight = True elif "Ready" in self.recievebuffer: self.busy = False self.logger.info('Machine ready, checking inputs') self.recievebuffer = '' except queue.Empty: pass #time.sleep(0.1) def main_IO_interface(self): # Main loop that executes the commands while self.run: # Check queue from main program self.queue_watcher() # Make shot if self.makeshot: self.logger.info('Making shot: ' + str(self.shotnumber)) if self.EnableI2COutput: self.MCP.output(self.shotnumber, 0) if self.shotnumber == 0: time.sleep(5) # 8 elif self.shotnumber == 1: time.sleep(6) # 4 elif self.shotnumber == 2: time.sleep(6) # 5 elif self.shotnumber == 3: time.sleep(5) # 5 elif self.shotnumber == 4: time.sleep(6) # 4 self.MCP.output(self.shotnumber, 1) self.makeshot = False time.sleep(1) self.ToMainQueue.put("Done with shot") # Flush pump if self.FlushPump: self.logger.info('Spoelen van pomp: ' + str(self.flushnumber)) if self.EnableI2COutput: self.MCP.output(self.flushnumber, 0) time.sleep(10) #TODO add possibility to stop on command self.MCP.output(self.flushnumber, 1) self.FlushPump = False time.sleep(1) self.ToMainQueue.put("Klaar met spoelen") # Change flashlight state if self.setflashlight: self.setflashlightfunc(self.flashlightState) self.setflashlight = False # Change shot leds state if self.SetShotLeds: self.setShotLedsfunc(self.shotLedsState) self.SetShotLeds = False # Check inputs if not self.busy: self.checkshothandle() self.checkfotoknop() #self.checkArduinoReset() # cleanup GPIO and pumps and close program if self.EnableI2COutput: del self.MCP time.sleep(1) self.GPIO.cleanup() def barcodeReaderThreat(self): # import required libraries for barcode scanner if self.OnRaspberry: from usb import core as usb_core from usb import util as usb_util else: from Functions.GPIOEmulator.ShotmachineIOEmulator import usb_core_emu usb_core = usb_core_emu() # make usb connection to scanner #if self.EnableBarcodeScanner: self.device = usb_core.find(idVendor=self.barcode_vencor_id, idProduct=self.barcode_product_id) self.usbEndpointEmu = namedtuple("usbEndpointEmu", "bEndpointAddress wMaxPacketSize") try: while self.run: # on raspberry, find actual scanner if self.OnRaspberry: if self.device is None: # No scanner found self.logger.error("No barcode scanner found, is it connected and turned on?") connected = False break else: # Found scanner, give it some time to start connected = True time.sleep(5) if connected: # claim the device and it's interface configuration = self.device.get_active_configuration() if self.device.is_kernel_driver_active(0): # fisrt detach scanner from os before it can be claimed self.device.detach_kernel_driver(0) endpoint = self.device[0][(1, 0)][0] self.device.set_configuration() self.logger.info("Barcode reader ready, start scanning") else: # Barcode scanner in emulator mode self.logger.info("Barcode scanner in emulation mode") connected = True endpoint = self.usbEndpointEmu(bEndpointAddress = None, wMaxPacketSize=None) while self.run and connected and self.OnRaspberry: # check usb connection for messages and convert to barcode try: data = self.device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize) read_string = ''.join(chr(e) for e in data) try: read_number = int(read_string) except: read_number = None if read_number != None: self.logger.info("Barcode scanned: " + str(read_number)) self.ToMainQueue.put("Barcode:" + str(read_number)) except usb_core.USBError as e: # error in checking messsages from scanner data = None if e.errno == 110: # timeout, just keep checking continue if e.errno == 19: # Connection lost, try to reconnect self.logger.warning("Connection to barode scanner lost, closed connection if software") connected = False break while self.run and connected and not self.OnRaspberry: # Emulator barcode scanner try: data = self.device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize) read_string = ''.join(chr(e) for e in data) try: read_number = int(read_string) except: read_number = None if read_number != None: self.logger.info("Barcode scanned: " + str(read_number)) self.ToMainQueue.put("Barcode:" + str(read_number)) except Exception as e: if str(e) == 'Timeout': continue else: self.logger.error("Warning in barcode reader: " + e) raise finally: # close connection to barcode scanner on closing if connected and self.OnRaspberry: usb_util.release_interface(self.device, 0) self.logger.info("Closed barcode scanner reader") def checkshothandle(self): # Controleer de sensor van de hendel self.ShotHendelState = self.GPIO.input(self.HendelSwitch) if not self.ShotHendelSend and self.ShotHendelState: self.logger.info('shothendel pulled') self.ToMainQueue.put("Shothendel") self.ShotHendelSend = True self.busy = True if not self.ShotHendelState: self.ShotHendelSend = False def checkArduinoReset(self): # reset function fro arduino, work in progress self.ConfigSwitchState = self.GPIO.input(self.ConfigSwitchPin) if self.ConfigSwitchState: time.sleep(0.5) self.ConfigSwitchState = self.GPIO.input(self.ConfigSwitchPin) if not self.ConfigSwitchStateSend and self.ConfigSwitchState: self.logger.info('Config button pressed, resetting arduino') self.ConfigSwitchStateSend = True self.GPIO.output(self.ResetArduinoPin, 1) time.sleep(1) self.GPIO.output(self.ResetArduinoPin, 0) if not self.ConfigSwitchState: self.ConfigSwitchStateSend = False def checkfotoknop(self): # Controleer fotoknop if self.HandleShotmachine["Settings"]["OnRaspberry"]: self.FotoKnopState = not self.GPIO.input(self.FotoSwitch) else: # in emulation mode the input is inverted self.FotoKnopState = self.GPIO.input(self.FotoSwitch) if not self.FotoKnopSend and self.FotoKnopState: self.logger.info('fotoknop pressed') self.ToMainQueue.put("Fotoknop") self.FotoKnopSend = True self.busy = True if not self.FotoKnopState: self.FotoKnopSend = False def checkshotglas(self): # check Ultrasonic sensor for shotglass detector, takes some time therefore in a separate thread while self.run: if self.EnableI2COutput: try: self.bus.write_byte_data(self.shotdetectorAddress, 0, 0x51) time.sleep(0.3) msb = self.bus.read_byte_data(self.shotdetectorAddress, 2) lsb = self.bus.read_byte_data(self.shotdetectorAddress, 3) measuredRange = (msb << 8) + lsb except: # print("error in i2c") measuredRange = 23 if (measuredRange != 7) or (measuredRange != 110): #print(measuredRange) if measuredRange < 26: #25: self.CheckShotglass = True else: self.CheckShotglass = False if self.shotglass != self.CheckShotglass: self.logger.info('shotglas status changed to: ' + str(int(self.CheckShotglass))) self.ToMainQueue.put("ShotglassState " + str(int(self.CheckShotglass))) self.shotglass = self.CheckShotglass else: if self.shotglass != self.CheckShotglass: self.logger.info('shotglas status changed to: ' + str(int(self.CheckShotglass))) self.ToMainQueue.put("ShotglassState " + str(int(self.CheckShotglass))) self.shotglass = self.CheckShotglass def setflashlightfunc(self, state): # change flashlight mode by sending mode to arduino that controls the leds self.logger.info('changing flashlight state to: ' + str(state)) string_to_send = "state;"+ str(state) + "\n" string_to_bytes = str.encode(string_to_send) self.GPIO.output(self.SPISSPin, 1) time.sleep(0.03) if self.EnableSPI: self.spi.xfer(string_to_bytes) self.GPIO.output(self.SPISSPin, 0) def setShotLedsfunc(self, state): # change leds in shothok by sensing mode to arduino that controls the leds self.logger.info('changing shot leds state to: ' + str(state)) string_to_send = "shot;"+ str(state) + "\n" string_to_bytes = str.encode(string_to_send) self.GPIO.output(self.SPISSPin, 1) time.sleep(0.03) if self.EnableSPI: self.spi.xfer(string_to_bytes) self.GPIO.output(self.SPISSPin, 0)
class LightController(object): def __init__(self, bus = 0, device = 0, pins = 24): self.bus = bus self.device = device self.spi = SpiDev() self.spi.open(bus, device) self.MAX = 0xfff self.MIN = 0x000 self.pins = pins self.light_values = [0 for _ in range(36)] self.send() self.scanning = 0 self.map = {0:1, 1:2, 2:4, 3:5, 4:7, 5:8, 6:10, 7:11, 8:13, 9:14, 10:16, 11:17, 12:19, 13:20, 14:22, 15:23, 16:25, 17:26, 18:28, 19:29, 20:31, 21:32, 22:34, 23:35} self.clear() def set(self, pin, val): assert(pin < self.pins and pin >= 0) if (val >= self.MAX): val = self.MAX if (val < self.MIN): val = self.MIN actual = self.map[pin] self.light_values[actual] = val def send(self): self.spi.xfer(self.light_values[::-1]) def pic_countdown(self, init_delay = 1, delay = 1): time.sleep(init_delay) for i in range(0, 4): self.set(i, self.MAX) self.send() time.sleep(delay) for i in range(4, 8): self.set(i, self.MAX) self.send() time.sleep(delay) for i in range(8, 12): self.set(i, self.MAX) self.send() time.sleep(delay) for i in range(12, 16): self.set(i, self.MAX) self.send() time.sleep(3) self.clear() def scan(self): self.clear() for i in range(0, 10, 2): self.set(i, self.MAX) self.set(i + 1, self.MAX) self.send() time.sleep(0.2) self.clear() for i in range(11, -1, -2): self.set(i, self.MAX) self.set(i - 1, self.MAX) self.send() time.sleep(0.2) self.clear() def scan_success(self): self.clear() self.set(12, self.MAX) self.set(13, self.MAX) self.set(14, self.MAX) self.set(15, self.MAX) self.send() time.sleep(3) self.clear() def cycle(self): for i in range(len(self.light_values)): self.set(i, self.MAX) self.send() print('Light ' + str(i) + " is on") time.sleep(1) self.set(i, self.MIN) self.send() def test(self): num = "" while num != "quit": num = int(input("which light to get lit? ")) self.clear() self.set(num, self.MAX) self.send() def clear(self): for i in range(0, self.pins): self.set(i, self.MIN) self.send() def __del__(self): self.spi.close()
class Dspin_motor(object): __has_toggled_reset_pin = False __spi_lock = None @classmethod def init_toggle_reset_pin(cls, reset_pin): if not cls.__has_toggled_reset_pin: cls.__has_toggled_reset_pin = True #cls.reset_gpio = LED(reset_pin) #cls.reset_gpio.on() #time.sleep(0.1) #cls.reset_gpio.off() #time.sleep(0.1) #cls.reset_gpio.on() #time.sleep(0.1) Dspin_motor.__spi_lock = threading.Lock() def __init__(self, bus, cs_pin, slave_select_pin, reset_pin): print('setting up dspin interface on pins: ', bus, cs_pin, slave_select_pin, reset_pin) Dspin_motor.init_toggle_reset_pin(reset_pin) self.reset_gpio = LED(reset_pin) self.reset_gpio.on() time.sleep(0.1) self.reset_gpio.off() time.sleep(0.1) self.reset_gpio.on() time.sleep(0.1) self.slave_select_gpio = LED(slave_select_pin) self.spi = SpiDev() self.slave_select_gpio.on() self.spi.open(bus, cs_pin) self.spi.max_speed_hz = 10000 self.spi.mode = 3 self.spi.lsbfirst = False #spi.no_cs = True #spi.loop = False self.connect_l6470() self.last_steps_count_time = datetime.datetime.now() self.current_speed = 0 self.absolute_pos_manual_count = 0 def dspin_xfer(self, data): data = data & 0xFF self.slave_select_gpio.off() result = self.spi.xfer([data]) #spi.writebytes([data]) #result = spi.readbytes(1) #print('xfering ' + hex(data)) self.slave_select_gpio.on() return result[0] def dspin_GetParam(self, param): self.dspin_xfer(dSPIN_GET_PARAM | param) return self.dspin_ParamHandler(param, 0) def dspin_SetParam(self, param, value): self.dspin_xfer(dSPIN_SET_PARAM | param) self.dspin_ParamHandler(param, value) def dspin_ParamHandler(self, param, value): if param == dSPIN_CONFIG: return self.dspin_param(value, 16) elif param == dSPIN_STATUS: return self.dspin_param(0, 16) elif param == dSPIN_STEP_MODE: return self.dspin_xfer(value) elif param in [dSPIN_KVAL_RUN, dSPIN_KVAL_ACC, dSPIN_KVAL_DEC]: return self.dspin_xfer(value) elif param == dSPIN_ACC: return self.dspin_param(value, 12) elif param == dSPIN_MAX_SPEED: return self.dspin_param(value, 10) elif param == dSPIN_MIN_SPEED: return self.dspin_param(value, 12) elif param == dSPIN_FS_SPD: return self.dspin_param(value, 10) elif param == dSPIN_OCD_TH: return self.dspin_xfer(value & 0x0F) elif param == dSPIN_ABS_POS: return self.dspin_param(value, 22) else: raise Exception('not implemented: ' + str(param)) def dspin_param(self, value, bit_length): byte_len = int(math.ceil(bit_length / 8.)) mask = 0xffffffff >> (32 - bit_length) if value > mask: value = mask result = 0 if byte_len == 3: result = result | (self.dspin_xfer(value>>16) << 16) if byte_len >= 2: result = result | (self.dspin_xfer(value>>8) << 8) if byte_len >= 1: result = result | (self.dspin_xfer(value)) return result & mask def dspin_GetStatus(self): Dspin_motor.__spi_lock.acquire() temp = 0 self.dspin_xfer(dSPIN_GET_STATUS) temp = self.dspin_xfer(0) << 8 temp |= self.dspin_xfer(0) Dspin_motor.__spi_lock.release() return temp def dspin_Run(self, dir, speed): speed = int(speed) # print('speed: ', speed) Dspin_motor.__spi_lock.acquire() self.dspin_xfer(dSPIN_RUN | dir) if speed > 0xFFFFF: speed = 0xFFFFF self.dspin_xfer(speed >> 16) self.dspin_xfer(speed >> 8) self.dspin_xfer(speed) Dspin_motor.__spi_lock.release() self.current_speed = speed * (1 if dir == FWD else -1) def dspin_SoftStop(self): Dspin_motor.__spi_lock.acquire() self.dspin_xfer(dSPIN_SOFT_STOP) Dspin_motor.__spi_lock.release() def dspin_SpdCalc(self, stepsPerSec): result = stepsPerSec * 67.106 #if result > 0x3FFF: # result = 0x3FFF # print('speed result: ', int(result)) return int(result) def dspin_GetPositionSteps(self): Dspin_motor.__spi_lock.acquire() result = self.dspin_GetParam(dSPIN_ABS_POS) Dspin_motor.__spi_lock.release() #print(result) result = twos_comp(result, 22) #result &= 0xFF80 result /= 16 #print(result) return result now = datetime.datetime.now() elapsed_seconds = (now - self.last_steps_count_time).total_seconds() self.last_steps_count_time = now steps_change = elapsed_seconds * self.current_speed/67.106 self.absolute_pos_manual_count += steps_change #print(result, self.absolute_pos_manual_count) return self.absolute_pos_manual_count return result def connect_l6470(self): config_result = self.dspin_GetParam(dSPIN_CONFIG) print('config result: ', hex(config_result)) config_result = self.dspin_GetParam(dSPIN_CONFIG) print('config result: ', hex(config_result)) status = self.dspin_GetStatus() print('status: ', hex(status)) self.dspin_SetParam(dSPIN_STEP_MODE, (0xFF - dSPIN_SYNC_EN) | dSPIN_STEP_SEL_1_128 | dSPIN_SYNC_SEL_64) status = self.dspin_GetStatus() print('status: ', hex(status)) self.dspin_SetParam(dSPIN_MIN_SPEED, 1) #self.dspin_SetParam(dSPIN_MAX_SPEED, 2000) print('min speed: ', self.dspin_GetParam(dSPIN_MIN_SPEED)) print('max speed: ', self.dspin_GetParam(dSPIN_MAX_SPEED)) #max speed? self.dspin_SetParam(dSPIN_FS_SPD, 0x3FF) self.dspin_SetParam(dSPIN_ACC, 0xFF) self.dspin_SetParam(dSPIN_OCD_TH, dSPIN_OCD_TH_6000mA) self.dspin_SetParam(dSPIN_CONFIG, dSPIN_CONFIG_PWM_DIV_1 | dSPIN_CONFIG_PWM_MUL_2 | dSPIN_CONFIG_SR_180V_us | dSPIN_CONFIG_OC_SD_DISABLE | dSPIN_CONFIG_VS_COMP_DISABLE | dSPIN_CONFIG_SW_HARD_STOP | dSPIN_CONFIG_INT_16MHZ) self.dspin_SetParam(dSPIN_KVAL_RUN, 0x7F); self.dspin_SetParam(dSPIN_KVAL_ACC, 0x0F); self.dspin_SetParam(dSPIN_KVAL_DEC, 0x0F); status = self.dspin_GetStatus() print('status: ', hex(status)) def disconnect_l6470(self): self.dspin_SoftStop() self.spi.close()
from spidev import SpiDev dev = SpiDev(0, 0) dev.max_speed_hz = 7800000 resp = dev.xfer([0xA3]) time_sec = 0x74749054 while True: resp = dev.xfer([0xA3]) if resp == [0xA0] or resp == [0xA5]: print "%s" % ''.join(["0x%02X " % x for x in resp]).strip() resp = dev.xfer([0xA2]) print "%s" % ''.join(["0x%02X " % x for x in resp]).strip() # first_stage_hash - 256 bits resp = dev.xfer([ 0x09, 0xA0, 0xD1, 0x91, 0x92, 0xEF, 0x77, 0xC3, 0x04, 0xFE, 0x44, 0x78, 0x88, 0xF9, 0xEF, 0x50, 0x69, 0xD6, 0x48, 0x46, 0x5A, 0x19, 0x14, 0x6F, 0xB7, 0x70, 0x61, 0x97, 0x14, 0xD0, 0x89, 0x04 ]) print "%s" % ''.join(["0x%02X " % x for x in resp]).strip() # input_M - 96 bits #resp = dev.xfer([0x45, 0xF4, 0x99, 0x2E, 0x74, 0x74, 0x90, 0x54, 0x74, 0x7B, 0x1B, 0x18]); resp = dev.xfer([0x45, 0xF4, 0x99, 0x2E]) print "%s" % ''.join(["0x%02X " % x for x in resp]).strip() # time
class Matrix(object): ''' The class which models the operation of the Olimex 8x8 RGB LED matrix. The numbering scheme used when defining the pins are with respect to the BCM numbering scheme. Wiring: - VCC = driving voltage for the matrix. 5 volts. - GND = ground connection from the matrix. - DIN = data in for the matrix, GPIO pin 10 (SPI MOSI). - CS = chip select, depending on SPI channel selection. - CLK = serial clock, GPIO pin 11 (SPI SCK). ''' def __init__(self, spidevice=0): ''' Basic constructor for our driver class. @param: spidevice - the SPI device to be used. Acts as a chip-enable. The Raspberry PI B+ has two such device output pins in-built. Defaults to 0. @return: None ''' if spidevice != 1: spidevice = 0 self.__spi = SpiDev() self.__spi.mode = 0b01 self.__spi.open(0, spidevice) self.__buffer = [0] * 24 def drawpixel(self, pixel): ''' Draws a given Pixel object to the internal buffer. The buffer is formed of 24 bytes. Each byte represents a single color, the n'th bit being whether that particular color is active in the n'th led of that row. The colors are ordered in reverse. (BGR). @param: pixel - a Pixel object. @return: the Pixel encoded as a byte. ''' # current row we're on: row = 3 * pixel.y # clear currently present color by unsetting the corresponding bit from # the three color bytes: self.__buffer[row] &= ~(1 << pixel.x) # clear red. self.__buffer[row + 1] &= ~(1 << pixel.x) # clear green. self.__buffer[row + 2] &= ~(1 << pixel.x) # clear blue. # set red bit for this pixel, if necessary: if pixel.color in [Color.red, Color.white, Color.brown, Color.purple]: self.__buffer[row] |= 1 << pixel.x # set green bit: if pixel.color in [Color.green, Color.white, Color.turquoise, Color.brown]: self.__buffer[row + 1] |= 1 << pixel.x # set blue bit: if pixel.color in [Color.blue, Color.white, Color.turquoise, Color.purple]: self.__buffer[row + 2] |= 1 << pixel.x def write(self): ''' Serially writes the whole of the video buffer to the matrix. ''' self.__spi.xfer(self.__buffer) def clear(self): ''' Clears both the internal buffer and the matrix. ''' self.__buffer = [0] * 24 self.write() def cleanup(self): ''' Clears all registers and terminates the SPI connection. ''' self.clear() self.__spi.close()
class MFRC522: NRSTPD = 22 MAX_LEN = 16 PCD_IDLE = 0x00 PCD_AUTHENT = 0x0E PCD_RECEIVE = 0x08 PCD_TRANSMIT = 0x04 PCD_TRANSCEIVE = 0x0C PCD_RESETPHASE = 0x0F PCD_CALCCRC = 0x03 PICC_REQIDL = 0x26 PICC_REQALL = 0x52 PICC_ANTICOLL = 0x93 PICC_SElECTTAG = 0x93 PICC_AUTHENT1A = 0x60 PICC_AUTHENT1B = 0x61 PICC_READ = 0x30 PICC_WRITE = 0xA0 PICC_DECREMENT = 0xC0 PICC_INCREMENT = 0xC1 PICC_RESTORE = 0xC2 PICC_TRANSFER = 0xB0 PICC_HALT = 0x50 Reserved00 = 0x00 CommandReg = 0x01 CommIEnReg = 0x02 DivlEnReg = 0x03 CommIrqReg = 0x04 DivIrqReg = 0x05 ErrorReg = 0x06 Status1Reg = 0x07 Status2Reg = 0x08 FIFODataReg = 0x09 FIFOLevelReg = 0x0A WaterLevelReg = 0x0B ControlReg = 0x0C BitFramingReg = 0x0D CollReg = 0x0E Reserved01 = 0x0F Reserved10 = 0x10 ModeReg = 0x11 TxModeReg = 0x12 RxModeReg = 0x13 TxControlReg = 0x14 TxAutoReg = 0x15 TxSelReg = 0x16 RxSelReg = 0x17 RxThresholdReg = 0x18 DemodReg = 0x19 Reserved11 = 0x1A Reserved12 = 0x1B MifareReg = 0x1C Reserved13 = 0x1D Reserved14 = 0x1E SerialSpeedReg = 0x1F Reserved20 = 0x20 CRCResultRegM = 0x21 CRCResultRegL = 0x22 Reserved21 = 0x23 ModWidthReg = 0x24 Reserved22 = 0x25 RFCfgReg = 0x26 GsNReg = 0x27 CWGsPReg = 0x28 ModGsPReg = 0x29 TModeReg = 0x2A TPrescalerReg = 0x2B TReloadRegH = 0x2C TReloadRegL = 0x2D TCounterValueRegH = 0x2E TCounterValueRegL = 0x2F Reserved30 = 0x30 TestSel1Reg = 0x31 TestSel2Reg = 0x32 TestPinEnReg = 0x33 TestPinValueReg = 0x34 TestBusReg = 0x35 AutoTestReg = 0x36 VersionReg = 0x37 AnalogTestReg = 0x38 TestDAC1Reg = 0x39 TestDAC2Reg = 0x3A TestADCReg = 0x3B Reserved31 = 0x3C Reserved32 = 0x3D Reserved33 = 0x3E Reserved34 = 0x3F serNum = [] def __init__(self, port=0, device=0): self.spi = SpiDev() self.spi.open(port, device) self.MFRC522_Init() def MFRC522_Reset(self): self.Write_MFRC522(self.CommandReg, self.PCD_RESETPHASE) def Write_MFRC522(self, addr, val): self.spi.xfer([(addr << 1) & 0x7E, val]) def Read_MFRC522(self, addr): val = self.spi.xfer([((addr << 1) & 0x7E) | 0x80, 0]) return val[1] def SetBitMask(self, reg, mask): tmp = self.Read_MFRC522(reg) self.Write_MFRC522(reg, tmp | mask) def ClearBitMask(self, reg, mask): tmp = self.Read_MFRC522(reg) self.Write_MFRC522(reg, tmp & (~mask)) def AntennaOn(self): temp = self.Read_MFRC522(self.TxControlReg) if(~(temp & 0x03)): self.SetBitMask(self.TxControlReg, 0x03) def AntennaOff(self): self.ClearBitMask(self.TxControlReg, 0x03) def MFRC522_ToCard(self, command, send_data): irqEn = 0x00 waitIRq = 0x00 if command == self.PCD_AUTHENT: irqEn = 0x12 waitIRq = 0x10 if command == self.PCD_TRANSCEIVE: irqEn = 0x77 waitIRq = 0x30 self.Write_MFRC522(self.CommIEnReg, irqEn | 0x80) self.ClearBitMask(self.CommIrqReg, 0x80) self.SetBitMask(self.FIFOLevelReg, 0x80) self.Write_MFRC522(self.CommandReg, self.PCD_IDLE) for value in send_data: self.Write_MFRC522(self.FIFODataReg, value) self.Write_MFRC522(self.CommandReg, command) if command == self.PCD_TRANSCEIVE: self.SetBitMask(self.BitFramingReg, 0x80) def await_interrupt(retry_count=100, delay=0.01): for _ in range(retry_count): sleep(delay) interrupts = self.Read_MFRC522(self.CommIrqReg) if (interrupts & 0x01) or (interrupts & waitIRq): return interrupts raise MifareError("No response within waiting period.") try: interrupts = await_interrupt() finally: self.ClearBitMask(self.BitFramingReg, 0x80) if (self.Read_MFRC522(self.ErrorReg) & 0x1B): raise MifareError() if interrupts & irqEn & 0x01: raise NoCardInField() if command == self.PCD_TRANSCEIVE: count = self.Read_MFRC522(self.FIFOLevelReg) last_bits = self.Read_MFRC522(self.ControlReg) & 0x07 if last_bits: length_in_bits = (count - 1) * 8 + last_bits else: length_in_bits = count * 8 count = min(self.MAX_LEN, max(1, count)) returned_data = [ self.Read_MFRC522(self.FIFODataReg) for _ in range(count) ] return (returned_data, length_in_bits) else: return ([], 0) def MFRC522_Request(self, req_mode): tag_type = [req_mode] self.Write_MFRC522(self.BitFramingReg, 0x07) (backData, backBits) = self.MFRC522_ToCard( self.PCD_TRANSCEIVE, tag_type ) if (backBits != 0x10): raise MifareError() return backData def MFRC522_Anticoll(self): # Anticollision serial = [self.PICC_ANTICOLL, 0x20] self.Write_MFRC522(self.BitFramingReg, 0x00) serial_number, _ = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, serial) if len(serial_number) != 5: raise InvalidCard("Serial number had invalid length") checksum = 0 for byte in serial_number: checksum ^= byte if checksum: raise InvalidCard("Serial number checksum failed") return serial_number def CalulateCRC(self, data): self.ClearBitMask(self.DivIrqReg, 0x04) self.SetBitMask(self.FIFOLevelReg, 0x80) for byte in data: self.Write_MFRC522(self.FIFODataReg, byte) self.Write_MFRC522(self.CommandReg, self.PCD_CALCCRC) for _ in range(0xFF): if self.Read_MFRC522(self.DivIrqReg) & 0x04: break pOutData = [ self.Read_MFRC522(self.CRCResultRegL), self.Read_MFRC522(self.CRCResultRegM) ] return pOutData def MFRC522_SelectTag(self, serial_number): backData = [] buf = [self.PICC_SElECTTAG, 0x70] buf.extend(serial_number) buf.extend(self.CalulateCRC(buf)) try: backData, backLen = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf) except MifareError: return 0 # No idea why, but the original code did this if backLen == 0x18: print("Size: {}".format(backData[0])) return backData[0] else: return 0 def MFRC522_Auth(self, authMode, BlockAddr, Sectorkey, serNum): buf = [ authMode, # First byte should be the authMode (A or B) BlockAddr # Second byte is the trailerBlock (usually 7) ] # Now we need to append the authKey which usually is 6 bytes of 0xFF buf.extend(Sectorkey) # Next we append the first 4 bytes of the UID buf.extend(serNum[:4]) # Now we start the authentication itself try: backData, backLen = self.MFRC522_ToCard(self.PCD_AUTHENT, buf) except NoCardInField: raise except MifareError: raise MifareAuthError() # Check if crypto1 unit is switched on if not (self.Read_MFRC522(self.Status2Reg) & 0x08): MifareAuthError("MFCrypto1On bit not enabled") def MFRC522_StopCrypto1(self): self.ClearBitMask(self.Status2Reg, 0x08) def MFRC522_Read(self, block_address): recv_data = [self.PICC_READ, block_address] recv_data.extend(self.CalulateCRC(recv_data)) returned_data, _ = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, recv_data) if len(returned_data) == 16: print("Sector {} {}".format(block_address, returned_data)) return returned_data def MFRC522_Write(self, block_address, data): buf = [self.PICC_WRITE, block_address] buf.extend(self.CalulateCRC(buf)) returned_data, length = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf) if length != 4 or (returned_data[0] & 0x0F) != 0x0A: raise MifareError() buf = [] buf.extend(data) buf.extend(self.CalulateCRC(buf)) returned_data, length = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf) if length != 4 or (returned_data[0] & 0x0F) != 0x0A: raise MifareError() def MFRC522_DumpClassic1K(self, key, uid): for i in range(64): self.MFRC522_Auth(self.PICC_AUTHENT1A, i, key, uid) print(self.MFRC522_Read(i)) def MFRC522_Init(self): self.MFRC522_Reset() self.Write_MFRC522(self.TModeReg, 0x8D) self.Write_MFRC522(self.TPrescalerReg, 0x3E) self.Write_MFRC522(self.TReloadRegL, 30) self.Write_MFRC522(self.TReloadRegH, 0) self.Write_MFRC522(self.TxAutoReg, 0x40) self.Write_MFRC522(self.ModeReg, 0x3D) self.AntennaOn()
class Matrix(object): ''' The class which models the operation of the Olimex 8x8 RGB LED matrix. The numbering scheme used when defining the pins are with respect to the BCM numbering scheme. Wiring: - VCC = driving voltage for the matrix. 5 volts. - GND = ground connection from the matrix. - DIN = data in for the matrix, GPIO pin 10 (SPI MOSI). - CS = chip select, depending on SPI channel selection. - CLK = serial clock, GPIO pin 11 (SPI SCK). ''' def __init__(self, spidevice=0): ''' Basic constructor for our driver class. @param: spidevice - the SPI device to be used. Acts as a chip-enable. The Raspberry PI B+ has two such device output pins in-built. Defaults to 0. @return: None ''' if spidevice != 1: spidevice = 0 self.__spi = SpiDev() self.__spi.mode = 0b01 self.__spi.open(0, spidevice) self.__buffer = [0] * 24 def drawpixel(self, pixel): ''' Draws a given Pixel object to the internal buffer. The buffer is formed of 24 bytes. Each byte represents a single color, the n'th bit being whether that particular color is active in the n'th led of that row. The colors are ordered in reverse. (BGR). @param: pixel - a Pixel object. @return: the Pixel encoded as a byte. ''' # current row we're on: row = 3 * pixel.y # clear currently present color by unsetting the corresponding bit from # the three color bytes: self.__buffer[row] &= ~(1 << pixel.x) # clear red. self.__buffer[row + 1] &= ~(1 << pixel.x) # clear green. self.__buffer[row + 2] &= ~(1 << pixel.x) # clear blue. # set red bit for this pixel, if necessary: if pixel.color in [Color.red, Color.white, Color.brown, Color.purple]: self.__buffer[row] |= 1 << pixel.x # set green bit: if pixel.color in [ Color.green, Color.white, Color.turquoise, Color.brown ]: self.__buffer[row + 1] |= 1 << pixel.x # set blue bit: if pixel.color in [ Color.blue, Color.white, Color.turquoise, Color.purple ]: self.__buffer[row + 2] |= 1 << pixel.x def write(self): ''' Serially writes the whole of the video buffer to the matrix. ''' self.__spi.xfer(self.__buffer) def clear(self): ''' Clears both the internal buffer and the matrix. ''' self.__buffer = [0] * 24 self.write() def cleanup(self): ''' Clears all registers and terminates the SPI connection. ''' self.clear() self.__spi.close()
class AMT20(): def __init__(self, address, direction, bitrate=976000, theta_max=0.15): """ Initialize and open an SPI connection with a CUI AMT20 encoder. :param bus: SPI address in the bus (e.g. 0 or 1). :type bus: int :param direction: Direction of rotation of the encoder, must be either 'ccw' or 'cw'. :type direction: string :param bitrate: Frequency of the SPI bus. The encoder defaults to 976[kHz]. :type bitrate: int :param theta_max: Max angle variation between samples, in radians. Defaults to 0.15[rad/sample]. :type theta_max: float """ assert address == 0 or address == 1, "SPI address must be 0 or 1" assert direction == "ccw" or direction == "cw", "Direction must be either 'ccw' or 'cw'" self.RESOLUTION = 4096 self.direction = direction self.theta_max = theta_max self.encoder = SpiDev() self.encoder.open(0, address) self.encoder.max_speed_hz = bitrate self._warm_up() self.last = {"angle": self.angle(), "time": datetime.now()} def _warm_up(self): """ Send a RD_POS and enough NOP_A5 commands until the enoder starts responding as expected. """ resp = self.encoder.xfer([NOP_A5], 0, 20)[0] while resp != 0xA5: resp = self.encoder.xfer([NOP_A5], 0, 20)[0] return True def read_position(self): """ Perform a series of SPI transactions, sending the 'RD_POS' command and waiting for the response. Then concatenates both bytes received. """ resp = self.encoder.xfer([RD_POS], 0, 20)[0] if resp == 0: raise IOError("Remote I/O error") while resp != RD_POS: resp = self.encoder.xfer([NOP_A5], 0, 20)[0] MSB = self.encoder.xfer([NOP_A5], 0, 20)[0] # Most Significant Byte LSB = self.encoder.xfer([NOP_A5], 0, 20)[0] # Least Significant Byte position = (MSB << 8) | LSB if self.direction == "ccw": return position else: return self.RESOLUTION - position def set_zero(self): """ Perform a series of SPI transactions to set the current position as zero and save this setting in the EEPROM. The encoder must be power cycled. Otherwise the position values will not be calculated off the latest zero position. When the encoder is powered on next the new offset will be used for the position calculation. """ resp = self.encoder.xfer([SET_ZERO_POINT], 0, 20)[0] if resp == 0: raise IOError("Remote I/O error") while resp != 0x80: resp = self.encoder.xfer([NOP_A5], 0, 20)[0] return True def angle(self): """ This command converts the reading of the encoder to a angle in the range [0, 2*pi] """ count = self.read_position() return (count * 2 * pi / self.RESOLUTION) def angular_speed(self): """ This command calculates the speed using the difference between the last and current angle and their corresponding timestamps """ # Get current time and angle angle = self.angle() time = datetime.now() # Get angle and time differences dTheta = angle - self.last["angle"] dTime = time - self.last["time"] # Update angle and time for future calls self.last["angle"] = angle self.last["time"] = time # When the encoder crosses zero, the difference will spike, # unless we add (or substract) 2pi if dTheta > self.theta_max: dTheta -= 2 * pi elif dTheta < -self.theta_max: dTheta += 2 * pi # Convert timedelta object to float (seconds) dt = dTime.seconds + dTime.microseconds * 1E-6 return dTheta / dt def __del__(self): """ Do a cleanup of the opened resources. """ self.encoder.close()
from spidev import SpiDev import time import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(6, GPIO.OUT) spi = SpiDev() spi.open(0, 0) spi.max_speed_hz = 390000 print("Flashlight to waitstate") #string_to_send = "state;1\n" string_to_send = "shot;1\n" string_to_bytes = str.encode(string_to_send) GPIO.output(6, 1) time.sleep(0.01) spi.xfer(string_to_bytes) GPIO.output(6, 0) time.sleep(1) GPIO.cleanup()
class SPI(object): """ classdocs """ __LOCK_TIMEOUT = 10.0 # ---------------------------------------------------------------------------------------------------------------- def __init__(self, bus, device, mode, max_speed): """ Constructor """ self.__bus = bus self.__device = device self.__mode = mode self.__max_speed = max_speed self.__connection = None # ---------------------------------------------------------------------------------------------------------------- def open(self): if self.__connection: return self.acquire_lock() self.__connection = SpiDev() self.__connection.open(self.__bus, self.__device) self.__connection.mode = self.__mode self.__connection.max_speed_hz = self.__max_speed def close(self): if self.__connection is None: return self.__connection.close() self.__connection = None self.release_lock() # ---------------------------------------------------------------------------------------------------------------- def acquire_lock(self): Lock.acquire(self.__lock_name, SPI.__LOCK_TIMEOUT) def release_lock(self): Lock.release(self.__lock_name) @property def __lock_name(self): return "%s-%s" % (self.__class__.__name__, self.__bus) # ---------------------------------------------------------------------------------------------------------------- def xfer(self, args): return self.__connection.xfer(args) def read_bytes(self, count): return self.__connection.readbytes(count) # ---------------------------------------------------------------------------------------------------------------- @property def bus(self): return self.__bus @property def device(self): return self.__device # ---------------------------------------------------------------------------------------------------------------- def __str__(self, *args, **kwargs): return "SPI:{bus:%d, device:%s, mode:%d, max_speed:%d, connection:%s}" % \ (self.__bus, self.__device, self.__mode, self.__max_speed, self.__connection)