Pages: [1] 2   Go Down
Author Topic: Code share: some of my util classes  (Read 2383 times)
0 Members and 1 Guest are viewing this topic.
Netherlands
Offline Offline
Jr. Member
**
Karma: 1
Posts: 93
Profile before you Optimize.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am a C# programmer and am used to work with classes and Object Orientation (OO).
So I created some simple classes to encapsulate some essentials.

I've attached a .zip file called Libraries. Unzip it in your Arduino folder in My Documents. It contains 3 mini libs: AnalogInput, DigitalInput and DigitalOutput.

Please read the header files for more information on the specific classes.

I find them useful and hope others will too.

Enjoy,
Marc Jacobi
Netherlands.

* Libraries.zip (6.98 KB - downloaded 29 times.)
Logged


Global Moderator
Netherlands
Online Online
Shannon Member
*****
Karma: 227
Posts: 14048
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I like the idea of a flag that the value has changed.

idea:
I am missing code to enable the internal pull up resistor

Maybe you can explain the rationale behind the details of these classes ?

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Netherlands
Offline Offline
Jr. Member
**
Karma: 1
Posts: 93
Profile before you Optimize.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It is a work in progress. I build what I need but make sure I can extend later.
BTW: there is a method enableInternalPullup on the DigitalInput class smiley-wink

I've created these classes as an exercise (in Arduino dependency management ;-) ) and because I don't like all the static and sequential stuff that seems to be the norm. I understand that it is convenient for beginners, but I am an OO programmer smiley-cool and like it when I don't have to keep all the low level details in my head  smiley-lol I truly believe that you get better code if you use OO responsibly. But I also understand that it is not the only variable on a platform like the Arduino. That is why I want to learn a bit more on code optimization first, before getting too far ahead of myself. smiley-grin

