Merge branch 'master' of https://github.com/C3MA/Wordclock
This commit is contained in:
commit
5f4e2afc35
144
displayword.lua
144
displayword.lua
@ -1,82 +1,126 @@
|
||||
-- Module filling a buffer, sent to the LEDs
|
||||
|
||||
function updateColor(data)
|
||||
if (data.usedCharacters <= data.charsPerMinute) then
|
||||
if (data.words.min1 == 1 or data.words.min2 == 1 or data.words.min3 == 1 or data.words.min4 == 1) then
|
||||
function updateColor(data, inverseRow, characters2draw)
|
||||
if (inverseRow == nil) then
|
||||
inverseRow=false
|
||||
end
|
||||
-- special case, and there are exactly 4 words to display (so each word for each minute)
|
||||
if (not inverseRow) then -- nomral row
|
||||
if (data.drawnCharacters < data.charsPerMinute) then
|
||||
return data.colorFg
|
||||
elseif (data.drawnCharacters < data.charsPerMinute*2) then
|
||||
return data.colorMin1
|
||||
else
|
||||
return data.colorFg
|
||||
end
|
||||
elseif (data.usedCharacters <= data.charsPerMinute*2) then
|
||||
if (data.words.min2 == 1 or data.words.min3 == 1 or data.words.min4 == 1) then
|
||||
elseif (data.drawnCharacters < data.charsPerMinute*3) then
|
||||
return data.colorMin2
|
||||
else
|
||||
return data.colorFg
|
||||
end
|
||||
elseif (data.usedCharacters <= data.charsPerMinute*3) then
|
||||
if (data.words.min3 == 1 or data.words.min4 == 1) then
|
||||
elseif (data.drawnCharacters > data.charsPerMinute*4) then
|
||||
return data.colorMin3
|
||||
else
|
||||
return data.colorFg
|
||||
end
|
||||
elseif (data.usedCharacters > data.charsPerMinute*3) then
|
||||
if (data.words.min4 == 1) then
|
||||
elseif (data.drawnCharacters > data.charsPerMinute*5) then
|
||||
return data.colorMin4
|
||||
else
|
||||
return data.colorFg
|
||||
end
|
||||
else -- inverse row
|
||||
--FIXME magic missing to start on the left side
|
||||
if (data.drawnCharacters < data.charsPerMinute) then
|
||||
return data.colorMin1
|
||||
elseif (data.drawnCharacters < data.charsPerMinute*2) then
|
||||
return data.colorMin2
|
||||
elseif (data.drawnCharacters < data.charsPerMinute*3) then
|
||||
return data.colorMin3
|
||||
elseif (data.drawnCharacters > data.charsPerMinute*4) then
|
||||
return data.colorMin4
|
||||
else
|
||||
return data.colorFg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function drawLEDs(data, numberNewChars)
|
||||
function drawLEDs(data, numberNewChars, inverseRow)
|
||||
if (inverseRow == nil) then
|
||||
inverseRow=false
|
||||
end
|
||||
if (numberNewChars == nil) then
|
||||
numberNewChars=0
|
||||
end
|
||||
print(tostring(numberNewChars) .. " charactes " .. tostring(data.charsPerMinute) .. " per minute; " .. tonumber(data.drawnCharacters) .. " used characters")
|
||||
local tmpBuf=nil
|
||||
for i=1,numberNewChars do
|
||||
if (tmpBuf == nil) then
|
||||
tmpBuf = updateColor(data)
|
||||
tmpBuf = updateColor(data, inverseRow, numberNewChars)
|
||||
else
|
||||
tmpBuf=tmpBuf .. updateColor(data)
|
||||
tmpBuf=tmpBuf .. updateColor(data, inverseRow, numberNewChars)
|
||||
end
|
||||
data.usedCharacters=data.usedCharacters+1
|
||||
|
||||
data.drawnCharacters=data.drawnCharacters+1
|
||||
end
|
||||
data.drawnWords=data.drawnWords+1
|
||||
return tmpBuf
|
||||
end
|
||||
|
||||
-- Utility function for round
|
||||
function round(num)
|
||||
under = math.floor(num)
|
||||
upper = math.floor(num) + 1
|
||||
underV = -(under - num)
|
||||
upperV = upper - num
|
||||
if (upperV > underV) then
|
||||
return under
|
||||
else
|
||||
return upper
|
||||
end
|
||||
end
|
||||
|
||||
-- Module displaying of the words
|
||||
function generateLEDs(words, colorFg, colorMin1, colorMin2, colorMin3, colorMin4, characters)
|
||||
function generateLEDs(words, colorForground, colorMin1, colorMin2, colorMin3, colorMin4, characters)
|
||||
-- Set the local variables needed for the colored progress bar
|
||||
data={}
|
||||
data.charsPerMinute=math.floor(characters/3) -- devide by three (Minute 1 to Minute 3, Minute 4 takes the last chars)
|
||||
|
||||
local minutes=1
|
||||
if (words.min1 == 1) then
|
||||
minutes = minutes + 1
|
||||
elseif (words.min2 == 1) then
|
||||
minutes = minutes + 2
|
||||
elseif (words.min3 == 1) then
|
||||
minutes = minutes + 3
|
||||
elseif (words.min4 == 1) then
|
||||
minutes = minutes + 4
|
||||
end
|
||||
data.charsPerMinute = round( (characters / minutes) )
|
||||
|
||||
-- devide by five (Minute 0, Minute 1 to Minute 4 takes the last chars)
|
||||
print("Minutes : " .. tostring(minutes) .. " Char minutes: " .. tostring(data.charsPerMinute) )
|
||||
data.words=words
|
||||
data.colorFg=colorFg
|
||||
data.colorFg=colorForground
|
||||
data.colorMin1=colorMin1
|
||||
data.colorMin2=colorMin2
|
||||
data.colorMin3=colorMin3
|
||||
data.colorMin4=colorMin4
|
||||
data.usedCharacters=0
|
||||
data.drawnCharacters=0
|
||||
data.drawnWords=0
|
||||
data.amountWords=display_countwords_de(words)
|
||||
local charsPerLine=11
|
||||
-- Space / background has no color by default
|
||||
local space=string.char(0,0,0)
|
||||
-- update the background color, if set
|
||||
if (colorBg ~= nil) then
|
||||
space = colorBg
|
||||
end
|
||||
-- set FG to fix value:
|
||||
colorFg = string.char(255,255,255)
|
||||
|
||||
-- Set the foreground color as the default color
|
||||
local buf=colorFg
|
||||
|
||||
-- line 1----------------------------------------------
|
||||
if (words.itis == 1) then
|
||||
if (words.it==1) then
|
||||
buf=drawLEDs(data,2) -- ES
|
||||
print(tostring(buf))
|
||||
else
|
||||
buf=space:rep(2)
|
||||
end
|
||||
-- K fill character
|
||||
buf=buf .. space:rep(1)
|
||||
if (words.is == 1) then
|
||||
buf=buf .. drawLEDs(data,3) -- IST
|
||||
else
|
||||
buf=buf .. space:rep(3)
|
||||
end
|
||||
-- L fill character
|
||||
buf=buf .. space:rep(1)
|
||||
else
|
||||
buf=space:rep(7)
|
||||
end
|
||||
if (words.fiveMin== 1) then
|
||||
buf= buf .. drawLEDs(data,4) -- FUENF
|
||||
else
|
||||
@ -84,12 +128,12 @@ function generateLEDs(words, colorFg, colorMin1, colorMin2, colorMin3, colorMin4
|
||||
end
|
||||
-- line 2-- even row (so inverted) --------------------
|
||||
if (words.twenty == 1) then
|
||||
buf= buf .. drawLEDs(data,7) -- ZWANZIG
|
||||
buf= buf .. drawLEDs(data,7,true) -- ZWANZIG
|
||||
else
|
||||
buf= buf .. space:rep(7)
|
||||
end
|
||||
if (words.tenMin == 1) then
|
||||
buf= buf .. drawLEDs(data,4) -- ZEHN
|
||||
buf= buf .. drawLEDs(data,4,true) -- ZEHN
|
||||
else
|
||||
buf= buf .. space:rep(4)
|
||||
end
|
||||
@ -105,12 +149,12 @@ function generateLEDs(words, colorFg, colorMin1, colorMin2, colorMin3, colorMin4
|
||||
--line 4-------- even row (so inverted) -------------
|
||||
if (words.before == 1) then
|
||||
buf=buf .. space:rep(2)
|
||||
buf= buf .. drawLEDs(data,3) -- VOR
|
||||
buf= buf .. drawLEDs(data,3,true) -- VOR
|
||||
else
|
||||
buf= buf .. space:rep(5)
|
||||
end
|
||||
if (words.after == 1) then
|
||||
buf= buf .. drawLEDs(data,4) -- NACH
|
||||
buf= buf .. drawLEDs(data,4,true) -- NACH
|
||||
buf= buf .. space:rep(2) -- TG
|
||||
else
|
||||
buf= buf .. space:rep(6)
|
||||
@ -130,19 +174,19 @@ function generateLEDs(words, colorFg, colorMin1, colorMin2, colorMin3, colorMin4
|
||||
end
|
||||
------------even row (so inverted) ---------------------
|
||||
if (words.seven == 1) then
|
||||
buf= buf .. drawLEDs(data,6) -- SIEBEN
|
||||
buf= buf .. drawLEDs(data,6,true) -- SIEBEN
|
||||
buf= buf .. space:rep(5)
|
||||
elseif (words.oneLong == 1) then
|
||||
buf= buf .. space:rep(5)
|
||||
buf= buf .. drawLEDs(data,4) -- EINS
|
||||
buf= buf .. drawLEDs(data,4,true) -- EINS
|
||||
buf= buf .. space:rep(2)
|
||||
elseif (words.one == 1) then
|
||||
buf= buf .. space:rep(6)
|
||||
buf= buf .. drawLEDs(data,3) -- EIN
|
||||
buf= buf .. drawLEDs(data,3,true) -- EIN
|
||||
buf= buf .. space:rep(2)
|
||||
elseif (words.two == 1) then
|
||||
buf= buf .. space:rep(7)
|
||||
buf= buf .. drawLEDs(data,4) -- ZWEI
|
||||
buf= buf .. drawLEDs(data,4,true) -- ZWEI
|
||||
else
|
||||
buf= buf .. space:rep(11)
|
||||
end
|
||||
@ -159,15 +203,15 @@ function generateLEDs(words, colorFg, colorMin1, colorMin2, colorMin3, colorMin4
|
||||
end
|
||||
------------even row (so inverted) ---------------------
|
||||
if (words.four == 1) then
|
||||
buf= buf .. drawLEDs(data,4) -- VIER
|
||||
buf= buf .. drawLEDs(data,4,true) -- VIER
|
||||
buf= buf .. space:rep(7)
|
||||
elseif (words.nine == 1) then
|
||||
buf= buf .. space:rep(4)
|
||||
buf= buf .. drawLEDs(data,4) -- NEUN
|
||||
buf= buf .. drawLEDs(data,4,true) -- NEUN
|
||||
buf= buf .. space:rep(3)
|
||||
elseif (words.eleven == 1) then
|
||||
buf= buf .. space:rep(8)
|
||||
buf= buf .. drawLEDs(data,3) -- ELEVEN
|
||||
buf= buf .. drawLEDs(data,3,true) -- ELEVEN
|
||||
else
|
||||
buf= buf .. space:rep(11)
|
||||
end
|
||||
@ -185,13 +229,13 @@ function generateLEDs(words, colorFg, colorMin1, colorMin2, colorMin3, colorMin4
|
||||
end
|
||||
------------even row (so inverted) ---------------------
|
||||
if (words.clock == 1) then
|
||||
buf= buf .. drawLEDs(data,3) -- UHR
|
||||
buf= buf .. drawLEDs(data,3,true) -- UHR
|
||||
else
|
||||
buf= buf .. space:rep(3)
|
||||
end
|
||||
if (words.six == 1) then
|
||||
buf= buf .. space:rep(2)
|
||||
buf= buf .. drawLEDs(data,5) -- SECHS
|
||||
buf= buf .. drawLEDs(data,5,true) -- SECHS
|
||||
buf= buf .. space:rep(1)
|
||||
else
|
||||
buf= buf .. space:rep(8)
|
||||
@ -218,5 +262,7 @@ function generateLEDs(words, colorFg, colorMin1, colorMin2, colorMin3, colorMin4
|
||||
buf= buf .. space:rep(1)
|
||||
end
|
||||
collectgarbage()
|
||||
|
||||
return buf
|
||||
end
|
||||
|
||||
|
4
init.lua
4
init.lua
@ -7,7 +7,8 @@ counter1=0
|
||||
ws2812.write(string.char(0,0,0):rep(114))
|
||||
tmr.alarm(2, 85, 1, function()
|
||||
counter1=counter1+1
|
||||
ws2812.write(string.char(128,0,0):rep(counter1) .. string.char(0,0,0):rep(MAXLEDS - (counter1*2)) .. string.char(0,0,64):rep(counter1))
|
||||
spaceLeds = math.max(MAXLEDS - (counter1*2), 0)
|
||||
ws2812.write(string.char(128,0,0):rep(counter1) .. string.char(0,0,0):rep(spaceLeds) .. string.char(0,0,64):rep(counter1))
|
||||
end)
|
||||
|
||||
local blacklistfile="init.lua config.lua config.lua.new"
|
||||
@ -54,3 +55,4 @@ tmr.alarm(1, 5000, 0, function()
|
||||
print("No Main file found")
|
||||
end
|
||||
end)
|
||||
print("Init file end reached")
|
||||
|
26
main.lua
26
main.lua
@ -50,14 +50,31 @@ function displayTime()
|
||||
time = getTime(sec, timezoneoffset)
|
||||
words = display_timestat(time.hour, time.minute)
|
||||
|
||||
local charactersOfTime = display_countwords_de(words)
|
||||
local charactersOfTime = display_countcharacters_de(words)
|
||||
local wordsOfTime = display_countwords_de(words)
|
||||
ledBuf = generateLEDs(words, color, color1, color2, color3, color4,
|
||||
charactersOfTime)
|
||||
|
||||
print("Local time : " .. time.year .. "-" .. time.month .. "-" .. time.day .. " " .. time.hour .. ":" .. time.minute .. ":" .. time.second .. " in " .. charactersOfTime .. " chars")
|
||||
print("Local time : " .. time.year .. "-" .. time.month .. "-" .. time.day .. " " .. time.hour .. ":" .. time.minute .. ":" .. time.second .. " in " .. charactersOfTime .. " chars " .. wordsOfTime .. " words")
|
||||
|
||||
-- Write the buffer to the LEDs
|
||||
--if lines 4 to 6 are inverted due to hardware-fuckup, unfuck it here
|
||||
if ((inv46 ~= nil) and (inv46 == "on")) then
|
||||
tempstring = ledBuf:sub(1,99) -- first 33 leds
|
||||
rowend = {44,55,66}
|
||||
for _, startled in ipairs(rowend) do
|
||||
for i = 0,10 do
|
||||
tempstring = tempstring .. ledBuf:sub((startled-i)*3-2,(startled-i)*3)
|
||||
end
|
||||
end
|
||||
tempstring = tempstring .. ledBuf:sub((67*3)-2,ledBuf:len())
|
||||
ws2812.write(tempstring)
|
||||
tempstring=nil
|
||||
else
|
||||
ws2812.write(ledBuf)
|
||||
ledBuf=nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Used for debugging
|
||||
if (clockdebug ~= nil) then
|
||||
@ -68,7 +85,7 @@ function displayTime()
|
||||
end
|
||||
end
|
||||
-- cleanup
|
||||
ledBuf=nil
|
||||
|
||||
words=nil
|
||||
time=nil
|
||||
collectgarbage()
|
||||
@ -115,7 +132,6 @@ function normalOperation()
|
||||
mydofile("webserver")
|
||||
startWebServer()
|
||||
end)
|
||||
|
||||
displayTime()
|
||||
-- Start the time Thread
|
||||
tmr.alarm(1, 20000, 1 ,function()
|
||||
|
1222
os/esptool.py
1222
os/esptool.py
File diff suppressed because it is too large
Load Diff
10
os/flash.sh
10
os/flash.sh
@ -31,6 +31,10 @@ if [ $? -ne 0 ]; then
|
||||
echo "Error reading the MAC -> set the device into the bootloader!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#./esptool.py --port /dev/$DEVICE $BAUD write_flash 0x00000 nodemcu-master-enduser_setup,file,gpio,net,node,rtcfifo,rtcmem,rtctime,sntp,spi,tmr,uart,wifi,ws2812-integer.bin
|
||||
./esptool.py --port /dev/ttyUSB0 $BAUD write_flash 0x00000 0x00000.bin 0x10000 0x10000.bin
|
||||
echo "Flashing the old one"
|
||||
./esptool.py --port /dev/$DEVICE $BAUD write_flash 0x00000 0x00000.bin 0x10000 0x10000.bin
|
||||
sleep 1
|
||||
echo "Flashing the new"
|
||||
./esptool.py --port /dev/$DEVICE $BAUD write_flash -fm dio 0x00000 nodemcu2.bin
|
||||
# 0x3fc000 esp_init_data_default_v08.bin 0x07e000 blank.bin 0x3fe000 blank.bin
|
||||
#./esptool.py --port /dev/$DEVICE $BAUD write_flash 0x00000 0x00000.bin 0x10000 0x10000.bin
|
||||
|
Binary file not shown.
BIN
os/nodemcu2.bin
Normal file
BIN
os/nodemcu2.bin
Normal file
Binary file not shown.
8
simulation/.classpath
Normal file
8
simulation/.classpath
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="libs/luaj-jme-3.0.1.jar" sourcepath="libs/luaj-3.0.1/src"/>
|
||||
<classpathentry kind="lib" path="libs/luaj-jse-3.0.1.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
1
simulation/.gitignore
vendored
Normal file
1
simulation/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/bin/
|
17
simulation/.project
Normal file
17
simulation/.project
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>WS2812Emulation</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
12
simulation/Readme.md
Normal file
12
simulation/Readme.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Simulation
|
||||
|
||||
The simualation should be started with the following arguments at this position:
|
||||
`../init.lua ws28128ClockLayout.txt config.lua`
|
||||
|
||||
# Use it without Eclipse
|
||||
|
||||
Compiling:
|
||||
`javac -d bin/ -cp libs/luaj-jme-3.0.1.jar:libs/luaj-jse-3.0.1.jar $(find src -name '*.java')`
|
||||
|
||||
Running:
|
||||
`java -cp libs/luaj-jme-3.0.1.jar:libs/luaj-jse-3.0.1.jar:bin de.c3ma.ollo.WS2812Simulation ../init.lua ws28128ClockLayout.txt config.lua`
|
15
simulation/config.lua
Normal file
15
simulation/config.lua
Normal file
@ -0,0 +1,15 @@
|
||||
green=0
|
||||
green2=128
|
||||
red=128
|
||||
blue=0
|
||||
|
||||
color=string.char(0, 0, 128)
|
||||
color1=string.char(128, 0, 0)
|
||||
color2=string.char(tonumber(green2*0.8), 0, 0)
|
||||
color3=string.char(tonumber(green2*0.4), 0, 0)
|
||||
color4=string.char(tonumber(green2*0.2), 0, 0)
|
||||
|
||||
colorBg=string.char(0,0,0) -- black is the default background color
|
||||
sntpserverhostname="ptbtime1.ptb.de"
|
||||
timezoneoffset=1
|
||||
|
3
simulation/libs/.gitignore
vendored
Normal file
3
simulation/libs/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
luaj-3.0.1.zip
|
||||
luaj-3.0.1/
|
||||
luaj-sources-3.0.1.jar
|
7
simulation/libs/Readme.md
Normal file
7
simulation/libs/Readme.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Dependencies
|
||||
|
||||
The following file is expected here:
|
||||
`luaj-3.0.1.zip`
|
||||
|
||||
It can be downloaded here:
|
||||
https://sourceforge.net/projects/luaj/files/latest/download
|
BIN
simulation/libs/luaj-jme-3.0.1.jar
Normal file
BIN
simulation/libs/luaj-jme-3.0.1.jar
Normal file
Binary file not shown.
BIN
simulation/libs/luaj-jse-3.0.1.jar
Normal file
BIN
simulation/libs/luaj-jse-3.0.1.jar
Normal file
Binary file not shown.
15
simulation/src/de/c3ma/ollo/LuaSimulation.java
Normal file
15
simulation/src/de/c3ma/ollo/LuaSimulation.java
Normal file
@ -0,0 +1,15 @@
|
||||
package de.c3ma.ollo;
|
||||
|
||||
/**
|
||||
* created at 29.12.2017 - 18:29:07<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public interface LuaSimulation {
|
||||
|
||||
public void rebootTriggered();
|
||||
|
||||
public void setSimulationTime(long timeInMillis);
|
||||
}
|
54
simulation/src/de/c3ma/ollo/LuaThreadTmr.java
Normal file
54
simulation/src/de/c3ma/ollo/LuaThreadTmr.java
Normal file
@ -0,0 +1,54 @@
|
||||
package de.c3ma.ollo;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
/**
|
||||
* created at 29.12.2017 - 18:48:27<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class LuaThreadTmr extends Thread {
|
||||
|
||||
|
||||
private boolean running = true;
|
||||
|
||||
private boolean stopped = false;
|
||||
|
||||
private LuaValue code;
|
||||
|
||||
private final int delay;
|
||||
|
||||
private final int timerNumber;
|
||||
|
||||
public LuaThreadTmr(int timerNumber, LuaValue code, boolean endlessloop, int delay) {
|
||||
this.code = code;
|
||||
this.running = endlessloop;
|
||||
this.delay = delay;
|
||||
this.timerNumber = timerNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
do {
|
||||
Thread.sleep(delay);
|
||||
if (code != null) {
|
||||
code.call();
|
||||
}
|
||||
} while(running);
|
||||
} catch(InterruptedException ie) {
|
||||
System.err.println("[TMR] Timer" + timerNumber + " interrupted");
|
||||
}
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
public boolean isStopped() { return stopped; }
|
||||
|
||||
public void stopThread() {
|
||||
running = false;
|
||||
code = null;
|
||||
}
|
||||
|
||||
}
|
173
simulation/src/de/c3ma/ollo/WS2812Simulation.java
Normal file
173
simulation/src/de/c3ma/ollo/WS2812Simulation.java
Normal file
@ -0,0 +1,173 @@
|
||||
package de.c3ma.ollo;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
import de.c3ma.ollo.mockup.DoFileFunction;
|
||||
import de.c3ma.ollo.mockup.ESP8266File;
|
||||
import de.c3ma.ollo.mockup.ESP8266Net;
|
||||
import de.c3ma.ollo.mockup.ESP8266Node;
|
||||
import de.c3ma.ollo.mockup.ESP8266Time;
|
||||
import de.c3ma.ollo.mockup.ESP8266Tmr;
|
||||
import de.c3ma.ollo.mockup.ESP8266Uart;
|
||||
import de.c3ma.ollo.mockup.ESP8266Wifi;
|
||||
import de.c3ma.ollo.mockup.ESP8266Ws2812;
|
||||
|
||||
/**
|
||||
* created at 28.12.2017 - 13:19:32<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
*
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class WS2812Simulation implements LuaSimulation {
|
||||
|
||||
private Globals globals = JsePlatform.standardGlobals();
|
||||
private ESP8266Tmr espTmr = new ESP8266Tmr();
|
||||
private ESP8266File espFile = new ESP8266File();
|
||||
private ESP8266Node espNode = new ESP8266Node(this);
|
||||
private DoFileFunction doFile = new DoFileFunction(globals);
|
||||
private ESP8266Ws2812 ws2812 = new ESP8266Ws2812();
|
||||
private String scriptName;
|
||||
|
||||
public WS2812Simulation(File sourceFolder) {
|
||||
globals.load(new ESP8266Uart());
|
||||
globals.load(ws2812);
|
||||
globals.load(espTmr);
|
||||
globals.load(espFile);
|
||||
globals.load(espNode);
|
||||
globals.load(new ESP8266Wifi());
|
||||
globals.load(new ESP8266Net());
|
||||
globals.load(new ESP8266Time());
|
||||
globals.set("dofile", doFile);
|
||||
|
||||
try {
|
||||
File tempFile = File.createTempFile("NodemcuSimuFile", "");
|
||||
File tempDir = new File(tempFile.getParent() + File.separator + "Nodemcu" + System.currentTimeMillis());
|
||||
tempDir.mkdir();
|
||||
|
||||
System.out.println("[Nodemcu] Directory is " + tempDir.getAbsolutePath());
|
||||
|
||||
// Copy all files into the temporary folder
|
||||
for (File f : sourceFolder.listFiles()) {
|
||||
Files.copy(f.toPath(), new File(tempDir.getAbsolutePath() + File.separator + f.getName()).toPath());
|
||||
}
|
||||
|
||||
espFile.setWorkingDirectory(tempDir);
|
||||
espNode.setWorkingDirectory(tempDir);
|
||||
doFile.setWorkingDirectory(tempDir);
|
||||
} catch (IOException e) {
|
||||
System.err.println("[Nodemcu] " + e.getMessage());
|
||||
espFile = null;
|
||||
espNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(final String[] args) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (args.length == 0) {
|
||||
printUsage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length >= 1) {
|
||||
File f = new File(args[0]);
|
||||
if (f.exists()) {
|
||||
WS2812Simulation simu = new WS2812Simulation(f.getParentFile());
|
||||
System.out.println("File : " + f.getAbsolutePath());
|
||||
|
||||
if (args.length >= 2) {
|
||||
simu.setWS2812Layout(new File(args[1]));
|
||||
}
|
||||
try {
|
||||
if (args.length >= 3) {
|
||||
File additionalFile = new File(args[2]);
|
||||
if (additionalFile.exists() && (simu.doFile != null)) {
|
||||
|
||||
Files.copy(additionalFile.toPath(), new File(simu.doFile.getWorkingDirectory()
|
||||
+ File.separator + additionalFile.getName()).toPath());
|
||||
System.out.println("Integrate " + additionalFile.getName() + " into simulation");
|
||||
} else {
|
||||
System.err.println("Script " + args[2] + " cannot be found");
|
||||
printUsage();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
if (args.length >= 4) {
|
||||
try {
|
||||
ESP8266Tmr.gTimingFactor = Integer.parseInt(args[3]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
System.err.println("Timing factor not parsable: " + nfe.getMessage());
|
||||
printUsage();
|
||||
}
|
||||
}
|
||||
|
||||
simu.callScript(f.getName());
|
||||
} catch (IOException e) {
|
||||
System.err.println("[Nodemcu] " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printUsage();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setWS2812Layout(File file) {
|
||||
if (file.exists()) {
|
||||
ws2812.setLayout(file, this);
|
||||
} else {
|
||||
throw new RuntimeException("WS2812 Layout: " + file.getAbsolutePath() + " does not exists");
|
||||
}
|
||||
}
|
||||
|
||||
private static void printUsage() {
|
||||
System.out.println("Usage:");
|
||||
System.out.println("one argument required: file to execute.");
|
||||
System.out.println(".e.g: init.lua (ws2812 layout configuration) (additional LUA script) (timing speedup factor)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rebootTriggered() {
|
||||
System.out.println("=================== Reboot in Simulation -> call it again =================");
|
||||
this.espTmr.stopAllTimer();
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
if (this.scriptName != null) {
|
||||
System.out.println("Reexecuting...");
|
||||
callScript(this.scriptName);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void callScript(String filename) {
|
||||
this.scriptName = filename;
|
||||
|
||||
if ((espFile != null) && (espFile.getFileInWorkingDir(filename) != null)) {
|
||||
LuaValue chunk = globals.loadfile(espFile.getFileInWorkingDir(filename).getAbsolutePath());
|
||||
chunk.call();
|
||||
} else {
|
||||
throw new RuntimeException("Copy into temporary folder failed; script not available");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSimulationTime(long timeInMillis) {
|
||||
ESP8266Time.setOverwrittenTime(timeInMillis);
|
||||
}
|
||||
}
|
54
simulation/src/de/c3ma/ollo/mockup/DoFileFunction.java
Normal file
54
simulation/src/de/c3ma/ollo/mockup/DoFileFunction.java
Normal file
@ -0,0 +1,54 @@
|
||||
package de.c3ma.ollo.mockup;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
|
||||
/**
|
||||
* created at 29.12.2017 - 20:23:48<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class DoFileFunction extends OneArgFunction {
|
||||
|
||||
private File workingDir = null;
|
||||
private Globals globals;
|
||||
|
||||
public DoFileFunction(Globals globals) {
|
||||
this.globals = globals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue luaFilename) {
|
||||
String filename = luaFilename.checkjstring();
|
||||
|
||||
System.out.println("[Nodemcu] dofile " + filename);
|
||||
|
||||
File f = new File(workingDir.getAbsolutePath() + File.separator + filename);
|
||||
|
||||
if (f.exists()) {
|
||||
LuaValue chunk = this.globals.loadfile(f.getAbsolutePath());
|
||||
chunk.call();
|
||||
return LuaValue.valueOf(true);
|
||||
} else {
|
||||
return LuaValue.valueOf(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void setWorkingDirectory(File workingDir) {
|
||||
this.workingDir = workingDir;
|
||||
}
|
||||
|
||||
public String getWorkingDirectory() {
|
||||
if (workingDir != null) {
|
||||
return workingDir.getAbsolutePath();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
101
simulation/src/de/c3ma/ollo/mockup/ESP8266File.java
Normal file
101
simulation/src/de/c3ma/ollo/mockup/ESP8266File.java
Normal file
@ -0,0 +1,101 @@
|
||||
package de.c3ma.ollo.mockup;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
|
||||
/**
|
||||
* created at 29.12.2017 - 01:08:53<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class ESP8266File extends TwoArgFunction {
|
||||
|
||||
private File workingDir = null;
|
||||
|
||||
private File openedFile = null;
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
env.checkglobals();
|
||||
final LuaTable file = new LuaTable();
|
||||
file.set("open", new OpenFunction());
|
||||
file.set("list", new ListFunction());
|
||||
file.set("remove", new RemoveFunction());
|
||||
env.set("file", file);
|
||||
env.get("package").get("loaded").set("file", file);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
private class ListFunction extends TwoArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg1, LuaValue arg2) {
|
||||
final LuaTable fileList = new LuaTable();
|
||||
|
||||
if ((workingDir != null) && (workingDir.exists())) {
|
||||
File[] files = workingDir.listFiles();
|
||||
for (File file : files) {
|
||||
fileList.set(file.getName(), file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
return fileList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class OpenFunction extends OneArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue fileName) {
|
||||
|
||||
final String codeFileName = fileName.checkjstring();
|
||||
final File f = new File( workingDir.getAbsolutePath() + File.separator + codeFileName);
|
||||
//System.out.println("[FILE] Loading " + codeFileName);
|
||||
if (f.exists()) {
|
||||
ESP8266File.this.openedFile = f;
|
||||
}
|
||||
|
||||
return LuaValue.valueOf((f.exists()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class RemoveFunction extends OneArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue fileName) {
|
||||
|
||||
final String luaFileName = fileName.checkjstring();
|
||||
System.out.println("[FILE] Removing " + luaFileName);
|
||||
File f = new File(workingDir.getAbsolutePath() + File.separator + fileName);
|
||||
if (f.exists()) {
|
||||
return LuaValue.valueOf(f.delete());
|
||||
} else {
|
||||
return LuaValue.valueOf(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setWorkingDirectory(File workingDir) {
|
||||
this.workingDir = workingDir;
|
||||
}
|
||||
|
||||
public File getFileInWorkingDir(String filename) {
|
||||
File f = new File (workingDir.getAbsolutePath() + File.separator + filename);
|
||||
if (f.exists()) {
|
||||
return f;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
83
simulation/src/de/c3ma/ollo/mockup/ESP8266Net.java
Normal file
83
simulation/src/de/c3ma/ollo/mockup/ESP8266Net.java
Normal file
@ -0,0 +1,83 @@
|
||||
package de.c3ma.ollo.mockup;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
import de.c3ma.ollo.LuaSimulation;
|
||||
|
||||
/**
|
||||
* created at 29.12.2017 - 01:29:40<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class ESP8266Net extends TwoArgFunction {
|
||||
|
||||
public static final int PORTNUMBER_OFFSET = 4000;
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
env.checkglobals();
|
||||
final LuaTable net = new LuaTable();
|
||||
net.set("createServer", new CreateServerFunction());
|
||||
|
||||
//FIXME net.set("send", new SendFunction());
|
||||
net.set("TCP", "TCP");
|
||||
env.set("net", net);
|
||||
env.get("package").get("loaded").set("net", net);
|
||||
return net;
|
||||
}
|
||||
|
||||
private class CreateServerFunction extends OneArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
final LuaTable srv = new LuaTable();
|
||||
srv.set("listen", new ListenFunction());
|
||||
return srv;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ListenFunction extends TwoArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue port, LuaValue function) {
|
||||
int portnumber = port.checkint();
|
||||
LuaFunction onListenFunction = function.checkfunction();
|
||||
|
||||
System.out.println("[Net] listening " + portnumber + "(simulating at " + (PORTNUMBER_OFFSET+ portnumber) + ")");
|
||||
|
||||
try
|
||||
{
|
||||
ServerSocket serverSocket = new ServerSocket(PORTNUMBER_OFFSET+portnumber);
|
||||
serverSocket.setSoTimeout( 60000 ); // Timeout after one minute
|
||||
|
||||
Socket client = serverSocket.accept();
|
||||
|
||||
}
|
||||
catch ( InterruptedIOException iioe )
|
||||
{
|
||||
System.err.println( "Timeout nach einer Minute!" );
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("[Net] server running");
|
||||
return LuaValue.valueOf(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
79
simulation/src/de/c3ma/ollo/mockup/ESP8266Node.java
Normal file
79
simulation/src/de/c3ma/ollo/mockup/ESP8266Node.java
Normal file
@ -0,0 +1,79 @@
|
||||
package de.c3ma.ollo.mockup;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
import de.c3ma.ollo.LuaSimulation;
|
||||
|
||||
/**
|
||||
* created at 29.12.2017 - 01:29:40<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class ESP8266Node extends TwoArgFunction {
|
||||
|
||||
private File workingDir = null;
|
||||
private LuaSimulation nodemcuSimu;
|
||||
|
||||
public ESP8266Node(LuaSimulation nodemcuSimu) {
|
||||
this.nodemcuSimu = nodemcuSimu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
env.checkglobals();
|
||||
final LuaTable node = new LuaTable();
|
||||
node.set("compile", new CompileFunction());
|
||||
node.set("restart", new RestartFunction());
|
||||
env.set("node", node);
|
||||
env.get("package").get("loaded").set("node", node);
|
||||
return node;
|
||||
}
|
||||
|
||||
private class CompileFunction extends OneArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue fileName) {
|
||||
final String codeFileName = fileName.checkjstring();
|
||||
final String compiledFileName = fileName.checkjstring().replace(".lua", ".lc");
|
||||
final File f = new File( workingDir.getAbsolutePath() + File.separator + codeFileName);
|
||||
System.out.println("[Node] Compiling " + compiledFileName);
|
||||
final File outf = new File( workingDir.getAbsolutePath() + File.separator + compiledFileName);
|
||||
if (f.exists()) {
|
||||
//Simply copy the file as .lc file
|
||||
try {
|
||||
Files.copy(f.toPath(), outf.toPath());
|
||||
} catch (IOException e) {
|
||||
return LuaValue.valueOf(false);
|
||||
}
|
||||
}
|
||||
|
||||
return LuaValue.valueOf(f.exists());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class RestartFunction extends ZeroArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call() {
|
||||
System.out.println("[Node] Restart");
|
||||
nodemcuSimu.rebootTriggered();
|
||||
return LuaValue.valueOf(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setWorkingDirectory(File workingDir) {
|
||||
this.workingDir = workingDir;
|
||||
}
|
||||
}
|
102
simulation/src/de/c3ma/ollo/mockup/ESP8266Time.java
Normal file
102
simulation/src/de/c3ma/ollo/mockup/ESP8266Time.java
Normal file
@ -0,0 +1,102 @@
|
||||
package de.c3ma.ollo.mockup;
|
||||
|
||||
import org.luaj.vm2.LuaFunction;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.ThreeArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
/**
|
||||
* created at 29.12.2017 - 00:07:22<br />
|
||||
* creator: ollo<br />
|
||||
* project: Time Emulation<br />
|
||||
*
|
||||
* Simulating the following modules:
|
||||
* Sntp
|
||||
* rtctime
|
||||
*
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class ESP8266Time extends TwoArgFunction {
|
||||
|
||||
private static long gSimulationStartTime = 0;
|
||||
|
||||
private static long gOverwrittenTime = 0;
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
env.checkglobals();
|
||||
final LuaTable sntp = new LuaTable();
|
||||
sntp.set("sync", new SyncFunction());
|
||||
env.set("sntp", sntp);
|
||||
final LuaTable rtctime = new LuaTable();
|
||||
rtctime.set("get", new GetFunction());
|
||||
env.set("rtctime", rtctime);
|
||||
env.get("package").get("loaded").set("sntp", sntp);
|
||||
env.get("package").get("loaded").set("rtctime", rtctime);
|
||||
|
||||
return sntp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a time. If there is no speedup, it is simply the current system time.
|
||||
* Otherwise the time is speedup by the given factor
|
||||
* @return
|
||||
*/
|
||||
private long generateCurrenttime() {
|
||||
if (gSimulationStartTime == 0) {
|
||||
gSimulationStartTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
if (gOverwrittenTime == 0) {
|
||||
/* Time simulation is disabled -> calculate something according to the speedup factor */
|
||||
long time = System.currentTimeMillis();
|
||||
if (ESP8266Tmr.gTimingFactor > 1) {
|
||||
time = gSimulationStartTime + ((time - gSimulationStartTime) * ESP8266Tmr.gTimingFactor);
|
||||
}
|
||||
return time;
|
||||
} else {
|
||||
return gOverwrittenTime;
|
||||
}
|
||||
}
|
||||
|
||||
private class SyncFunction extends ThreeArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue server, LuaValue callbackSuccess, LuaValue callbackFailure) {
|
||||
String serverName = server.checkjstring();
|
||||
LuaFunction cb = callbackSuccess.checkfunction();
|
||||
System.out.println("[SNTP] sync " + serverName);
|
||||
/*FIXME also make it possible to simulate the time */
|
||||
long time = generateCurrenttime();
|
||||
int seconds = (int) (time / 1000);
|
||||
int useconds = (int) (time % 1000);
|
||||
cb.call(LuaValue.valueOf(seconds), LuaValue.valueOf(useconds), LuaValue.valueOf(serverName));
|
||||
return LuaValue.valueOf(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GetFunction extends ZeroArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call() {
|
||||
LuaValue[] v = new LuaValue[2];
|
||||
/*FIXME also make it possible to simulate the time */
|
||||
long time = generateCurrenttime();
|
||||
int seconds = (int) (time / 1000);
|
||||
int useconds = (int) (time % 1000);
|
||||
v[0] = LuaValue.valueOf(seconds);
|
||||
v[1] = LuaValue.valueOf(useconds);
|
||||
return LuaValue.varargsOf(v).arg1();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void setOverwrittenTime(long timeInMillis) {
|
||||
gOverwrittenTime = timeInMillis;
|
||||
}
|
||||
|
||||
}
|
95
simulation/src/de/c3ma/ollo/mockup/ESP8266Tmr.java
Normal file
95
simulation/src/de/c3ma/ollo/mockup/ESP8266Tmr.java
Normal file
@ -0,0 +1,95 @@
|
||||
package de.c3ma.ollo.mockup;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
|
||||
import de.c3ma.ollo.LuaThreadTmr;
|
||||
|
||||
/**
|
||||
* created at 29.12.2017 - 00:07:22<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class ESP8266Tmr extends TwoArgFunction {
|
||||
|
||||
private static final int MAXTHREADS = 7;
|
||||
|
||||
private static LuaThreadTmr[] allThreads = new LuaThreadTmr[MAXTHREADS];
|
||||
|
||||
public static int gTimingFactor = 1;
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
env.checkglobals();
|
||||
final LuaTable tmr = new LuaTable();
|
||||
tmr.set("stop", new stop());
|
||||
tmr.set("alarm", new alarm());
|
||||
env.set("tmr", tmr);
|
||||
env.get("package").get("loaded").set("tmr", tmr);
|
||||
|
||||
/* initialize the Threads */
|
||||
for (Thread t : allThreads) {
|
||||
t = null;
|
||||
}
|
||||
|
||||
return tmr;
|
||||
}
|
||||
|
||||
private boolean stopTmr(int i) {
|
||||
if (allThreads[i] != null) {
|
||||
allThreads[i].stopThread();
|
||||
allThreads[i] = null;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class stop extends OneArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
final int timerNumer = arg.toint();
|
||||
System.out.println("[TMR] Timer" + timerNumer + " stopped");
|
||||
return LuaValue.valueOf(stopTmr(timerNumer));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class alarm extends VarArgFunction {
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
if (varargs.narg()== 4) {
|
||||
final int timerNumer = varargs.arg(1).toint();
|
||||
final byte endlessloop = varargs.arg(3).tobyte();
|
||||
final int delay = varargs.arg(2).toint();
|
||||
final LuaValue code = varargs.arg(4);
|
||||
System.out.println("[TMR] Timer" + timerNumer );
|
||||
|
||||
if ((timerNumer < 0) || (timerNumer > timerNumer)) {
|
||||
return LuaValue.error("[TMR] Timer" + timerNumer + " is not available, choose 0 to 6");
|
||||
}
|
||||
|
||||
if (stopTmr(timerNumer)) {
|
||||
System.err.println("[TMR] Timer" + timerNumer + " stopped");
|
||||
}
|
||||
|
||||
/* The cycletime is at least 1 ms */
|
||||
allThreads[timerNumer] = new LuaThreadTmr(timerNumer, code, (endlessloop == 1), Math.max(delay / gTimingFactor, 1));
|
||||
allThreads[timerNumer].start();
|
||||
}
|
||||
return LuaValue.valueOf(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopAllTimer() {
|
||||
for (int i = 0; i < allThreads.length; i++) {
|
||||
stopTmr(i);
|
||||
}
|
||||
}
|
||||
}
|
38
simulation/src/de/c3ma/ollo/mockup/ESP8266Uart.java
Normal file
38
simulation/src/de/c3ma/ollo/mockup/ESP8266Uart.java
Normal file
@ -0,0 +1,38 @@
|
||||
package de.c3ma.ollo.mockup;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.VarArgFunction;
|
||||
|
||||
/**
|
||||
* created at 28.12.2017 - 23:05:05<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class ESP8266Uart extends TwoArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
env.checkglobals();
|
||||
final LuaTable uart = new LuaTable();
|
||||
uart.set("setup", new setup());
|
||||
env.set("uart", uart);
|
||||
env.get("package").get("loaded").set("uart", uart);
|
||||
return uart;
|
||||
}
|
||||
|
||||
private class setup extends VarArgFunction {
|
||||
public Varargs invoke(Varargs varargs) {
|
||||
if (varargs.narg()== 6) {
|
||||
System.out.println("[UART] " + varargs.arg(2) + " " + varargs.arg(3)
|
||||
+ ((varargs.arg(4).checkint() > 0) ? "Y" : "N")
|
||||
+ varargs.arg(5));
|
||||
}
|
||||
return LuaValue.valueOf(true);
|
||||
}
|
||||
}
|
||||
}
|
81
simulation/src/de/c3ma/ollo/mockup/ESP8266Wifi.java
Normal file
81
simulation/src/de/c3ma/ollo/mockup/ESP8266Wifi.java
Normal file
@ -0,0 +1,81 @@
|
||||
package de.c3ma.ollo.mockup;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
import de.c3ma.ollo.LuaSimulation;
|
||||
|
||||
/**
|
||||
* created at 29.12.2017 - 01:29:40<br />
|
||||
* creator: ollo<br />
|
||||
* project: WifiEmulation<br />
|
||||
* $Id: $<br />
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class ESP8266Wifi extends TwoArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
env.checkglobals();
|
||||
final LuaTable wifi = new LuaTable();
|
||||
wifi.set("setmode", new SetModeFunction());
|
||||
final LuaTable ap = new LuaTable();
|
||||
ap.set("config", new ConfigFunction());
|
||||
wifi.set("ap", ap);
|
||||
final LuaTable sta = new LuaTable();
|
||||
sta.set("status", new StatusFunction());
|
||||
sta.set("getip", new GetIpFunction());
|
||||
wifi.set("sta", sta);
|
||||
wifi.set("SOFTAP", "SOFTAP");
|
||||
wifi.set("STATION", "STATION");
|
||||
env.set("wifi", wifi);
|
||||
env.get("package").get("loaded").set("wifi", wifi);
|
||||
return wifi;
|
||||
}
|
||||
|
||||
private class SetModeFunction extends OneArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue apmode) {
|
||||
final String APmodeString = apmode.checkjstring();
|
||||
System.out.println("[Wifi] set mode " + APmodeString);
|
||||
return LuaValue.valueOf(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ConfigFunction extends OneArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
System.out.println("[Wifi] config");
|
||||
return LuaValue.valueOf(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class StatusFunction extends ZeroArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call() {
|
||||
return LuaValue.valueOf(5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GetIpFunction extends ZeroArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call() {
|
||||
return LuaValue.valueOf("127.0.0.1");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
88
simulation/src/de/c3ma/ollo/mockup/ESP8266Ws2812.java
Normal file
88
simulation/src/de/c3ma/ollo/mockup/ESP8266Ws2812.java
Normal file
@ -0,0 +1,88 @@
|
||||
package de.c3ma.ollo.mockup;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.luaj.vm2.LuaString;
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
import de.c3ma.ollo.LuaSimulation;
|
||||
import de.c3ma.ollo.mockup.ui.WS2812Layout;
|
||||
|
||||
/**
|
||||
* created at 28.12.2017 - 23:34:04<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
*
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class ESP8266Ws2812 extends TwoArgFunction {
|
||||
|
||||
private static WS2812Layout layout = null;
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
env.checkglobals();
|
||||
final LuaTable ws2812 = new LuaTable();
|
||||
ws2812.set("init", new init());
|
||||
ws2812.set("write", new write());
|
||||
env.set("ws2812", ws2812);
|
||||
env.get("package").get("loaded").set("ws2812", ws2812);
|
||||
return ws2812;
|
||||
}
|
||||
|
||||
private class init extends ZeroArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call() {
|
||||
System.out.println("[WS2812] init");
|
||||
return LuaValue.valueOf(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class write extends OneArgFunction {
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
if (arg.isstring()) {
|
||||
LuaString jstring = arg.checkstring();
|
||||
final int length = jstring.rawlen();
|
||||
if ((length % 3) == 0) {
|
||||
final byte[] array = jstring.m_bytes;
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < length; i += 3) {
|
||||
if (ESP8266Ws2812.layout != null) {
|
||||
int r = array[i + 0]+(Byte.MIN_VALUE*-1);
|
||||
int b = array[i + 1]+(Byte.MIN_VALUE*-1);
|
||||
int g = array[i + 2]+(Byte.MIN_VALUE*-1);
|
||||
ESP8266Ws2812.layout.updateLED(i / 3, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (ESP8266Ws2812.layout == null) {
|
||||
System.out.println("[WS2812] write length:" + length);
|
||||
} else {
|
||||
}
|
||||
}
|
||||
return LuaValue.valueOf(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLayout(File file, LuaSimulation nodemcuSimu) {
|
||||
if (ESP8266Ws2812.layout == null) {
|
||||
ESP8266Ws2812.layout = WS2812Layout.parse(file, nodemcuSimu);
|
||||
}
|
||||
}
|
||||
}
|
301
simulation/src/de/c3ma/ollo/mockup/ui/WS2812Layout.java
Normal file
301
simulation/src/de/c3ma/ollo/mockup/ui/WS2812Layout.java
Normal file
@ -0,0 +1,301 @@
|
||||
package de.c3ma.ollo.mockup.ui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
import de.c3ma.ollo.LuaSimulation;
|
||||
|
||||
/**
|
||||
* created at 02.01.2018 - 12:57:02<br />
|
||||
* creator: ollo<br />
|
||||
* project: WS2812Emulation<br />
|
||||
* $Id: $<br />
|
||||
*
|
||||
* @author ollo<br />
|
||||
*/
|
||||
public class WS2812Layout extends JFrame {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -6815557232118826140L;
|
||||
|
||||
private ArrayList<String> mLines = new ArrayList<String>();
|
||||
private int mColumn = 0;
|
||||
private int mRow = 0;
|
||||
private Element[][] mElements;
|
||||
|
||||
private LuaSimulation nodemcuSimu;
|
||||
|
||||
public WS2812Layout(LuaSimulation nodemcuSimu) {
|
||||
this.nodemcuSimu = nodemcuSimu;
|
||||
}
|
||||
|
||||
public static WS2812Layout parse(File file, LuaSimulation nodemcuSimu) {
|
||||
WS2812Layout layout = null;
|
||||
try {
|
||||
BufferedReader br = new BufferedReader(new FileReader(file));
|
||||
try {
|
||||
String line = br.readLine();
|
||||
if (line != null) {
|
||||
layout = new WS2812Layout(nodemcuSimu);
|
||||
}
|
||||
|
||||
while (line != null) {
|
||||
if (!line.startsWith("#")) {
|
||||
layout.mLines.add(line);
|
||||
layout.mRow++;
|
||||
layout.mColumn = Math.max(layout.mColumn, line.length());
|
||||
}
|
||||
/* get the next line */
|
||||
line = br.readLine();
|
||||
}
|
||||
|
||||
/* parse each line */
|
||||
layout.parse();
|
||||
layout.createAndDisplayGUI();
|
||||
} finally {
|
||||
if (br != null) {
|
||||
br.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
|
||||
private void createAndDisplayGUI() {
|
||||
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
|
||||
JPanel contentPane = new JPanel();
|
||||
contentPane.setLayout(new BorderLayout());
|
||||
contentPane.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 2));
|
||||
|
||||
JPanel ledPanel = new JPanel();
|
||||
ledPanel.setBackground(Color.BLACK);
|
||||
ledPanel.setLayout(new GridLayout(this.mRow, this.mColumn, 10, 10));
|
||||
for (int i = 0; i < this.mRow; i++) {
|
||||
for (int j = 0; j < this.mColumn; j++) {
|
||||
if (this.mElements[i][j] != null) {
|
||||
ledPanel.add(this.mElements[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
contentPane.add(ledPanel, BorderLayout.CENTER);
|
||||
|
||||
JPanel bottomPanel = new JPanel();
|
||||
|
||||
final JTextField dateTime = new JTextField("yyyy-mm-dd HH:MM:SS");
|
||||
dateTime.getDocument().addDocumentListener(new DocumentListener() {
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
warn();
|
||||
}
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
warn();
|
||||
}
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
warn();
|
||||
}
|
||||
|
||||
public void warn() {
|
||||
final String pattern = "(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})";
|
||||
final String current = dateTime.getText();
|
||||
|
||||
if (current.length() <=0) {
|
||||
/* color "nothing" green */
|
||||
dateTime.setForeground(Color.GREEN);
|
||||
/* disable the time simulation */
|
||||
nodemcuSimu.setSimulationTime(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current.matches(pattern)) {
|
||||
dateTime.setForeground(Color.RED);
|
||||
} else {
|
||||
dateTime.setForeground(Color.BLACK);
|
||||
Pattern dateTimePattern = Pattern.compile(pattern);
|
||||
Matcher matcher = dateTimePattern.matcher(current);
|
||||
int year=0;
|
||||
int month=0;
|
||||
int day=0;
|
||||
int hour=0;
|
||||
int minute=0;
|
||||
int second=0;
|
||||
matcher.find();
|
||||
for (int g = 1; g <= matcher.groupCount(); g++) {
|
||||
switch(g) {
|
||||
case 1: /* Year */
|
||||
year = Integer.parseInt(matcher.group(g));
|
||||
break;
|
||||
case 2: /* Month */
|
||||
month = Integer.parseInt(matcher.group(g));
|
||||
break;
|
||||
case 3: /* Day */
|
||||
day = Integer.parseInt(matcher.group(g));
|
||||
break;
|
||||
case 4: /* Hour */
|
||||
hour = Integer.parseInt(matcher.group(g));
|
||||
break;
|
||||
case 5: /* Minute */
|
||||
minute = Integer.parseInt(matcher.group(g));
|
||||
break;
|
||||
case 6: /* Second */
|
||||
second = Integer.parseInt(matcher.group(g));
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.out.println("[GUI] Set time to: " + year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
|
||||
GregorianCalendar gc = new GregorianCalendar(year, month, day, hour, minute, second);
|
||||
|
||||
nodemcuSimu.setSimulationTime(gc.getTimeInMillis());
|
||||
}
|
||||
}
|
||||
});
|
||||
bottomPanel.add(dateTime);
|
||||
|
||||
final JButton btnSetCurrentTime = new JButton("Set time");
|
||||
btnSetCurrentTime.setActionCommand("Set time");
|
||||
btnSetCurrentTime.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent ae) {
|
||||
JButton but = (JButton) ae.getSource();
|
||||
if (but.equals(btnSetCurrentTime)) {
|
||||
GregorianCalendar gc = new GregorianCalendar();
|
||||
dateTime.setText(String.format("%d-%02d-%02d %02d:%02d:%02d",
|
||||
gc.get(Calendar.YEAR), gc.get(Calendar.MONTH), gc.get(Calendar.DAY_OF_MONTH),
|
||||
gc.get(Calendar.HOUR_OF_DAY), gc.get(Calendar.MINUTE), gc.get(Calendar.SECOND)));
|
||||
}
|
||||
}
|
||||
});
|
||||
bottomPanel.add(btnSetCurrentTime);
|
||||
|
||||
final JButton btnReboot = new JButton("Reboot");
|
||||
btnReboot.setActionCommand("Reboot simulation");
|
||||
btnReboot.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent ae) {
|
||||
JButton but = (JButton) ae.getSource();
|
||||
if (but.equals(btnReboot)) {
|
||||
System.out.println("[Node] Restart");
|
||||
nodemcuSimu.rebootTriggered();
|
||||
}
|
||||
}
|
||||
});
|
||||
bottomPanel.add(btnReboot);
|
||||
|
||||
contentPane.add(bottomPanel, BorderLayout.SOUTH);
|
||||
|
||||
setContentPane(contentPane);
|
||||
pack();
|
||||
setLocationByPlatform(true);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
private void parse() {
|
||||
this.mElements = new Element[this.mRow][this.mColumn];
|
||||
int row = 0;
|
||||
for (String line : this.mLines) {
|
||||
for (int i = 0; i < line.length(); i++) {
|
||||
char c = line.charAt(i);
|
||||
if ((('A' <= c) && (c <= 'Z')) || (('0' <= c) && (c <= '9')) || (c == 'Ä') || (c == 'Ö')
|
||||
|| (c == 'Ü')) {
|
||||
this.mElements[row][i] = new Element(c);
|
||||
} else {
|
||||
this.mElements[row][i] = new Element();
|
||||
}
|
||||
this.mElements[row][i].setColor(0, 0, 0);
|
||||
}
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
public class Element extends JLabel {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -3933903441113933637L;
|
||||
|
||||
private boolean noText = false;
|
||||
|
||||
/**
|
||||
* Draw a simple rect
|
||||
*/
|
||||
public Element() {
|
||||
super();
|
||||
this.noText = true;
|
||||
this.setBackground(Color.BLACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a character
|
||||
*
|
||||
* @param character
|
||||
* to show
|
||||
*/
|
||||
public Element(char character) {
|
||||
super("" + character);
|
||||
setFont(new Font("Dialog", Font.BOLD, 24));
|
||||
setHorizontalAlignment(CENTER);
|
||||
// FIXME: Background color is not updated:
|
||||
this.setBackground(Color.BLACK);
|
||||
}
|
||||
|
||||
public void setColor(int red, int green, int blue) {
|
||||
this.setForeground(new Color(red, green, blue));
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (noText) {
|
||||
sb.append(" ");
|
||||
} else {
|
||||
sb.append("" + this.getText());
|
||||
}
|
||||
sb.append("|" + Integer.toHexString(this.getForeground().getRed()) + " "
|
||||
+ Integer.toHexString(this.getForeground().getGreen()) + " "
|
||||
+ Integer.toHexString(this.getForeground().getBlue()));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateLED(int index, int r, int g, int b) {
|
||||
if (mElements != null) {
|
||||
int i = (index / mColumn);
|
||||
int j = (index % mColumn);
|
||||
// Swap each second row
|
||||
if (i % 2 == 1) {
|
||||
j = (mColumn-1) - j;
|
||||
}
|
||||
if ((i < mElements.length) && (j < mElements[i].length) && (mElements[i][j] != null)) {
|
||||
Element curlbl = mElements[i][j];
|
||||
curlbl.setColor(r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
17
simulation/ws28128ClockLayout.txt
Normal file
17
simulation/ws28128ClockLayout.txt
Normal file
@ -0,0 +1,17 @@
|
||||
# This file describes the layout of the WS2812 LEDs.
|
||||
# _ will only draw a rect
|
||||
# A-Z or 1-9 will draw the text or number
|
||||
# each element will be updated with its color with the known commands of the nodemcu firmware
|
||||
#
|
||||
# Here the configuration for the wordclock:
|
||||
ESKISTLFÜNF
|
||||
ZEHNZWANZIG
|
||||
DREIVIERTEL
|
||||
TGNACHVORJM
|
||||
HALBXZWÖLFP
|
||||
ZWEINSIEBEN
|
||||
KDREIRHFÜNF
|
||||
ELFNEUNVIER
|
||||
WACHTZEHNRS
|
||||
BSECHSFMUHR
|
||||
____
|
@ -18,10 +18,11 @@ if [ $# -ne 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FILES="displayword.lua main.lua timecore.lua webpage.lua webserver.lua wordclock.lua init.lua"
|
||||
FILES="displayword.lua main.lua timecore.lua webpage.html webserver.lua wordclock.lua init.lua"
|
||||
|
||||
# Format filesystem first
|
||||
echo "Format the complete ESP"
|
||||
$LUATOOL -p $DEVICE -w
|
||||
$LUATOOL -p $DEVICE -w -b 115200
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "STOOOOP"
|
||||
exit 1
|
||||
@ -36,7 +37,7 @@ for f in $FILES; do
|
||||
exit 1
|
||||
fi
|
||||
echo "------------- $f ------------"
|
||||
$LUATOOL -p $DEVICE -f $f -t $f
|
||||
$LUATOOL -p $DEVICE -f $f -b 115200 -t $f
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "STOOOOP"
|
||||
exit 1
|
||||
@ -44,6 +45,6 @@ for f in $FILES; do
|
||||
done
|
||||
|
||||
echo "Reboot the ESP"
|
||||
$LUATOOL -p $DEVICE -r
|
||||
$LUATOOL -p $DEVICE -r -b 115200
|
||||
|
||||
exit 0
|
||||
|
139
tools/tcpFlash.py
Executable file
139
tools/tcpFlash.py
Executable file
@ -0,0 +1,139 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import argparse
|
||||
import socket
|
||||
import os.path
|
||||
import sys #for exit and flushing of stdout
|
||||
import time
|
||||
|
||||
def sendRecv(s, message, answer):
|
||||
msg = message + "\n"
|
||||
s.sendall(msg)
|
||||
reply = s.recv(4096)
|
||||
i=1
|
||||
while ((not (answer in reply)) and (i < 10)):
|
||||
reply += s.recv(4096)
|
||||
i = i + 1
|
||||
if answer not in reply:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def sendCmd(s, message, cleaningEnter=False):
|
||||
msg = message + "\n"
|
||||
s.sendall(msg)
|
||||
time.sleep(0.050)
|
||||
reply = s.recv(4096)
|
||||
i=1
|
||||
while ((not (">" in reply)) and (i < 10)):
|
||||
time.sleep((0.050) * i)
|
||||
reply += s.recv(4096)
|
||||
i = i + 1
|
||||
|
||||
# print "Send\t" + message
|
||||
# print "Got\t" + reply
|
||||
if (cleaningEnter):
|
||||
s.sendall("\n")
|
||||
if "stdin:1:" in reply:
|
||||
print "ERROR, received : " + reply
|
||||
return False
|
||||
elif ">" in reply:
|
||||
return True
|
||||
else:
|
||||
print "ERROR, received : " + reply
|
||||
return False
|
||||
|
||||
def main(nodeip, luafile, volatile=None):
|
||||
if ( not os.path.isfile(luafile) ):
|
||||
print "The file " + luafile + " is not available"
|
||||
else:
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((nodeip, 80))
|
||||
time.sleep(0.050)
|
||||
s.sendall("\n")
|
||||
# Receive the hello Message of answer of the ESP
|
||||
if (not sendRecv(s, "\n", "Welcome to ") ):
|
||||
print "Cannot connect to the ESP"
|
||||
s.close()
|
||||
sys.exit(2)
|
||||
|
||||
# Read all lines from the welcome message
|
||||
i=0
|
||||
reply = s.recv(4096)
|
||||
while ((reply is not None) and (not (">" in reply)) and (i < 100)):
|
||||
reply = s.recv(4096)
|
||||
i = i + 1
|
||||
|
||||
|
||||
# Communication tests
|
||||
if ( not sendRecv(s, "print(12345)", "12345") ):
|
||||
print "NOT communicating with an ESP8266 running LUA (nodemcu) firmware"
|
||||
s.close()
|
||||
sys.exit(3)
|
||||
|
||||
if (volatile is None):
|
||||
print "Flashing " + luafile
|
||||
sendCmd(s, "file.remove(\"" + luafile+"\");", True)
|
||||
sendCmd(s, "w= file.writeline", True)
|
||||
sendCmd(s, "file.open(\"" + luafile + "\",\"w+\");", True)
|
||||
else:
|
||||
print "Executing " + luafile + " on nodemcu"
|
||||
|
||||
with open(luafile) as f:
|
||||
contents = f.readlines()
|
||||
i=1
|
||||
for line in contents:
|
||||
print "\rSending " + str(i) + "/" + str(len(contents)) + " ...",
|
||||
sys.stdout.flush()
|
||||
l = line.rstrip()
|
||||
if (volatile is None):
|
||||
if (not sendCmd(s, "w([[" + l + "]]);")):
|
||||
print "Cannot write line " + str(i)
|
||||
s.close()
|
||||
sys.exit(4)
|
||||
else:
|
||||
if (not sendCmd(s, l)):
|
||||
print "Cannot write line " + str(i)
|
||||
s.close()
|
||||
sys.exit(4)
|
||||
i=i+1
|
||||
|
||||
if (volatile is None):
|
||||
# Finished with updating the file in LUA
|
||||
if (not sendCmd(s, "w([[" + "--EOF" + "]]);")):
|
||||
print "Cannot write line " + "-- EOF"
|
||||
if (not sendCmd(s, "file.close();")):
|
||||
print "Cannot close the file"
|
||||
sys.exit(4)
|
||||
|
||||
# Check if the file exists:
|
||||
if (not sendRecv(s, "=file.open(\"" + luafile + "\")", "true")):
|
||||
print("Cannot send " + luafile + " to the ESP")
|
||||
sys.exit(4)
|
||||
else:
|
||||
print("Updated " + luafile + " successfully")
|
||||
else:
|
||||
print("Send " + luafile + " successfully")
|
||||
|
||||
# Cleaning the socket by closing it
|
||||
s.close()
|
||||
sys.exit(0) # Report that the flashing was succesfull
|
||||
except socket.error, msg:
|
||||
print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-t', '--target', help='IP address or dns of the ESP to flash')
|
||||
parser.add_argument('-f', '--file', help='LUA file, that should be updated')
|
||||
parser.add_argument('-v', '--volatile', help='File is executed at the commandline', action='store_const', const=1)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if (args.target and args.file and args.volatile):
|
||||
main(args.target, args.file, args.volatile)
|
||||
elif (args.target and args.file):
|
||||
main(args.target, args.file)
|
||||
else:
|
||||
parser.print_help()
|
@ -55,6 +55,8 @@ Please note that all settings are mandatory<br /><br />
|
||||
<tr><th>4. Minute Color</th><td><input type="color" name="colorMin4" value="$HEXCOLOR4"></td><td>Fourth minute after</td></tr>
|
||||
|
||||
<tr><th>Three quater</th><td><input type="checkbox" name="threequater" $THREEQUATER></td><td>Dreiviertel Joa/nei</td></tr>
|
||||
<tr><th>Invert lines 4-6</th><td><input type="checkbox" name="inv46" $THREEQUATER></td><td>invert</td></tr>
|
||||
|
||||
<tr><td colspan="3"><div align="center"><input type="submit" value="Save Configuration" onclick="this.value='Submitting ..';this.disabled='disabled'; this.form.submit();"></div></td></tr>
|
||||
<tr><td colspan="3"><div align="center"><input type="submit" name="action" value="Reboot"></div></td></tr>
|
||||
</table>
|
||||
|
@ -47,8 +47,8 @@ function sendPage(conn, nameOfFile, replaceMap)
|
||||
end
|
||||
buf = buf .. line
|
||||
|
||||
-- Sent after 1k data
|
||||
if (string.len(buf) >= 700) then
|
||||
-- Sent after 500 bytes data
|
||||
if ( (string.len(buf) >= 500) or (node.heap() < 2000) ) then
|
||||
line=nil
|
||||
conn:send(buf)
|
||||
print("Sent part of " .. sentBytes .. "B")
|
||||
@ -128,9 +128,10 @@ function startWebServer()
|
||||
|
||||
if (payload:find("GET /") ~= nil) then
|
||||
--here is code for handling http request from a web-browser
|
||||
collectgarbage()
|
||||
|
||||
if (sendPage ~= nil) then
|
||||
print("Sending webpage.html ...")
|
||||
print("Sending webpage.html (" .. tostring(node.heap()) .. "B free) ...")
|
||||
-- Load the sendPagewebcontent
|
||||
replaceMap=fillDynamicMap()
|
||||
sendPage(conn, "webpage.html", replaceMap)
|
||||
@ -165,7 +166,9 @@ function startWebServer()
|
||||
file.remove(configFile .. ".new")
|
||||
sec, _ = rtctime.get()
|
||||
file.open(configFile.. ".new", "w+")
|
||||
file.write("-- Config\n" .. "wifi.sta.config(\"" .. _POST.ssid .. "\",[[" .. _POST.password .. "]])\n" .. "sntpserverhostname=\"" .. _POST.sntpserver .. "\"\n" .. "timezoneoffset=\"" .. _POST.timezoneoffset .. "\"\n")
|
||||
file.write("-- Config\n" .. "station_cfg={}\nstation_cfg.ssid=\"" .. _POST.ssid .. "\"\nstation_cfg.pwd=\"" .. _POST.password .. "\"\nstation_cfg.save=false\nwifi.sta.config(station_cfg)\n")
|
||||
file.write("sntpserverhostname=\"" .. _POST.sntpserver .. "\"\n" .. "timezoneoffset=\"" .. _POST.timezoneoffset .. "\"\n".. "inv46=\"" .. tostring(_POST.inv46) .. "\"\n")
|
||||
|
||||
if ( _POST.fcolor ~= nil) then
|
||||
-- color=string.char(_POST.green, _POST.red, _POST.blue)
|
||||
print ("Got fcolor: " .. _POST.fcolor)
|
||||
|
@ -12,7 +12,7 @@ function display_timestat(hours, minutes, longmode)
|
||||
end
|
||||
|
||||
-- generate an empty return type
|
||||
local ret = { itis=0, fiveMin=0, tenMin=0, after=0, before=0, threeHour=0, quater=0, threequater=0, half=0, s=0,
|
||||
local ret = { it=0, is=0, fiveMin=0, tenMin=0, after=0, before=0, threeHour=0, quater=0, threequater=0, half=0, s=0,
|
||||
one=0, oneLong=0, two=0, three=0, four=0, five=0, six=0, seven=0, eight=0, nine=0, ten=0, eleven=0, twelve=0,
|
||||
twenty=0,
|
||||
clock=0, sr_nc=0, min1=0, min2=0, min3=0, min4=0 }
|
||||
@ -31,7 +31,8 @@ function display_timestat(hours, minutes, longmode)
|
||||
if ((longmode==1)
|
||||
or (minutes==0)
|
||||
or (minutes==6)) then
|
||||
ret.itis=1
|
||||
ret.it=1
|
||||
ret.is=1
|
||||
end
|
||||
|
||||
-- Handle minutes
|
||||
@ -104,10 +105,10 @@ function display_timestat(hours, minutes, longmode)
|
||||
end
|
||||
|
||||
if (hours == 1) then
|
||||
if (ret.before == 1) then
|
||||
ret.oneLong = 1
|
||||
else
|
||||
if (ret.it == 1) then
|
||||
ret.one=1
|
||||
else
|
||||
ret.oneLong=1
|
||||
end
|
||||
elseif (hours == 2) then
|
||||
ret.two=1
|
||||
@ -136,14 +137,17 @@ function display_timestat(hours, minutes, longmode)
|
||||
return ret
|
||||
end
|
||||
|
||||
-- @fn display_countwords
|
||||
-- @fn display_countcharacters_de
|
||||
-- Count the amount of characters, used to describe the current time in words
|
||||
-- @param words the same structure, as generated with the function @see display_timestat
|
||||
-- @return the amount of words, used to describe the time or <code>0</code> on errors
|
||||
function display_countwords_de(words)
|
||||
-- @return the amount of characters, used to describe the time or <code>0</code> on errors
|
||||
function display_countcharacters_de(words)
|
||||
local amount=0
|
||||
if (words.itis == 1) then
|
||||
amount = amount + 5
|
||||
if (words.it == 1) then
|
||||
amount = amount + 2
|
||||
end
|
||||
if (words.is == 1) then
|
||||
amount = amount + 3
|
||||
end
|
||||
if (words.fiveMin == 1) then
|
||||
amount = amount + 4
|
||||
@ -214,3 +218,20 @@ function display_countwords_de(words)
|
||||
|
||||
return amount
|
||||
end
|
||||
|
||||
-- @fn display_countcharacters_de
|
||||
-- Count the amount of words, used to describe the current time in words!
|
||||
-- (min1 to min4 are ignored)
|
||||
-- @param words the same structure, as generated with the function @see display_timestat
|
||||
-- @return the amount of words, used to describe the time or <code>0</code> on errors
|
||||
function display_countwords_de(words)
|
||||
local amount = 0
|
||||
for k,v in pairs(words) do
|
||||
if (v ~= nil and v == 1) then
|
||||
if (k ~= "min1" and k ~= "min2" and k ~= "min3" and k ~= "min4") then
|
||||
amount = amount + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return amount
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user