diff options
Diffstat (limited to 'klippy/extras/display/aip31068_spi.py')
-rw-r--r-- | klippy/extras/display/aip31068_spi.py | 151 |
1 files changed, 93 insertions, 58 deletions
diff --git a/klippy/extras/display/aip31068_spi.py b/klippy/extras/display/aip31068_spi.py index 75f4978f..9bbbbdaa 100644 --- a/klippy/extras/display/aip31068_spi.py +++ b/klippy/extras/display/aip31068_spi.py @@ -16,10 +16,11 @@ from .. import bus -LINE_LENGTH_DEFAULT=20 -LINE_LENGTH_OPTIONS={16:16, 20:20} +LINE_LENGTH_DEFAULT = 20 +LINE_LENGTH_OPTIONS = {16: 16, 20: 20} + +TextGlyphs = {"right_arrow": b"\x7e"} -TextGlyphs = { 'right_arrow': b'\x7e' } # Each command is 9 bits long: # 1 bit for RS (Register Select) - 0 for command, 1 for data @@ -30,66 +31,79 @@ TextGlyphs = { 'right_arrow': b'\x7e' } # or just by OR with enabled flags: # cmd = CMND | flg_CMND.param1 class CMND: - CLR = 1 # Clear display - HOME = 2 # Return home + CLR = 1 # Clear display + HOME = 2 # Return home ENTERY_MODE = 2**2 # Entry mode set - DISPLAY = 2**3 # Display on/off control - SHIFT = 2**4 # Cursor or display shift - FUNCTION = 2**5 # Function set - CGRAM = 2**6 # Character Generator RAM - DDRAM = 2**7 # Display Data RAM - WRITE_RAM = 2**8 # Write to RAM + DISPLAY = 2**3 # Display on/off control + SHIFT = 2**4 # Cursor or display shift + FUNCTION = 2**5 # Function set + CGRAM = 2**6 # Character Generator RAM + DDRAM = 2**7 # Display Data RAM + WRITE_RAM = 2**8 # Write to RAM + # Define flags for all commands: class flg_ENTERY_MODE: - INC = 2**1 # Increment - SHIFT = 2**0 # Shift display + INC = 2**1 # Increment + SHIFT = 2**0 # Shift display + class flg_DISPLAY: - ON = 2**2 # Display ON - CURSOR = 2**1 # Cursor ON - BLINK = 2**0 # Blink ON + ON = 2**2 # Display ON + CURSOR = 2**1 # Cursor ON + BLINK = 2**0 # Blink ON + class flg_SHIFT: - WHOLE_DISPLAY = 2**3 # Shift whole display - RIGHT = 2**2 # Shift right + WHOLE_DISPLAY = 2**3 # Shift whole display + RIGHT = 2**2 # Shift right + class flg_FUNCTION: - TWO_LINES = 2**3 # 2-line display mode - FIVE_BY_ELEVEN = 2**2 # 5x11 dot character font + TWO_LINES = 2**3 # 2-line display mode + FIVE_BY_ELEVEN = 2**2 # 5x11 dot character font + class flg_CGRAM: - MASK = 0b00111111 # CGRAM address mask + MASK = 0b00111111 # CGRAM address mask + class flg_DDRAM: - MASK = 0b01111111 # DDRAM address mask + MASK = 0b01111111 # DDRAM address mask + class flg_WRITE_RAM: - MASK = 0b11111111 # Write RAM mask + MASK = 0b11111111 # Write RAM mask -DISPLAY_INIT_CMNDS= [ + +DISPLAY_INIT_CMNDS = [ # CMND.CLR - no need as framebuffer will rewrite all - CMND.HOME, # move cursor to home (0x00) - CMND.ENTERY_MODE | flg_ENTERY_MODE.INC, # increment cursor and no shift - CMND.DISPLAY | flg_DISPLAY.ON, # keep cursor and blinking off - CMND.SHIFT | flg_SHIFT.RIGHT, # shift right cursor only - CMND.FUNCTION | flg_FUNCTION.TWO_LINES, # 2-line display mode, 5x8 dots + CMND.HOME, # move cursor to home (0x00) + CMND.ENTERY_MODE | flg_ENTERY_MODE.INC, # increment cursor and no shift + CMND.DISPLAY | flg_DISPLAY.ON, # keep cursor and blinking off + CMND.SHIFT | flg_SHIFT.RIGHT, # shift right cursor only + CMND.FUNCTION | flg_FUNCTION.TWO_LINES, # 2-line display mode, 5x8 dots ] + class aip31068_spi: def __init__(self, config): self.printer = config.get_printer() # spi config self.spi = bus.MCU_SPI_from_config( - config, 0x00, pin_option="latch_pin") # (config, mode, cs_name) + config, 0x00, pin_option="latch_pin" + ) # (config, mode, cs_name) self.mcu = self.spi.get_mcu() self.icons = {} - self.line_length = config.getchoice('line_length', LINE_LENGTH_OPTIONS, - LINE_LENGTH_DEFAULT) + self.line_length = config.getchoice( + "line_length", LINE_LENGTH_OPTIONS, LINE_LENGTH_DEFAULT + ) # each controller's line is 2 lines on the display and hence twice # line length - self.text_framebuffers = [bytearray(b' '*2*self.line_length), - bytearray(b' '*2*self.line_length)] + self.text_framebuffers = [ + bytearray(b" " * 2 * self.line_length), + bytearray(b" " * 2 * self.line_length), + ] self.glyph_framebuffer = bytearray(64) # all_framebuffers - list of tuples per buffer type. # Each tuple contains: @@ -102,23 +116,33 @@ class aip31068_spi: # (immutable tuple is allowed to store mutable bytearray) self.all_framebuffers = [ # Text framebuffers - (self.text_framebuffers[0], bytearray(b'~'*2*self.line_length), - CMND.DDRAM | (flg_DDRAM.MASK & 0x00) ), - (self.text_framebuffers[1], bytearray(b'~'*2*self.line_length), - CMND.DDRAM | (flg_DDRAM.MASK & 0x40) ), + ( + self.text_framebuffers[0], + bytearray(b"~" * 2 * self.line_length), + CMND.DDRAM | (flg_DDRAM.MASK & 0x00), + ), + ( + self.text_framebuffers[1], + bytearray(b"~" * 2 * self.line_length), + CMND.DDRAM | (flg_DDRAM.MASK & 0x40), + ), # Glyph framebuffer - (self.glyph_framebuffer, bytearray(b'~'*64), - CMND.CGRAM | (flg_CGRAM.MASK & 0x00) ) ] + ( + self.glyph_framebuffer, + bytearray(b"~" * 64), + CMND.CGRAM | (flg_CGRAM.MASK & 0x00), + ), + ] + @staticmethod - def encode(data, width = 9): + def encode(data, width=9): encoded_bytes = [] accumulator = 0 # To accumulate bits acc_bits = 0 # Count of bits in the accumulator for num in data: # check that num will fit in width bits if num >= (1 << width): - raise ValueError("Number {} does not fit in {} bits". - format(num, width)) + raise ValueError("Number {} does not fit in {} bits".format(num, width)) # Shift the current number into the accumulator from the right accumulator = (accumulator << width) | num acc_bits += width # Update the count of bits in the accumulator @@ -135,6 +159,7 @@ class aip31068_spi: last_byte = accumulator << (8 - acc_bits) encoded_bytes.append(last_byte) return encoded_bytes + def send(self, data, minclock=0): # different commands have different processing time # to avoid timing violation pad with some fast command, e.g. ENTRY_MODE @@ -142,56 +167,63 @@ class aip31068_spi: pad = CMND.ENTERY_MODE | flg_ENTERY_MODE.INC for i in range(0, len(data), 8): # Take a slice of 8 numbers - group = data[i:i+8] + group = data[i : i + 8] # Pad the group if it has fewer than 8 elements if len(group) < 8: group.extend([pad] * (8 - len(group))) self.spi.spi_send(self.encode(group), minclock) + def flush(self): # Find all differences in the framebuffers and send them to the chip for new_data, old_data, fb_cmnd in self.all_framebuffers: if new_data == old_data: continue # Find the position of all changed bytes in this framebuffer - diffs = [[i, 1] for i, (n, o) in enumerate(zip(new_data, old_data)) - if n != o] + diffs = [ + [i, 1] for i, (n, o) in enumerate(zip(new_data, old_data)) if n != o + ] # Batch together changes that are close to each other - for i in range(len(diffs)-2, -1, -1): + for i in range(len(diffs) - 2, -1, -1): pos, count = diffs[i] - nextpos, nextcount = diffs[i+1] + nextpos, nextcount = diffs[i + 1] if pos + 4 >= nextpos and nextcount < 16: diffs[i][1] = nextcount + (nextpos - pos) - del diffs[i+1] + del diffs[i + 1] # Transmit changes for pos, count in diffs: chip_pos = pos self.send([fb_cmnd + chip_pos]) - self.send([CMND.WRITE_RAM | byte for byte in - new_data[pos:pos+count]]) + self.send( + [CMND.WRITE_RAM | byte for byte in new_data[pos : pos + count]] + ) old_data[:] = new_data + def init(self): curtime = self.printer.get_reactor().monotonic() print_time = self.mcu.estimated_print_time(curtime) for i, cmds in enumerate(DISPLAY_INIT_CMNDS): - minclock = self.mcu.print_time_to_clock(print_time + i * .100) + minclock = self.mcu.print_time_to_clock(print_time + i * 0.100) self.send([cmds], minclock=minclock) self.flush() + def write_text(self, x, y, data): if x + len(data) > self.line_length: - data = data[:self.line_length - min(x, self.line_length)] + data = data[: self.line_length - min(x, self.line_length)] pos = x + ((y & 0x02) >> 1) * self.line_length - self.text_framebuffers[y & 1][pos:pos+len(data)] = data + self.text_framebuffers[y & 1][pos : pos + len(data)] = data + def set_glyphs(self, glyphs): for glyph_name, glyph_data in glyphs.items(): - data = glyph_data.get('icon5x8') + data = glyph_data.get("icon5x8") if data is not None: self.icons[glyph_name] = data + def write_glyph(self, x, y, glyph_name): data = self.icons.get(glyph_name) if data is not None: slot, bits = data self.write_text(x, y, [slot]) - self.glyph_framebuffer[slot * 8:(slot + 1) * 8] = bits + self.glyph_framebuffer[slot * 8 : (slot + 1) * 8] = bits return 1 char = TextGlyphs.get(glyph_name) if char is not None: @@ -199,11 +231,14 @@ class aip31068_spi: self.write_text(x, y, char) return 1 return 0 + def write_graphics(self, x, y, data): - pass # this display supports only hardcoded or 8 user defined glyphs + pass # this display supports only hardcoded or 8 user defined glyphs + def clear(self): - spaces = b' ' * 2*self.line_length + spaces = b" " * 2 * self.line_length self.text_framebuffers[0][:] = spaces self.text_framebuffers[1][:] = spaces + def get_dimensions(self): return (self.line_length, 4) |