Keep sending if serial line was only sent partially
So far the sending routine did not track the amount of bytes that were actually sent. This is now fixed such that if the number of sent bytes is less then the number of bytes of the whole message, the sending rountine will continue to send the unsent parts of the message until it succeeds (or a timeout occurs). Also adjusted the virtual printer to imitate a real serial interface with regards to having it return the written bytes and allowing a partial sending (returning the number of bytes that actually were sent).
This commit is contained in:
parent
0fec3aeca9
commit
2b9aef5874
2 changed files with 55 additions and 23 deletions
|
|
@ -30,7 +30,9 @@ class VirtualPrinter():
|
|||
self._read_timeout = read_timeout
|
||||
self._write_timeout = write_timeout
|
||||
|
||||
self.incoming = CharCountingQueue(settings().getInt(["devel", "virtualPrinter", "rxBuffer"]), name="RxBuffer")
|
||||
self._rx_buffer_size = settings().getInt(["devel", "virtualPrinter", "rxBuffer"])
|
||||
|
||||
self.incoming = CharCountingQueue(self._rx_buffer_size, name="RxBuffer")
|
||||
self.outgoing = Queue.Queue()
|
||||
self.buffered = Queue.Queue(maxsize=settings().getInt(["devel", "virtualPrinter", "commandBuffer"]))
|
||||
|
||||
|
|
@ -95,13 +97,13 @@ class VirtualPrinter():
|
|||
self._triggerResendWithTimeoutAt105 = True
|
||||
self._triggeredResendWithTimeoutAt105 = False
|
||||
|
||||
waitThread = threading.Thread(target=self._sendWaitAfterTimeout)
|
||||
waitThread = threading.Thread(target=self._sendWaitAfterTimeout, name="octoprint.plugins.virtual_printer.wait_thread")
|
||||
waitThread.start()
|
||||
|
||||
readThread = threading.Thread(target=self._processIncoming)
|
||||
readThread = threading.Thread(target=self._processIncoming, name="octoprint.plugins.virtual_printer.read_thread")
|
||||
readThread.start()
|
||||
|
||||
bufferThread = threading.Thread(target=self._processBuffer)
|
||||
bufferThread = threading.Thread(target=self._processBuffer, name="octoprint.plugins.virtual_printer.buffer_thread")
|
||||
bufferThread.start()
|
||||
|
||||
def __str__(self):
|
||||
|
|
@ -117,17 +119,26 @@ class VirtualPrinter():
|
|||
|
||||
def _processIncoming(self):
|
||||
next_wait_timeout = time.time() + self._waitInterval
|
||||
buf = ""
|
||||
while self.incoming is not None and not self._killed:
|
||||
self._simulateTemps()
|
||||
|
||||
try:
|
||||
data = self.incoming.get(timeout=0.01)
|
||||
self.incoming.task_done()
|
||||
except Queue.Empty:
|
||||
if self._sendWait and time.time() > next_wait_timeout:
|
||||
self.outgoing.put("wait")
|
||||
next_wait_timeout = time.time() + self._waitInterval
|
||||
continue
|
||||
|
||||
buf += data
|
||||
if "\n" in buf:
|
||||
data = buf[:buf.find("\n") + 1]
|
||||
buf = buf[buf.find("\n") + 1:]
|
||||
else:
|
||||
continue
|
||||
|
||||
next_wait_timeout = time.time() + self._waitInterval
|
||||
|
||||
if data is None:
|
||||
|
|
@ -322,6 +333,8 @@ class VirtualPrinter():
|
|||
if len(data.strip()) > 0 and not self._okBeforeCommandOutput:
|
||||
self._sendOk()
|
||||
|
||||
self._logger.info("Closing down read loop")
|
||||
|
||||
def _calculate_checksum(self, line):
|
||||
checksum = 0
|
||||
for c in line:
|
||||
|
|
@ -738,6 +751,9 @@ class VirtualPrinter():
|
|||
continue
|
||||
|
||||
self._performMove(line)
|
||||
self.buffered.task_done()
|
||||
|
||||
self._logger.info("Closing down buffer loop")
|
||||
|
||||
def write(self, data):
|
||||
if self._debug_drop_connection:
|
||||
|
|
@ -746,14 +762,14 @@ class VirtualPrinter():
|
|||
|
||||
with self._incoming_lock:
|
||||
if self.incoming is None or self.outgoing is None:
|
||||
return
|
||||
return 0
|
||||
|
||||
if "M112" in data and self._supportM112:
|
||||
self._kill()
|
||||
return
|
||||
return len(data)
|
||||
|
||||
try:
|
||||
self.incoming.put(data, timeout=self._write_timeout)
|
||||
return self.incoming.put(data, timeout=self._write_timeout, partial=True)
|
||||
except Queue.Full:
|
||||
self._logger.info("Incoming queue is full, raising SerialTimeoutException")
|
||||
raise SerialTimeoutException()
|
||||
|
|
@ -764,6 +780,7 @@ class VirtualPrinter():
|
|||
|
||||
try:
|
||||
line = self.outgoing.get(timeout=self._read_timeout)
|
||||
self.outgoing.task_done()
|
||||
return line
|
||||
except Queue.Empty:
|
||||
return ""
|
||||
|
|
@ -795,22 +812,25 @@ class CharCountingQueue(Queue.Queue):
|
|||
self._size = 0
|
||||
self._name = name
|
||||
|
||||
def put(self, item, block=True, timeout=None):
|
||||
def put(self, item, block=True, timeout=None, partial=False):
|
||||
self.not_full.acquire()
|
||||
|
||||
try:
|
||||
item_size = self._len(item)
|
||||
if not self._will_it_fit(item) and partial:
|
||||
space_left = self.maxsize - self._qsize()
|
||||
item = item[:space_left]
|
||||
|
||||
if not block:
|
||||
if self._qsize() + item_size >= self.maxsize:
|
||||
if not self._will_it_fit(item):
|
||||
raise Queue.Full
|
||||
elif timeout is None:
|
||||
while self._qsize() + item_size >= self.maxsize:
|
||||
while not self._will_it_fit(item):
|
||||
self.not_full.wait()
|
||||
elif timeout < 0:
|
||||
raise ValueError("'timeout' must be a positive number")
|
||||
else:
|
||||
endtime = time.time() + timeout
|
||||
while self._qsize() + item_size >= self.maxsize:
|
||||
while not self._will_it_fit(item):
|
||||
remaining = endtime - time.time()
|
||||
if remaining <= 0.0:
|
||||
raise Queue.Full
|
||||
|
|
@ -819,6 +839,8 @@ class CharCountingQueue(Queue.Queue):
|
|||
self._put(item)
|
||||
self.unfinished_tasks += 1
|
||||
self.not_empty.notify()
|
||||
|
||||
return self._len(item)
|
||||
finally:
|
||||
self.not_full.release()
|
||||
|
||||
|
|
@ -838,3 +860,6 @@ class CharCountingQueue(Queue.Queue):
|
|||
item = self.queue.popleft()
|
||||
self._size -= self._len(item)
|
||||
return item
|
||||
|
||||
def _will_it_fit(self, item):
|
||||
return self.maxsize - self._qsize() >= self._len(item)
|
||||
|
|
|
|||
|
|
@ -1933,24 +1933,31 @@ class MachineCom(object):
|
|||
return
|
||||
|
||||
self._log("Send: " + str(cmd))
|
||||
try:
|
||||
self._serial.write(cmd + '\n')
|
||||
except serial.SerialTimeoutException:
|
||||
self._log("Serial timeout while writing to serial port, trying again.")
|
||||
|
||||
cmd += "\n"
|
||||
written = 0
|
||||
while written < len(cmd):
|
||||
to_send = cmd[written:]
|
||||
try:
|
||||
self._serial.write(cmd + '\n')
|
||||
written += self._serial.write(to_send)
|
||||
except serial.SerialTimeoutException:
|
||||
self._log("Serial timeout while writing to serial port, trying again.")
|
||||
try:
|
||||
written += self._serial.write(to_send)
|
||||
except:
|
||||
if not self._connection_closing:
|
||||
self._logger.exception("Unexpected error while writing to serial port")
|
||||
self._log("Unexpected error while writing to serial port: %s" % (get_exception_string()))
|
||||
self._errorValue = get_exception_string()
|
||||
self.close(is_error=True)
|
||||
break
|
||||
except:
|
||||
if not self._connection_closing:
|
||||
self._logger.exception("Unexpected error while writing to serial port")
|
||||
self._log("Unexpected error while writing to serial port: %s" % (get_exception_string()))
|
||||
self._errorValue = get_exception_string()
|
||||
self.close(is_error=True)
|
||||
except:
|
||||
if not self._connection_closing:
|
||||
self._logger.exception("Unexpected error while writing to serial port")
|
||||
self._log("Unexpected error while writing to serial port: %s" % (get_exception_string()))
|
||||
self._errorValue = get_exception_string()
|
||||
self.close(is_error=True)
|
||||
break
|
||||
|
||||
##~~ command handlers
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue