microbit-dal: Added events to MicroBitPin

Added rise, fall, pulse HI and LO events.

The pulse Hi and LO event timestamp given in the MicroBitEvent is the
duration for which the input was HI or LO for.

eventOn(int eventType) is used to configure the events generated
from the pin instance.
master
James Devine 7 years ago
parent 3923dffffc
commit 732971e758
  1. 83
      inc/drivers/MicroBitPin.h
  2. 59
      inc/drivers/TimedInterruptIn.h
  3. 1
      source/CMakeLists.txt
  4. 161
      source/drivers/MicroBitPin.cpp
  5. 55
      source/drivers/TimedInterruptIn.cpp

@ -35,7 +35,8 @@ DEALINGS IN THE SOFTWARE.
#define IO_STATUS_ANALOG_IN 0x04 // Pin is Analog in
#define IO_STATUS_ANALOG_OUT 0x08 // Pin is Analog out
#define IO_STATUS_TOUCH_IN 0x10 // Pin is a makey-makey style touch sensor
#define IO_STATUS_EVENTBUS_ENABLED 0x80 // Pin is will generate events on change
#define IO_STATUS_EVENT_ON_EDGE 0x20 // Pin will generate events on pin change
#define IO_STATUS_EVENT_PULSE_ON_EDGE 0x40 // Pin will generate events on pin change
//#defines for each edge connector pin
#define MICROBIT_PIN_P0 P0_3 //P0 is the left most pad (ANALOG/DIGITAL) used to be P0_3 on green board
@ -64,6 +65,15 @@ DEALINGS IN THE SOFTWARE.
#define MICROBIT_PIN_DEFAULT_SERVO_RANGE 2000
#define MICROBIT_PIN_DEFAULT_SERVO_CENTER 1500
#define MICROBIT_PIN_EVENT_NONE 0
#define MICROBIT_PIN_EVENT_ON_EDGE 1
#define MICROBIT_PIN_EVENT_ON_PULSE 2
#define MICROBIT_PIN_EVENT_ON_TOUCH 3
#define MICROBIT_PIN_EVT_RISE 2
#define MICROBIT_PIN_EVT_FALL 3
#define MICROBIT_PIN_EVT_PULSE_HI 4
#define MICROBIT_PIN_EVT_PULSE_LO 5
/**
* Pin capabilities enum.
@ -103,6 +113,43 @@ class MicroBitPin : public MicroBitComponent
*/
int obtainAnalogChannel();
/**
* Interrupt handler for when an rise interrupt is triggered.
*/
void onRise();
/**
* Interrupt handler for when an fall interrupt is triggered.
*/
void onFall();
/**
* This member function manages the calculation of the timestamp of a pulse detected
* on a pin whilst in IO_STATUS_EVENT_PULSE_ON_EDGE or IO_STATUS_EVENT_ON_EDGE modes.
*
* @param eventValue the event value to distribute onto the message bus.
*/
void pulseWidthEvent(int eventValue);
/**
* This member function will construct an TimedInterruptIn instance, and configure
* interrupts for rise and fall.
*
* @param eventType the specific mode used in interrupt context to determine how an
* edge/rise is processed.
*
* @return MICROBIT_OK on success
*/
int enableRiseFallEvents(int eventType);
/**
* If this pin is in a mode where the pin is generating events, it will destruct
* the current instance attached to this MicroBitPin instance.
*
* @return MICROBIT_OK on success.
*/
int disableEvents();
public:
// mbed PinName of this pin.
@ -143,8 +190,9 @@ class MicroBitPin : public MicroBitComponent
/**
* Configures this IO pin as a digital input (if necessary) and tests its current value.
*
*
* @return 1 if this input is high, 0 if input is LO, or MICROBIT_NOT_SUPPORTED
* if the given pin does not have analog capability.
* if the given pin does not have digital capability.
*
* @code
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
@ -292,6 +340,37 @@ class MicroBitPin : public MicroBitComponent
* given pin is not configured as an analog output.
*/
int getAnalogPeriod();
/**
* Configures the events generated by this MicroBitPin instance.
*
* MICROBIT_PIN_EVENT_ON_EDGE - Configures this pin to a digital input, and generates events whenever a rise/fall is detected on this pin. (MICROBIT_PIN_EVT_RISE, MICROBIT_PIN_EVT_FALL)
* MICROBIT_PIN_EVENT_ON_PULSE - Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either HI or LO. (MICROBIT_PIN_EVT_PULSE_HI, MICROBIT_PIN_EVT_PULSE_LO)
* MICROBIT_PIN_EVENT_ON_TOUCH - Configures this pin as a makey makey style touch sensor, in the form of a MicroBitButton. Normal button events will be generated using the ID of this pin.
* MICROBIT_PIN_EVENT_NONE - Disables events for this pin.
*
* @param eventType One of: MICROBIT_PIN_EVENT_ON_EDGE, MICROBIT_PIN_EVENT_ON_PULSE, MICROBIT_PIN_EVENT_ON_TOUCH, MICROBIT_PIN_EVENT_NONE
*
* @code
* MicroBitMessageBus bus;
*
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
* P0.eventOn(MICROBIT_PIN_EVENT_ON_PULSE);
*
* void onPulse(MicroBitEvent evt)
* {
* int duration = evt.timestamp;
* }
*
* bus.listen(MICROBIT_ID_IO_P0, MICROBIT_PIN_EVT_PULSE_HI, onPulse, MESSAGE_BUS_LISTENER_IMMEDIATE)
* @endcode
*
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the given eventype does not match
*
* @note In the MICROBIT_PIN_EVENT_ON_PULSE mode, the smallest pulse that was reliably detected was 85us, around 5khz. If more precision is required,
* please use the InterruptIn class supplied by ARM mbed.
*/
int eventOn(int eventType);
};
#endif

