diff --git a/inc/MicroBit.h b/inc/MicroBit.h index 9c8bd12..b80b561 100644 --- a/inc/MicroBit.h +++ b/inc/MicroBit.h @@ -68,6 +68,7 @@ class MicroBit private: void compassCalibrator(MicroBitEvent e); + void onABListenerRegisteredEvent(MicroBitEvent evt); uint32_t randomValue; //the current tick period in MS diff --git a/inc/MicroBitButton.h b/inc/MicroBitButton.h index 58cae34..eff8691 100644 --- a/inc/MicroBitButton.h +++ b/inc/MicroBitButton.h @@ -90,6 +90,25 @@ class MicroBitButton : public MicroBitComponent */ int isPressed(); + /** + * Changes the event configuraiton of this button to the given value. + * All subsequent events generated by this button will then be informed by this configuraiton. + * + * @param config The new configuration for this button. Legal values are MICROBIT_BUTTON_ALL_EVENTS or MICROBIT_BUTTON_SIMPLE_EVENTS. + * + * Example: + * @code + * + * // Configure a button to generate all possible events. + * uBit.buttonA.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS); + * + * // Configure a button to suppress MICROBIT_BUTTON_EVT_CLICK and MICROBIT_BUTTON_EVT_LONG_CLICK events. + * uBit.buttonA.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS); + * + * @endcode + */ + void setEventConfiguration(MicroBitButtonEventConfiguration config); + /** * periodic callback from MicroBit clock. * Check for state change for this button, and fires a hold event if button is pressed. @@ -100,10 +119,6 @@ class MicroBitButton : public MicroBitComponent * Destructor for MicroBitButton, so that we deregister ourselves as a systemComponent */ ~MicroBitButton(); - - private: - void onMultiButtonAttachEvent(MicroBitEvent evt); - }; #endif diff --git a/inc/MicroBitMultiButton.h b/inc/MicroBitMultiButton.h index 43434d3..5596fec 100644 --- a/inc/MicroBitMultiButton.h +++ b/inc/MicroBitMultiButton.h @@ -21,16 +21,15 @@ class MicroBitMultiButton : public MicroBitComponent { uint16_t button1; // ID of the first button we're monitoring uint16_t button2; // ID of the second button we're monitoring + MicroBitButtonEventConfiguration eventConfiguration; // Do we want to generate high level event (clicks), or defer this to another service. uint16_t otherSubButton(uint16_t b); int isSubButtonPressed(uint16_t button); int isSubButtonHeld(uint16_t button); int isSubButtonSupressed(uint16_t button); - int isListenerAttached(); void setButtonState(uint16_t button, int value); void setHoldState(uint16_t button, int value); void setSupressedState(uint16_t button, int value); - void setListenerAttached(int value); public: @@ -72,9 +71,36 @@ class MicroBitMultiButton : public MicroBitComponent */ int isPressed(); + /** + * Changes the event configuraiton of this button to the given value. + * All subsequent events generated by this button will then be informed by this configuraiton. + * + * @param config The new configuration for this button. Legal values are MICROBIT_BUTTON_ALL_EVENTS or MICROBIT_BUTTON_SIMPLE_EVENTS. + * + * Example: + * @code + * + * // Configure a button to generate all possible events. + * uBit.buttonAB.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS); + * + * // Configure a button to suppress MICROBIT_BUTTON_EVT_CLICK and MICROBIT_BUTTON_EVT_LONG_CLICK events. + * uBit.buttonAB.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS); + * + * @endcode + * + * Possible Events: + * @code + * MICROBIT_BUTTON_EVT_DOWN + * MICROBIT_BUTTON_EVT_UP + * MICROBIT_BUTTON_EVT_CLICK + * MICROBIT_BUTTON_EVT_LONG_CLICK + * MICROBIT_BUTTON_EVT_HOLD + * @endcode + */ + void setEventConfiguration(MicroBitButtonEventConfiguration config); + private: void onButtonEvent(MicroBitEvent evt); - void onListenerRegisteredEvent(MicroBitEvent evt); }; #endif diff --git a/source/MicroBit.cpp b/source/MicroBit.cpp index 868f18f..09290f2 100644 --- a/source/MicroBit.cpp +++ b/source/MicroBit.cpp @@ -65,6 +65,23 @@ void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *) uBit.ble->startAdvertising(); } +void MicroBit::onABListenerRegisteredEvent(MicroBitEvent evt) +{ + (void) evt; // Unused parameter + + // A user has registered to receive events from the buttonAB multibutton. + // Disable click events from being generated by ButtonA and ButtonB, and defer the + // control of this to the multibutton handler. + // + // This way, buttons look independent unless a buttonAB is requested, at which + // point button A+B clicks can be correclty handled without breaking + // causal ordering. + + buttonA.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS); + buttonB.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS); + buttonAB.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS); +} + /** * Constructor. @@ -141,6 +158,7 @@ void MicroBit::init() // Register our compass calibration algorithm. MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CALIBRATE, this, &MicroBit::compassCalibrator, MESSAGE_BUS_LISTENER_IMMEDIATE); + MessageBus.listen(MICROBIT_ID_MESSAGE_BUS_LISTENER, MICROBIT_ID_BUTTON_AB, this, &MicroBit::onABListenerRegisteredEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); } /** diff --git a/source/MicroBitButton.cpp b/source/MicroBitButton.cpp index 1d1c3dd..f158125 100644 --- a/source/MicroBitButton.cpp +++ b/source/MicroBitButton.cpp @@ -29,16 +29,28 @@ MicroBitButton::MicroBitButton(uint16_t id, PinName name, MicroBitButtonEventCon this->downStartTime = 0; this->sigma = 0; uBit.addSystemComponent(this); - - uBit.MessageBus.listen(MICROBIT_ID_MULTIBUTTON_ATTACH, id, this, &MicroBitButton::onMultiButtonAttachEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); } -void MicroBitButton::onMultiButtonAttachEvent(MicroBitEvent evt) +/** + * Changes the event configuraiton of this button to the given value. + * all subsequent events generated by this button will then be informed by this configuration. + * + * @param config the new configuration for this button. legal values are MICROBIT_BUTTON_ALL_EVENTS or MICROBIT_BUTTON_SIMPLE_EVENTS. + * + * example: + * @code + * + * // configure a button to generate all possible events. + * uBit.buttonA.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS); + * + * // configure a button to suppress MICROBIT_BUTTON_EVT_CLICK and MICROBIT_BUTTON_EVT_LONG_CLICK events. + * uBit.buttonA.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS); + * + * @endcode + */ +void MicroBitButton::setEventConfiguration(MicroBitButtonEventConfiguration config) { - (void) evt; // Unused parameter - - // This button is now part of a button group. Suppress individual events (such as click) from being generated. - this->eventConfiguration = MICROBIT_BUTTON_SIMPLE_EVENTS; + this->eventConfiguration = config; } /** diff --git a/source/MicroBitMultiButton.cpp b/source/MicroBitMultiButton.cpp index 83ad3a7..20d93b7 100644 --- a/source/MicroBitMultiButton.cpp +++ b/source/MicroBitMultiButton.cpp @@ -28,10 +28,10 @@ MicroBitMultiButton::MicroBitMultiButton(uint16_t id, uint16_t button1, uint16_t this->id = id; this->button1 = button1; this->button2 = button2; + this->eventConfiguration = MICROBIT_BUTTON_SIMPLE_EVENTS; uBit.MessageBus.listen(button1, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); uBit.MessageBus.listen(button2, MICROBIT_EVT_ANY, this, &MicroBitMultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); - uBit.MessageBus.listen(MICROBIT_ID_MESSAGE_BUS_LISTENER, id, this, &MicroBitMultiButton::onListenerRegisteredEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); } uint16_t MicroBitMultiButton::otherSubButton(uint16_t b) @@ -72,20 +72,6 @@ int MicroBitMultiButton::isSubButtonSupressed(uint16_t button) return 0; } -int MicroBitMultiButton::isListenerAttached() -{ - return status & MICROBIT_MULTI_BUTTON_ATTACHED; -} - -void MicroBitMultiButton::setListenerAttached(int value) -{ - if (value) - status |= MICROBIT_MULTI_BUTTON_ATTACHED; - else - status &= ~MICROBIT_MULTI_BUTTON_ATTACHED; -} - - void MicroBitMultiButton::setButtonState(uint16_t button, int value) { if (button == button1) @@ -143,15 +129,26 @@ void MicroBitMultiButton::setSupressedState(uint16_t button, int value) } } -void MicroBitMultiButton::onListenerRegisteredEvent(MicroBitEvent evt) +/** + * Changes the event configuraiton of this button to the given value. + * All subsequent events generated by this button will then be informed by this configuration. + * + * @param config the new configuration for this button. legal values are MICROBIT_BUTTON_ALL_EVENTS or MICROBIT_BUTTON_SIMPLE_EVENTS. + * + * example: + * @code + * + * // configure a button to generate all possible events from attached buttons. + * uBit.buttonAB.setEventConfiguration(MICROBIT_BUTTON_ALL_EVENTS); + * + * // configure a button to suppress MICROBIT_BUTTON_EVT_CLICK and MICROBIT_BUTTON_EVT_LONG_CLICK events. + * uBit.buttonAB.setEventConfiguration(MICROBIT_BUTTON_SIMPLE_EVENTS); + * + * @endcode + */ +void MicroBitMultiButton::setEventConfiguration(MicroBitButtonEventConfiguration config) { - (void) evt; // Unused parameter - - // Simply indicate to the buttons we are tracking that they are now part of a button group. - // As a result, they will suppress some individual events from being generated. - MicroBitEvent(MICROBIT_ID_MULTIBUTTON_ATTACH, button1); - MicroBitEvent(MICROBIT_ID_MULTIBUTTON_ATTACH, button2); - setListenerAttached(1); + this->eventConfiguration = config; } void MicroBitMultiButton::onButtonEvent(MicroBitEvent evt) @@ -187,7 +184,7 @@ void MicroBitMultiButton::onButtonEvent(MicroBitEvent evt) setSupressedState(otherButton, 1); } - else if (!isSubButtonSupressed(button) && isListenerAttached()) + else if (!isSubButtonSupressed(button) && eventConfiguration == MICROBIT_BUTTON_ALL_EVENTS) { if (isSubButtonHeld(button)) MicroBitEvent e(button, MICROBIT_BUTTON_EVT_LONG_CLICK);