@ -409,6 +409,43 @@ class SimpleTextAndIcons:
class WriteMethod :
def __init__ ( self ) :
self . devices = None
def __del__ ( self ) :
self . close ( )
def open ( self , device_id ) :
if self . is_ready ( ) :
self . devices = self . _get_available_devices ( )
if self . devices and len ( self . devices ) > 0 :
if device_id == ' auto ' and len ( self . devices ) > 0 :
# /***/ was, wenn kein gerät angeschlossen?
device_id = sorted ( self . devices . keys ( ) ) [ 0 ]
elif device_id == ' list ' :
self . print_devices ( )
sys . exit ( 0 )
elif device_id not in self . devices . keys ( ) :
print ( " Device ID ' %s ' is unknown. Please choose from: " % ( device_id , ) )
self . print_devices ( )
sys . exit ( 1 )
return self . _open ( device_id )
# /***/ was wenn kein Device? -> Alle Meldungen hier raus in die vorbereitung
return None
def close ( self ) :
raise NotImplementedError ( )
def print_devices ( self ) :
for k , d in self . devices . items ( ) :
print ( " ' %s ' : %s " % ( k , d [ 0 ] ) )
def _open ( self , device_id ) :
raise NotImplementedError ( )
def _get_available_devices ( self ) :
raise NotImplementedError ( )
@staticmethod
def add_padding ( buf , blocksize ) :
need_padding = len ( buf ) % blocksize
@ -421,6 +458,9 @@ class WriteMethod:
print ( " Writing more than %d bytes damages the display! " % ( maxsize , ) )
sys . exit ( 1 )
def is_ready ( self ) :
raise NotImplementedError ( )
def has_device ( self ) :
raise NotImplementedError ( )
@ -442,15 +482,62 @@ class WriteLibUsb(WriteMethod):
except :
pass
def __init__ ( self , endpoint ) :
def __init__ ( self ) :
WriteMethod . __init__ ( self )
self . description = None
self . dev = None
self . endpoint = None
def _open ( self , device_id ) :
self . description = self . devices [ device_id ] [ 0 ]
self . dev = self . devices [ device_id ] [ 1 ]
self . endpoint = self . devices [ device_id ] [ 2 ]
print ( " Libusb device initialized " )
return True
def close ( self ) :
if self . devices :
for k , d in self . devices . items ( ) :
d [ 1 ] . reset ( )
WriteLibUsb . usb . util . dispose_resources ( d [ 1 ] )
self . description = None
self . dev = None
if WriteLibUsb . _module_loaded :
self . dev = WriteLibUsb . usb . core . find ( idVendor = 0x0416 , idProduct = 0x5020 )
if self . dev :
print ( " Libusb device initialized " )
self . endpoint = None
print ( " Libusb: device resources freed " )
def _get_available_devices ( self ) :
if not self . is_ready ( ) :
return { }
devs = WriteLibUsb . usb . core . find ( idVendor = 0x0416 , idProduct = 0x5020 , find_all = True )
devices = { }
for d in devs :
try :
# win32: NotImplementedError: is_kernel_driver_active
if d . is_kernel_driver_active ( 0 ) :
d . detach_kernel_driver ( 0 )
except :
pass
try :
d . set_configuration ( )
except ( WriteLibUsb . usb . core . USBError ) :
print ( " No write access to device! " )
# /***/
print ( " Maybe, you have to run this program with administrator rights. " )
if sys . platform . startswith ( ' linux ' ) :
print ( " * Try with sudo or add a udev rule like described in README.md. " )
sys . exit ( 1 )
@staticmethod
def is_ready ( ) :
cfg = d . get_active_configuration ( ) [ 0 , 0 ]
eps = WriteLibUsb . usb . util . find_descriptor ( cfg , find_all = True , custom_match = lambda e : \
WriteLibUsb . usb . util . endpoint_direction ( e . bEndpointAddress ) == WriteLibUsb . usb . util . ENDPOINT_OUT )
for ep in eps :
id = " %d : %d : %d " % ( d . bus , d . address , ep . bEndpointAddress )
descr = " ' %s %s ' (bus= %d dev= %d endpoint= %d ) " % ( d . manufacturer , d . product , d . bus , d . address , ep . bEndpointAddress )
devices [ id ] = ( descr , d , ep )
return devices
def is_ready ( self ) :
return WriteLibUsb . _module_loaded
def has_device ( self ) :
@ -476,14 +563,10 @@ class WriteLibUsb(WriteMethod):
print ( " * Try with sudo or add a udev rule like described in README.md. " )
sys . exit ( 1 )
print ( " Write using [ %s %s ] bus= %d dev= %d via libusb " %
( self . dev . manufacturer , self . dev . product , self . dev . bus , self . dev . address ) )
print ( " Write using %s via libusb " % ( self . description ) )
for i in range ( int ( len ( buf ) / 64 ) ) :
time . sleep ( 0.1 )
self . dev . write ( 1 , buf [ i * 64 : i * 64 + 64 ] )
WriteLibUsb . usb . util . dispose_resources ( self . dev )
self . dev . reset ( )
self . dev = None
self . endpoint . write ( buf [ i * 64 : i * 64 + 64 ] )
class WriteUsbHidApi ( WriteMethod ) :
@ -496,40 +579,55 @@ class WriteUsbHidApi(WriteMethod):
except :
pass
def __init__ ( self , endpoint ) :
def __init__ ( self ) :
WriteMethod . __init__ ( self )
self . description = None
self . path = None
self . dev = None
self . dev_info = None
if WriteUsbHidApi . _module_loaded :
self . dev_info = WriteUsbHidApi . pyhidapi . hid_enumerate ( 0x0416 , 0x5020 )
if self . dev_info :
self . dev = WriteUsbHidApi . pyhidapi . hid_open_path ( self . dev_info [ 0 ] . path )
if self . dev :
print ( " Hidapi device initialized " )
# alternative: self.dev = WriteUsbHidApi.pyhidapi.hid_open(0x0416, 0x5020)
def _open ( self , device_id ) :
self . description = self . devices [ device_id ] [ 0 ]
self . path = self . devices [ device_id ] [ 1 ]
self . dev = WriteUsbHidApi . pyhidapi . hid_open_path ( self . path )
if self . dev :
print ( " Hidapi device initialized " )
@staticmethod
def is_ready ( ) :
return self . dev is not None
def close ( self ) :
if self . dev is not None :
WriteUsbHidApi . pyhidapi . hid_close ( self . dev )
self . description = None
self . path = None
self . dev = None
print ( " Hidapi: device resources freed " )
def _get_available_devices ( self ) :
device_infos = WriteUsbHidApi . pyhidapi . hid_enumerate ( 0x0416 , 0x5020 )
devices = { }
for d in device_infos :
id = " %s " % ( str ( d . path . decode ( ' ascii ' ) ) , )
descr = " ' %s %s ' (if= %d ) " % ( d . manufacturer_string , d . product_string , d . interface_number )
devices [ id ] = ( descr , d . path )
return devices
def is_ready ( self ) :
return WriteUsbHidApi . _module_loaded
def has_device ( self ) :
return self . dev is not None
def _write ( self , buf ) :
if not self . dev or not self . dev_info :
if not self . dev :
return
print ( " Write using [ %s %s ] int= %d page= %s via hidapi " % (
self . dev_info [ 0 ] . manufacturer_string , self . dev_info [ 0 ] . product_string ,
self . dev_info [ 0 ] . interface_number , self . dev_info [ 0 ] . usage_page ) )
print ( " Write using [ %s ] via hidapi " % ( self . description , ) )
for i in range ( int ( len ( buf ) / 64 ) ) :
# sendbuf must contain "report ID" as first byte. "0" does the job here.
sendbuf = array ( ' B ' , [ 0 ] )
# Then, put the 64 payload bytes into the buffer
sendbuf . extend ( buf [ i * 64 : i * 64 + 64 ] )
WriteUsbHidApi . pyhidapi . hid_write ( self . dev , sendbuf )
WriteUsbHidApi . pyhidapi . hid_close ( self . dev )
self . dev = None
class LedNameBadge :
@ -612,30 +710,27 @@ class LedNameBadge:
raise TypeError ( " Please give a list or tuple with at least one number: " + str ( iterable ) )
@staticmethod
def write ( buf , method = ' auto ' , endpoint = ' auto ' ) :
def write ( buf , method = ' auto ' , device_id = ' auto ' ) :
""" Write the given buffer to the device.
It has to begin with a protocol header as provided by header ( ) and followed by the bitmap data .
In short : the bitmap data is organized in bytes with 8 horizontal pixels per byte and 11 resp . 12
bytes per ( 8 pixels wide ) byte - column . Then just put one byte - column after the other and one bitmap
after the other .
"""
write_method = LedNameBadge . _find_write_method ( method , endpoint )
write_method = LedNameBadge . _find_write_method ( method , device_id )
if write_method :
write_method . write ( buf )
@staticmethod
def _find_write_method ( method , endpoint ) :
if method is None :
method = ' auto '
if endpoint is None :
endpoint = ' auto '
def _find_write_method ( method , device_id ) :
if method not in ( ' libusb ' , ' hidapi ' , ' auto ' ) :
print ( " Unknown write method ' %s ' . " % ( method , ) )
print ( " Available options: ' libusb ' , ' hidapi ' and ' auto ' (default) " )
sys . exit ( 1 )
libusb = WriteLibUsb ( )
hidapi = WriteUsbHidApi ( )
# Python2 only with libusb
if method == ' auto ' :
if sys . version_info [ 0 ] < 3 :
@ -647,7 +742,7 @@ class LedNameBadge:
elif sys . platform . startswith ( ' win ' ) :
method = ' libusb '
print ( " Selected method ' libusb ' with Windows " )
elif not WriteLibU sb. is_ready ( ) and not WriteUsbHidA pi. is_ready ( ) :
elif not libu sb. is_ready ( ) and not hida pi. is_ready ( ) :
if sys . version_info [ 0 ] < 3 or sys . platform . startswith ( ' win ' ) :
print ( " You need the usb.core module. " )
LedNameBadge . _print_libusb_install_hints ( )
@ -667,7 +762,7 @@ class LedNameBadge:
print ( " For MacOs, please use method ' hidapi ' or ' auto ' . " )
print ( " Or help us implementing support for MacOs. " )
sys . exit ( 1 )
elif not WriteLibU sb. is_ready ( ) :
elif not libu sb. is_ready ( ) :
LedNameBadge . _print_libusb_install_hints ( )
sys . exit ( 1 )
@ -679,30 +774,30 @@ class LedNameBadge:
elif sys . version_info [ 0 ] < 3 :
print ( " Please use method ' libusb ' or ' auto ' with python-2.x because of https://github.com/jnweiger/led-badge-ls32/issues/9 " )
sys . exit ( 1 )
elif not WriteUsbHidA pi. is_ready ( ) :
elif not hida pi. is_ready ( ) :
LedNameBadge . _print_hidapi_install_hints ( )
sys . exit ( 1 )
if ( method == ' auto ' or method == ' hidapi ' ) and WriteUsbHidApi . is_ready ( ) :
method_obj = WriteUsbHidApi ( endpoint )
if method_obj . has_device ( ) :
if ( method == ' auto ' or method == ' hidapi ' ) :
method_obj = hidapi
if method_obj . open ( device_id ) :
return method_obj
if ( method == ' auto ' or method == ' libusb ' ) and WriteLibUsb . is_ready ( ) :
method_obj = WriteLibUsb ( endpoint )
if method_obj . has_device ( ) :
if ( method == ' auto ' or method == ' libusb ' ) :
method_obj = libusb
if method_obj . open ( device_id ) :
return method_obj
endpoint_str = ' '
if endpoint != ' auto ' :
endpoint = int ( endpoint )
endpoint_str = ' on endpoint %d ' % ( endpoint , )
device_id_str = ' '
if device_id != ' auto ' :
device_id_str = ' with device_id %s ' % ( device_id , )
print ( " The device is not available with write method ' %s ' %s . " % ( method , endpoint _str) )
print ( " The device is not available with write method ' %s ' %s . " % ( method , device_id _str) )
print ( " * Is a led tag device with vendorID 0x0416 and productID 0x5020 connected? " )
if endpoint != ' auto ' :
print ( " * Have you given the right endpoint ? " )
if device_id != ' auto ' :
print ( " * Have you given the right device_id ? " )
if sys . platform . startswith ( ' linux ' ) :
# /***/
print ( " Try this to find the available endpoint addresses: " )
print ( ' $ lsusb -d 0416:5020 -v | grep -i " endpoint.*out " ' )
print ( " * If it is connected and still do not work, maybe you have to run " )
@ -753,22 +848,22 @@ def main():
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 ( ' -H ' , ' --hid ' , default = ' 0 ' , help = " Deprecated, only for backwards compatibility, please use -M! Set to 1 to ensure connect via HID API, program will then not fallback to usb.core library " )
parser . add_argument ( ' -M ' , ' --method ' , default = ' auto ' , help = " Force using the given write method ( ' hidapi ' or ' libusb ' ) " )
parser . add_argument ( ' -E ' , ' --endpoint ' , default = ' auto ' , help = " Force using the given device endpoint " )
parser . add_argument ( ' -s ' , ' --speed ' , default = ' 4 ' , help = " Scroll speed (Range 1..8). Up to 8 comma-separated values " )
parser . add_argument ( ' -H ' , ' --hid ' , default = ' 0 ' , help = " Deprecated, only for backwards compatibility, please use -M! Set to 1 to ensure connect via HID API, program will then not fallback to usb.core library. " )
parser . add_argument ( ' -M ' , ' --method ' , default = ' auto ' , help = " Force using the given write method ( ' hidapi ' or ' libusb ' ). " )
parser . add_argument ( ' -D ' , ' --device-id ' , default = ' auto ' , help = " Force using the given device id, if ambiguous. Usue one of ' auto ' , ' list ' or whatever list is printing. " )
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 " )
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 ( ' -a ' , ' --ants ' , default = ' 0 ' , help = " 1: animated border, 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 ( ' -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 ( ' -l ' , ' --list-names ' , action = ' version ' , help = " list named icons to be embedded in messages and exit " ,
parser . add_argument ( ' -l ' , ' --list-names ' , action = ' version ' , help = " list named icons to be embedded in messages and exit. " ,
version = ' : ' + ' : : ' . join ( SimpleTextAndIcons . _get_named_bitmaps_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 " )
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 = """
- m 5 " Animation "
@ -837,7 +932,7 @@ def main():
else :
sys . exit ( " Parameter values are ambiguous. Please use either -H or -M. " )
LedNameBadge . write ( buf , method , args . endpoint )
LedNameBadge . write ( buf , method , args . device_id )
def split_to_ints ( list_str ) :