@ -0,0 +1,59 @@
/*
The MIT License (MIT)
Copyright (c) 2016 Lancaster University, UK.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef TIMED_INTERRUPT_H
#define TIMED_INTERRUPT_H
#include "mbed.h"
#include "MicroBitConfig.h"
class TimedInterruptIn : public InterruptIn
{
uint64_t timestamp;
public:
/**
* Constructor.
*
* Create an instance of TimedInterruptIn that has an additional timestamp field.
*/
TimedInterruptIn(PinName name);
/**
* Stores the given timestamp for this instance of TimedInterruptIn.
*
* @param timestamp the timestamp to retain.
*/
void setTimestamp(uint64_t timestamp);
/**
* Retrieves the retained timestamp for this instance of TimedInterruptIn.
*
* @return the timestamp held by this instance.
*/
uint64_t getTimestamp();
};
#endif

@ -40,6 +40,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
"drivers/MicroBitSerial.cpp"
"drivers/MicroBitStorage.cpp"
"drivers/MicroBitThermometer.cpp"
"drivers/TimedInterruptIn.cpp"
"bluetooth/MicroBitAccelerometerService.cpp"
"bluetooth/MicroBitBLEManager.cpp"

@ -31,6 +31,8 @@ DEALINGS IN THE SOFTWARE.
#include "MicroBitConfig.h"
#include "MicroBitPin.h"
#include "MicroBitButton.h"
#include "MicroBitSystemTimer.h"
#include "TimedInterruptIn.h"
#include "DynamicPwm.h"
#include "ErrorNo.h"
@ -92,8 +94,11 @@ void MicroBitPin::disconnect()
if (status & IO_STATUS_TOUCH_IN)
delete ((MicroBitButton *)pin);
if ((status & IO_STATUS_EVENT_ON_EDGE) || (status & IO_STATUS_EVENT_PULSE_ON_EDGE))
delete ((TimedInterruptIn *)pin);
this->pin = NULL;
this->status = status & IO_STATUS_EVENTBUS_ENABLED; //retain event bus status
this->status = 0;
}
/**
@ -135,8 +140,9 @@ int MicroBitPin::setDigitalValue(int value)
/**
* Configures this IO pin as a digital input (if necessary) and tests its current value.
*
*
* @return 1 if this input is high, 0 if input is LO, or MICROBIT_NOT_SUPPORTED
* if the given pin does not have analog capability.
* if the given pin does not have digital capability.
*
* @code
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
@ -150,12 +156,16 @@ int MicroBitPin::getDigitalValue()
return MICROBIT_NOT_SUPPORTED;
// Move into a Digital input state if necessary.
if (!(status & IO_STATUS_DIGITAL_IN)){
if (!(status & (IO_STATUS_DIGITAL_IN | IO_STATUS_EVENT_ON_EDGE | IO_STATUS_EVENT_PULSE_ON_EDGE)))
{
disconnect();
pin = new DigitalIn(name,PullDown);
status |= IO_STATUS_DIGITAL_IN;
}
if(status & (IO_STATUS_EVENT_ON_EDGE | IO_STATUS_EVENT_PULSE_ON_EDGE))
return ((TimedInterruptIn *)pin)->read();
return ((DigitalIn *)pin)->read();
}
@ -430,3 +440,148 @@ int MicroBitPin::getAnalogPeriod()
{
return getAnalogPeriodUs()/1000;
}
/**
* This member function manages the calculation of the timestamp of a pulse detected
* on a pin whilst in IO_STATUS_EVENT_PULSE_ON_EDGE or IO_STATUS_EVENT_ON_EDGE modes.
*
* @param eventValue the event value to distribute onto the message bus.
*/
void MicroBitPin::pulseWidthEvent(int eventValue)
{
MicroBitEvent evt(id, eventValue, CREATE_ONLY);
uint64_t now = evt.timestamp;
uint64_t previous = ((TimedInterruptIn *)pin)->getTimestamp();
if (previous != 0)
{
evt.timestamp -= previous;
evt.fire();
}
((TimedInterruptIn *)pin)->setTimestamp(now);
}
/**
* Interrupt handler for when an rise interrupt is triggered.
*/
void MicroBitPin::onRise()
{
if(status & IO_STATUS_EVENT_PULSE_ON_EDGE)
pulseWidthEvent(MICROBIT_PIN_EVT_PULSE_LO);
if(status & IO_STATUS_EVENT_ON_EDGE)
MicroBitEvent(id, MICROBIT_PIN_EVT_RISE);
}
/**
* Interrupt handler for when an fall interrupt is triggered.
*/
void MicroBitPin::onFall()
{
if(status & IO_STATUS_EVENT_PULSE_ON_EDGE)
pulseWidthEvent(MICROBIT_PIN_EVT_PULSE_HI);
if(status & IO_STATUS_EVENT_ON_EDGE)
MicroBitEvent(id, MICROBIT_PIN_EVT_FALL);
}
/**
* This member function will construct an TimedInterruptIn instance, and configure
* interrupts for rise and fall.
*
* @param eventType the specific mode used in interrupt context to determine how an
* edge/rise is processed.
*
* @return MICROBIT_OK on success
*/
int MicroBitPin::enableRiseFallEvents(int eventType)
{
// if we are in neither of the two modes, configure pin as a TimedInterruptIn.
if (!(status & (IO_STATUS_EVENT_ON_EDGE | IO_STATUS_EVENT_PULSE_ON_EDGE)))
{
disconnect();
pin = new TimedInterruptIn(name);
((TimedInterruptIn *)pin)->mode(PullDown);
((TimedInterruptIn *)pin)->rise(this, &MicroBitPin::onRise);
((TimedInterruptIn *)pin)->fall(this, &MicroBitPin::onFall);
}
status &= ~(IO_STATUS_EVENT_ON_EDGE | IO_STATUS_EVENT_PULSE_ON_EDGE);
// set our status bits accordingly.
if(eventType == MICROBIT_PIN_EVENT_ON_EDGE)
status |= IO_STATUS_EVENT_ON_EDGE;
else if(eventType == MICROBIT_PIN_EVENT_ON_PULSE)
status |= IO_STATUS_EVENT_PULSE_ON_EDGE;
return MICROBIT_OK;
}
/**
* If this pin is in a mode where the pin is generating events, it will destruct
* the current instance attached to this MicroBitPin instance.
*
* @return MICROBIT_OK on success.
*/
int MicroBitPin::disableEvents()
{
if (status & (IO_STATUS_EVENT_ON_EDGE | IO_STATUS_EVENT_PULSE_ON_EDGE | IO_STATUS_TOUCH_IN))
disconnect();
return MICROBIT_OK;
}
/**
* Configures the events generated by this MicroBitPin instance.
*
* MICROBIT_PIN_EVENT_ON_EDGE - Configures this pin to a digital input, and generates events whenever a rise/fall is detected on this pin. (MICROBIT_PIN_EVT_RISE, MICROBIT_PIN_EVT_FALL)
* MICROBIT_PIN_EVENT_ON_PULSE - Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either HI or LO. (MICROBIT_PIN_EVT_PULSE_HI, MICROBIT_PIN_EVT_PULSE_LO)
* MICROBIT_PIN_EVENT_ON_TOUCH - Configures this pin as a makey makey style touch sensor, in the form of a MicroBitButton. Normal button events will be generated using the ID of this pin.
* MICROBIT_PIN_EVENT_NONE - Disables events for this pin.
*
* @param eventType One of: MICROBIT_PIN_EVENT_ON_EDGE, MICROBIT_PIN_EVENT_ON_PULSE, MICROBIT_PIN_EVENT_ON_TOUCH, MICROBIT_PIN_EVENT_NONE
*
* @code
* MicroBitMessageBus bus;
*
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
* P0.eventOn(MICROBIT_PIN_EVENT_ON_PULSE);
*
* void onPulse(MicroBitEvent evt)
* {
* int duration = evt.timestamp;
* }
*
* bus.listen(MICROBIT_ID_IO_P0, MICROBIT_PIN_EVT_PULSE_HI, onPulse, MESSAGE_BUS_LISTENER_IMMEDIATE)
* @endcode
*
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the given eventype does not match
*
* @note In the MICROBIT_PIN_EVENT_ON_PULSE mode, the smallest pulse that was reliably detected was 85us, around 5khz. If more precision is required,
* please use the InterruptIn class supplied by ARM mbed.
*/
int MicroBitPin::eventOn(int eventType)
{
switch(eventType)
{
case MICROBIT_PIN_EVENT_ON_EDGE:
case MICROBIT_PIN_EVENT_ON_PULSE:
enableRiseFallEvents(eventType);
break;
case MICROBIT_PIN_EVENT_ON_TOUCH:
isTouched();
break;
case MICROBIT_PIN_EVENT_NONE:
disableEvents();
break;
default:
return MICROBIT_INVALID_PARAMETER;
}
return MICROBIT_OK;
}

@ -0,0 +1,55 @@
/*
The MIT License (MIT)
Copyright (c) 2016 Lancaster University, UK.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "MicroBitConfig.h"
#include "TimedInterruptIn.h"
/**
* Constructor.
*
* Create an instance of TimedInterruptIn that has an additional timestamp field.
*/
TimedInterruptIn::TimedInterruptIn(PinName name) : InterruptIn(name)
{
timestamp = 0;
}
/**
* Stores the given timestamp for this instance of TimedInterruptIn.
*
* @param timestamp the timestamp to retain.
*/
void TimedInterruptIn::setTimestamp(uint64_t timestamp)
{
this->timestamp = timestamp;
}
/**
* Retrieves the retained timestamp for this instance of TimedInterruptIn.
*
* @return the timestamp held by this instance.
*/
uint64_t TimedInterruptIn::getTimestamp()
{
return timestamp;
}
Loading…
Cancel
Save