Go Down

Topic: header file: order of definitions - using typdefs / structs in each others (Read 697 times) previous topic - next topic

s-light


Hello Community,

i am Experimenting with Structures and Callback functions. (build a 'Input Event System')
Now iam at the point where i try to make the calling 'object' (a typdefed struct) available in the called function
in my headerfile i have the following definitions:
Code: [Select]
// Encoder 'Object'
struct sEncoder
{
const byte bNr;

byte pin_A;
byte pin_B;

boolean bA;
boolean bB;
boolean bA_last;
boolean bB_last;

boolean bLastFullStep;

byte bState;

unsigned long ulTimeStamp;

//tCBF_OnStep cbfOnStep;
};
typedef struct sEncoder tEncoder;

// typdef for input state change callback
//typedef void (* tCBF_OnStep) (tEncoder *encObj);


in my ino file iam using it this way:
Code: [Select]
...
/**************************************************************************************************/
/** Include yourselfs header file  (used to define structs and co)                               **/
/**************************************************************************************************/
#include "SwitchPCB_Test_RotaryEncoder_v02.h"
// use "" for files in same directory as .ino

/**************************************************************************************************/
/** definitions                                                                                  **/
/**************************************************************************************************/

tEncoder enc_left = {

111, //const byte bNr;

22, // byte pin_A;
26, // byte pin_B;

0, // boolean bA;
0, // boolean bB;
0, // boolean bA_last;
0, // boolean bB_last;
0, // boolean bLastFullStep;

state_UNDEFINED, // byte bState;

0, // unsigned long ulTimeStamp;

};

tEncoder enc_right = {
....
};

/**************************************************************************************************/
/** functions                                                                                    **/
/**************************************************************************************************/

void callback_Encoder_OnStep (tEncoder *encObj) {
/** Debug Out **/
Serial.print((*encObj).bNr);
Serial.print(":");
Serial.println((*encObj).bState);
/** **/
}

void readEncoder(tEncoder *encObj) {
boolean bTemp_A = digitalRead((*encObj).pin_A);
boolean bTemp_B = digitalRead((*encObj).pin_B);
.....
/**  RUN CALLBACK Function: **/
(*encObj).cbfOnStateChange(encObj);
.....
}

/****************************************************************************************************/
/** Main Loop                                                                                      **/
/****************************************************************************************************/
void loop()
{
readEncoder(&enc_left);
readEncoder(&enc_right);
}


so with this setup the compiler stops and says:
Code: [Select]
In file included from SwitchPCB_Test_RotaryEncoder_v02.ino:42:
SwitchPCB_Test_RotaryEncoder_v02.h:42: error: 'tCBF_OnStep' does not name a type

- ok thats clear - on this point he does not know the definition that comes later  -
but i also cant reorder this - because in the function i use the type tEncoder - and if i write this for the tEncoder definition he also cant find it..

i hope it is clear what iam trying to do -
is there a solution or iam just on the absolute wrong way with this concept?!
i just know a little about this 'callback function' and pointer and reference and co system.
if you know a good tutorial or example how to do such things i am ready to learn new things..
(iam coming from the computer and javascript world - and sometimes its hard to think in limited memory and co..)

sunny greetings stefan

PaulS

Quote
i am Experimenting with Structures and Callback functions.

And ranDom caPitalIzaTion, too, I see.

Code: [Select]
SwitchPCB_Test_RotaryEncoder_v02.h:42: error: 'tCBF_OnStep' does not name a type
Well, where IS tCBF_OnStep typed?

Quote
is there a solution

Of course. It does not involve posting snippets, though. Post your real code. All of it.

s-light

sorry - i commented the definition out..
here comes the full code:
SwitchPCB_Test_RotaryEncoder_v02.h
Code: [Select]
/**
** see SwitchPCB_Test_RotaryEncoder_v02.ino                                                     **
**/

/**
  * Includes Core Arduino functionality
  **/
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif

/** type and struct       definition                                                             **/

const byte state_UNDEFINED = 0;
const byte state_CW = 1;
const byte state_CCW = 2;
const byte state_HalfStep = 3;



// Input Event
struct sEncoder
{
const byte bNr;

byte pin_A;
byte pin_B;

boolean bA;
boolean bB;
boolean bA_last;
boolean bB_last;

boolean bLastFullStep;

byte bState;

unsigned long ulTimeStamp;

tCBF_OnStep cbfOnStep;
};
typedef struct sEncoder tEncoder;

// typdef for step callback
typedef void (* tCBF_OnStep) (tEncoder *encObj);

/** END                                        **/


SwitchPCB_Test_RotaryEncoder_v02.ino
Code: [Select]
/**************************************************************************************************
** RotaryEncoder Tester                                                                         **
**  Tests the Rotary Encoders of the SwitchPCBs at 2ChControll Project                          **
** based on infos and ideas from:                                                               **
**  ~ http://www.mikrocontroller.net/articles/Drehgeber                                         **
**  ~ http://www.mikrocontroller.net/topic/drehgeber-auslesen                                   **
**  ~ http://www.mikrocontroller.net/topic/38863                                                **
**  ~ http://hacks.ayars.org/2009/12/using-quadrature-encoder-rotary-switch.html                **
**  ~ http://playground.arduino.cc/Main/RotaryEncoders#Waveform                                 **
**  written by stefan krueger (s-light), stefan@s-light.eu, http://s-light.eu                   **
**  changelog / history                                                                         **
**   17.02.2013 22:25 created                                                                   **
**   23.04.2013 15:06 uncomment code for posting and testing in forum.                          **
**                                                                                              **
**                                                                                              **
**  TO DO:                                                                                      **
**   ~ ask for help with the call back function                                                 **
**   ~ get this into a library or                                                               **
**   ~ a 'addon' file to add to projects (to much customization needed to fit every encoder?!   **
**                                                                                              **
**************************************************************************************************/

/** Include yourselfs header file  (used to define structs and co)                               **/
#include "SwitchPCB_Test_RotaryEncoder_v02.h"
// use "" for files in same directory as .ino


/** definitions                                                                                  **/

tEncoder enc_left = {

111, //const byte bNr;

22, // byte pin_A;
26, // byte pin_B;

0, // boolean bA;
0, // boolean bB;
0, // boolean bA_last;
0, // boolean bB_last;
0, // boolean bLastFullStep;

state_UNDEFINED, // byte bState;

0, // unsigned long ulTimeStamp;

callback_Encoder_OnStep, // tCBF_OnStep cbfOnStep;

};

tEncoder enc_right = {

222, //const byte bNr;

24, // byte pin_A;
28, // byte pin_B;

0, // boolean bA;
0, // boolean bB;
0, // boolean bA_last;
0, // boolean bB_last;
0, // boolean bLastFullStep;

state_UNDEFINED, // byte bState;

0, // unsigned long ulTimeStamp;

callback_Encoder_OnStep, // tCBF_OnStep cbfOnStep;
};



/** functions                                                                                    **/

void callback_Encoder_OnStep (tEncoder *encObj) {
/** Debug Out **/
Serial.print((*encObj).bNr);
Serial.print(":");
Serial.println((*encObj).bState);
/** **/
}

