luanodemcu

Problem with upvalue in nodemcu on ESP8266


On a ESP8266 with nodemcu and LUA 5.1 I need to use an upvalue to process a turn event for a rotary encoder. However this variable is always NIL. As I understand the principle of upvalues, the variable sv should be passed the the callback of the 'turn' function, but it is not. What I miss by understanding of upvalues?

local turn = function(type, pos, when)
    print(type, pos, when, sv.value)
    if type == rotary.TURN then
        local move = sv.last - pos
        sv.last = pos
        sv.x = sv.value + move
        local tm
        if tm == nil then
            tm = tmr.create()
            tm:register(500, tmr.ALARM_SINGLE, function()
                setTo(sv)
            end)
        end
        tm:start()                  
    end
end

local setupRotary = function(sv)
    local ch, a, b, sw = sv.rotary_ch, sv.rotary_a, sv.rotary_b, sv.rotary_sw
    print(ch, a, b, sw)
    rot.init(ch, a, b, 1, sw)
    sv.last = 0
    rot.on(ch, rot.TURN, turn)
end

By the way, "rot" is also a lua module. When I rotate the encoder, I get "attempt to index global 'sv' (a nil value)" at the first line of th "turn" function.


Solution

  • The manual describes upvalue as follows:

    A local variable used by an inner function is called an upvalue, or external local variable, inside the inner function.

    turn is not an inner function of setupRotary, so sv will not be passed.

    You can fix this problem by moving the function inside:

    local turn
    
    local setupRotary = function(sv)
        turn = function(type, pos, when)
            -- here sv is visible
        end
    end