Compare commits

9 Commits

18 changed files with 193 additions and 1348 deletions

View File

@@ -1,5 +1,7 @@
# Badger2040 System II
> Forked from https://github.com/oneearedrabbit/badger-system-ii
Tired of boring badges that just blend in with the crowd? You want to show off your quirky personality and love of retro technology? You are looking for a fun project to bond with your engineering team? Look no further than the programmable e-ink badge!
https://kruzenshtern.org/the-e-ink-badge-the-coolest-badge-you-didnt-know-you-needed/

3
scripts/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.bin
*.png
*.jpeg

136
scripts/convert.py Normal file
View File

@@ -0,0 +1,136 @@
#!/usr/bin/env python3
"""
Converts images into a format suitable for display on Badger 2040.
Optionally resizes images to 296x128 to fit the display.
Crunches images down to dithered, 1bit colour depth.
Outputs either in raw binary format or as a .py file for embedding into MicroPython.
Output to py functionality is borrwed from data_to_py.py, Copyright (c) 2016 Peter Hinch
"""
import io
import argparse
from PIL import Image, ImageEnhance
from pathlib import Path
PY_HEADER = """# Code generated by convert.py.
"""
PY_FOOTER = """_mvdata = memoryview(_data)
def data():
return _mvdata
"""
parser = argparse.ArgumentParser(description='Converts images into the format used by Badger2040.')
parser.add_argument('file', nargs="+", help='input files to convert')
parser.add_argument('--out_dir', type=Path, default=None, help='output directory')
parser.add_argument('--binary', action="store_true", help='output binary file for MicroPython')
parser.add_argument('--py', action="store_true", help='output .py file for MicroPython embedding')
parser.add_argument('--resize', action="store_true", help='force images to 296x128 pixels')
options = parser.parse_args()
class ByteWriter(object):
bytes_per_line = 16
def __init__(self, stream, varname):
self.stream = stream
self.stream.write('{} =\\\n'.format(varname))
self.bytecount = 0 # For line breaks
def _eol(self):
self.stream.write("'\\\n")
def _eot(self):
self.stream.write("'\n")
def _bol(self):
self.stream.write("b'")
# Output a single byte
def obyte(self, data):
if not self.bytecount:
self._bol()
self.stream.write('\\x{:02x}'.format(data))
self.bytecount += 1
self.bytecount %= self.bytes_per_line
if not self.bytecount:
self._eol()
# Output from a sequence
def odata(self, bytelist):
for byt in bytelist:
self.obyte(byt)
# ensure a correct final line
def eot(self): # User force EOL if one hasn't occurred
if self.bytecount:
self._eot()
self.stream.write('\n')
def convert_image(img):
if options.resize:
img = img.resize((296, 128)) # resize
try:
enhancer = ImageEnhance.Contrast(img)
img = enhancer.enhance(2.0)
except ValueError:
pass
img = img.convert("1") # convert to black and white
return img
def write_stream(header, footer, ip_stream, op_stream):
op_stream.write(header)
op_stream.write('\n')
data = ip_stream.read()
bw_data = ByteWriter(op_stream, '_data')
bw_data.odata(data)
bw_data.eot()
op_stream.write(footer)
# create map of images based on input filenames
for input_filename in options.file:
with Image.open(input_filename) as img:
img = convert_image(img)
image_name = Path(input_filename).stem
w, h = img.size
output_data = [~b & 0xff for b in list(img.tobytes())]
if options.binary:
if options.out_dir is not None:
output_filename = (options.out_dir / image_name).with_suffix(".bin")
else:
output_filename = Path(input_filename).with_suffix(".bin")
print(f"Saving to {output_filename}, {w}x{h}")
with open(output_filename, "wb") as out:
out.write(bytearray(output_data))
elif options.py:
if options.out_dir is not None:
output_filename = (options.out_dir / image_name).with_suffix(".py")
else:
output_filename = Path(input_filename).with_suffix(".py")
print(f"Saving to {output_filename}, {w}x{h}")
with open(output_filename, "w") as out:
write_stream(PY_HEADER, PY_FOOTER, io.BytesIO(bytes(output_data)), out)
else:
image_code = '''\
static const uint8_t {image_name}[{count}] = {{
{byte_data}
}};
'''.format(image_name=image_name, count=len(output_data), byte_data=", ".join(str(b) for b in output_data))
print(image_code)

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,5 +1,5 @@
Kirill Timofeev
Engineering Team
Census
oneearedrabbit
badge.bin
Mariano Sciacco
IoT & Cloud Engineer
Vimar S.p.A.
git.marianosciacco.it
badgem.bin

BIN
src/badges/badgem.bin Normal file

Binary file not shown.

