Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start creating production code #50

Merged
merged 1 commit into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,15 @@ jobs:
with:
options: "--check --verbose"
src: "./Software/Testing"

- name: Flake8 Lint Production
uses: py-actions/flake8@v2
with:
path: "./Software/Production"
ignore: "E501,E203,E722" #Ignore line to long, we don't care

- name: Black File Formatter Production
uses: psf/black@stable
with:
options: "--check --verbose"
src: "./Software/Production"
67 changes: 67 additions & 0 deletions Software/Production/StartupState.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import time
import terminalio
from State import State
from adafruit_display_text import label
from setup import (
display,
keys,
neopixels,
)


class StartupState(State):
color = (0, 0, 0)
timer = 0
stage = 0

@property
def name(self):
return "startup"

def enter(self, machine):
neopixels.fill((0, 0, 0))
State.enter(self, machine)

def exit(self, machine):
neopixels.fill((255, 0, 0))
self.color = (0, 0, 0)
self.timer = 0
self.stage = 0
State.exit(self, machine)

def update(self, machine):
self.timer = self.timer + 1
if self.stage == 0:
text = " DCZia\n Electric Sampler"
if len(text) > self.timer:
text = text[0 : self.timer]
text_area = label.Label(terminalio.FONT, text=text, x=2, y=5)
display.show(text_area)
self.color = (self.timer, self.timer, 0)
if self.timer > (len(text) * 1.5):
self.timer = 0
self.stage = 1
elif self.stage == 1:
text = "Fueled by Green Chile\n and Solder"
if len(text) > self.timer:
text = text[0 : self.timer]
text_area = label.Label(terminalio.FONT, text=text, x=2, y=10)
display.show(text_area)
if self.timer > (len(text) * 1.5):
self.timer = 0
self.stage = 2
else:
if self.timer < (255 * 8):
color = (0, self.timer % 255, 0)
neopixels[self.timer // 255] = color
neopixels.show()
self.timer = self.timer + 1 # make it faster
else:
time.sleep(0.1)
machine.go_to_state(
"startup"
) # TODO: Should go to menu when that is in
# Skip to menu if encoder is pressed
key_event = keys.events.get()
if key_event and key_event.pressed:
machine.go_to_state("startup") # TODO: Should go to menu when that is in
16 changes: 16 additions & 0 deletions Software/Production/State.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class State(object):
def __init__(self):
pass

@property
def name(self):
return ""

def enter(self, machine):
pass

def exit(self, machine):
pass

def update(self, machine):
return True
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
135 changes: 135 additions & 0 deletions Software/Production/lib/adafruit_displayio_ssd1306.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# SPDX-FileCopyrightText: 2019 Scott Shawcroft for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
`adafruit_displayio_ssd1306`
================================================================================

DisplayIO driver for SSD1306 monochrome displays


* Author(s): Scott Shawcroft

Implementation Notes
--------------------

**Hardware:**

* `Monochrome 1.3" 128x64 OLED graphic display <https://www.adafruit.com/product/938>`_
* `Monochrome 128x32 I2C OLED graphic display <https://www.adafruit.com/product/931>`_
* `Monochrome 0.96" 128x64 OLED graphic display <https://www.adafruit.com/product/326>`_
* `Monochrome 128x32 SPI OLED graphic display <https://www.adafruit.com/product/661>`_
* `Adafruit FeatherWing OLED - 128x32 OLED <https://www.adafruit.com/product/2900>`_
* Monochrome 0.49" 64x32 I2C OLED graphic display
* Might work on other sub-128 width display: Dots 72x40, 64x48, 96x16

**Software and Dependencies:**

* Adafruit CircuitPython (version 5+) firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases

"""

import displayio

try:
from typing import Union
except ImportError:
pass

__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_SSD1306.git"

# Sequence from page 19 here: https://cdn-shop.adafruit.com/datasheets/UG-2864HSWEG01+user+guide.pdf
_INIT_SEQUENCE = (
b"\xAE\x00" # DISPLAY_OFF
b"\x20\x01\x00" # Set memory addressing to horizontal mode.
b"\x81\x01\xcf" # set contrast control
b"\xA1\x00" # Column 127 is segment 0
b"\xA6\x00" # Normal display
b"\xc8\x00" # Normal display
b"\xA8\x01\x3f" # Mux ratio is 1/64
b"\xd5\x01\x80" # Set divide ratio
b"\xd9\x01\xf1" # Set pre-charge period
b"\xda\x01\x12" # Set com configuration
b"\xdb\x01\x40" # Set vcom configuration
b"\x8d\x01\x14" # Enable charge pump
b"\xAF\x00" # DISPLAY_ON
)


class SSD1306(displayio.Display):
"""
SSD1306 driver

:param int width: The width of the display
:param int height: The height of the display
:param int rotation: The rotation of the display in degrees. Default is 0. Must be one of
(0, 90, 180, 270)
"""

def __init__(
self, bus: Union[displayio.FourWire, displayio.I2CDisplay], **kwargs
) -> None:
# Patch the init sequence for 32 pixel high displays.
init_sequence = bytearray(_INIT_SEQUENCE)
height = kwargs["height"]
width = kwargs["width"]
if "rotation" in kwargs and kwargs["rotation"] % 180 != 0:
height = kwargs["width"]
width = kwargs["height"]
init_sequence[16] = height - 1 # patch mux ratio
if height == 32 and width == 64: # Make sure this only apply to that resolution
init_sequence[16] = 64 - 1 # FORCED for 64x32 because it fail with formula
if height in (32, 16) and width != 64:
init_sequence[25] = 0x02 # patch com configuration
col_offset = (
0 if width == 128 else (128 - width) // 2
) # https://github.com/micropython/micropython/pull/7411
super().__init__(
bus,
init_sequence,
**kwargs,
colstart=col_offset,
rowstart=col_offset,
color_depth=1,
grayscale=True,
pixels_in_byte_share_row=False,
set_column_command=0x21,
set_row_command=0x22,
data_as_commands=True,
brightness_command=0x81,
single_byte_bounds=True,
)
self._is_awake = True # Display starts in active state (_INIT_SEQUENCE)

@property
def is_awake(self) -> bool:
"""
The power state of the display. (read-only)

`True` if the display is active, `False` if in sleep mode.

:type: bool
"""
return self._is_awake

def sleep(self) -> None:
"""
Put display into sleep mode.

Display uses < 10uA in sleep mode. Display remembers display data and operation mode
active prior to sleeping. MP can access (update) the built-in display RAM.
"""
if self._is_awake:
self.bus.send(0xAE, b"") # 0xAE = display off, sleep mode
self._is_awake = False

def wake(self) -> None:
"""
Wake display from sleep mode
"""
if not self._is_awake:
self.bus.send(0xAF, b"") # 0xAF = display on
self._is_awake = True
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Software/Production/lib/adafruit_midi/note_off.mpy
Binary file not shown.
Binary file added Software/Production/lib/adafruit_midi/note_on.mpy
Binary file not shown.
Binary file added Software/Production/lib/adafruit_midi/pitch_bend.mpy
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Software/Production/lib/adafruit_midi/start.mpy
Binary file not shown.
Binary file added Software/Production/lib/adafruit_midi/stop.mpy
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Software/Production/lib/adafruit_sdcard.mpy
Binary file not shown.
Binary file added Software/Production/lib/neopixel.mpy
Binary file not shown.
53 changes: 53 additions & 0 deletions Software/Production/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import time

from setup import (
select_enc,
volume_enc,
)

from StartupState import StartupState


class StateMachine(object):
def __init__(self):
self.state = None
self.states = {}
self.last_select_pos = select_enc.position
self.last_volume_pos = volume_enc.position
self.paused_state = None
self.ticks_ms = 0
self.animation = None

def add_state(self, state):
self.states[state.name] = state

def go_to_state(self, state_name):
if self.state:
self.state.exit(self)
self.state = self.states[state_name]
self.state.enter(self)

def update(self):
if self.state:
self.state.update(self)
if self.ticks_ms > 0:
time.sleep(self.ticks_ms / 1000)

# When pausing, don't exit the state
def pause(self):
self.state = self.states["paused"]
self.state.enter(self)

# When resuming, don't re-enter the state
def resume_state(self, state_name):
if self.state:
self.state.exit(self)
self.state = self.states[state_name]


machine = StateMachine()
machine.add_state(StartupState())
machine.go_to_state("startup")

while True:
machine.update()
76 changes: 76 additions & 0 deletions Software/Production/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import adafruit_displayio_ssd1306
import adafruit_midi
import adafruit_sdcard
import board
import busio
import digitalio
import displayio
import keypad
import neopixel
import rotaryio
import storage
import terminalio
import time
import usb_midi

from adafruit_display_text import label

# OLED Screen ( display )
displayio.release_displays()
i2c = busio.I2C(board.GP15, board.GP14)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)

# Neopixels
neopixels = neopixel.NeoPixel(board.GP3, 10, brightness=0.1, auto_write=True)

# Board LED
led = digitalio.DigitalInOut(board.LED)
led.direction = digitalio.Direction.OUTPUT

# Sync Out
sync_out = digitalio.DigitalInOut(board.GP7)
sync_out.direction = digitalio.Direction.OUTPUT

# Sync In
sync_in = digitalio.DigitalInOut(board.GP6)
sync_in.direction = digitalio.Direction.INPUT

# Buttons
# 0-7 Buttons
# 8 Play
# 9 Function
# 10 Select
# 11 Volume
keys = keypad.KeyMatrix(
row_pins=(board.GP27, board.GP26, board.GP18),
column_pins=(board.GP20, board.GP21, board.GP22, board.GP28),
columns_to_anodes=False,
)

# Setup rotary encoders
select_enc = rotaryio.IncrementalEncoder(board.GP16, board.GP17)
volume_enc = rotaryio.IncrementalEncoder(board.GP4, board.GP5)

# MIDI setup
midi_uart = busio.UART(tx=board.GP8, baudrate=31250)
midi_serial_channel = 2
midi_serial = adafruit_midi.MIDI(
midi_out=midi_uart, out_channel=midi_serial_channel - 1
)

midi_usb = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0)

# Setup the SD card and mount it as /sd
try:
# busio.SPI(clock:, MOSI: , MISO:)
spi = busio.SPI(board.GP10, board.GP11, board.GP12)
cs = digitalio.DigitalInOut(board.GP13)
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
except:
text = "No SD Card Found!"
text_area = label.Label(terminalio.FONT, text=text, color=0xFFFF00, x=2, y=15)
display.show(text_area)
time.sleep(5)