Callbacks and context

Hey, I’m having some trouble getting an agent.on callback to work and I’m pretty sure the problem is that one of my functions doesn’t have the right context. Here’s a simplified version of my code:


function update (updates) {
update_sensor.call(sensor_0, updates)
update_sensor.call(sensor_1, updates)
update_sensor.call(sensor_2, updates)
update_sensor.call(sensor_3, updates)
update_chip.call(chip, updates.chip)
initialize.call(chip)
}

local sensor_0 = Sensor(“Not configured”)
local sensor_1 = Sensor(“Mike”, 0xfff)
local sensor_2 = Sensor(“Steve”)
local sensor_3 = Sensor(“Not configured”)

local sensor_package = [sensor_0, sensor_1, sensor_2, sensor_3]

local chip = Sensor_chip(“myFDC”,sensor_package,other_stuff)

agent.on(“update_from_agent”, update.bindenv(this))


Basically I’m updating the registers on a chip that has 4 sensor channels. So the agent sends an update file that includes parameters for both the sensors and the chip. Each sensor instance should be updated, followed by the chip instance itself, and then the registers are all written with an initialize call to the chip instance. As you can see, there are 4 sensor objects (sensor_0, sensor_1, sensor_2, and sensor_3) and one chip object (chip). The “sensor_package” associates a sensor with a channel on the chip but I don’t think that’s relevant to my issue.

When I execute this code, I get an ‘index not found for sensor_0’ error on the ‘update_sensor.call(sensor_0, updates)’ line. So clearly the update function does not have the context it needs to see the sensor_0 instance. I think I understand how to provide context when the context is a function (or an instance), but how do you provide context when you need something from the main body of the code? I tried adding a ‘bindenv’ to the agent.on code but that didn’t work. I think, since the agent.on function is essentially without context when called back (is that right?) that the ‘this’ context I used is either limited to the agent.on function or it has no value at all.

I’m sure I could fix this by having one update ‘agent.on’ function for each item that needs updating (then I could just pass the target instance’s context straight from the agent.on function) but is there a way to essentially have the update function affect multiple instances?

Any ideas?

Thanks!

Scott

If update_sensor is a method of your Sensor object, there are multiple ways of calling it. You could use:

sensor_0.update_sensor.call(sensor_0,updates);
or:
Sensor.update_sensor.call(sensor_0,updates);
or:
Sensor.update_sensor.bindenv(sensor_0)(updates);
or most simply:
sensor_0.update_sensor(updates);

You generally don’t need to use the call method at all.

Is your function update() in the root level of your code? If you are using bindenv(this) for agent.on, you need to make sure that it is called in a similar scope to where update() is declared.

coverdriven, thanks very much for your reply. To answer your question, the update() function is at the root level of my code. The block you see is all at the root level. At one point I had the update_sensor() and update_chip() functions at the root level too - but I’ve moved them into the objects with no change in outcome.

Unless I pass the sensor_0 object to the function the function can’t access the object. For example, this doesn’t work either (and I understand why):


1: function update (updates) {
2: sensor_0.update_sensor(updates)
3: }
4:
5: local sensor_0 = Sensor(“Not configured”)
6:
7: update(updates)

//Error - sensor_0 index not found line 2


Can be made to work pretty easily:


function update (updates, obj) {
obj.update_sensor(updates)
}

local sensor_0 = Sensor(“Not configured”)

update(updates, sensor_0)

//I pass sensor_0 to the update() function and the function can work with the sensor


or even (haven’t tried this but if I understand this then it should):


function update (updates) {
update_sensor(updates)
}

local sensor_0 = Sensor(“Not configured”)

update.call(sensor_0, updates) //presuming update_sensor is defined in Sensor


But if the update() function is a callback I don’t know how you get device-local objects into the function. AFAIK the only parameter a callback function can take is the argument from agent.send. That’s why I was trying to use bindenv or call to “inform” update() where to find sensor_0’s update_sensor() function.

I guess I could just make the sensor and chip objects globals and call it a day. :slight_smile:

Again, thanks.

Scott

Local variables, declared using “local”, do not count as members of any object. In particular they are not added to the current context object. The best way to do what you want, is to make a class (or table), put the “sensor_0” object in that table, and use the table as the context object (i.e. bindenv the callback to the table).

Peter

peter, thanks for the aha! moment. If I bindenv() to the chip, I can access the sensor table that’s in the chip and manipulate all the objects I need to work with from there. So I don’t really need to use context from multiple items, or to globalize my local variables since all the instances were already in the chip.

For anyone who’s having a similar problem, here’s a simplified version of how peter’s suggestion fixed it:


function update (updates) {

//iterate through the sensors provided in the update table
foreach (idx, sensor in updates) {

// use the chip’s sensor table (called ‘sensor_package’) to access the sensor object and its name, then set it
sensor_package[idx]["_name"] = sensor.name
}
}

local sensor_0 = Sensor(“Not configured”) // the first parameter is the sensor name
local sensor_1 = Sensor(“Mike”, 0xfff)
local sensor_2 = Sensor(“Steve”)
local sensor_3 = Sensor(“Not configured”)

local sensor_package = [sensor_0, sensor_1, sensor_2, sensor_3]

local chip = Sensor_chip(“myFDC”,sensor_package,other_stuff)

agent.on(“update_from_agent”, update.bindenv(chip))


With gratitude,

Scott