Passing a pointer to a function from another class, from a function in that clas

Hi,

I'm trying to use the TimerOne library with another class I'm writing. One of my functions needs to call a function from the TimerOne class. The function I'm trying to call is defined as:

    void attachInterrupt(void (*isr)(), long microseconds=-1);

Now, I need to call this method from my class, which I can do quite easily. However, how do I pass another function from my class to the argument for the attachInterrupt function?

In my specific example, I'm basically trying to do this

	Timer1.attachInterrupt( className::classFunction );

The function I need to call is defined as:

 void classFunction(void);

Thanks in advance.

Apologies in advance for my limited understanding of the static keyword. Is there any real disadvantages to declaring my ISR as static? I do not need to instantiate more than one instance of the class.

EDIT: I declared the function as static, but now, as expected, I can't access other functions or variables of the class. Is there any work around for this? Or shall I just make all the variables it needs to access, static?

Great.

Is the reason for the function needing to be static, so that the pointer has a fixed memory location to jump to, as it would if the function were not defined within a class?

Thanks very much for your help.

EDIT: In trying to make the entire class static, I run into the following error:

 ir_driver.cpp:In file included from
ir_driver.h:44: error: a storage class can only be specified for objects and functions
ir_driver.cpp:In member function 'void Ir_driverClass::sendData(uint8_t*, uint8_t)'
ir_driver.cpp:42: error: no matching function for call to 'TimerOne::attachInterrupt(<unresolved overloaded function type>)'
TimerOne.h:attachInterrupt(void (*)(), long int)

Does this mean I cannot have a static class with variables in?

This thread oop - How do you create a static class in C++? - Stack Overflow seems to suggest C++ doesn't cater for static classes?

Difficult to say without seeing your amended code and not just snippets.

This is my current version:

.H

// ir_driver.h

#ifndef _IR_DRIVER_h
#define _IR_DRIVER_h

#if defined(ARDUINO) && ARDUINO >= 100
	#include "Arduino.h"
#else
	#include "WProgram.h"
#endif

#include <TimerOne.h>

class Ir_driverClass
{
private:
	//Variables to hold pin numbers.
	static uint8_t _SDI_PIN, _CLK_PIN, _LE_PIN, _OE_PIN, _SDO_PIN;

	static uint8_t sdipinio;

	//Variables to store frequency and data rates.
	//NOTE: Not yet supported!!!!
	//unsigned long _DESIRED_FREQUENCY, _DESIRED_DATARATE;

	//Variables to hold state of transmission.
	static uint8_t* DATA_BUF_ptr;
	static uint8_t DATA_BUF_LENGTH;

	static uint8_t OEstate, LEstate, SDIstate, CLKstate;

	static unsigned int cycleno;
	static uint8_t SDIcount, SDIbitno, SDIbyteno;

	//ISR that sends the message.
	//NOTE: Must be static in order to call as parameter for Timer1.Initialize()
	static void sendISR(void);

public:
	//Constructor
	Ir_driverClass(uint8_t SDI_PIN, uint8_t CLK_PIN, uint8_t LE_PIN, uint8_t OE_PIN, uint8_t SDO_PIN);

	//Initialises the class
	void init();
	//This method is non-blocking.
	void sendData(uint8_t* dataToSend, uint8_t length);
};

#endif

.CPP

#include "ir_driver.h"
#include <TimerOne.h>

Ir_driverClass::Ir_driverClass(uint8_t SDI_PIN, uint8_t CLK_PIN, uint8_t LE_PIN, uint8_t OE_PIN, uint8_t SDO_PIN)
{
	_SDI_PIN = SDI_PIN;
	_CLK_PIN = CLK_PIN;
	_LE_PIN = LE_PIN;
	_OE_PIN = OE_PIN;
	_SDO_PIN = SDO_PIN;
}

void Ir_driverClass::init()
{
	pinMode(_SDI_PIN, OUTPUT);
	pinMode(_CLK_PIN, OUTPUT);
	pinMode(_LE_PIN, OUTPUT);
	pinMode(_OE_PIN, OUTPUT);
	pinMode(_SDO_PIN, OUTPUT);

	//TODO: Calculate interrupt timing and initialize timer accordingly.
	Timer1.initialize(17);
}

void Ir_driverClass::sendData(uint8_t* dataToSend, uint8_t length)
{
	//Prepare buffers.
	DATA_BUF_ptr = dataToSend;
	DATA_BUF_LENGTH = length;


	//Reset counters before starting transmission.
	SDIbitno = 0;
	SDIcount = 0;
	SDIbyteno = 0;
	cycleno = 0;

	Timer1.attachInterrupt( sendISR );
}

void Ir_driverClass::sendISR(void)
{
	//			24 cycles per bit * 10 bits per byte * number of bytes + 24 to allow for delay before data is latched to output.
	if(cycleno >= ((240 * DATA_BUF_LENGTH) + 24))
	{
		Timer1.detachInterrupt();
		bitClear(PORTD, _SDI_PIN);
		bitClear(PORTD, _CLK_PIN);
		bitClear(PORTD, _LE_PIN);
		bitSet(PORTD, _OE_PIN);

		return;
	}

	//CLK
	if(cycleno % 2)			//If odd cycle.
		CLKstate = 1;
	else
		CLKstate = 0;

	//LE
	//NOTE: Could not work out why LEcount was implemented as seperate variables from SDIcount so deprecated it.
	/*if(LEcount >= 21 && LEcount < 23)	
		LEstate = 1;
	else
		LEstate = 0;*/

	if(SDIcount >= 21 && SDIcount < 23) //Latch our data to the output buffers after all the data has been shifted in.
		LEstate = 1;
	else
		LEstate = 0;



	//SDI
	switch(SDIbitno)
	{
	case 0:					//If start bit.
		SDIstate = 0;
		break;
	case 9:					//If stop bit.
		SDIstate = 1;
		break;
	default:				//Else, fetch the correct bit value.
		SDIstate = bitRead(DATA_BUF_ptr[SDIbyteno], SDIbitno - 1);
		break;
	}

	if(SDIcount == 23)		//We've counted our 12 cycles for this bit. 
							//NOTE: 12 is hardcoded due to relationship between encoding frequency (28.8khz) and baud rate (2400bps). 28800 / 2400 = 12.
	{
		SDIcount = 0;		//Reset our SDI cycle counter.
		SDIbitno++;			//Incremenet our bit counter.

		if(SDIbitno == 10)	//We've finished this byte
		{
			SDIbitno = 0;	//Reset our bit counter.
							//Increment our byte counter.
			if(SDIbyteno < DATA_BUF_LENGTH)	//NOTE: This is to ensure we don't overflow when message is finished.
				SDIbyteno++;
		}
	}
	else
		SDIcount++;			//Otherwise, go ahead and increment our SDI cycle counter.

	//OE
	if((cycleno > 24) && (cycleno % 2))	//Oscillate our output enable pin each time the ISR is run, but only once the first bit of data has been shifted to the output.
		OEstate = 0;
	else
		OEstate = 1;

	//NOTE: This section prevents LE SDI or CLK being modified once last bit of data has been latched.
	if(cycleno > (240 * DATA_BUF_LENGTH))
	{
		LEstate = 0;
		SDIstate = 0;
		CLKstate = 0;
	}

	//NOTE: This is not a nice way of doing it as it means we can't use other PORTD pins!
	//TODO: fix this!
	PORTD = (OEstate << _OE_PIN) + (LEstate << _LE_PIN) + (SDIstate << _SDI_PIN) + (CLKstate << _CLK_PIN);
	
	//NOTE: Removed from original source. See LE section for reimplementation.
	/*if(LEcount >= 23)
		LEcount = 0;
	else
		LEcount++;*/
	cycleno++;
}

If I remove the static keywords from the individual variables and functions, and attempt to make the class static

 static class Ir_driverClass

I run into:

 ir_driver.cpp:In file included from
ir_driver.h:47: error: a storage class can only be specified for objects and functions
ir_driver.cpp:In member function 'void Ir_driverClass::sendData(uint8_t*, uint8_t)'
ir_driver.cpp:42: error: no matching function for call to 'TimerOne::attachInterrupt(<unresolved overloaded function type>)'
TimerOne.h:attachInterrupt(void (*)(), long int)
Error compiling

Having each variable and function static is fine for my purposes, but using the code I listed above, I run into the following error when trying to call the constructor:

 ir_driver.cpp.o:In function `Ir_driverClass'
ir_driver.cpp:_SDI_PIN'
ir_driver.cpp:_CLK_PIN'
ir_driver.cpp:_LE_PIN'
ir_driver.cpp:_OE_PIN'
ir_driver.cpp:_SDO_PIN'
Error creating .elf

Where the code that calls the class is:

 #include "ir_driver.h"
#include <TimerOne.h>

#define SDI 2
#define CLK 3
#define LE	4
#define OE	5
#define SDO 7

uint8_t data[] = {'H', 'E', 'L', 'L', 'O'};

//Note: Guaranteed to work for these pin numbers. Won't work on anything outside of PORTD.
//Note: Class consumes entirety of PORTD, whether defined here or not!
//TODO: Fix that.
Ir_driverClass ir(SDI, CLK, LE, OE, SDO);

void setup()
{
	//ir.init();
}

void loop()
{
	//ir.sendData(data, sizeof(data));
	delay(1000);
}

I've worked out the latter problem (whereby I couldn't call my initialisation function). Wasn't easy to track down as the error messages weren't exactly helpful.

Turns out you need to re-initialise these variables exactly once in actual executable code (.cpp).

EDIT:
Well, this did away with the errors for the constructor, but calling other functions, these variables still throw the same problem.

EDIT2:
Re-reading the stackoverflow link above, I tried this:

#include "ir_driver.h"
#include <TimerOne.h>


uint8_t Ir_driverClass::_SDI_PIN;
uint8_t Ir_driverClass::_CLK_PIN;
uint8_t Ir_driverClass::_LE_PIN;
uint8_t Ir_driverClass::_OE_PIN;
uint8_t Ir_driverClass::_SDO_PIN;

Ir_driverClass::Ir_driverClass(uint8_t SDI_PIN, uint8_t CLK_PIN, uint8_t LE_PIN, uint8_t OE_PIN, uint8_t SDO_PIN)
{
	_SDI_PIN = SDI_PIN;
	_CLK_PIN = CLK_PIN;
	_LE_PIN = LE_PIN;
	_OE_PIN = OE_PIN;
	_SDO_PIN = SDO_PIN;

	/*uint8_t OEstate = 0, LEstate = 0, SDIstate = 0, CLKstate = 0;
	uint8_t SDIcount = 0, SDIbitno = 0, SDIbyteno = 0;
	unsigned int cycleno = 0;

	uint8_t* DATA_BUF_ptr = 0;
	uint8_t DATA_BUF_LENGTH = 0;*/
}

//Other function definitions here.

and this seems to work. =)