Steve's blog

A blog about what's going on in Analysis UK...

Build Indicator – Part 2 (The firmware)

This is part 2 of the Build Indicator series. Part 1 – the construction of the hardware is here.

The firmware is written using the Arduino’s own programming language which is much like C/C++, using the IDE provided it’s easy to develop the code and push it down to the Arduino.

I decided that as the Arduino has 13 IO pins it would be a shame not to make these available for 6 build indicators so 6 individual projects could be monitored. I’ve not used OO to implement the code so it’s a little messy with individual arrays for project status, red and green led pins which are indexed based on the project number. I think you can create classes but this has to be done in external C++ files so for a simple application like this I didn’t worry to add that extra complexity.

Serial (RS232) communications is used to send a status message down to the Arduino build indicator to update the project status.

The full Arduino build indicator code can be download here.

License : Please use, copy and modify this code as you wish, all I ask is that you don’t take credit for the bits I wrote. You should ensure it’s fit for purpose before using it.

Variable declaration :


    1 /*


    2   Build Indicator (c) Analysis UK Ltd 2008


    3  *


    4   Digital Pin Assignments:


    5   0 - RX


    6   1 - TX


    7   2 - Project 6 - Green LED


    8   3 - Project 6 - Red LED


    9   4 - Project 5 - Green LED


   10   5 - Project 5 - Red LED


   11   6 - Project 4 - Green LED


   12   7 - Project 4 - Red LED


   13   8 - Project 3 - Green LED


   14   9 - Project 3 - Red LED


   15   10 - Project 2 - Green LED


   16   11 - Project 2 - Red LED


   17   12 - Project 1 - Green LED


   18   13 - Project 1 - Red LED


   19  */


   20 


   21 #define VERSION "1.0"


   22 


   23 // Project not enabled of not connected.


   24 int PROJECT_OFF = 0;


   25 


   26 // Project build failed


   27 int PROJECT_FAIL = 1; // 001


   28 


   29 // Project build good


   30 int PROJECT_GOOD = 2; // 010


   31 


   32 // project building from a failed project.


   33 int PROJECT_BUILDING_FAIL = 5; // 101


   34 


   35 // project building from a good build.


   36 int PROJECT_BUILDING_GOOD = 6; // 110


   37 


   38 // Maximum number of projects.


   39 int maxProjects = 6;


   40 


   41 // Project status codes.  Indexed by project.


   42 int projectStatus[] = {


   43   0, 0, 0, 0, 0, 0};


   44 


   45 // Pins for the Red LEDs.  Indexed by project. 


   46 int redLEDPin[] = {


   47   13, 11, 9, 7, 5, 3};


   48 


   49 // Pins for the Green LEDs.  Indexed by project.


   50 int greenLEDPin[] = {


   51   12, 10, 8, 6, 4, 2}; // pins 0 and 1 reserverd for RS232.





The arrays redLEDPin and greenLEDPin represent the pins to use for the red/green leds and are indexed on the project number (i.e. project 0's red led is on pin 13). The array projectStatus holds the status of the project and again is indexed by the project number.

Setup:


   54 // run once, when the sketch starts


   55 void setup()                   


   56 {


   57   // Initialise the ports for output to drive the LEDs


   58   for (int i=0; i<maxProjects; i++) {


   59     pinMode(greenLEDPin[i], OUTPUT);    // sets the digital pin as output for the green/blue part of the tri color LED


   60     pinMode(redLEDPin[i], OUTPUT);      // sets the digital pin as output for the red part of the tri color LED


   61   }


   62 


   63   // Setup Serial communications


   64   Serial.begin(57600);


   65 }




The setup method iterates through all the projects setting up the pins designated as led’s for output and then sets up serial communications at a baud rate or 57,600. Fortunately the Arduino takes care of the difficult serial comms bits for us.

Main Loop:


   67 // Main loop, runs over and over again


   68 void loop()                   


   69 { 


   70   // Check and Read settings from PC


   71   ReadCommands();


   72 


   73   // Update the LED's to indicate project status'


   74   UpdateLEDs();


   75 


   76   // Idle.      


   77   Idle();


   78 }


   79 




The loop method is the main application loop that the Arduino will enter once setup is complete and will keep repeating.

Within loop we call 3 basic methods, ReadCommands() which will check the serial port for commands from the host, UpdateLEDs() which will update the leds based on the project status and Idle() which just inserts a small delay but can be used for other background tasks.

The comms protocol is a fairly simple one. All messages should start with a byte value of 2 and terminate with a byte value of 3 so the Arduino can easily know when a instruction has been received.

To update a project status send the ascii string “@P[x]=y” with x being the project number 1-6 and y being the status (0, 1, 2, 5, 6).

To query the version number of the firmware send ?V.

I’ve stolen the comms protocol from another project I’m working on with the Arduino that has more commands and queries so I’ve based all commands where the Arduino has to do work on the @ character and all queries on the ? character to help separate out the commands and queries.

RS232 Message handling:


   86 // Read commands sent from the PC


   87 void ReadCommands()


   88 {


   89   // Check if serial data available, if so then read this in


   90 


   91   // Read all from the serial port until no more bytes available looking for the


   92   // start byte (1) of a message.


   93   while (Serial.available()) {


   94     //read the incoming byte:


   95     int incomingByte = Serial.read();


   96 


   97     // Start identifier.  STX


   98     if (incomingByte == 2) {


   99       // Found start byte now read in until we get the end of message byte.


  100       ReadSeialCommand();


  101       return;


  102     }


  103   } 


  104 }


  105 


  106 // Read a command from the serial port.  Read until the read byte


  107 // is an end of message (new line) indicator.


  108 void ReadSeialCommand() {


  109   // Expect maximum of 25 bytes (normally 6)


  110   byte buffer[25];


  111   int index=0;


  112 


  113   while (true) {


  114     if (Serial.available()) {


  115       // read the incoming byte:


  116       int incomingByte = Serial.read();


  117 


  118       // Terminating byte


  119       // Wait for ETX (End of text - transmision)


  120       if (incomingByte==3) {


  121         ProcessRequest(buffer);


  122         return;


  123       }


  124       else {


  125         buffer[index] = incomingByte;


  126         index++;


  127       }


  128 


  129       // Check for buffer overflow and give up if it has.


  130       if (index>25) {


  131         Serial.print("Error:Buffer Overflow.\n\r");


  132         return;


  133       }


  134     }


  135   }


  136 }


  137 


  138 void ProcessRequest(byte request[]) {


  139 


  140   boolean processed = false;


  141 


  142   // Check for Query commands (? at the start)


  143   if (request[0] == 63) {


  144     // Query


  145     processed = ProcessQuery(request);


  146   }


  147   else if (request[0] == 64) {


  148     // Set (@P[x]=0) - Set Project x = status.


  149     processed = ProcessSetValue(request);


  150   }


  151 


  152   if (!processed) {


  153     Serial.print ("Error:Unknown Request.\n\r");


  154   }


  155 }


  156 


  157 boolean ProcessQuery(byte request[]) {


  158 


  159   boolean processed = false;


  160 


  161   switch (request[1]) {


  162   case 86: // ?V - version


  163     processed = SendVersion();


  164   default:


  165     Serial.print ("Error:Unknown Query.\n\r");


  166   }   


  167   return processed;


  168 }


  169 


  170 boolean ProcessSetValue(byte request[]) {


  171 


  172   boolean processed = false;


  173   byte command = request[1];


  174   // Allow ascii version of the fan number.


  175   //Position 2 should be [


  176   byte project = request[3] - 48; // 48 = 0


  177   //position 4 should be ]


  178   //position 5 should be =


  179   //position 6 should be the raw value.


  180   byte value = request[6];


  181 


  182   switch (command) {


  183   case 80: //@P[x]=y Set project x status y.  y is ascii version of the status (0-9).  so subtract 48.


  184     processed = SetProjectStatus((int)project, (int)value - 48);


  185     break;


  186   default:


  187     Serial.print ("Error:Unknown set command.");


  188   }


  189 


  190   return processed;


  191 }


  192 


  193 boolean SendVersion() {


  194   Serial.print ("Version=");


  195   Serial.print (VERSION);


  196   Serial.print ("\n\r");


  197   return true;


  198 }


  199 


  200 // Set the status for the project.


  201 boolean SetProjectStatus(int project, int status) {


  202 


  203   if (projectStatus[project-1] != status) {


  204     projectStatus[project-1] = status;


  205 


  206     // Build failed.  Flash the red LED briefly to get attention.


  207     if (status == 1) {


  208       digitalWrite(greenLEDPin[project-1], LOW);


  209 


  210       for (int i=0; i<6; i++) {


  211         digitalWrite(redLEDPin[project-1], HIGH);


  212         delay(100);


  213         digitalWrite(redLEDPin[project-1], LOW);


  214         delay(100);


  215       }


  216     }


  217   }


  218 


  219   return true;


  220 }


  221 




The method ReadCommands() will read the input buffer until it receives the start byte then call ReadSerialCommand() which reads the rest of the command into a buffer until it received the end byte. I’ve limited the buffer to 25 bytes which should be plenty and if this overflows then we just abandon it. Their is no timeout between receiving the start and end bytes so this could cause a problem if the end byte is not received.

Notice in the method SetProjectStatus() that the project index used is -1 from the project value sent. When sending commands the first project is project 1 however the Arduino uses 0 based arrays.

In SetProjectStatus() if the project state changes to be failure (value 1) then the red led is flashed 6 times to draw attention to the indicator.

Project State Indication:


  222 boolean UpdateLEDs() {


  223 


  224   for (int i=0; i<maxProjects; i++) {


  225     int greenLEDStatus = LOW;


  226     int redLEDStatus = LOW;


  227 


  228     switch (projectStatus[i]) {


  229     case 0: // NC


  230       // No acton


  231       break;


  232     case 1: // Fail


  233       redLEDStatus = HIGH;


  234       break;


  235     case 2: // Good


  236       greenLEDStatus = HIGH;


  237       break;


  238     case 5: // Building from a Fail build


  239     case 6: // Building from a good build


  240       greenLEDStatus = HIGH;


  241       redLEDStatus = HIGH;


  242       break;


  243     default:


  244       redLEDStatus = HIGH;


  245       break;


  246     }


  247 


  248     // Determine project LED pins and set them appropriatly.


  249     digitalWrite(redLEDPin[i], redLEDStatus);


  250     digitalWrite(greenLEDPin[i], greenLEDStatus);


  251   }


  252 }




In the method UpdateLEDs() we update the led status based on the project status.

If you are wondering what happened to status codes 3 & 4 I’ve used a bit based project status. 0001 (1) is fail, 0010 (2) is good, 01xx is building so 0101 (5) is building from a previously failed state and 0110 (6) is building from a good previous good state.

If you want to use indicators other than leds for your project state then you can update the UpdateLEDs() method with another way to indicate the project status (maybe a LCD panel?).

That’s basically the firmware, not much to it, the Arduino does most of the work for us which is the best bit!

To program the Arduino connect it up, install the drivers (my Vista x64 and Vista x86 installs got the drivers from Windows Update without a problem and also installed the VCP virtual com port drivers). Open up the IDE, ensure the board and serial port are correct and load the build indicator firmware, then hit the upload to I/O board button.

In the next entry I’ll talk about the PC application to drive the Arduino.

Comments are closed