Pages: [1]   Go Down
Author Topic: moving function map into library  (Read 557 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm trying to write library for interfacing with some hardware via serial.  I've got things working well like this in a sketch:

Code:
const static struct {
  const char *name;
  void (*func)(char *);
} function_map [] = {
  { "status", processStatusLine },
};

void processStatusLine(char * buffer) {
  Serial.println((char*)buffer);
}

int call_function(const char *name, char * var) {
  int i;
  for (i = 0; i < (sizeof(function_map) / sizeof(function_map[0])); i++) {
    if (!strcmp(function_map[i].name, name) && function_map[i].func) {
      function_map[i].func(var);
      return 0;
    }
  }
  return -1;
}

void setup () {
  Serial.begin(9600);
  char * buffer;
  call_function("status", buffer);
}

void loop() {
}
How do I move the function_map and call_function into my HardwareClass.h and HardwareClass.cpp?  I've tried quite a few things and couldn't get it working.
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 70
Posts: 2171
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This kind of layout below should work, ( untested ) and function_map is not available outside of the Cpp, if it needs to be usable in the sketch file, you'll need a variable marked extern.

Edit: or you will have to make processStatusLine visible to the cpp, by placing its declaration in the header ( can leave the definition in the sketch )

Header:
Code:
struct function_map_type{
  const char *name;
  void (*func)(char *);
};

int call_function(const char *name, char * var);

Cpp
Code:
#include "Arduino.h"

static const function_map_type function_map[] = { { "status", processStatusLine }, };

int call_function(const char *name, char * var) {
  int i;
  for (i = 0; i < (sizeof(function_map) / sizeof(function_map[0])); i++) {
    if (!strcmp(function_map[i].name, name) && function_map[i].func) {
      function_map[i].func(var);
      return 0;
    }
  }
  return -1;
}
« Last Edit: February 25, 2013, 12:25:15 am by pYro_65 » Logged


0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That's not working either.  I also think I need the struct to be private to the object:

Here's what I was trying that's not working

header
Code:
#ifndef HwClassSerial_h
#define HwClassSerial_h

#include "Arduino.h"

class HwClassSerial
{
  public:
    HwClassSerial(HardwareSerial &_hwClassSerial);
   
  private:
    HardwareSerial* hwClassSerial;   
    void init();
   
    struct _function_map{
      char *name;
      void (*func)(char *);
    };
   
    int _call_function(const char *name, char * var);
    void _processStatusLine(char * buffer);

Also tried this under private
Code:
    typedef struct {
      char *name;
      void (HwClassSerial::*func)(char *);
    } function_map[];
   
    static function_map _function_map;

cpp
Code:
#include "Arduino.h"
#include "HwClassSerial.h"

static const _function_map function_map[] = { { "status", _processStatusLine }, };

HwClassSerial::HwClassSerial(HardwareSerial &_hwClassSerial) {
  hwClassSerial = &_hwClassSerial;
  init(); 
}

void HwClassSerial::init()

  hwClassSerial->begin(9600);
  static function_map _function_map  = {
    { "status", _processStatusLine },
  };
}

int HwClassSerial::_call_function(const char * name, char * var) {
  int i;

  for (i = 0; i < (sizeof(_function_map) / sizeof(_function_map[0])); i++) {
    if (!strcmp(_function_map[i].name, name) && _function_map[i].func) {
      //_function_map[i].func(var);
      return 0;
    }
  }

  return -1;
}

void HwClassSerial::_processStatusLine(char * buffer) {
}
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 70
Posts: 2171
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    typedef struct {
      char *name;
      void (HwClassSerial::*func)(char *);
    } function_map[];
   
    static function_map _function_map;

 static function_map _function_map; is invalid, function_map is declared as an array of 'anonymous structs'. Don't worry about typedefs on structs, they are not necessary for this usage in C++.

What I had does work, here is a working example you can modify.

Sketch file:
Code:
#include "a.h"

void processStatusLine(char * buffer) {
  Serial.println((char*)buffer);
}

void setup()
  {
    Serial.begin( 9600 );
    call_function( "status", "test string" );
    return;
  }

void loop(){ return; }

Header ( a.h )
Code:
struct function_map_type{
  const char *name;
  void (*func)(char *);
};

int call_function(const char *name, char * var);
void processStatusLine(char * buffer);

Source ( a.cpp )
Code:
#include "a.h"
#include "Arduino.h"

static const function_map_type function_map[] = { { "status", processStatusLine }, };

int call_function(const char *name, char * var) {
  int i;
  for (i = 0; i < (sizeof(function_map) / sizeof(function_map[0])); i++) {
    if (!strcmp(function_map[i].name, name) && function_map[i].func) {
      function_map[i].func(var);
      return 0;
    }
  }
  return -1;
}
Logged


0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, that does work that way. 

Is it possible for the processStatusLine, function_map_struct, and call_function to all be within the scope of a HwClassSerial class instance instead of in the global scope?  The reason for this is I have several pieces of gear all controlled by serial so I'm trying to setup a base class for each to extend.  Each child class would define it's own function_map_type and there could be several child classes instantiated simultaneously.
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 70
Posts: 2171
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Is it possible for the processStatusLine, function_map_struct, and call_function to all be within the scope of a HwClassSerial class instance instead of in the global scope?

Yes, using the correct working code I provided, you should be able to put them in. However not for the way you want.
To keep with ease of use, processStatusLine and other functions to be called via a pointer need to be non-member functions( static or friends ).

But really, you are mixing two different systems when one will do. call_function is a lookup method, whereas using an inherited/base type should imply that the derived type provides the missing information, which completes the base type.
Logged


0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The problem I'm trying to solve is that I will have several device classes.  For code re-usability I want to have a base class that has a few private methods.
Code:
// sends a command to a serial device and sends each received byte from the output to _processIncomingByte
void _processCommand(const char * commandName, const int longestLine, int linesToRead);

// this takes each received byte and constructs character arrays to be processed.  The method to process the
// character array is determined by the mapping of the commandName
void _processIncomingByte(const byte c, char * buffer, const char * commandName, const int lineLength);

So each class that extends the base class will have a different set of commands to run and methods to process those commands.  Once class could have:
Code:
struct {
  const char *name;
  void (*func)(char *);
} function_map [] = {
  { "status", processStatusLine },
  { "update", processUpdateLine },
};

and another class could have:
Code:
struct {
  const char *name;
  void (*func)(char *);
} function_map [] = {
  { "config", processConfigLine },
  { "reset", processRestLine },
};

Each process function should also be private to each class.  I hope that makes sense. smiley
Logged

North Queensland, Australia
Offline Offline
Edison Member
*
Karma: 70
Posts: 2171
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

If you want the idea encapsulated in a class, and only one serial device is communicating at once, then things are easy using classes.

Imagine your base class is something like this.
Code:
struct BaseType{
  /*
    Pure virtual as you will not be creating instances of this class, only instances of
    classes that derive this base class.
  */
  virtual void RunCommand( const char *c_Data ) = 0;
};

Code:
struct DerivedA : BaseType{

  void RunCommand( const char *c_Data ){

    if( strcmp( "status", c_Data ) ){

    }else if( strcmp( "update", c_Data ) ){

    }
  }
};

struct DerivedB : BaseType{

  void RunCommand( const char *c_Data ){

    if( strcmp( "config", c_Data ) ){

    }else if( strcmp( "reset", c_Data ) ){

    }    
  }
};


Code:
DerivedA objA;
DerivedB objB;

BaseType *currentObj = &objA;

void loop(){

char c_Buffer[ x ];
//...  fill c_buffer with command.

//Run command based on current object.
currentObj->RunCommand( c_Buffer );
}
« Last Edit: February 25, 2013, 05:57:54 pm by pYro_65 » Logged


Pages: [1]   Go Up
Jump to: