diff --git a/klippy/extras/display.py b/klippy/extras/display.py index 01aa1dc0..45286c10 100644 --- a/klippy/extras/display.py +++ b/klippy/extras/display.py @@ -17,6 +17,11 @@ HD44780_DELAY = .000037 class HD44780: char_right_arrow = '\x7e' + char_thermometer = '\x00' + char_heater_bed = '\x01' + char_speed_factor = '\x02' + char_clock = '\x03' + char_degrees = '\x04' def __init__(self, config): self.printer = config.get_printer() # pin config @@ -90,19 +95,66 @@ class HD44780: for i, cmds in enumerate(init): minclock = self.mcu.print_time_to_clock(print_time + i * .100) self.send_cmds_cmd.send([self.oid, cmds], minclock=minclock) + # Add custom fonts + self.glyph_framebuffer[0][:len(HD44780_chars)] = HD44780_chars + for i in range(len(self.glyph_framebuffer[0])): + self.glyph_framebuffer[1][i] = self.glyph_framebuffer[0][i] ^ 1 self.flush() - def load_glyph(self, glyph_id, data, alt_text): - return alt_text def write_text(self, x, y, data): if x + len(data) > 20: data = data[:20 - min(x, 20)] pos = [0, 40, 20, 60][y] + x self.text_framebuffer[0][pos:pos+len(data)] = data - def write_graphics(self, x, y, row, data): - pass def clear(self): self.text_framebuffer[0][:] = ' '*80 +HD44780_chars = [ + # Thermometer + 0b00100, + 0b01010, + 0b01010, + 0b01010, + 0b01010, + 0b10001, + 0b10001, + 0b01110, + # Heated bed + 0b00000, + 0b11111, + 0b10101, + 0b10001, + 0b10101, + 0b11111, + 0b00000, + 0b00000, + # Speed factor + 0b11100, + 0b10000, + 0b11000, + 0b10111, + 0b00101, + 0b00110, + 0b00101, + 0b00000, + # Clock + 0b00000, + 0b01110, + 0b10011, + 0b10101, + 0b10001, + 0b01110, + 0b00000, + 0b00000, + # Degrees + 0b01100, + 0b10010, + 0b10010, + 0b01100, + 0b00000, + 0b00000, + 0b00000, + 0b00000, +] ###################################################################### # ST7920 (128x64 graphics) lcd chip @@ -200,12 +252,11 @@ class ST7920: 0x0c] # Enable display and hide cursor self.send(cmds) self.flush() - def load_glyph(self, glyph_id, data, alt_text): + def load_glyph(self, glyph_id, data): if len(data) > 32: data = data[:32] pos = min(glyph_id * 32, 96) self.glyph_framebuffer[0][pos:pos+len(data)] = data - return (0x00, glyph_id * 2) def write_text(self, x, y, data): if x + len(data) > 16: data = data[:16 - min(x, 16)] @@ -373,16 +424,17 @@ LCD_chips = { 'st7920': ST7920, 'hd44780': HD44780 } class PrinterLCD: def __init__(self, config): self.printer = config.get_printer() - self.lcd_chip = config.getchoice('lcd_type', LCD_chips)(config) - # work timer self.reactor = self.printer.get_reactor() - self.work_timer = self.reactor.register_timer(self.work_event) - # glyphs - self.fan_glyphs = self.heat_glyphs = None + self.lcd_chip = config.getchoice('lcd_type', LCD_chips)(config) + self.lcd_type = config.get('lcd_type') # printer objects self.gcode = self.toolhead = self.sdcard = None self.fan = self.extruder0 = self.extruder1 = self.heater_bed = None + # screen updating + self.screen_update_timer = self.reactor.register_timer( + self.screen_update_event) # Initialization + FAN1_GLYPH, FAN2_GLYPH, BED1_GLYPH, BED2_GLYPH = 0, 1, 2, 3 def printer_state(self, state): if state == 'ready': self.lcd_chip.init() @@ -395,28 +447,31 @@ class PrinterLCD: self.extruder1 = self.printer.lookup_object('extruder1', None) self.heater_bed = self.printer.lookup_object('heater_bed', None) # Load glyphs - self.fan_glyphs = [self.load_glyph(0, fan1_icon, "f*"), - self.load_glyph(1, fan2_icon, "f+")] - self.heat_glyphs = [self.load_glyph(2, heat1_icon, "b_"), - self.load_glyph(3, heat2_icon, "b-")] + self.load_glyph(self.BED1_GLYPH, heat1_icon) + self.load_glyph(self.BED2_GLYPH, heat2_icon) + self.load_glyph(self.FAN1_GLYPH, fan1_icon) + self.load_glyph(self.FAN2_GLYPH, fan2_icon) # Start screen update timer - self.reactor.update_timer(self.work_timer, self.reactor.NOW) - # Glyphs - def load_glyph(self, glyph_id, data, alt_text): + self.reactor.update_timer(self.screen_update_timer, self.reactor.NOW) + # ST7920 Glyphs + def load_glyph(self, glyph_id, data): + if self.lcd_type != 'st7920': + return glyph = [0x00] * (len(data) * 2) for i, bits in enumerate(data): glyph[i*2] = (bits >> 8) & 0xff glyph[i*2 + 1] = bits & 0xff - return self.lcd_chip.load_glyph(glyph_id, glyph, alt_text) - def animate_glyphs(self, eventtime, x, y, glyphs, do_animate): + return self.lcd_chip.load_glyph(glyph_id, glyph) + def animate_glyphs(self, eventtime, x, y, glyph_id, do_animate): frame = do_animate and int(eventtime) & 1 - self.lcd_chip.write_text(x, y, glyphs[frame]) + self.lcd_chip.write_text(x, y, (0, (glyph_id + frame)*2)) # Graphics drawing def draw_icon(self, x, y, data): for i, bits in enumerate(data): self.lcd_chip.write_graphics( x, y, i, [(bits >> 8) & 0xff, bits & 0xff]) def draw_progress_bar(self, x, y, width, value): + value = int(value * 100.) data = [0x00] * width char_pcnt = int(100/width) for i in range(width): @@ -433,66 +488,114 @@ class PrinterLCD: self.lcd_chip.write_graphics(x, y, i, data) self.lcd_chip.write_graphics(x, y, 15, [0xff]*width) # Screen updating - def format_temperature(self, info): - temperature, target = info['temperature'], info['target'] - if target and abs(temperature - target) > 2.: - return "%3d%s%-3d" % (temperature, self.lcd_chip.char_right_arrow, target) - return "%3d" % (temperature) - def work_event(self, eventtime): + def screen_update_event(self, eventtime): self.lcd_chip.clear() - write_text = self.lcd_chip.write_text + if self.lcd_type == 'hd44780': + self.screen_update_hd44780(eventtime) + else: + self.screen_update_st7920(eventtime) + self.lcd_chip.flush() + return eventtime + .500 + def screen_update_hd44780(self, eventtime): + lcd_chip = self.lcd_chip + # Heaters + if self.extruder0 is not None: + info = self.extruder0.get_heater().get_status(eventtime) + lcd_chip.write_text(0, 0, lcd_chip.char_thermometer) + self.draw_heater(1, 0, info) + if self.extruder1 is not None: + info = self.extruder1.get_heater().get_status(eventtime) + lcd_chip.write_text(0, 1, lcd_chip.char_thermometer) + self.draw_heater(1, 1, info) + if self.heater_bed is not None: + info = self.heater_bed.get_status(eventtime) + lcd_chip.write_text(10, 0, lcd_chip.char_heater_bed) + self.draw_heater(11, 0, info) + # Fan speed + if self.fan is not None: + info = self.fan.get_status(eventtime) + lcd_chip.write_text(10, 1, "Fan") + self.draw_percent(14, 1, 4, info['speed']) + # G-Code speed factor + gcode_info = self.gcode.get_status(eventtime) + lcd_chip.write_text(0, 2, lcd_chip.char_speed_factor) + self.draw_percent(1, 2, 4, gcode_info['speed_factor']) + # SD card print progress + if self.sdcard is not None: + info = self.sdcard.get_status(eventtime) + lcd_chip.write_text(7, 2, "SD") + self.draw_percent(9, 2, 4, info['progress']) + # Printing time and status + toolhead_info = self.toolhead.get_status(eventtime) + lcd_chip.write_text(14, 2, lcd_chip.char_clock) + self.draw_time(15, 2, toolhead_info['printing_time']) + self.draw_status(0, 3, gcode_info, toolhead_info) + def screen_update_st7920(self, eventtime): # Heaters if self.extruder0 is not None: info = self.extruder0.get_heater().get_status(eventtime) self.draw_icon(0, 0, nozzle_icon) - write_text(2, 0, self.format_temperature(info)) + self.draw_heater(2, 0, info) extruder_count = 1 if self.extruder1 is not None: info = self.extruder1.get_heater().get_status(eventtime) self.draw_icon(0, 1, nozzle_icon) - write_text(2, 1, self.format_temperature(info)) + self.draw_heater(2, 1, info) extruder_count = 2 if self.heater_bed is not None: info = self.heater_bed.get_status(eventtime) self.draw_icon(0, extruder_count, bed_icon) if info['target']: self.animate_glyphs(eventtime, 0, extruder_count, - self.heat_glyphs, True) - write_text(2, extruder_count, self.format_temperature(info)) + self.BED1_GLYPH, True) + self.draw_heater(2, extruder_count, info) # Fan speed if self.fan is not None: info = self.fan.get_status(eventtime) - self.animate_glyphs(eventtime, 10, 0, self.fan_glyphs, + self.animate_glyphs(eventtime, 10, 0, self.FAN1_GLYPH, info['speed'] != 0.) - write_text(12, 0, "%3d%%" % (info['speed'] * 100.,)) + self.draw_percent(12, 0, 4, info['speed']) # SD card print progress if self.sdcard is not None: info = self.sdcard.get_status(eventtime) - progress = int(info['progress'] * 100.) if extruder_count == 1: - write_text(0, 2, " {:^9}".format(str(progress)+'%')) - self.draw_progress_bar(0, 2, 10, progress) + x, y, width = 0, 2, 10 else: - write_text(10, 1, " {:^5}".format(str(progress)+'%')) - self.draw_progress_bar(10, 1, 6, progress) + x, y, width = 10, 1, 6 + self.draw_percent(x, y, width, info['progress']) + self.draw_progress_bar(x, y, width, info['progress']) # G-Code speed factor gcode_info = self.gcode.get_status(eventtime) if extruder_count == 1: self.draw_icon(10, 1, feedrate_icon) - write_text(12, 1, "%3d%%" % (gcode_info['speed_factor'] * 100.,)) - # Printing time + self.draw_percent(12, 1, 4, gcode_info['speed_factor']) + # Printing time and status toolhead_info = self.toolhead.get_status(eventtime) - printing_time = int(toolhead_info['printing_time']) - write_text(10, 2, " %02d:%02d" % ( - printing_time // (60 * 60), (printing_time // 60) % 60)) - # Printer status + self.draw_time(10, 2, toolhead_info['printing_time']) + self.draw_status(0, 3, gcode_info, toolhead_info) + # Screen update helpers + def draw_heater(self, x, y, info): + temperature, target = info['temperature'], info['target'] + if target and abs(temperature - target) > 2.: + s = "%3d%s%d" % (temperature, self.lcd_chip.char_right_arrow, target) + else: + s = "%3d" % (temperature,) + if self.lcd_type == 'hd44780': + s += self.lcd_chip.char_degrees + self.lcd_chip.write_text(x, y, s) + def draw_percent(self, x, y, width, value): + value = int(value * 100.) + self.lcd_chip.write_text(x, y, ("%d%%" % (value)).center(width)) + def draw_time(self, x, y, seconds): + seconds = int(seconds) + self.lcd_chip.write_text(x, y, "%02d:%02d" % ( + seconds // (60 * 60), (seconds // 60) % 60)) + def draw_status(self, x, y, gcode_info, toolhead_info): status = toolhead_info['status'] if status == 'Printing' or gcode_info['busy']: pos = self.toolhead.get_position() status = "X%-4dY%-4dZ%-5.2f" % (pos[0], pos[1], pos[2]) - write_text(0, 3, status) - self.lcd_chip.flush() - return eventtime + .500 + self.lcd_chip.write_text(x, y, status) def load_config(config): return PrinterLCD(config)