i am a total beginner with LUA / ESP8266 and i am trying to find out where this error comes from:
PANIC: unprotected error in call to Lua API (bad argument #2 to 'set' (index out of range))
This is the Whole Message in serial monitor:
NodeMCU 2.2.0.0 built with Docker provided by frightanic.com
.branch: master
.commit: 11592951b90707cdcb6d751876170bf4da82850d
.SSL: false
.Build type: float
.LFS: disabled
.modules: adc,bit,dht,file,gpio,i2c,mqtt,net,node,ow,spi,tmr,uart,wifi
build created on 2019-12-07 23:52
powered by Lua 5.1.4 on SDK 2.2.1(6ab97e9)
> Config done, IP is 192.168.2.168
LED-Server started
PANIC: unprotected error in call to Lua API (bad argument #2 to 'set' (index out of range))
ets Jan 8 2013,rst cause:2, boot mode:(3,6)
load 0x40100000, len 27780, room 16
tail 4
chksum 0xbc
load 0x3ffe8000, len 2188, room 4
tail 8
chksum 0xba
load 0x3ffe888c, len 136, room 0
tail 8
chksum 0xf2
csum 0xf2
å¬ú‰.Éo‰ísÉÚo|Ï.å.õd$`..#íú..æÑ2rí.lúN‡.Éo„..l`.Ñ‚r€lÑ$.å...l`.Ñ‚s≤pɉ$.å....l`.Ñ‚r€l.èæ.å...$l`.{$é.êo.Ñü¬cc.ÑÑ".|l.Bè.c.‰è¬.lc‰ÚnÓ.2NN‚....å#€‚n.ÏéÑ.l..$Ïådè|Ïl.é.lÄ.o¸.Ñæ.#".llÏÑè..c...åû„åc.l.Ñb.{$r.
I Uploaded this code (https://github.com/Christoph-D/esp8266-wakelight) to the ESP8266, and did build the correct NodeMCU firmware with all required modules.
The Serial output is ok for a couple of seconds, then i get this error and it starts to repeat rebooting.
Where would i start looking for the Problem?
Thanks a lot!!!
EDIT: there are only a few places in the lua files where anything about "set" is written:
local function update_buffer(buffer, c)
if not c.r_frac then c.r_frac = 0 end
if not c.g_frac then c.g_frac = 0 end
if not c.b_frac then c.b_frac = 0 end
local r2 = c.r_frac >= 0 and c.r + 1 or c.r - 1
local g2 = c.g_frac >= 0 and c.g + 1 or c.g - 1
local b2 = c.b_frac >= 0 and c.b + 1 or c.b - 1
local r3, g3, b3
local set = buffer.set
for i = 1, NUM_LEDS do
if i > c.r_frac then r3 = c.r else r3 = r2 end
if i > c.g_frac then g3 = c.g else g3 = g2 end
if i > c.b_frac then b3 = c.b else b3 = b2 end
set(buffer, i - 1, g3, r3, b3)
end
end
Is there anything wrong?
Just above the for-loop where set is called, try adding this:
print(buffer:size(), NUM_LEDS)
If everything is OK, it should print the same number twice. If NUM_LEDS is larger, then that's your bug.
I don't really get why it uses the global variable in that place anyway; it'd make much more sense to use buffer:size() instead for exactly this reason.
Related
I know that Common Lisp discourages a programmer from touching raw memory, but I would like to know whether it is possible to see how an object is stored on a byte level. Of course, a garbage collector moves objects in memory space and two subsequent calls of a function (obj-as-bytes obj) could yield different results, but let us assume that we need just a memory snapshot. How would you implement such function?
My attempt with SBCL looks as follows:
(defun obj-as-bytes (obj)
(let* ((addr (sb-kernel:get-lisp-obj-address obj)) ;; get obj address in memory
(ptr (sb-sys:int-sap addr)) ;; make pointer to this area
(size (sb-ext:primitive-object-size obj)) ;; get object size
(output))
(dotimes (idx size)
(push (sb-sys:sap-ref-64 ptr idx) output)) ;; collect raw bytes into list
(nreverse output))) ;; return bytes in the reversed order
Let's try:
(obj-as-bytes #(1)) =>
(0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 111 40 161 4 16 0 0 0 23 1 16 80 0 0 0)
(obj-as-bytes #(2) =>
(0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 95 66 161 4 16 0 0 0 23 1 16 80 0 0 0)
From this output I conclude that there is a lot of garbage, which occupies space for future memory allocations. And we see it because (sb-ext:primitive-object-size obj) seems to return a chunk of memory which is large enough to fit the object.
This code demonstrates it:
(loop for n from 0 below 64 collect
(sb-ext:primitive-object-size (make-string n :initial-element #\a))) =>
(16 32 32 32 32 48 48 48 48 64 64 64 64 80 80 80 80 96 96 96 96 112 112 112 112 128 128 128 128 144 144 144 144 160 160 160 160 176 176 176 176 192 192 192 192 208 208 208 208 224 224 224 224 240 240 240 240 256 256 256 256 272 272 272)
So, obj-as-bytes would give a correct result if sb-ext:primitive-object-size were more accurate. But I cannot find any alternative.
Do you have any suggestions how to fix this function or how to implement it differently?
As I mentioned in a comment the layout of objects in memory is very implementation-specific and the tools to explore it are necessarily also implementation-dependent.
This answer discusses the layout for 64-bit versions of SBCL and only for 64-bit versions which have 'wide fixnums'. I'm not sure in which order these two things arrived in SBCL as I haven't looked seriously at any of this since well before SBCL and CMUCL diverged.
This answer also may be wrong: I'm not an SBCL developer and I'm only adding it because no one who is has (I suspect tagging the question properly might help with this).
Information below comes from looking at the GitHub mirror, which seems to be very up to date with the canonical source but a lot faster.
Pointers, immediate objects, tags
[Information from here.] SBCL allocates on two-word boundaries. On a 64-bit system this means that the low four bits of any address are always zero. These low four bits are used as a tag (the documentation calls this the 'lowtag') to tell you what sort of thing is in the rest of the word.
A lowtag of xyz0 means that the rest of the word is a fixnum, and in particular xyz will then be the low bits of the fixnum, rather than tag bits at all. This means both that there are 63 bits available for fixnums and that fixnum addition is trivial: you don't need to mask off any bits.
A lowtag of xy01 means that the rest of the word is some other immediate object. Some of the bits to the right of the lowtag (which I think SBCL calls a 'widetag' although I am confused about this as the term seems to be used in two ways) will say what the immediate object is. Examples of immediate objects are characters and single-floats (on a 64-bit platform!).
the remaining lowtag patterns are xy11, and they all mean that things are pointers to some non-immediate object:
0011 is an instance of something;
0111 is a cons;
1011 is a function;
1111 is something else.
Conses
Because conses don't need any additional type information (a cons is a cons) the lowtag is enough: a cons is then just two words in memory, each of which in turn has lowtags &c.
Other non-immediate objects
I think (but am not sure) that all other non-immediate objects have a word which says what they are (which may also be called a 'widetag') and at least one other word (because allocation is on two-word boundaries). I suspect that the special tag for functions means that function call can just jump to the entry point of the function's code.
Looking at this
room.lisp has a nice function called hexdump which knows how to print out non-immediate objects. Based on that I wrote a little shim (below) which tries to tell you useful things. Here are some examples.
> (hexdump-thing 1)
lowtags: 0010
fixnum: 0000000000000002 = 1
1 is a fixnum and its representation is just shifted right one bit as described above. Note that the lowtags actually contain the whole value in this case!
> (hexdump-thing 85757)
lowtags: 1010
fixnum: 0000000000029DFA = 85757
... but not in this case.
> (hexdump-thing #\c)
lowtags: 1001
immediate: 0000000000006349 = #\c
> (hexdump-thing 1.0s0)
lowtags: 1001
immediate: 3F80000000000019 = 1.0
Characters and single floats are immediate: some of the bits to the left of the lowtag tells the system what they are, I think?
> (hexdump-thing '(1 . 2))
lowtags: 0111
cons: 00000010024D6E07 : 00000010024D6E00
10024D6E00: 0000000000000002 = 1
10024D6E08: 0000000000000004 = 2
> (hexdump-thing '(1 2 3))
lowtags: 0111
cons: 00000010024E4BC7 : 00000010024E4BC0
10024E4BC0: 0000000000000002 = 1
10024E4BC8: 00000010024E4BD7 = (2 3)
Conses. In the first case you can see the two fixnums sitting as immediate values in the two fields of the cons. In the second, if you decoded the lowtag of the second field it would be 0111: it's another cons.
> (hexdump-thing "")
lowtags: 1111
other: 00000010024FAE8F : 00000010024FAE80
10024FAE80: 00000000000000E5
10024FAE88: 0000000000000000 = 0
> (hexdump-thing "x")
lowtags: 1111
other: 00000010024FC22F : 00000010024FC220
10024FC220: 00000000000000E5
10024FC228: 0000000000000002 = 1
10024FC230: 0000000000000078 = 60
10024FC238: 0000000000000000 = 0
> (hexdump-thing "xyzt")
lowtags: 1111
other: 00000010024FDDAF : 00000010024FDDA0
10024FDDA0: 00000000000000E5
10024FDDA8: 0000000000000008 = 4
10024FDDB0: 0000007900000078 = 259845521468
10024FDDB8: 000000740000007A = 249108103229
Strings. These have some type information, a length field, and then characters are packed two to a word. A single-character string needs four words, the same as a four-character one. You can read the character codes out of the data.
> (hexdump-thing #())
lowtags: 1111
other: 0000001002511C3F : 0000001002511C30
1002511C30: 0000000000000089
1002511C38: 0000000000000000 = 0
> (hexdump-thing #(1))
lowtags: 1111
other: 00000010025152BF : 00000010025152B0
10025152B0: 0000000000000089
10025152B8: 0000000000000002 = 1
10025152C0: 0000000000000002 = 1
10025152C8: 0000000000000000 = 0
> (hexdump-thing #(1 2))
lowtags: 1111
other: 000000100252DC2F : 000000100252DC20
100252DC20: 0000000000000089
100252DC28: 0000000000000004 = 2
100252DC30: 0000000000000002 = 1
100252DC38: 0000000000000004 = 2
> (hexdump-thing #(1 2 3))
lowtags: 1111
other: 0000001002531C8F : 0000001002531C80
1002531C80: 0000000000000089
1002531C88: 0000000000000006 = 3
1002531C90: 0000000000000002 = 1
1002531C98: 0000000000000004 = 2
1002531CA0: 0000000000000006 = 3
1002531CA8: 0000000000000000 = 0
Same deal for simple vectors: header, length, but now each entry takes a word of course. Above all entries are fixnums and you can see them in the data.
And so it goes on.
The code that did this
This may be wrong and an earlier version of it definitely did not like small bignums (I think hexdump doesn't like them). If you want real answers either read the source or ask an SBCL person. Other implementations are available, and will be different.
(defun hexdump-thing (obj)
;; Try and hexdump an object, including immediate objects. All the
;; work is done by sb-vm:hexdump in the interesting cases.
#-(and SBCL 64-bit)
(error "not a 64-bit SBCL")
(let* ((address/thing (sb-kernel:get-lisp-obj-address obj))
(tags (ldb (byte 4 0) address/thing)))
(format t "~&lowtags: ~12T~4,'0b~%" tags)
(cond
((zerop (ldb (byte 1 0) tags))
(format t "~&fixnum:~12T~16,'0x = ~S~%" address/thing obj))
((= (ldb (byte 2 0) tags) #b01)
(format t "~&immediate:~12T~16,'0x = ~S~%" address/thing obj))
((= (ldb (byte 2 0) tags) #b11) ;must be true
(format t "~&~A:~12T~16,'0x : ~16,'0x~%"
(case (ldb (byte 2 2) tags)
(#b00 "instance")
(#b01 "cons")
(#b10 "function")
(#b11 "other"))
address/thing (dpb #b0000 (byte 4 0) address/thing))
;; this tells you at least something (and really annoyingly
;; does not pad addresses on the left)
(sb-vm:hexdump obj))
;; can't happen
(t (error "mutant"))))
(values))
Recently bought gy bme280 and trying to connect it with the Esp8266 Nodemcu V3 Esp 12.
Followed the instructions here for the hookup and then for the code, followed this tutorial.
I built the firmware from https://nodemcu-build.com/ a couple of days ago from master.
The debug logs shows this
Queue empty
Running
Function platform_gpio_mode() is called. pin_mux:1610614844, func:0
Function platform_gpio_mode() is called. pin_mux:1610614848, func:0
i2c setup result --> 100000
mode: b7
humidity oss: 5
config: f0
No ACK on address: 76
No ACK on address: 77
bme280 setup result -->
nil
pm open,type:2 0
My code
srv = net.createServer(net.TCP)
scl = 1
sda = 2
i2cResult = i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
print("i2c setup result --> " .. i2cResult)
local bmeResult = bme280.setup()
print("bme280 setup result --> ")
print(bmeResult)
The connections between BME280 and ESP8266 I have are
SDO -> G
CSB -> 3V
SDA -> D2
SCL -> D1
VCC -> 3V
GND -> G
Any idea of what is failing or what else can I do to troubleshoot it?
I'm looking to make sure that it is/isn't possible to write this statement more efficiently in Lua:
if (value == 1 or value == 2) then
something like this for an example (nonworking I assume):
if (value == (1 or 2)) then
or
if value == (1;2) then
Let's look at the produced bytecode as a proxy for speed. (Microbenchmarks are not reliable. Caching, pipelinging, branch prediction, … can have really weird effects that can make code that should be slower in principle perform better in practice in the context where you're actually using it. Bytecode size also isn't a very good indicator (same problems apply), but at least it's easy to produce, deterministic, and easy to interpret.)
(To follow along, throw your test files at luac -p -l, which will only parse (not write a compiled file) and list the resulting bytecode as a side-effect. If you want to understand the bytecode, have a look at the unofficial bytecode reference as initially created by Kein-Hong Man and kindly updated by Dibyendu Majumdar. But you don't have to.)
If value is a global variable, you'll get this:
1 [1] GETTABUP 0 0 -1 ; _ENV "value"
2 [1] EQ 1 0 -2 ; - 1 (fall through to next comparison)
3 [1] JMP 0 3 ; to 7 (true branch)
4 [1] GETTABUP 0 0 -1 ; _ENV "value"
5 [1] EQ 0 0 -3 ; - 2 (fall through into true branch)
6 [1] JMP 0 1 ; to 8 (beyond true branch)
Translating back into "pseudo-Lua", this is rougly
local r0 = _ENV["value"]
if r0 == 1 then goto true_branch end
local r0 = _ENV["value"]
if r0 ~= 2 then goto fin end
::true_branch::
-- stuff here
::fin::
If value is local (or a function argument) in the function where you use this, then you'll get something like this instead:
1 [1] EQ 1 0 -1 ; - 1
2 [1] JMP 0 2 ; to 5
3 [1] EQ 0 0 -2 ; - 2
4 [1] JMP 0 1 ; to 6
or roughly
if r0 == 1 then goto true_branch end
if r0 ~= 2 then goto fin end
::true_branch::
-- stuff here
::fin::
"Much" better!
So if value is a global variable (or an upvalue), doing
local value = value
if value == 1 or value == 2 then
-- stuff
end
will give you
1 [1] GETTABUP 0 0 -1 ; _ENV "value"
2 [1] EQ 1 0 -2 ; - 1
3 [1] JMP 0 2 ; to 6
4 [1] EQ 0 0 -3 ; - 2
5 [1] JMP 0 1 ; to 7
or
local r0 = _ENV["value"]
if r0 == 1 then goto true_branch end
if r0 == 2 then goto true_branch end
goto fin
::true_branch::
-- stuff here
::fin::
which saves one lookup. (While microbenchmarks will show a clear difference, in practice you'll almost never notice a difference. If you're doing a deeper lookup if foo.bar.baz == 1 or foo.bar.baz == 2 then it makes sense to local first, and it will probably also increase readability.)
I've been working on yasm assembly language and I generated a listing file that contains the following. I need help understanding how the memory displacement is computed in the first column. Thanks in advance.
1 %line 1+1 memory.asm
2 [section .data]
3 00000000 04000000 a dd 4
4 00000004 CDCC8C40 b dd 4.4
5 00000008 00000000<rept> c times 10 dd 0
6 00000030 01000200 d dw 1, 2
7 00000034 FB e db 0xfb
8 00000035 68656C6C6F20776F72- f db "hello world", 0
9 00000035 6C6400
Assembler is producing bytes (machine code), starting at some start address (here 0) and laying them next to each other. So first a dd 4 produces 4 bytes of data 04 00 00 00, thus memory at addresses 0, 1, 2 and 3 are filled up. Next free slot is at address 4. There goes b dd 4.4, again 4 bytes long. c times 10 dd 0 is 40 bytes long, so 8+40 = 48 (0x30) => next free slot.
Is the current Lua compiler smart enough to optimize away local variables that are used for clarity?
local top = x - y
local bottom = x + y
someCall(top, bottom)
Or does inlining things by hand run faster?
someCall(x - y, x + y)
Since Lua often compiles source code into byte code on the fly, it is designed to be a fast single-pass compiler. It does do some constant folding, but other than that there are not many optimizations. You can usually check what the compiler does by executing luac -l -l -p file.lua and looking at the generated (disassembled) byte code.
In your case the Lua code
function a( x, y )
local top = x - y
local bottom = x + y
someCall(top, bottom)
end
function b( x, y )
someCall(x - y, x + y)
end
results int the following byte code listing when run through luac5.3 -l -l -p file.lua (some irrelevant parts skipped):
function <file.lua:1,5> (7 instructions at 0xcd7d30)
2 params, 7 slots, 1 upvalue, 4 locals, 1 constant, 0 functions
1 [2] SUB 2 0 1
2 [3] ADD 3 0 1
3 [4] GETTABUP 4 0 -1 ; _ENV "someCall"
4 [4] MOVE 5 2
5 [4] MOVE 6 3
6 [4] CALL 4 3 1
7 [5] RETURN 0 1
constants (1) for 0xcd7d30:
1 "someCall"
locals (4) for 0xcd7d30:
0 x 1 8
1 y 1 8
2 top 2 8
3 bottom 3 8
upvalues (1) for 0xcd7d30:
0 _ENV 0 0
function <file.lua:7,9> (5 instructions at 0xcd7f10)
2 params, 5 slots, 1 upvalue, 2 locals, 1 constant, 0 functions
1 [8] GETTABUP 2 0 -1 ; _ENV "someCall"
2 [8] SUB 3 0 1
3 [8] ADD 4 0 1
4 [8] CALL 2 3 1
5 [9] RETURN 0 1
constants (1) for 0xcd7f10:
1 "someCall"
locals (2) for 0xcd7f10:
0 x 1 6
1 y 1 6
upvalues (1) for 0xcd7f10:
0 _ENV 0 0
As you can see, the first variant (the a function) has two additional MOVE instructions, and two additional locals.
If you are interested in the details of the opcodes, you can check the comments for the OpCode enum in lopcodes.h.
E.g. the opcode format for OP_ADD is:
OP_ADD,/* A B C R(A) := RK(B) + RK(C) */
So the 2 [3] ADD 3 0 1 from above takes the values from registers 0 and 1 (the locals x and y in this case), adds them together, and stores the result in register 3. It is the second opcode in this function and the corresponding source code is on line 3.