BIN
src/badges/badgem.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -4,9 +4,9 @@ import badger_os
from widgets import draw_window, pprint, ptitle, plength, ppara, button, draw_ui
from random import random
IMAGE_WIDTH = 96
IMAGE_HEIGHT = 96
DELTA = 0
# IMAGE_WIDTH = 96
# IMAGE_HEIGHT = 96
# DELTA = 0
# Check that the fortune directory exists, if not, make it
try:
@@ -25,8 +25,8 @@ state = {
"running": "badge_app",
}
IMAGE_WIDTH = 64
IMAGE_HEIGHT = 64
IMAGE_WIDTH = 29
IMAGE_HEIGHT = 32
def render():
display.pen(15)
@@ -47,11 +47,11 @@ def draw_clippy():
y = 21
width = 294
height = 106
draw_window(display, x, y, width, height, " Special ")
draw_window(display, x, y, width, height, " Information ")
clippy_dat = bytearray(int(IMAGE_WIDTH * IMAGE_HEIGHT / 8))
open(f"images/clippy.bin", "rb").readinto(clippy_dat)
display.image(clippy_dat, IMAGE_WIDTH, IMAGE_HEIGHT, 212, 56)
# clippy_dat = bytearray(int(IMAGE_WIDTH * IMAGE_HEIGHT / 8))
# open(f"images/logo.bin", "rb").readinto(clippy_dat)
# display.image(clippy_dat, IMAGE_WIDTH, IMAGE_HEIGHT, 212, 56)
# scrollbars
display.pen(0)
@@ -92,7 +92,7 @@ def draw_elements():
display.pen(15)
display.clear()
draw_ui(display, "Special")
draw_ui(display, "About")
draw_clippy()

BIN
src/images/loghetto.bin Normal file

Binary file not shown.

BIN
src/images/loghetto.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
src/images/logo.bin Normal file

Binary file not shown.

BIN
src/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

View File

@@ -34,19 +34,19 @@ def draw_about():
# logo
image = bytearray(int(32 * 32 / 8))
open("images/{}".format("census.bin"), "r").readinto(image)
open("images/{}".format("logo.bin"), "r").readinto(image)
display.image(image, 32, 32, 86, 56)
pprint(display, "Engineering", 125, 56, 0)
pprint(display, "Offsite", 125, 66, 0)
pprint(display, "Brooklyn", 125, 76, 0)
pprint(display, "2022", 125, 86, 0)
pprint(display, "AWS Summit", 125, 56, 0)
# pprint(display, "---", 125, 66, 0)
pprint(display, "Milan (Italy)", 125, 66, 0)
pprint(display, "2024", 125, 76, 0)
def render():
display.pen(15)
display.clear()
draw_ui(display, "About")
draw_ui(display, "Event")
draw_about()

View File

@@ -51,7 +51,7 @@ def draw_qr_code(ox, oy, size, code):
def draw_qr_file(n):
draw_window(display, 6, 26, 282, 94, " About us ")
draw_window(display, 6, 26, 282, 94, " About me ")
file = CODES[n]
codetext = open("qrcodes/{}".format(file), "r")

View File

@@ -1,8 +1,8 @@
https://getcensus.com/
Census
* the leading reverse ETL
* no more CSV files
* sync data in real-time
https://marianosciacco.it/publications/qrfuzz-paper/
Mariano Sciacco
* IoT & Cloud Engineer
* Vimar S.p.A.
* (AWS Summit 2024)
Scan this code to learn
more about Census.
If You Are Scanning This,
It Is Too Late!

View File

@@ -187,23 +187,28 @@ def draw_background(display):
# display.image(image, 296, 128, 0, 0)
def draw_menu(display, selected):
menu = "Badge QR Special About"
menu = "Badge QR About Event"
# logo
display.pen(0)
display.thickness(1)
x = 12
y = 6
display.line(x + 2, y, x + 8, y)
display.line(x + 6, y + 1, x + 9, y + 1)
display.line(x + 1, y + 2, x + 10, y + 2)
display.line(x + 5, y + 3, x + 10, y + 3)
display.line(x, y + 4, x + 10, y + 4)
display.line(x + 5, y + 5, x + 10, y + 5)
display.line(x + 1, y + 6, x + 10, y + 6)
display.line(x + 6, y + 7, x + 9, y + 7)
display.line(x + 2, y + 8, x + 8, y + 8)
loghetto = bytearray(int(16 * 18 / 8))
open("images/{}".format("loghetto.bin"), "r").readinto(loghetto)
display.image(loghetto, 16, 18, 10, 2)
# old logo
# x = 12
# y = 6
# display.line(x + 2, y, x + 8, y)
# display.line(x + 6, y + 1, x + 9, y + 1)
# display.line(x + 1, y + 2, x + 10, y + 2)
# display.line(x + 5, y + 3, x + 10, y + 3)
# display.line(x, y + 4, x + 10, y + 4)
# display.line(x + 5, y + 5, x + 10, y + 5)
# display.line(x + 1, y + 6, x + 10, y + 6)
# display.line(x + 6, y + 7, x + 9, y + 7)
# display.line(x + 2, y + 8, x + 8, y + 8)
x = 40
pprint(display, menu, x, 6, 0)
@@ -226,6 +231,7 @@ def draw_border(display):
display.line(1, 1, 1, 127)
display.line(1, 127, 295, 127)
display.line(295, 1, 295, 127)
display.image(bytearray((0xff, 0xff, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0xc0)), 8, 8, 0, 0)
display.image(bytearray((0xff, 0xff, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x03)), 8, 8, 288, 0)
display.image(bytearray((0x03, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0xff, 0xff)), 8, 8, 288, 120)