Logging function to be called by a class hierarchy

Hi, I'm currently making a project for controlling servos. I have some "coded" commands, represented by a class hierarchy (a base class, and some classes which represents a specific command).
The commands will be sent via i2c to my controller board.
What I'd like to do is, before "executing a command", to log it.
The logging function, though, shouldn't be defined at the command level, since it depends on how I choose to log: it should be passed down from the main sketch (imo) and, since it is the same for all instances I thought it as a static param.

Unfortunately it doesn't work.
Currently I work with only one servo (but I'm already prepared for 2), an attiny804 using the megatinycore, and one command (I have more but I want at least one to work).
Please note that before making this changes to the logs everything worked perfectly.
Here is my main program (it targets an attiny804):

#include <avr/delay.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define LCDA 0x27
volatile Servo mot[2];
LiquidCrystal_I2C lcd(LCDA, 16, 2);
CommandServo* command;//dinamico array

void writeToDiag(CommandServo* c) {
 lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Executing:");
  lcd.setCursor(0,1);
  lcd.print(c->_code,HEX);
  lcd.print(" ");
  lcd.print(c->_delay,HEX);
  lcd.print(" ");
  lcd.print(c->angle,HEX);

  }
void setup() {
  // put your setup code here, to run once:

  const Servo s = Servo();
  s.attach(PIN_PA4);
  PORTA.DIRSET |= (0x01 << 5);
  mot[0] = s;
  mot[1] = s;

  initLCD();
   void (*CommandServo::loggin)(CommandServo*)=(&writeToDiag);
command = CreateServo(0x01,0x02,0x1F);

command->execute(mot,0);

}
void initLCD() {
  Wire.begin();
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.clear();
  lcd.blink();
  lcd.cursor();

}
void loop() { }

here is the base class header (command.h):

#ifndef command_h
#define command_h
#include <Arduino.h>
#include <Servo_megaTinyCore.h>
class CommandServo{
       
        public:
                typedef void (*loggin)(CommandServo*);
                CommandServo(){};
                uint8_t _code;
                uint8_t _delay;
                uint8_t angle;             
                virtual void execute(Servo s[], uint8_t curr);
                static loggin;               

};

class MstpOne : public CommandServo{
        public:
                
                virtual void execute(Servo s[], uint8_t curr) override;
};

static inline CommandServo* CreateServo (uint8_t cod, uint8_t del, uint8_t ang){
        CommandServo* cs;
        switch (cod){
                
                case 0x01:
                        cs= (CommandServo*) new Mdir();
                        break;
                default:
                        cs=0;
                        break;
        }
        cs->_code=cod;
        cs->_delay=del;
        cs->angle=ang;

                        return cs;
                }
#endif

the command.cpp file

#include "command.h"
void CommandServo::execute(Servo s[],uint8_t curr){
        CommandServo::loggin(this);
}

and the implementattion of Mdir:

#include "./command.h"
#include <Arduino.h>

void Mdir::execute(Servo s[],uint8_t curr){
  CommandServo::execute(s,curr);
       s[this->_delay].write(this->angle);
}

of course I will add new implementations in the future but what I expected was my i2cdisplay to show me the command values. I must have done something wrong, but my c++ experience is low (it took me 4 hours to make these things). Can someone please help?

It seems to me that the code doesn't compile.

The first line creates a new type - pointer to function with one parameter. The name of type is loggin. Therefore, in the second line you stated the type only and missed the function name.

Hi, thanks for your reply.
The code compiled for me, but regardless: I changed the line in:

 static loggin l;

That does not work: if I leave everything else as is it compiles but still does not work; I get the following warning:

warning: statement has no effect [-Wunused-value]
                   CommandServo::loggin(this);
                                 ^~~~~~~~~~~~

Otoh if I try and use CommandServo::l instead of CommandServo::loggin it does not compile with the following error:

undefined reference to `CommandServo::l'

What am I doing wrong, again?
Thanks

The declaration of the static member inside a class is an incomplete. To finish it you need to add a definition in global scope.
Example from the C book:

class S
{
    static int a; // declaration, incomplete type
};
 
int S::a; // definition, complete type

So I changed your code this way:

 class CommandServo;
 typedef void (*loggin)(CommandServo*);
  
class CommandServo{
       
public:
       CommandServo(){};
       uint8_t _code;
       uint8_t _delay;
       uint8_t angle;             
                
       static loggin l;
};


void writeToDiag(CommandServo* c) {
   
 // do something...
 }
  
// definition of static function pointer l
loggin CommandServo::l = writeToDiag;;
  
CommandServo cs;
void setup() {
  // using the function pointer
CommandServo::l(&cs);
}

void loop() {
  // put your main code here, to run repeatedly:

}
1 Like

Thanks a lot!
Both for your patience and the solution. it works like a charm && I also learned something today! cheers

You are welcome!