-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First part of moving du-stream to separate repo.
- Loading branch information
1 parent
6278ee8
commit 26ed6a6
Showing
18 changed files
with
615 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
return { | ||
_all = { | ||
coverage = true | ||
}, | ||
default = { | ||
verbose = true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,3 +39,4 @@ luac.out | |
*.x86_64 | ||
*.hex | ||
|
||
**/luacov-html/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[submodule "external/du-serializer"] | ||
path = external/du-serializer | ||
url = [email protected]:PerMalmberg/du-serializer.git | ||
[submodule "external/du-unit-testing"] | ||
path = external/du-unit-testing | ||
url = [email protected]:PerMalmberg/du-unit-testing.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
reporter = "html" | ||
include = { | ||
"src$", | ||
"src%/.+$" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
.PHONY: clean test dev release | ||
CLEAN_COV=if [ -e luacov.report.out ]; then rm luacov.report.out; fi; if [ -e luacov.stats.out ]; then rm luacov.stats.out; fi | ||
PWD=$(shell pwd) | ||
|
||
LUA_PATH := ./src/?.lua | ||
LUA_PATH := $(LUA_PATH);$(PWD)/external/du-serializer/?.lua | ||
LUA_PATH := $(LUA_PATH);$(PWD)/external/du-unit-testing/src/?.lua | ||
LUA_PATH := $(LUA_PATH);$(PWD)/external/du-unit-testing/external/du-lua-examples/?.lua | ||
LUA_PATH := $(LUA_PATH);$(PWD)/external/du-unit-testing/external/du-lua-examples/api-mockup/?.lua | ||
LUA_PATH := $(LUA_PATH);$(PWD)/external/du-unit-testing/external/du-luac/lua/?.lua | ||
|
||
|
||
all: release | ||
|
||
lua_path: | ||
@echo "$(LUA_PATH)" | ||
|
||
clean_cov: | ||
@$(CLEAN_COV) | ||
|
||
clean_report: | ||
@if [ -d ./luacov-html ]; then rm -rf ./luacov-html; fi | ||
|
||
clean: clean_cov clean_report | ||
@rm -rf out | ||
|
||
test: clean | ||
@echo Runnings unit tests on du-render | ||
@LUA_PATH="$(LUA_PATH)" busted . --exclude-pattern=".*serializer.*" | ||
@luacov | ||
@$(CLEAN_COV) | ||
|
||
dev: test | ||
@LUA_PATH="$(LUA_PATH)" du-lua build --copy=development/main | ||
@# Modify file inline. Actual regex is '/^\s*---.*$/d' but $ must be doubled in make file | ||
@sed -i '/^\s*---.*$$/d' "./out/development/example/stream/screen.lua" | ||
@sed -i '/^\s*---.*$$/d' "./out/development/example/render/main.lua" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
# du-stream | ||
A data stream library for Dual Universe screens and emitter/receivers | ||
|
||
A stream library for Dual Universe | ||
|
||
This file was automatically generated by [DU-LuaC](https://github.com/wolfe-labs/DU-LuaC)'s interactive CLI. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"folders": [ | ||
{ | ||
"path": "." | ||
} | ||
], | ||
"settings": { | ||
"runOnSave.commands": [ | ||
{ | ||
"match": ".*\\.lua", | ||
"command": "make test", | ||
"runIn": "terminal" | ||
} | ||
], | ||
"Lua.workspace.library": [ | ||
"external/du-libs/", | ||
"${3rd}/luassert/library", | ||
"${3rd}/busted/library" | ||
] | ||
} | ||
} |
Submodule du-serializer
added at
337226
Submodule du-unit-testing
added at
6df3fe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"cli": { | ||
"fmtVersion": 3 | ||
}, | ||
"name": "du-stream", | ||
"description": "A stream library for Dual Universe", | ||
"sourcePath": "src", | ||
"outputPath": "out", | ||
"libs": [], | ||
"builds": { | ||
"main": { | ||
"name": "main", | ||
"type": "control", | ||
"slots": {} | ||
} | ||
}, | ||
"targets": { | ||
"development": { | ||
"name": "development", | ||
"minify": false, | ||
"handleErrors": false | ||
} | ||
}, | ||
"internalPaths": [ | ||
"autoconf/", | ||
"cpml/", | ||
"pl/", | ||
"utils/event" | ||
] | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
require("serializer") --QQQ from du-libs??? | ||
local serializer = { | ||
Serialize = serialize, | ||
Deserialize = deserialize | ||
} | ||
---@module "interface.Device" | ||
|
||
---@alias CommQueue { queue:string[], waitingForReply:boolean, seq:integer } | ||
---@alias ScreenLink {setScriptInput:fun(string), clearScriptOutput:fun(), getScriptOutput:fun():string} | ||
---@alias Renderer {setOutput:fun(string), getInput:fun():string} | ||
---@alias StreamData {output:CommQueue, input:CommQueue, lastReceived:number} | ||
|
||
---@class Stream | ||
---@field New fun(device:Device, parent:DataReceiver, timeout:number):Stream | ||
---@field Tick fun() | ||
---@field Write fun(data:table|string) | ||
---@field WaitingToSend fun():boolean | ||
|
||
--[[ | ||
Data format: | ||
#remaining_chucks|seq|cmd|payload | ||
Where: | ||
- remaining_chunks is a 2-digit integer indicating how many chunks remains to complete the message. 0 means the last chuck. | ||
- seq is a single digit seqence number, used to ensure we don't read the same data twice. It wraps around at 9. | ||
- cmd is a two digit integer indicating what to do with the data | ||
- payload is the actual payload, if any | ||
]] | ||
local headerSize = 1 -- # | ||
+ 2 -- remaining_chucks | ||
+ 1 -- | | ||
+ 1 -- seq | ||
+ 1 -- | | ||
+ 2 -- cmd | ||
+ 1 -- | | ||
|
||
---@enum StreamCommand | ||
local Command = { | ||
Reset = 0, | ||
Poll = 1, | ||
Ack = 2, | ||
Data = 3, | ||
} | ||
|
||
---Represents a stream between two entities. | ||
local Stream = {} | ||
Stream.__index = Stream | ||
|
||
---Create a new Stream | ||
---@param device Device | ||
---@param parent DataReceiver | ||
---@param timeout number The amount of time to wait for a reply before considering the connection broken. | ||
---@return Stream | ||
function Stream.New(device, parent, timeout) -- QQQ Block size as argument or enum | ||
local s = {} | ||
local blockSize = 1024 - headerSize -- Game allows max 1024 bytes in buffers | ||
|
||
---@diagnostic disable-next-line: undefined-global | ||
local getTime = getTime or system.getUtcTime | ||
|
||
device.Clear() | ||
|
||
---@type StreamData | ||
local streamData = { | ||
input = { queue = {}, waitingForReply = false, seq = 0 }, | ||
output = { queue = {}, waitingForReply = false, seq = 0 }, | ||
lastReceived = getTime() | ||
} | ||
|
||
local input = streamData.input | ||
local output = streamData.output | ||
|
||
---Assembles the package | ||
---@param payload string | ||
local function assemblePackage(payload) | ||
local queue = input.queue | ||
|
||
if #queue == 0 then | ||
table.insert(queue, "") | ||
end | ||
queue[#queue] = queue[#queue] .. payload | ||
end | ||
|
||
---Completes a transmission | ||
---@param count number | ||
local function completeTransmission(count) | ||
if count == 0 then | ||
local queue = input.queue | ||
|
||
local deserialized = serializer.Deserialize(queue[#queue]) | ||
|
||
parent.OnData(deserialized) | ||
-- Last part, begin new data | ||
queue[1] = "" | ||
end | ||
end | ||
|
||
local function sameInput(commQueue, seq) | ||
if seq == commQueue.seq then | ||
return true | ||
end | ||
|
||
commQueue.seq = seq | ||
return false | ||
end | ||
|
||
---Creates a block | ||
---@param blockCount integer | ||
---@param commQueue CommQueue | ||
---@param cmd StreamCommand | ||
---@param payload string? | ||
---@return string | ||
local function createBlock(blockCount, commQueue, cmd, payload) | ||
commQueue.seq = (commQueue.seq + 1) | ||
if commQueue.seq > 9 then | ||
commQueue.seq = 0 | ||
end | ||
|
||
payload = payload or "" | ||
local b = string.format("#%0.2d|%0.1d|%0.2d|%s", blockCount, commQueue.seq, cmd, payload) | ||
return b | ||
end | ||
|
||
---Reads incoming data | ||
---@return StreamCommand|nil #Command | ||
---@return number #Packet count | ||
---@return string #Payload | ||
local function readData() | ||
local r = device.Read() | ||
|
||
local count, seq, cmd, payload = r:match("^#(%d+)|(%d)|(%d+)|(.*)$") | ||
|
||
payload = payload or "" | ||
local validPacket = count and cmd | ||
if validPacket then | ||
cmd = tonumber(cmd) | ||
count = tonumber(count) or 0 | ||
validPacket = validPacket and cmd and count | ||
end | ||
|
||
if not validPacket then | ||
return nil, 0, "" | ||
end | ||
|
||
-- Since we can't clear the input when running in RenderScript, we have to rely on the sequence number to prevent duplicate data. | ||
if sameInput(input, seq) then | ||
return nil, 0, "" | ||
end | ||
|
||
return cmd, count, payload | ||
end | ||
|
||
---Call this function in OnUpdate | ||
function s.Tick() | ||
local cmd, count, payload = readData() | ||
|
||
-- Did we get any input? | ||
if cmd then | ||
parent.OnTimeout(false, s) | ||
streamData.lastReceived = getTime() | ||
|
||
if device.IsController() then | ||
if cmd == Command.Data then | ||
assemblePackage(payload) | ||
completeTransmission(count) | ||
end | ||
-- No need to handle ACK, it's just a trigger to move on. | ||
output.waitingForReply = false | ||
else | ||
local sendAck = false | ||
|
||
if cmd == Command.Poll or cmd == Command.Data then | ||
if cmd == Command.Data then | ||
assemblePackage(payload) | ||
completeTransmission(count) | ||
end | ||
|
||
-- Send either ACK or actual data as a reply | ||
if #output.queue > 0 then | ||
device.Send(table.remove(output.queue, 1)) | ||
else | ||
sendAck = true | ||
end | ||
elseif cmd == Command.Reset then | ||
output.queue = {} | ||
output.waitingForReply = false | ||
input.queue = {} | ||
input.waitingForReply = false | ||
sendAck = true | ||
end | ||
|
||
if sendAck then | ||
device.Send(createBlock(0, output, Command.Ack)) | ||
end | ||
end | ||
end | ||
|
||
if getTime() - streamData.lastReceived >= timeout then | ||
parent.OnTimeout(true, s) | ||
streamData.lastReceived = getTime() -- Reset to trigger again | ||
output.queue = {} | ||
output.waitingForReply = false | ||
end | ||
|
||
if device.IsController() and not output.waitingForReply then | ||
if #output.queue == 0 then | ||
device.Send(createBlock(0, output, Command.Poll)) | ||
output.waitingForReply = true | ||
else | ||
device.Send(table.remove(output.queue, 1)) | ||
output.waitingForReply = true | ||
end | ||
end | ||
end | ||
|
||
---Write the data to the stream | ||
---@param dataToSend table|string | ||
function s.Write(dataToSend) | ||
local data = serializer.Serialize(dataToSend) | ||
local blockCount = math.ceil(data:len() / blockSize) - 1 | ||
|
||
while data:len() > blockSize - headerSize do | ||
local part = data:sub(1, blockSize) | ||
data = data:sub(blockSize + 1) | ||
table.insert(output.queue, createBlock(blockCount, output, Command.Data, part)) | ||
blockCount = blockCount - 1 | ||
end | ||
|
||
if data:len() > 0 then | ||
table.insert(output.queue, createBlock(blockCount, output, Command.Data, data)) | ||
end | ||
end | ||
|
||
---Returns true if there is data waiting to be sent. Good for holding off additional write. | ||
---@return boolean | ||
function s.WaitingToSend() return #output.queue > 0 end | ||
|
||
return setmetatable(s, Stream) | ||
end | ||
|
||
return Stream |
Oops, something went wrong.