Use the hardware PwmOut to pulsate an LED (or something else), with selectable active high/low, customisable intensity function, gamma correction, and number of brightness levels.

Dependents:   RedButton

Revision:
6:5eeb1acc1c50
Parent:
5:26cc18306d95
Child:
7:7abc04b4c474
--- a/Pulsator.cpp	Fri Apr 24 21:26:05 2015 +0000
+++ b/Pulsator.cpp	Sun Apr 26 01:39:38 2015 +0000
@@ -35,64 +35,62 @@
 #include <mbed.h>
 #include <Pulsator.h>
 
-Pulsator led(LED1, 2.0, false);
+Pulsator led(LED1);
 
 int main(void) {
-    led = true;
+    led.period(2.0).gamma(1.8) = true;
     while(1) wait(1);
 }
  * \endcode
  * \see \a PwmOut, \a Ticker
  */
 
-void Pulsator::step(void)
+void Pulsator::disable(void)
 {
-    // sinf(phase_2)^2 == (1 - cosf(phase)) / 2
-    float s = sinf(phase_2);
-    float level = powf(s * s, gamma);
-    out = active_high ? level : 1.0 - level;
-    phase_2 += M_PI_2 / (float)(levels - 1);
-    if(phase_2 >= M_PI)
-        phase_2 -= M_PI;
+    _enable = false;
+    detach();
+    out = _active_high ? 0.0 : 1.0;
 }
 
 void Pulsator::enable(void)
 {
-    _enable = true;
     out.period(1.0 / 1024.0);
     phase_2 = 0.0;
     step();
-    ticker.attach(this, &Pulsator::step, 0.5 * period / (float)(levels - 1));
+    _enable = true;
+    attach(this, &Pulsator::step, 0.5 * _period / (float)(_levels - 1));
 }
 
-void Pulsator::disable(void)
+//! Bit of a hack to update _delay without re-attaching the handler.
+void Pulsator::reload(void)
 {
-    _enable = false;
-    ticker.detach();
-    out = active_high ? 0.0 : 1.0;
+    _delay = 1000000.0 * 0.5 * _period / (float)(_levels - 1);
 }
 
-/*! Create a \a Pulsator object.
- * \param pin Pin to pulsate. Note that some platforms can only
- *      drive certain pins with the hardware PWM.
- * \param period Duration of each cycle, in seconds.
- * \param active_high Should the output pin be active high (\a true),
- *      or active low (\a false)?
- * \param gamma Gamma correction for the output LED.
- * \param levels Number of distinct brightness levels: a minimum of 2.
- */
-Pulsator::Pulsator(PinName pin, float period, bool active_high, float gamma, int levels)
-    : out(pin), period(period), active_high(active_high), gamma(gamma), levels(levels)
+void Pulsator::step(void)
 {
-    disable();
+    // sinf(phase_2)^2 == (1 - cosf(phase)) / 2
+    float s = sinf(phase_2);
+    float level = powf(s * s, _gamma);
+    out = _active_high ? level : 1.0 - level;
+    phase_2 += M_PI_2 / (float)(_levels - 1);
+    if(phase_2 >= M_PI)
+        phase_2 -= M_PI;
 }
 
-/*! Enable or disable the output.
- * \param state Pulsate the output?
- * \note Passing \a false deactivates the output completely, rather than
- *      keeping the LED brightness at the point where this is called.
- *      Conversely, \a true starts pulsating from the inactive state.
- */
+//! Create a \a Pulsator attached to the specified \a pin.
+//! \param pin Pin to pulsate.
+//! \note Some platforms can only drive certain pins with the hardware PWM.
+Pulsator::Pulsator(PinName pin) : out(pin)
+{
+    active_high(); disable(); gamma(); period(); levels();
+}
+
+//! Enable or disable the output.
+/* \note Passing \a false deactivates the output completely, rather than
+    maintaining the LED brightness at the point when this is called.
+    Conversely, \a true starts pulsating from the inactive state.
+    Setting the curent state is a no-op. */
 Pulsator& Pulsator::operator=(bool state)
 {
     if(state != _enable)
@@ -100,7 +98,40 @@
     return *this;
 }
 
+//! Get the current state of the output.
 Pulsator::operator bool(void)
 {
     return _enable;
 }
+
+//! Should the output pin be active high (\a true), or active low (\a false)?
+Pulsator& Pulsator::active_high(bool high)
+{
+    _active_high = high;
+    if(!_enable)
+        out = _active_high ? 0.0 : 1.0;
+    return *this;
+}
+
+//! Set the gamma correction for the output LED.
+Pulsator& Pulsator::gamma(float power)
+{
+    _gamma = power;
+    return *this;
+}
+
+//! Set the number (>= 2) of distinct brightness levels.
+Pulsator& Pulsator::levels(int number)
+{
+    _levels = number;
+    reload();
+    return *this;
+}
+
+//! Set the duration of each cycle, in seconds.
+Pulsator& Pulsator::period(float seconds)
+{
+    _period = seconds;
+    reload();
+    return *this;
+}