Badger 2040, tests Ferreol et Capucine
This commit is contained in:
92
badger2040/os/badger2040/README.md
Normal file
92
badger2040/os/badger2040/README.md
Normal file
@ -0,0 +1,92 @@
|
||||
# Badger 2040 Examples <!-- omit in toc -->
|
||||
|
||||
- [Function Examples](#function-examples)
|
||||
- [Battery](#battery)
|
||||
- [Button Test](#button-test)
|
||||
- [LED](#led)
|
||||
- [Pin interrupt](#pin-interrupt)
|
||||
- [Application Examples](#application-examples)
|
||||
- [Badge](#badge)
|
||||
- [Checklist](#checklist)
|
||||
- [Clock](#clock)
|
||||
- [E-Book](#e-book)
|
||||
- [Fonts](#fonts)
|
||||
- [Image](#image)
|
||||
- [QR gen](#qr-gen)
|
||||
- [Launcher](#launcher)
|
||||
|
||||
|
||||
## Function Examples
|
||||
|
||||
### Battery
|
||||
[battery.py](battery.py)
|
||||
|
||||
An example of how to read the battery voltage and display a battery level indicator.
|
||||
|
||||
### Button Test
|
||||
[button_test.py](button_test.py)
|
||||
|
||||
An example of how to read Badger2040's buttons and display a unique message for each.
|
||||
|
||||
### LED
|
||||
[led.py](led.py)
|
||||
|
||||
Blinks Badger's LED on and off.
|
||||
|
||||
### Pin interrupt
|
||||
[pin_interrupt.py](pin_interrupt.py)
|
||||
|
||||
An example of drawing text and graphics and using the buttons.
|
||||
|
||||
## Application Examples
|
||||
|
||||
### Badge
|
||||
[badge.py](badge.py)
|
||||
|
||||
Create your own name badge! This application looks for two files on your MicroPython drive:
|
||||
* `badge.txt` - A text file containing 6 lines, corresponding to the 6 different pieces of text on the badge
|
||||
* `badge-image.bin` - A 108x128px 1-bit colour depth image to display alongside the text. You can use `examples/badger2040/image_converter/convert.py` to convert them:
|
||||
|
||||
```shell
|
||||
python3 convert.py --binary --resize image_file_1.png image_file_2.png image_file_3.png
|
||||
```
|
||||
|
||||
### Checklist
|
||||
[list.py](list.py)
|
||||
|
||||
A checklist application, letting you navigate through items and tick each of them off.
|
||||
|
||||
### Clock
|
||||
[clock.py](clock.py)
|
||||
|
||||
A simple clock showing the time and date, that uses the E Ink's fast speed to update every second
|
||||
|
||||
### E-Book
|
||||
[ebook.py](ebook.py)
|
||||
|
||||
A mini text file e-reader. Comes pre-loaded with an excerpt of The Wind In the Willows.
|
||||
|
||||
### Fonts
|
||||
[fonts.py](fonts.py)
|
||||
|
||||
A demonstration of the various fonts that can be used in your programs.
|
||||
|
||||
### Image
|
||||
[image.py](image.py)
|
||||
|
||||
An image gallery. Displays and lets you cycle through any images stored within the MicroPython device's `/images` directory. Images must be 296x128 pixels with 1-bit colour depth. You can use `examples/badger2040/image_converter/convert.py` to convert them:
|
||||
|
||||
```shell
|
||||
python3 convert.py --binary --resize image_file_1.png image_file_2.png image_file_3.png
|
||||
```
|
||||
|
||||
### QR gen
|
||||
[qrgen.py](qrgen.py)
|
||||
|
||||
This application looks for a file on your MicroPython drive:
|
||||
- `qrcode.txt` - A text file containing 9 lines. The first line should be a URL which will be converted into and displayed as a QR code. Up to 8 more lines of information can be added, which will be shown as plain text to the right of the QR code.
|
||||
|
||||
### Launcher
|
||||
[launcher.py](launcher.py)
|
||||
|
||||
A launcher-style application, that provide a menu of other applications that can be loaded, as well as information such as battery level.
|
File diff suppressed because it is too large
Load Diff
BIN
badger2040/os/badger2040/assets/badge_image.png
Normal file
BIN
badger2040/os/badger2040/assets/badge_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
BIN
badger2040/os/badger2040/assets/badgerpunk.png
Normal file
BIN
badger2040/os/badger2040/assets/badgerpunk.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
6
badger2040/os/badger2040/assets/boot.py
Normal file
6
badger2040/os/badger2040/assets/boot.py
Normal file
@ -0,0 +1,6 @@
|
||||
try:
|
||||
open("main.py", "r")
|
||||
except OSError:
|
||||
with open("main.py", "w") as f:
|
||||
f.write("import _launcher")
|
||||
f.flush()
|
BIN
badger2040/os/badger2040/assets/launchericons.png
Normal file
BIN
badger2040/os/badger2040/assets/launchericons.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
267
badger2040/os/badger2040/badge.py
Normal file
267
badger2040/os/badger2040/badge.py
Normal file
@ -0,0 +1,267 @@
|
||||
import badger2040
|
||||
import machine
|
||||
import time
|
||||
|
||||
# Global Constants
|
||||
WIDTH = badger2040.WIDTH
|
||||
HEIGHT = badger2040.HEIGHT
|
||||
|
||||
IMAGE_WIDTH = 104
|
||||
|
||||
COMPANY_HEIGHT = 30
|
||||
DETAILS_HEIGHT = 20
|
||||
NAME_HEIGHT = HEIGHT - COMPANY_HEIGHT - (DETAILS_HEIGHT * 2) - 2
|
||||
TEXT_WIDTH = WIDTH - IMAGE_WIDTH - 1
|
||||
|
||||
COMPANY_TEXT_SIZE = 0.6
|
||||
DETAILS_TEXT_SIZE = 0.5
|
||||
|
||||
LEFT_PADDING = 5
|
||||
NAME_PADDING = 20
|
||||
DETAIL_SPACING = 10
|
||||
|
||||
OVERLAY_BORDER = 40
|
||||
OVERLAY_SPACING = 20
|
||||
OVERLAY_TEXT_SIZE = 0.6
|
||||
|
||||
DEFAULT_TEXT = """mustelid inc
|
||||
H. Badger
|
||||
RP2040
|
||||
2MB Flash
|
||||
E ink
|
||||
296x128px"""
|
||||
|
||||
BADGE_IMAGE = bytearray(int(IMAGE_WIDTH * HEIGHT / 8))
|
||||
|
||||
try:
|
||||
open("badge-image.bin", "rb").readinto(BADGE_IMAGE)
|
||||
except OSError:
|
||||
try:
|
||||
import badge_image
|
||||
BADGE_IMAGE = bytearray(badge_image.data())
|
||||
del badge_image
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Utility functions
|
||||
# ------------------------------
|
||||
|
||||
# Reduce the size of a string until it fits within a given width
|
||||
def truncatestring(text, text_size, width):
|
||||
while True:
|
||||
length = display.measure_text(text, text_size)
|
||||
if length > 0 and length > width:
|
||||
text = text[:-1]
|
||||
else:
|
||||
text += ""
|
||||
return text
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Drawing functions
|
||||
# ------------------------------
|
||||
|
||||
# Draw an overlay box with a given message within it
|
||||
def draw_overlay(message, width, height, line_spacing, text_size):
|
||||
|
||||
# Draw a light grey background
|
||||
display.pen(12)
|
||||
display.rectangle((WIDTH - width) // 2, (HEIGHT - height) // 2, width, height)
|
||||
|
||||
# Take the provided message and split it up into
|
||||
# lines that fit within the specified width
|
||||
words = message.split(" ")
|
||||
lines = []
|
||||
line = ""
|
||||
appended_line = ""
|
||||
for word in words:
|
||||
if len(word) > 0:
|
||||
appended_line += " "
|
||||
appended_line += word
|
||||
if display.measure_text(appended_line, text_size) >= width:
|
||||
lines.append(line)
|
||||
appended_line = word
|
||||
else:
|
||||
line = appended_line
|
||||
if len(line) != 0:
|
||||
lines.append(line)
|
||||
|
||||
display.pen(0)
|
||||
display.thickness(2)
|
||||
|
||||
# Display each line of text from the message, centre-aligned
|
||||
num_lines = len(lines)
|
||||
for i in range(num_lines):
|
||||
length = display.measure_text(lines[i], text_size)
|
||||
current_line = (i * line_spacing) - ((num_lines - 1) * line_spacing) // 2
|
||||
display.text(lines[i], (WIDTH - length) // 2, (HEIGHT // 2) + current_line, text_size)
|
||||
|
||||
|
||||
# Draw the badge, including user text
|
||||
def draw_badge():
|
||||
display.pen(0)
|
||||
display.clear()
|
||||
|
||||
# Draw badge image
|
||||
display.image(BADGE_IMAGE, IMAGE_WIDTH, HEIGHT, WIDTH - IMAGE_WIDTH, 0)
|
||||
|
||||
# Draw a border around the image
|
||||
display.pen(0)
|
||||
display.thickness(1)
|
||||
display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - 1, 0)
|
||||
display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - IMAGE_WIDTH, HEIGHT - 1)
|
||||
display.line(WIDTH - IMAGE_WIDTH, HEIGHT - 1, WIDTH - 1, HEIGHT - 1)
|
||||
display.line(WIDTH - 1, 0, WIDTH - 1, HEIGHT - 1)
|
||||
|
||||
# Uncomment this if a white background is wanted behind the company
|
||||
# display.pen(15)
|
||||
# display.rectangle(1, 1, TEXT_WIDTH, COMPANY_HEIGHT - 1)
|
||||
|
||||
# Draw the company
|
||||
display.pen(15) # Change this to 0 if a white background is used
|
||||
display.font("serif")
|
||||
display.thickness(3)
|
||||
display.text(company, LEFT_PADDING, (COMPANY_HEIGHT // 2) + 1, COMPANY_TEXT_SIZE)
|
||||
|
||||
# Draw a white background behind the name
|
||||
display.pen(15)
|
||||
display.thickness(1)
|
||||
display.rectangle(1, COMPANY_HEIGHT + 1, TEXT_WIDTH, NAME_HEIGHT)
|
||||
|
||||
# Draw the name, scaling it based on the available width
|
||||
display.pen(0)
|
||||
display.font("sans")
|
||||
display.thickness(4)
|
||||
name_size = 2.0 # A sensible starting scale
|
||||
while True:
|
||||
name_length = display.measure_text(name, name_size)
|
||||
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1:
|
||||
name_size -= 0.01
|
||||
else:
|
||||
display.text(name, (TEXT_WIDTH - name_length) // 2, (NAME_HEIGHT // 2) + COMPANY_HEIGHT + 1, name_size)
|
||||
break
|
||||
|
||||
# Draw a white backgrounds behind the details
|
||||
display.pen(15)
|
||||
display.thickness(1)
|
||||
display.rectangle(1, HEIGHT - DETAILS_HEIGHT * 2, TEXT_WIDTH, DETAILS_HEIGHT - 1)
|
||||
display.rectangle(1, HEIGHT - DETAILS_HEIGHT, TEXT_WIDTH, DETAILS_HEIGHT - 1)
|
||||
|
||||
# Draw the first detail's title and text
|
||||
display.pen(0)
|
||||
display.font("sans")
|
||||
display.thickness(3)
|
||||
name_length = display.measure_text(detail1_title, DETAILS_TEXT_SIZE)
|
||||
display.text(detail1_title, LEFT_PADDING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), DETAILS_TEXT_SIZE)
|
||||
display.thickness(2)
|
||||
display.text(detail1_text, 5 + name_length + DETAIL_SPACING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), DETAILS_TEXT_SIZE)
|
||||
|
||||
# Draw the second detail's title and text
|
||||
display.thickness(3)
|
||||
name_length = display.measure_text(detail2_title, DETAILS_TEXT_SIZE)
|
||||
display.text(detail2_title, LEFT_PADDING, HEIGHT - (DETAILS_HEIGHT // 2), DETAILS_TEXT_SIZE)
|
||||
display.thickness(2)
|
||||
display.text(detail2_text, LEFT_PADDING + name_length + DETAIL_SPACING, HEIGHT - (DETAILS_HEIGHT // 2), DETAILS_TEXT_SIZE)
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Program setup
|
||||
# ------------------------------
|
||||
|
||||
# Global variables
|
||||
show_overlay = False
|
||||
|
||||
# Create a new Badger and set it to update NORMAL
|
||||
display = badger2040.Badger2040()
|
||||
display.update_speed(badger2040.UPDATE_NORMAL)
|
||||
|
||||
# Open the badge file
|
||||
try:
|
||||
badge = open("badge.txt", "r")
|
||||
except OSError:
|
||||
badge = open("badge.txt", "w")
|
||||
badge.write(DEFAULT_TEXT)
|
||||
badge.flush()
|
||||
badge.seek(0)
|
||||
|
||||
# Read in the next 6 lines
|
||||
company = badge.readline() # "mustelid inc"
|
||||
name = badge.readline() # "H. Badger"
|
||||
detail1_title = badge.readline() # "RP2040"
|
||||
detail1_text = badge.readline() # "2MB Flash"
|
||||
detail2_title = badge.readline() # "E ink"
|
||||
detail2_text = badge.readline() # "296x128px"
|
||||
|
||||
# Truncate all of the text (except for the name as that is scaled)
|
||||
company = truncatestring(company, COMPANY_TEXT_SIZE, TEXT_WIDTH)
|
||||
|
||||
detail1_title = truncatestring(detail1_title, DETAILS_TEXT_SIZE, TEXT_WIDTH)
|
||||
detail1_text = truncatestring(detail1_text, DETAILS_TEXT_SIZE,
|
||||
TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail1_title, DETAILS_TEXT_SIZE))
|
||||
|
||||
detail2_title = truncatestring(detail2_title, DETAILS_TEXT_SIZE, TEXT_WIDTH)
|
||||
detail2_text = truncatestring(detail2_text, DETAILS_TEXT_SIZE,
|
||||
TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail2_title, DETAILS_TEXT_SIZE))
|
||||
|
||||
# Set up the buttons
|
||||
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
|
||||
# Button handling function
|
||||
def button(pin):
|
||||
global show_overlay
|
||||
|
||||
if pin == button_a:
|
||||
show_overlay = True
|
||||
return
|
||||
|
||||
if pin == button_b:
|
||||
show_overlay = True
|
||||
return
|
||||
|
||||
if pin == button_c:
|
||||
show_overlay = True
|
||||
return
|
||||
|
||||
if pin == button_up:
|
||||
show_overlay = True
|
||||
return
|
||||
|
||||
if pin == button_down:
|
||||
show_overlay = True
|
||||
return
|
||||
|
||||
|
||||
# Register the button handling function with the buttons
|
||||
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Main program loop
|
||||
# ------------------------------
|
||||
|
||||
draw_badge()
|
||||
display.update()
|
||||
|
||||
while True:
|
||||
if show_overlay:
|
||||
draw_overlay("To change the text, connect Badger2040 to a PC, load up Thonny, and modify badge.txt",
|
||||
WIDTH - OVERLAY_BORDER, HEIGHT - OVERLAY_BORDER, OVERLAY_SPACING, OVERLAY_TEXT_SIZE)
|
||||
display.update()
|
||||
time.sleep(4)
|
||||
|
||||
draw_badge()
|
||||
display.update()
|
||||
show_overlay = False
|
||||
|
||||
time.sleep(0.1)
|
163
badger2040/os/badger2040/battery.py
Normal file
163
badger2040/os/badger2040/battery.py
Normal file
@ -0,0 +1,163 @@
|
||||
import badger2040
|
||||
from machine import Pin, ADC
|
||||
import time
|
||||
|
||||
# Global Constants
|
||||
# for e.g. 2xAAA batteries, try max 3.4 min 3.0
|
||||
MAX_BATTERY_VOLTAGE = 4.0
|
||||
MIN_BATTERY_VOLTAGE = 3.2
|
||||
|
||||
WIDTH = badger2040.WIDTH
|
||||
HEIGHT = badger2040.HEIGHT
|
||||
|
||||
BATT_WIDTH = 200
|
||||
BATT_HEIGHT = 100
|
||||
BATT_BORDER = 10
|
||||
BATT_TERM_WIDTH = 20
|
||||
BATT_TERM_HEIGHT = 50
|
||||
BATT_BAR_PADDING = 10
|
||||
BATT_BAR_HEIGHT = BATT_HEIGHT - (BATT_BORDER * 2) - (BATT_BAR_PADDING * 2)
|
||||
BATT_BAR_START = ((WIDTH - BATT_WIDTH) // 2) + BATT_BORDER + BATT_BAR_PADDING
|
||||
BATT_BAR_END = ((WIDTH + BATT_WIDTH) // 2) - BATT_BORDER - BATT_BAR_PADDING
|
||||
|
||||
NUM_BATT_BARS = 4
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Utility functions
|
||||
# ------------------------------
|
||||
|
||||
|
||||
def map_value(input, in_min, in_max, out_min, out_max):
|
||||
return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Drawing functions
|
||||
# ------------------------------
|
||||
|
||||
# Draw the frame of the reader
|
||||
def draw_battery(level, resolution):
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
|
||||
display.thickness(1)
|
||||
|
||||
# Draw the battery outline
|
||||
display.pen(0)
|
||||
display.rectangle(
|
||||
(WIDTH - BATT_WIDTH) // 2, (HEIGHT - BATT_HEIGHT) // 2, BATT_WIDTH, BATT_HEIGHT
|
||||
)
|
||||
|
||||
display.rectangle(
|
||||
(WIDTH + BATT_WIDTH) // 2,
|
||||
(HEIGHT - BATT_TERM_HEIGHT) // 2,
|
||||
BATT_TERM_WIDTH,
|
||||
BATT_TERM_HEIGHT,
|
||||
)
|
||||
|
||||
display.pen(15)
|
||||
display.rectangle(
|
||||
(WIDTH - BATT_WIDTH) // 2 + BATT_BORDER,
|
||||
(HEIGHT - BATT_HEIGHT) // 2 + BATT_BORDER,
|
||||
BATT_WIDTH - BATT_BORDER * 2,
|
||||
BATT_HEIGHT - BATT_BORDER * 2,
|
||||
)
|
||||
|
||||
# Add a special check for no battery
|
||||
if level < 1:
|
||||
X = WIDTH // 2
|
||||
Y = HEIGHT // 2
|
||||
|
||||
display.pen(0)
|
||||
display.thickness(1)
|
||||
thickness = (BATT_BORDER * 3) // 2
|
||||
start_extra = thickness // 3
|
||||
end_extra = (thickness * 2) // 3
|
||||
for i in range(0, thickness):
|
||||
excess = i // 2
|
||||
display.line(
|
||||
X - (BATT_HEIGHT // 2) + i - excess - start_extra,
|
||||
Y - (BATT_HEIGHT // 2) - excess - start_extra,
|
||||
X + (BATT_HEIGHT // 2) + i - excess + end_extra,
|
||||
Y + (BATT_HEIGHT // 2) - excess + end_extra,
|
||||
)
|
||||
display.pen(15)
|
||||
for i in range(0 - thickness, 0):
|
||||
display.line(
|
||||
X - (BATT_HEIGHT // 2) + i,
|
||||
Y - (BATT_HEIGHT // 2),
|
||||
X + (BATT_HEIGHT // 2) + i,
|
||||
Y + (BATT_HEIGHT // 2),
|
||||
)
|
||||
else:
|
||||
# Draw the battery bars
|
||||
display.pen(0)
|
||||
length = (
|
||||
BATT_BAR_END - BATT_BAR_START - ((NUM_BATT_BARS - 1) * BATT_BAR_PADDING)
|
||||
) // NUM_BATT_BARS
|
||||
current_level = 0.0
|
||||
normalised_level = level / resolution
|
||||
for i in range(NUM_BATT_BARS):
|
||||
current_level = (1.0 * i) / NUM_BATT_BARS
|
||||
if normalised_level > current_level:
|
||||
pos = i * (length + BATT_BAR_PADDING)
|
||||
display.rectangle(
|
||||
BATT_BAR_START + pos,
|
||||
(HEIGHT - BATT_BAR_HEIGHT) // 2,
|
||||
length,
|
||||
BATT_BAR_HEIGHT,
|
||||
)
|
||||
|
||||
display.update()
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Program setup
|
||||
# ------------------------------
|
||||
|
||||
# Create a new Badger and set it to update FAST
|
||||
display = badger2040.Badger2040()
|
||||
display.update_speed(badger2040.UPDATE_FAST)
|
||||
|
||||
# Set up the ADCs for measuring battery voltage
|
||||
vbat_adc = ADC(badger2040.PIN_BATTERY)
|
||||
vref_adc = ADC(badger2040.PIN_1V2_REF)
|
||||
vref_en = Pin(badger2040.PIN_VREF_POWER)
|
||||
vref_en.init(Pin.OUT)
|
||||
vref_en.value(0)
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Main program loop
|
||||
# ------------------------------
|
||||
|
||||
last_level = -1
|
||||
|
||||
while True:
|
||||
# Enable the onboard voltage reference
|
||||
vref_en.value(1)
|
||||
|
||||
# Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries
|
||||
vdd = 1.24 * (65535 / vref_adc.read_u16())
|
||||
vbat = (
|
||||
(vbat_adc.read_u16() / 65535) * 3 * vdd
|
||||
) # 3 in this is a gain, not rounding of 3.3V
|
||||
|
||||
# Disable the onboard voltage reference
|
||||
vref_en.value(0)
|
||||
|
||||
# Print out the voltage
|
||||
print("Battery Voltage = ", vbat, "V", sep="")
|
||||
|
||||
# Convert the voltage to a level to display onscreen
|
||||
level = int(
|
||||
map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, NUM_BATT_BARS)
|
||||
)
|
||||
|
||||
# Only draw if the battery level has changed significantly
|
||||
if level != last_level:
|
||||
draw_battery(level, NUM_BATT_BARS)
|
||||
last_level = level
|
||||
|
||||
time.sleep(1)
|
67
badger2040/os/badger2040/button_test.py
Normal file
67
badger2040/os/badger2040/button_test.py
Normal file
@ -0,0 +1,67 @@
|
||||
import badger2040
|
||||
import machine
|
||||
import time
|
||||
|
||||
display = badger2040.Badger2040()
|
||||
display.update_speed(badger2040.UPDATE_TURBO)
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
display.update()
|
||||
|
||||
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
# the User button (boot/usr on back of board) is inverted from the others
|
||||
button_user = machine.Pin(badger2040.BUTTON_USER, machine.Pin.IN, machine.Pin.PULL_UP)
|
||||
|
||||
|
||||
message = None
|
||||
message_y = 60
|
||||
|
||||
|
||||
def button(pin):
|
||||
global message
|
||||
if message is not None:
|
||||
return
|
||||
if pin == button_a:
|
||||
message = "Button a"
|
||||
return
|
||||
if pin == button_b:
|
||||
message = "Button b"
|
||||
return
|
||||
if pin == button_c:
|
||||
message = "Button c"
|
||||
return
|
||||
if pin == button_up:
|
||||
message = "Button Up"
|
||||
return
|
||||
if pin == button_down:
|
||||
message = "Button Down"
|
||||
return
|
||||
if pin == button_user:
|
||||
message = "Button Usr"
|
||||
return
|
||||
|
||||
|
||||
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
|
||||
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_user.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
|
||||
|
||||
while True:
|
||||
if message is not None:
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
display.pen(0)
|
||||
display.thickness(4)
|
||||
display.text(message, 6, message_y, 1.4)
|
||||
for _ in range(2):
|
||||
display.update()
|
||||
message = None
|
||||
time.sleep(0.1)
|
148
badger2040/os/badger2040/clock.py
Normal file
148
badger2040/os/badger2040/clock.py
Normal file
@ -0,0 +1,148 @@
|
||||
import time
|
||||
import machine
|
||||
import badger2040
|
||||
|
||||
|
||||
rtc = machine.RTC()
|
||||
screen = badger2040.Badger2040()
|
||||
screen.update_speed(badger2040.UPDATE_TURBO)
|
||||
screen.font("gothic")
|
||||
|
||||
cursors = ["year", "month", "day", "hour", "minute"]
|
||||
set_clock = False
|
||||
cursor = 0
|
||||
last = 0
|
||||
|
||||
# Set up the buttons
|
||||
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
|
||||
def days_in_month(month, year):
|
||||
if month == 2 and ((year % 4 == 0 and year % 100 != 0) or year % 400 == 0):
|
||||
return 29
|
||||
return (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[month - 1]
|
||||
|
||||
|
||||
# Button handling function
|
||||
def button(pin):
|
||||
global last, set_clock, cursor, year, month, day, hour, minute
|
||||
|
||||
time.sleep(0.05)
|
||||
if not pin.value():
|
||||
return
|
||||
|
||||
adjust = 0
|
||||
changed = False
|
||||
|
||||
if pin == button_b:
|
||||
set_clock = not set_clock
|
||||
changed = True
|
||||
if not set_clock:
|
||||
rtc.datetime((year, month, day, 0, hour, minute, second, 0))
|
||||
|
||||
if set_clock:
|
||||
if pin == button_c:
|
||||
cursor += 1
|
||||
cursor %= len(cursors)
|
||||
|
||||
if pin == button_a:
|
||||
cursor -= 1
|
||||
cursor %= len(cursors)
|
||||
|
||||
if pin == button_up:
|
||||
adjust = 1
|
||||
|
||||
if pin == button_down:
|
||||
adjust = -1
|
||||
|
||||
if cursors[cursor] == "year":
|
||||
year += adjust
|
||||
year = max(year, 2022)
|
||||
day = min(day, days_in_month(month, year))
|
||||
if cursors[cursor] == "month":
|
||||
month += adjust
|
||||
month = min(max(month, 1), 12)
|
||||
day = min(day, days_in_month(month, year))
|
||||
if cursors[cursor] == "day":
|
||||
day += adjust
|
||||
day = min(max(day, 1), days_in_month(month, year))
|
||||
if cursors[cursor] == "hour":
|
||||
hour += adjust
|
||||
hour %= 24
|
||||
if cursors[cursor] == "minute":
|
||||
minute += adjust
|
||||
minute %= 60
|
||||
|
||||
if set_clock or changed:
|
||||
draw_clock()
|
||||
|
||||
|
||||
# Register the button handling function with the buttons
|
||||
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
|
||||
|
||||
def draw_clock():
|
||||
hms = "{:02}:{:02}:{:02}".format(hour, minute, second)
|
||||
ymd = "{:04}/{:02}/{:02}".format(year, month, day)
|
||||
|
||||
hms_width = screen.measure_text(hms, 1.8)
|
||||
hms_offset = int((badger2040.WIDTH / 2) - (hms_width / 2))
|
||||
h_width = screen.measure_text(hms[0:2], 1.8)
|
||||
mi_width = screen.measure_text(hms[3:5], 1.8)
|
||||
mi_offset = screen.measure_text(hms[0:3], 1.8)
|
||||
|
||||
ymd_width = screen.measure_text(ymd, 1.0)
|
||||
ymd_offset = int((badger2040.WIDTH / 2) - (ymd_width / 2))
|
||||
y_width = screen.measure_text(ymd[0:4], 1.0)
|
||||
m_width = screen.measure_text(ymd[5:7], 1.0)
|
||||
m_offset = screen.measure_text(ymd[0:5], 1.0)
|
||||
d_width = screen.measure_text(ymd[8:10], 1.0)
|
||||
d_offset = screen.measure_text(ymd[0:8], 1.0)
|
||||
|
||||
screen.pen(15)
|
||||
screen.clear()
|
||||
screen.pen(0)
|
||||
screen.thickness(5)
|
||||
screen.text(hms, hms_offset, 40, 1.8)
|
||||
screen.thickness(3)
|
||||
screen.text(ymd, ymd_offset, 100, 1.0)
|
||||
|
||||
if set_clock:
|
||||
if cursors[cursor] == "year":
|
||||
screen.line(ymd_offset, 120, ymd_offset + y_width, 120)
|
||||
if cursors[cursor] == "month":
|
||||
screen.line(ymd_offset + m_offset, 120, ymd_offset + m_offset + m_width, 120)
|
||||
if cursors[cursor] == "day":
|
||||
screen.line(ymd_offset + d_offset, 120, ymd_offset + d_offset + d_width, 120)
|
||||
|
||||
if cursors[cursor] == "hour":
|
||||
screen.line(hms_offset, 70, hms_offset + h_width, 70)
|
||||
if cursors[cursor] == "minute":
|
||||
screen.line(hms_offset + mi_offset, 70, hms_offset + mi_offset + mi_width, 70)
|
||||
|
||||
screen.update()
|
||||
|
||||
|
||||
year, month, day, wd, hour, minute, second, _ = rtc.datetime()
|
||||
|
||||
if (year, month, day) == (2021, 1, 1):
|
||||
rtc.datetime((2022, 2, 28, 0, 12, 0, 0, 0))
|
||||
|
||||
last_second = second
|
||||
|
||||
while True:
|
||||
if not set_clock:
|
||||
year, month, day, wd, hour, minute, second, _ = rtc.datetime()
|
||||
if second != last_second:
|
||||
draw_clock()
|
||||
last_second = second
|
||||
time.sleep(0.1)
|
211
badger2040/os/badger2040/conway.py
Normal file
211
badger2040/os/badger2040/conway.py
Normal file
@ -0,0 +1,211 @@
|
||||
import math
|
||||
import time
|
||||
from random import random
|
||||
|
||||
import machine
|
||||
|
||||
import badger2040
|
||||
|
||||
# ------------------------------
|
||||
# Program setup
|
||||
# ------------------------------
|
||||
|
||||
# Global constants
|
||||
CELL_SIZE = 6 # Size of cell in pixels
|
||||
INITIAL_DENSITY = 0.3 # Density of cells at start
|
||||
|
||||
# Create a new Badger and set it to update TURBO
|
||||
screen = badger2040.Badger2040()
|
||||
screen.update_speed(badger2040.UPDATE_TURBO)
|
||||
|
||||
restart = False # should sim be restarted
|
||||
|
||||
# ------------------------------
|
||||
# Button functions
|
||||
# ------------------------------
|
||||
|
||||
|
||||
# Button handling function
|
||||
def button(pin):
|
||||
global restart
|
||||
# if 'a' button is pressed, restart the sim
|
||||
if pin == button_a:
|
||||
restart = True
|
||||
|
||||
|
||||
# Set up button
|
||||
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
|
||||
# ------------------------------
|
||||
# Screen functions
|
||||
# ------------------------------
|
||||
|
||||
|
||||
# Remove everything from the screen
|
||||
def init_screen():
|
||||
screen.update_speed(badger2040.UPDATE_NORMAL)
|
||||
screen.pen(15)
|
||||
screen.clear()
|
||||
screen.update()
|
||||
screen.update_speed(badger2040.UPDATE_TURBO)
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Classes
|
||||
# ------------------------------
|
||||
|
||||
# Define a 'cell'
|
||||
class Cell:
|
||||
def __init__(self):
|
||||
self._alive = False
|
||||
|
||||
def make_alive(self):
|
||||
self._alive = True
|
||||
|
||||
def make_dead(self):
|
||||
self._alive = False
|
||||
|
||||
def is_alive(self):
|
||||
return self._alive
|
||||
|
||||
|
||||
# Define the whole board
|
||||
class Board:
|
||||
def __init__(self):
|
||||
self._rows = math.floor(badger2040.WIDTH / CELL_SIZE)
|
||||
self._columns = math.floor(badger2040.HEIGHT / CELL_SIZE)
|
||||
self._grid = [[Cell() for _ in range(self._columns)] for _ in range(self._rows)]
|
||||
|
||||
self._initialise_board()
|
||||
|
||||
# Draw the board to the screen
|
||||
def draw_board(self):
|
||||
row_idx = 0
|
||||
column_idx = 0
|
||||
|
||||
for row in self._grid:
|
||||
column_idx = 0
|
||||
for cell in row:
|
||||
if cell.is_alive():
|
||||
screen.pen(0)
|
||||
else:
|
||||
screen.pen(15)
|
||||
screen.rectangle(
|
||||
row_idx * CELL_SIZE, column_idx * CELL_SIZE, CELL_SIZE, CELL_SIZE
|
||||
)
|
||||
column_idx += 1
|
||||
row_idx += 1
|
||||
|
||||
screen.update()
|
||||
|
||||
# Generate the first iteration of the board
|
||||
def _initialise_board(self):
|
||||
for row in self._grid:
|
||||
for cell in row:
|
||||
if random() <= INITIAL_DENSITY:
|
||||
cell.make_alive()
|
||||
|
||||
# Get the neighbour cells for a given cell
|
||||
def get_neighbours(self, current_row, current_column):
|
||||
# Cells either side of current cell
|
||||
neighbour_min = -1
|
||||
neighbour_max = 2
|
||||
neighbours = []
|
||||
|
||||
for row in range(neighbour_min, neighbour_max):
|
||||
for column in range(neighbour_min, neighbour_max):
|
||||
neighbour_row = current_row + row
|
||||
neighbour_column = current_column + column
|
||||
# Don't count the current cell
|
||||
if not (
|
||||
neighbour_row == current_row and neighbour_column == current_column
|
||||
):
|
||||
# It's a toroidal world so go all the way round if necessary
|
||||
if (neighbour_row) < 0:
|
||||
neighbour_row = self._rows - 1
|
||||
elif (neighbour_row) >= self._rows:
|
||||
neighbour_row = 0
|
||||
|
||||
if (neighbour_column) < 0:
|
||||
neighbour_column = self._columns - 1
|
||||
elif (neighbour_column) >= self._columns:
|
||||
neighbour_column = 0
|
||||
|
||||
neighbours.append(self._grid[neighbour_row][neighbour_column])
|
||||
return neighbours
|
||||
|
||||
# Calculate the next generation
|
||||
def create_next_generation(self):
|
||||
to_alive = []
|
||||
to_dead = []
|
||||
changed = False
|
||||
|
||||
for row in range(len(self._grid)):
|
||||
for column in range(len(self._grid[row])):
|
||||
# Get all the neighours that are alive
|
||||
alive_neighbours = []
|
||||
for neighbour_cell in self.get_neighbours(row, column):
|
||||
if neighbour_cell.is_alive():
|
||||
alive_neighbours.append(neighbour_cell)
|
||||
|
||||
current_cell = self._grid[row][column]
|
||||
# Apply the Conway GoL rules (B3/S23)
|
||||
if current_cell.is_alive():
|
||||
if len(alive_neighbours) < 2 or len(alive_neighbours) > 3:
|
||||
to_dead.append(current_cell)
|
||||
if len(alive_neighbours) == 3 or len(alive_neighbours) == 2:
|
||||
to_alive.append(current_cell)
|
||||
else:
|
||||
if len(alive_neighbours) == 3:
|
||||
to_alive.append(current_cell)
|
||||
|
||||
for cell in to_alive:
|
||||
if not cell.is_alive():
|
||||
# The board has changed since the previous generation
|
||||
changed = True
|
||||
cell.make_alive()
|
||||
|
||||
for cell in to_dead:
|
||||
if cell.is_alive():
|
||||
# The board has changed since the previous generation
|
||||
changed = True
|
||||
cell.make_dead()
|
||||
|
||||
return changed
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Main program loop
|
||||
# ------------------------------
|
||||
|
||||
|
||||
def main():
|
||||
global restart
|
||||
|
||||
init_screen()
|
||||
board = Board()
|
||||
board.draw_board()
|
||||
time.sleep(0.5)
|
||||
|
||||
while True:
|
||||
# The 'a' button has been pressed so restart sim
|
||||
if restart:
|
||||
init_screen()
|
||||
restart = False
|
||||
board = Board()
|
||||
board.draw_board()
|
||||
time.sleep(0.5)
|
||||
# The board didn't update since the previous generation
|
||||
if not board.create_next_generation():
|
||||
screen.update_speed(badger2040.UPDATE_NORMAL)
|
||||
board.draw_board()
|
||||
screen.update_speed(badger2040.UPDATE_TURBO)
|
||||
time.sleep(5)
|
||||
restart = True
|
||||
# Draw the next generation
|
||||
else:
|
||||
board.draw_board()
|
||||
|
||||
|
||||
main()
|
276
badger2040/os/badger2040/ebook.py
Normal file
276
badger2040/os/badger2040/ebook.py
Normal file
@ -0,0 +1,276 @@
|
||||
import badger2040
|
||||
import machine
|
||||
import time
|
||||
import gc
|
||||
|
||||
|
||||
# **** Put the name of your text file here *****
|
||||
text_file = "book.txt" # File must be on the MicroPython device
|
||||
|
||||
|
||||
try:
|
||||
open(text_file, "r")
|
||||
except OSError:
|
||||
try:
|
||||
# If the specified file doesn't exist,
|
||||
# pre-populate with Wind In The Willows
|
||||
import witw
|
||||
open(text_file, "wb").write(witw.data())
|
||||
del witw
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
gc.collect()
|
||||
|
||||
# Global Constants
|
||||
WIDTH = badger2040.WIDTH
|
||||
HEIGHT = badger2040.HEIGHT
|
||||
|
||||
ARROW_THICKNESS = 3
|
||||
ARROW_WIDTH = 18
|
||||
ARROW_HEIGHT = 14
|
||||
ARROW_PADDING = 2
|
||||
|
||||
TEXT_PADDING = 4
|
||||
|
||||
TEXT_SIZE = 0.5
|
||||
TEXT_SPACING = int(34 * TEXT_SIZE)
|
||||
TEXT_WIDTH = WIDTH - TEXT_PADDING - TEXT_PADDING - ARROW_WIDTH
|
||||
|
||||
FONTS = ["sans", "gothic", "cursive", "serif"]
|
||||
FONT_THICKNESSES = [2, 1, 1, 2]
|
||||
# ------------------------------
|
||||
# Drawing functions
|
||||
# ------------------------------
|
||||
|
||||
|
||||
# Draw a upward arrow
|
||||
def draw_up(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 4) + padding
|
||||
display.line(x + border, y + height - border,
|
||||
x + (width // 2), y + border)
|
||||
display.line(x + (width // 2), y + border,
|
||||
x + width - border, y + height - border)
|
||||
|
||||
|
||||
# Draw a downward arrow
|
||||
def draw_down(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 2) + padding
|
||||
display.line(x + border, y + border,
|
||||
x + (width // 2), y + height - border)
|
||||
display.line(x + (width // 2), y + height - border,
|
||||
x + width - border, y + border)
|
||||
|
||||
|
||||
# Draw the frame of the reader
|
||||
def draw_frame():
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
display.pen(12)
|
||||
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
|
||||
display.pen(0)
|
||||
display.thickness(ARROW_THICKNESS)
|
||||
if current_page > 1:
|
||||
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
|
||||
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
|
||||
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Program setup
|
||||
# ------------------------------
|
||||
|
||||
# Global variables
|
||||
next_page = True
|
||||
prev_page = False
|
||||
change_font_size = False
|
||||
change_font = False
|
||||
last_offset = 0
|
||||
current_page = 0
|
||||
|
||||
# Create a new Badger and set it to update FAST
|
||||
display = badger2040.Badger2040()
|
||||
display.update_speed(badger2040.UPDATE_FAST)
|
||||
|
||||
# Set up the buttons
|
||||
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
# Set up the activity LED
|
||||
led = machine.Pin(badger2040.PIN_LED, machine.Pin.OUT)
|
||||
|
||||
offsets = []
|
||||
|
||||
|
||||
# Button handling function
|
||||
def button(pin):
|
||||
global next_page, prev_page, change_font_size, change_font
|
||||
|
||||
if pin == button_down:
|
||||
next_page = True
|
||||
|
||||
if pin == button_up:
|
||||
prev_page = True
|
||||
|
||||
if pin == button_a:
|
||||
change_font_size = True
|
||||
|
||||
if pin == button_b:
|
||||
change_font = True
|
||||
|
||||
|
||||
# Register the button handling function with the buttons
|
||||
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Render page
|
||||
# ------------------------------
|
||||
|
||||
def render_page():
|
||||
row = 0
|
||||
line = ""
|
||||
pos = ebook.tell()
|
||||
next_pos = pos
|
||||
add_newline = False
|
||||
display.font(FONTS[0])
|
||||
|
||||
while True:
|
||||
# Read a full line and split it into words
|
||||
words = ebook.readline().split(" ")
|
||||
|
||||
# Take the length of the first word and advance our position
|
||||
next_word = words[0]
|
||||
if len(words) > 1:
|
||||
next_pos += len(next_word) + 1
|
||||
else:
|
||||
next_pos += len(next_word) # This is the last word on the line
|
||||
|
||||
# Advance our position further if the word contains special characters
|
||||
if '\u201c' in next_word:
|
||||
next_word = next_word.replace('\u201c', '\"')
|
||||
next_pos += 2
|
||||
if '\u201d' in next_word:
|
||||
next_word = next_word.replace('\u201d', '\"')
|
||||
next_pos += 2
|
||||
if '\u2019' in next_word:
|
||||
next_word = next_word.replace('\u2019', '\'')
|
||||
next_pos += 2
|
||||
|
||||
# Rewind the file back from the line end to the start of the next word
|
||||
ebook.seek(next_pos)
|
||||
|
||||
# Strip out any new line characters from the word
|
||||
next_word = next_word.strip()
|
||||
|
||||
# If an empty word is encountered assume that means there was a blank line
|
||||
if len(next_word) == 0:
|
||||
add_newline = True
|
||||
|
||||
# Append the word to the current line and measure its length
|
||||
appended_line = line
|
||||
if len(line) > 0 and len(next_word) > 0:
|
||||
appended_line += " "
|
||||
appended_line += next_word
|
||||
appended_length = display.measure_text(appended_line, TEXT_SIZE)
|
||||
|
||||
# Would this appended line be longer than the text display area, or was a blank line spotted?
|
||||
if appended_length >= TEXT_WIDTH or add_newline:
|
||||
|
||||
# Yes, so write out the line prior to the append
|
||||
print(line)
|
||||
display.pen(0)
|
||||
display.thickness(FONT_THICKNESSES[0])
|
||||
display.text(line, TEXT_PADDING, (row * TEXT_SPACING) + (TEXT_SPACING // 2) + TEXT_PADDING, TEXT_SIZE)
|
||||
|
||||
# Clear the line and move on to the next row
|
||||
line = ""
|
||||
row += 1
|
||||
|
||||
# Have we reached the end of the page?
|
||||
if (row * TEXT_SPACING) + TEXT_SPACING >= HEIGHT:
|
||||
print("+++++")
|
||||
display.update()
|
||||
|
||||
# Reset the position to the start of the word that made this line too long
|
||||
ebook.seek(pos)
|
||||
return
|
||||
else:
|
||||
# Set the line to the word and advance the current position
|
||||
line = next_word
|
||||
pos = next_pos
|
||||
|
||||
# A new line was spotted, so advance a row
|
||||
if add_newline:
|
||||
print("")
|
||||
row += 1
|
||||
if (row * TEXT_SPACING) + TEXT_SPACING >= HEIGHT:
|
||||
print("+++++")
|
||||
display.update()
|
||||
return
|
||||
add_newline = False
|
||||
else:
|
||||
# The appended line was not too long, so set it as the line and advance the current position
|
||||
line = appended_line
|
||||
pos = next_pos
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Main program loop
|
||||
# ------------------------------
|
||||
|
||||
# Open the book file
|
||||
ebook = open(text_file, "r")
|
||||
|
||||
while True:
|
||||
# Was the next page button pressed?
|
||||
if next_page:
|
||||
current_page += 1
|
||||
|
||||
# Is the next page one we've not displayed before?
|
||||
if current_page > len(offsets):
|
||||
offsets.append(ebook.tell()) # Add its start position to the offsets list
|
||||
draw_frame()
|
||||
render_page()
|
||||
next_page = False # Clear the next page button flag
|
||||
|
||||
# Was the previous page button pressed?
|
||||
if prev_page:
|
||||
if current_page > 1:
|
||||
current_page -= 1
|
||||
ebook.seek(offsets[current_page - 1]) # Retrieve the start position of the last page
|
||||
draw_frame()
|
||||
render_page()
|
||||
prev_page = False # Clear the prev page button flag
|
||||
|
||||
if change_font_size:
|
||||
TEXT_SIZE += 0.1
|
||||
if TEXT_SIZE > 0.8:
|
||||
TEXT_SIZE = 0.5
|
||||
TEXT_SPACING = int(34 * TEXT_SIZE)
|
||||
offsets = [0]
|
||||
ebook.seek(0)
|
||||
current_page = 1
|
||||
draw_frame()
|
||||
render_page()
|
||||
change_font_size = False
|
||||
|
||||
if change_font:
|
||||
FONTS.append(FONTS.pop(0))
|
||||
FONT_THICKNESSES.append(FONT_THICKNESSES.pop(0))
|
||||
offsets = [0]
|
||||
ebook.seek(0)
|
||||
current_page = 1
|
||||
draw_frame()
|
||||
render_page()
|
||||
change_font = False
|
||||
|
||||
time.sleep(0.1)
|
141
badger2040/os/badger2040/fonts.py
Normal file
141
badger2040/os/badger2040/fonts.py
Normal file
@ -0,0 +1,141 @@
|
||||
import badger2040
|
||||
import machine
|
||||
import time
|
||||
|
||||
# Global Constants
|
||||
FONT_NAMES = ("sans", "gothic", "cursive", "serif", "serif_italic")
|
||||
|
||||
WIDTH = badger2040.WIDTH
|
||||
HEIGHT = badger2040.HEIGHT
|
||||
|
||||
MENU_TEXT_SIZE = 0.5
|
||||
MENU_SPACING = 20
|
||||
MENU_WIDTH = 84
|
||||
MENU_PADDING = 2
|
||||
|
||||
TEXT_SIZE = 0.8
|
||||
TEXT_INDENT = MENU_WIDTH + 10
|
||||
|
||||
ARROW_THICKNESS = 3
|
||||
ARROW_WIDTH = 18
|
||||
ARROW_HEIGHT = 14
|
||||
ARROW_PADDING = 2
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Drawing functions
|
||||
# ------------------------------
|
||||
|
||||
# Draw a upward arrow
|
||||
def draw_up(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 4) + padding
|
||||
display.line(x + border, y + height - border,
|
||||
x + (width // 2), y + border)
|
||||
display.line(x + (width // 2), y + border,
|
||||
x + width - border, y + height - border)
|
||||
|
||||
|
||||
# Draw a downward arrow
|
||||
def draw_down(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 2) + padding
|
||||
display.line(x + border, y + border,
|
||||
x + (width // 2), y + height - border)
|
||||
display.line(x + (width // 2), y + height - border,
|
||||
x + width - border, y + border)
|
||||
|
||||
|
||||
# Draw the frame of the reader
|
||||
def draw_frame():
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
display.pen(12)
|
||||
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
|
||||
display.pen(0)
|
||||
display.thickness(ARROW_THICKNESS)
|
||||
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
|
||||
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
|
||||
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
|
||||
|
||||
# Draw the fonts and menu
|
||||
def draw_fonts():
|
||||
display.font("sans")
|
||||
display.thickness(1)
|
||||
for i in range(len(FONT_NAMES)):
|
||||
name = FONT_NAMES[i]
|
||||
display.pen(0)
|
||||
if i == selected_font:
|
||||
display.rectangle(0, i * MENU_SPACING, MENU_WIDTH, MENU_SPACING)
|
||||
display.pen(15)
|
||||
|
||||
display.text(name, MENU_PADDING, (i * MENU_SPACING) + (MENU_SPACING // 2), MENU_TEXT_SIZE)
|
||||
|
||||
display.font(FONT_NAMES[selected_font])
|
||||
display.thickness(2)
|
||||
|
||||
display.pen(0)
|
||||
display.text("The quick", TEXT_INDENT, 10, TEXT_SIZE)
|
||||
display.text("brown fox", TEXT_INDENT, 32, TEXT_SIZE)
|
||||
display.text("jumped over", TEXT_INDENT, 54, TEXT_SIZE)
|
||||
display.text("the lazy dog.", TEXT_INDENT, 76, TEXT_SIZE)
|
||||
display.text("0123456789", TEXT_INDENT, 98, TEXT_SIZE)
|
||||
display.text("!\"£$%^&*()", TEXT_INDENT, 120, TEXT_SIZE)
|
||||
display.thickness(1)
|
||||
|
||||
display.update()
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Program setup
|
||||
# ------------------------------
|
||||
|
||||
# Global variables
|
||||
selected_font = 0
|
||||
pressed = False
|
||||
|
||||
# Create a new Badger and set it to update FAST
|
||||
display = badger2040.Badger2040()
|
||||
display.update_speed(badger2040.UPDATE_FAST)
|
||||
|
||||
# Set up the buttons
|
||||
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
|
||||
# Button handling function
|
||||
def button(pin):
|
||||
global pressed
|
||||
global selected_font
|
||||
|
||||
if not pressed:
|
||||
if pin == button_up:
|
||||
selected_font -= 1
|
||||
if selected_font < 0:
|
||||
selected_font = len(FONT_NAMES) - 1
|
||||
pressed = True
|
||||
return
|
||||
if pin == button_down:
|
||||
selected_font += 1
|
||||
if selected_font >= len(FONT_NAMES):
|
||||
selected_font = 0
|
||||
pressed = True
|
||||
return
|
||||
|
||||
|
||||
# Register the button handling function with the buttons
|
||||
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Main program loop
|
||||
# ------------------------------
|
||||
|
||||
while True:
|
||||
draw_frame()
|
||||
draw_fonts()
|
||||
|
||||
pressed = False
|
||||
while not pressed:
|
||||
time.sleep(0.1)
|
40
badger2040/os/badger2040/help.py
Normal file
40
badger2040/os/badger2040/help.py
Normal file
@ -0,0 +1,40 @@
|
||||
import badger2040
|
||||
import time
|
||||
from badger2040 import WIDTH
|
||||
|
||||
TEXT_SIZE = 0.45
|
||||
LINE_HEIGHT = 16
|
||||
|
||||
display = badger2040.Badger2040()
|
||||
display.pen(0)
|
||||
display.rectangle(0, 0, WIDTH, 16)
|
||||
display.thickness(1)
|
||||
display.pen(15)
|
||||
display.text("badgerOS", 3, 8, 0.4)
|
||||
|
||||
display.pen(0)
|
||||
|
||||
y = 16 + int(LINE_HEIGHT / 2)
|
||||
|
||||
display.thickness(2)
|
||||
display.text("Normal:", 0, y, TEXT_SIZE)
|
||||
display.thickness(1)
|
||||
y += LINE_HEIGHT
|
||||
display.text("Up / Down - Change launcher page", 0, y, TEXT_SIZE)
|
||||
y += LINE_HEIGHT
|
||||
display.text("a, b or c - Launch app", 0, y, TEXT_SIZE)
|
||||
y += LINE_HEIGHT
|
||||
y += LINE_HEIGHT
|
||||
|
||||
display.thickness(2)
|
||||
display.text("Holding USER button:", 0, y, TEXT_SIZE)
|
||||
display.thickness(1)
|
||||
y += LINE_HEIGHT
|
||||
display.text("Up / Down - Change font size", 0, y, TEXT_SIZE)
|
||||
y += LINE_HEIGHT
|
||||
display.text("a - Toggle invert", 0, y, TEXT_SIZE)
|
||||
y += LINE_HEIGHT
|
||||
|
||||
display.update()
|
||||
while True:
|
||||
time.sleep(1)
|
154
badger2040/os/badger2040/image.py
Normal file
154
badger2040/os/badger2040/image.py
Normal file
@ -0,0 +1,154 @@
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import machine
|
||||
import badger2040
|
||||
from badger2040 import WIDTH, HEIGHT
|
||||
|
||||
|
||||
REAMDE = """
|
||||
Images must be 296x128 pixel with 1bit colour depth.
|
||||
|
||||
You can use examples/badger2040/image_converter/convert.py to convert them:
|
||||
|
||||
python3 convert.py --binary --resize image_file_1.png image_file_2.png image_file_3.png
|
||||
|
||||
Create a new "images" directory via Thonny, and upload the .bin files there.
|
||||
"""
|
||||
|
||||
OVERLAY_BORDER = 40
|
||||
OVERLAY_SPACING = 20
|
||||
OVERLAY_TEXT_SIZE = 0.5
|
||||
|
||||
TOTAL_IMAGES = 0
|
||||
|
||||
# Try to preload BadgerPunk image
|
||||
try:
|
||||
os.mkdir("images")
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import badgerpunk
|
||||
with open("images/badgerpunk.bin", "wb") as f:
|
||||
f.write(badgerpunk.data())
|
||||
f.flush()
|
||||
with open("images/readme.txt", "w") as f:
|
||||
f.write(REAMDE)
|
||||
f.flush()
|
||||
del badgerpunk
|
||||
except (OSError, ImportError):
|
||||
pass
|
||||
|
||||
try:
|
||||
IMAGES = [f for f in os.listdir("/images") if f.endswith(".bin")]
|
||||
TOTAL_IMAGES = len(IMAGES)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
display = badger2040.Badger2040()
|
||||
|
||||
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
image = bytearray(int(296 * 128 / 8))
|
||||
current_image = 0
|
||||
show_info = True
|
||||
|
||||
|
||||
# Draw an overlay box with a given message within it
|
||||
def draw_overlay(message, width, height, line_spacing, text_size):
|
||||
|
||||
# Draw a light grey background
|
||||
display.pen(12)
|
||||
display.rectangle((WIDTH - width) // 2, (HEIGHT - height) // 2, width, height)
|
||||
|
||||
# Take the provided message and split it up into
|
||||
# lines that fit within the specified width
|
||||
words = message.split(" ")
|
||||
|
||||
lines = []
|
||||
current_line = ""
|
||||
for word in words:
|
||||
if display.measure_text(current_line + word + " ", text_size) < width:
|
||||
current_line += word + " "
|
||||
else:
|
||||
lines.append(current_line.strip())
|
||||
current_line = word + " "
|
||||
lines.append(current_line.strip())
|
||||
|
||||
display.pen(0)
|
||||
display.thickness(2)
|
||||
|
||||
# Display each line of text from the message, centre-aligned
|
||||
num_lines = len(lines)
|
||||
for i in range(num_lines):
|
||||
length = display.measure_text(lines[i], text_size)
|
||||
current_line = (i * line_spacing) - ((num_lines - 1) * line_spacing) // 2
|
||||
display.text(lines[i], (WIDTH - length) // 2, (HEIGHT // 2) + current_line, text_size)
|
||||
|
||||
|
||||
def show_image(n):
|
||||
file = IMAGES[n]
|
||||
name = file.split(".")[0]
|
||||
open("images/{}".format(file), "r").readinto(image)
|
||||
display.image(image)
|
||||
|
||||
if show_info:
|
||||
name_length = display.measure_text(name, 0.5)
|
||||
display.pen(0)
|
||||
display.rectangle(0, HEIGHT - 21, name_length + 11, 21)
|
||||
display.pen(15)
|
||||
display.rectangle(0, HEIGHT - 20, name_length + 10, 20)
|
||||
display.pen(0)
|
||||
display.text(name, 5, HEIGHT - 10, 0.5)
|
||||
|
||||
for i in range(TOTAL_IMAGES):
|
||||
x = 286
|
||||
y = int((128 / 2) - (TOTAL_IMAGES * 10 / 2) + (i * 10))
|
||||
display.pen(0)
|
||||
display.rectangle(x, y, 8, 8)
|
||||
if current_image != i:
|
||||
display.pen(15)
|
||||
display.rectangle(x + 1, y + 1, 6, 6)
|
||||
|
||||
display.update()
|
||||
|
||||
|
||||
if TOTAL_IMAGES == 0:
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
draw_overlay("To run this demo, create an /images directory on your device and upload some 1bit 296x128 pixel images.", WIDTH - OVERLAY_BORDER, HEIGHT - OVERLAY_BORDER, OVERLAY_SPACING, OVERLAY_TEXT_SIZE)
|
||||
display.update()
|
||||
sys.exit()
|
||||
|
||||
|
||||
show_image(current_image)
|
||||
|
||||
|
||||
while True:
|
||||
if button_up.value():
|
||||
if current_image > 0:
|
||||
current_image -= 1
|
||||
show_image(current_image)
|
||||
if button_down.value():
|
||||
if current_image < TOTAL_IMAGES - 1:
|
||||
current_image += 1
|
||||
show_image(current_image)
|
||||
if button_a.value():
|
||||
show_info = not show_info
|
||||
show_image(current_image)
|
||||
if button_b.value() or button_c.value():
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
draw_overlay("To add images connect Badger2040 to a PC, load up Thonny, and see readme.txt in images/", WIDTH - OVERLAY_BORDER, HEIGHT - OVERLAY_BORDER, OVERLAY_SPACING, 0.5)
|
||||
display.update()
|
||||
time.sleep(4)
|
||||
show_image(current_image)
|
||||
|
||||
time.sleep(0.01)
|
38
badger2040/os/badger2040/info.py
Normal file
38
badger2040/os/badger2040/info.py
Normal file
@ -0,0 +1,38 @@
|
||||
import badger2040
|
||||
import time
|
||||
from badger2040 import WIDTH
|
||||
|
||||
TEXT_SIZE = 0.45
|
||||
LINE_HEIGHT = 16
|
||||
|
||||
display = badger2040.Badger2040()
|
||||
display.pen(0)
|
||||
display.rectangle(0, 0, WIDTH, 16)
|
||||
display.thickness(1)
|
||||
display.pen(15)
|
||||
display.text("badgerOS", 3, 8, 0.4)
|
||||
|
||||
display.pen(0)
|
||||
|
||||
y = 16 + int(LINE_HEIGHT / 2)
|
||||
|
||||
display.text("Made by Pimoroni, powered by MicroPython", 0, y, TEXT_SIZE)
|
||||
y += LINE_HEIGHT
|
||||
display.text("Dual-core RP2040, 133MHz, 264KB RAM", 0, y, TEXT_SIZE)
|
||||
y += LINE_HEIGHT
|
||||
display.text("2MB Flash (1MB OS, 1MB Storage)", 0, y, TEXT_SIZE)
|
||||
y += LINE_HEIGHT
|
||||
display.text("296x128 pixel Black/White e-Ink", 0, y, TEXT_SIZE)
|
||||
y += LINE_HEIGHT
|
||||
y += LINE_HEIGHT
|
||||
|
||||
display.thickness(2)
|
||||
display.text("For more info:", 0, y, TEXT_SIZE)
|
||||
display.thickness(1)
|
||||
y += LINE_HEIGHT
|
||||
display.text("https://pimoroni.com/badger2040", 0, y, TEXT_SIZE)
|
||||
|
||||
display.update()
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
260
badger2040/os/badger2040/launcher.py
Normal file
260
badger2040/os/badger2040/launcher.py
Normal file
@ -0,0 +1,260 @@
|
||||
import gc
|
||||
import os
|
||||
import time
|
||||
import math
|
||||
import machine
|
||||
import badger2040
|
||||
from badger2040 import WIDTH
|
||||
import launchericons
|
||||
|
||||
# for e.g. 2xAAA batteries, try max 3.4 min 3.0
|
||||
MAX_BATTERY_VOLTAGE = 4.0
|
||||
MIN_BATTERY_VOLTAGE = 3.2
|
||||
|
||||
|
||||
page = 0
|
||||
font_size = 1
|
||||
inverted = False
|
||||
|
||||
icons = bytearray(launchericons.data())
|
||||
icons_width = 576
|
||||
|
||||
examples = [
|
||||
("_clock", 0),
|
||||
("_fonts", 1),
|
||||
("_ebook", 2),
|
||||
("_image", 3),
|
||||
("_list", 4),
|
||||
("_badge", 5),
|
||||
("_qrgen", 8),
|
||||
("_info", 6),
|
||||
("_help", 7),
|
||||
]
|
||||
|
||||
font_sizes = (0.5, 0.7, 0.9)
|
||||
|
||||
# Approximate center lines for buttons A, B and C
|
||||
centers = (41, 147, 253)
|
||||
|
||||
MAX_PAGE = math.ceil(len(examples) / 3)
|
||||
|
||||
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
# Inverted. For reasons.
|
||||
button_user = machine.Pin(badger2040.BUTTON_USER, machine.Pin.IN, machine.Pin.PULL_UP)
|
||||
|
||||
# Battery measurement
|
||||
vbat_adc = machine.ADC(badger2040.PIN_BATTERY)
|
||||
vref_adc = machine.ADC(badger2040.PIN_1V2_REF)
|
||||
vref_en = machine.Pin(badger2040.PIN_VREF_POWER)
|
||||
vref_en.init(machine.Pin.OUT)
|
||||
vref_en.value(0)
|
||||
|
||||
|
||||
display = badger2040.Badger2040()
|
||||
|
||||
|
||||
def map_value(input, in_min, in_max, out_min, out_max):
|
||||
return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min
|
||||
|
||||
|
||||
def get_battery_level():
|
||||
# Enable the onboard voltage reference
|
||||
vref_en.value(1)
|
||||
|
||||
# Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries
|
||||
vdd = 1.24 * (65535 / vref_adc.read_u16())
|
||||
vbat = (
|
||||
(vbat_adc.read_u16() / 65535) * 3 * vdd
|
||||
) # 3 in this is a gain, not rounding of 3.3V
|
||||
|
||||
# Disable the onboard voltage reference
|
||||
vref_en.value(0)
|
||||
|
||||
# Convert the voltage to a level to display onscreen
|
||||
return int(map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, 4))
|
||||
|
||||
|
||||
def draw_battery(level, x, y):
|
||||
# Outline
|
||||
display.thickness(1)
|
||||
display.pen(15)
|
||||
display.rectangle(x, y, 19, 10)
|
||||
# Terminal
|
||||
display.rectangle(x + 19, y + 3, 2, 4)
|
||||
display.pen(0)
|
||||
display.rectangle(x + 1, y + 1, 17, 8)
|
||||
if level < 1:
|
||||
display.pen(0)
|
||||
display.line(x + 3, y, x + 3 + 10, y + 10)
|
||||
display.line(x + 3 + 1, y, x + 3 + 11, y + 10)
|
||||
display.pen(15)
|
||||
display.line(x + 2 + 2, y - 1, x + 4 + 12, y + 11)
|
||||
display.line(x + 2 + 3, y - 1, x + 4 + 13, y + 11)
|
||||
return
|
||||
# Battery Bars
|
||||
display.pen(15)
|
||||
for i in range(4):
|
||||
if level / 4 > (1.0 * i) / 4:
|
||||
display.rectangle(i * 4 + x + 2, y + 2, 3, 6)
|
||||
|
||||
|
||||
def draw_disk_usage(x):
|
||||
# f_bfree and f_bavail should be the same?
|
||||
# f_files, f_ffree, f_favail and f_flag are unsupported.
|
||||
f_bsize, f_frsize, f_blocks, f_bfree, _, _, _, _, _, f_namemax = os.statvfs(
|
||||
"/")
|
||||
|
||||
f_total_size = f_frsize * f_blocks
|
||||
f_total_free = f_bsize * f_bfree
|
||||
f_total_used = f_total_size - f_total_free
|
||||
|
||||
f_used = 100 / f_total_size * f_total_used
|
||||
# f_free = 100 / f_total_size * f_total_free
|
||||
|
||||
display.image(
|
||||
bytearray(
|
||||
(
|
||||
0b00000000,
|
||||
0b00111100,
|
||||
0b00111100,
|
||||
0b00111100,
|
||||
0b00111000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000001,
|
||||
)
|
||||
),
|
||||
8,
|
||||
8,
|
||||
x,
|
||||
4,
|
||||
)
|
||||
display.pen(15)
|
||||
display.rectangle(x + 10, 3, 80, 10)
|
||||
display.pen(0)
|
||||
display.rectangle(x + 11, 4, 78, 8)
|
||||
display.pen(15)
|
||||
display.rectangle(x + 12, 5, int(76 / 100.0 * f_used), 6)
|
||||
display.text("{:.2f}%".format(f_used), x + 91, 8, 0.4)
|
||||
|
||||
|
||||
def render():
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
display.pen(0)
|
||||
display.thickness(2)
|
||||
|
||||
max_icons = min(3, len(examples[(page * 3):]))
|
||||
|
||||
for i in range(max_icons):
|
||||
x = centers[i]
|
||||
label, icon = examples[i + (page * 3)]
|
||||
label = label[1:].replace("_", " ")
|
||||
display.pen(0)
|
||||
display.icon(icons, icon, icons_width, 64, x - 32, 24)
|
||||
w = display.measure_text(label, font_sizes[font_size])
|
||||
display.text(label, x - int(w / 2), 16 + 80, font_sizes[font_size])
|
||||
|
||||
for i in range(MAX_PAGE):
|
||||
x = 286
|
||||
y = int((128 / 2) - (MAX_PAGE * 10 / 2) + (i * 10))
|
||||
display.pen(0)
|
||||
display.rectangle(x, y, 8, 8)
|
||||
if page != i:
|
||||
display.pen(15)
|
||||
display.rectangle(x + 1, y + 1, 6, 6)
|
||||
|
||||
display.pen(0)
|
||||
display.rectangle(0, 0, WIDTH, 16)
|
||||
display.thickness(1)
|
||||
draw_disk_usage(90)
|
||||
draw_battery(get_battery_level(), WIDTH - 22 - 3, 3)
|
||||
display.pen(15)
|
||||
display.text("badgerOS", 3, 8, 0.4)
|
||||
|
||||
display.update()
|
||||
|
||||
|
||||
def launch(file):
|
||||
for k in locals().keys():
|
||||
if k not in ("gc", "file", "machine"):
|
||||
del locals()[k]
|
||||
gc.collect()
|
||||
try:
|
||||
__import__(file[1:]) # Try to import _[file] (drop underscore prefix)
|
||||
except ImportError:
|
||||
__import__(file) # Failover to importing [_file]
|
||||
machine.reset() # Exit back to launcher
|
||||
|
||||
|
||||
def launch_example(index):
|
||||
try:
|
||||
launch(examples[(page * 3) + index][0])
|
||||
return True
|
||||
except IndexError:
|
||||
return False
|
||||
|
||||
|
||||
def button(pin):
|
||||
global page, font_size, inverted
|
||||
|
||||
if button_user.value(): # User button is NOT held down
|
||||
if pin == button_a:
|
||||
launch_example(0)
|
||||
if pin == button_b:
|
||||
launch_example(1)
|
||||
if pin == button_c:
|
||||
launch_example(2)
|
||||
if pin == button_up:
|
||||
if page > 0:
|
||||
page -= 1
|
||||
render()
|
||||
if pin == button_down:
|
||||
if page < MAX_PAGE - 1:
|
||||
page += 1
|
||||
render()
|
||||
else: # User button IS held down
|
||||
if pin == button_up:
|
||||
font_size += 1
|
||||
if font_size == len(font_sizes):
|
||||
font_size = 0
|
||||
render()
|
||||
if pin == button_down:
|
||||
font_size -= 1
|
||||
if font_size < 0:
|
||||
font_size = 0
|
||||
render()
|
||||
if pin == button_a:
|
||||
inverted = not inverted
|
||||
display.invert(inverted)
|
||||
render()
|
||||
|
||||
|
||||
display.update_speed(badger2040.UPDATE_MEDIUM)
|
||||
render()
|
||||
display.update_speed(badger2040.UPDATE_FAST)
|
||||
|
||||
|
||||
# Wait for wakeup button to be released
|
||||
while button_a.value() or button_b.value() or button_c.value() or button_up.value() or button_down.value():
|
||||
pass
|
||||
|
||||
|
||||
while True:
|
||||
if button_a.value():
|
||||
button(button_a)
|
||||
if button_b.value():
|
||||
button(button_b)
|
||||
if button_c.value():
|
||||
button(button_c)
|
||||
|
||||
if button_up.value():
|
||||
button(button_up)
|
||||
if button_down.value():
|
||||
button(button_down)
|
||||
|
||||
time.sleep(0.01)
|
12
badger2040/os/badger2040/led.py
Normal file
12
badger2040/os/badger2040/led.py
Normal file
@ -0,0 +1,12 @@
|
||||
# Blinky badger fun!
|
||||
|
||||
import badger2040
|
||||
import time
|
||||
|
||||
badger = badger2040.Badger2040()
|
||||
|
||||
while True:
|
||||
badger.led(255)
|
||||
time.sleep(1)
|
||||
badger.led(0)
|
||||
time.sleep(1)
|
311
badger2040/os/badger2040/list.py
Normal file
311
badger2040/os/badger2040/list.py
Normal file
@ -0,0 +1,311 @@
|
||||
import badger2040
|
||||
import machine
|
||||
import time
|
||||
|
||||
# **** Put your list title and contents here *****
|
||||
list_title = "Checklist"
|
||||
list_content = ["Badger", "Badger", "Badger", "Badger", "Badger", "Mushroom", "Mushroom", "Snake"]
|
||||
list_states = [False] * len(list_content)
|
||||
list_file = "checklist.txt"
|
||||
|
||||
|
||||
# Global Constants
|
||||
WIDTH = badger2040.WIDTH
|
||||
HEIGHT = badger2040.HEIGHT
|
||||
|
||||
ARROW_THICKNESS = 3
|
||||
ARROW_WIDTH = 18
|
||||
ARROW_HEIGHT = 14
|
||||
ARROW_PADDING = 2
|
||||
|
||||
MAX_ITEM_CHARS = 26
|
||||
TITLE_TEXT_SIZE = 0.7
|
||||
ITEM_TEXT_SIZE = 0.6
|
||||
ITEM_SPACING = 20
|
||||
|
||||
LIST_START = 40
|
||||
LIST_PADDING = 2
|
||||
LIST_WIDTH = WIDTH - LIST_PADDING - LIST_PADDING - ARROW_WIDTH
|
||||
LIST_HEIGHT = HEIGHT - LIST_START - LIST_PADDING - ARROW_HEIGHT
|
||||
|
||||
|
||||
def save_list():
|
||||
with open(list_file, "w") as f:
|
||||
f.write(list_title + "\n")
|
||||
for i in range(len(list_content)):
|
||||
list_item = list_content[i]
|
||||
if list_states[i]:
|
||||
list_item += " X"
|
||||
f.write(list_item + "\n")
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Drawing functions
|
||||
# ------------------------------
|
||||
|
||||
# Draw the list of items
|
||||
def draw_list(items, item_states, start_item, highlighted_item, x, y, width, height, item_height, columns):
|
||||
item_x = 0
|
||||
item_y = 0
|
||||
current_col = 0
|
||||
for i in range(start_item, len(items)):
|
||||
if i == highlighted_item:
|
||||
display.pen(12)
|
||||
display.rectangle(item_x, item_y + y - (item_height // 2), width // columns, item_height)
|
||||
display.pen(0)
|
||||
display.text(items[i], item_x + x + item_height, item_y + y, ITEM_TEXT_SIZE)
|
||||
draw_checkbox(item_x, item_y + y - (item_height // 2), item_height, 15, 0, 2, item_states[i], 2)
|
||||
item_y += item_height
|
||||
if item_y >= height - (item_height // 2):
|
||||
item_x += width // columns
|
||||
item_y = 0
|
||||
current_col += 1
|
||||
if current_col >= columns:
|
||||
return
|
||||
|
||||
|
||||
# Draw a upward arrow
|
||||
def draw_up(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 4) + padding
|
||||
display.line(x + border, y + height - border,
|
||||
x + (width // 2), y + border)
|
||||
display.line(x + (width // 2), y + border,
|
||||
x + width - border, y + height - border)
|
||||
|
||||
|
||||
# Draw a downward arrow
|
||||
def draw_down(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 2) + padding
|
||||
display.line(x + border, y + border,
|
||||
x + (width // 2), y + height - border)
|
||||
display.line(x + (width // 2), y + height - border,
|
||||
x + width - border, y + border)
|
||||
|
||||
|
||||
# Draw a left arrow
|
||||
def draw_left(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 2) + padding
|
||||
display.line(x + width - border, y + border,
|
||||
x + border, y + (height // 2))
|
||||
display.line(x + border, y + (height // 2),
|
||||
x + width - border, y + height - border)
|
||||
|
||||
|
||||
# Draw a right arrow
|
||||
def draw_right(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 2) + padding
|
||||
display.line(x + border, y + border,
|
||||
x + width - border, y + (height // 2))
|
||||
display.line(x + width - border, y + (height // 2),
|
||||
x + border, y + height - border)
|
||||
|
||||
|
||||
# Draw a tick
|
||||
def draw_tick(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 2) + padding
|
||||
display.line(x + border, y + ((height * 2) // 3),
|
||||
x + (width // 2), y + height - border)
|
||||
display.line(x + (width // 2), y + height - border,
|
||||
x + width - border, y + border)
|
||||
|
||||
|
||||
# Draw a cross
|
||||
def draw_cross(x, y, width, height, thickness, padding):
|
||||
border = (thickness // 2) + padding
|
||||
display.line(x + border, y + border, x + width - border, y + height - border)
|
||||
display.line(x + width - border, y + border, x + border, y + height - border)
|
||||
|
||||
|
||||
# Draw a checkbox with or without a tick
|
||||
def draw_checkbox(x, y, size, background, foreground, thickness, tick, padding):
|
||||
border = (thickness // 2) + padding
|
||||
display.pen(background)
|
||||
display.rectangle(x + border, y + border, size - (border * 2), size - (border * 2))
|
||||
display.pen(foreground)
|
||||
display.thickness(thickness)
|
||||
display.line(x + border, y + border, x + size - border, y + border)
|
||||
display.line(x + border, y + border, x + border, y + size - border)
|
||||
display.line(x + size - border, y + border, x + size - border, y + size - border)
|
||||
display.line(x + border, y + size - border, x + size - border, y + size - border)
|
||||
if tick:
|
||||
draw_tick(x, y, size, size, thickness, 2 + border)
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Program setup
|
||||
# ------------------------------
|
||||
|
||||
# Global variables
|
||||
update = True
|
||||
needs_save = False
|
||||
current_item = 0
|
||||
items_per_page = 0
|
||||
|
||||
# Create a new Badger and set it to update FAST
|
||||
display = badger2040.Badger2040()
|
||||
display.update_speed(badger2040.UPDATE_FAST)
|
||||
|
||||
# Set up the buttons
|
||||
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
# Find out what the longest item is
|
||||
longest_item = 0
|
||||
for i in range(len(list_content)):
|
||||
while True:
|
||||
item = list_content[i]
|
||||
item_length = display.measure_text(item, ITEM_TEXT_SIZE)
|
||||
if item_length > 0 and item_length > LIST_WIDTH - ITEM_SPACING:
|
||||
list_content[i] = item[:-1]
|
||||
else:
|
||||
break
|
||||
longest_item = max(longest_item, display.measure_text(list_content[i], ITEM_TEXT_SIZE))
|
||||
|
||||
|
||||
# And use that to calculate the number of columns we can fit onscreen and how many items that would give
|
||||
list_columns = 1
|
||||
while longest_item + ITEM_SPACING < (LIST_WIDTH // (list_columns + 1)):
|
||||
list_columns += 1
|
||||
|
||||
items_per_page = ((LIST_HEIGHT // ITEM_SPACING) + 1) * list_columns
|
||||
|
||||
|
||||
# Button handling function
|
||||
def button(pin):
|
||||
global update, current_item, needs_save
|
||||
|
||||
if len(list_content) > 0 and not update:
|
||||
if pin == button_a:
|
||||
if current_item > 0:
|
||||
current_item = max(current_item - (items_per_page) // list_columns, 0)
|
||||
update = True
|
||||
return
|
||||
if pin == button_b:
|
||||
list_states[current_item] = not list_states[current_item]
|
||||
needs_save = True
|
||||
update = True
|
||||
return
|
||||
if pin == button_c:
|
||||
if current_item < len(list_content) - 1:
|
||||
current_item = min(current_item + (items_per_page) // list_columns, len(list_content) - 1)
|
||||
update = True
|
||||
return
|
||||
if pin == button_up:
|
||||
if current_item > 0:
|
||||
current_item -= 1
|
||||
update = True
|
||||
return
|
||||
if pin == button_down:
|
||||
if current_item < len(list_content) - 1:
|
||||
current_item += 1
|
||||
update = True
|
||||
return
|
||||
|
||||
|
||||
# Register the button handling function with the buttons
|
||||
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
|
||||
|
||||
# ------------------------------
|
||||
# Main program loop
|
||||
# ------------------------------
|
||||
|
||||
try:
|
||||
with open(list_file, "r") as f:
|
||||
list_content = f.read().strip().split("\n")
|
||||
list_title = list_content.pop(0)
|
||||
list_states = [False] * len(list_content)
|
||||
for i in range(len(list_content)):
|
||||
list_content[i] = list_content[i].strip()
|
||||
if list_content[i].endswith(" X"):
|
||||
list_states[i] = True
|
||||
list_content[i] = list_content[i][:-2]
|
||||
|
||||
except OSError:
|
||||
save_list()
|
||||
|
||||
|
||||
while True:
|
||||
if needs_save:
|
||||
save_list()
|
||||
needs_save = False
|
||||
|
||||
if update:
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
|
||||
display.pen(12)
|
||||
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
|
||||
display.rectangle(0, HEIGHT - ARROW_HEIGHT, WIDTH, ARROW_HEIGHT)
|
||||
|
||||
y = LIST_PADDING + 12
|
||||
display.pen(0)
|
||||
display.thickness(3)
|
||||
display.text(list_title, LIST_PADDING, y, TITLE_TEXT_SIZE)
|
||||
|
||||
y += 12
|
||||
display.pen(0)
|
||||
display.thickness(2)
|
||||
display.line(LIST_PADDING, y, WIDTH - LIST_PADDING - ARROW_WIDTH, y)
|
||||
|
||||
if len(list_content) > 0:
|
||||
page_item = 0
|
||||
if items_per_page > 0:
|
||||
page_item = (current_item // items_per_page) * items_per_page
|
||||
|
||||
# Draw the list
|
||||
display.pen(0)
|
||||
display.thickness(2)
|
||||
draw_list(list_content, list_states, page_item, current_item, LIST_PADDING, LIST_START,
|
||||
LIST_WIDTH, LIST_HEIGHT, ITEM_SPACING, list_columns)
|
||||
|
||||
# Draw the interaction button icons
|
||||
display.pen(0)
|
||||
display.thickness(ARROW_THICKNESS)
|
||||
|
||||
# Previous item
|
||||
if current_item > 0:
|
||||
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
|
||||
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
|
||||
# Next item
|
||||
if current_item < (len(list_content) - 1):
|
||||
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
|
||||
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
|
||||
# Previous column
|
||||
if current_item > 0:
|
||||
draw_left((WIDTH // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
|
||||
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
|
||||
# Next column
|
||||
if current_item < (len(list_content) - 1):
|
||||
draw_right(((WIDTH * 6) // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
|
||||
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
|
||||
if list_states[current_item]:
|
||||
# Tick off item
|
||||
draw_cross((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
|
||||
ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
else:
|
||||
# Untick item
|
||||
draw_tick((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
|
||||
ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
|
||||
else:
|
||||
# Say that the list is empty
|
||||
empty_text = "Nothing Here"
|
||||
text_length = display.measure_text(empty_text, ITEM_TEXT_SIZE)
|
||||
display.text(empty_text, ((LIST_PADDING + LIST_WIDTH) - text_length) // 2, (LIST_HEIGHT // 2) + LIST_START - (ITEM_SPACING // 4), ITEM_TEXT_SIZE)
|
||||
|
||||
display.update()
|
||||
display.update_speed(badger2040.UPDATE_TURBO)
|
||||
update = False
|
||||
|
||||
time.sleep(0.1)
|
54
badger2040/os/badger2040/micropython-builtins.cmake
Normal file
54
badger2040/os/badger2040/micropython-builtins.cmake
Normal file
@ -0,0 +1,54 @@
|
||||
function (convert_image TARGET IMAGE)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../modules/${IMAGE}.py
|
||||
|
||||
COMMAND
|
||||
cd ${CMAKE_CURRENT_LIST_DIR}/assets && python3 ../../../../examples/badger2040/image_converter/convert.py --out_dir ${CMAKE_CURRENT_BINARY_DIR}/../modules --py ${IMAGE}.png
|
||||
|
||||
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/assets/${IMAGE}.png
|
||||
)
|
||||
target_sources(${TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/../modules/${IMAGE}.py)
|
||||
endfunction()
|
||||
|
||||
function (convert_raw TARGET SRC DST)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py
|
||||
|
||||
COMMAND
|
||||
cd ${CMAKE_CURRENT_LIST_DIR}/assets && python3 ../../../../examples/badger2040/image_converter/data_to_py.py ${CMAKE_CURRENT_LIST_DIR}/assets/${SRC} ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py
|
||||
|
||||
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/assets/${SRC}
|
||||
)
|
||||
target_sources(${TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py)
|
||||
endfunction()
|
||||
|
||||
function (copy_module TARGET SRC DST)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py
|
||||
|
||||
COMMAND
|
||||
cp ${SRC} ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py
|
||||
|
||||
DEPENDS ${src}
|
||||
)
|
||||
|
||||
target_sources(${TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py)
|
||||
endfunction()
|
||||
|
||||
convert_image(usermod_badger2040 badge_image)
|
||||
convert_image(usermod_badger2040 badgerpunk)
|
||||
convert_image(usermod_badger2040 launchericons)
|
||||
|
||||
convert_raw(usermod_badger2040 289-0-wind-in-the-willows-abridged.txt witw)
|
||||
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/assets/boot.py boot)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/launcher.py _launcher)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/clock.py _clock)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/fonts.py _fonts)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/ebook.py _ebook)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/image.py _image)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/list.py _list)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/badge.py _badge)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/help.py _help)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/info.py _info)
|
||||
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/qrgen.py _qrgen)
|
65
badger2040/os/badger2040/pin_interrupt.py
Normal file
65
badger2040/os/badger2040/pin_interrupt.py
Normal file
@ -0,0 +1,65 @@
|
||||
import badger2040
|
||||
import machine
|
||||
|
||||
display = badger2040.Badger2040()
|
||||
|
||||
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN)
|
||||
|
||||
display.thickness(10)
|
||||
display.pen(0)
|
||||
display.line(0, 5, 295, 5)
|
||||
display.line(0, 123, 295, 123)
|
||||
|
||||
display.thickness(1)
|
||||
for x in range(14):
|
||||
display.line(x * 20, 10, x * 20, 118)
|
||||
|
||||
display.line(0, 0, 295, 127)
|
||||
display.line(0, 127, 295, 0)
|
||||
|
||||
display.font("sans")
|
||||
display.thickness(5)
|
||||
display.text("Hello World", 10, 30, 1.0)
|
||||
display.pen(7)
|
||||
display.text("Hello World", 10, 60, 1.0)
|
||||
display.pen(11)
|
||||
display.text("Hello World", 10, 90, 1.0)
|
||||
|
||||
display.update()
|
||||
|
||||
dirty = False
|
||||
pressed = None
|
||||
|
||||
|
||||
def button(pin):
|
||||
global dirty, pressed
|
||||
if pin == button_a:
|
||||
pressed = "Button A"
|
||||
dirty = True
|
||||
return
|
||||
if pin == button_b:
|
||||
pressed = "Button B"
|
||||
dirty = True
|
||||
return
|
||||
|
||||
|
||||
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
|
||||
|
||||
# This breaks Thonny, since it's no longer possible to Stop the code
|
||||
# need to press the reset button on the board...
|
||||
# It will also crash your USB bus, probably, your whole bus...
|
||||
# @micropython.asm_thumb
|
||||
# def lightsleep():
|
||||
# wfi()
|
||||
|
||||
while True:
|
||||
if dirty:
|
||||
display.pen(15)
|
||||
display.clear()
|
||||
display.pen(0)
|
||||
display.text(pressed, 10, 60, 2.0)
|
||||
display.update()
|
||||
dirty = False
|
||||
# machine.lightsleep() # Currently imposible to wake from this on IRQ
|
70
badger2040/os/badger2040/qrgen.py
Normal file
70
badger2040/os/badger2040/qrgen.py
Normal file
@ -0,0 +1,70 @@
|
||||
import badger2040
|
||||
import qrcode
|
||||
import time
|
||||
|
||||
|
||||
# Open the qrcode file
|
||||
try:
|
||||
text = open("qrcode.txt", "r")
|
||||
except OSError:
|
||||
text = open("qrcode.txt", "w")
|
||||
text.write("""https://pimoroni.com/badger2040
|
||||
Badger 2040
|
||||
* 296x128 1-bit e-ink
|
||||
* six user buttons
|
||||
* user LED
|
||||
* 2MB QSPI flash
|
||||
|
||||
Scan this code to learn
|
||||
more about Badger 2040.
|
||||
""")
|
||||
text.flush()
|
||||
text.seek(0)
|
||||
|
||||
|
||||
lines = text.read().strip().split("\n")
|
||||
code_text = lines.pop(0)
|
||||
title_text = lines.pop(0)
|
||||
detail_text = lines
|
||||
|
||||
display = badger2040.Badger2040()
|
||||
code = qrcode.QRCode()
|
||||
|
||||
|
||||
def measure_qr_code(size, code):
|
||||
w, h = code.get_size()
|
||||
module_size = int(size / w)
|
||||
return module_size * w, module_size
|
||||
|
||||
|
||||
def draw_qr_code(ox, oy, size, code):
|
||||
size, module_size = measure_qr_code(size, code)
|
||||
display.pen(15)
|
||||
display.rectangle(ox, oy, size, size)
|
||||
display.pen(0)
|
||||
for x in range(size):
|
||||
for y in range(size):
|
||||
if code.get_module(x, y):
|
||||
display.rectangle(ox + x * module_size, oy + y * module_size, module_size, module_size)
|
||||
|
||||
|
||||
code.set_text(code_text)
|
||||
size, _ = measure_qr_code(128, code)
|
||||
left = top = int((badger2040.HEIGHT / 2) - (size / 2))
|
||||
draw_qr_code(left, top, 128, code)
|
||||
|
||||
left = 128 + 5
|
||||
|
||||
display.thickness(2)
|
||||
display.text(title_text, left, 20, 0.5)
|
||||
display.thickness(1)
|
||||
|
||||
top = 40
|
||||
for line in detail_text:
|
||||
display.text(line, left, top, 0.4)
|
||||
top += 10
|
||||
|
||||
display.update()
|
||||
|
||||
while True:
|
||||
time.sleep(1.0)
|
Reference in New Issue
Block a user