Page 1 of 1

Arduino Programming for Beginners – Part 6: Functions

Arduino Programming for Beginners – Part 6: Functions
   9

In this article we will talk about Functions. In previous parts we have worked with two functions already (setup and loop), but in this part we will go deeper into using functions and creating our own.

This is the sixth part of a series of articles I’ve written to get beginners started with Arduino Programming in the programming language C, which I’ve written with the intend to teach my 13 year old nephew (Bram) to get started with the Arduino. After all, he wants to build a robot, but without some basic knowledge about programming, he won’t get far ….

Besides an introduction into the language C, the default language used for Arduino Programming, “Arduino Programming for Beginners” will also touch topics like how to setup an Arduino, get a developers environment running, and look at a few basic electronic parts which we connect to our Arduino.




Overview of this Chapter

  A complete overview of this course can be found here: Course Overview.

What are Functions and Why do we need them?

Theoretically we do not really need functions … however, without functions our code would become super long and completely unreadable. Not to mention; we’d have to write a lot more code.

We have already worked with 2 functions that are required for your Arduino: “setup()” and “loop()”.

But what are functions and why do we need them? Or better said: why do we like them?

A function (also called: subroutine) can be seen as a set of instructions, grouped together, with a specific task in mind.
We can create a function to keep our code more readable, or because we’d like to use that particular task in several locations of our program(s).

It’s called “subroutine” in some languages, because that’s what it is; see it as a little program on it’s own. And as with a regular program, a function can therefor also have other functions defined inside it, and that brings us to another issue to pay attention to: A function has a scope, just like with variables – the “area” in which it can be seen and used!

I realize this is a little bit much to grasp right away, but it is something to keep in mind.

We can define functions that does return a result (value) or does not return a result.
The latter, not returning a result, is called a “procedure” in other programming languages. The language C however calls both just a “function”.

A function, is a group of instructions for a specific task.

When do we define our function?

  • When code is repeated more than once in my program
  • If my code becomes more readable with functions
  • If my code becomes more manageable with functions
  • If we’d like to re-use a piece of code for example in other programs

Let’s look at an example of what a function could be – just to grasp the concept.

Say we have a dog, which needs walking 4 times a day: At 8 AM, 12 PM, 5 PM, and at 9 PM.

The task of walking the dog involves:
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the part for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.

Now let’s assume our program handles our day when it comes to walking the dog:

if 8 AM then
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the part for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.

if 12 PM then
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the part for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.

if 5 PM then
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the part for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.

if 9 PM then
– Put on a coat
– Put on the leash of the dog
– Go outside
– Walk through the part for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.

Our program is pretty long, right? And a lot of repeating code as well …

We could create a function, let’s call it “WalkTheDog()”, and define it as follows.

WalkTheDog():
– Put on a coat

– Put on the leash of the dog
– Go outside
– Walk through the part for 15 minutes
– Go back inside
– Take off the leash of the dog
– Take off your coat.

Now our program would look much simpler:

if 8 AM then
  WalkTheDog()

if 12 PM then
  WalkTheDog()

if 5 PM then
  WalkTheDog()

if 9 PM then
  WalkTheDog()

You see, that not only our code has gotten much shorter, but it also has become much more readable – the “function” is called as if it was a regular statement. We in fact expanded our “language”.

In most scenario’s, using your own functions will also result in a smaller compiled program for your Arduino or computer, therefor being more efficient with memory needed on your Arduino (or computer).

But functions have also the advantage that if you made a mistake in your steps of walking the dog, that you only have to modify your code in one spot: the function – which makes your code more manageable. For example, if we forgot to add “Unlock the door” as a step. We just edit the function WalkTheDog() instead of having to edit the code in 4 different spots in the previous code.

Now if we have a function that is more of a generic use, we can even put them in what is called a library and re-use the function in our other programs. But more about “libraries” in a next part.

Please keep in mind that:

 

  • A function is like a little program on it’s own … inside a program
  • A function can have functions inside it …
  • A function has a scope” – like we have seen with variables and constants.

Creating our own Function(s)

It’s pretty easy to define our own functions in the language C which we use for Arduino programming. The basic structure looks like this:


datatype FunctionName ( FunctionParameters } {
  // function code
}

I hope you remember some of the DataTypes we have mentioned in Part 3 – DataTypes. If not, don’t worry, you can look back if you’d like, but I will also mention some of the details here.

The datatype is defining what kind of data is being returned from the function and unfortunately, not all datatypes are all that suitable for use as a return value for functions. Definitely avoid arrays!

The most common datatypes for a return value are boolean, int, char, float and void (other types will work as well, like double, long and the “unsigned” types).

Obviously, our function needs a FunctionName, and we need to follow the same naming rules as with variables and constants:

Function name:

  • Should start with a letter (a, b, …, z, A, B, … , Z) or underscore ( _ )
  • Can contain letters 
  • Can contain underscore(s)
  • Can contain numbers 
  • CAN NOT contain special characters, symbols or spaces
  • is case sensitive!

The Function Parameters are zero or more values that we want to pass to the function. The number of values and the datatype of these values however is fixed and defined in our function definition!

In some C dialects you will need to “declare” (announce) or “define” a function before it’s being used in the code. The compiler needs to “know” it exists before it can use it. This appears not to be the case with C on the Arduino, which is why it will not be addressed here.

We have used function parameters before, even though you might not have been fully aware. It’s those values we pass between brackets, for example in this line: Serial.print("Hello");

Here we call the function “print()” from the object “Serial” and we pass the parameter “Hello” (a string). More about objects later.

The following code block, between accolades, is something we have seen before as well in for example the “if” function and the different loop kinds (“for”, “while” and “do … while …”).

This code block groups the instructions for our function.

Let’s start with a simple function:


1
2
3
void SayHello() {
  Serial.println("Hello");
}

This function, called “SayHello()”, takes no parameters since there is nothing between the () brackets.
It also does not return a value, since we used the special datatype “void” – which means “nothing, thin air, nada”.

The “body” of the function (the code block), holds the instructions for this function, and it just outputs “Hello”.

An example of how we’d use this:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  for(int A=1; A<=5; A++) {
    SayHello();
  }
}

void loop() {
  // leave empty for now
}

void SayHello() {
  Serial.println("Hello");
}

Most of this should look familiar, I’d hope anyway …

At the end of the code you see how we defined our “SayHello()” function.
In the “for”-loop you see how we call our function 5 times, which results in an output like this:

Hello
Hello
Hello
Hello
Hello

Easy right?

Passing a Value to a Function

This was a rather simple example, let’s look at an example where we actually pass a parameter, where we use a previous example of turning on 5 lights with a “for”-loop.

For this we create a new function, called “DoLights”, to which we want to pass the light number of the light that needs to be switched on.

We already know that this number is a whole number of datatype “int” (see also the definition of “A” in the “for”-loop).

We also know that it will not return any values, which then get’s us this function:


void DoLights(int LightNumber) {
  Serial.print("Switch lights on for light ");
  Serial.println(LightNumber);
}

The parameter “LightNumber” is defined as an “int”. You can see that there is a the definition of the variable “LightNumber” inside the function called “DoLights”. When we pass a value for that parameter, the value will be copied into that “new” variable.

Keeping “scope” in mind, “LightNumber” obviously only exists in the function “DoLights”.

Calling our function (line 6) is just the same as the previous example, this time however we pass the value of the variable “A”. The value of “A” is being copied into the variable “LightNumber” – remember that it’s COPIED.

All this combined:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  for(int A=1; A<=5; A++) {
    DoLights(A);
  }
}

void loop() {
  // leave empty for now
}

void DoLights(int LightNumber) {
  Serial.print("Switch lights on for light ");
  Serial.println(LightNumber);
}

You see how the variable “LightNumber” is being used in the function?

But this was just an example on how to pass just one value. How does this work if we need to pass multiple values?

As an illustration, we will add a boolean value which we’d like to pass to our function. If this value is true then the lights should go ON, if it’s false the lights should go off.

