-->
Page 6 of 6

Re: wireless coding firmware..

PostPosted: Thu May 28, 2015 11:22 am
by robo
hasty indeed, but for a reason:
1. a language / platform should be intuitive
2. copy&paste is the 21st century style of programming !
(of course the linux-faithful will disagree..)

nodeMCU is fine.. even regular expressions.. problem is that with wifi we immediately are tempted with web client/server stuff involving large strings and 150 lines nodeMCU code already crash with a 300 byte string :-/
I guess a complete rework of all string functions would be needed.. so they all work on streams, best with some kind of "stored procedures" to parse a long string in one pass. Not my playground.

By now i agree with Terrys socket approach. Socket communication might be the only way to install (large) lua script onto the ESP. With 24 days no update Terry has either finished his work or abandoned it.

When i have learned socket communication i will rewrite my ESPLoad.
With the ESP in client mode a simple php script might feed the ESP line by line with a lua file hosted on the server.
With the ESP in server mode, a simple javascript page in the client browser might do the communication.

Originally i never intended to write such a system myself. This thread was rather meant to collect some ideas..

I think this is my latest version of ESPLoad:

Code: Select all--install.lu
print("install ESPLoad")

function Finish()
    if sFile then
        print("size: " .. (iSeek-iStart))
        if string.match(sFile, "\.lua") then
            print("compiling..")
            node.compile(sFile)
        end
    end
    iStart = iSeek
end

file.open("install.lua","r")
iSeek=0
iStart=0
sFile = nil
s=file.readline()
while s ~= nil do
    iSeek = iSeek + string.len(s)
    sFileNew = string.match(s, "file:([%w.]+)")
    if sFileNew then
        print(sFileNew)
        file.close()
        file.remove(sFileNew)
        file.open("install.lua","r")
        file.seek("set",iSeek)
        Finish()
        sFile = sFileNew
    end
    if sFile then
        file.close()
   
        file.open(sFile,"a+")
        file.write(s)
        file.close()
   
        file.open("install.lua","r")
        file.seek("set",iSeek)
        collectgarbage()
    end
    s=file.readline()
end
file.close()
--file.remove("install.lua")

Finish()

print("install finished :-)")

--[[
file:y.htm
Content-Type: text/html; charset=UTF-8

<html><body><form method=post enctype="multipart/form-data">
error: <input name=err value='_err'/><br/>
<h2>access point:</h2>
SSID: <input name=ssid value='_ssid'/><br/>
pwd: <input name=pwd value='_pwd'/><br/>
upload:<br/>
<textarea style="font-size:8pt;" cols=80 rows=10 name=upload>_upload</textarea>
<h2>fetch lua:</h2>
ip: <input name=host value='_host'/><br/>
domain: <input name=domain value='_domain'/><br/>
path: <input name=path value='_path'/><br/>
reboot: <input type=number size=4 name=update value='_update'/> minutes<br/>
<input type=submit value='submit'/>
</form></body></html>
 
--file:start.lua

print(collectgarbage("count").." kB used")

s = {ssid="", pwd="", host="", domain="", path="", err="no data",update=0,upload=""}
if (file.open("s.txt","r")) then
    local sF = file.read()
    file.close()
    for k, v in string.gmatch(sF, "([%w.]+)=([%S ]*)") do   
        s[k] = v
        --print(k .. ": " .. v)
    end
end


if s.err == "" then
    if (tonumber(s.update)>0) then
        tmr.alarm (0, tonumber(s.update)*60000, 1, function()
                print("checking for update")
            end)
    end
    dofile("client.lua")   
else
    require("server")
    --dofile("server.lua")   
end
--file:server.lua

function M(s)
    print(s .. ": " .. collectgarbage("count").." kB used")
end

function SaveX(sErr)
    if (sErr) then
        print (sErr)
        s.err = sErr
    end
    file.remove("s.txt")
    file.open("s.txt","w+")
    for k, v in pairs(s) do
        file.writeline(k .. "=" .. v)
    end               
    file.close()
    collectgarbage()
end

wifi.setmode(wifi.SOFTAP)
wifi.ap.config({ssid="node_"..node.chipid(), pwd=""})
srv=net.createServer(net.TCP)
print(wifi.sta.getip())

        function _read()
            l = file.readline()
            if l then
                iSeek = iSeek + string.len(l)
            end
            return l
        end


srv:listen(1985,function(conn)
    conn:on("receive", function(client,request)
        M("1985..")
        client:send("HTTP/1.x 200 OK\n")

        file.remove("t")
        file.open("t","w+")
        file.write(request)
        file.close()
        request = ""
        collectgarbage()

        file.open("t","r")
        iSeek = 0
        boundary = nil
        local l = _read()
        repeat
            --print(iSeek)
            local bRead = true;
            if boundary then
               print("'"..l.."'")
                local i,j = string.find(l, boundary)
                --print(j)
                if j then
                --print("'"..boundary.."'")
                --if l == boundary then
                    l = _read()
                   --print (l)
                   if l then
                        local key = string.match(l, 'name="(%w+)"')
                        if key then
                            --print ("key: "..key)
                            l = _read()
                            if key == "upload" then
                                l = _read()
                                --print ("save upload: "..l)
                                local iStart = iSeek
                                local sFile = string.match(l, '^--file:([%w.]+)')
                                if not sFile then
                                    sFile = "do.lua"
                                end
                                print ("save upload to ".. sFile)
                                file.remove(sFile)
                                repeat
                                    file.close()
                                    file.open(sFile,"a+")
                                    local i,j = string.find(l, boundary)
                                    if j then
                                        file.close()
                                        file.open("t","r")
                                        file.seek("set",iSeek)
                                        bRead = false
                                        s.path = sFile
                                    else
                                        file.write(l)
                                        file.close()
                                        file.open("t","r")
                                        file.seek("set",iSeek)
                                        l = _read()
                                    end
                                until (l == nil) or not bRead
                            else
                                s[key] = _read()
                                print(key .." = " .. s[key])
                                --s[key] = string.gsub(_read(),"[\n\r]","")
                            end
                        else
                            --print("no key found :-(")
                        end
                    end
                end
            else
                boundary = string.match(l, 'boundary=([^\s]+)')
            end
            if bRead then
                l = _read()
            end
            print(iSeek)
        until l == nil
        file.close()


        M("open y")
        file.open("y.htm","r")
        local sH = file.read()
        --M(string.len(sH))
        for k, v in pairs(s) do
            --M(k)
            sH,n = string.gsub(sH,"_"..k,v)
            --sH,n = string.gsub(sH,"_"..k,unescape(v))
        end   
        M(string.len(sH))

        s.upload = ""
        print(string.len(sH))
        file.close()
        client:send(sH)
        client:close()

        collectgarbage()
       M("1985 done")
    end)
end)
--if s.path ~= "" then
--    if file.open(s.path,"r") then
--        dofile(s.path)
--    end
--end
--file:client.lua

function SaveX(sErr)
    if (sErr) then
        print (sErr)
        s.err = sErr
    end
    file.remove("s.txt")
    file.open("s.txt","w+")
    for k, v in pairs(s) do
        file.writeline(k .. "=" .. v)
    end               
    file.close()
    collectgarbage()
end

function NewLua(sck,c)
    local nStart, nEnd = string.find(c, "\n\n")
    if (nEnd == nil) then
        nStart, nEnd = string.find(c, "\r\n\r\n")
    end
    c = string.sub(c,nEnd+1)
    print("lua length: "..string.len(c))

    if (string.sub(c,0,7) ~= "--file:") then
        SaveX(s.domain.."/"..s.path .. " does not begin with --lua")
        node.restart()
        return
    end
    file.remove("do.lua")
    file.open("do.lua","w+")
    file.writeline(c)
    file.close()
    node.compile("do.lua")
    --dofile("do.lua")
    dofile("do.lc")   
    collectgarbage()
end

print("fetch lua..")

wifi.setmode (wifi.STATION)
wifi.sta.config(s.ssid, s.pwd)
wifi.sta.autoconnect (1)

iFail = 20
tmr.alarm (1, 1000, 1, function ( )
  iFail = iFail -1
  print(iFail)
  if (iFail == 0) then
    SaveX("could not access "..s.ssid)
    node.restart()
  end     
 
  if wifi.sta.getip ( ) == nil then
    print(s.ssid)
  else
    print ("ip: " .. wifi.sta.getip ( ))
    tmr.stop (1)
    sk=net.createConnection(net.TCP, 0)
    sk:on("receive", NewLua)
    sk:connect(80,s.host)
    sGet = "GET /".. s.path .. " HTTP/1.1\r\nHost: " .. s.domain .. "\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n"
    print(sGet)
    sk:send(sGet)
   
  end
  collectgarbage()
 
end)

 print(collectgarbage("count").." kB: client.lua")
--]]


