display: Make hd44780 glyphs configurable

Allow the 20x4 hd44780 screen glyphs to be customizable from the
config file.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2020-06-08 22:04:24 -04:00
parent 1a7e4e51b3
commit 7713986ae1
6 changed files with 179 additions and 115 deletions

View File

@ -1913,7 +1913,15 @@
# pixel) where '.' is a blank pixel and '*' is an on pixel (e.g., # pixel) where '.' is a blank pixel and '*' is an on pixel (e.g.,
# "****************" to display a solid horizontal line). Put each # "****************" to display a solid horizontal line). Put each
# display line into a separate config line. The glyph must consist # display line into a separate config line. The glyph must consist
# of exactly 16 lines with 16 bits each. # of exactly 16 lines with 16 bits each. This parameter is optional.
#hd44780_data:
# Glyph to use on 20x4 hd44780 displays. The glyph must consist of
# exactly 8 lines with 5 bits each. This parameter is optional.
#hd44780_slot:
# The hd44780 hardware index (0..7) to store the glyph at. If
# multiple distinct images use the same slot then make sure to only
# use one of those images in any given screen. This parameter is
# required if hd44780_data is specified.
# If a primary [display] section has been defined in printer.cfg as shown # If a primary [display] section has been defined in printer.cfg as shown
# above it is possible to define multiple auxilary displays. Note that # above it is possible to define multiple auxilary displays. Note that

View File

@ -188,7 +188,7 @@ text: { render("_print_status") }
###################################################################### ######################################################################
# Default display glyphs # Default 16x4 glyphs
###################################################################### ######################################################################
[display_glyph extruder] [display_glyph extruder]
@ -327,8 +327,130 @@ data:
# In addition to the above glyphs, 16x4 displays also have the # In addition to the above glyphs, 16x4 displays also have the
# following hard-coded single character glyphs: right_arrow, degrees. # following hard-coded single character glyphs: right_arrow, degrees.
# The 20x4 displays do not have configurable glyphs. They do have
# hard-coded support for the following single character glyphs: ######################################################################
# right_arrow, degrees, extruder, bed, bed_heat1 (same as bed), # Default 20x4 glyphs
# bed_heat2 (same as bed), feedrate, clock, usb, sd, fan1, fan2 (same ######################################################################
# as fan1).
[display_glyph extruder]
hd44780_slot: 0
hd44780_data:
..*..
.*.*.
.*.*.
.*.*.
.*.*.
*...*
*...*
.***.
[display_glyph bed]
hd44780_slot: 1
hd44780_data:
.....
*****
*.*.*
*...*
*.*.*
*****
.....
.....
[display_glyph bed_heat1]
hd44780_slot: 1
hd44780_data:
.....
*****
*.*.*
*...*
*.*.*
*****
.....
.....
[display_glyph bed_heat2]
hd44780_slot: 1
hd44780_data:
.....
*****
*.*.*
*...*
*.*.*
*****
.....
.....
[display_glyph fan]
hd44780_slot: 2
hd44780_data:
.....
*..**
**.*.
..*..
.*.**
**..*
.....
.....
[display_glyph feedrate]
hd44780_slot: 3
hd44780_data:
***..
*....
**...
*.***
..*.*
..**.
..*.*
.....
[display_glyph clock]
hd44780_slot: 4
hd44780_data:
.....
.***.
*..**
*.*.*
*...*
.***.
.....
.....
[display_glyph degrees]
hd44780_slot: 5
hd44780_data:
.**..
*..*.
*..*.
.**..
.....
.....
.....
.....
[display_glyph usb]
hd44780_slot: 6
hd44780_data:
.***.
.***.
.***.
*****
*****
*****
..*..
..*..
[display_glyph sd]
hd44780_slot: 6
hd44780_data:
.....
..***
.****
*****
*****
*****
*****
.....
# In addition to the above glyphs, 20x4 displays also have the
# following hard-coded glyphs: right_arrow.

View File

