chore: add french accentuated character

rebase020124
Yann MORERE 1 year ago
parent 908c393de0
commit 36d9e0ddb0
  1. 481
      led-badge-11x44.py

@ -52,39 +52,41 @@
import sys, os, re, time, argparse import sys, os, re, time, argparse
from datetime import datetime from datetime import datetime
from array import array from array import array
try: try:
if sys.version_info[0] < 3: raise Exception("prefer usb.core with python-2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9") if sys.version_info[0] < 3: raise Exception(
import pyhidapi "prefer usb.core with python-2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9")
pyhidapi.hid_init() import pyhidapi
have_pyhidapi = True
pyhidapi.hid_init()
have_pyhidapi = True
except: except:
have_pyhidapi = False have_pyhidapi = False
try: try:
import usb.core import usb.core
except: except:
print("ERROR: Need the pyhidapi or usb.core module.") print("ERROR: Need the pyhidapi or usb.core module.")
if sys.platform == "darwin": if sys.platform == "darwin":
print("""Please try print("""Please try
pip3 install pyhidapi pip3 install pyhidapi
pip install pyhidapi pip install pyhidapi
brew install hidapi""") brew install hidapi""")
elif sys.platform == "linux": elif sys.platform == "linux":
print("""Please try print("""Please try
sudo pip3 install pyhidapi sudo pip3 install pyhidapi
sudo pip install pyhidapi sudo pip install pyhidapi
sudo apt-get install libhidapi-hidraw0 sudo apt-get install libhidapi-hidraw0
sudo ln -s /usr/lib/x86_64-linux-gnu/libhidapi-hidraw.so.0 /usr/local/lib/ sudo ln -s /usr/lib/x86_64-linux-gnu/libhidapi-hidraw.so.0 /usr/local/lib/
or or
sudo apt-get install python3-usb""") sudo apt-get install python3-usb""")
else: # windows? else: # windows?
print("""Please with Linux or MacOS or help us implement support for """ + sys.platform) print("""Please with Linux or MacOS or help us implement support for """ + sys.platform)
sys.exit(1) sys.exit(1)
__version = "0.12" __version = "0.12"
font_11x44 = ( font_11x44 = (
# 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00,
0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0xc6, 0x7c, 0x00,
@ -201,94 +203,129 @@ font_11x44 = (
0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x3c, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x6c, 0x60, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x6c, 0x60,
# "àäòöùüèéêëôöûîïÿç"
0x00, 0x60, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x60, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x60, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x60, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
0x00, 0x18, 0x60, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
0x00, 0x10, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00,
0x00, 0x10, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x10, 0x6c, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x10, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8,
0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x10, 0x30,
# "ÀÅÄÉÈÊËÖÔÜÛÙŸ"
0x60, 0x18, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
0x10, 0x6c, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
0x6c, 0x6c, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
0x18, 0x60, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
0x60, 0x18, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
0x10, 0x6c, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
0x6c, 0x6c, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00,
0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Ö
0x10, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Ô
0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Ü
0x10, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Û
0x60, 0x18, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, # Ù
0x66, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, # Ÿ
) )
charmap = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \ charmap = u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \
u'abcdefghijklmnopqrstuvwxyz' + \ u'abcdefghijklmnopqrstuvwxyz' + \
u'0987654321^ !"\0$%&/()=?` °\\}][{' + \ u'0987654321^ !"\0$%&/()=?` °\\}][{' + \
u"@ ~ |<>,;.:-_#'+* " + \ u"@ ~ |<>,;.:-_#'+* " + \
u"äöüÄÖÜß" u"äöüÄÖÜß" + \
u"àäòöùüèéêëôöûîïÿç" + \
u"ÀÅÄÉÈÊËÖÔÜÛÙŸ"
char_offset = {} char_offset = {}
for i in range(len(charmap)): for i in range(len(charmap)):
char_offset[charmap[i]] = 11 * i char_offset[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)]
bitmaps_preloaded_unused = False bitmaps_preloaded_unused = False
bitmap_named = { bitmap_named = {
'ball': (array('B', ( 'ball': (array('B', (
0b00000000, 0b00000000,
0b00000000, 0b00000000,
0b00111100, 0b00111100,
0b01111110, 0b01111110,
0b11111111, 0b11111111,
0b11111111, 0b11111111,
0b11111111, 0b11111111,
0b11111111, 0b11111111,
0b01111110, 0b01111110,
0b00111100, 0b00111100,
0b00000000 0b00000000
)), 1, '\x1e'), )), 1, '\x1e'),
'happy': (array('B', ( 'happy': (array('B', (
0b00000000, # 0x00 0b00000000, # 0x00
0b00000000, # 0x00 0b00000000, # 0x00
0b00111100, # 0x3c 0b00111100, # 0x3c
0b01000010, # 0x42 0b01000010, # 0x42
0b10100101, # 0xa5 0b10100101, # 0xa5
0b10000001, # 0x81 0b10000001, # 0x81
0b10100101, # 0xa5 0b10100101, # 0xa5
0b10011001, # 0x99 0b10011001, # 0x99
0b01000010, # 0x42 0b01000010, # 0x42
0b00111100, # 0x3c 0b00111100, # 0x3c
0b00000000 # 0x00 0b00000000 # 0x00
)), 1, '\x1d'), )), 1, '\x1d'),
'happy2': (array('B', (0x00, 0x08, 0x14, 0x08, 0x01, 0x00, 0x00, 0x61, 0x30, 0x1c, 0x07, 'happy2': (array('B', (0x00, 0x08, 0x14, 0x08, 0x01, 0x00, 0x00, 0x61, 0x30, 0x1c, 0x07,
0x00, 0x20, 0x50, 0x20, 0x00, 0x80, 0x80, 0x86, 0x0c, 0x38, 0xe0)), 2, '\x1c'), 0x00, 0x20, 0x50, 0x20, 0x00, 0x80, 0x80, 0x86, 0x0c, 0x38, 0xe0)), 2, '\x1c'),
'heart': (array('B', (0x00, 0x00, 0x6c, 0x92, 0x82, 0x82, 0x44, 0x28, 0x10, 0x00, 0x00)), 1, '\x1b'), 'heart': (array('B', (0x00, 0x00, 0x6c, 0x92, 0x82, 0x82, 0x44, 0x28, 0x10, 0x00, 0x00)), 1, '\x1b'),
'HEART': (array('B', (0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00)), 1, '\x1a'), 'HEART': (array('B', (0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00)), 1, '\x1a'),
'heart2': (array('B', (0x00, 0x0c, 0x12, 0x21, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 'heart2': (array('B', (0x00, 0x0c, 0x12, 0x21, 0x20, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
0x00, 0x60, 0x90, 0x08, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00)), 2, '\x19'), 0x00, 0x60, 0x90, 0x08, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00)), 2, '\x19'),
'HEART2': (array('B', (0x00, 0x0c, 0x1e, 0x3f, 0x3f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 'HEART2': (array('B', (0x00, 0x0c, 0x1e, 0x3f, 0x3f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01,
0x00, 0x60, 0xf0, 0xf8, 0xf8, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00)), 2, '\x18'), 0x00, 0x60, 0xf0, 0xf8, 0xf8, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00)), 2, '\x18'),
'fablab': (array('B', (0x07, 0x0e, 0x1b, 0x03, 0x21, 0x2c, 0x2e, 0x26, 0x14, 0x1c, 0x06, 'fablab': (array('B', (0x07, 0x0e, 0x1b, 0x03, 0x21, 0x2c, 0x2e, 0x26, 0x14, 0x1c, 0x06,
0x80, 0x60, 0x30, 0x80, 0x88, 0x38, 0xe8, 0xc8, 0x10, 0x30, 0xc0)), 2, '\x17'), 0x80, 0x60, 0x30, 0x80, 0x88, 0x38, 0xe8, 0xc8, 0x10, 0x30, 0xc0)), 2, '\x17'),
'bicycle': (array('B', (0x01, 0x02, 0x00, 0x01, 0x07, 0x09, 0x12, 0x12, 0x10, 0x08, 0x07, 'bicycle': (array('B', (0x01, 0x02, 0x00, 0x01, 0x07, 0x09, 0x12, 0x12, 0x10, 0x08, 0x07,
0x00, 0x87, 0x81, 0x5f, 0x22, 0x94, 0x49, 0x5f, 0x49, 0x80, 0x00, 0x00, 0x87, 0x81, 0x5f, 0x22, 0x94, 0x49, 0x5f, 0x49, 0x80, 0x00,
0x00, 0x80, 0x00, 0x80, 0x70, 0xc8, 0x24, 0xe4, 0x04, 0x88, 0x70)), 3, '\x16'), 0x00, 0x80, 0x00, 0x80, 0x70, 0xc8, 0x24, 0xe4, 0x04, 0x88, 0x70)), 3, '\x16'),
'bicycle_r':(array('B', (0x00, 0x00, 0x00, 0x00, 0x07, 0x09, 0x12, 0x13, 0x10, 0x08, 0x07, 'bicycle_r': (array('B', (0x00, 0x00, 0x00, 0x00, 0x07, 0x09, 0x12, 0x13, 0x10, 0x08, 0x07,
0x00, 0xf0, 0x40, 0xfd, 0x22, 0x94, 0x49, 0xfd, 0x49, 0x80, 0x00, 0x00, 0xf0, 0x40, 0xfd, 0x22, 0x94, 0x49, 0xfd, 0x49, 0x80, 0x00,
0x40, 0xa0, 0x80, 0x40, 0x70, 0xc8, 0x24, 0x24, 0x04, 0x88, 0x70)), 3, '\x15'), 0x40, 0xa0, 0x80, 0x40, 0x70, 0xc8, 0x24, 0x24, 0x04, 0x88, 0x70)), 3, '\x15'),
'owncloud': (array('B', (0x00, 0x01, 0x02, 0x03, 0x06, 0x0c, 0x1a, 0x13, 0x11, 0x19, 0x0f, 'owncloud': (array('B', (0x00, 0x01, 0x02, 0x03, 0x06, 0x0c, 0x1a, 0x13, 0x11, 0x19, 0x0f,
0x78, 0xcc, 0x87, 0xfc, 0x42, 0x81, 0x81, 0x81, 0x81, 0x43, 0xbd, 0x78, 0xcc, 0x87, 0xfc, 0x42, 0x81, 0x81, 0x81, 0x81, 0x43, 0xbd,
0x00, 0x00, 0x00, 0x80, 0x80, 0xe0, 0x30, 0x10, 0x28, 0x28, 0xd0)), 3, '\x14'), 0x00, 0x00, 0x00, 0x80, 0x80, 0xe0, 0x30, 0x10, 0x28, 0x28, 0xd0)), 3, '\x14'),
} }
bitmap_builtin = {} bitmap_builtin = {}
for i in bitmap_named: for i in bitmap_named:
bitmap_builtin[bitmap_named[i][2]] = bitmap_named[i] bitmap_builtin[bitmap_named[i][2]] = bitmap_named[i]
def bitmap_char(ch): def bitmap_char(ch):
""" Returns a tuple of 11 bytes, """ Returns a tuple of 11 bytes,
ch = '_' returns (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255) ch = '_' returns (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255)
The bits in each byte are horizontal, highest bit is left. The bits in each byte are horizontal, highest bit is left.
""" """
if ord(ch) < 32: if ord(ch) < 32:
if ch in bitmap_builtin: if ch in bitmap_builtin:
return bitmap_builtin[ch][:2] return bitmap_builtin[ch][:2]
global bitmaps_preloaded_unused global bitmaps_preloaded_unused
bitmaps_preloaded_unused = False bitmaps_preloaded_unused = False
return bitmap_preloaded[ord(ch)] return bitmap_preloaded[ord(ch)]
o = char_offset[ch] o = char_offset[ch]
return (font_11x44[o:o+11],1) return (font_11x44[o:o + 11], 1)
def bitmap_text(text): def bitmap_text(text):
""" returns a tuple of (buffer, length_in_byte_columns_aka_chars) """ returns a tuple of (buffer, length_in_byte_columns_aka_chars)
We preprocess the text string for substitution patterns We preprocess the text string for substitution patterns
"::" is replaced with a single ":" "::" is replaced with a single ":"
":1: is replaced with CTRL-A referencing the first preloaded or loaded image. ":1: is replaced with CTRL-A referencing the first preloaded or loaded image.
@ -296,137 +333,145 @@ def bitmap_text(text):
":heart:" is replaced with a reference to a builtin heart glyph ":heart:" is replaced with a reference to a builtin heart glyph
":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):
name = m.group(1) def colonrepl(m):
if name == '': name = m.group(1)
return ':' if name == '':
if re.match('^[0-9]*$', name): # py3 name.isdecimal() return ':'
return chr(int(name)) if re.match('^[0-9]*$', name): # py3 name.isdecimal()
if '.' in name: return chr(int(name))
bitmap_preloaded.append(bitmap_img(name)) if '.' in name:
return chr(len(bitmap_preloaded)-1) bitmap_preloaded.append(bitmap_img(name))
b = bitmap_named[name] return chr(len(bitmap_preloaded) - 1)
return b[2] b = bitmap_named[name]
return b[2]
text = re.sub(r':([^:]*):', colonrepl, text)
buf = array('B') text = re.sub(r':([^:]*):', colonrepl, text)
cols = 0 buf = array('B')
for c in text: cols = 0
(b,n) = bitmap_char(c) for c in text:
buf.extend(b) (b, n) = bitmap_char(c)
cols += n buf.extend(b)
return (buf, cols) cols += n
return (buf, cols)
def bitmap_img(file): def bitmap_img(file):
""" returns a tuple of (buffer, length_in_byte_columns) """ returns a tuple of (buffer, length_in_byte_columns)
""" """
from PIL import Image from PIL import Image
im = Image.open(file) im = Image.open(file)
print("fetching bitmap from file %s -> (%d x %d)" % (file, im.width, im.height)) print("fetching bitmap from file %s -> (%d x %d)" % (file, im.width, im.height))
if im.height != 11: if im.height != 11:
sys.exit("%s: image height must be 11px. Seen %d" % (file, im.height)) sys.exit("%s: image height must be 11px. Seen %d" % (file, im.height))
buf = array('B') buf = array('B')
cols = int((im.width+7)/8) cols = int((im.width + 7) / 8)
for col in range(cols): for col in range(cols):
for row in range(11): # [0..10] for row in range(11): # [0..10]
byte_val = 0 byte_val = 0
for bit in range(8): # [0..7] for bit in range(8): # [0..7]
bit_val = 0 bit_val = 0
x = 8*col+bit x = 8 * col + bit
if x < im.width and row < im.height: if x < im.width and row < im.height:
pixel_color = im.getpixel( (x, row) ) pixel_color = im.getpixel((x, row))
if isinstance(pixel_color, tuple): if isinstance(pixel_color, tuple):
monochrome_color = sum(pixel_color[:3]) / len(pixel_color[:3]) monochrome_color = sum(pixel_color[:3]) / len(pixel_color[:3])
elif isinstance(pixel_color, int): elif isinstance(pixel_color, int):
monochrome_color = pixel_color monochrome_color = pixel_color
else: else:
sys.exit("%s: Unknown pixel format detected (%s)!" % (file, pixel_color)) sys.exit("%s: Unknown pixel format detected (%s)!" % (file, pixel_color))
if monochrome_color > 127: if monochrome_color > 127:
bit_val = 1 << (7-bit) bit_val = 1 << (7 - bit)
byte_val += bit_val byte_val += bit_val
buf.append(byte_val) buf.append(byte_val)
im.close() im.close()
return (buf, cols) return (buf, cols)
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)
return bitmap_text(arg) return bitmap_text(arg)
proto_header = ( proto_header = (
0x77, 0x61, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x77, 0x61, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
) )
def header(lengths, speeds, modes, blink, ants, brightness=100): def header(lengths, speeds, modes, blink, ants, brightness=100):
""" 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.
""" """
a = [int(x) for x in re.split(r'[\s,]+', ants)] a = [int(x) for x in re.split(r'[\s,]+', ants)]
a = a + [a[-1]]*(8-len(a)) # repeat last element a = a + [a[-1]] * (8 - len(a)) # repeat last element
b = [int(x) for x in re.split(r'[\s,]+', blink)]
b = b + [b[-1]]*(8-len(b)) # repeat last element
s = [int(x)-1 for x in re.split(r'[\s,]+', speeds)] b = [int(x) for x in re.split(r'[\s,]+', blink)]
s = s + [s[-1]]*(8-len(s)) # repeat last element b = b + [b[-1]] * (8 - len(b)) # repeat last element
m = [int(x) for x in re.split(r'[\s,]+', modes)] s = [int(x) - 1 for x in re.split(r'[\s,]+', speeds)]
m = m + [m[-1]]*(8-len(m)) # repeat last element s = s + [s[-1]] * (8 - len(s)) # repeat last element
h = list(proto_header) m = [int(x) for x in re.split(r'[\s,]+', modes)]
m = m + [m[-1]] * (8 - len(m)) # repeat last element
if brightness <= 25: h = list(proto_header)
h[5] = 0x40
elif brightness <= 50:
h[5] = 0x20
elif brightness <= 75:
h[5] = 0x10
for i in range(8): if brightness <= 25:
h[6] += b[i]<<i h[5] = 0x40
h[7] += a[i]<<i elif brightness <= 50:
h[5] = 0x20
elif brightness <= 75:
h[5] = 0x10
for i in range(8): for i in range(8):
h[8+i] = 16*s[i] + m[i] h[6] += b[i] << i
h[7] += a[i] << i
for i in range(len(lengths)): for i in range(8):
h[17+(2*i)-1] = lengths[i] // 256 h[8 + i] = 16 * s[i] + m[i]
h[17+(2*i)] = lengths[i] % 256
for i in range(len(lengths)):
h[17 + (2 * i) - 1] = lengths[i] // 256
h[17 + (2 * i)] = lengths[i] % 256
cdate = datetime.now() cdate = datetime.now()
h[38+0] = cdate.year % 100 h[38 + 0] = cdate.year % 100
h[38+1] = cdate.month h[38 + 1] = cdate.month
h[38+2] = cdate.day h[38 + 2] = cdate.day
h[38+3] = cdate.hour h[38 + 3] = cdate.hour
h[38+4] = cdate.minute h[38 + 4] = cdate.minute
h[38+5] = cdate.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, 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', help="Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.") 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,
epilog='Example combining image and text:\n sudo %s "I:HEART2:you"' % sys.argv[0])
parser.add_argument('-t', '--type', default='11x44',
help="Type of display: supported values are 12x48 or (default) 11x44. Rename the program to led-badge-12x48, to switch the default.")
parser.add_argument('-s', '--speed', default='4', help="Scroll speed (Range 1..8). Up to 8 comma-separated values") parser.add_argument('-s', '--speed', default='4', help="Scroll speed (Range 1..8). Up to 8 comma-separated values")
parser.add_argument('-B', '--brightness', default='100', help="Brightness for the display in percent: 25, 50, 75, or 100") parser.add_argument('-B', '--brightness', default='100',
parser.add_argument('-m', '--mode', default='0', 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('-m', '--mode', default='0',
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('-b', '--blink', default='0', help="1: blinking, 0: normal. Up to 8 comma-separated values") parser.add_argument('-b', '--blink', default='0', help="1: blinking, 0: normal. Up to 8 comma-separated values")
parser.add_argument('-a', '--ants', default='0', help="1: animated border, 0: normal. Up to 8 comma-separated values") parser.add_argument('-a', '--ants', default='0', help="1: animated border, 0: normal. Up to 8 comma-separated values")
parser.add_argument('-p', '--preload', metavar='FILE', action='append', help=argparse.SUPPRESS) # "Load bitmap images. Use ^A, ^B, ^C, ... in text messages to make them visible. Deprecated, embed within ':' instead") parser.add_argument('-p', '--preload', metavar='FILE', action='append',
parser.add_argument('-l', '--list-names', action='version', help="list named icons to be embedded in messages and exit", 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='+', help="Up to 8 message texts with embedded builtin icons or loaded images within colons(:) -- See -l for a list of builtins") parser.add_argument('-l', '--list-names', action='version', help="list named icons to be embedded in messages and exit",
version=':' + ': :'.join(bitmap_named.keys()) + ': :: or e.g. :path/to/some_icon.png:')
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")
parser.add_argument('--mode-help', action='version', help=argparse.SUPPRESS, version=""" parser.add_argument('--mode-help', action='version', help=argparse.SUPPRESS, version="""
-m 5 "Animation" -m 5 "Animation"
@ -450,77 +495,79 @@ parser.add_argument('--mode-help', action='version', help=argparse.SUPPRESS, ver
""" % sys.argv[0]) """ % sys.argv[0])
args = parser.parse_args() args = parser.parse_args()
if have_pyhidapi: if have_pyhidapi:
devinfo = pyhidapi.hid_enumerate(0x0416, 0x5020) devinfo = pyhidapi.hid_enumerate(0x0416, 0x5020)
#dev = pyhidapi.hid_open(0x0416, 0x5020) # dev = pyhidapi.hid_open(0x0416, 0x5020)
else: else:
dev = usb.core.find(idVendor=0x0416, idProduct=0x5020) dev = usb.core.find(idVendor=0x0416, idProduct=0x5020)
if have_pyhidapi: if have_pyhidapi:
if devinfo: if devinfo:
dev = pyhidapi.hid_open_path(devinfo[0].path) 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)) print("using [%s %s] int=%d page=%s via pyHIDAPI" % (
else: devinfo[0].manufacturer_string, devinfo[0].product_string, devinfo[0].interface_number, devinfo[0].usage_page))
print("No led tag with vendorID 0x0416 and productID 0x5020 found.") else:
print("Connect the led tag and run this tool as root.") print("No led tag with vendorID 0x0416 and productID 0x5020 found.")
sys.exit(1) print("Connect the led tag and run this tool as root.")
sys.exit(1)
else: else:
if dev is None: if dev is None:
print("No led tag with vendorID 0x0416 and productID 0x5020 found.") print("No led tag with vendorID 0x0416 and productID 0x5020 found.")
print("Connect the led tag and run this tool as root.") print("Connect the led tag and run this tool as root.")
sys.exit(1) sys.exit(1)
try: try:
# win32: NotImplementedError: is_kernel_driver_active # win32: NotImplementedError: is_kernel_driver_active
if dev.is_kernel_driver_active(0): if dev.is_kernel_driver_active(0):
dev.detach_kernel_driver(0) dev.detach_kernel_driver(0)
except: except:
pass pass
dev.set_configuration() dev.set_configuration()
print("using [%s %s] bus=%d dev=%d" % (dev.manufacturer, dev.product, dev.bus, dev.address)) print("using [%s %s] bus=%d dev=%d" % (dev.manufacturer, dev.product, dev.bus, dev.address))
if args.preload: if args.preload:
for file in args.preload: for file in args.preload:
bitmap_preloaded.append(bitmap_img(file)) bitmap_preloaded.append(bitmap_img(file))
bitmaps_preloaded_unused = True bitmaps_preloaded_unused = True
msgs = [] msgs = []
for arg in args.message: for arg in args.message:
msgs.append(bitmap(arg)) msgs.append(bitmap(arg))
if bitmaps_preloaded_unused == True: 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") 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]: if '12' in args.type or '12' in sys.argv[0]:
print("Type: 12x48") print("Type: 12x48")
for msg in msgs: for msg in msgs:
# trivial hack to support 12x48 badges: # trivial hack to support 12x48 badges:
# patch extra empty lines into the message stream. # patch extra empty lines into the message stream.
for o in reversed(range(1, int(len(msg[0])/11)+1)): for o in reversed(range(1, int(len(msg[0]) / 11) + 1)):
msg[0][o*11:o*11] = array('B', [0]) msg[0][o * 11:o * 11] = array('B', [0])
else: else:
print("Type: 11x44") print("Type: 11x44")
buf = array('B') buf = array('B')
buf.extend(header(list(map(lambda x: x[1], msgs)), args.speed, args.mode, args.blink, args.ants, int(args.brightness))) 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: for msg in msgs:
buf.extend(msg[0]) buf.extend(msg[0])
needpadding = len(buf)%64 needpadding = len(buf) % 64
if needpadding: if needpadding:
buf.extend( (0,) * (64-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]) # 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: if len(buf) > 8192:
print ("Writing more than 8192 bytes damages the display!") print("Writing more than 8192 bytes damages the display!")
sys.exit(1) sys.exit(1)
if have_pyhidapi: if have_pyhidapi:
pyhidapi.hid_write(dev, buf) pyhidapi.hid_write(dev, buf)
else: else:
for i in range(int(len(buf)/64)): for i in range(int(len(buf) / 64)):
time.sleep(0.1) time.sleep(0.1)
dev.write(1, buf[i*64:i*64+64]) dev.write(1, buf[i * 64:i * 64 + 64])
if have_pyhidapi: if have_pyhidapi:
pyhidapi.hid_close(dev) pyhidapi.hid_close(dev)

Loading…
Cancel
Save