It seems, conn:on("receive", function(client,request)
already contains the entire string in "request" and not a stream :-(
Directly saving it to the filesystem and then stream reading/parsing it allowed me to form-upload files of size 500 bytes, ha ha :-/
Maybe someone will like that compact POST-parser:
Code: Select alls = {ssid="", pwd="", host="", domain="", path="", err="no data",update=0,upload=""}

function _read()
    l = file.readline()
    if l then
        iSeek = iSeek + string.len(l)
    end
    return l
end

srv:listen(1985,function(conn)
    conn:on("receive", function(client,request)
        M("1985..")
        client:send("HTTP/1.x 200 OK\n")

        file.remove("t")
        file.open("t","w+")
        file.write(request)
        file.close()
        request = ""
        collectgarbage()

        file.open("t","r")
        iSeek = 0
        boundary = nil
        local l = _read()
        repeat
            local bRead = true;
            if boundary then
                local i,j = string.find(l, boundary)
                if j then
                    l = _read()
                   if l then
                        local key = string.match(l, 'name="(%w+)"')
                        if key then
                            l = _read()
                            if key == "upload" then
                                l = _read()
                                local iStart = iSeek
                                local sFile = string.match(l, '^--file:([%w.]+)')
                                if not sFile then
                                    sFile = "do.lua"
                                end
                                print ("save upload to ".. sFile)
                                file.remove(sFile)
                                repeat
                                    file.close()
                                    file.open(sFile,"a+")
                                    local i,j = string.find(l, boundary)
                                    if j then
                                        file.close()
                                        file.open("t","r")
                                        file.seek("set",iSeek)
                                        bRead = false
                                        s.path = sFile
                                    else
                                        file.write(l)
                                        file.close()
                                        file.open("t","r")
                                        file.seek("set",iSeek)
                                        l = _read()
                                    end
                                until (l == nil) or not bRead
                            else
                                s[key] = _read()
                            end
                        else
                            --print("no key found :-(")
                        end
                    end
                end
            else
                boundary = string.match(l, 'boundary=([^\s]+)')
            end
            if bRead then
                l = _read()
            end
            print(iSeek)
        until l == nil
        file.close()

        -- ...


I guess the current version of ESPLoad could be optimized with http://www.esp8266.com/viewtopic.php?f=19&t=1940

But as i wrote in the first lines, this is not my way.

Ah yes: make.bat
Code: Select allcopy install.lu+y.htm+start.lua+server.lua+client.lua install.lua


i have ordered 1+3 https://www.kickstarter.com/projects/706167548/dominoio-an-open-hardware-wifi-platform-for-things

I still like the ESP-201, but only for simple sensor logging. And i guess, only 1 ADC will not be enough for me. So i guess i will have to bundle whatever wifi-SoC with a good old Arduino Mini anyway.

Ideas welcome :-)