Phil B even more fixes re: linting errors

This commit is contained in:
John Edgar Park 2018-08-24 15:11:49 -07:00
parent 2921f46fbf
commit 2f830df5e8
2 changed files with 142 additions and 152 deletions

View file

@ -1,5 +1,6 @@
# Simple NeoPixel light painter for CPX. Single image filename and speed are set """Circuit Playground Express Light Paintbrush"""
# in code, there's no interface for selecting items/speed/triggering etc. # Single images only. Filename and speed are set in code,
# images should be 30px high, up to 100px wide, 24-bit .bmp files
import gc import gc
import time import time
@ -10,13 +11,12 @@ from neopixel_write import neopixel_write
# uncomment one line only here to select bitmap # uncomment one line only here to select bitmap
FILENAME = "bats.bmp" # BMP file to load from flash filesystem FILENAME = "bats.bmp" # BMP file to load from flash filesystem
#FILENAME = "jpw01.bmp"
#FILENAME = "digikey.bmp" #FILENAME = "digikey.bmp"
#FILENAME = "burger.bmp" #FILENAME = "burger.bmp"
#FILENAME = "afbanner.bmp" #FILENAME = "afbanner.bmp"
#FILENAME = "blinka.bmp" #FILENAME = "blinka.bmp"
# FILENAME = "ghost04.bmp" #FILENAME = "ghost.bmp"
# FILENAME = "ghost07.bmp"
# FILENAME = "ghost02.bmp"
#FILENAME = "helix-32x30.bmp" #FILENAME = "helix-32x30.bmp"
#FILENAME = "wales2-107x30.bmp" #FILENAME = "wales2-107x30.bmp"
#FILENAME = "pumpkin.bmp" #FILENAME = "pumpkin.bmp"
@ -29,23 +29,22 @@ FILENAME = "bats.bmp" # BMP file to load from flash filesystem
#FILENAME = "red_blue.bmp" #FILENAME = "red_blue.bmp"
#FILENAME = "minerva.bmp" #FILENAME = "minerva.bmp"
TOUCH = touchio.TouchIn(board.A5) # Rightmost capacitive touch pad TOUCH = touchio.TouchIn(board.A5) # capacitive touch pad
BRIGHTNESS = 1.0 # NeoPixel brightness 0.0 (min) to 1.0 (max) SPEED = 50000
BRIGHTNESS = 1.0 # Set brightness here, NOT in NeoPixel constructor
GAMMA = 2.7 # Adjusts perceived brighthess linearity GAMMA = 2.7 # Adjusts perceived brighthess linearity
NUM_PIXELS = 30 # NeoPixel strip length (in pixels) NUM_PIXELS = 30 # NeoPixel strip length (in pixels)
SPEED = 20000 # adjust this to change the playback speed e.g. 50000 is slow NEOPIXEL_PIN = board.A1 # Pin where NeoPixels are connected
LOOP = False # set to True for looping DELAY_TIME = 0.01 # Timer delay before it starts
# Switch off onboard NeoPixel... LOOP = False # Set to True for looping
NEOPIXEL_PIN = digitalio.DigitalInOut(board.NEOPIXEL)
NEOPIXEL_PIN.direction = digitalio.Direction.OUTPUT # Enable NeoPixel pin as output and clear the strip
neopixel_write(NEOPIXEL_PIN, bytearray(3)) NEOPIXEL_PIN = digitalio.DigitalInOut(NEOPIXEL_PIN)
# ...then assign NEOPIXEL_PIN to the external NeoPixel connector:
NEOPIXEL_PIN = digitalio.DigitalInOut(board.A1)
NEOPIXEL_PIN.direction = digitalio.Direction.OUTPUT NEOPIXEL_PIN.direction = digitalio.Direction.OUTPUT
neopixel_write(NEOPIXEL_PIN, bytearray(NUM_PIXELS * 3)) neopixel_write(NEOPIXEL_PIN, bytearray(NUM_PIXELS * 3))
# Interpret multi-byte value from file as little-endian value
def read_le(value): def read_le(value):
"""Interpret multi-byte value from file as little-endian value"""
result = 0 result = 0
shift = 0 shift = 0
for byte in value: for byte in value:
@ -54,72 +53,69 @@ def read_le(value):
return result return result
class BMPError(Exception): class BMPError(Exception):
"""Error handler for BMP-loading function"""
pass pass
def load_bmp(filename): def load_bmp(filename):
"""Load BMP file, return as list of column buffers"""
# pylint: disable=too-many-locals, too-many-branches
try: try:
print("Loading", filename) print("Loading", filename)
with open("/" + filename, "rb") as f: with open("/" + filename, "rb") as bmp:
print("File opened") print("File opened")
if f.read(2) != b'BM': # check signature if bmp.read(2) != b'BM': # check signature
raise BMPError("Not BitMap file") raise BMPError("Not BitMap file")
f.read(4) # Read & ignore file size bmp.read(8) # Read & ignore file size and creator bytes
f.read(4) # Read & ignore creator bytes
bmpImageoffset = read_le(f.read(4)) # Start of image data bmp_image_offset = read_le(bmp.read(4)) # Start of image data
f.read(4) # Read & ignore header size bmp.read(4) # Read & ignore header size
bmpWidth = read_le(f.read(4)) bmp_width = read_le(bmp.read(4))
bmpHeight = read_le(f.read(4)) bmp_height = read_le(bmp.read(4))
# BMPs are traditionally stored bottom-to-top. # BMPs are traditionally stored bottom-to-top.
# If bmpHeight is negative, image is in top-down order. # If bmp_height is negative, image is in top-down order.
# This is not BMP canon but has been observed in the wild! # This is not BMP canon but has been observed in the wild!
flip = True flip = True
if bmpHeight < 0: if bmp_height < 0:
bmpHeight = -bmpHeight bmp_height = -bmp_height
flip = False flip = False
print("WxH: (%d,%d)" % (bmpWidth, bmpHeight)) print("WxH: (%d,%d)" % (bmp_width, bmp_height))
if read_le(f.read(2)) != 1: if read_le(bmp.read(2)) != 1:
raise BMPError("Not single-plane") raise BMPError("Not single-plane")
bmpDepth = read_le(f.read(2)) # bits per pixel if read_le(bmp.read(2)) != 24: # bits per pixel
# print("Bit depth: %d" % (bmpDepth))
if bmpDepth != 24:
raise BMPError("Not 24-bit") raise BMPError("Not 24-bit")
if read_le(f.read(2)) != 0: if read_le(bmp.read(2)) != 0:
raise BMPError("Compressed file") raise BMPError("Compressed file")
print("Image format OK, reading data...") print("Image format OK, reading data...")
rowSize = (bmpWidth * 3 + 3) & ~3 # 32-bit line boundary row_size = (bmp_width * 3 + 3) & ~3 # 32-bit line boundary
# Constrain rows loaded to pixel strip length # Constrain rows loaded to pixel strip length
clippedHeight = bmpHeight clipped_height = min(bmp_height, NUM_PIXELS)
if clippedHeight > NUM_PIXELS:
clippedHeight = NUM_PIXELS
# Allocate per-column pixel buffers, sized for NeoPixel strip: # Allocate per-column pixel buffers, sized for NeoPixel strip:
columns = [bytearray(NUM_PIXELS * 3) for i in range(bmpWidth)] columns = [bytearray(NUM_PIXELS * 3) for _ in range(bmp_width)]
# Image is displayed at END (not start) of NeoPixel strip, # Image is displayed at END (not start) of NeoPixel strip,
# this index works incrementally backward in column buffers... # this index works incrementally backward in column buffers...
idx = (NUM_PIXELS - 1) * 3 idx = (NUM_PIXELS - 1) * 3
for row in range(clippedHeight): # For each scanline... for row in range(clipped_height): # For each scanline...
if flip: # Bitmap is stored bottom-to-top order (normal BMP) if flip: # Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize pos = bmp_image_offset + (bmp_height - 1 - row) * row_size
else: # Bitmap is stored top-to-bottom else: # Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize pos = bmp_image_offset + row * row_size
f.seek(pos) # Start of scanline bmp.seek(pos) # Start of scanline
for c in columns: # For each pixel of scanline... for column in columns: # For each pixel of scanline...
# BMP files use BGR color order # BMP files use BGR color order
# blue, green, red = bytearray(f.read(3)) blue, green, red = bmp.read(3)
blue, green, red = f.read(3)
# Rearrange into NeoPixel strip's color order, # Rearrange into NeoPixel strip's color order,
# while handling brightness & gamma correction: # while handling brightness & gamma correction:
c[idx ] = int(pow(green / 255, GAMMA) * BRIGHTNESS * 255 + 0.5) column[idx] = int(pow(green / 255, GAMMA) * BRIGHTNESS * 255 + 0.5)
c[idx+1] = int(pow(red / 255, GAMMA) * BRIGHTNESS * 255 + 0.5) column[idx+1] = int(pow(red / 255, GAMMA) * BRIGHTNESS * 255 + 0.5)
c[idx+2] = int(pow(blue / 255, GAMMA) * BRIGHTNESS * 255 + 0.5) column[idx+2] = int(pow(blue / 255, GAMMA) * BRIGHTNESS * 255 + 0.5)
idx -= 3 # Advance (back) one pixel idx -= 3 # Advance (back) one pixel
# Add one more column with no color data loaded. This is used # Add one more column with no color data loaded. This is used
@ -131,40 +127,39 @@ def load_bmp(filename):
gc.collect() # Garbage-collect now so playback is smoother gc.collect() # Garbage-collect now so playback is smoother
return columns return columns
except OSError as e: except OSError as err:
if e.args[0] == 28: if err.args[0] == 28:
raise OSError("OS Error 28 0.25") raise OSError("OS Error 28 0.25")
else: else:
raise OSError("OS Error 0.5") raise OSError("OS Error 0.5")
except BMPError as e: except BMPError as err:
print("Failed to parse BMP: " + e.args[0]) print("Failed to parse BMP: " + err.args[0])
# Load BMP image, return 'columns' array: # Load BMP image, return 'columns' array:
columns = load_bmp(FILENAME) COLUMNS = load_bmp(FILENAME)
print("Mem free:", gc.mem_free()) print("Mem free:", gc.mem_free())
# Orig code: 10320 bytes free
# New code: 13216 bytes free
column_delay = SPEED / 65535.0 / 10.0 # 0.0 to 0.1 seconds COLUMN_DELAY = SPEED / 65535.0 / 10.0 # 0.0 to 0.1 seconds
# print(COLUMN_DELAY)
while LOOP: while LOOP:
for c in columns: for COLUMN in COLUMNS:
neopixel_write(NEOPIXEL_PIN, c) neopixel_write(NEOPIXEL_PIN, COLUMN)
time.sleep(column_delay) # Column-to-column delay time.sleep(COLUMN_DELAY)
while True: while True:
# Wait for touch pad input: # Wait for touch pad input:
while not TOUCH.value: while not TOUCH.value:
continue continue
column_delay = SPEED / 65535.0 / 10.0 # 0.0 to 0.1 seconds time.sleep(DELAY_TIME)
# print(column_delay)
# Play back color data loaded into each column: # Play back color data loaded into each column:
for c in columns: for COLUMN in COLUMNS:
neopixel_write(NEOPIXEL_PIN, c) neopixel_write(NEOPIXEL_PIN, COLUMN)
time.sleep(column_delay) # Column-to-column delay time.sleep(COLUMN_DELAY)
# Last column is all 0's, no need to explicitly clear strip # Last column is all 0's, no need to explicitly clear strip
# Wait for touch pad release, just in case: # Wait for touch pad release, just in case:

View file

@ -1,6 +1,6 @@
# HalloWing Light Paintbrush """HalloWing Light Paintbrush"""
# Single images only. Filename is set # Single images only. Filename is set in code,
# in code, potentiometer is used to tune playback SPEED # potentiometer is used to tune playback SPEED
# images should be 30px high, up to 100px wide, 24-bit .bmp files # images should be 30px high, up to 100px wide, 24-bit .bmp files
import gc import gc
@ -47,8 +47,8 @@ NEOPIXEL_PIN = digitalio.DigitalInOut(board.EXTERNAL_NEOPIXEL)
NEOPIXEL_PIN.direction = digitalio.Direction.OUTPUT NEOPIXEL_PIN.direction = digitalio.Direction.OUTPUT
neopixel_write(NEOPIXEL_PIN, bytearray(NUM_PIXELS * 3)) neopixel_write(NEOPIXEL_PIN, bytearray(NUM_PIXELS * 3))
# Interpret multi-byte value from file as little-endian value
def read_le(value): def read_le(value):
"""Interpret multi-byte value from file as little-endian value"""
result = 0 result = 0
shift = 0 shift = 0
for byte in value: for byte in value:
@ -57,72 +57,69 @@ def read_le(value):
return result return result
class BMPError(Exception): class BMPError(Exception):
"""Error handler for BMP-loading function"""
pass pass
def load_bmp(filename): def load_bmp(filename):
"""Load BMP file, return as list of column buffers"""
# pylint: disable=too-many-locals, too-many-branches
try: try:
print("Loading", filename) print("Loading", filename)
with open("/" + filename, "rb") as f: with open("/" + filename, "rb") as bmp:
print("File opened") print("File opened")
if f.read(2) != b'BM': # check signature if bmp.read(2) != b'BM': # check signature
raise BMPError("Not BitMap file") raise BMPError("Not BitMap file")
f.read(4) # Read & ignore file size bmp.read(8) # Read & ignore file size and creator bytes
f.read(4) # Read & ignore creator bytes
bmpImageoffset = read_le(f.read(4)) # Start of image data bmp_image_offset = read_le(bmp.read(4)) # Start of image data
f.read(4) # Read & ignore header size bmp.read(4) # Read & ignore header size
bmpWidth = read_le(f.read(4)) bmp_width = read_le(bmp.read(4))
bmpHeight = read_le(f.read(4)) bmp_height = read_le(bmp.read(4))
# BMPs are traditionally stored bottom-to-top. # BMPs are traditionally stored bottom-to-top.
# If bmpHeight is negative, image is in top-down order. # If bmp_height is negative, image is in top-down order.
# This is not BMP canon but has been observed in the wild! # This is not BMP canon but has been observed in the wild!
flip = True flip = True
if bmpHeight < 0: if bmp_height < 0:
bmpHeight = -bmpHeight bmp_height = -bmp_height
flip = False flip = False
print("WxH: (%d,%d)" % (bmpWidth, bmpHeight)) print("WxH: (%d,%d)" % (bmp_width, bmp_height))
if read_le(f.read(2)) != 1: if read_le(bmp.read(2)) != 1:
raise BMPError("Not single-plane") raise BMPError("Not single-plane")
bmpDepth = read_le(f.read(2)) # bits per pixel if read_le(bmp.read(2)) != 24: # bits per pixel
# print("Bit depth: %d" % (bmpDepth))
if bmpDepth != 24:
raise BMPError("Not 24-bit") raise BMPError("Not 24-bit")
if read_le(f.read(2)) != 0: if read_le(bmp.read(2)) != 0:
raise BMPError("Compressed file") raise BMPError("Compressed file")
print("Image format OK, reading data...") print("Image format OK, reading data...")
rowSize = (bmpWidth * 3 + 3) & ~3 # 32-bit line boundary row_size = (bmp_width * 3 + 3) & ~3 # 32-bit line boundary
# Constrain rows loaded to pixel strip length # Constrain rows loaded to pixel strip length
clippedHeight = bmpHeight clipped_height = min(bmp_height, NUM_PIXELS)
if clippedHeight > NUM_PIXELS:
clippedHeight = NUM_PIXELS
# Allocate per-column pixel buffers, sized for NeoPixel strip: # Allocate per-column pixel buffers, sized for NeoPixel strip:
columns = [bytearray(NUM_PIXELS * 3) for i in range(bmpWidth)] columns = [bytearray(NUM_PIXELS * 3) for _ in range(bmp_width)]
# Image is displayed at END (not start) of NeoPixel strip, # Image is displayed at END (not start) of NeoPixel strip,
# this index works incrementally backward in column buffers... # this index works incrementally backward in column buffers...
idx = (NUM_PIXELS - 1) * 3 idx = (NUM_PIXELS - 1) * 3
for row in range(clippedHeight): # For each scanline... for row in range(clipped_height): # For each scanline...
if flip: # Bitmap is stored bottom-to-top order (normal BMP) if flip: # Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize pos = bmp_image_offset + (bmp_height - 1 - row) * row_size
else: # Bitmap is stored top-to-bottom else: # Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize pos = bmp_image_offset + row * row_size
f.seek(pos) # Start of scanline bmp.seek(pos) # Start of scanline
for c in columns: # For each pixel of scanline... for column in columns: # For each pixel of scanline...
# BMP files use BGR color order # BMP files use BGR color order
# blue, green, red = bytearray(f.read(3)) blue, green, red = bmp.read(3)
blue, green, red = f.read(3)
# Rearrange into NeoPixel strip's color order, # Rearrange into NeoPixel strip's color order,
# while handling brightness & gamma correction: # while handling brightness & gamma correction:
c[idx ] = int(pow(green / 255, GAMMA) * BRIGHTNESS * 255 + 0.5) column[idx] = int(pow(green / 255, GAMMA) * BRIGHTNESS * 255 + 0.5)
c[idx+1] = int(pow(red / 255, GAMMA) * BRIGHTNESS * 255 + 0.5) column[idx+1] = int(pow(red / 255, GAMMA) * BRIGHTNESS * 255 + 0.5)
c[idx+2] = int(pow(blue / 255, GAMMA) * BRIGHTNESS * 255 + 0.5) column[idx+2] = int(pow(blue / 255, GAMMA) * BRIGHTNESS * 255 + 0.5)
idx -= 3 # Advance (back) one pixel idx -= 3 # Advance (back) one pixel
# Add one more column with no color data loaded. This is used # Add one more column with no color data loaded. This is used
@ -134,40 +131,38 @@ def load_bmp(filename):
gc.collect() # Garbage-collect now so playback is smoother gc.collect() # Garbage-collect now so playback is smoother
return columns return columns
except OSError as e: except OSError as err:
if e.args[0] == 28: if err.args[0] == 28:
raise OSError("OS Error 28 0.25") raise OSError("OS Error 28 0.25")
else: else:
raise OSError("OS Error 0.5") raise OSError("OS Error 0.5")
except BMPError as e: except BMPError as err:
print("Failed to parse BMP: " + e.args[0]) print("Failed to parse BMP: " + err.args[0])
# Load BMP image, return 'columns' array: # Load BMP image, return 'COLUMNS' array:
columns = load_bmp(FILENAME) COLUMNS = load_bmp(FILENAME)
print("Mem free:", gc.mem_free()) print("Mem free:", gc.mem_free())
# Orig code: 10320 bytes free
# New code: 13216 bytes free
column_delay = ANALOG.value / 65535.0 / 10.0 # 0.0 to 0.1 seconds COLUMN_DELAY = ANALOG.value / 65535.0 / 10.0 # 0.0 to 0.1 seconds
while LOOP: while LOOP:
for c in columns: for COLUMN in COLUMNS:
neopixel_write(NEOPIXEL_PIN, c) neopixel_write(NEOPIXEL_PIN, COLUMN)
time.sleep(column_delay) # Column-to-column delay time.sleep(COLUMN_DELAY)
while True: while True:
# Wait for touch pad input: # Wait for touch pad input:
while not TOUCH.value: while not TOUCH.value:
continue continue
column_delay = ANALOG.value / 65535.0 / 10.0 # 0.0 to 0.1 seconds COLUMN_DELAY = ANALOG.value / 65535.0 / 10.0 # 0.0 to 0.1 seconds
# print(column_delay) # print(COLUMN_DELAY)
# Play back color data loaded into each column: # Play back color data loaded into each column:
for c in columns: for COLUMN in COLUMNS:
neopixel_write(NEOPIXEL_PIN, c) neopixel_write(NEOPIXEL_PIN, COLUMN)
time.sleep(column_delay) # Column-to-column delay time.sleep(COLUMN_DELAY)
# Last column is all 0's, no need to explicitly clear strip # Last column is all 0's, no need to explicitly clear strip
# Wait for touch pad release, just in case: # Wait for touch pad release, just in case: