/*
   OrangutanPulseIn.cpp - Library for reading digital pulses with the
	Orangutan LV, SV, SVP, X2, Baby Orangutan B, or 3pi robot.  Pulses
	are measured in ticks, which have units of 0.4 us.  Note that the
	pulse info is updated by pin change interrupts as the pulses occur,
	so unless you use the get_pulse_info() function to freeze a snapshot
	of the current pulse state, values might change on you in unexpected
	ways.  For example, if you want to do something only when there is
	a new high pulse, you might do the following:
	
	if (new_high_pulse(0) && !new_low_pulse(0))
		do something with pulse data
		
	However, a pulse might occur right after you make it past the if
	statement but before you run your conditional code, changing the
	condition to one that would never have made it past the if statement.
*/

/*
 * Written by Ben Schmidel, August 13, 2009.
 * Copyright (c) 2009 Pololu Corporation. For more information, see
 *
 *   http://www.pololu.com
 *   http://forum.pololu.com
 *   http://www.pololu.com/docs/0J18
 *
 * You may freely modify and share this code, as long as you keep this
 * notice intact (including the two links above).  Licensed under the
 * Creative Commons BY-SA 3.0 license:
 *
 *   http://creativecommons.org/licenses/by-sa/3.0/
 *
 * Disclaimer: To the extent permitted by law, Pololu provides this work
 * without any warranty.  It might be defective, in which case you agree
 * to be responsible for all resulting costs and damages.
 */
 

#ifndef OrangutanPulseIn_h
#define OrangutanPulseIn_h

#include "../OrangutanTime/OrangutanTime.h"

// possible values for the newPulse member of PulseInputStruct
#define LOW_PULSE			1		// the pulse just completed was a low pulse (pin just went high)
#define HIGH_PULSE			2		// the pulse just completed was a high pulse (pin just went low)
#define ANY_PULSE			3		// newPulse member is not zero


// Structure for storing pulse input data.  This structure holds a copy of part of
// the data maintained by the pin-change ISR.  The copy is made when the user calls the
// getPulseInfo() method.
struct PulseInputStruct
{
	unsigned long lastPCTime;
	unsigned char inputState;
	unsigned long lastHighPulse;
	unsigned long lastLowPulse;
	unsigned char newPulse;
};


#ifdef __cplusplus

class OrangutanPulseIn
{
  public:

    // constructor (doesn't do anything)
	OrangutanPulseIn();
	
	// destructor (frees allocated memory)
	~OrangutanPulseIn();
		
	static unsigned char start(const unsigned char *pulsePins, unsigned char numPins);
		
	static void getPulseInfo(unsigned char idx, struct PulseInputStruct* pulseInfo);

	static inline unsigned char newHighPulse(unsigned char idx)
	{
		return newPulse(idx, HIGH_PULSE);
	}

	static inline unsigned char newLowPulse(unsigned char idx)
	{
		return newPulse(idx, LOW_PULSE);
	}

	static inline unsigned char newPulse(unsigned char idx)
	{
		return newPulse(idx, ANY_PULSE);
	}
	
	static unsigned long getLastHighPulse(unsigned char idx);
	
	static unsigned long getLastLowPulse(unsigned char idx);
	
	static void getCurrentState(unsigned char idx, unsigned long* pulseWidth, unsigned char* state);

	static inline unsigned long toMicroseconds(unsigned long pulse)
	{
		return OrangutanTime::ticksToMicroseconds(pulse);
	}
	
	static void stop();
	
	
  private:

	static unsigned char newPulse(unsigned char idx, unsigned char state);
};

#else

// use of pulse_in_init() is discouraged; use pulse_in_start() instead
unsigned char pulse_in_start(const unsigned char *pulsePins, unsigned char numPins);
void get_pulse_info(unsigned char idx, struct PulseInputStruct* pulse_info);
unsigned char new_pulse(unsigned char idx);
unsigned char new_high_pulse(unsigned char idx);
unsigned char new_low_pulse(unsigned char idx);
unsigned long get_last_high_pulse(unsigned char idx);
unsigned long get_last_low_pulse(unsigned char idx);
void get_current_pulse_state(unsigned char idx, unsigned long* pulse_width, unsigned char* state);
unsigned long pulse_to_microseconds(unsigned long pulse);
void pulse_in_stop();

#endif // _cplusplus

#endif // OrangutanPulseIn_h

// Local Variables: **
// mode: C++ **
// c-basic-offset: 4 **
// tab-width: 4 **
// indent-tabs-mode: t **
// end: **
