Creating and storing instances of objects

Hi, I'm trying to create a library for debug purpouses that will write messages either to the serial or to an UDP port on a server.

To use UDP datagrams, I'm using ClientUDP extension to the ethernet library from Ilya Danilov (http://arduino-powered.blogspot.com/2009/07/using-udp-with-arduino.html) .

In a regular sketch, you will use ClientUDP udp(ip,port); to create an instance of this class and then udp.write or whatever function on the lib. But, right now, I'm stuck with the syntax to, either pass this object to the library to reuse this conection, or store the object in the constructor of my class, and then use it from within my methods.

I've tried:

class udp;

udp=ClientUDP(ip,port);

debugmsg(udp,"some text");

but this does not compile.

I've also tried in the declaration of my library

private: int _Mode; ClientUDPP _udp;

and then, in th constructor:

_udp(server,port);

with no luck,

Can someone help me???

Thx in advance for your help regards Chano

Have you tried this?

ClientUDPP _udp(server,port);

Yeah… no way

Here is the code more deailed

in UdpDebug.h:

#ifndef UdpDebug_h
#define UdpDebug_h
#include “WProgram.h”
#include <ClientUDP.h>
#define DEBUG_SERIAL 1
#define DEBUG_UDP 2

class UdpDebug
{
public:
UdpDebug(int Mode,byte *dserver, uint16_t dport);
void print(char msg);
private:
char _buffer[100];
int _Mode;
class ClientUDP::ClientUDP(uint8_t
dserver, uint16_t dport) _udp;
};

#endif

and in UdpDebug.cpp

#include “UdpDebug.h”
#include <ClientUDP.h>

UdpDebug::UdpDebug(int Mode, byte *dserver, uint16_t dport )
{
_Mode=Mode;
if (_Mode & DEBUG_SERIAL)
Serial.begin(9600);

if (_Mode & DEBUG_UDP)
{
ClientUDP _udp(dserver,dport);
}

}

and here the compiler errors…