@ -104,6 +104,18 @@ class PrinterLCD:
self.screen_update_timer = self.reactor.register_timer( self.screen_update_timer = self.reactor.register_timer(
self.screen_update_event) self.screen_update_event)
# Configurable display # Configurable display
def _parse_glyph(self, config, glyph_name, data, width, height):
glyph_data = []
for line in data.split('\n'):
line = line.strip().replace('.', '0').replace('*', '1')
if not line:
continue
if len(line) != width or line.replace('0', '').replace('1', ''):
raise config.error("Invalid glyph line in %s" % (glyph_name,))
glyph_data.append(int(line, 2))
if len(glyph_data) != height:
raise config.error("Glyph %s incorrect lines" % (glyph_name,))
return glyph_data
def load_config(self, config): def load_config(self, config):
# Load default display config file # Load default display config file
pconfig = self.printer.lookup_object('configfile') pconfig = self.printer.lookup_object('configfile')
@ -145,18 +157,15 @@ class PrinterLCD:
if c.get_name() not in dg_main_names] if c.get_name() not in dg_main_names]
for dg in dg_main + dg_def: for dg in dg_main + dg_def:
glyph_name = dg.get_name()[len(dg_prefix):] glyph_name = dg.get_name()[len(dg_prefix):]
glyph_data = [] data = dg.get('data', None)
for line in dg.get('data').split('\n'): if data is not None:
line = line.strip().replace('.', '0').replace('*', '1') idata = self._parse_glyph(config, glyph_name, data, 16, 16)
if not line: icons.setdefault(glyph_name, {})['icon16x16'] = idata
continue data = dg.get('hd44780_data', None)
if len(line) != 16 or line.replace('0', '').replace('1', ''): if data is not None:
raise config.error("Invalid glyph line in %s" slot = dg.getint('hd44780_slot', minval=0, maxval=7)
% (glyph_name,)) idata = self._parse_glyph(config, glyph_name, data, 5, 8)
glyph_data.append(int(line, 2)) icons.setdefault(glyph_name, {})['icon5x8'] = (slot, idata)
if len(glyph_data) != 16:
raise config.error("Glyph %s must be 16 lines" % (glyph_name,))
icons[glyph_name] = glyph_data
self.lcd_chip.set_glyphs(icons) self.lcd_chip.set_glyphs(icons)
# Initialization # Initialization
def handle_ready(self): def handle_ready(self):

View File

