Some small refactorings

rebase020124
Ben 1 year ago
parent be3ba32458
commit f1849a5f88
  1. 262
      led-badge-11x44.py

@ -247,9 +247,9 @@ charmap = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \
u"àäòöùüèéêëôöûîïÿç" + \ u"àäòöùüèéêëôöûîïÿç" + \
u"ÀÅÄÉÈÊËÖÔÜÛÙŸ" u"ÀÅÄÉÈÊËÖÔÜÛÙŸ"
char_offset = {} char_offsets = {}
for i in range(len(charmap)): for i in range(len(charmap)):
char_offset[charmap[i]] = 11 * i char_offsets[charmap[i]] = 11 * i
# print(i, charmap[i], char_offset[charmap[i]]) # print(i, charmap[i], char_offset[charmap[i]])
bitmap_preloaded = [([], 0)] bitmap_preloaded = [([], 0)]
@ -320,7 +320,7 @@ def bitmap_char(ch):
bitmaps_preloaded_unused = False bitmaps_preloaded_unused = False
return bitmap_preloaded[ord(ch)] return bitmap_preloaded[ord(ch)]
o = char_offset[ch] o = char_offsets[ch]
return (font_11x44[o:o + 11], 1) return (font_11x44[o:o + 11], 1)
@ -334,7 +334,7 @@ def bitmap_text(text):
":gfx/logo.png:" preloads the file gfx/logo.png and is replaced the corresponding control char. ":gfx/logo.png:" preloads the file gfx/logo.png and is replaced the corresponding control char.
""" """
def colonrepl(m): def replace_symbolic(m):
name = m.group(1) name = m.group(1)
if name == '': if name == '':
return ':' return ':'
@ -343,10 +343,9 @@ def bitmap_text(text):
if '.' in name: if '.' in name:
bitmap_preloaded.append(bitmap_img(name)) bitmap_preloaded.append(bitmap_img(name))
return chr(len(bitmap_preloaded) - 1) return chr(len(bitmap_preloaded) - 1)
b = bitmap_named[name] return bitmap_named[name][2]
return b[2]
text = re.sub(r':([^:]*):', colonrepl, text) text = re.sub(r':([^:]*):', replace_symbolic, text)
buf = array('B') buf = array('B')
cols = 0 cols = 0
for c in text: for c in text:
@ -391,7 +390,7 @@ def bitmap_img(file):
def bitmap(arg): def bitmap(arg):
""" if arg is a valid and existing path name, we load it as an image. """ if arg is a valid and existing path name, we load it as an image.
Otherwise we take it as a string. Otherwise, we take it as a string.
""" """
if os.path.exists(arg): if os.path.exists(arg):
return bitmap_img(arg) return bitmap_img(arg)
@ -406,7 +405,7 @@ proto_header = (
) )
def header(lengths, speeds, modes, blink, ants, brightness=100): def header(lengths, speeds, modes, blink, ants, brightness=100, date=datetime.now()):
""" lengths[0] is the number of chars of the first text """ lengths[0] is the number of chars of the first text
Speeds come in as 1..8, but are needed 0..7 here. Speeds come in as 1..8, but are needed 0..7 here.
@ -443,131 +442,132 @@ def header(lengths, speeds, modes, blink, ants, brightness=100):
h[17 + (2 * i) - 1] = lengths[i] // 256 h[17 + (2 * i) - 1] = lengths[i] // 256
h[17 + (2 * i)] = lengths[i] % 256 h[17 + (2 * i)] = lengths[i] % 256
cdate = datetime.now() h[38 + 0] = date.year % 100
h[38 + 0] = cdate.year % 100 h[38 + 1] = date.month
h[38 + 1] = cdate.month h[38 + 2] = date.day
h[38 + 2] = cdate.day h[38 + 3] = date.hour
h[38 + 3] = cdate.hour h[38 + 4] = date.minute
h[38 + 4] = cdate.minute h[38 + 5] = date.second
h[38 + 5] = cdate.second
return h return h
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
description='Upload messages or graphics to a 11x44 led badge via USB HID.\nVersion %s from https://github.com/jnweiger/led-badge-ls32\n -- see there for more examples and for updates.' % __version, if __name__ == '__main__':
epilog='Example combining image and text:\n sudo %s "I:HEART2:you"' % sys.argv[0]) parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
parser.add_argument('-t', '--type', default='11x44', description='Upload messages or graphics to a 11x44 led badge via USB HID.\nVersion %s from https://github.com/jnweiger/led-badge-ls32\n -- see there for more examples and for updates.' % __version,
help="Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.") epilog='Example combining image and text:\n sudo %s "I:HEART2:you"' % sys.argv[0])
parser.add_argument('-s', '--speed', default='4', help="Scroll speed (Range 1..8). Up to 8 comma-separated values") parser.add_argument('-t', '--type', default='11x44',
parser.add_argument('-B', '--brightness', default='100', help="Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.")
help="Brightness for the display in percent: 25, 50, 75, or 100") parser.add_argument('-s', '--speed', default='4', help="Scroll speed (Range 1..8). Up to 8 comma-separated values")
parser.add_argument('-m', '--mode', default='0', parser.add_argument('-B', '--brightness', default='100',
help="Up to 8 mode values: Scroll-left(0) -right(1) -up(2) -down(3); still-centered(4); animation(5); drop-down(6); curtain(7); laser(8); See '--mode-help' for more details.") help="Brightness for the display in percent: 25, 50, 75, or 100")
parser.add_argument('-b', '--blink', default='0', help="1: blinking, 0: normal. Up to 8 comma-separated values") parser.add_argument('-m', '--mode', default='0',
parser.add_argument('-a', '--ants', default='0', help="1: animated border, 0: normal. Up to 8 comma-separated values") help="Up to 8 mode values: Scroll-left(0) -right(1) -up(2) -down(3); still-centered(4); animation(5); drop-down(6); curtain(7); laser(8); See '--mode-help' for more details.")
parser.add_argument('-p', '--preload', metavar='FILE', action='append', parser.add_argument('-b', '--blink', default='0', help="1: blinking, 0: normal. Up to 8 comma-separated values")
help=argparse.SUPPRESS) # "Load bitmap images. Use ^A, ^B, ^C, ... in text messages to make them visible. Deprecated, embed within ':' instead") parser.add_argument('-a', '--ants', default='0', help="1: animated border, 0: normal. Up to 8 comma-separated values")
parser.add_argument('-l', '--list-names', action='version', help="list named icons to be embedded in messages and exit", parser.add_argument('-p', '--preload', metavar='FILE', action='append',
version=':' + ': :'.join(bitmap_named.keys()) + ': :: or e.g. :path/to/some_icon.png:') help=argparse.SUPPRESS) # "Load bitmap images. Use ^A, ^B, ^C, ... in text messages to make them visible. Deprecated, embed within ':' instead")
parser.add_argument('message', metavar='MESSAGE', nargs='+', parser.add_argument('-l', '--list-names', action='version', help="list named icons to be embedded in messages and exit",
help="Up to 8 message texts with embedded builtin icons or loaded images within colons(:) -- See -l for a list of builtins") version=':' + ': :'.join(bitmap_named.keys()) + ': :: or e.g. :path/to/some_icon.png:')
parser.add_argument('--mode-help', action='version', help=argparse.SUPPRESS, version=""" parser.add_argument('message', metavar='MESSAGE', nargs='+',
help="Up to 8 message texts with embedded builtin icons or loaded images within colons(:) -- See -l for a list of builtins")
-m 5 "Animation" parser.add_argument('--mode-help', action='version', help=argparse.SUPPRESS, version="""
Animation frames are 6 character (or 48px) wide. Upload an animation of -m 5 "Animation"
N frames as one image N*48 pixels wide, 11 pixels high.
Frames run from left to right and repeat endless. Animation frames are 6 character (or 48px) wide. Upload an animation of
Speeds [1..8] result in ca. [1.2 1.3 2.0 2.4 2.8 4.5 7.5 15] fps. N frames as one image N*48 pixels wide, 11 pixels high.
Frames run from left to right and repeat endless.
Example of a slowly beating heart: Speeds [1..8] result in ca. [1.2 1.3 2.0 2.4 2.8 4.5 7.5 15] fps.
sudo %s -s1 -m5 " :heart2: :HEART2:"
Example of a slowly beating heart:
-m 9 "Smooth" sudo %s -s1 -m5 " :heart2: :HEART2:"
-m 10 "Rotate"
-m 9 "Smooth"
These modes are mentioned in the BMP Badge software. -m 10 "Rotate"
Text is shown static, or sometimes (longer texts?) not shown at all.
One significant difference is: The text of the first message stays visible after These modes are mentioned in the BMP Badge software.
upload, even if the USB cable remains connected. Text is shown static, or sometimes (longer texts?) not shown at all.
(No "rotation" or "smoothing"(?) effect can be expected, though) One significant difference is: The text of the first message stays visible after
""" % sys.argv[0]) upload, even if the USB cable remains connected.
args = parser.parse_args() (No "rotation" or "smoothing"(?) effect can be expected, though)
if have_pyhidapi: """ % sys.argv[0])
devinfo = pyhidapi.hid_enumerate(0x0416, 0x5020) args = parser.parse_args()
# dev = pyhidapi.hid_open(0x0416, 0x5020) if have_pyhidapi:
else: devinfo = pyhidapi.hid_enumerate(0x0416, 0x5020)
dev = usb.core.find(idVendor=0x0416, idProduct=0x5020) # dev = pyhidapi.hid_open(0x0416, 0x5020)
if have_pyhidapi:
if devinfo:
dev = pyhidapi.hid_open_path(devinfo[0].path)
print("using [%s %s] int=%d page=%s via pyHIDAPI" % (
devinfo[0].manufacturer_string, devinfo[0].product_string, devinfo[0].interface_number, devinfo[0].usage_page))
else: else:
print("No led tag with vendorID 0x0416 and productID 0x5020 found.") dev = usb.core.find(idVendor=0x0416, idProduct=0x5020)
print("Connect the led tag and run this tool as root.")
sys.exit(1) if have_pyhidapi:
else: if devinfo:
if dev is None: dev = pyhidapi.hid_open_path(devinfo[0].path)
print("No led tag with vendorID 0x0416 and productID 0x5020 found.") print("using [%s %s] int=%d page=%s via pyHIDAPI" % (
print("Connect the led tag and run this tool as root.") devinfo[0].manufacturer_string, devinfo[0].product_string, devinfo[0].interface_number, devinfo[0].usage_page))
else:
print("No led tag with vendorID 0x0416 and productID 0x5020 found.")
print("Connect the led tag and run this tool as root.")
sys.exit(1)
else:
if dev is None:
print("No led tag with vendorID 0x0416 and productID 0x5020 found.")
print("Connect the led tag and run this tool as root.")
sys.exit(1)
try:
# win32: NotImplementedError: is_kernel_driver_active
if dev.is_kernel_driver_active(0):
dev.detach_kernel_driver(0)
except:
pass
dev.set_configuration()
print("using [%s %s] bus=%d dev=%d" % (dev.manufacturer, dev.product, dev.bus, dev.address))
if args.preload:
for file in args.preload:
bitmap_preloaded.append(bitmap_img(file))
bitmaps_preloaded_unused = True
msg_bitmaps = []
for msg_arg in args.message:
msg_bitmaps.append(bitmap(msg_arg))
if bitmaps_preloaded_unused == True:
print(
"\nWARNING:\n Your preloaded images are not used.\n Try without '-p' or embed the control character '^A' in your message.\n")
if '12' in args.type or '12' in sys.argv[0]:
print("Type: 12x48")
for msg_bitmap in msg_bitmaps:
# trivial hack to support 12x48 badges:
# patch extra empty lines into the message stream.
for o in reversed(range(1, int(len(msg_bitmap[0]) / 11) + 1)):
msg_bitmap[0][o * 11:o * 11] = array('B', [0])
else:
print("Type: 11x44")
buf = array('B')
buf.extend(header(list(map(lambda x: x[1], msg_bitmaps)), args.speed, args.mode, args.blink, args.ants, int(args.brightness)))
for msg_bitmap in msg_bitmaps:
buf.extend(msg_bitmap[0])
need_padding = len(buf) % 64
if need_padding:
buf.extend((0,) * (64 - need_padding))
# print(buf) # array('B', [119, 97, 110, 103, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 126, 255, 255, 255, 255, 126, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
if len(buf) > 8192:
print("Writing more than 8192 bytes damages the display!")
sys.exit(1) sys.exit(1)
try:
# win32: NotImplementedError: is_kernel_driver_active if have_pyhidapi:
if dev.is_kernel_driver_active(0): pyhidapi.hid_write(dev, buf)
dev.detach_kernel_driver(0) else:
except: for i in range(int(len(buf) / 64)):
pass time.sleep(0.1)
dev.set_configuration() dev.write(1, buf[i * 64:i * 64 + 64])
print("using [%s %s] bus=%d dev=%d" % (dev.manufacturer, dev.product, dev.bus, dev.address))
if have_pyhidapi:
if args.preload: pyhidapi.hid_close(dev)
for file in args.preload:
bitmap_preloaded.append(bitmap_img(file))
bitmaps_preloaded_unused = True
msgs = []
for arg in args.message:
msgs.append(bitmap(arg))
if bitmaps_preloaded_unused == True:
print(
"\nWARNING:\n Your preloaded images are not used.\n Try without '-p' or embed the control character '^A' in your message.\n")
if '12' in args.type or '12' in sys.argv[0]:
print("Type: 12x48")
for msg in msgs:
# trivial hack to support 12x48 badges:
# patch extra empty lines into the message stream.
for o in reversed(range(1, int(len(msg[0]) / 11) + 1)):
msg[0][o * 11:o * 11] = array('B', [0])
else:
print("Type: 11x44")
buf = array('B')
buf.extend(header(list(map(lambda x: x[1], msgs)), args.speed, args.mode, args.blink, args.ants, int(args.brightness)))
for msg in msgs:
buf.extend(msg[0])
needpadding = len(buf) % 64
if needpadding:
buf.extend((0,) * (64 - needpadding))
# print(buf) # array('B', [119, 97, 110, 103, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 126, 255, 255, 255, 255, 126, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
if len(buf) > 8192:
print("Writing more than 8192 bytes damages the display!")
sys.exit(1)
if have_pyhidapi:
pyhidapi.hid_write(dev, buf)
else:
for i in range(int(len(buf) / 64)):
time.sleep(0.1)
dev.write(1, buf[i * 64:i * 64 + 64])
if have_pyhidapi:
pyhidapi.hid_close(dev)

Loading…
Cancel
Save