C:\Users\Documents\Arduino\arduino-0018\libraries\UdpDebug/UdpDebug.h:19: error: expected `)’ before ‘*’ token

C:\Users\Documents\Arduino\arduino-0018\libraries\UdpDebug\UdpDebug.cpp: In member function ‘void UdpDebug::print(char*)’:

C:\Users\Documents\Arduino\arduino-0018\libraries\UdpDebug\UdpDebug.cpp:29: error: ‘_udp’ was not declared in this scope

For anyone else having problems reading yellow-on-white, just highlight the code, and it should come out a little more legible.

class ClientUDP::ClientUDP(uint8_t* dserver, uint16_t dport) _udp;

What's this?

In the sketch, you wouldn't declared a variable like this. You can't do it in a library, either.

Yes, this is one of the different tests I'm tryning

What I'm trying to do is "store in _udp the result of the creation of an instance of ClientUDP" so I can create the instance in the constructor, and invoke that instance from the different methods of the class.

And I'm really confused, I don't know how to do it!!

One thing to think about is when constructors are called. Initializing instances in the constructor is rarely a good idea.

You should be able, in the class, to declare that _udp is a ClientUDP:

private:
   ClientUDP _udp;

Then, in the begin method (not the constructor), initialize _udp:

_udp = ClientUDP(dserver, dport);

Of course, the constructor for your class will need to have dserver and dport as arguments, and will need private members to store them, so that the begin method can use them.

I’ve tried that way, the code is now:

in .h

#ifndef UdpDebug_h
#define UdpDebug_h
#include "WProgram.h"
#include <ClientUDP.h>
#define DEBUG_SERIAL 1
#define DEBUG_UDP 2

class UdpDebug
{
  public:
    UdpDebug(int Mode,byte *dserver, uint16_t dport);
    void print(char *msg);
    void begin(); 
  private:
    char _buffer[100];
    int _Mode;
    byte *_dserver; 
    uint16_t _dport; 
    ClientUDP _udp; 
};

#endif

and the .cpp

#include "UdpDebug.h"
#include <ClientUDP.h>

UdpDebug::UdpDebug(int Mode, byte *dserver, uint16_t dport )
{
    _Mode=Mode; 
    _dserver=dserver; 
    _dport=dport; 
    if (_Mode & DEBUG_SERIAL)
           Serial.begin(9600);
           

           
}

void UdpDebug::begin()
{
        if (_Mode & DEBUG_UDP)
    {
           _udp = ClientUDP(_dserver,_dport);
    }            
}

and compiler says…

C:\Users\Documents\Arduino\arduino-0018\libraries\UdpDebug\UdpDebug.cpp: In constructor ‘UdpDebug::UdpDebug(int, byte*, uint16_t)’:

C:\Users\Documents\Arduino\arduino-0018\libraries\UdpDebug\UdpDebug.cpp:4: error: no matching function for call to ‘ClientUDP::ClientUDP()’

C:\Users\Documents\Arduino\arduino-0018\libraries\Ethernet/ClientUDP.h:48: note: candidates are: ClientUDP::ClientUDP(uint8_t*, uint16_t)

C:\Users\Documents\Arduino\arduino-0018\libraries\Ethernet/ClientUDP.h:47: note: ClientUDP::ClientUDP(uint8_t)

C:\Users\Documents\Arduino\arduino-0018\libraries\Ethernet/ClientUDP.h:36: note: ClientUDP::ClientUDP(const ClientUDP&)

(That’s why I ended up in the weird syntax I wrote in previos posts…

You need to whack the ClientUPD developer upside the head then, and have them include a default (no argument) constructor and a begin method, like all good Arduino classes do.

Or supply some arguments, even though they might be bogus when declaring _udp, and overwrite the value in _udp with the real object in the begin method.

THX!!! Thats it,

As far as I have the ClientUDP.cpp an .h, I've added a dummy ClientUDP() constructor and the .begin method (with those two parms) and now it compiles and works great!!!

Thx so much for your help!!

You do realise that there is sample code given with the library....

Yes, I do. Actually, I’ve been using that lib for quite a long time with no probs.

The problem was more generic (as I’ve placed in the subject of this post) and if you try to store an instance of this object (imagine you want to have different IP destinations a send messages to those destinations based in some var in your code) it won’t work becuase, as PaulS said, arduino “well coded” libraries always have a no args constructor.

By the way, if someone gets stucked with this, to solve the problem, you need to make this changes to the ClientUDP files.

ClientUDP.h will end up like this:

/*
  ClientUDP.cpp - Ethernet UDP library for Wiring & Arduino,
  based on Client.cpp from Arduino IDE 0016 library.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  2009-Jun-25      v1.0, created by Ilya Danilov <arduino@idanilov.ru>
  2009-Jul-12   v1.1, added _sent and open retucn codes by Ilya Danilov <arduino@idanilov.ru>

  
*/

#ifndef ClientUDP_h
#define ClientUDP_h

#include "Print.h"

#define ERR_UDP_NO_ERROR      0
#define ERR_UDP_SOCKET_USED      1
#define ERR_UDP_NO_SOCK_AVAIL      2
#define ERR_UDP_OPEN_FAILED      3


class ClientUDP : public Print {
private:
  static uint16_t _srcport;
  uint8_t  _sock;
  uint8_t  *_ip;
  uint16_t _port;

public:

  uint16_t _sent;
  
  ClientUDP();
  ClientUDP(uint8_t);
  ClientUDP(uint8_t *, uint16_t);

  uint8_t open(uint16_t = 0);
  uint8_t status();
  virtual void write(uint8_t);
  virtual void write(const uint8_t *, size_t);
  uint16_t read(uint8_t *, uint16_t *, uint8_t *, uint16_t); 
  int available();
  void stop();
  uint8_t opened();
};

#endif

and ClientUDP.cpp just add after the includes at the begining of the file

ClientUDP::ClientUDP() 
{
}

after this, you can properly use code like this in your libraries;

class UdpDebug
{
  public:
    UdpDebug();
    void print(char *msg);
    void printbuff(char *msg, int len);
    void begin(int Mode,byte *dserver, uint16_t dport); 
    void printf(char *fmt,...);
  private:
        void do_print(char *msg); 
    int _Mode;
    byte *_dserver; 
    uint16_t _dport; 
    ClientUDP _udp; 
    int _begined; 
    char _tmp[128];
};

Then, in the begin method (not the constructor), initialize _udp:

Code:

_udp = ClientUDP(dserver, dport);

It is bad practice to do this on any class that does not overload the = operator because of all the implicit actions that happen on this line. You only get away with it because ClientUDP does not own any heap memory. What happens on this one line is:

  1. A transient instance of ClientUDP is declared on the stack. The instance exists only for the life of this one line.

  2. The compiler searches for an overloaded operator=, does not find one and performs a bitwise member copy of the transient class over the top of _udp. If ClientUDP contained pointers into the heap, they would be copied verbatim.

  3. The destructor for the transient ClientUDP is called. If it owned heap memory, the well-written destructor would free() it, invalidating the pointers that were copied into _udp.

  4. The next line executes.

It is a common C++ interview question to show a candidate this scenario, with heap allocated memory, and ask why the program crashes.

So, how is the proper way of doing it??

As you mention, I'm having some problems with constants in the UdpDebug class. (if I place a Serial,print("Hello"); it will print three dots...)

I was wondering what was happening and probably it's related with your comment.

So, how is the proper way to store instances??

thx again

What about a pointer?

in your class:

private: ClientUDP *_pUDP;

Your constructor: MyClass(ClientUDP *pUdp) { _pUDP= pUdp; }

later, in your methods of the class....

_pUDP->write();

You can store a pointer, but it doesn't get around the underlying problem that the ClientUDP does not supply a default constructor. The standard pattern for dealing with a badly behaved class is to wrap it in a well behaved class that encapsulates all the bad stuff. This is made a little unsightly because avr-libc does supply default operators new and delete but it's still possible to completely encapsulate everything.

Here's a demo sketch that shows the following scenario. I have a class 'myclass' that I want to contain a member class 'badclass'. Sadly 'badclass' does not have a default constructor so I must wrap it 'badclasswrapper' and now I am able to create and initialize 'badclass' through the setup() method of 'myclass'. This demo is pared to the bone - sensible state checks in setup() and destroy() have been removed.

class badclass
{
public:
  badclass(int a) { Serial.println("badclass::ctor(a)"); }
  ~badclass() { Serial.println("badclass::dtor"); }
};


class myclass
{
private:
  class badclasswrapper
  {
  private:
    badclass _badclass;
    
  public:
    badclasswrapper(int a) 
      : _badclass(a)
    { 
      Serial.println("badclasswrapper::ctor"); 
    }

    ~badclasswrapper() { Serial.println("badclasswrapper::dtor"); }

    void *operator new(unsigned int size_) { return malloc(size_); }
    void operator delete(void *p) { free(p); }
  };

  badclasswrapper *_wrapper;

public:  
  myclass() { Serial.println("myclass::ctor"); }
  ~myclass() { Serial.println("myclass::dtor"); }
  
  void setup(int a)
  {
    _wrapper=new badclasswrapper(a);
  }
  
  void destroy()
  {
    delete _wrapper;
  }
};


void setup()
{
  Serial.begin(9600);
  
  Serial.println("startup");
  {
    myclass a;

    a.setup(1);
    a.destroy();
  }
  Serial.println("shutdown");
}

void loop()
{
}

The examples given with the link that is posted explain how to do it.

They are in the folder called “examples”.

This is working code given by Ilya Danilov so that people may use his library easily.

“ClientUDPSender.pde”

#include <Ethernet.h>
#include <ClientUDP.h>

byte mac[] = { 0x00, 0x1D, 0x60, 0xAF, 0x03, 0x31 };
byte ip[]  = { 192, 168, 0, 3 };
byte gw[] = { 192, 168, 0, 1 };
byte subnet[] = { 255, 255, 255, 0 };

byte buttons[] = {7,6,5};
byte states[] = {HIGH,HIGH,HIGH};

#define PORT  2222

byte ip_to[] = {192,168,0,2};
uint16_t port_to = PORT;
byte buffer[2];

[glow]ClientUDP udp(ip_to,port_to);[/glow]

void setup() {
  pinMode(4,OUTPUT); 
  digitalWrite(4,HIGH);
  for (int i=0;i<sizeof(buttons);i++) { 
    pinMode(buttons[i],INPUT);
    digitalWrite(buttons[i],HIGH);
    states[i] = digitalRead(buttons[i]);
  }  
  Ethernet.begin(mac, ip, gw, subnet);  
  udp.open(PORT);
}

void loop() {
  for (int i=0;i<sizeof(buttons);i++) { 
    byte s = digitalRead(buttons[i]);
    if (s != states[i]) {      
      states[i] = s;
      buffer[0] = i;
      buffer[1] = !s;
      udp.write(buffer,sizeof(buffer));
    }    
  }
  delay(1);
}

and…

“ClientUDPReceiver.pde”

#include <Ethernet.h>
#include <ClientUDP.h>

byte mac[] = { 0x00, 0x1D, 0x60, 0xAF, 0x03, 0x32 };
byte ip[]  = { 192, 168, 0, 2 };
byte gw[] = { 192, 168, 0, 1 };
byte subnet[] = { 255, 255, 255, 0 };

byte leds[] = {7,6,5};

#define PORT  2222

byte ip_from[] = {0,0,0,0};
uint16_t port_from = 0;
uint16_t pkt_len;
byte buffer[16];

[glow]ClientUDP udp(ip_from,port_from);
[/glow]
void setup() {
  for (int i=0;i<sizeof(leds);i++) { 
    pinMode(leds[i],OUTPUT);
    digitalWrite(leds[i],LOW);
  }  
  Ethernet.begin(mac, ip, gw, subnet);  
  udp.open(PORT);  
}

void loop() {
  if (udp.available()) {
    if (pkt_len = udp.read(ip_from,&port_from,buffer,sizeof(buffer))) {
      if (pkt_len > 1) {
        digitalWrite(leds[buffer[0]],buffer[1]);
      }
    } 
  }
}

You should always read example code.

In the name of knowledge:

/*
  A demonstration of how to initialize members that need a parameterized initialization
*/

class ParameterConstructor {
public:
  ParameterConstructor(int i) {}
};

class ClientClass {
public:
  ClientClass(int i) : parameterConstructor(i) {} //that is the syntax for initializing types that need initialisation
private:
  ParameterConstructor parameterConstructor;
};

ClientClass cc(2);

void setup() {
}

void loop() {
}

:slight_smile:

Thx Paul and AlphaBeta, I'm going to try to "swallow" and understand all your valuable info.

Instead of wrapping the class, I'm going to try to fix it with Alphabeta suggestion and, once it's working, I'll send it to the writer (Ilya Danilow) just in case he wants to update his site.

@invalidapple: I perfectly know how to use the basics of ClientUDP class, as I mentioned, I've been using int for a long time. The question here is not directly related to ClientUDP, it's a more generic ( and complex, as I've been tought by Paul an Alphabeta) about creating instances of classes that are not well coded.

Thx everybody anyway.

I am trying to figure out the same thing. I am writing a Serial LCD library that will use SoftwareSerial if it is Initialized with a txPin Value. Otherwise, it will just use HardwareSerial.

If I wrap SoftwareSerial like so:

class LCDRS2 {
      public:
            LCDRS2();
      
            void init();
            void init(uint8_t txPin);
      private:
            void                  lcd_cmd(byte c);
            void                  serial_write(char* data);
            int8_t                  _txPin;
      class ss_wrap {
            private:
                  SoftwareSerial _ss;
            
            public:
                  ss_wrap( uint8_t receivePin, uint8_t transmitPin ) : _ss( receivePin, transmitPin ){}
                  ~ss_wrap() {}
            
                  void *operator new(unsigned int size_) { return malloc(size_); }
                  void operator delete(void *p) { free(p); }
      };
      
      ss_wrap *cerial;
};

I get the following error when I try:

void LCDRS2::init(uint8_t txPin) {
      cerial = new ss_wrap( NULL, txPin );
      cerial.begin(9600);
}

/Users/Jaesin/Documents/Arduino/libraries/LCDRS2/LCDRS2.cpp: In member function 'void LCDRS2::init()':

/Users/Jaesin/Documents/Arduino/libraries/LCDRS2/LCDRS2.cpp:39: error: request for member 'begin' in '((LCDRS2*)this)->LCDRS2::cerial', which is of non-class type 'LCDRS2::ss_wrap*'