Skip to content

Commit

Permalink
Encapsulate IntervalTimerEx to enable up to 4 Simulator objects
Browse files Browse the repository at this point in the history
  • Loading branch information
lunOptics committed Oct 4, 2020
1 parent b6263ab commit b68c078
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 11 deletions.
33 changes: 33 additions & 0 deletions examples/TwoSimulators/TwoSimulators.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "EncSim.h"

EncSim e1(0, 1, 2); // A=0, B=1, Z=2
EncSim e2(3, 4, 5); // A=2, B=3; Z=5

void setup()
{
pinMode(LED_BUILTIN, OUTPUT);

e1
.begin()
.setFrequency(1000) // 1000 pps
.setPeriod(500) // Index every 500 pulses
.setPhase(90) // 90° phase signal
.setTotalBounceDuration(0); // no bouncing

e2
.begin()
.setFrequency(7000) // 1000 pps
.setPeriod(1500) // Index every 500 pulses
.setPhase(90) // 90° phase signal
.setTotalBounceDuration(0); // no bouncing


e1.moveRelAsync(INT32_MAX); // run for some time INT32_MAX = 2147483647
e2.moveRelAsync(INT32_MAX); // run for some time INT32_MAX = 2147483647
}

void loop()
{
Serial.printf("e1: %d, e2: %d\n", e1.current, e2.current);
delay(100);
}
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=EncSim
version=2.2.0.0
version=2.3.0
author=Lutz Niggl
maintainer=Lutz Niggl
sentence=Quadrature Signal Generator
Expand Down
6 changes: 1 addition & 5 deletions src/EncSim.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
#include "EncSim.h"

static EncSim* This; // hack, allows one instance only

EncSim::EncSim(unsigned pinA, unsigned pinB, unsigned pinZ)
{
This = this;
this->A = pinA;
this->B = pinB;
this->Z = pinZ;
}

EncSim& EncSim::begin(/*unsigned pinA, unsigned pinB, int pinZ*/)
{
//CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; // set PIT clock to 150MHz

phaseA.begin(A);
phaseB.begin(B);
if (Z < UINT32_MAX)
Expand Down Expand Up @@ -43,7 +39,7 @@ void EncSim::moveAbsAsync(int _target)
direction = (target >= current) ? 1 : -1;

if (!running)
mainTimer.begin([] { This->pitISR(); }, T[current & 1]);
mainTimer.begin([this] {pitISR(); }, T[current & 1]);
running = true;
}

Expand Down
9 changes: 4 additions & 5 deletions src/EncSim.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "BouncingPin.h"
#include "IntervalTimerEx.h"
#include "TeensyTimerTool.h"
#include <algorithm>

Expand Down Expand Up @@ -33,9 +34,7 @@ class EncSim
EncSim& setBounceDurationMin(unsigned microseconds);
EncSim& setBounceDurationMax(unsigned microseconds);


protected:

protected:
void pitISR()
{
current += direction;
Expand All @@ -47,7 +46,7 @@ class EncSim

if (Z < UINT32_MAX)
{
digitalWriteFast(Z, ((current - 2) % period) == 0); // current-2 to have the zero pulse on the rising edge of B
digitalWriteFast(Z, ((current - 2) % period) == 0); // current-2 to have the zero pulse on the rising edge of B
}

if (current & 1)
Expand All @@ -71,5 +70,5 @@ class EncSim
unsigned period;

BouncingPin phaseA, phaseB;
IntervalTimer mainTimer;
IntervalTimerEx mainTimer;
};
51 changes: 51 additions & 0 deletions src/IntervalTimerEx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "IntervalTimerEx.h"


IntervalTimerEx::~IntervalTimerEx()
{
end();
}

void IntervalTimerEx::end()
{
callbacks[index] = nullptr;
IntervalTimer::end();
}


// generate and preset the callback storage
callback_t IntervalTimerEx::callbacks[4]{
nullptr,
nullptr,
nullptr,
nullptr,
};

#if defined (USE_CPP11_CALLBACKS)

relay_t IntervalTimerEx::relays[4]{
[] { callbacks[0](); },
[] { callbacks[1](); },
[] { callbacks[2](); },
[] { callbacks[3](); },
};

#else

// generate the static array of relay functions
relay_t IntervalTimerEx::relays[4]{
[] { callbacks[0](states[0]); },
[] { callbacks[1](states[1]); },
[] { callbacks[2](states[2]); },
[] { callbacks[3](states[3]); },
};

// storage for the state values
void* IntervalTimerEx::states[4]{
nullptr,
nullptr,
nullptr,
nullptr,
};

#endif
84 changes: 84 additions & 0 deletions src/IntervalTimerEx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#pragma once

#include "Arduino.h"

#define USE_CPP11_CALLBACKS // comment out if you want to use the traditional void pointer pattern to pass state to callbacks

#if defined(USE_CPP11_CALLBACKS)
#include <functional>
using callback_t = std::function<void()>;
using relay_t = void (*)();

#else
using callback_t = void (*)(void*);
using relay_t = void (*)();
#endif


class IntervalTimerEx : public IntervalTimer
{
public:
template <typename period_t> // begin is implemented as template to avoid replication the various versions of IntervalTimer::begin
#if defined(USE_CPP11_CALLBACKS)
bool begin(callback_t callback, period_t period);
#else
bool begin(callback_t callback, void* state, period_t period);
#endif

void end();
~IntervalTimerEx();

protected:
unsigned index = 0;
static callback_t callbacks[4]; // storage for callbacks
static relay_t relays[4]; // storage for relay functions
#if !defined(USE_CPP11_CALLBACKS)
static void* states[4]; // storage for state variables
#endif

};

// Inline implementation ===============================================


#if defined(USE_CPP11_CALLBACKS)
template <typename period_t>
bool IntervalTimerEx::begin(std::function<void()> callback, period_t period)
{
for (index = 0; index < 4; index++) // find the next free slot
{
if (callbacks[index] == nullptr) // ->free slot
{
if (IntervalTimer::begin(relays[index], period)) // we got a slot but we need to also get an actual timer
{
callbacks[index] = callback; // if ok -> store callback
return true;
}
return false;
}
}
return false; // can never happen if bookkeeping is ok
}

#else // traditional void pointer pattern to pass state to callbacks

template <typename period_t>
bool IntervalTimerEx::begin(callback_t callback, void* state, period_t period)
{
for (index = 0; index < 4; index++) // find the next free slot
{
if (callbacks[index] == nullptr) // ->free slot
{
if (IntervalTimer::begin(relays[index], period)) // we got a slot but we need to also get an actual timer
{
callbacks[index] = callback; // if ok -> store callback...
states[index] = state; // ...and state
return true;
}
return false;
}
}
return false; // can never happen if bookkeeping is ok
}

#endif

0 comments on commit b68c078

Please sign in to comment.