To do this we need to separate the two values and for this we use a comma ( , ).

Parameters in a function are separated by a comma,
both when defining the function and when calling the function.

As with any value we’d like to pass, we again need to define it’s datatype (boolean) and name (LightOn).

I’ve added an “if” statement, so that the function can accommodate for switching the lights ON or OFF – another cool feature of functions; we can write them in such a way that they can work for more than one scenario.

All this combined:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  for(int A=1; A<=5; A++) {
    DoLights(A, true);
  }
 
  for(int A=1; A<=5; A++) {
    DoLights(A, false);
  }
}

void loop() {
  // leave empty for now
}

void DoLights(int LightNumber, boolean LightOn) {
  if(LightOn) {
    Serial.print("Switch lights ON for light ");
  }
  else
  {
    Serial.print("Switch lights OFF for light ");
  }
 
  Serial.println(LightNumber);
}

As you can see, we first run a “for”-loop, of 5 iterations, switching the 5 lights ON.
The values we pass are separated by a comma as well!
In the next “for”-loop, also 5 iterations, we switch the lights OFF.

Your output should look like this:

Switch lights ON for light 1
Switch lights ON for light 2
Switch lights ON for light 3
Switch lights ON for light 4
Switch lights ON for light 5
Switch lights OFF for light 1
Switch lights OFF for light 2
Switch lights OFF for light 3
Switch lights OFF for light 4
Switch lights OFF for light 5

Now obviously, the examples here are not really good ones when it comes to begin more efficient. But when you start creating your first, larger, programs, you will see how functions are an asset for a programmer.

Returning a Value from a Function

So we know that a function can “receive” values by using parameters. Now what if we want the function to return an answer or result – for example from a complex calculation?

Remember we used “void” with our previous function definitions? That’s where we define what the returning result will be.

In the function itself however, we do need to actually “return” that type of value, and we use the function “return” for that.

If you define a function which will return a defined datatype, then you will need to use the “return” statement to return a value, which has to be of the same datatype as the defined return value datatype of your function …

An example could be made with one of the previous examples where we calculated “AllMyMoney” by adding what is in our wallet and what is in the bank. A pretty trivial situation, since we can calculate this already more efficient without creating a function, but it’s a good illustration. Obviously, once you start writing you own programs, these functions will contain much more and more complex code than this.

So we created a function “CalculateMyMoney”, which takes two parameters. I intentionally named them differently again, to illustrate that the values of the 2 variables (PocketMoney and Savings) are being COPIED to the variables names we defined in the function. It would have been fine to give the parameter variable names the same names, if you recall the “scope” of variables: the variables in the function are not the same variables as the ones outside of the function.

In the function we add these 2 values and return the result “Total”. This “return” value is then assigned to the variable “AllMyMoney”.

Go ahead and try this code.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  // define our variables
  int PocketMoney;
  int Savings;
  int AllMyMoney;

  // assign the values
  PocketMoney = 4;
  Savings = 12;
  AllMyMoney = CalculateMyMoney(PocketMoney, Savings);

  // print the values to the serial monitor
  Serial.print("PocketMoney = ");
  Serial.println(PocketMoney);

  Serial.print("Savings = ");
  Serial.println(Savings);

  Serial.print("AllMyMoney = ");
  Serial.println(AllMyMoney);
}

void loop() {
  // leave empty for now
}

int CalculateMyMoney(int Wallet, int Bank) {
  int Total;

  Total = Wallet + Bank;

  return Total;
}

A function with a returning value, could be seen as a variable. So where ever we can use a value, or a variable, we could also use the function that returns a value, which I’ll illustrate in this slightly modified version. Look at line 21 … we’ve just placed the function call right there as a “parameter” for the “Serial.println() ” … and that works! So we do not need to first assign a returning value to a variable.

If you need the result of a function more often, then storing it in a variable makes perfect sense. After all: calling the function will exectute it’s code again, which would be redundant if we would need the same answer more than once.

A function with return value, can take the place of a regular value or variable …

Each time we call a function, it’s code will be executed. So if you need the result more than once, consider storing the value in a variable instead of calling the function repeatedly.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  // define our variables
  int PocketMoney;
  int Savings;

  // assign the values
  PocketMoney = 4;
  Savings = 12;

  // print the values to the serial monitor
  Serial.print("PocketMoney = ");
  Serial.println(PocketMoney);

  Serial.print("Savings = ");
  Serial.println(Savings);

  Serial.print("AllMyMoney = ");
  Serial.println( CalculateMyMoney(PocketMoney, Savings) );
}

void loop() {
  // leave empty for now
}

int CalculateMyMoney(int Wallet, int Bank) {
  int Total;

  Total = Wallet + Bank;

  return Total;
}

At this point I strongly recommend playing with functions. Make up a function yourself, with or without return value, and do some experimenting.

Functions calling Themselves (Recursion)

  This paragraph maybe be too complicated for beginners – feel free to skip it if you feel it’s too much for you.

A function can actually call itself, this is called “Recursion“.

You must be thinking that we ended up in crazy town – well, do not worry if recursion is a little bit too much for you. It is a little much for any beginner and even some experienced programmers.

So for this course we will leave it be for what it is: something you will not be using until you get more experienced with programming.

Recursion can be a very powerful tool, to write a limited amount of code yet produce stunning results. For example certain graphics can be generated with recursion like the tree below or the so called Sierpinski triangle. (image source: Wikipedia – Tree by Brentsmith101, Sierpinski by Wereon).
These a drawn by utilizing Recursion.

Recursive Tree

Recursive Tree

Sierpinski Triangle - Triangle in triangle

Sierpinski Triangle – Triangle in triangle

If you’re interested anyway … here a quick and simple example that is less complicated as the two images above.

Let’s say we want to add all whole numbers, for all numbers between 1 and 5. So we want to know how much 1+2+3+4+5 is (15).
Obviously we can do this very simple by either entering that manually, or by using a “for”-loop, but today we want to be difficult so we use this scenario as our recursion example.

We are going to create a function that starts at “5” and adds the number below that (4), then add the number below that (3), etc etc. until we added 1.


1
2
3
4
5
6
int AddOneLess(int Number){
    if(Number==0)
       return Number;
    else
       return Number+AddOneLess(Number-1);
}

So what this function does is, take the “Number” value. If this number is zero, then return zero. If the number is not zero, then take that number and call the “AddOneLess” function for the number minus 1.

Weird right?

In other words: this function will start with a given number, and keeps adding each time the previous number until it reached zero (0).

Let me display this differently by using this example code:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void setup() {
  // set the speed for the serial monitor:
  Serial.begin(9600);
 
  Serial.println(AddOneLess(5));
}

void loop() {
  // leave empty for now
}

int AddOneLess(int Number){
    if(Number==0)
       return Number;
    else
       return Number+AddOneLess(Number-1);
}

First we call AddOneLess(5).

The value of “Number” is not zero, so we do 5 + “AddOneLess(5-1)”, and there is NO return value yet since we now went into the AddOneLess(5-1) function call.
This second call, is where the value of “Number” is 4, and still not zero so we add 4 + “AddOneLess(4-1)” and we’re calling AddOneLess again, so no return value yet.
This results in the third call where the value of “Number” is 3 and still not zero so we add 3 + “AddOneLess(3-1)” – no return value yet.
This results in the fourth call where the value of “Number” is 2 and still not zero so we add 2 + “AddOneLess(2-1)” – no return value yet.
This results in the fifth call where the value of “Number” is 1 and still not zero so we add 1 + “AddOneLess(1-1)” – no return value yet.

The sixth call however the value of “Number” is 0 (zero), so we return “zero”.

However ,… we return zero in the “scope” of the fifth call, we went one step back, where the value of “Number” is 1, and where we say: return the value of “Number” and the return value of calling “AddOneLess(1-1)”.

So the fifth call returns 1 (value of “Number”) + 0 (return value of AddOneLess(1-1) ) = 1.

Now we return to the scope of the fourth call, where “Number” had the value 2, and which returns the value of “Number” + the return value of “AddOneLess(2-1)”, so: 2 + 1 = 3.

Returning to the scope of the third call, “Number” has a value of 3, and the return value = 3 + 3 (return from “AddOneLess(3-1)”)  = 6.

When getting back to the second call, “Number” has a value of 4, so the return value = 4 + 6 = 10;

And coming back to the original call, “Number” is 5, and the return of the “AddOneLess(5-1)” has become 10. So this call returns 5 + 10 = 15.

Nice and confusing right?

Maybe it makes more sense to show it this way:


1
2
3
4
5
6
7
8
9
10
11
12
13
1st call:     AddOneLess(5)    // in the setup() function
2nd call:     AddOneLess(4)    // in the AddOneLess(5) function call
3rd call:     AddOneLess(3)    // in the AddOneLess(4) function call
4th call:     AddOneLess(2)    // in the AddOneLess(3) function call
5th call:     AddOneLess(1)    // in the AddOneLess(2) function call
6th call:     AddOneLess(0)    // in the AddOneLess(1) function call, Number will now be zero!
5th call:     Return = Number + result 6th call = 1 + 0 = 1
4th call:     Return = Number + result 5th call = 2 + 1 = 3
3th call:     Return = Number + result 4th call = 3 + 3 = 6
2nd call:     Return = Number + result 3th call = 4 + 6 = 10
1st call:     Return = Number + result 5th call = 5 + 10 = 15

Final return: = 15

I know this is complicated to grasp for the first time, so no worries if this is way over your head. I really had to think hard about even putting this explanation in here, but for all completeness I’ve added it anyway. Just remember that a function can call itself and that it will not interfere with previous calls. Each function call will get it’s own “scope”.

Just a rule of thumb to keep in mind when using recursion: Always make sure there is an “exit” condition in the function so the function does not keep going forever and crash your Arduino or computer … after all, for each call a scope is being stored in memory and your Arduino does have a limited amount of that.

When creating Recursive functions:

ALWAYS make sure the function has an “exitcondition to leave the function.

 

If you have questions, just ask them below in the comment section, and keep in mind: There are no stupid questions! We all had to start at some point!

Next chapter: Arduino Programming for Beginners – Part 7: Strings

Donation options


Donations are very much appreciated, but not required. Donations will be used for web-hosting expenses, project hardware or a motivational boost (a drink or snack). Thank you very much for those have donated already! It's truly AwEsOmE to see that folks like our articles and small applications.

Comments


There are 9 comments. You can read them below.
You can post your own comments by using the form below, or reply to existing comments by using the "Reply" button.

  • Feb 11, 2017 - 9:01 AM - Stan Comment Link

    Hi Hans. I know in this chapter we learn to create our own Functions but i just want to ask whats the real difference between these two.

    If i m right with the logic ; 

    Code 2 makes A to count start from 1 and execute serial.print and serial.println statements together like a “Flow-After” and then goes to top and do this for 2,3,4 and 5 too. Because its a (count) For Statement. This creates a Count!

    in Code 1 we make again a For statement but for the result we want the sayHello() function to be run and we defined function sayHello() as a text value to be printed. This creates a Repeat!

    So one is a Repeat and other is a Count but i cldnt understand the real difference and also  i have another question; We define sayHello() function AFTER the statement of usage of it! Shldnt we First define it and Then call it? Why sayHello() function is UNDER the statement? (Even at the Last, after void loop)

    Code 1 ;

    void setup() {

      Serial.begin(9600);

      for(int A=1; A<=5; A++) {

        SayHello();

      }

    }

    void SayHello() {

      Serial.println(“Hello”);

    }

    Code 2;

    int A ;

    for(A=1; A<=5; A++) {

      Serial.print(“Switch lights on for light “);

      Serial.println(A);

    }

    Reply

    Stan

    • Feb 11, 2017 - 11:45 AM - hans - Author: Comment Link

      Hi Stan,

      both code 1 and 2 are a loop, where we repeat something 5 times. You can call it repeat or loop – but in both cases you’re using a so called for-loop which counts and executes code between { and }. The only difference between these 2 examples is that in Code 1 you execute a function you made yourself, and in code 2 you execute the code straight.

      The advantage of using a function is when you see it being used more than once,… or when the code get’s very large and hard to read.
      The first one (code that is being used more than once elsewhere in your program) is the most common one. However, when the code between { and } in the for-loop becomes very extensive, it can be beneficial to split it in “tasks” (meaning: functions), just so it becomes more readable and easier to debug in the future.

      As for the definition of the function being at the end; it is more correct to “declare” the function first, write the rest of the code and then actually write the code of the function. For example:

      void SayHello(); // declare function
      
      void setup() {
        Serial.begin(9600);
        for(int A=1; A<=5; A++) {
          SayHello(); // use function
        }
      }
      void SayHello() { // actual function code
        Serial.println(“Hello”);
      }

      This would be the proper way – this way we tell the compiler up front that when it sees the function “SayHello” that this function does not have a return value (void) and does not take any parameters. The actual implementation follows later.
      This forward declaration is seemingly not needed for the Arduino compiler.

      Other languages (like Pascal) are much more strict and require a forward declarion. That’s why a language like Pascal is a better language to learn programming, since it forces you to work correctly. C (and derivates from C, like C++, C#, Java, etc.) allow quite often that the programmer can work a lot more sloppy – which causes sometimes unexpected results that can be hard to debug.

      Reply

      hans

      • Feb 11, 2017 - 11:59 AM - Stan Comment Link

        Real sorry Hans. I didnt get what i this ;

        void SayHello(); // declare function

        We never use (;) right after double brackets (). Whats to declare? We declared at the bottom already! :(

        Reply

        Stan

      • Feb 11, 2017 - 12:09 PM - hans - Author: Comment Link

        Well, that’s why I left it out of the tutorial .

        The declaration basically tells the compiler: if you run into this function, before you found the real function, then this is how it should work and be used. Since more and more modern compilers look through the entire code first, it would already have seen the function the way you defined it. So don’t worry too much about it just yet … 

        Reply

        hans

        • Feb 11, 2017 - 12:12 PM - Stan Comment Link

          Oh umm okay. So i can use my homemade function um for example in an if..then.. function but declare my function After if..then..function. and its ok.. true?

          Reply

          Stan

          • Feb 11, 2017 - 12:26 PM - Stan Comment Link

            This my First Code that i wrote on my own!!! No copy no research just thought and built.. And thats a very big step(start) for me and i m so happy. Because Hans is my teacher who has a brillant way to explain things! So i wanted to dedicate my First code to Hans..( my fav number is 7 😆)

            void setup () {

            Serial.begin(9600);

            for(int myFirstCode=1; myFirstCode<=7; myFirstCode++) {

            Serial.print(“Hurray Hans for “);

            Serial.println(myFirstCode); 

               }

            }

            Applause goes to Hans the Golden Man ! 👏👏👏🤗

            Stan

          • Feb 11, 2017 - 2:08 PM - hans - Author: Comment Link

            Haha … very cool! (your first code)

            Yes usually you can use your homemade function like that 

            hans

          • Feb 11, 2017 - 2:16 PM - Stan Comment Link

            Hehe yes i know its not even a code for u Master. More like a Replacing maybe.  Sure. But i opened new sketch and decided and did. Therefore i got the logic and the codes for example For-loop. Comeon. Thats a step for me ; not to memorise but to write whit Thinking ! 😊

            Stan

          • Feb 12, 2017 - 3:15 PM - hans - Author: Comment Link

            Stan i think you’re doing great! I mean that! 
            Not many people keep trying like you do.

            hans



Your Comment …

Friendly request to not post large files here (like source codes, log files or config files). Please use the Forum for that purpose.

Please share:
*
*
Notify me about new comments (email).
       You can also use your RSS reader to track comments.


Tweaking4All uses the free Gravatar service for Avatar display.
Tweaking4All will never share your email address with others.