Hello
[EDIT]Sorry for the bad formatting. i use TextMate with tabs spacing=4 if you want to copy/paste the code for good visibility. Oh and for those interested, i have remodeled some makefiles and the TextMate integration is flawless on my setup now PM me if you need it, or if you think i should consider put my work here too[/EDIT]
i received my Arduino a couple of days ago. i have started reading about electronics about a week ago. i understand everything, and i'm able to do powerful stuff already. So i was thinking about starting a small library for my Arduino, and i wanted to have your general advices. For instance... I started with a LED and a Debug class, here comes the dilemma.
Consider this class, located in "LED.h":
#ifndef PQR_LED_h
#define PQR_LED_h
#include "Debug"
#include <WProgram.h>
namespace PQR {
class LED {
public:
// Constructors / Destructor.
/**/ LED (byte pinNumber, bool initialState=false)
: _pin(pinNumber), _state(initialState) {
_leds = (LED**)(_leds ? realloc(_leds, sizeof(LED*)*_count) : malloc(sizeof(LED*)));
_leds[_count] = this;
_count ++;
}
// Global setup method, needs to be called once at the very begining of the program.
static void setup () {
byte pin;
for (byte i=0; i<_count; i++) {
pin = _leds[i]->_pin;
pinMode (pin, OUTPUT);
digitalWrite (pin, _leds[i]->_state ? HIGH : LOW);
}
}
// Accessors.
inline bool state () const { return _state; }
inline void setState (bool v) { if (_state==v) return; _state = v; digitalWrite(_pin, _state ? HIGH : LOW); }
inline bool invert () { setState(!_state); }
// Factory management.
inline static byte count () { return _count; }
inline static LED& at (byte i) { return *_leds[i]; }
// Debug a LED to debugging.
#ifdef DEBUG
inline friend Debug& operator<< (Debug &d, LED const &l) {
return d << "L@" << (int)l._pin << "=" << l._state;
}
#endif
private:
// Static members.
static LED** _leds;
static byte _count;
// Members.
byte _pin;
bool _state;
};
LED** LED::_leds = 0;
byte LED::_count = 0;
}
#endif
It's very easy to use, an Arduino "sketch" could look like this:
#include <PQR/LED>
using namespace PQR;
// Declare as many LEDs as you want.
LED l2 (12, HIGH);
LED l1 (13, LOW);
void setup () {
LED::setup(); Â // The LED static "setup" method takes care of configuring all declared LEDs ports as OUTPUTS.
}
void loop () {
// It's very easy to iterate thru LEDs:
for (byte i=0; i<LED::count(); ++i)
LED::at(i).invert();
// [edit] Was originally LED::at(i)->invert(); thanks Nick Gammon for pointing out the typo.[/edit]
}
So as you may notice, the invert and the setState methods of the LED class are calling the digitalWrite function, which i believe is not very nice for later use of the PIC. So my dilemma would be to make the call do absolutely nothing in the hardware, and instead do something like that:
void loop () {
// It's very easy to iterate thru LEDs:
for (byte i=0; i<LED::count(); ++i)
LED::at(i)->invert(); // Which would not do anything on hardware output yet.
LED::commit(); // Which would make a smart binary use of PORTA / PORTB / PORTC to make sure all I/O are simultaneous.
}
What do you think? Is there such a library already around? My goal is to have a very small memory footprint, as well as a very tiny compiled code. For instance, my debugging class looks like that (You may reuse it, but please give credits if you do):
#ifndef PQR_Debug_h
#define PQR_Debug_h
#ifdef DEBUG_FUNCTION
# define Dbg PQR::Debug() << "Dbg (" << __PRETTY_FUNCTION__ << "): "
# define Wrn PQR::Debug() << "Wrn (" << __PRETTY_FUNCTION__ << "): "
# define Crt PQR::Debug() << "Crt (" << __PRETTY_FUNCTION__ << "): "
#else
# define Dbg PQR::Debug() << "Dbg: "
# define Wrn PQR::Debug() << "Wrn: "
# define Crt PQR::Debug() << "Crt: "
#endif
namespace PQR {
class Debug {
public:
/**/ Debug () {}
/**/ ~Debug () {
#ifdef DEBUG
Serial.println('.');
#endif
}
// Global setup method, needs to be called once at the very begining of the program.
static void setup (unsigned int rate=9600) {
#ifdef DEBUG
Serial.begin (9600);
#endif
}
// Main debugging method.
#ifdef DEBUG
template<class V>
Debug& operator<< (V const &v) { Serial.print(v); };
Debug& operator<< (bool const b) { Serial.print(b ? 'Y' : 'N' ); };
#else
template<class V>
Debug& operator<< (V const &v) { return *this; };
#endif
};
}
#endif
Then in your sketch, debugging via serial basically becomes a breeze:
#define DEBUG
#define DEBUG_FUNCTION
#include <PQR/Debug>
void setup () {
#ifdef DEBUG
Debug::setup ();
#endif
}
void loop () {
Dbg << "This is informative: " << l1;
Wrn << "This requires your attention: " << l1;
Crt << "This is critical: " << l1;
l1.invert ();
delay (500);
}
The output looks like:
Dbg (void loop()): This is informative: L@13=Y.
Wrn (void loop()): This requires your attention: L@13=Y.
Crt (void loop()): This is critical: L@13=Y.
Dbg (void loop()): This is informative: L@13=N.
Wrn (void loop()): This requires your attention: L@13=N.
Crt (void loop()): This is critical: L@13=N.
As you might have understood, you can chain whatever streams you want (E.g. Dbg << "Toto" << 3 << var << '@' << "Blah" and this would work.
Also, if you disable the "#define DEBUG" line, debug lines don't get COMPILED (Really, that's my goal), so you instantly get your PIC memory when you need it.
The dilemma about it: Since i'm very new to Arduino and PICs in general, i have no idea what people usually use for serial debugging. Is it ALWAYS the Serial.print/ln stuff? Or is the Serial1 Serial2 Serial3 etc used too? And is there anything other than that around for debugging which i should consider to integrate into my debugging class for later use?
Any idea?
Thanks,
Pierre.