136 lines
3.8 KiB
Lua
136 lines
3.8 KiB
Lua
|
_G.node = {
|
||
|
chipid = function() return 12345678 end
|
||
|
}
|
||
|
|
||
|
_G.file = {
|
||
|
exists = function() return true end,
|
||
|
open = function()
|
||
|
return {
|
||
|
readline = function(_) return nil end,
|
||
|
close = function() end,
|
||
|
}
|
||
|
end,
|
||
|
}
|
||
|
|
||
|
_G.now = 0 -- current simulated time in seconds
|
||
|
|
||
|
-- tracks the value of the pin by elapsed time
|
||
|
-- a value of 0 means LOW, 1 means HIGH and everything in between indicates the duty cycle of pwm
|
||
|
_G.pinByTime ={
|
||
|
data = {},
|
||
|
set = function(self, pin, value)
|
||
|
local time = _G.now
|
||
|
if time - math.floor(time) >= 0.5 then
|
||
|
time = math.ceil(time)
|
||
|
else
|
||
|
time = math.floor(time)
|
||
|
end
|
||
|
|
||
|
self.data[pin] = self.data[pin] or {}
|
||
|
self.data[pin][time] = value
|
||
|
end,
|
||
|
get = function(self, pin, time)
|
||
|
local closestTime
|
||
|
local value
|
||
|
for theTime, theValue in pairs(self.data[pin]) do
|
||
|
if theTime <= time and (closestTime == nil or closestTime < theTime) then
|
||
|
closestTime = theTime
|
||
|
value = theValue
|
||
|
end
|
||
|
end
|
||
|
return value
|
||
|
end,
|
||
|
print = function(self, pin)
|
||
|
for k,v in pairs(self.data[pin]) do
|
||
|
print(k, v)
|
||
|
end
|
||
|
end,
|
||
|
}
|
||
|
|
||
|
_G.gpio = {
|
||
|
OUTPUT = "output",
|
||
|
HIGH = 1,
|
||
|
LOW = 0,
|
||
|
modeByPin = {},
|
||
|
mode = function(pin, mode)
|
||
|
if mode ~= _G.gpio.OUTPUT then
|
||
|
error("Only gpio as output pins are supported by the mock.")
|
||
|
end
|
||
|
_G.gpio.modeByPin[pin] = mode
|
||
|
end,
|
||
|
write = function(pin, level)
|
||
|
_G.pinByTime:set(pin, level)
|
||
|
end
|
||
|
}
|
||
|
_G.pwm2 = {
|
||
|
start = function() end,
|
||
|
pulsePeriodByPin = {},
|
||
|
setup_pin_hz = function(pin, freqAsHz, pulsePeriod, initialDuty)
|
||
|
if (freqAsHz < 100) then
|
||
|
error("frequencies lower as 100Hz are not supported by the mock. We just assume pwm is used to dim LEDs")
|
||
|
end
|
||
|
_G.pwm2.pulsePeriodByPin[pin] = pulsePeriod
|
||
|
_G.pinByTime:set(pin, initialDuty / pulsePeriod)
|
||
|
end,
|
||
|
set_duty = function(pin, duty)
|
||
|
if _G.pwm2.pulsePeriodByPin[pin] == nil then
|
||
|
error("Pin " .. pin .. " has not been set up for pwm")
|
||
|
end
|
||
|
_G.pinByTime:set(pin, duty / _G.pwm2.pulsePeriodByPin[pin])
|
||
|
end
|
||
|
}
|
||
|
_G.tmr = {
|
||
|
ALARM_AUTO = "auto",
|
||
|
create = function()
|
||
|
local maxSimTime = 3000 -- abort the mock simulation after this many seconds
|
||
|
local timerActive = false
|
||
|
return {
|
||
|
unregister = function()
|
||
|
timerActive = false
|
||
|
end,
|
||
|
alarm = function(self, delay, type, func)
|
||
|
timerActive = true
|
||
|
if type ~= _G.tmr.ALARM_AUTO then
|
||
|
error("only type ALARM_AUTO is supported by the mock.")
|
||
|
end
|
||
|
|
||
|
_G.now = 0
|
||
|
while timerActive and _G.now <= maxSimTime do
|
||
|
_G.now = _G.now + delay
|
||
|
func()
|
||
|
end
|
||
|
timerActive = false
|
||
|
_G.now = 0
|
||
|
end
|
||
|
}
|
||
|
end
|
||
|
}
|
||
|
|
||
|
_G.ws2812 = {
|
||
|
data = {},
|
||
|
MODE_SINGLE = "single",
|
||
|
init = function(mode)
|
||
|
if mode ~= "single" then
|
||
|
error("Only MODE_SINGLE is supported by the ws2812 mock", 2)
|
||
|
end
|
||
|
end,
|
||
|
write = function(data)
|
||
|
local time = _G.now
|
||
|
if time - math.floor(time) >= 0.5 then
|
||
|
time = math.ceil(time)
|
||
|
else
|
||
|
time = math.floor(time)
|
||
|
end
|
||
|
_G.ws2812.data[time] = data
|
||
|
end,
|
||
|
getDataAt = function(self, time)
|
||
|
local data = self.data[time]
|
||
|
if data == nil then return nil end
|
||
|
--@TODO: table.pack would be the way to go in Lua5.3
|
||
|
local dataStream = {}
|
||
|
for i=1,string.len(data) do
|
||
|
table.insert(dataStream, data:byte(i))
|
||
|
end
|
||
|
return dataStream
|
||
|
end,
|
||
|
}
|