Skip to content

Commit

Permalink
DigiROM type display + battery monitor (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmcomm authored Mar 5, 2024
1 parent b438b42 commit 0c7d90a
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 5 deletions.
18 changes: 17 additions & 1 deletion board_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,32 @@
- Raspberry Pi Pico
- Seeeduino Xiao RP2040
Note `wifi_type` is not present in older board_config.
Note:
- `wifi_type` is not present in older `board_config`
- `battery_monitor` is optional
'''

import board
import dmcomm.hardware as hw

def picow_voltage_monitor(voltage):
'''
Return PicoW VSYS voltage monitor result for `voltage`.
VSYS is divided by 3, then given to the ADC, which reads 0xFFFF at 3.3V.
'''
return (int) (0xFFFF * voltage / 9.9)

if board.board_id in ["raspberry_pi_pico", "raspberry_pi_pico_w"]:
if board.board_id == "raspberry_pi_pico_w":
wifi_type = "picow"
led_pin = board.GP10
#battery_monitor = {
# "pin": board.VOLTAGE_MONITOR,
# "empty": picow_voltage_monitor(3.2),
# "full": picow_voltage_monitor(4.1),
# "charging": picow_voltage_monitor(4.3),
#}
else:
wifi_type = None
led_pin = board.LED
Expand Down
31 changes: 27 additions & 4 deletions lib/wificom/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import dmcomm.hardware as hw
import dmcomm.protocol
import wificom.realtime as rt
import wificom.status
import wificom.ui
from wificom import modes
from wificom import mqtt
Expand All @@ -37,6 +38,7 @@
startup_mode = None
controller = None
ui = None #pylint: disable=invalid-name
status_display = None
done_wifi_before = False
serial = usb_cdc.console

Expand Down Expand Up @@ -264,7 +266,7 @@ def fail(message):
fail("MQTT failed")
ui.led_dim()
ui.beep_ready()
ui.display_text("WiFi\nHold C to exit")
status_display.change("WiFi", "Hold C to exit", "Paused")
while not ui.is_c_pressed():
time_start = time.monotonic()
new_command = mqtt.get_subscribed_output()
Expand All @@ -273,9 +275,11 @@ def fail(message):
(command_type, output) = process_new_digirom(new_command)
if command_type == COMMAND_DIGIROM:
digirom = output
status_display.do(digirom)
elif command_type in [COMMAND_ERROR, COMMAND_P, COMMAND_I]:
print(output)
mqtt.send_digirom_output(output)
status_display.do("Paused")
if rtb.active:
rtb_type_id_new = (rtb.battle_type, rtb.user_type)
if not rtb_was_active or rtb_type_id_new != rtb_type_id:
Expand All @@ -289,8 +293,10 @@ def fail(message):
rtb_status_callback,
)
rtb_status_callback(rtb_runner.status, True)
status_display.do("RTB: follow LED")
else:
print(rtb.battle_type + " not implemented")
status_display.do("Paused")
rtb_was_active = True
# Heartbeat approx every 10 seconds
if time_start - rtb_last_ping > 10:
Expand Down Expand Up @@ -321,6 +327,7 @@ def fail(message):
if time.monotonic() - time_start >= 5:
break
time.sleep(0.1)
status_display.redraw()
mqtt.quit_rtb()

def run_serial():
Expand All @@ -329,7 +336,7 @@ def run_serial():
'''
print("Running serial")
digirom = None
ui.display_text("Serial\nHold C to exit")
status_display.change("Serial", "Hold C to exit", "Paused", show_battery=False)
while not ui.is_c_pressed():
time_start = time.monotonic()
serial_str = serial_readline()
Expand All @@ -341,9 +348,11 @@ def run_serial():
if command_type == COMMAND_DIGIROM:
digirom = output
print(f"{digirom.signal_type}{digirom.turn}-[{len(digirom)} packets]")
status_display.do(digirom)
time.sleep(1)
elif command_type in [COMMAND_ERROR, COMMAND_P, COMMAND_I]:
print(output)
status_display.do("Paused")
if digirom is not None:
execute_digirom(digirom)
seconds_passed = time.monotonic() - time_start
Expand All @@ -364,13 +373,14 @@ def run_punchbag():
rom = ui.menu(names, roms, "")
if rom == "":
return
ui.display_text("Punchbag\nHold C to change")
status_display.change("Punchbag", "Hold C to change", rom)
while not ui.is_c_pressed():
time_start = time.monotonic()
execute_digirom(rom)
seconds_passed = time.monotonic() - time_start
if seconds_passed < 5:
time.sleep(5 - seconds_passed)
status_display.redraw()
ui.beep_cancel()
ui.display_text("Exiting\n(Release button)")
while ui.is_c_pressed():
Expand Down Expand Up @@ -462,6 +472,18 @@ def hold_c_to_reboot():
pass
mode_change_reboot(modes.MODE_MENU)

def setup_battery_monitor():
'''
Set up the battery monitor if configured.
'''
try:
info = board_config.battery_monitor
except AttributeError:
print("No battery monitor configured")
return None
print("Set up battery monitor")
return wificom.status.BatteryMonitor(**info)

def failure_alert(message, hard_reset=False, reconnect=False):
'''
Alert on failure and allow restart.
Expand Down Expand Up @@ -539,7 +561,7 @@ def main(led_pwm):
WiFiCom main program.
'''
# pylint: disable=too-many-statements
global startup_mode, controller, ui # pylint: disable=global-statement
global startup_mode, controller, ui, status_display # pylint: disable=global-statement

serial.timeout = 1
print("WiFiCom starting")
Expand Down Expand Up @@ -575,6 +597,7 @@ def main(led_pwm):
ui.sound_on = settings.is_sound_on(default=config["sound_on"])
else:
ui.sound_on = config["sound_on"]
status_display = wificom.status.StatusDisplay(ui, setup_battery_monitor())
version.set_display(ui.has_display)

run_column = 0
Expand Down
82 changes: 82 additions & 0 deletions lib/wificom/status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
'''
status.py
Handles status monitoring.
'''

import analogio

class BatteryMonitor:
'''
Handles the battery monitor.
'''
def __init__(self, pin, empty, full, charging):
self._monitor = analogio.AnalogIn(pin)
self._empty = empty
self._full = full
self._charging = charging
def ratio(self):
'''
Return battery fullness 0-1, or None if charging.
'''
reading = self._monitor.value
if reading >= self._charging:
return None
if reading < self._empty:
reading = self._empty
if reading > self._full:
reading = self._full
return (reading - self._empty) / (self._full - self._empty)
def meter(self):
'''
Return text representing fullness, or a message if charging.
'''
sections = 5
ratio = self.ratio()
if ratio is None:
return "(On USB)"
filled = (int)(sections * ratio + 0.5)
unfilled = sections - filled
return "[" + "=" * filled + " " * unfilled + "]"

class StatusDisplay:
'''
Handles status display for WiFi/Serial/Punchbag.
'''
def __init__(self, ui, battery_monitor): #pylint:disable=invalid-name
self._ui = ui
self._battery_monitor = battery_monitor
self._mode = ""
self._line2 = ""
self._status = ""
self._show_battery = True
def change(self, mode, line2, status, show_battery=True):
'''
Set mode, line2 and status and redraw.
'''
self._mode = mode
self._line2 = line2
self._show_battery = show_battery
self.do(status)
def do(self, status): #pylint:disable=invalid-name
'''
Set status and redraw trying digirom then string.
'''
try:
guide = "wait for start" if status.turn == 1 else "push vpet button"
status = f"{status.signal_type}{status.turn}: {guide}"
except AttributeError:
pass
self._status = status
self.redraw()
def redraw(self):
'''
Redraw screen.
'''
rows = [
self._mode,
self._line2,
self._status,
]
if self._show_battery and self._battery_monitor is not None:
rows[0] += " " + self._battery_monitor.meter()
self._ui.display_rows(rows)

0 comments on commit 0c7d90a

Please sign in to comment.