Hope this makes Eric smile a little. A question on TinyClr NETMF forum prompted this. The question was related to looking at a Cpu.Pin stream for a certain pattern. Right away I thought of Rx. However a 35K+ port of Rx is overkill. But mixing in some of the ideas, I was able to come up with two (very handy I think) extention methods that get the job done in a composable way. You subscribe to an event pin with an observer and do what you need. I thought it was cool.
public delegate bool PinChange(bool state, DateTime time);
public delegate bool PinChangeSpan(bool state, long tickSpan);
public static class Extentions
{
/// <summary>
/// This overload passes tick span between pin changes.
/// </summary>
public static void Subscribe(this InterruptPort port, PinChangeSpan predicate)
{
if (predicate == null) throw new ArgumentNullException("predicate");
long lastTick = -1;
port.Subscribe((bool state, DateTime dt) =>
{
if (lastTick < 0)
{
lastTick = dt.Ticks;
// The first "real" pin change has no delta yet.
return predicate(state, -1);
}
long delta = dt.Ticks - lastTick;
lastTick = dt.Ticks;
return predicate(state, delta);
}, 1); // Always skip first as dirty because no idea when it was set.
}
/// <summary>
/// This overload passes DateTime of current pin state.
/// </summary>
/// <param name="predicate">User predicate.</param>
/// <param name="skipCount">Number of changes to skip.</param>
public static void Subscribe(this InterruptPort port, PinChange predicate, uint skipCount=0)
{
if (predicate == null) throw new ArgumentNullException("predicate");
NativeEventHandler del = null;
del = (uint data1, uint data2, DateTime time) =>
{
if (skipCount > 0)
{
skipCount--;
return;
}
if (del == null)
return; // Already unregisted. Not sure why this needed to avoid extra callback. MF Bug?
bool state = data2 == 0 ? false : true;
// If user predicate not want more, then unregister.
if (! predicate(state, time))
{
port.OnInterrupt -= del;
del = null;
}
};
// Register observer.
port.OnInterrupt += del;
}
}
Usage samples:
InterruptPort inPort = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di13, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
int highCount = 0; // local state var.
inPort.Subscribe((isHigh, dt) =>
{
if (isHigh && ++highCount >= 5)
{
Debug.Print("Pin high 5 times. Do something.");
return false; // unsubscribe.
}
return true; // keep subscription active.
});
// PulseIn sample:
// Milliseconds span between first low and high.
inPort.Subscribe((bool isHigh, long ticks) =>
{
if (ticks == -1)
return true; // Skip first, because we have no delta time context yet.
if (isHigh)
{
Debug.Print("\nDelay between first low and first high: " + ticks / 10000);
return false; // done.
}
else
return true;
});
Thread Closed
This thread is kinda stale and has been closed but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.