Ok now the fun stuff. Now we can do something..  We still have a small mess to clean up now. It's the Arduino's Libraries. They are quite a mess so here is what we have to do
The Arduino's IDE wants only to see two main functions:

  • setup()  Setup is where you do something once.
  • loop()  Loop is just that a loop. Now while in the loop() function you may call other functions. A function is nothing more than a subroutine, with a defined argument list, or none, and some return type or void for nothing.

Most of the time when I write software in almost any language with the exception of Perl, my code looks like this (ANSI C):

#include main.h

#include stdio.h

int main (int argc, char *argv[]) {

int errorcode = housekeeping();

if( errorcode) => 1) {

// this is my function that has the initialization code or what you would put in the Arduino's sketch.

// the # sign includes my personal header file with defines, pin defines etc.

// the # sign include stdio is to load the standard IO lib which lets me use printf.

// the first function I call is main() which is the mandatory entry point for user input commands etc.

// Now function I call is housekeeping () in its own file and companion header ie. (housekeeping.c and housekeeping.h

// why doesn't it have a return type on housekeeping well its formally described in its two files and it has an int return type (something might have failed) so my return is 0 which is reverse logic.  Please don't panic any return with a 1 or higher means well are done. Or if you really want to, make them negative numbers. )(purist)

NOTE: NEVER EVER do error checking as shown below in the table (the program was on "Stack Exchange" voted the correct way of using a GOTO LOL) (just don't use the damn thing.)

// the reasoning is that as your program gets larger and larger you wish to hide code from some other parts. This is part of the scoping rules
// here you can implement a case statement to print out the errorcode you don't have to go look it up.

printf( "Huston we have a problem: %d \n", errorcode); }

else {

Now about my style, I know I'm going to get jumped but what the hell, but here goes. (I and the universe hates blank space its a vacuum.)

  • Between a ) and { as in for, while, if, function call, etc. there is always 1 space. NOT a new line with the curly brace on a newline.
  • To end a { with a }: the closing curly brace is on the last line of the function, etc.  NOT a new line with the curly brace on a newline. (if you like it please use a heavily typed language like Python or Ada. 
  • example:

errorcode( int n) {

    if ( something ) {

          switch errornumber {

              case 1 {

                    I'm dead;

                  break; }  // always use the break so your code doesn't fall through. 

              case 2 {

                    Your dead;

                    break; // better for me!! } Please Note this will NOT work as the comment is before  }

              defualt {

                    Someone else died!; }}}}  //Please always use a default case!!

Please note the last line with the 4 closing curly braces I much prefer it to this silliness.

                  default

                                {

                                Someone else died!;

                                }

                            }

                      }

                  } 

Organization Each one of your functions should have its own file.c and file.h remember the header is where you will define your function. So your usage of your function anywhere must agree with it's declaration in the header file (.h). Now an easy way to include all the headers that your software needs to be seen is just included them in a header file. yup a header file containing other header files. (what a concept)

So for instance, if your program uses both the I2C and TCP. The way I encapsulate this is very simple. The software never calls either directly as there are no public header files; as there are no public header files included. what I have done is included 6 functions setup_I2C, setup_TCP, read_I2C, read_TCP, write_I2C, write_TCP. And yes I also have to write an interrupt handler as well. Please note my capitalization. The only reason that TCP and I2C are capped is that they are protocol names and normally capped.

NOTHING IS CAPED except #define as in #define TRUE 1; or structure names which I normally cap the first letter.

 

Oh yes, flower-ism. Please avoid these things which other programming languages try to enforce, ie PASCAL, you have to use a pointer -> to basically dereference something. Like fred->car.color  which is very simple which is the color of Fred's car; right? So please refrain from using flower-isms like this: FredpointstoCarColor -> Car.Color .

This nonsense gets worse in Java with their crazy Cap No Cap Cap and No Cap. This all gets carried to its logical conclusion by our friends the French who came up with a set of rules (guidelines) of how to write a program. No nothing to do with logic. it is MISRA. they have over 144 rules. Unfortunately, the FAA and Uncle Sam loves MISRA and there is a complete set of dah rules published in the JSF Coding Standard. I believe that I have a lint with the rules built into it.[2]

NEVER DO THIS:DON'T DO THIS:

void foo()
{
  
if (!doA())
  
goto exit;
  
if (!doB())
  
goto cleanupA;
  
if (!doC())
  
goto cleanupB;

  
/* everything has succeeded */

   return;
cleanupB:
  undoB
();
leanupA
:
  undoA
();
exit:
  
return;
}

*** 2  returns, Very Bad.

*** conditions !doB and !doC never tested

also his name conventions are not the same between function and Cleanup

 

here I moved doA to the bottom, As to allow testing of B & C

void foo() {
   if( !doB()) {
      undoA(); }
    else if (!doC()) {
      undoB(); }
    else if(!doA()) {
       return;
    else {  //

now what are you going to do?

MAYBE THIS: NOPE But CloseTHIS WILL WORK

void foo() {
if (!doA() && !doB() && !doC(){ return; }

 

The following is still wrong what happens when do C fails??

void foo() {

   if (!doB()) {

      undoA(); }

   else if (!doC(){

      undoB(); }

   else if (!doA() && !doB() && !doC() {

      return; }}

First fix doA(), doB() and doC()

they now return (ERROR) // simple #define ERROR -1

now we can do this intelligently.

#define PASS 1;

void foo() {

int A, B, C = PASS; // assign them all to PASS

if (( B = doB()) == ERROR ){

    undoA(); }

else if(( C = doC()) == ERROR ){

    undoB(); }

else if(( A = doA()) == ERROR ){

   // do something!!

else{

// ::= !A + !B + !C   WINER WINER CHICKEN DINNER

   return;

}

 

Naming Conventions: Never start anything with a number, or an underscore (reserved for OS calls) Never use the world or prefix my this is a holdover from Perl and Pascal - Just don't.[1]

 

Only one more thing TAB vs WHITESPACE

you can do whichever you prefer BUT a tab is not a tab on every system is it 2, 4, 8 spaces. So the moral is if your code is only seen by your eyes than its up to you. But If your code will be seen on other eyes on other systems, then use white space in that way the next guy who sees your code does not have to reformat it.

 

Go Build something.

 

 

 

 

 

 

 

 

 

Revision History: (most are underlined)

  • Comment in Naming Conventions and the usage of my
  • Added info on JSF Coding Standard.
  • Added table with hated goto
  • in the last table fixed missing ) in if tests
  • I added a better expanation of both main() and the includes