diff --git a/bm_game/SPIManager.py b/bm_game/SPIManager.py index b784154..ce8ce0c 100644 --- a/bm_game/SPIManager.py +++ b/bm_game/SPIManager.py @@ -15,101 +15,101 @@ import RPi.GPIO as GPIO import time + class SPIManager(object): - - SPI_MOSI = 27 - SPI_MISO = 22 - SPI_SCLK = 23 - SPI_CE0 = 18 - - def __init__(self): - self.SPISetupGPIO(); - - def SPISetupGPIO(self): - GPIO.setmode(GPIO.BCM) - - GPIO.setup(SPIManager.SPI_MOSI, GPIO.OUT) - GPIO.output(SPIManager.SPI_MOSI, GPIO.LOW) - - GPIO.setup(SPIManager.SPI_MISO, GPIO.IN) - - GPIO.setup(SPIManager.SPI_SCLK, GPIO.OUT) - GPIO.output(SPIManager.SPI_SCLK, GPIO.LOW) - - GPIO.setup(SPIManager.SPI_CE0, GPIO.OUT) - GPIO.output(SPIManager.SPI_CE0, GPIO.HIGH) - - - def SPISelect(self): - GPIO.output(SPIManager.SPI_CE0, GPIO.LOW) - - def SPIUnSelect(self): - GPIO.output(SPIManager.SPI_CE0, GPIO.HIGH) - - def SPIPulseClock(self): - GPIO.output(SPIManager.SPI_SCLK, GPIO.HIGH) - GPIO.output(SPIManager.SPI_SCLK, GPIO.LOW) - - def SPISend(self, data): - currentMOSIstate = False - - for i in range (len(data)): - byteToSend = data[i] - for j in range (8): - - desiredState = False - if (byteToSend & 0x80) > 0 : - desiredState = True - - if desiredState == True and currentMOSIstate == False : - GPIO.output(SPIManager.SPI_MOSI, GPIO.HIGH) - currentMOSIstate = True - elif desiredState == False and currentMOSIstate == True : - GPIO.output(SPIManager.SPI_MOSI, GPIO.LOW) - currentMOSIstate = False - - # Pulse the clock. - self.SPIPulseClock() - - # Shift to the next bit. - byteToSend <<= 1; - if currentMOSIstate == True : - GPIO.output(SPIManager.SPI_MOSI, GPIO.LOW) - - - def SPIReceive(self, numBits): - numBytes = (numBits + 7) // 8 - - buffer = bytearray() - - # Array is filled in received byte order. - # Any padding bits are the least significant bits, of the last byte. - - currentBit = 0; - for i in range (numBytes): - receiveByte = 0x00 - for j in range(8): - # Shift to the next bit. - receiveByte <<= 1 - - # Skip padding bits - currentBit += 1 - if currentBit > numBits: - continue - - # Set the clock high. - GPIO.output(SPIManager.SPI_SCLK, GPIO.HIGH) - - # Read the value. - bit = GPIO.input(SPIManager.SPI_MISO) - - # Set the clock low. - GPIO.output(SPIManager.SPI_SCLK, GPIO.LOW) - - # Set the received bit. - if bit == True : - receiveByte |= 1 - - buffer.append(receiveByte) - - return buffer; + + SPI_MOSI = 27 + SPI_MISO = 22 + SPI_SCLK = 23 + SPI_CE0 = 18 + + def __init__(self): + self.SPISetupGPIO() + + def SPISetupGPIO(self): + GPIO.setmode(GPIO.BCM) + + GPIO.setup(SPIManager.SPI_MOSI, GPIO.OUT) + GPIO.output(SPIManager.SPI_MOSI, GPIO.LOW) + + GPIO.setup(SPIManager.SPI_MISO, GPIO.IN) + + GPIO.setup(SPIManager.SPI_SCLK, GPIO.OUT) + GPIO.output(SPIManager.SPI_SCLK, GPIO.LOW) + + GPIO.setup(SPIManager.SPI_CE0, GPIO.OUT) + GPIO.output(SPIManager.SPI_CE0, GPIO.HIGH) + + def SPISelect(self): + GPIO.output(SPIManager.SPI_CE0, GPIO.LOW) + + def SPIUnSelect(self): + GPIO.output(SPIManager.SPI_CE0, GPIO.HIGH) + + def SPIPulseClock(self): + GPIO.output(SPIManager.SPI_SCLK, GPIO.HIGH) + GPIO.output(SPIManager.SPI_SCLK, GPIO.LOW) + + def SPISend(self, data): + currentMOSIstate = False + + for i in range(len(data)): + byteToSend = data[i] + for j in range(8): + + desiredState = False + if (byteToSend & 0x80) > 0: + desiredState = True + + # noqa: E712 + if desiredState == True and currentMOSIstate == False: + GPIO.output(SPIManager.SPI_MOSI, GPIO.HIGH) + currentMOSIstate = True + elif desiredState == False and currentMOSIstate == True: + GPIO.output(SPIManager.SPI_MOSI, GPIO.LOW) + currentMOSIstate = False + + # Pulse the clock. + self.SPIPulseClock() + + # Shift to the next bit. + byteToSend <<= 1 + if currentMOSIstate == True: + GPIO.output(SPIManager.SPI_MOSI, GPIO.LOW) + + def SPIReceive(self, numBits): + numBytes = (numBits + 7) // 8 + + buffer = bytearray() + + # Array is filled in received byte order. + # Any padding bits are the least significant bits, of the last byte. + + currentBit = 0 + for i in range(numBytes): + receiveByte = 0x00 + for j in range(8): + # Shift to the next bit. + receiveByte <<= 1 + + # Skip padding bits + currentBit += 1 + if currentBit > numBits: + continue + + # Set the clock high. + GPIO.output(SPIManager.SPI_SCLK, GPIO.HIGH) + + # Read the value. + bit = GPIO.input(SPIManager.SPI_MISO) + + # Set the clock low. + GPIO.output(SPIManager.SPI_SCLK, GPIO.LOW) + + # Set the received bit. + if bit == True: + receiveByte |= 1 + + buffer.append(receiveByte) + + return buffer diff --git a/bm_game/XPT2046.py b/bm_game/XPT2046.py index 68f915c..fa10a74 100644 --- a/bm_game/XPT2046.py +++ b/bm_game/XPT2046.py @@ -14,101 +14,101 @@ from bm_game.SPIManager import SPIManager + class XPT2046(object): - - StartBit = 0b10000000 - - class ChannelSelect(object): - X_POSITION = 0b01010000 - Y_POSITION = 0b00010000 - Z1_POSITION = 0b00110000 - Z2_POSITION = 0b01000000 - TEMPERATURE_0 = 0b00000000 - TEMPERATURE_1 = 0b01110000 - BATTERY_VOLTAGE = 0b00100000 - AUXILIARY = 0b01100000 - - class ConversionSelect(object): - _8_BIT = 0b00001000 - _12_BIT = 0b00000000 - - def __init__(self): - self._ConversionSelect = XPT2046.ConversionSelect._12_BIT - self._SPIManager = SPIManager() - - def setMode(self, conversionSelect): - self._ConversionSelect = conversionSelect - - def makeControlByte(self, channelSelect): - # @@TODO Other elements in control byte. - return XPT2046.StartBit | channelSelect | self._ConversionSelect - - def readValue(self, channelSelect): - controlByte = self.makeControlByte(channelSelect) - msg = bytearray() - msg.append(controlByte) - self._SPIManager.SPISelect() - self._SPIManager.SPISend(msg) - - # Skip the 'busy' bit. - self._SPIManager.SPIPulseClock(); - - responseValue = 0 - - if self._ConversionSelect == XPT2046.ConversionSelect._12_BIT: - responseData = self._SPIManager.SPIReceive(12) - responseValue = (responseData[0] << 4) | (responseData[1] >> 4) - else: - responseData = self._SPIManager.SPIReceive(8) - responseValue = responseData[0] - - self._SPIManager.SPIUnSelect() - return responseValue - - - def readX(self): - return self.readValue(XPT2046.ChannelSelect.X_POSITION) - - def readY(self): - return self.readValue(XPT2046.ChannelSelect.Y_POSITION) - - def readZ1(self): - return self.readValue(XPT2046.ChannelSelect.Z1_POSITION) - - def readZ2(self): - return self.readValue(XPT2046.ChannelSelect.Z2_POSITION) - - def readBatteryVoltage(self): - return self.readValue(XPT2046.ChannelSelect.BATTERY_VOLTAGE) - - def readTemperature0(self): - return self.readValue(XPT2046.ChannelSelect.TEMPERATURE_0) - - def readTemperature1(self): - return self.readValue(XPT2046.ChannelSelect.TEMPERATURE_1) - - def readAuxiliary(self): - return self.readValue(XPT2046.ChannelSelect.AUXILIARY) - - def readTouchPressure(self): - # Formula (option 1) according to the datasheet (12bit conversion) - # RTouch = RX-Plate.(XPosition/4096).((Z1/Z2)-1) - # Not sure of the correct value of RX-Plate. - # Assuming the ratio is sufficient. - # Empirically this function seems to yield a values in the range of 0.4 - # for a firm touch, and 1.75 for a light touch. - - x = self.readX(); - z1 = self.readZ1(); - z2 = self.readZ2(); - - # Avoid division by zero exception - if (z1 == 0) : - z1 = 1 - - xDivisor = 4096; - if (self._ConversionSelect == XPT2046.ConversionSelect._8_BIT) : - xDivisor = 256; - - result = ( x / xDivisor) * (( z2 / z1) - 1); - return result; + + StartBit = 0b10000000 + + class ChannelSelect(object): + X_POSITION = 0b01010000 + Y_POSITION = 0b00010000 + Z1_POSITION = 0b00110000 + Z2_POSITION = 0b01000000 + TEMPERATURE_0 = 0b00000000 + TEMPERATURE_1 = 0b01110000 + BATTERY_VOLTAGE = 0b00100000 + AUXILIARY = 0b01100000 + + class ConversionSelect(object): + _8_BIT = 0b00001000 + _12_BIT = 0b00000000 + + def __init__(self): + self._ConversionSelect = XPT2046.ConversionSelect._12_BIT + self._SPIManager = SPIManager() + + def setMode(self, conversionSelect): + self._ConversionSelect = conversionSelect + + def makeControlByte(self, channelSelect): + # @@TODO Other elements in control byte. + return XPT2046.StartBit | channelSelect | self._ConversionSelect + + def readValue(self, channelSelect): + controlByte = self.makeControlByte(channelSelect) + msg = bytearray() + msg.append(controlByte) + self._SPIManager.SPISelect() + self._SPIManager.SPISend(msg) + + # Skip the 'busy' bit. + self._SPIManager.SPIPulseClock() + + responseValue = 0 + + if self._ConversionSelect == XPT2046.ConversionSelect._12_BIT: + responseData = self._SPIManager.SPIReceive(12) + responseValue = (responseData[0] << 4) | (responseData[1] >> 4) + else: + responseData = self._SPIManager.SPIReceive(8) + responseValue = responseData[0] + + self._SPIManager.SPIUnSelect() + return responseValue + + def readX(self): + return self.readValue(XPT2046.ChannelSelect.X_POSITION) + + def readY(self): + return self.readValue(XPT2046.ChannelSelect.Y_POSITION) + + def readZ1(self): + return self.readValue(XPT2046.ChannelSelect.Z1_POSITION) + + def readZ2(self): + return self.readValue(XPT2046.ChannelSelect.Z2_POSITION) + + def readBatteryVoltage(self): + return self.readValue(XPT2046.ChannelSelect.BATTERY_VOLTAGE) + + def readTemperature0(self): + return self.readValue(XPT2046.ChannelSelect.TEMPERATURE_0) + + def readTemperature1(self): + return self.readValue(XPT2046.ChannelSelect.TEMPERATURE_1) + + def readAuxiliary(self): + return self.readValue(XPT2046.ChannelSelect.AUXILIARY) + + def readTouchPressure(self): + # Formula (option 1) according to the datasheet (12bit conversion) + # RTouch = RX-Plate.(XPosition/4096).((Z1/Z2)-1) + # Not sure of the correct value of RX-Plate. + # Assuming the ratio is sufficient. + # Empirically this function seems to yield a values in the range of 0.4 + # for a firm touch, and 1.75 for a light touch. + + x = self.readX() + z1 = self.readZ1() + z2 = self.readZ2() + + # Avoid division by zero exception + if (z1 == 0): + z1 = 1 + + xDivisor = 4096 + if (self._ConversionSelect == XPT2046.ConversionSelect._8_BIT): + xDivisor = 256 + + result = (x / xDivisor) * ((z2 / z1) - 1) + return result diff --git a/bm_game/displaying.py b/bm_game/displaying.py index 9dab128..a95c82e 100644 --- a/bm_game/displaying.py +++ b/bm_game/displaying.py @@ -52,13 +52,13 @@ def __init__(self, x, y, pixel_per_spin): # hardware display self.hw_display = ili9341.ILI9341( - HW_SPI, - width=WIDTH, - height=HEIGHT, - baudrate=30000000, - cs=digitalio.DigitalInOut(CS_PIN), - dc=digitalio.DigitalInOut(DC_PIN), - rst=digitalio.DigitalInOut(RST_PIN)) + HW_SPI, + width=WIDTH, + height=HEIGHT, + baudrate=30000000, + cs=digitalio.DigitalInOut(CS_PIN), + dc=digitalio.DigitalInOut(DC_PIN), + rst=digitalio.DigitalInOut(RST_PIN)) self.size_field = np.array([x, y]) self.pixel_per_spin = pixel_per_spin @@ -74,16 +74,26 @@ def __init__(self, x, y, pixel_per_spin): self.level_new = False # Images - dir_path = os.path.dirname(os.path.realpath(__file__)) + dir_path = os.path.dirname(os.path.realpath(__file__)) self.images = [ [ - pygame.transform.scale(pygame.image.load(f"{dir_path}/images/spinup.png"), (self.pixel_per_spin, self.pixel_per_spin)), - pygame.transform.scale(pygame.image.load(f"{dir_path}/images/spindown.png"), (self.pixel_per_spin, self.pixel_per_spin)), - pygame.transform.scale(pygame.image.load(f"{dir_path}/images/questionmark.png"), (self.pixel_per_spin, self.pixel_per_spin)), + pygame.transform.scale( + pygame.image.load(f"{dir_path}/images/spinup.png"), + (self.pixel_per_spin, self.pixel_per_spin)), + pygame.transform.scale( + pygame.image.load(f"{dir_path}/images/spindown.png"), + (self.pixel_per_spin, self.pixel_per_spin)), + pygame.transform.scale( + pygame.image.load(f"{dir_path}/images/questionmark.png"), + (self.pixel_per_spin, self.pixel_per_spin)), ], [ - pygame.transform.scale(pygame.image.load(f"{dir_path}/images/spinup_fix.png"), (self.pixel_per_spin, self.pixel_per_spin)), - pygame.transform.scale(pygame.image.load(f"{dir_path}/images/spindown_fix.png"), (self.pixel_per_spin, self.pixel_per_spin)), + pygame.transform.scale( + pygame.image.load(f"{dir_path}/images/spinup_fix.png"), + (self.pixel_per_spin, self.pixel_per_spin)), + pygame.transform.scale( + pygame.image.load(f"{dir_path}/images/spindown_fix.png"), + (self.pixel_per_spin, self.pixel_per_spin)), ], ] @@ -117,16 +127,15 @@ def update(self, state, forced): self.update_target() pygame.display.update() - strFormat = 'RGB' raw_str = pygame.image.tostring(self.win, strFormat, False) - #print(self.win.get_size()) + # print(self.win.get_size()) image = Image.frombytes(strFormat, self.win.get_size(), raw_str) - #print(image.size) - image = image.resize((320, 240), box = (0,0,320, 240)) + # print(image.size) + image = image.resize((320, 240), box=(0, 0, 320, 240)) image = image.transpose(Image.ROTATE_90) - #image.save(f'out/{datetime.now()}.png') - #print(image.size) + # image.save(f'out/{datetime.now()}.png') + # print(image.size) self.hw_display.image(image) def update_field(self, state, forced): @@ -150,10 +159,11 @@ def update_target(self): self.win.blit(img, (i * self.pixel_per_spin + offset_x, j * self.pixel_per_spin + offset_y)) - pygame.draw.rect(self.win, BLACK, - (*((self.size_field // 2 - 2) * self.pixel_per_spin), - 3 * self.pixel_per_spin, 3 * self.pixel_per_spin,), - 1) + pygame.draw.rect( + self.win, BLACK, + (*((self.size_field // 2 - 2) * self.pixel_per_spin), + 3 * self.pixel_per_spin, 3 * self.pixel_per_spin,), + 1) def set_up_level(self, level_txt, target): """at beginning of level save text and target""" diff --git a/bm_game/game.py b/bm_game/game.py index 43a2232..c162bd1 100644 --- a/bm_game/game.py +++ b/bm_game/game.py @@ -11,6 +11,7 @@ class Game: """this is where the magic happens: lvl control and general procedure""" + def __init__(self, size, pixel_per_spin): self.size = size self.pixel_per_spin = pixel_per_spin @@ -26,7 +27,8 @@ def __init__(self, size, pixel_per_spin): [(i // 3, i % 3, i // 3 < i % 3) for i in range(9)], [(i // 3, i % 3, i // 3 == i % 3) for i in range(9)], [(i // 3, i % 3, i // 3 != i % 3) for i in range(9)], - [(0, 1, 0), (1, 1, 0), (2, 1, 0), (1, 0, 1), (1, 1, 1), (1, 2, 1), ], + [(0, 1, 0), (1, 1, 0), (2, 1, 0), + (1, 0, 1), (1, 1, 1), (1, 2, 1), ], ] self.level_no = 0 @@ -44,12 +46,14 @@ def __init__(self, size, pixel_per_spin): def check_win(self): """determine whether target satisfied, if so upgrade lvl""" - to_check = self.ising.get_rectangular_states()[self.size // 2 - 2:, self.size // 2 - 2:] + to_check = self.ising.get_rectangular_states( + )[self.size // 2 - 2:, self.size // 2 - 2:] to_check = to_check[:3, :3] # print(self.ising.get_rectangular_states()) # print(to_check) # time.sleep(400) - winning = np.all(to_check[self.target > -1] == self.target[self.target > -1]) + winning = np.all(to_check[self.target > -1] == + self.target[self.target > -1]) if not winning: return self.level_no += 1 @@ -104,14 +108,16 @@ def run(self): sys.exit() # measure touch x_touch, y_touch = self.touch_input.get_touch_input( - self.x_lim, - self.y_lim) + self.x_lim, + self.y_lim) if (x_touch is not None): - #cox, coy = displaying.pygame.mouse.get_pos() + # cox, coy = displaying.pygame.mouse.get_pos() cox, coy = y_touch, x_touch # the following loops through the values 1, 0, -1 - idx, idy = cox // self.pixel_per_spin, coy // self.pixel_per_spin - if idx in range(self.size) and idy in range(self.size) and not ( + idx, idy = cox // self.pixel_per_spin, coy //\ + self.pixel_per_spin + if idx in range(self.size) and idy in range(self.size)\ + and not ( idx in range(2, 5) and idy in range(2, 5) ): self.forced_spins[idx, idy] %= 3 @@ -119,9 +125,11 @@ def run(self): self.force_spins() states = self.ising.get_rectangular_states() - self.display.update(states, forced=(self.forced_spins > -1)) + self.display.update( + states, forced=(self.forced_spins > -1)) else: - print(f"from xy{cox}{coy} followed idxy{idx}{idy}, but doesnt exit") + print(f"from xy{cox}{coy} followed idxy{idx}{idy}," + " but doesnt exit") time.sleep(.08 + 0 * i) diff --git a/bm_game/ising.py b/bm_game/ising.py index 151bb01..78d1cab 100644 --- a/bm_game/ising.py +++ b/bm_game/ising.py @@ -17,14 +17,16 @@ def create_connection_matrix(size: int): unit_index = row * size + col # neigbors in the row - nr_left = (unit_index + size - 1) if (col == 0) else (unit_index - 1) - nr_right = (unit_index - size + 1) if (col == - size-1) else (unit_index + 1) + nr_left = (unit_index + size - 1) if \ + (col == 0) else (unit_index - 1) + nr_right = (unit_index - size + 1) if \ + (col == size-1) else (unit_index + 1) # neighbors in the column - nc_up = (unit_index + (size-1)*size) if (row == 0) else (unit_index - size) - nc_down = (unit_index - (size-1)*size) if (row == - (size-1)) else (unit_index + size) + nc_up = (unit_index + (size-1)*size) if \ + (row == 0) else (unit_index - size) + nc_down = (unit_index - (size-1)*size) if \ + (row == (size-1)) else (unit_index + size) # set the connections to one weights[unit_index, [nr_left, nr_right, nc_up, nc_down]] = 1 diff --git a/bm_game/touchscreen.py b/bm_game/touchscreen.py index 3f8b81d..6acdb37 100644 --- a/bm_game/touchscreen.py +++ b/bm_game/touchscreen.py @@ -5,9 +5,10 @@ # calibration constants Y_AT_ZERO = 400 Y_AT_FULL = 2640 -X_AT_ZERO = 3850 # x is flipped +X_AT_ZERO = 3850 # x is flipped X_AT_FULL = 805 + class TouchInput(): """Class to handle the touchscreen input""" @@ -26,7 +27,7 @@ def get_touch_input(self, x_max, y_max): # first check if the preassure is sensible print('Called for measurement') - preassure = round(self.xpt2046.readTouchPressure(),2) + preassure = round(self.xpt2046.readTouchPressure(), 2) if preassure < 0.2 or preassure > 800.0: # this is no touch return None, None @@ -42,4 +43,3 @@ def get_touch_input(self, x_max, y_max): print(f'The scaled data: x: {x_scaled}, y:{y_scaled}') return x_scaled, y_scaled - diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..2d7e731 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[pycodestyle] +exclude = bm_game/SPIManager.py +statistics = True \ No newline at end of file