diff --git a/src/main/scripts/lib/lua/devices.lua b/src/main/scripts/lib/lua/devices.lua index e299a4f9..861e8c97 100644 --- a/src/main/scripts/lib/lua/devices.lua +++ b/src/main/scripts/lib/lua/devices.lua @@ -107,7 +107,6 @@ local function fillBuffer(bus) return nil, "timeout" else bus.buffer = unistd.read(bus.fd, 1024) - bus.bufferLen = string.len(bus.buffer) bus.bufferPos = 1 return true end @@ -126,7 +125,7 @@ local function readOne(bus) end local result = bus.buffer:byte(bus.bufferPos) - if bus.bufferPos >= bus.bufferLen then + if bus.bufferPos >= #bus.buffer then bus.buffer = nil else bus.bufferPos = bus.bufferPos + 1 @@ -139,23 +138,39 @@ local function readMessage(bus) local value local message = "" while true do - value, reason = readOne(bus) - if value == nil then -- error - return value, reason + if not bus.buffer then + local result, status = fillBuffer(bus) + if not result then + return result, status + end + end + + value = bus.buffer:sub(bus.bufferPos, -1) + + if #message == 0 and value:byte(1) == 0 then + bus.bufferPos = bus.bufferPos + 1 + value = value:sub(2, -1) + end + + if value:find(message_delimiter) then + value = value:sub(1, value:find(message_delimiter)) + bus.bufferPos = bus.bufferPos + #value + if bus.bufferPos > #bus.buffer then + clearBuffer(bus) + end else - if value == 0 then - if message:match("%S") ~= nil then - local ok, result = pcall(cjson.decode, message) - if ok then - return result - else - return nil, result - end - else - message = "" - end + clearBuffer(bus) + end + + message = message .. value + + if message:byte(-1) == 0 then + message = message:sub(1, -2) + local ok, result = pcall(cjson.decode, message) + if ok then + return result else - message = message .. string.char(value) + return nil, result end end end diff --git a/src/main/scripts/lib/micropython/devices.py b/src/main/scripts/lib/micropython/devices.py index 9c7aeeb0..98a09b1a 100644 --- a/src/main/scripts/lib/micropython/devices.py +++ b/src/main/scripts/lib/micropython/devices.py @@ -109,20 +109,36 @@ class DeviceBus: def _read_message(self, expected_type): message = "" while True: - value = chr(self._read_one()) - if value == self.MESSAGE_DELIMITER: - if message: - data = json.loads(message) - if data["type"] != expected_type: - raise Exception("unexpected message type: %s" % data["type"]) + if self.buffer is None: + self._fill_buffer() + + value = self.buffer.decode()[self.buffer_pos:] + + if len(message) == 0 and value[0] == self.MESSAGE_DELIMITER: + self.buffer_pos += 1 + value = value[1:] + + if value.find(self.MESSAGE_DELIMITER) != -1: + value = value[:value.find(self.MESSAGE_DELIMITER) + 1] + self.buffer_pos += len(value) + if self.buffer_pos >= len(self.buffer): + self._clear_buffer() + else: + self._clear_buffer() + + message += value + + if message[-1] == self.MESSAGE_DELIMITER: + data = json.loads(message) + if data["type"] == expected_type: if "data" in data: return data["data"] else: return + elif data["type"] == "error": + raise Exception(data["data"]) else: - message = "" - else: - message += value + raise Exception("unexpected message type: %s" % data["type"]) def _read_one(self): if self.buffer is None: @@ -146,8 +162,10 @@ class DeviceBus: # This is horrible, but don't know how to know how many bytes are available, # so reading one by one is necessary to avoid blocking. data = bytearray() - while len(data) < limit and len(self.poll.poll(0)) > 0: + bytesRead = 0 + while bytesRead < limit and len(self.poll.poll(0)) > 0: data.extend(self.file.read(1)) + bytesRead += 1 return data def _skip_input(self):