/************************************************/
/** read Encoder and rect                      **/
/************************************************/
void readEncoder(tEncoder *encObj) {

/**
rast punkt immer bei 0,0 oder 1,1
CCW
---- A, B
111: 0, 1
111: 0, 0 !
111: 1, 0
111: 1, 1 !
---- A, B
111: 0, 1
111: 0, 0 !
111: 1, 0
111: 1, 1 !

CW
---- A, B
111: 1, 0
111: 0, 0 !
111: 0, 1
111: 1, 1 !
---- A, B
111: 1, 0
111: 0, 0 !
111: 0, 1
111: 1, 1 !

Error
---- A, B
111: 1, 0
111: 0, 0
111:1
111+1
111: 0, 1
111: 1, 1
111:1
111+1
111: 1, 0
111: 1, 1
111:2 <--Wrong reading!!!
111-1
111: 1, 0
111: 0, 0
111:1
111+1

this reading is wrong.
it is not alowed to have 1,1; 1,0; 1,1

**/

boolean bTemp_A = digitalRead((*encObj).pin_A);
boolean bTemp_B = digitalRead((*encObj).pin_B);
if ( (bTemp_A != (*encObj).bA) || (bTemp_B != (*encObj).bB)) {
//status changed.
(*encObj).bA = bTemp_A;
(*encObj).bB = bTemp_B;

Serial.print((*encObj).bNr);
Serial.print(": ");
Serial.print((*encObj).bA);
Serial.print(", ");
Serial.println((*encObj).bB);

// half step; save state of encoder pins for direction check
if ((*encObj).bA != (*encObj).bB) {
(*encObj).bA_last = (*encObj).bA;
(*encObj).bB_last = (*encObj).bB;
(*encObj).bState = state_HalfStep;
} else {
// full step; one step is finished. --> This is Only true if the last full step was not the same level (high or low)
if ( ((*encObj).bA == (*encObj).bB) && ((*encObj).bA != (*encObj).bLastFullStep) ) {
//remember LastFullStep (error correction)
(*encObj).bLastFullStep = (*encObj).bA;
// Encoder turns CW
if ((*encObj).bA == (*encObj).bB_last)  {
//Do Something
(*encObj).bState = state_CW;
/**  RUN CALLBACK Function: **/
(*encObj).cbfOnStep(encObj);

// direct call for testing..
  //callback_Encoder_OnStep(encObj);
/** **/
Serial.print((*encObj).bNr);
Serial.println(": +1");
/** **/


} else {
// Encoder turns CCW
if ((*encObj).bB == (*encObj).bA_last)  {
//Do Something
(*encObj).bState = state_CCW;
/**  RUN CALLBACK Function: **/
(*encObj).cbfOnStep(encObj);

// direct call for testing..
  //callback_Encoder_OnStep(encObj);
/** **/
Serial.print((*encObj).bNr);
Serial.println(": -1");
/** **/


}
}
}
}
}



}

void setup() {
pinMode(enc_left.pin_A, INPUT_PULLUP);
pinMode(enc_left.pin_B, INPUT_PULLUP);
pinMode(enc_right.pin_A, INPUT_PULLUP);
pinMode(enc_right.pin_B, INPUT_PULLUP);

} // setup


/** Main Loop                                                                                      **/
void loop() {
readEncoder(&enc_left);
readEncoder(&enc_right);
}


and the errors when i try to compile:
Code: [Select]
In file included from SwitchPCB_Test_RotaryEncoder_v02.ino:51:
SwitchPCB_Test_RotaryEncoder_v02.h:46: error: 'tCBF_OnStep' does not name a type
SwitchPCB_Test_RotaryEncoder_v02:89: error: too many initializers for 'tEncoder'
SwitchPCB_Test_RotaryEncoder_v02:109: error: too many initializers for 'tEncoder'
SwitchPCB_Test_RotaryEncoder_v02.ino: In function 'void readEncoder(tEncoder*)':
SwitchPCB_Test_RotaryEncoder_v02:208: error: 'struct sEncoder' has no member named 'cbfOnStep'
SwitchPCB_Test_RotaryEncoder_v02:224: error: 'struct sEncoder' has no member named 'cbfOnStep'


if i put the typedef of the function for the sEncoder struct i have some other / similar errors
Code: [Select]
In file included from SwitchPCB_Test_RotaryEncoder_v02.ino:51:
SwitchPCB_Test_RotaryEncoder_v02.h:27: error: typedef 'tCBF_OnStep' is initialized (use __typeof__ instead)
SwitchPCB_Test_RotaryEncoder_v02.h:27: error: 'tEncoder' was not declared in this scope
SwitchPCB_Test_RotaryEncoder_v02.h:27: error: 'encObj' was not declared in this scope
SwitchPCB_Test_RotaryEncoder_v02.h:48: error: 'tCBF_OnStep' does not name a type
SwitchPCB_Test_RotaryEncoder_v02:89: error: too many initializers for 'tEncoder'
SwitchPCB_Test_RotaryEncoder_v02:109: error: too many initializers for 'tEncoder'
SwitchPCB_Test_RotaryEncoder_v02.ino: In function 'void readEncoder(tEncoder*)':
SwitchPCB_Test_RotaryEncoder_v02:208: error: 'struct sEncoder' has no member named 'cbfOnStep'
SwitchPCB_Test_RotaryEncoder_v02:224: error: 'struct sEncoder' has no member named 'cbfOnStep'


i think i missing some basic understanding of this..

thanks for your help

sunny greetings stefan

PS: how do you prefer such code? in-line or as attached file? i had to remove some formating comments to get under 9500 characters..

pYro_65

The first lot of information you provided was sufficient, I'll explain why:

'tCBF_OnStep' is not found due to it being declared after the class ( which you already assumed ), and as the compiler reads the code linearly, it does not see the function type definition until after the malformed class.

C++ has a feature called "forward declarations" which allows the compiler to use a type it has not seen (not previously declared ) in other declarations. This differs from using ( defining ) the type before it is declared.

To fix your scenario:

  • Remove this line: typedef struct sEncoder tEncoder;
       It is not needed in C++, structs are types by definition. Typedefs are only useful when you change the type, as in:
    Code: [Select]
    typedef sEncoder* tEncoder;

    This provides a pointer type, rather than the original type.

  • Add 'class sEncoder;' above the structure, this is the forward declaration.

  • Underneath the forward declaration but above the struct, add: typedef void (* tCBF_OnStep) (sEncoder*encObj);  

    Once complete, bob should be your uncle.


s-light

Thanks pYro_65,

it is working great :-)
[solved]

my next step is to convert this into a library - maybe this is a bit overkill for this easy thing - but hey - its easy to use and makes a project more structured. (so my opinion)

so in this case - if i have the same schema for the callback function the class would need to give a referenc to herself.
how is this possible ? or is there a other method or construct to make something similar?

i have the library attached as zip but for a fast look i include the header and cpp here:
(in the zip is also an example - my test sketch for developing the lib)

slight_RotaryEncoder.h
Code: [Select]

/**
  * slight_RotaryEncoder.h
  * for Infos  see slight_RotaryEncoder.cpp file
  **/

 
#ifndef slight_RotaryEncoder_h
#define slight_RotaryEncoder_h

/**
  * Includes Core Arduino functionality
  **/
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif


/**
  *
  * Definitions
  *
  **/

/*
struct aspecialthing
{
int one;
int two;
int three;
};

typedef struct aspecialthing AspecialThing;
*/

// definitions
// typdef for step callback
//typedef void (* tCBF_OnStep) (slight_RotaryEncoder*encObj);
typedef void (* tCBF_OnStep) (byte bState); 

const byte state_UNDEFINED = 0;
const byte state_CW = 1;
const byte state_CCW = 2;
const byte state_HalfStep = 3;

class slight_RotaryEncoder
{
public:
// public methods
//Constructor
slight_RotaryEncoder(byte bPin_A_NewValue, byte bPin_B_NewValue, byte bPulsPerStep_NewValue, tCBF_OnStep cbfOnStep_NewValue);
// bool inverse_logic = false --- the = false means a standard value / makes it optional?

//Destructor
~slight_RotaryEncoder();

//word xYfuncName(word XXX);

// run every loop to update stee of system.
void update();

// get state
byte getState();



private:
// per object data

byte pin_A;
byte pin_B;

byte bPulsPerStep;

tCBF_OnStep cbfOnStep;


//internal data
byte bNr;

boolean bA;
boolean bB;
boolean bA_last;
boolean bB_last;
boolean bLastFullStep;

byte bPulsCount;
byte bState;

unsigned long ulTimeStamp;



//word _blubber;
//AspecialThing _theValues;

// private methods
void test();

void stateChange();
void printState();
};

#endif



slight_RotaryEncoder.cpp
Code: [Select]
/**
  * slight_RotaryEncoder.cpp
  * library for easy encoder using
  *
  * copyright (c) 2013 by stefan krueger
  *
  * based on infos and ideas from:
  *  ~ http://www.mikrocontroller.net/articles/Drehgeber
  *  ~ http://www.mikrocontroller.net/topic/drehgeber-auslesen
  *  ~ http://www.mikrocontroller.net/topic/38863
  *  ~ http://hacks.ayars.org/2009/12/using-quadrature-encoder-rotary-switch.html
  *  ~ http://playground.arduino.cc/Main/RotaryEncoders#Waveform
  *
  * whit help from:
  *   pYro_65 ( http://arduino.cc/forum/index.php/topic,162249.0.html )
  *
  * changelog / history:
  *   24.04.2013 08:46 created; based on SwitchPCB_Test_RotaryEncoder_v02
  *
  * to do:
  *   
  **/


/**
  * Includes Core Arduino functionality
  **/
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif


/**
  * Include yourselfs header file
  **/
#include <slight_RotaryEncoder.h>


/**
  * Constructor
  **/
slight_RotaryEncoder::slight_RotaryEncoder(byte bPin_A_NewValue, byte bPin_B_NewValue, byte bPulsPerStep_NewValue, tCBF_OnStep cbfOnStep_NewValue) {

// initialise variables
pin_A = bPin_A_NewValue;
pin_B = bPin_B_NewValue;
bPulsPerStep = bPulsPerStep_NewValue;
cbfOnStep = cbfOnStep_NewValue;

//debug nr.
bNr = 33;

bA = 0;
bB = 0;
bA_last = 0;
bB_last = 0;
bLastFullStep = 0;
bPulsCount = 0;
bState = state_UNDEFINED;
ulTimeStamp = 0;

// initialise pins
pinMode(pin_A, INPUT_PULLUP);
pinMode(pin_B, INPUT_PULLUP);

}

/**
  * Destructor
  **/
slight_RotaryEncoder::~slight_RotaryEncoder() {
  //
}



/**
  * Public methods
  **/

/*
word slight_RotaryEncoder::xYfuncName(word XXX)
{
  //some code
  result XXX;
}*/


/**
  * Returns State (direction)
  **/
byte slight_RotaryEncoder::getState() {
return bState;
}


/**
  * update
  **/
void slight_RotaryEncoder::update() {

/**
rast punkt immer bei 0,0 oder 1,1
CCW
---- A, B
111: 0, 1
111: 0, 0 !
111: 1, 0
111: 1, 1 !
---- A, B
111: 0, 1
111: 0, 0 !
111: 1, 0
111: 1, 1 !

CW
---- A, B
111: 1, 0
111: 0, 0 !
111: 0, 1
111: 1, 1 !
---- A, B
111: 1, 0
111: 0, 0 !
111: 0, 1
111: 1, 1 !

Error
---- A, B
111: 1, 0
111: 0, 0
111:1
111+1
111: 0, 1
111: 1, 1
111:1
111+1
111: 1, 0
111: 1, 1
111:2 <--Wrong reading!!!
111-1
111: 1, 0
111: 0, 0
111:1
111+1

this reading is wrong.
it is not alowed to have 1,1; 1,0; 1,1

**/

boolean bTemp_A = digitalRead(pin_A);
boolean bTemp_B = digitalRead(pin_B);
if ( (bTemp_A != bA) || (bTemp_B != bB)) {
//status changed.
bA = bTemp_A;
bB = bTemp_B;

/** **
Serial.print(bNr);
Serial.print("?: ");
Serial.print(bA);
Serial.print(", ");
Serial.println(bB);
/** **/

// half step; save state of encoder pins for direction check
if (bA != bB) {
bA_last = bA;
bB_last = bB;
bState = state_HalfStep;
stateChange();
} else {
// full step; one step is finished. --> This is Only true if the last full step was not the same level (high or low)
if ( (bA == bB) && (bA != bLastFullStep) ) {
//remember LastFullStep (error correction)
bLastFullStep = bA;
// Encoder turns CW
if (bA == bB_last)  {
//Do Something
bState = state_CW;
stateChange();
} else {
// Encoder turns CCW
if (bB == bA_last)  {
bState = state_CCW;
stateChange();
}
}
}
}
}



}



/**
  * Private methods
  **/
/*
void slight_RotaryEncoder::test()
{
_blubber = _blubber + 1;
}*/

void slight_RotaryEncoder::stateChange() {

if ( (bState == state_CW) || (bState == state_CCW) ) {
if (bPulsCount >= bPulsPerStep) {
// One Step for the User
bPulsCount = 0;

/** DEBUG OUT **/
Serial.print(bNr);
Serial.print(": ");
printState();
Serial.println();
/** **/

/**  RUN CALLBACK Function: **/
cbfOnStep(bState);
} else {
bPulsCount = bPulsCount + 1;
}
}





}

void slight_RotaryEncoder::printState() {
switch (bState)
{
case state_UNDEFINED: {
Serial.print("state_UNDEFINED");
break;
}
case state_CW: {
Serial.print("state_CW   +1");
break;
}
case state_CCW: {
Serial.print("state_CCW  -1");
break;
}
case state_HalfStep: {
Serial.print("state_HalfStep");
break;
}
default: {
Serial.println("??");
}
}
}

/** THE END **/


Thanks for your help!
sunny greetings stefan

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy