paneldue: implement queues for command handling
This implements two queues, one for commands that execute locally and a second for gcode commands that execute on the Klippy host. While it is valid for a local command to execute concurrently with a remote command, commands of the same type (local or remote) should execute sequentially. Signed-off-by: Eric Callahan <arksine.code@gmail.com> Update paneldue.py
This commit is contained in:
parent
eea2abd60e
commit
ba4d771d10
|
@ -9,6 +9,7 @@ import time
|
||||||
import json
|
import json
|
||||||
import errno
|
import errno
|
||||||
import logging
|
import logging
|
||||||
|
import asyncio
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from utils import ServerError
|
from utils import ServerError
|
||||||
from tornado import gen
|
from tornado import gen
|
||||||
|
@ -165,6 +166,9 @@ class PanelDue:
|
||||||
self.is_ready = False
|
self.is_ready = False
|
||||||
self.is_shutdown = False
|
self.is_shutdown = False
|
||||||
self.initialized = False
|
self.initialized = False
|
||||||
|
self.cq_busy = self.gq_busy = False
|
||||||
|
self.command_queue = []
|
||||||
|
self.gc_queue = []
|
||||||
self.last_printer_state = 'O'
|
self.last_printer_state = 'O'
|
||||||
self.last_update_time = 0.
|
self.last_update_time = 0.
|
||||||
|
|
||||||
|
@ -351,11 +355,9 @@ class PanelDue:
|
||||||
logging.info("PanelDue: " + msg)
|
logging.info("PanelDue: " + msg)
|
||||||
raise PanelDueError(msg)
|
raise PanelDueError(msg)
|
||||||
|
|
||||||
self._run_gcode(line[line_index+1:cs_index])
|
script = line[line_index+1:cs_index]
|
||||||
else:
|
else:
|
||||||
self._run_gcode(line)
|
script = line
|
||||||
|
|
||||||
def _run_gcode(self, script):
|
|
||||||
# Execute the gcode. Check for special RRF gcodes that
|
# Execute the gcode. Check for special RRF gcodes that
|
||||||
# require special handling
|
# require special handling
|
||||||
parts = script.split()
|
parts = script.split()
|
||||||
|
@ -376,7 +378,7 @@ class PanelDue:
|
||||||
return
|
return
|
||||||
params["arg_" + arg] = val
|
params["arg_" + arg] = val
|
||||||
func = self.direct_gcodes[cmd]
|
func = self.direct_gcodes[cmd]
|
||||||
func(**params)
|
self.queue_command(func, **params)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Prepare GCodes that require special handling
|
# Prepare GCodes that require special handling
|
||||||
|
@ -386,18 +388,44 @@ class PanelDue:
|
||||||
|
|
||||||
if not script:
|
if not script:
|
||||||
return
|
return
|
||||||
elif script in RESTART_GCODES:
|
self.queue_gcode(script)
|
||||||
self.ioloop.spawn_callback(self.klippy_apis.do_restart, script)
|
|
||||||
return
|
|
||||||
self.ioloop.spawn_callback(self._send_klippy_gcode, script)
|
|
||||||
|
|
||||||
async def _send_klippy_gcode(self, script):
|
def queue_gcode(self, script):
|
||||||
try:
|
self.gc_queue.append(script)
|
||||||
await self.klippy_apis.run_gcode(script)
|
if not self.gq_busy:
|
||||||
except self.server.error:
|
self.gq_busy = True
|
||||||
msg = f"Error executing script {script}"
|
self.ioloop.spawn_callback(self._process_gcode_queue)
|
||||||
self.handle_gcode_response("!! " + msg)
|
|
||||||
logging.exception(msg)
|
async def _process_gcode_queue(self):
|
||||||
|
while self.gc_queue:
|
||||||
|
script = self.gc_queue.pop(0)
|
||||||
|
try:
|
||||||
|
if script in RESTART_GCODES:
|
||||||
|
await self.klippy_apis.do_restart(script)
|
||||||
|
else:
|
||||||
|
await self.klippy_apis.run_gcode(script)
|
||||||
|
except self.server.error:
|
||||||
|
msg = f"Error executing script {script}"
|
||||||
|
self.handle_gcode_response("!! " + msg)
|
||||||
|
logging.exception(msg)
|
||||||
|
self.gq_busy = False
|
||||||
|
|
||||||
|
def queue_command(self, cmd, *args, **kwargs):
|
||||||
|
self.command_queue.append((cmd, args, kwargs))
|
||||||
|
if not self.cq_busy:
|
||||||
|
self.cq_busy = True
|
||||||
|
self.ioloop.spawn_callback(self._process_command_queue)
|
||||||
|
|
||||||
|
async def _process_command_queue(self):
|
||||||
|
while self.command_queue:
|
||||||
|
cmd, args, kwargs = self.command_queue.pop(0)
|
||||||
|
try:
|
||||||
|
ret = cmd(*args, **kwargs)
|
||||||
|
if asyncio.iscoroutine(ret):
|
||||||
|
await ret
|
||||||
|
except Exception:
|
||||||
|
logging.exception("Error processing command")
|
||||||
|
self.cq_busy = False
|
||||||
|
|
||||||
def _clean_filename(self, filename):
|
def _clean_filename(self, filename):
|
||||||
# Remove quotes and whitespace
|
# Remove quotes and whitespace
|
||||||
|
@ -419,11 +447,11 @@ class PanelDue:
|
||||||
|
|
||||||
def _prepare_M23(self, args):
|
def _prepare_M23(self, args):
|
||||||
filename = self._clean_filename(args[0])
|
filename = self._clean_filename(args[0])
|
||||||
return "M23 " + filename
|
return f"M23 {filename}"
|
||||||
|
|
||||||
def _prepare_M32(self, args):
|
def _prepare_M32(self, args):
|
||||||
filename = self._clean_filename(args[0])
|
filename = self._clean_filename(args[0])
|
||||||
return "SDCARD_PRINT_FILE FILENAME=" + filename
|
return f"SDCARD_PRINT_FILE FILENAME=\"{filename}\""
|
||||||
|
|
||||||
def _prepare_M98(self, args):
|
def _prepare_M98(self, args):
|
||||||
macro = args[0][1:].strip(" \"\t\n")
|
macro = args[0][1:].strip(" \"\t\n")
|
||||||
|
@ -463,6 +491,7 @@ class PanelDue:
|
||||||
mbox['msgBox.title'] = title
|
mbox['msgBox.title'] = title
|
||||||
mbox['msgBox.controls'] = 0
|
mbox['msgBox.controls'] = 0
|
||||||
mbox['msgBox.timeout'] = 0
|
mbox['msgBox.timeout'] = 0
|
||||||
|
logging.debug(f"Creating PanelDue Confirmation: {mbox}")
|
||||||
self.write_response(mbox)
|
self.write_response(mbox)
|
||||||
|
|
||||||
def handle_gcode_response(self, response):
|
def handle_gcode_response(self, response):
|
||||||
|
@ -490,8 +519,6 @@ class PanelDue:
|
||||||
return 'S'
|
return 'S'
|
||||||
|
|
||||||
printer_state = self.printer_state
|
printer_state = self.printer_state
|
||||||
p_busy = printer_state['idle_timeout'].get(
|
|
||||||
'state', 'Idle') == "Printing"
|
|
||||||
sd_state = printer_state['print_stats'].get('state', "standby")
|
sd_state = printer_state['print_stats'].get('state', "standby")
|
||||||
if sd_state == "printing":
|
if sd_state == "printing":
|
||||||
if self.last_printer_state == 'A':
|
if self.last_printer_state == 'A':
|
||||||
|
@ -500,17 +527,15 @@ class PanelDue:
|
||||||
# Printing
|
# Printing
|
||||||
return 'P'
|
return 'P'
|
||||||
elif sd_state == "paused":
|
elif sd_state == "paused":
|
||||||
if p_busy and self.last_printer_state != 'A':
|
p_active = printer_state['idle_timeout'].get(
|
||||||
|
'state', 'Idle') == "Printing"
|
||||||
|
if p_active and self.last_printer_state != 'A':
|
||||||
# Pausing
|
# Pausing
|
||||||
return 'D'
|
return 'D'
|
||||||
else:
|
else:
|
||||||
# Paused
|
# Paused
|
||||||
return 'A'
|
return 'A'
|
||||||
|
|
||||||
if p_busy:
|
|
||||||
# Printer is "busy"
|
|
||||||
return 'B'
|
|
||||||
|
|
||||||
return 'I'
|
return 'I'
|
||||||
|
|
||||||
def _run_paneldue_M408(self, arg_r=None, arg_s=1):
|
def _run_paneldue_M408(self, arg_r=None, arg_s=1):
|
||||||
|
@ -678,7 +703,7 @@ class PanelDue:
|
||||||
response['files'] = flist
|
response['files'] = flist
|
||||||
self.write_response(response)
|
self.write_response(response)
|
||||||
|
|
||||||
def _run_paneldue_M30(self, arg_p=None):
|
async def _run_paneldue_M30(self, arg_p=None):
|
||||||
# Delete a file. Clean up the file name and make sure
|
# Delete a file. Clean up the file name and make sure
|
||||||
# it is relative to the "gcodes" root.
|
# it is relative to the "gcodes" root.
|
||||||
path = arg_p
|
path = arg_p
|
||||||
|
@ -690,7 +715,7 @@ class PanelDue:
|
||||||
|
|
||||||
if not path.startswith("gcodes/"):
|
if not path.startswith("gcodes/"):
|
||||||
path = "gcodes/" + path
|
path = "gcodes/" + path
|
||||||
self.ioloop.spawn_callback(self.file_manager.delete_file, path)
|
await self.file_manager.delete_file(path)
|
||||||
|
|
||||||
def _run_paneldue_M36(self, arg_p=None):
|
def _run_paneldue_M36(self, arg_p=None):
|
||||||
response = {}
|
response = {}
|
||||||
|
|
Loading…
Reference in New Issue