@ -8,6 +8,8 @@ import logging
BACKGROUND_PRIORITY_CLOCK = 0x7fffffff00000000 BACKGROUND_PRIORITY_CLOCK = 0x7fffffff00000000
TextGlyphs = { 'right_arrow': '\x7e' }
HD44780_DELAY = .000040 HD44780_DELAY = .000040
class HD44780: class HD44780:
@ -27,6 +29,7 @@ class HD44780:
self.oid = self.mcu.create_oid() self.oid = self.mcu.create_oid()
self.mcu.register_config_callback(self.build_config) self.mcu.register_config_callback(self.build_config)
self.send_data_cmd = self.send_cmds_cmd = None self.send_data_cmd = self.send_cmds_cmd = None
self.icons = {}
# framebuffers # framebuffers
self.text_framebuffers = [bytearray(' '*40), bytearray(' '*40)] self.text_framebuffers = [bytearray(' '*40), bytearray(' '*40)]
self.glyph_framebuffer = bytearray(64) self.glyph_framebuffer = bytearray(64)
@ -85,10 +88,6 @@ class HD44780:
for i, cmds in enumerate(init): for i, cmds in enumerate(init):
minclock = self.mcu.print_time_to_clock(print_time + i * .100) minclock = self.mcu.print_time_to_clock(print_time + i * .100)
self.send_cmds_cmd.send([self.oid, cmds], minclock=minclock) self.send_cmds_cmd.send([self.oid, cmds], minclock=minclock)
# Add custom fonts
self.glyph_framebuffer[:len(HD44780_chars)] = HD44780_chars
for i in range(len(self.glyph_framebuffer)):
self.all_framebuffers[2][1][i] = self.glyph_framebuffer[i] ^ 1
self.flush() self.flush()
def write_text(self, x, y, data): def write_text(self, x, y, data):
if x + len(data) > 20: if x + len(data) > 20:
@ -96,8 +95,17 @@ class HD44780:
pos = x + ((y & 0x02) >> 1) * 20 pos = x + ((y & 0x02) >> 1) * 20
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): def set_glyphs(self, glyphs):
pass for glyph_name, glyph_data in glyphs.items():
data = glyph_data.get('icon5x8')
if data is not None:
self.icons[glyph_name] = data
def write_glyph(self, x, y, glyph_name): 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, chr(slot))
self.glyph_framebuffer[slot * 8:(slot + 1) * 8] = bits
return 1
char = TextGlyphs.get(glyph_name) char = TextGlyphs.get(glyph_name)
if char is not None: if char is not None:
# Draw character # Draw character
@ -112,90 +120,3 @@ class HD44780:
self.text_framebuffers[1][:] = spaces self.text_framebuffers[1][:] = spaces
def get_dimensions(self): def get_dimensions(self):
return (20, 4) return (20, 4)
HD44780_chars = [
# Extruder (a thermometer)
0b00100,
0b01010,
0b01010,
0b01010,
0b01010,
0b10001,
0b10001,
0b01110,
# Heated bed
0b00000,
0b11111,
0b10101,
0b10001,
0b10101,
0b11111,
0b00000,
0b00000,
# Feed rate
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,
# USB
0b01110,
0b01110,
0b01110,
0b11111,
0b11111,
0b11111,
0b00100,
0b00100,
# SD
0b00000,
0b00111,
0b01111,
0b11111,
0b11111,
0b11111,
0b11111,
0b00000,
# Fan
0b00000,
0b10011,
0b11010,
0b00100,
0b01011,
0b11001,
0b00000,
0b00000,
]
TextGlyphs = {
'right_arrow': '\x7e',
'extruder': '\x00',
'bed': '\x01', 'bed_heat1': '\x01', 'bed_heat2': '\x01',
'feedrate': '\x02',
'clock': '\x03',
'degrees': '\x04',
'usb': '\x05',
'sd': '\x06',
'fan1': '\x07', 'fan2': '\x07',
}

View File

@ -137,7 +137,9 @@ class ST7920:
self.graphics_framebuffers[gfx_fb][x:x+len(data)] = data self.graphics_framebuffers[gfx_fb][x:x+len(data)] = data
def set_glyphs(self, glyphs): def set_glyphs(self, glyphs):
for glyph_name, glyph_data in glyphs.items(): for glyph_name, glyph_data in glyphs.items():
self.icons[glyph_name] = glyph_data data = glyph_data.get('icon16x16')
if data is not None:
self.icons[glyph_name] = data
# Setup animated glyphs # Setup animated glyphs
self.cache_glyph('fan2', 'fan1', 0) self.cache_glyph('fan2', 'fan1', 0)
self.cache_glyph('bed_heat2', 'bed_heat1', 1) self.cache_glyph('bed_heat2', 'bed_heat1', 1)

View File

@ -81,9 +81,11 @@ class DisplayBase:
pix_x += 1 pix_x += 1
def set_glyphs(self, glyphs): def set_glyphs(self, glyphs):
for glyph_name, glyph_data in glyphs.items(): for glyph_name, glyph_data in glyphs.items():
top1, bot1 = self._swizzle_bits([d >> 8 for d in glyph_data]) data = glyph_data.get('icon16x16')
top2, bot2 = self._swizzle_bits(glyph_data) if data is not None:
self.icons[glyph_name] = (top1 + top2, bot1 + bot2) top1, bot1 = self._swizzle_bits([d >> 8 for d in data])
top2, bot2 = self._swizzle_bits(data)
self.icons[glyph_name] = (top1 + top2, bot1 + bot2)
def write_glyph(self, x, y, glyph_name): def write_glyph(self, x, y, glyph_name):
icon = self.icons.get(glyph_name) icon = self.icons.get(glyph_name)
if icon is not None and x < 15: if icon is not None and x < 15: