219 lines
6.9 KiB
Python
219 lines
6.9 KiB
Python
from enum import Enum
|
|
import time
|
|
from transitions.experimental.utils import with_model_definitions, add_transitions, transition
|
|
from transitions.extensions import GraphMachine
|
|
from ipkvm.util.mkb import esp32_serial
|
|
from ipkvm.util.mkb.mkb import GPIO
|
|
from ipkvm.util.mkb.scancodes import HIDKeyCode
|
|
from ipkvm.app import logging, ui
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
class State(Enum):
|
|
PoweredOff = "powered off"
|
|
EnterBIOS = "enter bios"
|
|
BIOSSetup = "bios setup"
|
|
WaitingForOS = "waiting for os"
|
|
OCTypeDecision = "next process decision"
|
|
RoughMulticoreUndervolt = "rough multicore undervolting"
|
|
PreciseMulticoreUndervolt = "precise multicore undervolting"
|
|
POST = "power on self test"
|
|
WaitingForHWInfo = "waiting for hwinfo"
|
|
BootLoop = "boot loop"
|
|
IdleWaitingForInput = "idle, waiting for input"
|
|
SingleCoreTuning = "single core tuning"
|
|
|
|
class Overclocking:
|
|
|
|
# wait for power status ig
|
|
time.sleep(0.5)
|
|
if esp32_serial.usb_status:
|
|
state: State = State.IdleWaitingForInput
|
|
else:
|
|
state: State = State.PoweredOff
|
|
|
|
_enter_bios_flag = False
|
|
_running_automatic = False
|
|
|
|
_current_BIOS_location = "EZ Mode"
|
|
|
|
# TRANSITION DEFINITIONS
|
|
@add_transitions(transition(State.PoweredOff, State.POST, unless="client_powered"))
|
|
def power_on(self): ...
|
|
|
|
@add_transitions(transition(State.POST, State.WaitingForOS))
|
|
def wait_os(self): ...
|
|
|
|
@add_transitions(transition(State.WaitingForOS, State.WaitingForHWInfo))
|
|
def os_booted(self): ...
|
|
|
|
@add_transitions(transition(State.WaitingForHWInfo, State.OCTypeDecision))
|
|
def hwinfo_available(self): ...
|
|
|
|
@add_transitions(transition(State.POST, State.EnterBIOS))
|
|
def enter_bios(self): ...
|
|
|
|
@add_transitions(transition(State.EnterBIOS, State.BIOSSetup))
|
|
def start_bios_setup(self): ...
|
|
|
|
@add_transitions(transition(State.BIOSSetup, State.POST))
|
|
def finished_bios_setup(self): ...
|
|
|
|
@add_transitions(transition(State.IdleWaitingForInput, State.WaitingForHWInfo))
|
|
def begin_automation(self): ...
|
|
|
|
@add_transitions(transition(State.POST, State.BootLoop))
|
|
def unsuccessful_post(self): ...
|
|
|
|
@add_transitions(transition(State.BootLoop, State.PoweredOff))
|
|
def trigger_cmos_reset(self): ...
|
|
|
|
@add_transitions(transition([State.IdleWaitingForInput, State.RoughMulticoreUndervolt,
|
|
State.PreciseMulticoreUndervolt, State.SingleCoreTuning], State.POST))
|
|
def reboot(self): ...
|
|
|
|
@add_transitions(transition([State.BIOSSetup, State.IdleWaitingForInput, State.POST, State.WaitingForOS,
|
|
State.RoughMulticoreUndervolt, State.PreciseMulticoreUndervolt,
|
|
State.SingleCoreTuning], State.PoweredOff, after="_hard_shutdown"))
|
|
def hard_shutdown(self): ...
|
|
|
|
@add_transitions(transition(State.IdleWaitingForInput, State.PoweredOff,
|
|
after="_soft_shutdown"))
|
|
def soft_shutdown(self): ...
|
|
|
|
@add_transitions(transition(State.OCTypeDecision, State.RoughMulticoreUndervolt))
|
|
def rough_multicore_undervolt(self): ...
|
|
|
|
@add_transitions(transition(State.OCTypeDecision, State.PreciseMulticoreUndervolt))
|
|
def precise_multicore_undervolt(self): ...
|
|
|
|
@add_transitions(transition(State.OCTypeDecision, State.SingleCoreTuning))
|
|
def single_core_tuning(self): ...
|
|
|
|
@add_transitions(transition([State.POST, State.EnterBIOS], State.IdleWaitingForInput))
|
|
def go_idle(self): ...
|
|
|
|
|
|
# PROPERTIES GO HERE
|
|
@property
|
|
def client_powered(self):
|
|
return esp32_serial.usb_status
|
|
|
|
@property
|
|
def current_BIOS_location(self):
|
|
return self._current_BIOS_location
|
|
|
|
@current_BIOS_location.setter
|
|
def current_BIOS_location(self, value: str):
|
|
if type(value) == str:
|
|
self._current_BIOS_location = value
|
|
|
|
else:
|
|
raise ValueError("Attempted to set the current BIOS location to a non-string value!")
|
|
|
|
# STATE ENTRY FUNCTIONS
|
|
def on_enter_POST(self):
|
|
post_timer = time.time()
|
|
|
|
# If five minutes passes with no USB availability, something has gone terribly wrong...
|
|
while time.time() - post_timer <= 300 and not esp32_serial.usb_status:
|
|
pass
|
|
|
|
if not esp32_serial.usb_status:
|
|
self.unsuccessful_post()
|
|
|
|
else:
|
|
if self._enter_bios_flag:
|
|
self.enter_bios()
|
|
|
|
elif self._running_automatic:
|
|
self.wait_os()
|
|
|
|
else:
|
|
self.go_idle()
|
|
|
|
def on_enter_EnterBIOS(self):
|
|
# # Wait until the POST has progressed far enough for USB devices to be loaded and options to be imminent
|
|
# esp32_serial.notify_code = "45"
|
|
# esp32_serial.active_notification_request.set()
|
|
# esp32_serial.post_code_notify.wait()
|
|
# esp32_serial.post_code_notify.clear()
|
|
#
|
|
# # Spam delete until the BIOS is loaded
|
|
# esp32_serial.notify_code = "Ab"
|
|
# esp32_serial.active_notification_request.set()
|
|
# while not esp32_serial.post_code_notify.is_set():
|
|
|
|
spam_timer = time.time()
|
|
|
|
# Crushed by my lack of consistent access to BIOS post codes, we simply take our time...
|
|
while time.time() - spam_timer <= 10:
|
|
msg = {
|
|
"key_down": HIDKeyCode.Delete.value
|
|
}
|
|
esp32_serial.mkb_queue.put(msg)
|
|
time.sleep(0.1)
|
|
msg = {
|
|
"key_up": HIDKeyCode.Delete.value
|
|
}
|
|
esp32_serial.mkb_queue.put(msg)
|
|
time.sleep(0.1)
|
|
|
|
# esp32_serial.post_code_notify.clear()
|
|
|
|
# Wait a few seconds for the BIOS to become responsive
|
|
time.sleep(5)
|
|
|
|
self._enter_bios_flag = False
|
|
|
|
if self._running_automatic:
|
|
self.start_bios_setup()
|
|
|
|
else:
|
|
self.go_idle()
|
|
|
|
# STATE EXIT FUNCTIONS
|
|
def on_exit_PoweredOff(self):
|
|
self._power_switch(0.2)
|
|
|
|
# UTILITY FUNCTIONS GO HERE
|
|
def _power_switch(self, delay: float):
|
|
msg = {
|
|
"pwr": GPIO.HIGH.value
|
|
}
|
|
esp32_serial.mkb_queue.put(msg)
|
|
time.sleep(delay)
|
|
msg = {
|
|
"pwr": GPIO.LOW.value
|
|
}
|
|
esp32_serial.mkb_queue.put(msg)
|
|
|
|
# FUNCTIONS TRIGGERED BY STATE CHANGES
|
|
def _hard_shutdown(self):
|
|
self._power_switch(5)
|
|
|
|
def _soft_shutdown(self):
|
|
self._power_switch(0.2)
|
|
while esp32_serial.usb_status:
|
|
pass
|
|
|
|
# Wait a few seconds to REALLY be sure we're powered off...
|
|
time.sleep(10)
|
|
|
|
# OTHER FUNCTIONS GO HERE
|
|
def reboot_into_bios(self):
|
|
if esp32_serial.usb_status:
|
|
if self.state is State.IdleWaitingForInput:
|
|
self.soft_shutdown()
|
|
|
|
else:
|
|
self.hard_shutdown()
|
|
|
|
self._enter_bios_flag = True
|
|
self.power_on()
|
|
|
|
|
|
@with_model_definitions
|
|
class MyMachine(GraphMachine):
|
|
pass
|