-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DemoHelloAPI.init is called again after DeviceAPI.open is called #2
Comments
Update: I tried renaming the |
Appears the issue was with the port. I changed as follows and it doesn't repeat the init call. However it doesn't progress past the "open" step of the sequence. Here is the updated DemoHelloAPI.js example, which gets the port automatically. I also commented out the option to skipCapabilities because I found it was not necessary to skip. // This module exercises the high-level API interface to a DDHello
// Luni device driver running on a remote Arduino under Firmata.
//
// This program is strict-mode throughout.
//
// Doug Johnson, May 2016
const log4js = require("log4js");
const path = require("path");
const thisModule = path.basename(module.filename,".js");
const log = log4js.getLogger(thisModule);
log.setLevel('TRACE');
const API = require("../lib/HelloAPI");
const RDD = API.RDD;
const Sequencer = require("../lib/Sequencer").Sequencer;
const firmata = require("firmata");
const unitName = "Hello:0";
const exitAtEnd = false;
let firmataBoard;
let proxyRDD;
let api;
let seq;
let handle;
// Set up
const init = () => {
firmata.Board.requestPort(function(error, port) {
if (error) {
log.debug(error);
return;
}
//let opts = {skipCapabilities: true};
let opts = {};
firmataBoard = new firmata.Board(port.comName, opts, () => {
log.debug(`Board is ready.`);
proxyRDD = new RDD.RemoteDeviceDriver({board: firmataBoard});
log.debug(`RemoteDeviceDriver is ready.`);
api = new API.HelloAPI({driver : proxyRDD});
log.debug(`HelloAPI is created.`);
seq = new Sequencer(api,["open", "read", "write", "close", "read-continuous"]);
log.debug(`Sequencer is created.`);
seq.on("error", (apiError) => {
log.error(`Error ${RDD.SC[apiError.status].sym} (${apiError.status}) ${RDD.SC[apiError.status].msg}.`);
});
seq.on("done", (apiResult) => {
if (exitAtEnd) {
log.info(`Goodbye.`);
firmataBoard.transport.close();
} else {
log.info(`Steps completed.`);
}
}
);
seq.start(step);
});
});
};
// Everything has been opened and we have a handle by the time this step
// sequence is started. Assuming that each of the following step functions
// will result in one of the events captured above, we will progress through
// the following async steps in order.
let step = [
(apiResult) => {
log.info(`Begin step processing.`);
api.open(unitName,RDD.DAF.FORCE,0);
},
(apiResult) => {
log.info(`Opened ${apiResult.unitName} with handle ${apiResult.handle}.`);
handle = apiResult.handle;
api.getGreeting(handle);
},
(apiResult) => {
log.info(`${unitName} says ${apiResult.data}`);
api.getGreeting(handle);
},
(apiResult) => {
log.info(`${unitName} says ${apiResult.data}`);
api.setGreeting(handle, "blah, blah");
},
(apiResult) => {
log.info(`New greeting has been set.`);
api.getGreeting(handle);
},
(apiResult) => {
log.info(`${unitName} says ${apiResult.data}`);
api.setIntervals(handle,null,1000);
},
(apiResult) => {
log.info(`New intervals have been set.`);
api.getContinuousGreeting(handle);
},
(apiResult) => {
log.info(`Continuous greeting started.`);
if (exitAtEnd) {
api.close(handle);
} else {
api.on("read-continuous", (apiResult) => {
log.info(`${unitName} says ${apiResult.data}`);
});
}
},
(apiResult) => {
if (apiResult.eventType === "close") {
log.info(`Closed handle ${apiResult.handle}. Goodbye.`);
firmataBoard.transport.close();
}
}
];
// Start the engine running
log.info(`Program ${thisModule} is running.`);
init(); |
Okay it is working now. I had to remove additional Firmata features and run on a Leonardo rather than Uno (Leonard has an additional 500 bytes of SRAM). It appears that even when the compiler reports a few hundred bytes of available RAM, that memory is actually running out and the application running on the board is freezing. I assume you may be using a lot of dynamic memory allocation in your Luni lib stack? If so I'd recommend changing to static allocation wherever possible so the available memory is more realistic. Use fixed static buffers for Strings and reuse them rather than dynamically allocating, etc. |
To provide additional context on the amount of memory being consumed at run-time, if I compile and upload to an Arduino Uno (excluding the following Firmata features in ConfigurableFirmataDeviceDriver.ino: Servo, I2C, OneWire, Stepper, Serial, Scheduler), the compiler reports the board has 701 bytes of dynamic memory available. If I run DemoHelloAPI.js, memory on the board appears to run out just after the handle is opened. Here's the console output:
With a Leonardo, because of the extra 500 bytes of memory I can get past that point and program execution continues successfully. There is either way to much dynamic memory consumed (for a microcontroller at least) or there is a leak somewhere. |
Jeff: Yes, memory is an issue, and I used dynamic allocation more than is probably a good idea in the long term. I’m hoping to be able to take the time to comb the code for specific issues. One thing is the way I built the read/write continuous functions. I reserve space in each LogicalUnitInfo object for two complete commands to be repeated. This takes a fair amount of memory. Another issue is the memory used by compiled but removed modules. When I took those out of the picture entirely, I saved something like 260 bytes of SRAM with no loss of functionality. There are some things that can go in EEPROM, but at least at first glance, it didn’t look like it would save as much SRAM as I’d hoped. I am a believer in the role of ‘don’t do premature optimization', so I haven’t worried too much about the issue as long as I could configure something that would run. If the functionality seems useful to you and others, then it’ll definitely be time for a thorough memory improvement review. The UNO has 2 KB (ATmega328P), and the Leonardo has 2.5 KB (ATmega32u4), so I agree that the extra memory helps. However, it’s only 500 bytes difference, not 500 K (I wish!) As you say, memory is an issue, and I just got an Uno a few weeks ago specifically to test this configuration. However, my main interest is in being able to write code that handles more functionality on the Arduino side and that does not cause more Firmata protocol pollution as time goes on, so I’ve kind of deferred worrying about low memory devices too much and focussed on the interfaces and capabilities for now. Thanks for your testing and analysis, it’s much appreciated! Doug
|
My ideal minimum memory target for anything included in ConfigurableFirmata is that it should be able to run on an Arduino Uno (still the most popular Arduino board by far) with the following Firmata features included (basically the same as StandardFirmata): DigitalInputFirmata, DigitalOutputFirmata, AnalogInputFirmata, AnalogOutputFirmata, ServoFirmata, I2CFirmata, FirmataExt. |
Sounds good. I did most of the early development with everything there except I2C and Servo. Will work on getting to your list.
|
After a couple of weekends out of town I finally have time to continue testing DeviceFirmata. In attempting to run the DemoHelloAPI example, I see that init is called a second time after DeviceAPI.open is called. I don't see anything in the application flow that would trigger this, but it is what I'm observing. Same for DemoMetaAPI.
This is the error message I get (I added a console log just inside the init function):
The SYSEX_RESPONSE error is due to the second call to init, where the first call already populated the 0x5F command id.
The text was updated successfully, but these errors were encountered: