def __init__(self): super(ApplicationWindow, self).__init__() self.bus_num = Logic.bus_num self.bus = SMBus(self.bus_num) self.ui = Ui_MainWindow() self.ui.setupUi(self) # Get easy access to UI elements self.rgb = self.ui.lid_display.layout() self.minutes = self.ui.lcdMinutes self.seconds = self.ui.lcdSeconds self.potentiometer = self.ui.dial # TODO Make connections to functions # TODO Listen on the SMBus for messages and then call the right functions for h, button in self.keypad.items(): button.clicked.connect( partial(lambda: self.bus.write_byte(self.bus_num, I2C.ARDUINO), h)) for _, checkbox in self.photo_resistor.items(): checkbox.clicked.connect( partial(lambda: self.bus.write_byte_data( self.bus_num, I2C.LASERS, self.laser_mask))) self.potentiometer.valueChanged.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.ROTARY, self.potentiometer.value())) for _, switch in self.switches.items(): switch.valueChanged.connect(lambda: self.bus.write_byte_data( self.bus_num, I2C.SWITCHES, self.switch_mask)) # Colored disconnectable wires self.ui.wire_red.clicked.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.WIRE, 0xd)) self.ui.wire_blue.clicked.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.WIRE, 0xb)) self.ui.wire_green.clicked.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.WIRE, 0xe)) # Reset button self.ui.start_reset.clicked.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.RESET, 0x1)) self.ui.ultrasonicSlider.valueChanged.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.ULTRASONIC, self.ui.ultrasonicSlider.value())) self.scheduler = APScheduler(scheduler=BackgroundScheduler()) self.scheduler.add_job("poll", self.poll_sensors, max_instances=2, replace_existing=False)
def __init__(self): self.laserPattern = LaserPattern.ONE_CYCLES self._timer = 0 self._patternIndex = 0 # Initialize ICc Devices self._bus = SMBus(self.bus_num) self.lasers = LaserControl(self._bus) self.arduino = SevenSeg(self._bus) self.photo_resistors = ReceptorControl(self._bus)
class Logic: bus_num = 1 db = Database() shared = Manager().dict() scheduler = None lasers = None _comQueue = Queue() _process = Lock() _solenoid = SOLENOID_STATE.UNLOCKED _ultrasonic = ULTRASONIC_STATE.ENABLED _laserState = LaserPattern.LASER_OFF _laserCounter = 0 _patternIndex = 0 _laserValue = 0x00 def __init__(self): self.laserPattern = LaserPattern.ONE_CYCLES self._timer = 0 self._patternIndex = 0 # Initialize ICc Devices self._bus = SMBus(self.bus_num) self.lasers = LaserControl(self._bus) self.arduino = SevenSeg(self._bus) self.photo_resistors = ReceptorControl(self._bus) @property def patternIndex(self) -> int: return self._patternIndex @patternIndex.setter def patternIndex(self, value: int): self._patternIndex = value @property def laserCounter(self) -> int: return self._laserCounter @laserCounter.setter def laserCounter(self, value: int): self._laserCounter = value def laserCounterIncrement(self): self.laserCounter = self.laserCounter + 1 @property def laserState(self) -> LaserPattern: return LaserPattern( self.shared.get("laserpattern", LaserPattern.LASER_OFF.value)) @laserState.setter def laserState(self, value: LaserPattern): self.shared["laserpattern"] = value.value @property def laserValue(self) -> int: return self.shared.get("laservalue", 0x00) @laserValue.setter def laserValue(self, value: int): self.shared["laservalue"] = value @property def timer_text(self) -> str: newDatetime = datetime.now() - self.start_time seconds = MAX_TIME - newDatetime.seconds minutes = seconds // 60 secondsToPrint = seconds - minutes * 60 if self.state is STATE.WAIT: return "RESET" if self.state is STATE.RUNNING: if minutes < 0 or seconds < 0: ComQueue().getComQueue().put([INTERRUPT.KILL_PLAYER]) return "DEAD" elif self.state is STATE.EXPLODE: return "DEAD" elif self.state is STATE.WIN: return "SUCCESS!" return "{}:{:2}".format(minutes, str(secondsToPrint).zfill(2)) @property def start_time(self) -> datetime: return self.shared.get("start time", datetime.now()) @start_time.setter def start_time(self, value: datetime): self.shared["start time"] = value @property def ultrasonic(self) -> ULTRASONIC_STATE: return ULTRASONIC_STATE( self.shared.get("ultrasonic", ULTRASONIC_STATE.ENABLED.value)) @ultrasonic.setter def ultrasonic(self, value: ULTRASONIC_STATE): # TODO send the new ultrasonic logic over I2C log.debug("Ultrasonic logic changed from {} to {}".format( self.ultrasonic.value, value.value)) self.shared["ultrasonic"] = value.value @property def comQueue(self) -> Queue: return self._comQueue @comQueue.setter def comQueue(self, value): log.debug("Queue was created") self._comQueue = value @property def solenoid(self) -> SOLENOID_STATE: return SOLENOID_STATE( self.shared.get("solenoid", SOLENOID_STATE.UNLOCKED.value)) @solenoid.setter def solenoid(self, value: SOLENOID_STATE): # TODO send the new solenoid logic over I2C log.debug("Solenoid logic changed from {} to {}".format( self.solenoid.value, value.value)) self.shared["solenoid"] = value.value @property def state(self): return STATE(self.shared.get("logic", STATE.WAIT.value)) @state.setter def state(self, value: STATE): log.debug("State changed from {} to {}".format(self.state.value, value.value)) self.shared["logic"] = value.value @property def keypad_code(self) -> hex: return self.shared.get("code", 0x000) @keypad_code.setter def keypad_code(self, value: hex): assert 0x0 <= value <= 0xfff log.debug("Setting new keypad code: 0x{}".format(value)) self.shared["code"] = value @property def team(self) -> str: return self.shared.get( "team", self.db.last.name if self.db.get_rows() else "--") @team.setter def team(self, value: str): log.debug("Setting current team name to: {}".format(value)) self.shared["team"] = value if self.db.get_rows(): self.db.last = Row(name=value) @property def rgb_color(self) -> RGBColor: return RGBColor(self.shared.get("rgb", RGBColor.BLANK.value)) @rgb_color.setter def rgb_color(self, value: RGBColor): log.debug("Setting new rgb color: {}".format(value)) # TODO send the command over i2c to change the rgb color self.shared["rgb"] = value.value def run(self, queue: Queue, mock: bool): """ Start the game and make sure there is only a single instance of this process This is the setup function, when it is done, it will start the game loop """ with self._process: # Initialize I2C server self.state = STATE.WAIT # Change logic of game to WAIT self.solenoid = SOLENOID_STATE.LOCKED self.comQueue = queue self.ultrasonic = ULTRASONIC_STATE.ENABLED self.laserPattern = LaserPattern.ONE_CYCLES self.scheduler = APScheduler(scheduler=BackgroundScheduler(), app=current_app) self.scheduler.add_job("loop", self._loop, trigger='interval', seconds=1, max_instances=1, replace_existing=False) self.scheduler.start() # TODO start thread polling sensors try: while True: self.poll_sensors() except KeyboardInterrupt: return def poll_sensors(self): """ Poll all of the sensors and raise a flag if one of them has tripped. If the right wire was clipped at the end of the puzzle, raise the win flag """ """ for i in I2C: word = self._bus.read_byte_data(self.bus_num, i) if word is not None: # log.info("{}: {}".format(i.name, hex(word))) if i is I2C.RESET: ComQueue().getComQueue().put([INTERRUPT.TOGGLE_TIMER]) elif i is I2C.LASERS: if self.laserValue != word: ComQueue().getComQueue().put([INTERRUPT.KILL_PLAYER]) """ # self._bus.write_byte_data(I2C.LASERS.value, 0, 9) # for i2c in I2C: # log.debug("Reading from I2C on {}".format(i2c.name)) # foo = self._bus.read_word_data(i2c.value, 0) # self._send(I2C.SEVEN_SEG, "Hello!") def getNextLaserPatternList(self): if self.laserState is LaserPattern.ONE_CYCLES: return LaserPattern.TWO_CYCLES elif self.laserState is LaserPattern.TWO_CYCLES: return LaserPattern.UP_AND_DOWN elif self.laserState is LaserPattern.UP_AND_DOWN: return LaserPattern.INVERSION elif self.laserState is LaserPattern.INVERSION: return LaserPattern.LASER_OFF else: return self.laserState def getLaserPattern(self): if self.laserState is LaserPattern.ONE_CYCLES: pattern = LaserPatternValues.ONE_CYCLES.value elif self.laserState is LaserPattern.TWO_CYCLES: pattern = LaserPatternValues.TWO_CYCLES.value elif self.laserState is LaserPattern.UP_AND_DOWN: pattern = LaserPatternValues.UP_AND_DOWN.value elif self.laserState is LaserPattern.INVERSION: pattern = LaserPatternValues.INVERSION.value elif self.laserState is LaserPattern.LASER_OFF: pattern = LaserPatternValues.LASER_OFF.value elif self.laserState is LaserPattern.RANDOM: pattern = LaserPatternValues.RANDOM.value elif self.laserState is LaserPattern.STATIC: return self.laserValue else: pattern = None # Increment the patternIndex if pattern is not None: if self.patternIndex < len(pattern): retValue = pattern[self.patternIndex] self.patternIndex += 1 else: self.patternIndex = 0 retValue = pattern[self.patternIndex] if retValue == 0xFF: return random.randint(0, 0x3F) else: return retValue else: # All lasers turn return 0x3F def updateLaserPattern(self): if self.laserCounter < SECONDS_PER_PATTERN: self.laserCounterIncrement() else: self.laserState = self.getNextLaserPatternList() self.patternIndex = 0 # So that we start at the beginning self.laserCounter = 0 # Time per element of pattern self.laserValue = self.getLaserPattern() # Set laser pattern setVar = 0 while setVar < NUMBER_OF_LASERS: self.lasers.state[setVar] = self.laserValue & (1 << setVar) setVar += 1 self.lasers.update() def _loop(self): command_id = None if not self.comQueue.empty(): command = self.comQueue.get() command_id = command[0] # State Actions if self.state is STATE.WAIT: self.laserState = LaserPattern.LASER_OFF elif self.state is STATE.RUNNING: self.updateLaserPattern() elif self.state is STATE.EXPLODE: pass # TODO randomize laser pattern so that they flash elif self.state is STATE.WIN: pass else: log.error("Reached an unknown state: {}".format(self.state)) # State Transitions if self.state is STATE.WAIT: if command_id is INTERRUPT.TOGGLE_TIMER: # TODO? Verify that the box is reset before starting the game self.state = STATE.RUNNING self.start_game() elif self.state is STATE.RUNNING: if command_id is INTERRUPT.RESET_GAME or command_id is INTERRUPT.TOGGLE_TIMER: self.state = STATE.WAIT # FIXME? Delete last row on reset self.end_game(success=False) elif command_id is INTERRUPT.KILL_PLAYER: self.state = STATE.EXPLODE self.end_game(success=False) elif command_id is INTERRUPT.DEFUSED: self.state = STATE.WIN self.end_game(success=True) elif self.state is STATE.EXPLODE: if command_id is INTERRUPT.RESET_GAME or command_id is INTERRUPT.TOGGLE_TIMER: self.state = STATE.WAIT elif self.state is STATE.WIN: if command_id is INTERRUPT.RESET_GAME or command_id is INTERRUPT.TOGGLE_TIMER: self.state = STATE.WAIT def _send(self, device: I2C, message: str): """ Send a command to a device over I2c. Nothing external should call this, only "loop" :param device: :param message: :return: """ assert len(message) < 32 log.debug("Address: 0x{:02x} Message: '{}'".format( device.value, message)) try: self._bus.write_i2c_block_data(device.value, 0x00, [ord(c) for c in message]) except IOError: pass @staticmethod def random_laser_pattern() -> int: # TODO make sure the laser pattern conforms to certain rules return random.randint(0, 0x3f) def start_game(self): """ Add a row to the database, generate random data for all the puzzles """ self.solenoid = SOLENOID_STATE.LOCKED self.start_time = datetime.now() self.keypad_code = random.randint(0, 0xfff) self.rgb_color = random.choice([RGBColor.RED, RGBColor.BLUE]) self.laserState = LaserPattern.ONE_CYCLES row = Row( name=self.team, lasers=self.laserValue, code=self.keypad_code, success=False, time=MAX_TIME, color=self.rgb_color.value, ) log.debug("Adding new row to the database:\n{}".format(row)) self.db.add_row(row) def end_game(self, success: bool = False): log.debug("Game Over") self.db.last = Row(name=self.team, code=self.keypad_code, lasers=self.laserValue, success=success, time=(datetime.now() - self.start_time).seconds)
self.current_color = color self.write_byte(color) @property def keypad(self) -> chr: # TODO device won't read data unless listening on serial too success, data = self.read_bytes(16) if success and data[0] != self.NO_DATA: return [chr(x) for x in data] else: return [] if __name__ == "__main__": from time import sleep device = ArduinoI2C(SMBus(1)) # Test RGB for c in COLOR: device.RGB(c) sleep(1) device.RGB(COLOR.BLANK) # Test Keypad while True: sleep(1) rcv = device.keypad if rcv: print(rcv)
from threading import Thread from time import sleep from i2c import SMBus from i2c.laser_i2c import LaserControl from i2c.lid_kit import ArduinoI2C, COLOR from i2c.sevenseg import SevenSeg from mockpi.mock_box_ui import ApplicationWindow bus = SMBus(1) arduino = ArduinoI2C(bus) lasers = LaserControl(bus) seven = SevenSeg(bus) def run_sevenseg(): while True: for n in range(0xffff): seven.sevenseg(value=n) sleep(.1) def run_rgb(): while True: for c in COLOR: arduino.RGB(c) sleep(1) arduino.RGB(COLOR.BLANK)
super().__init__(bus, address) self.receptors = [0] * self.RECEPTOR_COUNT self.write_reg_bytes(ReceptorRegisters.Config, self.CONFIG) def read_all(self) -> List[bool]: # TODO return a list with a boolean for each photoresistor's state _, data = self.read_reg_bytes(self.READ_ALL, 2 * self.RECEPTOR_COUNT) self.receptors = list( unpack(self.UNPACK_ALL, array('B', data).tostring())) return self.receptors def read(self, n) -> bool: # TODO return True if the laser is HIGH else False if n >= self.RECEPTOR_COUNT: return None _, data = self.read_reg_bytes(self.CHANNEL[n], 2) data2 = unpack('>H', array('B', data).tostring()) self.receptors[n] = data2[0] return self.receptors[n] if __name__ == '__main__': master = SMBus(1) read = ReceptorControl(master) while True: # print('{}, {}, {}, {}, {}, {}'.format(*[read.read(n) for n in range(6)])) # print(read.read_all()) print(read.read(1)) sleep(1)
class ApplicationWindow(QtWidgets.QMainWindow): def __init__(self): super(ApplicationWindow, self).__init__() self.bus_num = Logic.bus_num self.bus = SMBus(self.bus_num) self.ui = Ui_MainWindow() self.ui.setupUi(self) # Get easy access to UI elements self.rgb = self.ui.lid_display.layout() self.minutes = self.ui.lcdMinutes self.seconds = self.ui.lcdSeconds self.potentiometer = self.ui.dial # TODO Make connections to functions # TODO Listen on the SMBus for messages and then call the right functions for h, button in self.keypad.items(): button.clicked.connect( partial(lambda: self.bus.write_byte(self.bus_num, I2C.ARDUINO), h)) for _, checkbox in self.photo_resistor.items(): checkbox.clicked.connect( partial(lambda: self.bus.write_byte_data( self.bus_num, I2C.LASERS, self.laser_mask))) self.potentiometer.valueChanged.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.ROTARY, self.potentiometer.value())) for _, switch in self.switches.items(): switch.valueChanged.connect(lambda: self.bus.write_byte_data( self.bus_num, I2C.SWITCHES, self.switch_mask)) # Colored disconnectable wires self.ui.wire_red.clicked.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.WIRE, 0xd)) self.ui.wire_blue.clicked.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.WIRE, 0xb)) self.ui.wire_green.clicked.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.WIRE, 0xe)) # Reset button self.ui.start_reset.clicked.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.RESET, 0x1)) self.ui.ultrasonicSlider.valueChanged.connect( lambda: self.bus.write_byte_data(self.bus_num, I2C.ULTRASONIC, self.ui.ultrasonicSlider.value())) self.scheduler = APScheduler(scheduler=BackgroundScheduler()) self.scheduler.add_job("poll", self.poll_sensors, max_instances=2, replace_existing=False) # self.scheduler.start() def poll_sensors(self): for i in I2C: word = self.bus.read_byte_data(i, 0) if word is not None: log.info("{}: {}".format(i.name, hex(word))) if i is I2C.SEVENSEG: pass self.scheduler.add_job("poll", self.poll_sensors, max_instances=2, replace_existing=False) @property def time(self) -> str: """ :return: The current time shown on the lcd """ @time.setter def time(self, value): """ TODO set the value on the timer :param value: :return: """ @property def switches(self) -> Dict[int, QSlider]: return { 4: self.ui.verticalSlider_1, 3: self.ui.verticalSlider_2, 2: self.ui.verticalSlider_3, 1: self.ui.verticalSlider_4, 0: self.ui.verticalSlider_5, } @property def switch_mask(self) -> bin: result = 0b00000 for offset, sw in self.switches.items(): result ^= ((1 if sw.value() else 0) << offset) return result @property def laser_mask(self) -> bin: """ :return: An integer that represents all the photo resistors that have a laser shining on them """ result = 0b000000 for offset, box in self.photo_resistor.items(): result ^= ((1 if box.isChecked() else 0) << offset) return result @property def laser(self) -> Dict[int, QCheckBox]: return { 5: self.ui.laser_0, 4: self.ui.laser_1, 3: self.ui.laser_2, 2: self.ui.laser_3, 1: self.ui.laser_4, 0: self.ui.laser_5, } @property def photo_resistor(self) -> Dict[int, QCheckBox]: return { 5: self.ui.photodiode_0, 4: self.ui.photodiode_1, 3: self.ui.photodiode_2, 2: self.ui.photodiode_3, 1: self.ui.photodiode_4, 0: self.ui.photodiode_5, } @property def led(self) -> Dict[int, QCheckBox]: return { 0: self.ui.led_0, 1: self.ui.led_1, 2: self.ui.led_2, 3: self.ui.led_3, 4: self.ui.led_4, 5: self.ui.led_5, 6: self.ui.led_6, 7: self.ui.led_7, } @property def keypad(self) -> Dict[hex, QPushButton]: return { 0x0: self.ui.pushButton0, 0x1: self.ui.pushButton1, 0x2: self.ui.pushButton2, 0x3: self.ui.pushButton3, 0x4: self.ui.pushButton4, 0x5: self.ui.pushButton5, 0x6: self.ui.pushButton6, 0x7: self.ui.pushButton7, 0x8: self.ui.pushButton8, 0x9: self.ui.pushButton9, 0xa: self.ui.pushButtona, 0xb: self.ui.pushButtonb, 0xc: self.ui.pushButtonc, 0xd: self.ui.pushButtond, 0xe: self.ui.pushButtone, 0xf: self.ui.pushButtonf, } @staticmethod def run(): app = QtWidgets.QApplication(sys.argv) application = ApplicationWindow() application.show() return app.exec_()
buffer.append((dots[i] << 7) | chars[i]) buffer.append(0) if i == 1: buffer.append(self.COLON if colon else 0) buffer.append(0) try: with self._lock: self.bus.write_i2c_block_data(self.ADDRESS, 0, buffer) except OSError as c: logger.error("{}:{}".format(c, hex(value))) def brightness(self, level: int): level = 0 if level > 15 else level self.write(self.CMD_BRIGHTNESS | level) def blink_rate(self, rate: int = 0): rate = rate if rate <= 3 else 0 self.write(self.BLINK_CMD | self.BLINK_DISPLAY_ON | (rate << 1)) if __name__ == '__main__': from time import sleep kit = SevenSeg(SMBus(1), brightness=3) while True: for n in range(0xffff): kit.sevenseg(value=n) sleep(.1)