Also being a beginner in experimenting with the Arduino (although I had previous experience with other types of MCU's) I quickly found that I was repeating myself (in code). To me, that is always a sign 'something needs to be done'. This is my first pass at it.

I hope more people will see its value and find these classes useful.
Logged


Global Moderator
Netherlands
Online Online
Shannon Member
*****
Karma: 227
Posts: 14048
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
BTW: there is a method enableInternalPullup on the DigitalInput class
Sorry, I missed it in the quick look

Quote
I truly believe that you get better code if you use OO responsibly
But allways remember that OO is a tool not the goal itself. And any technique should be used responsibly.

Quote
all the static and sequential stuff that seems to be the norm.
Not necessary the norm but sometimes the only way to get the functionality needed packed in the memory available.

That all said, keep posting your work as it is allways inspiring to see other peoples code.
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Netherlands
Offline Offline
Jr. Member
**
Karma: 1
Posts: 93
Profile before you Optimize.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not necessary the norm but sometimes the only way to get the functionality needed packed in the memory available.

Can you elaborate on that? I have no idea (yet) on how efficient the compiler packs down the code and how smart it is in optimizing.
What I saw was staticly defined class instances just so the MyLib.someFunction (like SPI.write or whatever) syntax can be used. Is the compiler smart enough not to package up unused code? Otherwise if you don't use those statics (because you need more than one instance?) they will only take up  memory space.
Logged


0
Offline Offline
God Member
*****
Karma: 2
Posts: 596
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This brings me to a question I had in my mind since I first posted SimpleTimer on the Playground... what's the best place to share some Arduino code ? Playground seems a bit too "official" sometimes, while libraries posted here in the forum are quickly buried to oblivion due to the sheer amount of activity going on.... The github idea is good IMHO, but it seems the staff doesn't have enough time to bring it forward.
I think some improvement is needed in this area.

I apologize with the OP for hijacking his thread ;-P I'll have a look at the libraries ASAP.
Logged

0
Offline Offline
God Member
*****
Karma: 2
Posts: 596
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Is the compiler smart enough not to package up unused code?

I think unreferenced code is stripped by the linker. Therefore you get into the final .hex file only the code that is actually called (to be precise, that appears to be called at compile time - there's no run-time analysis of dead codepaths, of course).
Logged

Netherlands
Offline Offline
Jr. Member
**
Karma: 1
Posts: 93
Profile before you Optimize.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I dont get why an empty program -with just an empty setup and loop method- is still 466 bytes long!?

 smiley-eek
Logged


0
Offline Offline
God Member
*****
Karma: 2
Posts: 596
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here's main.cpp from Arduino 1.0:

Code:
#include <Arduino.h>

int main(void)
{
init();

#if defined(USBCON)
USB.attach();
#endif

setup();
   
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
       
return 0;
}

At least setup() and init() are called, even on an "empry" sketch, therefore some code has to be compiled in.
Logged

Netherlands
Offline Offline
Jr. Member
**
Karma: 1
Posts: 93
Profile before you Optimize.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Its not complete or done, by any means, I'm just playing around with this...

Debug.h
Code:
#ifndef _Debug_h_
#define _Debug_h_

#include <Stream.h>

#ifdef DEBUG

class Debug
{
public:
Debug(Stream* output) { _output = output; }
inline bool inDebug() { return true; }
inline void writeLine(const char* string) { _output->println(string); }
inline void assert(bool condition, const char* description)
{
if(condition) return;

_output->print("WARNING: Debug assertion failed: ");
_output->println(description);
_output->print(__FILE__);
_output->print(" (");
_output->print(__LINE__);
_output->print("):");
_output->println(__func__);
}
private:
Stream* _output;
};

#else

class Debug
{
public:
Debug(Stream* output) {}
inline bool inDebug() { return false; }
inline void writeLine(const char* string) {}
inline void assert(bool condition, const char* description) {}
};

#endif //DEBUG

#endif //_Debug_h_

I'm still struggling to get the __FILE__ and __LINE__ to work... smiley-wink

usage:
Code:
#define DEBUG // comment out for Release build.

#include "Debug.h"

Debug debug(&Serial);

void setup()
{
if(debug.inDebug())
{
    Serial.begin(9600);
}
}

void loop()
{

    debug.writeLine("inside loop");
    delay(1000);

    debug.assert(false==true, "Test Assertion");

}

Constructive criticism is appreciated.
Hope you like it.
« Last Edit: February 23, 2012, 01:54:51 pm by obiwanjacobi » Logged


Global Moderator
Netherlands
Online Online
Shannon Member
*****
Karma: 227
Posts: 14048
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Quote
I dont get why an empty program -with just an empty setup and loop method- is still 466 bytes long!?

that are two functions, called from main() - C:\Program Files (x86)\arduino-0022\hardware\arduino\cores\arduino\main.cpp

Code:
#include <WProgram.h>

int main(void)
{
init();

setup();
   
for (;;)
loop();
       
return 0;
}

SO it does more than the eye can see (directly)


Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 20
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you for sharing your codes
Logged

Netherlands
Offline Offline
Jr. Member
**
Karma: 1
Posts: 93
Profile before you Optimize.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanx! I hope it will lead to new ideas  smiley-wink
Logged


Netherlands
Offline Offline
Jr. Member
**
Karma: 1
Posts: 93
Profile before you Optimize.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think unreferenced code is stripped by the linker. Therefore you get into the final .hex file only the code that is actually called (to be precise, that appears to be called at compile time - there's no run-time analysis of dead codepaths, of course).

I was reading up on the underlying avr toolset and libraries and came across this page:
http://www.nongnu.org/avr-libc/user-manual/library.html

At the "How the linker works" section it describes how the linker uses complete object files to decide what to include and what not. So only if you write each function in a separate file, it cannot get optimized even when it is not in use. There goes the class file  smiley-cry
Logged


Netherlands
Offline Offline
Jr. Member
**
Karma: 1
Posts: 93
Profile before you Optimize.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

BitArray.h

Code:
#ifndef __BITARRAY_H__
#define __BITARRAY_H__

#include <Arduino.h>

// The BitArray class stores bits in one or more bytes.
// This class can be used for maintaining boolean flags in a memory effecient way.
// A normal boolean takes up a whole byte.
// T is an (unsigned) integer datatype.
template<typename T>
class BitArray
{
public:
BitArray(T initialValues)
{
_bits = initialValues;
}

bool Set(byte bitIndex, bool value)
{
if (bitIndex > getMaxBits()) return false;

T mask = 1 << bitIndex;
// clear bit
_bits &= ~mask;

if (value)
{
// set bit
_bits |= mask;
}

return true;
}

bool IsTrue(byte bitIndex)
{
if (bitIndex > getMaxBits()) return false;

T mask = 1 << bitIndex;
return ((_bits & mask) > 0);
}

bool IsFalse(byte bitIndex)
{
if (bitIndex > getMaxBits()) return false;

T mask = 1 << bitIndex;
return ((_bits & mask) == 0);
}

byte getMaxBits()
{
return (sizeof(T) * 8);
}

bool operator[] (byte bitIndex)
{
return IsTrue(bitIndex);
}

operator T()
{
return _bits;
}

private:
T _bits;
};

#endif //__BITARRAY_H__

usage:

Code:
#include <HardwareSerial.h>

#include "BitArray.h"

BitArray<byte> bits(0);

void setup()
{
Serial.begin(115200);

bits.Set(0, false);
bits.Set(1, false);
bits.Set(2, true);
bits.Set(3, false);
bits.Set(4, false);
bits.Set(5, false);
bits.Set(6, true);
bits.Set(7, true);
}

void loop()
{
Serial.print(bits.getMaxBits());
Serial.println(" bits");
Serial.print("value = ");
Serial.println(bits);

for (int i = 0; i < bits.getMaxBits(); i++)
{
Serial.print(i);
Serial.print(" = ");
Serial.println(bits.IsTrue(i) ? "true" : "false");
}
 
delay(2000);
}
« Last Edit: March 03, 2012, 09:17:35 am by obiwanjacobi » Logged


Pages: [1] 2   Go Up
Jump to: