A64 memmory problem
Posted: Mon Dec 05, 2016 7:03 pm
Mmiscool, I know you won't like me telling you this, any more than I like being the one having to tell you, but I think Alpha 64 may have introduced a serious memory problem. I've triple-checked to make sure before 'annoying' you, but have reproduced the same problems 3 times by reverting back to A63 to check things then re-installing A64 and getting the same problems, so it seems more than just coincidence.
There are 2 major symptoms on A64 that I don't get with A63.
1. I had included a memory guage in my script for trying to track down memory leakage problems that I was getting on A63. So it quickly became evident that every time I RUN the A64 script I had less RAMFREE available than the previous time, until eventually there is so little free ram available that the ESP just reboots itself.
This doesn't happen with A63, the memclear instruction causes each re-RUN to start with the same available free ram.
2. But even before able to RUN the script it obviously needs to be SAVED, and whereas on A63 the 'Saved OK' confirmation window only appeared every alternative SAVE as was previously reported, now in A64 it never returns a 'Saved OK' confirmation and it reboots every time - sometimes rebooting itself multiple times on the trot! - so the script never saves or runs correctly.
Perhaps the best way of reproducing my situation is to load the enclosed script on a 4Mb A63 device.
Just SAVE and RUN. If the SAVE causes a reboot the wait till it reconnects and do another SAVE to get the SAVED OK window without the reboot, else the memory is corrupt. RUN the script and note the max available ram to the right of the meter, then browser back and re-run it again to note the same free ram again. If you do that with A64 you will see it reducing every time.
You can check the script stability on A63 by keep sending it a TOGGLE command via serial or udp - the free mem will drop down initially but then stabilise for multiple toggles. Doing the same on A64 will keep eating up free mem till it reboots.
There are 2 major symptoms on A64 that I don't get with A63.
1. I had included a memory guage in my script for trying to track down memory leakage problems that I was getting on A63. So it quickly became evident that every time I RUN the A64 script I had less RAMFREE available than the previous time, until eventually there is so little free ram available that the ESP just reboots itself.
This doesn't happen with A63, the memclear instruction causes each re-RUN to start with the same available free ram.
2. But even before able to RUN the script it obviously needs to be SAVED, and whereas on A63 the 'Saved OK' confirmation window only appeared every alternative SAVE as was previously reported, now in A64 it never returns a 'Saved OK' confirmation and it reboots every time - sometimes rebooting itself multiple times on the trot! - so the script never saves or runs correctly.
Perhaps the best way of reproducing my situation is to load the enclosed script on a 4Mb A63 device.
Just SAVE and RUN. If the SAVE causes a reboot the wait till it reconnects and do another SAVE to get the SAVED OK window without the reboot, else the memory is corrupt. RUN the script and note the max available ram to the right of the meter, then browser back and re-run it again to note the same free ram again. If you do that with A64 you will see it reducing every time.
You can check the script stability on A63 by keep sending it a TOGGLE command via serial or udp - the free mem will drop down initially but then stabilise for multiple toggles. Doing the same on A64 will keep eating up free mem till it reboots.
Code: Select all
memclear
max = ramfree()
memfree = ramfree()
'meter memfree, 0, max
'cssid htmlid(), "background-color: yellow; color:red; width: 100%; height:10px;"
localIP = ip()
pos = instrrev(localIP,".")
netIP = left(localIP,pos)
nodeIP = mid(localIP,pos+1)
title = "EasyNet"
localname = "" 'Populate for clarity, else will be uniquely named "NODE" + last IP address byte
if localname == "" then localname = "Node" & nodeIP
localname = upper(localname) 'Names are deliberately case-insensitive to offer simplest ease of use
groupname = "some" 'Optional way of being addressed by sub groups (ie: PIRs, LIGHTs, etc)
globalname = "all" 'Optional way of being addressed by large groups or systems (ie: CCTV, HouseAlarm, etc)
udpport = "5001" 'Dev default, so change to suit, different ports could be used for different separated systems
'debugmode = "y"
udp = "y"
serial1 = "y"
serial2 = "y"
buttonmode = "MultiMode" 'Quick press (<2s) to toggle led, long press (>2s)to blink ip
buttonpin = 0 'Uses gpio00 flashing button by default, change to suit (needs pullup resistor).
buttonoff = 1 'Default botton OFF state
ledpin = 1 'Uses onboard gpio01 blue led by default, change to suit
ledoff = 1 'Default led pin off state (allows configuring led pin for active high or active low operation)
relaypin = 12 'Set to the required Relay control pin
relayoff = 0 'Default relay OFF state - Allows for use of active high or active low relay (or alternative output)
if ledoff == 1 then io(po,ledpin,1) else io(po,ledpin,0) 'initialise led to its off state
if relayoff == 1 then io(po,relaypin,1) else io(po,relaypin,0) 'initialise relay to its off state
usercmds = "MyCommand " 'Add your own user commands here, remember to add a corresponding uppercase named branch
commoncmds = " Toggle Relay1 Relay2 RelayON RelayOFF " 'Common commands
systemcmds = " Blinks BlinkIP ? Help ! Ping Debug Exit Reboot " 'System commands
vocabulary = usercmds & " " & commoncmds & " " & systemcmds
payload = ""
qos = 0
ims = ""
source = ""
target = ""
words = 0
start = 0 'used by MultiMode button-pressed timer
stop = 0 'used by MultiMode button-pressed timer
numblinks = 5
if serial1 == "y" then serialbranch [SERIAL1MSG]
if serial2 == "y" then serial2branch [SERIAL2MSG]
if udp == "y" then
udpbegin udpport
udpbranch [UDPMSG]
endif
interrupt buttonpin, [PRESSED]
html |<h2 style="text-align:center;top-padding:0px;bottom-padding:0px;">| & title & |</h2>|
'style="color:blue;">'html "<hr>"
meter memfree, 1000, max
cssid htmlid(), "width:100%;"
html |<p style="text-align:right;">Max available memory=| & max & |</p>|
print
html "<BR>"
html "Localname: " & localname & "<BR>"
html "Groupname: " & groupname & "<BR>"
html "Globalname: " & globalname & "<BR>"
html "IP address: " & localIP & "<BR>"
html "UDP port: " & udpport
html "<BR><BR>"
memfree = ramfree()
button "Help", [HELP]
wait
[SERIAL1MSG]
serialinput payload
if asc(right(payload,1)) <33 then payload = left(payload,len(payload)-1)
payload = payload & " ims=serial1"
gosub [PARSER]
return
[SERIAL2MSG]
serial2input payload
if asc(right(payload,1)) <33 then payload = left(payload,len(payload)-1)
payload = payload & " ims=serial2"
gosub [PARSER]
return
[UDPMSG]
payload = udpread()
payload = payload & " ims=udp"
gosub [PARSER]
return
[PARSER]
memfree = ramfree()
'html "."
'print
'return
if debugmode == "y" and instr(payload,"ims=serial1") > 0 then html "Serial1 Message Received<BR>"
if debugmode == "y" and instr(payload,"ims=serial2") > 0 then html "Serial2 Message Received<BR>"
if debugmode == "y" and instr(payload,"ims=udp") > 0 then html "UDP Message Received<BR>"
if asc(right(payload,1)) < 33 then payload = left(payload,len(payload) - 1
qos = 0
ims = ""
source = ""
target = ""
words = 0
memfree = ramfree()
'html "Parser " & ramfree() & "<BR>"
'return
do 'count payload words after controls have been extracted
words = words + 1 'count words
tmp = word(payload,words)
if tmp <> "" then
pos = instr(tmp,"target=")
if pos > 0 then
target = word(tmp,2,"=")
'payload = trim(replace(payload," " & tmp,""))
words = words + 1
endif
pos = instr(tmp,"qos=")
if pos > 0 then
qos = word(tmp,2,"=")
'payload = trim(replace(payload," " & tmp,""))
words = words + 1
endif
pos = instr(tmp,"ims=")
if pos > 0 then
ims = word(tmp,2,"=")
'payload = trim(replace(payload, " " & tmp,""))
words = words + 1
endif
pos = instr(tmp,"source=")
if pos > 0 then
source = word(tmp,2,"=")
'payload = trim(replace(payload, " " & tmp,""))
words = words + 1
endif
endif
loop while tmp <> ""
if debugmode == "y" then
html "payload=" & payload & ", (length=" & len(payload) & "), (words=" & words & ")<br>"
endif
if target == "" then target = localname else target = upper(target) 'Subsribers list
target = upper(target)
if debugmode == "y" then html "source=" & source & "target=" & target & ", qos=" & qos & "ims=" & ims & "<br>"
if instr(target,localname)>0 or instr(target,groupname)>0 or instr(target,globalname)>0 or instr(target,localIP)>0 then
if instr(upper(payload),"ACK") <> 0 then gosub [ACKIN] else gosub [SUBSCRIBE]
else
if debugmode == "y" then html "Not a target for payload " & payload & "<br>"
endif
return
[SUBSCRIBE]
tmp = upper(word(payload,1))
if debugmode == "y" then html "command=" & tmp & ", length=" & len(tmp) & "<BR>"
if instr(upper(vocabulary),tmp) > 0 then
if qos > 0 then gosub [ACKOUT]
gosub "[" & tmp & "]"
else
tmp = "ERROR: Command (" & tmp & ") not recognised in Payload (" & payload & ")"
if debugmode == "y" then html tmp & "<BR>"
if ims=="udp" then udpreply tmp
if ims=="serial1" then serialprintln tmp
if ims=="serial2" then serial2println tmp
endif
return
[ACKIN]
sentq = "tim|blinks 5 qos=2|fred target=local|" 'dev test xxxxxx
payload = replace(payload," ACK","")
sentq = replace(sentq,payload & "|","")
return
[PRESSED]
if io(laststat,buttonpin) == 0 then start = millis() else stop = millis()
if stop > start then
if stop-start < 2000 then gosub [TOGGLE] else gosub [BLINKIP]
endif
memfree = ramfree()
wait
[TOGGLE]
'html ramfree() & "<BR>"
if io(laststat,ledpin) = 1 then io(po,ledpin,0) else io(po,ledpin,1)
if io(laststat,relaypin) = 1 then io(po,relaypin,0) else io(po,relaypin,1)
return
[PING]
[!]
'if debugmode == "y" then udpreply localname & " PING Declare IP acknowledged "
udpreply localname & " " & localIP & " PING acknowledged"
serialprintln localname & " " & localIP & " PING acknowledged"
html localname & " " & localIP & " acknowledged<BR>"
return
[BLINKS]
'if debugmode == "y" then udpreply localname & " Blinks acknowledged. Params=" & params
let oldstate = io(laststat,ledpin) 'Remember LED state before blinking
io(po,ledpin,ledoff)
if val(word(payload,2)) > 0 and val(word(payload,2)) < 99 then numblinks = val(word(payload,2))
data = ""
delay 200
for count = 1 to numblinks
if ledoff == 0 then io(po,ledpin,1) else io(po,ledpin,0)
delay 600
if ledoff == 0 then io(po,ledpin,0) else io(po,ledpin,1)
delay 400
next count
delay 2000
io(po,ledpin,oldstate) 'Restore LED state to its prior value
return
[BLINKIP]
oldstate = io(laststat,ledpin) 'remember original state
blinkon = 200
blinkoff = 400
blinkpause = 1000
blinkgap = 1400
if ledoff == 0 then io(po,ledpin,0) else io(po,ledpin,1) ' turn led off
delay blinkpause
for pos = 1 to len(localIP)
digitchr = mid(localIP,pos,1)
if digitchr == "." then
delay blinkgap
else
if digitchr = "0" then digit = val("10") else digit = val(digitchr)
for count = 1 to digit
if ledoff == 0 then io(po,ledpin,1) else io(po,ledpin,0)
delay blinkon
if ledoff == 0 then io(po,ledpin,0) else io(po,ledpin,1)
delay blinkoff
next count
delay blinkpause
end if
next pos
delay blinkgap
io(po,ledpin,oldstate) 'restore to original state
return
[EXIT]
end
[REBOOT]
reboot
[DEBUG]
if upper(word(payload,2)) == "OFF" or upper(word(payload,2)) == "n" then debugmode = "n"
if upper(word(payload,2)) == "ON" or upper(word(payload,2)) == "y" then debugmode = "y"
return
[HELP]
[?]
tmp = "Syntax: COMMAND [params] [options]"
'if ims="" or debugmode == "y" then html "<br>" & tmp & "<br>"
if ims="" then html "<br>" & tmp & "<br>"
if ims="serial1" then serialprintln tmp
if ims="serial2" then serial2println tmp
if ims="udp" then udpreply tmp
tmp = "User commands: "
if usercmds == "" then tmp = tmp & " (no user commands defined)" else tmp = tmp & usercmds
if ims="" or debugmode == "y" then html tmp & "<br>"
if ims="serial1" then serialprintln tmp
if ims="serial2" then serial2println tmp
if ims="udp" then udpreply tmp
tmp = "Common commands: " & commoncmds
if ims="" or debugmode == "y" then html tmp & "<br>"
if ims="serial1" then serialprintln tmp
if ims="serial2" then serial2println tmp
if ims="udp" then udpreply tmp
tmp = "System commands: " & systemcmds
if ims="" or debugmode == "y" then html tmp & "<br>"
if ims="serial1" then serialprintln tmp
if ims="serial2" then serial2println tmp
if ims="udp" then udpreply tmp
tmp = "Params: " & "command dependent - eg: On, Off, Y, N, temp_value etc"
if ims="" or debugmode == "y" then html tmp & "<br>"
if ims="serial1" then serialprintln tmp
if ims="serial2" then serial2println tmp
if ims="udp" then udpreply tmp
tmp = "Options: "
tmp = tmp & " target=(subscribers list), qos=(number of unacknowledged transmit retries)"
if ims="" or debugmode == "y" then html tmp & "<br>"
if ims="serial1" then serialprintln tmp
if ims="serial2" then serial2println tmp
if ims="udp" then udpreply tmp
tmp = "Automatic System Options: "
tmp = tmp & " ims=(input msg stream), ACK (subscriber QoS>0 received msg acknowledgement)"
if ims="" or debugmode == "y" then html tmp & "<br>"
if ims="serial1" then serialprintln tmp
if ims="serial2" then serial2println tmp
if ims="udp" then udpreply tmp
if ims <> "" then return
memfree = ramfree()
wait