Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maker: Fix accelerometer #13843

Merged
merged 3 commits into from Mar 16, 2017
Merged

Maker: Fix accelerometer #13843

merged 3 commits into from Mar 16, 2017

Conversation

islemaster
Copy link
Contributor

Gets the accelerometer component working again.

Fixes two major problems:

  1. accelerometer.start() was removed when I upgraded playground-io in Upgrade playground-io聽#12979 - obviously I didn't test that change well enough. The method was removed in favor of lazy-enabling streaming when an event handler gets attached, but in some cases we just want to read accelerometer properties, not attach events.

  2. Accelerometer events were only working on the first run after a page load. This is because only the first Playground instance was attaching a sysex-response (incoming data) handler, which in turn happens because Firmata tracks these handlers in a static context and complains if you try to replace one 馃槨 - I've already made a small change to avoid reattaching a handler but in our case we do actually want to replace it, both at the Playground and Firmata level - so I'm doing that invasively for now, and we'll look at improvements to those libraries down the road.

The latter was probably interfering with other sensors/components too, I'm not sure how much though.

Some changes I'm explicitly not addressing here, in the interest of quickly "unbreaking" the accelerometer:

  • Removing accelerometer.start() in favor of blocking reads on accelerometer properties if streaming is not yet enabled.
  • Deeper fixes to Firmata and playground-io that might make some of these changes unnecessary.

Manually deregisters Firmata's sysex response handler for Circuit Playground commands (`CP_COMMAND`) on destroy, and clears the playground-io flag that normally prevents it from registering its handler more than once per static context.  This allows each new playground instance to register its own handler, which makes the accelerometer reset properly and work beyond the initial run on a page load.
In the playground-io upgrade, accelerometer.start() was removed in favor of lazily enabling streaming when an event was attached.  Unfortunately we have some use cases where we want to read the accelerometer without attaching an event handler, so this change puts accelerometer.start() back.
if (Firmata.SYSEX_RESPONSE) {
delete Firmata.SYSEX_RESPONSE[CP_COMMAND];
}
delete Playground.hasRegisteredSysexResponse;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the fix for problem 2: On destroy, we clear playground-io's handler for incoming data out of Firmata's static handler list, and tell playground-io that it's okay to re-register next time it's constructed. This makes me 馃槩 because it means we can't construct more than one CircuitPlaygroundBoard at a time and have them work, but in practice that's a nonissue for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd love to see a TODO comment here for the desired library improvment


accelerometer.start = function () {
accelerometer.io.sysexCommand([CP_COMMAND, CP_ACCEL_STREAM_ON]);
};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restoring the start() function. See how playground-io enables accelerometer streaming when an event handler is attached. I confirmed that it's a no-op to send this command more than once.

Practical upshot is that you don't actually need to call this if you're using accelerometer events, but if you just want to read accelerometer.x or something you'll need to call start() first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously this should move down into forked playground-io at some point (maybe all three extra methods here should) but I'd like to get this unbroken first.

// This is a fragile approach to testing this fix, but reproducing the
// real problem in tests is going to be near-impossible since we stub
// Firmata at the webpack layer in our tests.
expect(Playground.hasRegisteredSysexResponse).to.be.undefined;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to suggestions on better ways to harden against this problem, given that we have to stub Firmata.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also just stub playground.handlers[CP_ACCEL_STREAM_ON] to be a Chai spy?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. Do you mean handlers[CP_ACCEL_READ_REPLY]? CP_ACCEL_STREAM_OUT is a command out to the board, not a message we'd expect in a sysex response; and mock-firmata really isn't set up to simulate such a response anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, indeed I did!

@Hamms Hamms self-assigned this Mar 16, 2017
Copy link
Contributor

@Hamms Hamms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The joys of working with a deep dependency chain :/

It seems exceptionally weird to me that this is an issue we have to deal with; why is it that these libraries aren't handling dis- and re-connecting all on their own?

if (Firmata.SYSEX_RESPONSE) {
delete Firmata.SYSEX_RESPONSE[CP_COMMAND];
}
delete Playground.hasRegisteredSysexResponse;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd love to see a TODO comment here for the desired library improvment

// This is a fragile approach to testing this fix, but reproducing the
// real problem in tests is going to be near-impossible since we stub
// Firmata at the webpack layer in our tests.
expect(Playground.hasRegisteredSysexResponse).to.be.undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also just stub playground.handlers[CP_ACCEL_STREAM_ON] to be a Chai spy?

@islemaster
Copy link
Contributor Author

As to why the libraries aren't handling this themselves... well, your guess is as good as mine. Rick opposed the addition of an exit() function to Firmata a while back, but it might be opposition to the particular implementation which didn't clean up any of Firmata.js' internal state. It's possible there are too many pieces to this puzzle and no one of them wants to own cleanup logic, so we've got to own it ourselves... still, you wonder if blocks like this couldn't exist outside of some test mode.

@islemaster islemaster merged commit 2090ed8 into staging Mar 16, 2017
@islemaster islemaster deleted the maker-fix-accelerometer branch March 16, 2017 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants