Psi Swarm robot library version 0.9

Fork of PsiSwarmV8_CPP by Psi Swarm Robot

Files at this revision

API Documentation at this revision

Comitter:
jah128
Date:
Thu Jun 01 21:58:14 2017 +0000
Parent:
14:2f1ad77d281e
Commit message:
Added colour detection code

Changed in this revision

colour.cpp Show annotated file Show diff for this revision Revisions of this file
colour.h Show annotated file Show diff for this revision Revisions of this file
demo.cpp Show annotated file Show diff for this revision Revisions of this file
demo.h Show annotated file Show diff for this revision Revisions of this file
display.cpp Show annotated file Show diff for this revision Revisions of this file
display.h Show annotated file Show diff for this revision Revisions of this file
psiswarm.cpp Show annotated file Show diff for this revision Revisions of this file
psiswarm.h Show annotated file Show diff for this revision Revisions of this file
settings.h Show annotated file Show diff for this revision Revisions of this file
diff -r 2f1ad77d281e -r 66be5ec52c3b colour.cpp
--- a/colour.cpp	Tue May 30 21:03:18 2017 +0000
+++ b/colour.cpp	Thu Jun 01 21:58:14 2017 +0000
@@ -1,11 +1,11 @@
 /* University of York Robotics Laboratory PsiSwarm Library: Colour Sensors Source File
- * 
+ *
  * Copyright 2017 University of York
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and limitations under the License.
  *
  * File: colour.cpp
@@ -24,24 +24,207 @@
 // Top colour sensor (if fitted) is a TCS34721
 #include "psiswarm.h"
 
+int CS_C_BLACK =  63;
+int CS_C_WHITE =  802;
+int CS_R_BLACK = 22;
+int CS_R_WHITE = 244;
+int CS_G_BLACK = 24;
+int CS_G_WHITE = 297;
+int CS_B_BLACK = 16;
+int CS_B_WHITE = 232;
+int last_detected_colour = -1;
 
-void Colour::read_base_colour_sensor_values(int * store_array){
-    
+void Colour::read_base_colour_sensor_values(int * store_array)
+{
+    char buffer[8] = { 0 };
+    IF_readMultipleRegisters( CDATA, buffer, 8 );
+    store_array[0] = (int)buffer[1] << 8 | (int)buffer[0];
+    store_array[1] = (int)buffer[3] << 8 | (int)buffer[2];
+    store_array[2] = (int)buffer[5] << 8 | (int)buffer[4];
+    store_array[3] = (int)buffer[7] << 8 | (int)buffer[6];
+}
+
+void Colour::set_base_colour_sensor_gain(char gain)
+{
+    char control;
+    int ack = 0;
+    switch (gain) {
+        case 1:
+            control = 0;
+            break;
+        case 4:
+            control = 1;
+            break;
+        case 16:
+            control = 2;
+            break;
+        case 60:
+            control = 3;
+            break;
+        default:
+            ack = 2; // 2 used to indicate invalid entry
+            break;
+    }
+    if ( ack != 2 ) {
+        ack = IF_writeSingleRegister( CONTROL, control );
+    }
 }
 
-void Colour::set_base_colour_sensor_gain(char gain){
-    
+void Colour::set_base_colour_sensor_integration_time(char int_time)
+{
+    char atime = 256 - IF_roundTowardsZero( int_time / 2.4 ); // rounding ensures nearest value of atime is used
+    int ack = IF_writeSingleRegister( ATIME, atime );
+}
+
+float Colour::IF_roundTowardsZero( const float value )
+{
+    float result = 0;
+    if ( ( value >= 0 && ( value - (int)value ) < 0.5 ) || ( value < 0 && ( abs(value) - (int)abs(value) ) >= 0.5 ) ) {
+        result = floor(value);
+    } else {
+        result = ceil(value);
+    }
+    return result;
+}
+
+void Colour::enable_base_colour_sensor(void)
+{
+    char enable_old = IF_readSingleRegister( ENABLE );
+    char enable_new = enable_old | 3; // sets PON (bit 0) and AEN (bit 1) to 1
+    int ack = IF_writeSingleRegister( ENABLE, enable_new );
+}
+
+
+void Colour::disable_base_colour_sensor(void)
+{
+    char enable_old = IF_readSingleRegister( ENABLE );
+    char enable_new = enable_old & 252; // sets PON (bit 0) and AEN (bit 1) to 0
+    int ack = IF_writeSingleRegister( ENABLE, enable_new );
+}
+
+Timeout colour_ticker;
+int colour_ticker_period;
+int colour_ticker_on = 0;
+
+void Colour::start_colour_ticker(int period_ms)
+{
+    colour_ticker_on = 1;
+    colour_ticker_period = period_ms;
+    colour_ticker.attach_us(this,&Colour::IF_colour_ticker_start, 100);
+}
+
+void Colour::IF_colour_ticker_start()
+{
+    led.set_base_led(1);
+    enable_base_colour_sensor();
+    colour_ticker.attach_us(this,&Colour::IF_colour_ticker_main, 25000);
 }
 
-void Colour::set_base_colour_sensor_integration_time(char int_time){
-    
+void Colour::IF_colour_ticker_main()
+{
+    int rgb_readings [4];
+    read_base_colour_sensor_values( rgb_readings );
+    disable_base_colour_sensor();
+    led.set_base_led(0);
+    if(rgb_readings[1] > 0 && rgb_readings[1] < 1024 && rgb_readings[2] > 0 && rgb_readings[2] < 1024 && rgb_readings[3] > 0 && rgb_readings[3] < 1024) {
+        float adjusted[4];
+        get_calibrated_colour(rgb_readings,adjusted);
+        last_detected_colour = identify_colour_from_calibrated_colour_scores(adjusted);
+    }
+    if(colour_ticker_on == 1)colour_ticker.attach_us(this,&Colour::IF_colour_ticker_start, colour_ticker_period * 1000);
+}
+
+
+
+int Colour::detect_colour_once()
+{
+    int rgb_readings [4];
+    led.set_base_led(1);
+    enable_base_colour_sensor();
+    wait(0.03);
+    read_base_colour_sensor_values( rgb_readings );
+    disable_base_colour_sensor();
+    led.set_base_led(0);
+    if(rgb_readings[1] < 1 || rgb_readings[1] > 1022 || rgb_readings[2] < 1 || rgb_readings[2] > 1022 || rgb_readings[3] < 1 || rgb_readings[3] > 1022) return -1;
+    float adjusted[4];
+    get_calibrated_colour(rgb_readings,adjusted);
+    last_detected_colour = identify_colour_from_calibrated_colour_scores(adjusted);
+    return last_detected_colour;
+}
+
+int Colour::get_detected_colour()
+{
+    return last_detected_colour;
 }
 
-void Colour::enable_base_colour_sensor(void){
-    
+const char * Colour::get_colour_string(int colour_index)
+{
+    switch(colour_index) {
+        case 0:
+            return "RED    ";
+        case 1:
+            return "YELLOW ";
+        case 2:
+            return "GREEN  ";
+        case 3:
+            return "CYAN   ";
+        case 4:
+            return "BLUE   ";
+        case 5:
+            return "MAGENTA";
+        case 6:
+            return "WHITE  ";
+        case 7:
+            return "BLACK  ";
+    }
+    return "-------";
 }
 
-char Colour::IF_check_base_colour_sensor(void){
+void Colour::get_calibrated_colour(int * colour_array_in, float * colour_array_out)
+{
+    int colour_temp = colour_array_in[0];
+    if(colour_temp < CS_C_BLACK) colour_temp = CS_C_BLACK;
+    if(colour_temp > CS_C_WHITE) colour_temp = CS_C_WHITE;
+    colour_array_out[0] = (colour_temp - CS_C_BLACK) / (float) (CS_C_WHITE - CS_C_BLACK);
+    float black_level = 1.0 - colour_array_out[0];
+    colour_array_out[1] = ((colour_array_in[1] / (float)CS_R_WHITE) * colour_array_out[0]) + ((colour_array_in[1] / (float)CS_R_BLACK) * black_level);
+    colour_array_out[2] = ((colour_array_in[2] / (float)CS_G_WHITE) * colour_array_out[0]) + ((colour_array_in[2] / (float)CS_G_BLACK) * black_level);
+    colour_array_out[3] = ((colour_array_in[3] / (float)CS_B_WHITE) * colour_array_out[0]) + ((colour_array_in[3] / (float)CS_B_BLACK) * black_level);
+    // Normalise array
+    float norm_factor = 3.0/(colour_array_out[1] + colour_array_out[2] + colour_array_out[3]);
+    colour_array_out[1] *= norm_factor;
+    colour_array_out[2] *= norm_factor;
+    colour_array_out[3] *= norm_factor;
+    // int sum_black = CS_R_BLACK + CS_G_BLACK + CS_
+    // colour_array_out[1] =
+}
+
+int Colour::identify_colour_from_calibrated_colour_scores(float * calibrate_colour_array_in)
+{
+    float scores[8];
+    scores[0] = ((calibrate_colour_array_in[1] * 2) * (calibrate_colour_array_in[1] * 2)) / ((calibrate_colour_array_in[2] + calibrate_colour_array_in[3]) * (calibrate_colour_array_in[2] + calibrate_colour_array_in[3]));
+    scores[1] = ((calibrate_colour_array_in[1] + calibrate_colour_array_in[2]) * (calibrate_colour_array_in[1] + calibrate_colour_array_in[2])) / (calibrate_colour_array_in[3] * calibrate_colour_array_in[3] * 4);
+    scores[2] = ((calibrate_colour_array_in[2] * 2) * (calibrate_colour_array_in[2] * 2)) / ((calibrate_colour_array_in[1] + calibrate_colour_array_in[3]) * (calibrate_colour_array_in[1] + calibrate_colour_array_in[3]));
+    scores[3] = ((calibrate_colour_array_in[2] + calibrate_colour_array_in[3]) * (calibrate_colour_array_in[2] + calibrate_colour_array_in[3])) / (calibrate_colour_array_in[1] * calibrate_colour_array_in[1] * 4);
+    scores[4] = ((calibrate_colour_array_in[3] * 2) * (calibrate_colour_array_in[3] * 2)) / ((calibrate_colour_array_in[2] + calibrate_colour_array_in[1]) * (calibrate_colour_array_in[2] + calibrate_colour_array_in[1]));
+    scores[5] = ((calibrate_colour_array_in[3] + calibrate_colour_array_in[1]) * (calibrate_colour_array_in[3] + calibrate_colour_array_in[1])) / (calibrate_colour_array_in[2] * calibrate_colour_array_in[2] * 4);
+    float grey_factor = 1.0 / (1 + ((((calibrate_colour_array_in[1] - 1) * 10) * ((calibrate_colour_array_in[1] - 1) * 10)) * (((calibrate_colour_array_in[2] - 1) * 10) * ((calibrate_colour_array_in[2] - 1) * 10)) * (((calibrate_colour_array_in[3] - 1) * 10) * ((calibrate_colour_array_in[3] - 1) * 10))));
+    scores[6] = calibrate_colour_array_in[0] * calibrate_colour_array_in[0] * grey_factor * 4;
+    scores[7] = (1-calibrate_colour_array_in[0]) * (1-calibrate_colour_array_in[0]) * grey_factor * 4;
+    //pc.printf("R:%1.2f Y:%1.2f G:%1.2f C:%1.2f B:%1.2f M:%1.2f W:%1.2f B:%1.2f G:%1.2f\n\n", scores[0],scores[1],scores[2],scores[3],scores[4],scores[5],scores[6],scores[7],grey_factor);
+    float max = 2;
+    int max_index = 8;
+    for(int i=0; i<8; i++) {
+        if(scores[i] > max) {
+            max=scores[i];
+            max_index=i;
+        }
+    }
+    return max_index;
+}
+
+char Colour::IF_check_base_colour_sensor(void)
+{
     //Reads the device ID flag of the colour sensor [0xB2]
     //This should equal 0x44 for both TCS34721 (top) and TCS34725 (base) sensors
     //Return a 1 if successful or a 0 otherwise
@@ -54,3 +237,38 @@
     else psi.debug("Invalid response from colour sensor:%X\n",data[0]);
     return return_value;
 }
+
+int Colour::IF_writeSingleRegister( char address, char data )
+{
+    char tx[2] = { address | 160, data }; //0d160 = 0b10100000
+    int ack = primary_i2c.write(BASE_COLOUR_ADDRESS, tx, 2, false);
+    return ack;
+}
+
+int Colour::IF_writeMultipleRegisters( char address, char* data, int quantity )
+{
+    char tx[ quantity + 1 ];
+    tx[0] = address | 160;
+    for ( int i = 1; i <= quantity; i++ ) {
+        tx[ i ] = data[ i - 1 ];
+    }
+    int ack = primary_i2c.write(BASE_COLOUR_ADDRESS, tx, quantity + 1, false);
+    return ack;
+}
+
+char Colour::IF_readSingleRegister( char address )
+{
+    char output = 255;
+    char command = address | 160; //0d160 = 0b10100000
+    primary_i2c.write( BASE_COLOUR_ADDRESS, &command, 1, true );
+    primary_i2c.read( BASE_COLOUR_ADDRESS, &output, 1 );
+    return output;
+}
+
+int Colour::IF_readMultipleRegisters( char address, char* output, int quantity )
+{
+    char command = address | 160; //0d160 = 0b10100000
+    primary_i2c.write(BASE_COLOUR_ADDRESS, &command, 1, true );
+    int ack = primary_i2c.read( BASE_COLOUR_ADDRESS, output, quantity );
+    return ack;
+}
diff -r 2f1ad77d281e -r 66be5ec52c3b colour.h
--- a/colour.h	Tue May 30 21:03:18 2017 +0000
+++ b/colour.h	Thu Jun 01 21:58:14 2017 +0000
@@ -24,6 +24,11 @@
 #ifndef COLOUR_H
 #define COLOUR_H
 
+#define ENABLE                  0x00
+#define ATIME                   0x01
+#define CONTROL                 0x0F
+#define CDATA                   0x14
+
 /**
  *  The Colour class contains the functions for reading the base-mounted and top-mounted I2C colour sensors (optional).
 */
@@ -46,12 +51,64 @@
     */
     void enable_base_colour_sensor(void);
 
+    /** Disable (power-down) the base colour sensor
+    */
+    void disable_base_colour_sensor(void);
+
     /** Read the values from the base colour sensor
     *
     * @param Pointer to 3 x int array for r-g-b values
     */
     void read_base_colour_sensor_values(int * store_array);
+    
+    /** Function enables colour sensor, takes a reading, returns a single int (range -1 to 8)
+    *
+    * @return Output of identify_colour_from_calibrated_colour_scores - int range -1 to 8
+    */
+    int detect_colour_once();
+    
+    /** Returns the most recent identified colour from detect_colour_once or detect_colour_ticker (range -1 to 8)
+    *
+    * @return Output of identify_colour_from_calibrated_colour_scores - int range -1 to 8
+    */  
+    int get_detected_colour();
+
+    /** Attempts to identify a colour from a given array of calibrated colour values
+    *
+    * @param calibrate_colour_array_in : Pointer to the calibrate colour array [output of get_calibrated_colour] 
+    * @return int defining detected colour: 0=RED 1=YELLOW 2=GREEN 3=CYAN 4=BLUE 5=MAGENTA 6=WHITE 7=BLACK 8=UNSURE
+    */
+    int identify_colour_from_calibrated_colour_scores(float * calibrate_colour_array_in);
+    
+    /** Translate an input array of raw CT,R,G,B values into calibrated, normalised values 
+    *
+    * @param colour_array_in : 4-element int input array [output of read_base_colour_sensor_values()]
+    * @param colour_array_out : Target 4-element float array of normalised values [0=CT, range 0-1  1=R 2=G 3=B, Sum R+G+B=3.0]
+    */
+    void get_calibrated_colour(int * colour_array_in, float * colour_array_out);
+    
+    /** Returns a string form of the output of identify_colour_from_calibrated_colour_scores()
+    *
+    * @param colour_index : Output of identify_colour_from_calibrated_colour_scores()
+    * @return 7-character String (eg 0="RED    ")
+    */
+    const char * get_colour_string(int colour_index); 
+
+    /** Starts a polling ticker that cyclically checks to see if a colour can be detected
+    *
+    * @param period_ms : The approximate cycle period in milliseconds
+    */
+    void start_colour_ticker(int period_ms);
+    
+    
+
+    void IF_colour_ticker_start();
+    void IF_colour_ticker_main();
     char IF_check_base_colour_sensor(void);
-
+    int IF_writeSingleRegister( char address, char data );
+    int IF_writeMultipleRegisters( char address, char* data, int quantity );
+    char IF_readSingleRegister( char address );
+    int IF_readMultipleRegisters( char address, char* output, int quantity );
+    float IF_roundTowardsZero( const float value );
 };
 #endif
\ No newline at end of file
diff -r 2f1ad77d281e -r 66be5ec52c3b demo.cpp
--- a/demo.cpp	Tue May 30 21:03:18 2017 +0000
+++ b/demo.cpp	Thu Jun 01 21:58:14 2017 +0000
@@ -1,11 +1,11 @@
 /* University of York Robotics Laboratory PsiSwarm Library: Demo Mode Source File
- * 
+ *
  * Copyright 2017 University of York
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and limitations under the License.
  *
  * File: demo.cpp
@@ -37,6 +37,7 @@
 #define LF_I_TERM 0
 #define LF_D_TERM 4
 
+char quick_test = 0;
 char top_menu = 0;
 char sub_menu = 0;
 char level = 0;
@@ -136,20 +137,24 @@
             case 1: //Up pressed
                 switch(level) {
                     case 0:
-                        if(top_menu != 8) {
+                        if(top_menu != 9 && top_menu!= 0) {
                             level++;
                             sub_menu = 0;
                         } else {
-                            demo_on = 0;
-                            user_code_running = user_code_restore_mode;
+                            if(top_menu == 0) {
+                                toggle_quick_test();
+                            } else {
+                                demo_on = 0;
+                                user_code_running = user_code_restore_mode;
+                            }
                         }
                         break;
                     case 1:
                         switch(top_menu) {
-                            case 7: // PsiBasic Menu
+                            case 8: // PsiBasic Menu
                                 if(sub_menu == psi_basic_file_count) level = 0;
                                 break;
-                            case 0: //LED Menu
+                            case 7: //LED Menu
                                 if(sub_menu < 9) {
                                     if(led_state[sub_menu] == 0) led_state[sub_menu] = 3;
                                     else led_state[sub_menu]--;
@@ -196,7 +201,7 @@
                                 }
                                 if(sub_menu == 13) level = 0;
                                 break;
-                            case 1: // Sensors Menu
+                            case 2: // Sensors Menu
                                 if(sub_menu == 4 || sub_menu == 5) {
                                     if(base_ir_index == 0) base_ir_index = 4;
                                     else base_ir_index --;
@@ -207,7 +212,7 @@
                                 }
                                 if(sub_menu == 11) level = 0;
                                 break;
-                            case 2: // Motor Menu
+                            case 3: // Motor Menu
                                 if(sub_menu == 0) {
                                     left_speed += 5;
                                     if(left_speed > 100) left_speed = 100;
@@ -246,13 +251,13 @@
                                     level = 0;
                                 }
                                 break;
-                            case 3: // Radio Menu
+                            case 4: // Radio Menu
                                 if(sub_menu == 0) level = 0;
                                 break;
-                            case 4: // Info Menu
+                            case 5: // Info Menu
                                 if(sub_menu == 6) level = 0;
                                 break;
-                            case 5: // Demo Menu
+                            case 6: // Demo Menu
                                 if(sub_menu == 0) {
                                     if(demo_running == 0) {
                                         start_line_demo();
@@ -298,20 +303,24 @@
             case 2: //Down pressed
                 switch(level) {
                     case 0:
-                        if(top_menu != 8) {
+                        if(top_menu != 9 && top_menu != 0) {
                             level++;
                             sub_menu = 0;
                         } else {
-                            demo_on = 0;
-                            user_code_running = user_code_restore_mode;
+                            if(top_menu == 0) {
+                                toggle_quick_test();
+                            } else {
+                                demo_on = 0;
+                                user_code_running = user_code_restore_mode;
+                            }
                         }
                         break;
                     case 1:
                         switch(top_menu) {
-                            case 7: // PsiBasic Menu
+                            case 8: // PsiBasic Menu
                                 if(sub_menu == psi_basic_file_count) level = 0;
                                 break;
-                            case 0: //LED Menu
+                            case 1: //LED Menu
                                 if(sub_menu < 9) {
                                     led_state[sub_menu]++;
                                     if(led_state[sub_menu] == 4) led_state[sub_menu] = 0;
@@ -360,7 +369,7 @@
                                 if(sub_menu == 13) level = 0;
 
                                 break;
-                            case 1: // Sensors Menu
+                            case 2: // Sensors Menu
                                 if(sub_menu == 4 || sub_menu == 5) {
                                     if(base_ir_index == 4) base_ir_index = 0;
                                     else base_ir_index ++;
@@ -371,7 +380,7 @@
                                 }
                                 if(sub_menu == 11) level = 0;
                                 break;
-                            case 2: // Motor Menu
+                            case 3: // Motor Menu
                                 if(sub_menu == 0) {
                                     left_speed -= 5;
                                     if(left_speed < -100) left_speed = -100;
@@ -410,13 +419,13 @@
                                     level = 0;
                                 }
                                 break;
-                            case 3: // Radio Menu
+                            case 4: // Radio Menu
                                 if(sub_menu == 0) level = 0;
                                 break;
-                            case 4: // Info Menu
+                            case 5: // Info Menu
                                 if(sub_menu == 6) level = 0;
                                 break;
-                            case 5: // Demo Menu
+                            case 6: // Demo Menu
                                 if(sub_menu == 0) {
                                     if(demo_running == 0) {
                                         start_line_demo();
@@ -464,41 +473,40 @@
                 switch(level) {
                     case 0:
                         if(top_menu == 0) {
-                            top_menu = 8;
-                        }
-                        else {
-                            if(use_flash_basic == 0 && top_menu == 7) top_menu = 6;
+                            top_menu = 9;
+                        } else {
+                            if(use_flash_basic == 0 && top_menu == 8) top_menu = 7;
                             top_menu --;
                         }
                         break;
                     case 1:
                         switch(top_menu) {
-                            case 0: //LED Menu
+                            case 1: //LED Menu
                                 if(sub_menu == 0) sub_menu = 13;
                                 else sub_menu --;
                                 break;
-                            case 1: //Sensors Menu
+                            case 2: //Sensors Menu
                                 if(sub_menu == 0) sub_menu = 11;
                                 else sub_menu --;
                                 break;
 
-                            case 2: //Motor Menu
+                            case 3: //Motor Menu
                                 if(sub_menu == 0) sub_menu = 3;
                                 else sub_menu --;
                                 break;
-                            case 4: //Info Menu
+                            case 5: //Info Menu
                                 if(sub_menu == 0) sub_menu = 6;
                                 else sub_menu --;
                                 break;
-                            case 5: //Demo Menu
+                            case 6: //Demo Menu
                                 if(sub_menu == 0) sub_menu = 4;
                                 else sub_menu --;
                                 break;
-                            case 6: //Calibrate Menu
+                            case 7: //Calibrate Menu
                                 if(sub_menu == 0) sub_menu = 2;
                                 else sub_menu --;
                                 break;
-                            case 7: //PsiBasic Menu
+                            case 8: //PsiBasic Menu
                                 if(sub_menu == 0) sub_menu = psi_basic_file_count;
                                 else sub_menu --;
                         }
@@ -514,108 +522,37 @@
                         break;
                     case 1:
                         switch(top_menu) {
-                            case 0: //LED Menu
+                            case 1: //LED Menu
                                 if(sub_menu == 13) sub_menu = 0;
                                 else sub_menu ++;
                                 break;
-                            case 1: //Sensors Menu
+                            case 2: //Sensors Menu
                                 if(sub_menu == 11) sub_menu = 0;
                                 else sub_menu ++;
                                 break;
-                            case 2: //Motor Menu
+                            case 3: //Motor Menu
                                 if(sub_menu == 3) sub_menu = 0;
                                 else sub_menu ++;
                                 break;
-                            case 4: //Info Menu
+                            case 5: //Info Menu
                                 if(sub_menu == 6) sub_menu = 0;
                                 else sub_menu ++;
                                 break;
-                            case 5: //Demo Menu
+                            case 6: //Demo Menu
                                 if(sub_menu == 4) sub_menu = 0;
                                 else sub_menu ++;
                                 break;
-                            case 6: //Calibrate Menu
+                            case 7: //Calibrate Menu
                                 if(sub_menu == 2) sub_menu = 0;
                                 else sub_menu ++;
                                 break;
-                            case 7: //PsiBasic Menu
+                            case 8: //PsiBasic Menu
                                 if(sub_menu == psi_basic_file_count) sub_menu = 0;
                                 else sub_menu ++;
                         }
                         break;
                 }
                 break;
-            case 16: //Select pressed
-                switch(level) {
-                    case 0:
-                        if(top_menu != 8) {
-                            level++;
-                            sub_menu = 0;
-                        } else {
-                            demo_on = 0;
-                            user_code_running = user_code_restore_mode;
-                        }
-                        break;
-                    case 1:
-                        switch(top_menu) {
-                            case 0: //LED Menu
-                                if(sub_menu == 9) {
-                                    for(int i=0; i<9; i++) {
-                                        led_state[i]=all_led_state;
-                                    }
-                                    demo_update_leds();
-                                }
-                                if(sub_menu == 13) level = 0;
-                                break;
-                            case 1: // Sensors Menu
-                                if(sub_menu == 11) level = 0;
-                                break;
-                            case 2: //Motor Menu
-                                if(sub_menu == 2) {
-                                    switch(both_motor_mode) {
-                                        case 0:
-                                            motors.stop();
-                                            break;
-                                        case 1:
-                                            motors.brake();
-                                            break;
-                                        case 2:
-                                            motors.forward(0.5);
-                                            break;
-                                        case 3:
-                                            motors.forward(1);
-                                            break;
-                                        case 4:
-                                            motors.backward(0.5);
-                                            break;
-                                        case 5:
-                                            motors.backward(1.0);
-                                            break;
-                                    }
-                                }
-                                if(sub_menu == 3) {
-                                    level = 0;
-                                }
-                                break;
-                            case 3: // Radio Menu
-                                if(sub_menu == 0) level = 0;
-                                break;
-                            case 4: // Info Menu
-                                if(sub_menu == 6) level = 0;
-                                break;
-                            case 5: // Demo Menu
-                                if(sub_menu == 4) level = 0;
-                                break;
-                            case 6: // Calibrate Menu
-                                if(sub_menu == 2) level = 0;
-                                break;
-                            case 7: // PsiBasic Menu
-                                if(sub_menu == psi_basic_file_count) level = 0;
-                                break;
-                        }
-                        break;
-                }
-                break;
         }
     } else started = 1;
     display.clear_display();
@@ -624,30 +561,33 @@
             //Top level menu
             switch(top_menu) {
                 case 0:
+                    strcpy(topline,"---QUICK TEST---");
+                    break;
+                case 1:
                     strcpy(topline,"---TEST LEDS----");
                     break;
-                case 1:
+                case 2:
                     strcpy(topline,"--TEST SENSORS--");
                     break;
-                case 2:
+                case 3:
                     strcpy(topline,"--TEST MOTORS---");
                     break;
-                case 3:
-                    strcpy(topline,"---TEST RADIO---");
-                    break;
                 case 4:
-                    strcpy(topline,"------INFO------");
+                    strcpy(topline,"---TEST RADIO---");
                     break;
                 case 5:
-                    strcpy(topline,"---CODE DEMOS---");
+                    strcpy(topline,"------INFO------");
                     break;
                 case 6:
-                    strcpy(topline,"-MOTOR CALIBRATE");
+                    strcpy(topline,"---CODE DEMOS---");
                     break;
                 case 7:
+                    strcpy(topline,"-MOTOR CALIBRATE");
+                    break;
+                case 8:
                     strcpy(topline,"---PSI BASIC----");
                     break;
-                case 8:
+                case 9:
                     strcpy(topline,"------EXIT------");
                     break;
             }
@@ -656,12 +596,12 @@
         case 1:
             //Sub level menu
             switch(top_menu) {
-                case 7:
+                case 8:
                     strcpy(topline,"-PSI BASIC MENU-");
                     if(sub_menu == psi_basic_file_count) strcpy(bottomline,"EXIT");
                     else strcpy(bottomline,basic_filenames.at(sub_menu).c_str());
                     break;
-                case 0:
+                case 1:
                     strcpy(topline,"----LED MENU----");
                     char led_status[7];
                     if(sub_menu<9) {
@@ -709,7 +649,7 @@
                     if(sub_menu == 13) strcpy(bottomline,"EXIT");
                     break;
 
-                case 1:
+                case 2:
                     strcpy(topline,"--SENSORS MENU--");
                     switch(sub_menu) {
                         case 0: {
@@ -767,7 +707,7 @@
                             break;
                     }
                     break;
-                case 2:
+                case 3:
                     strcpy(topline,"--MOTORS MENU---");
                     switch(sub_menu) {
                         case 0:
@@ -805,7 +745,7 @@
                             break;
                     }
                     break;
-                case 3:
+                case 4:
                     strcpy(topline,"---RADIO MENU---");
                     switch(sub_menu) {
 
@@ -814,7 +754,7 @@
                             break;
                     }
                     break;
-                case 4:
+                case 5:
                     strcpy(topline,"---INFO MENU----");
                     switch(sub_menu) {
                         case 0:
@@ -841,7 +781,7 @@
                             break;
                     }
                     break;
-                case 5:
+                case 6:
                     strcpy(topline,"---CODE DEMOS---");
                     switch(sub_menu) {
                         case 0:
@@ -861,7 +801,7 @@
                             break;
                     }
                     break;
-                case 6:
+                case 7:
                     strcpy(topline,"-MOTOR CALIBRATE");
                     switch(sub_menu) {
                         case 0:
@@ -869,7 +809,7 @@
                             break;
                         case 1:
                             sprintf(bottomline,"ENTER VALUE");
-                            break;   
+                            break;
                         case 2:
                             sprintf(bottomline,"EXIT");
                             break;
@@ -886,6 +826,174 @@
     }
 }
 
+char test_step = 0;
+char test_substep = 0;
+char test_warnings = 0;
+
+
+void Demo::quick_test_cycle()
+{
+    char next_step [] = {4,5,8,3};
+    char test_message [17];
+    int wait_period = SELF_TEST_PERIOD * 10;
+  
+    if(test_substep == 0) {
+        display.clear_display();
+        switch(test_step) {
+            case 0:
+                display.write_string("01 - Power      ");
+                pc.printf("\nTest 01: Power quick tests [%f]\n",psi.get_uptime());
+                break;
+            case 1:
+                display.write_string("02 - Base IR    ");
+                pc.printf("\nTest 02: Base infrared tests [%f]\n",psi.get_uptime());
+                break;
+            case 2:
+                display.write_string("03 - Side IR    ");
+                pc.printf("\nTest 03: Side infrared tests [%f]\n",psi.get_uptime());
+                break;
+            case 3:
+                display.write_string("04 - LEDs       ");
+                pc.printf("\nTest 04: LED quick tests [%f]\n",psi.get_uptime());
+                break;
+        }
+    }
+    if(test_step == 0) {
+        // Power self-test
+        switch(test_substep) {
+            case 0: { // Battery Voltage
+                float battery_voltages [SAMPLE_SIZE];
+                float mean_battery_voltage = 0;
+                float sd_battery_voltage = 0;
+                for(int i=0; i<SAMPLE_SIZE; i++) {
+                    battery_voltages[i]=sensors.get_battery_voltage ();
+                    mean_battery_voltage += battery_voltages[i];
+                    wait_us(SELF_TEST_PERIOD);
+                }
+                mean_battery_voltage /= SAMPLE_SIZE;
+                for(int i=0; i<SAMPLE_SIZE; ++i) sd_battery_voltage += pow(battery_voltages[i] - mean_battery_voltage, 2);
+                sd_battery_voltage = sqrt(sd_battery_voltage/SAMPLE_SIZE);
+
+                sprintf(test_message,"BATTERY: %1.3fV",mean_battery_voltage);
+                pc.printf(" - Battery Voltage    : %1.4fV [SD = % 1.4f]\n",mean_battery_voltage,sd_battery_voltage);
+                if(mean_battery_voltage < 3.6) {
+                    pc.printf(" - WARNING            : Battery voltage low\n");
+                    test_warnings++;
+                }
+                break;
+            }
+            case 1: {// DC Voltage
+                float dc_voltages [SAMPLE_SIZE];
+                float mean_dc_voltage = 0;
+                float sd_dc_voltage = 0;
+                for(int i=0; i<SAMPLE_SIZE; i++) {
+                    dc_voltages[i]=sensors.get_dc_voltage ();
+                    mean_dc_voltage += dc_voltages[i];
+                    wait_us(SELF_TEST_PERIOD);
+                }
+                mean_dc_voltage /= SAMPLE_SIZE;
+                for(int i=0; i<SAMPLE_SIZE; ++i) sd_dc_voltage += pow(dc_voltages[i] - mean_dc_voltage, 2);
+                sd_dc_voltage = sqrt(sd_dc_voltage/SAMPLE_SIZE);
+
+                sprintf(test_message,"DC     : %1.3fV",mean_dc_voltage);
+                pc.printf(" - DC Input Voltage   : %1.4fV [SD = % 1.4f]\n",mean_dc_voltage,sd_dc_voltage);
+                if(mean_dc_voltage < 0.5) {
+                    pc.printf(" - WARNING            : DC voltage low - check charging resistor\n");
+                    test_warnings++;
+                }
+                break;
+            }
+
+
+            case 2: { // Current
+                float currents [SAMPLE_SIZE];
+                float mean_current = 0;
+                float sd_current = 0;
+                for(int i=0; i<SAMPLE_SIZE; i++) {
+                    currents[i]=sensors.get_current ();
+                    mean_current += currents[i];
+                    wait_us(SELF_TEST_PERIOD);
+                }
+                mean_current /= SAMPLE_SIZE;
+                for(int i=0; i<SAMPLE_SIZE; ++i) sd_current += pow(currents[i] - mean_current, 2);
+                sd_current = sqrt(sd_current/SAMPLE_SIZE);
+
+                sprintf(test_message,"CURRENT: %1.3fV",mean_current);
+                pc.printf(" - Load Current       : %1.4fA [SD = % 1.4f]\n",mean_current,sd_current);      
+                if(mean_current > 0.2) {
+                    pc.printf(" - WARNING            : Higher than expected load current\n");
+                    test_warnings++;
+                }
+                break;
+            }
+            
+            case 3: {// System temperature
+                float temps[SAMPLE_SIZE];
+                float mean_temp = 0;
+                float sd_temp = 0;
+                for(int i=0; i<SAMPLE_SIZE; i++) {
+                    temps[i]=sensors.get_temperature();
+                    mean_temp += temps[i];
+                    wait_us(SELF_TEST_PERIOD);
+                }
+                mean_temp /= SAMPLE_SIZE;
+                for(int i=0; i<SAMPLE_SIZE; ++i) sd_temp += pow(temps[i] - mean_temp, 2);
+                sd_temp = sqrt(sd_temp/SAMPLE_SIZE);
+
+                sprintf(test_message,"TEMP   : %3.2fC",mean_temp);
+                pc.printf(" - System Temperature : %3.2fC [SD = % 1.4f]\n",mean_temp,sd_temp);   
+                if(mean_temp > 32) {
+                    pc.printf(" - WARNING            : High system temperature detected\n");
+                    test_warnings++;
+                }
+                if(mean_temp < 10) {
+                    pc.printf(" - WARNING            : Low system temperature detected\n");
+                    test_warnings++;
+                }
+                break;
+            }
+        }
+    }
+
+    display.set_position(1,0);
+    display.write_string("                ");
+    display.set_position(1,0);
+    display.write_string(test_message);
+    test_substep++;
+    if(test_substep >= next_step[test_step]) {
+        test_substep = 0;
+        test_step ++;
+        if(test_step == 4) test_step = 0;
+    }
+
+    demo_timeout.attach_us(this,&Demo::quick_test_cycle, wait_period);
+}
+
+void Demo::toggle_quick_test()
+{
+    quick_test = 1 - quick_test;
+    if(quick_test == 0) {
+        pc.printf("________________________________________\n");
+        pc.printf("Self test stopped at %f with %d warnings\n\n",psi.get_uptime(),test_warnings);
+        demo_running = 0;
+        demo_timeout.detach();
+        display.set_backlight_brightness(1);
+        display.clear_display();
+        display.write_string("---QUICK TEST---");
+
+
+    } else {
+        // Reset all LEDs, motors, display
+        pc.printf("\n________________________________________\n");
+        pc.printf("Self test started at %f\n\n",psi.get_uptime(),test_warnings);
+        display.clear_display();
+        test_step = 0;
+        test_substep = 0;
+        demo_running = 1;
+        demo_timeout.attach_us(this,&Demo::quick_test_cycle,1000);
+    }
+}
+
 void Demo::start_line_demo()
 {
     display.set_backlight_brightness(0);
@@ -976,35 +1084,35 @@
                 lf_left = 0;
             else if (lf_left > 1.0f)
                 lf_left = 1.0f;
-        }else{
-          //Cannot see line: hunt for it
-          if(lf_left > lf_right){
-            //Currently turning left, keep turning left   
-            state ++;
-            float d_step = state * 0.04;
-            lf_left = 0.2 + d_step;
-            lf_right = -0.2 - d_step;
-            if(state > 20){
-                state = 0;
-                lf_right = 0.2;
-                lf_left = -0.2;
-                time_out += 0.01f;
-                if(time_out > 0.1f) demo_running = 0;
+        } else {
+            //Cannot see line: hunt for it
+            if(lf_left > lf_right) {
+                //Currently turning left, keep turning left
+                state ++;
+                float d_step = state * 0.04;
+                lf_left = 0.2 + d_step;
+                lf_right = -0.2 - d_step;
+                if(state > 20) {
+                    state = 0;
+                    lf_right = 0.2;
+                    lf_left = -0.2;
+                    time_out += 0.01f;
+                    if(time_out > 0.1f) demo_running = 0;
+                }
+            } else {
+                //Currently turning right, keep turning right
+                state ++;
+                float d_step = state * 0.04;
+                lf_left = -0.2 - d_step;
+                lf_right = 0.2 + d_step;
+                if(state > 20) {
+                    state = 0;
+                    lf_right = -0.2;
+                    lf_left = 0.2;
+                    time_out += 0.01f;
+                    if(time_out > 0.1f) demo_running = 0;
+                }
             }
-          }else{
-            //Currently turning right, keep turning right   
-            state ++;
-            float d_step = state * 0.04;
-            lf_left = -0.2 - d_step;
-            lf_right = 0.2 + d_step;
-            if(state > 20){
-                state = 0;
-                lf_right = -0.2;
-                lf_left = 0.2;
-                time_out += 0.01f;
-                if(time_out > 0.1f) demo_running = 0;
-            } 
-          }
         }
         // set speed
         motors.set_left_motor_speed(lf_left);
diff -r 2f1ad77d281e -r 66be5ec52c3b demo.h
--- a/demo.h	Tue May 30 21:03:18 2017 +0000
+++ b/demo.h	Thu Jun 01 21:58:14 2017 +0000
@@ -53,5 +53,7 @@
     void obstacle_demo_cycle(void);
     void spinning_demo_cycle(void);
     void stress_demo_cycle(void);
+    void quick_test_cycle(void);
+    void toggle_quick_test(void);
 };
 #endif
\ No newline at end of file
diff -r 2f1ad77d281e -r 66be5ec52c3b display.cpp
--- a/display.cpp	Tue May 30 21:03:18 2017 +0000
+++ b/display.cpp	Thu Jun 01 21:58:14 2017 +0000
@@ -64,9 +64,7 @@
    wait(0.01);
    return c;
 }
-
-void Display::init_display(char mode){
-   //Set initial states: display on, cursor off
+void Display::init_display_start(){
    display_on = 1;
    set_backlight_brightness(1);
    cursor_on = 0;
@@ -95,14 +93,16 @@
    write_string(psis,16);
    set_position(1,0);
    write_string(psis,16);
-   wait(0.25);
+}
+
+void Display::init_display_end(char mode){
    clear_display();
     if(mode == 0) {
         set_position(0,0);
         write_string("  YORK ROBOTICS");
         set_position(1,0);
         write_string("   LABORATORY");
-   init_timeout.attach(this,&Display::post_init,0.3);}
+   init_timeout.attach(this,&Display::post_init,0.25);}
    else {      
    set_position(0,0);
    write_string("Hold button to");
@@ -111,6 +111,30 @@
     }
 } 
 
+void Display::show_switch_state(char switch_state){
+    switch(switch_state){
+        /// Switch_state = 1 if up is pressed, 2 if down is pressed, 4 if left is pressed, 8 if right is pressed and 16 if the center button is pressed
+        case 0: write_string("REL   "); break;
+        case 1: write_string("UP    "); break;
+        case 2: write_string("DOWN  "); break;
+        case 4: write_string("LEFT  "); break;
+        case 5: write_string("UP-L  "); break;
+        case 6: write_string("DN-L  "); break;
+        case 8: write_string("RIGHT "); break;
+        case 9: write_string("UP-R  "); break;
+        case 10: write_string("DN-R  "); break;
+        case 16: write_string("PRESS"); break;
+        case 17: write_string("UP   *"); break;
+        case 18: write_string("DOWN *"); break;
+        case 20: write_string("LEFT *"); break;
+        case 21: write_string("UP-L *"); break;
+        case 22: write_string("DN-L *"); break;
+        case 24: write_string("RIGHT*"); break;
+        case 25: write_string("UP-R *"); break;
+        case 26: write_string("DN-R *"); break;
+    }    
+}
+
 void Display::post_init(){
     clear_display();
     home();
@@ -120,7 +144,7 @@
     sprintf(line,"VERSION %1.2f", SOFTWARE_VERSION_CODE  );
     set_position(1,0);
     write_string(line);
-    init_timeout.attach(this,&Display::post_post_init,0.3);
+    init_timeout.attach(this,&Display::post_post_init,0.25);
 }
 
 void Display::post_post_init(){
diff -r 2f1ad77d281e -r 66be5ec52c3b display.h
--- a/display.h	Tue May 30 21:03:18 2017 +0000
+++ b/display.h	Thu Jun 01 21:58:14 2017 +0000
@@ -116,6 +116,11 @@
     */
     void set_backlight_brightness(float brightness);
 
+    /** Display the switch state at the current cursor position
+    * @param switch_state - The value of the cursor switch (range 0 to 31)
+    */
+    void show_switch_state(char switch_state);
+    
     // Special function for when debug messages are sent to display
     void debug_page(char * message, char length);
 
@@ -135,8 +140,11 @@
     // Send a 1-byte control message to the display
     int i2c_message(char byte);
 
-    // Default initialisation sequence for the display
-    void init_display(char mode);
+    // Default initialisation sequence for the display (start of boot)
+    void init_display_start();
+
+    // Default initialisation sequence for the display (end of boot)
+    void init_display_end(char mode);
 
     int disp_putc(int c);
 
diff -r 2f1ad77d281e -r 66be5ec52c3b psiswarm.cpp
--- a/psiswarm.cpp	Tue May 30 21:03:18 2017 +0000
+++ b/psiswarm.cpp	Thu Jun 01 21:58:14 2017 +0000
@@ -1,6 +1,6 @@
 /* University of York Robotics Laboratory PsiSwarm Library: PsiSwarm C++ Core Source File
  * 
- * Copyright 2016 University of York
+ * Copyright 2017 University of York
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
@@ -13,9 +13,9 @@
  * (C) Dept. Electronics & Computer Science, University of York
  * James Hilder, Alan Millard, Alexander Horsfield, Homero Elizondo, Jon Timmis
  *
- * PsiSwarm Library Version: 0.8
+ * PsiSwarm Library Version: 0.9
  *
- * October 2016
+ * May 2017
  *
  *
  */
@@ -175,6 +175,8 @@
     primary_i2c.frequency(400000);
     serial.setup_serial_interfaces();
     debug("PsiSwarm Robot Library %1.2f\n\n",SOFTWARE_VERSION_CODE);
+    debug("- Set up display\n");
+    display.init_display_start();
     debug("- Setting up serial interface\n");
     debug("- Reading firmware: ");
     if(eprom.read_firmware() == 1) {
@@ -183,13 +185,13 @@
         if(use_motor_calibration){
             if(!motor_calibration_set){
                 if(firmware_version < 1.1){
-                    debug("- WARNING: This firmware is incompatible with motor calibration");
-                    debug("- WARNING: Please update the firmware to use this feature.");
+                    debug("- WARNING: This firmware is incompatible with motor calibration\n");
+                    debug("- WARNING: Please update the firmware to use this feature.\n");
                     use_motor_calibration = 0;   
                 }   
                 else {
-                    debug("- WARNING: Motor calibration values have not been stored in firmware");
-                    debug("- WARNING: Run calibration routine to use this feature.");
+                    debug("- WARNING: Motor calibration values have not been stored in firmware\n");
+                    debug("- WARNING: Run calibration routine to use this feature.\n");
                     use_motor_calibration = 0;   
                 }
             }
@@ -244,15 +246,16 @@
     }
     char demo_on = 0;
     if(ENABLE_DEMO == 1 && switchstate > 0) demo_on=1;
-    display.init_display(demo_on);
+    display.init_display_end(demo_on);
     event_handler.attach_us(this,&Psiswarm::IF_handle_events, 1000);
     if(demo_on > 0) {
         debug("- Demo mode button is pressed\n");
-        wait(1.0);
+        wait(0.6);
         demo_on = i2c_setup.IF_get_switch_state();
         if(demo_on > 0) demo.start_demo_mode();
-        display.init_display(0);
+        display.init_display_end(0);
     }
+    debug("___________________________________________________");
 }
 
 void Psiswarm::IF_update_minutes()
diff -r 2f1ad77d281e -r 66be5ec52c3b psiswarm.h
--- a/psiswarm.h	Tue May 30 21:03:18 2017 +0000
+++ b/psiswarm.h	Thu Jun 01 21:58:14 2017 +0000
@@ -1,6 +1,6 @@
 /* University of York Robotics Laboratory PsiSwarm Library: PsiSwarm C++ Core Header File
  *
- * Copyright 2016 University of York
+ * Copyright 2017 University of York
  *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
@@ -13,9 +13,9 @@
  * (C) Dept. Electronics & Computer Science, University of York
  * James Hilder, Alan Millard, Alexander Horsfield, Homero Elizondo, Jon Timmis
  *
- * PsiSwarm Library Version: 0.8
+ * PsiSwarm Library Version: 0.9
  *
- * October 2016
+ * May 2017
  *
  *
  */
@@ -23,7 +23,7 @@
 #ifndef PSISWARM_H
 #define PSISWARM_H
 
-#define SOFTWARE_VERSION_CODE 0.80
+#define SOFTWARE_VERSION_CODE 0.90
 
 #define PIC_ADDRESS 0x30
 #define LCD_ADDRESS 0x7C
@@ -85,7 +85,7 @@
  * Psiswarm psi;
  * char * program_name = "Example";
  * char * author_name  = "Name";
- * char * version_name = "0.8";
+ * char * version_name = "0.9";
  * void handle_switch_event(char switch_state){}
  * void handle_user_serial_message(char * message, char length, char interface) {}
  * int main(){
@@ -154,6 +154,7 @@
 extern Demo demo;
 extern Animations animations;
 extern Basic basic;
+extern Colour colour;
 extern char * program_name;
 extern char * author_name;
 extern char * version_name;
diff -r 2f1ad77d281e -r 66be5ec52c3b settings.h
--- a/settings.h	Tue May 30 21:03:18 2017 +0000
+++ b/settings.h	Thu Jun 01 21:58:14 2017 +0000
@@ -96,5 +96,10 @@
 /* DEBUG_OUTPUT_STREAM [1=PC\USB 2=BlueSmirf 4=Display]:  Specify which output stream(s) should be used by default for debug messages, if enabled*/
 #define DEBUG_OUTPUT_STREAM 1
 
+/* SELF_TEST_PERIOD [recommended = 10000]:  Step time (in uS) for the quick self-test in the demo mode*/
+#define SELF_TEST_PERIOD 10000
+
+/* SAMPLE_SIZE [recommended = 10]:  Number of samples to take for the quick self-test in the demo mode*/
+#define SAMPLE_SIZE 10
 #endif