Index: bom.c
===================================================================
--- bom.c	(revision 1460)
+++ bom.c	(revision 1461)
@@ -3,242 +3,273 @@
  * 
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- * 
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- **/
-
-
-/**
- * @file bom.c
- * @brief Implementation for using the BOM
- *
- * Contains functions for using the Bearing and Orientation Module (BOM)
- *
- * @author Colony Project, CMU Robotics Club
- **/
-
-#include "bom.h"
-#include "dio.h"
-#include "serial.h"
-#include "analog.h"
-
-//On the original BOM1.0, the emmitter angular order does not match the analog mux order
-//so you need to iterate through the mux index in the following order if you want to get
-//the detector readings in order:
-static const char lookup[16] = {7,6,5,0xe,1,4,3,2,0xf,0,0xd,8,0xc,0xb,9,0xa};
-
-// internal function prototypes
-static void bom_select(char which);
-
-/*
- Bk R Y (Analog)
----------
- Green
- Blue
- White
----------
- Blue
- White
-*/
-
-
-/*
-the analog pin definitions from dio.h DO NOT work here,
-so we must use PF0 from avrgcc (as opposed to _PIN_F0).
-BUT the dio pin definitions from dio.h must be used (no PE...).
-
-also, _PIN_E2 is initialized to high for some reason,
-which turns the BOM on when the robot is turned on.
-WORK-AROUND: call digital_output(_PIN_E2,0) at some point.
-
-*/
-
-#define MONKI PF0         //analog (yellow)
-//------------------------//
-#define MONKL _PIN_E2     //green
-#define MONK1 _PIN_E3     //blue
-#define MONK0 _PIN_E4     //white
-//------------------------//
-#define MONK3 _PIN_E6     //blue
-#define MONK2 _PIN_E7     //white
-
-#define BOM_VALUE_THRESHOLD 150 //200
-#define NUM_BOM_LEDS 16
-
-/*
-  *The following pin definitions are for the BOM v1.5
-  */
-
-#define BOM_MODE	_PIN_E2	//dio0
-#define BOM_STROBE	_PIN_E3	//dio1
-
-#define BOM_DATA	_PIN_A0 //servo0
-#define BOM_CLOCK	_PIN_A1	//servo1
-
-#define BOM_S0		_PIN_E5	//dio3
-#define BOM_S1		_PIN_E4	//dio2
-#define BOM_S2		_PIN_E7	//dio4
-#define BOM_S3		_PIN_E6	//dio5
-#define BOM_OUT		PF0		//analog(yellow)
-
-/**
- * @defgroup bom BOM (Bearing and Orientation Module)
- * @brief Functions for dealing with the BOM.
- *
- * The Bearing and Orientation Module / Barrel of Monkeys / BOM
- * is a custom sensor designed and built by the Colony Project.
- * It consists of a ring of 16 IR emitters and 16 IR detectors.
- * The BOM is most often use to determine the direction of other
- * robots. This module contains functions for controlling the BOM.
- *
- * Include bom.h to access these functions.
- *
- * @{
- **/
-
-static unsigned int bom_val[NUM_BOM_LEDS];
-static volatile char bom_type = BOM10;
-static int select_pins[4];
-static int analog_pin;
-
-/**
- * Initializes the BOM.
- * Call bom_init before reading bom values or turning bom leds.
- *
- * @bugs INCOMPLETE - No utilization of BOM1.5 RSSI capability. Probably leave this out
- * until Cornell and Pras return
- * 
- * @see bom_refresh, bom_leds_on, bom_leds_off
- **/
-void bom_init(char type) {
-    bom_type = type;
-    
-    switch(bom_type) {
-    case BOM10:
-		select_pins[0] = MONK0; 
-		select_pins[1] = MONK1;
-		select_pins[2] = MONK2;
-		select_pins[3] = MONK3;
-		analog_pin = MONKI;
-        break;
-    case BOM15:
-        //Sets BOM1.5 to normal [BOM] mode
-        digital_output(BOM_MODE, 0);
-		select_pins[0] = BOM_S0; 
-		select_pins[1] = BOM_S1;
-		select_pins[2] = BOM_S2;
-		select_pins[3] = BOM_S3;
-		bom_set_leds(BOM_ALL);
-		analog_pin = BOM_OUT;
-        break;
-    case RBOM:
-        break;
-    //default:
-    }
-}
-
-/**
- * Iterates through each bit in the bit_field. For each set bit, sets the corresponding bom select bits
- *    and updates the corresponding bom value with an analog_get8 reading.  analog_init and bom_init
- *    must be called for this to work. Must call this before reading BOM values!
- *
- *
- * @param bit_field specifies which elements in bom_val[] should be updated. Use BOM_ALL to refresh all values.
- *    Ex. if 0x0003 is passed, bom_val[0] and bom_val[1] will be updated.
- *
- * @see bom_get
- **/
-void bom_refresh(int bit_field) {
-    int i;
-	int loop_was_running = 0;
-    
-	//Check analog loop status
-    if(analog_loop_status() == ADC_LOOP_RUNNING) {
-		loop_was_running = 1;
-		analog_stop_loop();
-	}
-    
-	//Read BOM values
-    for(i = 0; i < NUM_BOM_LEDS; i++) {
-        if(bit_field & 0x1) {
-            bom_select(i);
-            bom_val[i] = analog_get8(analog_pin);
-        }
-        bit_field = bit_field >> 1;
-    }
-    
-	//Restore analog loop status
-	if(loop_was_running)
-		analog_start_loop();
-}
-
-/**
- * Gets the bom reading from bom_val[which].  Call bom_refresh beforehand to read new bom values.
- *
- * @pre must call bom refresh first
- *
- * @param which which bom value to return
- *
- * @return the bom value
- *
- * see bom_refresh
- **/
-int bom_get(int which) {
-    return bom_val[which];
-}
-
-/** 
- * Compares all the values in bom_val[] and returns the index to the lowest (max) value element.
- *
- * @pre must call bom refresh
- * @return index to the lowest (max) bom value element.  -1 if no value is lower than
- *    BOM_VALUE_THRESHOLD
- **/
-int bom_get_max(void) {
-    int i, lowest_val, lowest_i;
-    lowest_i = -1;
-    lowest_val = 255;
-    for(i = 0; i < NUM_BOM_LEDS; i++) {
-        if(bom_val[i] < lowest_val) {
-            lowest_val = bom_val[i];
-            lowest_i = i;
-        }
-    }
-    
-    if(lowest_val < BOM_VALUE_THRESHOLD)
-        return lowest_i;
-    else
-        return -1;
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ **/
+
+
+/**
+ * @file bom.c
+ * @brief Implementation for using the BOM
+ *
+ * Contains functions for using the Bearing and Orientation Module (BOM)
+ *
+ * @author Colony Project, CMU Robotics Club
+ **/
+
+#include "bom.h"
+#include "dio.h"
+#include "serial.h"
+#include "analog.h"
+
+//On the original BOM1.0, the emmitter angular order does not match the analog mux order
+//so you need to iterate through the mux index in the following order if you want to get
+//the detector readings in order:
+static const char lookup[16] = {7,6,5,0xe,1,4,3,2,0xf,0,0xd,8,0xc,0xb,9,0xa};
+
+// internal function prototypes
+static void bom_select(char which);
+
+/*
+ Bk R Y (Analog)
+---------
+ Green
+ Blue
+ White
+---------
+ Blue
+ White
+*/
+
+
+/*
+the analog pin definitions from dio.h DO NOT work here,
+so we must use PF0 from avrgcc (as opposed to _PIN_F0).
+BUT the dio pin definitions from dio.h must be used (no PE...).
+
+also, _PIN_E2 is initialized to high for some reason,
+which turns the BOM on when the robot is turned on.
+WORK-AROUND: call digital_output(_PIN_E2,0) at some point.
+
+*/
+
+#define MONKI PF0         //analog (yellow)
+//------------------------//
+#define MONKL _PIN_E2     //green
+#define MONK1 _PIN_E3     //blue
+#define MONK0 _PIN_E4     //white
+//------------------------//
+#define MONK3 _PIN_E6     //blue
+#define MONK2 _PIN_E7     //white
+
+#define BOM_VALUE_THRESHOLD 150 //200
+#define NUM_BOM_LEDS 16
+
+/*
+  *The following pin definitions are for the BOM v1.5
+  */
+
+#define BOM_MODE	_PIN_E2	//dio0
+#define BOM_STROBE	_PIN_E3	//dio1
+
+#define BOM_DATA	_PIN_A0 //servo0
+#define BOM_CLOCK	_PIN_A1	//servo1
+
+#define BOM_S0		_PIN_E5	//dio3
+#define BOM_S1		_PIN_E4	//dio2
+#define BOM_S2		_PIN_E7	//dio4
+#define BOM_S3		_PIN_E6	//dio5
+#define BOM_OUT		PF0		//analog(yellow)
+
+/**
+ * @defgroup bom BOM (Bearing and Orientation Module)
+ * @brief Functions for dealing with the BOM.
+ *
+ * The Bearing and Orientation Module / Barrel of Monkeys / BOM
+ * is a custom sensor designed and built by the Colony Project.
+ * It consists of a ring of 16 IR emitters and 16 IR detectors.
+ * The BOM is most often use to determine the direction of other
+ * robots. This module contains functions for controlling the BOM.
+ *
+ * Include bom.h to access these functions.
+ *
+ * @{
+ **/
+
+unsigned char bom_initd=0;
+
+static unsigned int bom_val[NUM_BOM_LEDS];
+static volatile char bom_type = BOM10;
+static int select_pins[4];
+static int analog_pin;
+
+/**
+ * Initializes the BOM.
+ * Call bom_init before reading bom values or turning bom leds.
+ *
+ * @bugs INCOMPLETE - No utilization of BOM1.5 RSSI capability. Probably leave this out
+ * until Cornell and Pras return
+ *
+ * @return 0 if init succesfull, an error code otherwise 
+ *
+ * @see bom_refresh, bom_leds_on, bom_leds_off
+ **/
+int bom_init(char type) {
+
+    if(bom_initd)
+      return ERROR_INIT_ALREADY_INITD;
+
+
+    bom_type = type;
+    
+    switch(bom_type) {
+    case BOM10:
+		select_pins[0] = MONK0; 
+		select_pins[1] = MONK1;
+		select_pins[2] = MONK2;
+		select_pins[3] = MONK3;
+		analog_pin = MONKI;
+        break;
+    case BOM15:
+        //Sets BOM1.5 to normal [BOM] mode
+        digital_output(BOM_MODE, 0);
+		select_pins[0] = BOM_S0; 
+		select_pins[1] = BOM_S1;
+		select_pins[2] = BOM_S2;
+		select_pins[3] = BOM_S3;
+		bom_set_leds(BOM_ALL);
+		analog_pin = BOM_OUT;
+        break;
+    case RBOM:
+        break;
+    //default:
+    }
+
+    bom_initd=1;
+    return 0;
 }
 
-/** 
- * Computes the weighted average of all the bom readings to estimate the position (and distance) of another robot.
- *
+/**
+ * Iterates through each bit in the bit_field. For each set bit, sets the corresponding bom select bits
+ *    and updates the corresponding bom value with an analog_get8 reading.  analog_init and bom_init
+ *    must be called for this to work. Must call this before reading BOM values!
+ *
+ *
+ * @param bit_field specifies which elements in bom_val[] should be updated. Use BOM_ALL to refresh all values.
+ *    Ex. if 0x0003 is passed, bom_val[0] and bom_val[1] will be updated.
+ *
+ * @return 0 if init succesfull, an error code otherwise
+ *
+ * @see bom_get
+ **/
+int bom_refresh(int bit_field) {
+    int i;
+    int loop_was_running = 0;
+
+    if(!bom_initd)
+      return ERROR_LIBRARY_NOT_INITD;
+
+    
+    //Check analog loop status
+    if(analog_loop_status() == ADC_LOOP_RUNNING) {
+      loop_was_running = 1;
+      analog_stop_loop();
+    }
+    
+    //Read BOM values
+    for(i = 0; i < NUM_BOM_LEDS; i++) {
+      if(bit_field & 0x1) {
+	bom_select(i);
+	bom_val[i] = analog_get8(analog_pin);
+      }
+      bit_field = bit_field >> 1;
+    }
+    
+    //Restore analog loop status
+    if(loop_was_running)
+      analog_start_loop();
+
+    return 0;
+}
+
+/**
+ * Gets the bom reading from bom_val[which].  Call bom_refresh beforehand to read new bom values.
+ *
+ * @pre must call bom refresh first
+ *
+ * @param which which bom value to return
+ *
+ * @return the bom value, -1 on error
+ *
+ * see bom_refresh
+ **/
+int bom_get(int which) {
+    if(!bom_initd)
+      return -1;
+
+    return bom_val[which];
+}
+
+/** 
+ * Compares all the values in bom_val[] and returns the index to the lowest (max) value element.
+ *
  * @pre must call bom refresh
- * @param dist  pointer to int in which to return the estimated distance to the other robot
+ * @return index to the lowest (max) bom value element.  -1 if no value is lower than
+ *    BOM_VALUE_THRESHOLD, -2 if the bom is not initialized
+ **/
+int bom_get_max(void) {
+    int i, lowest_val, lowest_i;
+
+    if(!bom_initd)
+      return -2;
+
+    lowest_i = -1;
+    lowest_val = 255;
+    for(i = 0; i < NUM_BOM_LEDS; i++) {
+        if(bom_val[i] < lowest_val) {
+            lowest_val = bom_val[i];
+            lowest_i = i;
+        }
+    }
+    
+    if(lowest_val < BOM_VALUE_THRESHOLD)
+        return lowest_i;
+    else
+        return -1;
+}
+
+/** 
+ * Computes the weighted average of all the bom readings to estimate the position (and distance) of another robot.
+ *
+ * @pre must call bom refresh
+ * @param dist  pointer to int in which to return the estimated distance to the other robot
  * @return estimated position of the max bom value element as a fixed point value analogous to 10 times the
- *        index of the max bom value.  -1 if no value is lower than BOM_VALUE_THRESHOLD.
+ *        index of the max bom value.  -1 if no value is lower than BOM_VALUE_THRESHOLD, -2 if the bom is not initialized
  **/
 int bom_get_max10(int *dist) {
     int i, max;
     long long mean = 0, sum = 0;
 
+    if(!bom_initd)
+      return ERROR_LIBRARY_NOT_INITD;
+
+
     max = bom_get_max();
     if (max < 0)
     {
@@ -264,125 +295,148 @@
     }
 
     return mean;
-}
-
-/**
- * Iterates through each bit in the bit_field. If the bit is set, the corresponding emitter will
- *    be enabled to turn on when bom_on() is called.
- *    bom_init must be called for this to work. Does nothing if a BOM1.0 is installed
- *
- * @param bit_field specifies which leds should be turned on when bom_on is called.  Use BOM_ALL to turn on all bom leds.
- *    Ex. if 0x0005 is passed, leds 0 and 2 will be turned on.
- **/
-void bom_set_leds(int bit_field) {
-    int i;
-	unsigned int mask = 1<<(NUM_BOM_LEDS-1);
-	switch(bom_type) {
-    case BOM10:
-        //TODO: put an assert here to alert the user that this should not be called
-        break;
-		
-    case BOM15:
-	    for(i=NUM_BOM_LEDS; i>0; i--)
-	    {
-		    //set the current bit, sending MSB first
-		    digital_output(BOM_DATA, bit_field&mask);
-		    //then pulse the clock
-		    digital_output(BOM_CLOCK, 1);
-		    digital_output(BOM_CLOCK, 0);
-			mask = mask>>1;
-	    }
-        break;
-		
-    case RBOM:
-        //add rbom code here
-        break;
-    }
-}
-
-
-/**
- * (DEPRECATED) Returns the direction of the maximum BOM reading,
- * as an integer in the range 0-15. 0 indicates to the
- * robot's right, while the rest of the sensors are
- * numbered counterclockwise. This is useful for determining
- * the direction of a robot flashing its BOM, of only one
- * robot is currently doing so. analog_init must be called
- * before this function can be used.
- *
- * @return the direction of the maximum BOM reading
- *
- * @see analog_init
- **/
-int get_max_bom(void) {
-    bom_refresh(BOM_ALL);
-    return bom_get_max();
-}
-
-/**
- * Flashes the BOM.  If using a BOM1.5, only the emitters that have been enabled using
- * bom_set_leds will turn on.
- * 
- * @see bom_off, bom_set_leds
- **/
-void bom_on(void)
-{
-  switch(bom_type) {
-  case BOM10:
-	digital_output(MONKL, 1);
-	break;
-  case BOM15:
-	digital_output(BOM_STROBE, 1);
-	break;
-  case RBOM:
-	break;
-  }
-}
-
-/**
- * Turns off all bom leds.
- * 
- * @see bom_on
- **/
-void bom_off(void)
-{
-  switch(bom_type) {
-  case BOM10:
-	digital_output(MONKL, 0);
-	break;
-  case BOM15:
-	digital_output(BOM_STROBE, 0);
-	break;
-  case RBOM:
-	break;
-  }
-}
-
-/** @} **/ //end group
-
-//select a detector to read
-static void bom_select(char which) {
-	if(bom_type == BOM10)
-	  which = lookup[(int)which];
-	
-    if (which&8)
-      digital_output(select_pins[3], 1);
-    else
-      digital_output(select_pins[3], 0);
-
-    if (which&4)
-      digital_output(select_pins[2], 1);
-    else
-      digital_output(select_pins[2], 0);
-
-    if (which&2)
-      digital_output(select_pins[1], 1);
-    else
-      digital_output(select_pins[1], 0);
-
-    if (which&1)
-      digital_output(select_pins[0], 1);
-    else
-      digital_output(select_pins[0], 0);
-	
-}
+}
+
+/**
+ * Iterates through each bit in the bit_field. If the bit is set, the corresponding emitter will
+ *    be enabled to turn on when bom_on() is called.
+ *    bom_init must be called for this to work. Does nothing if a BOM1.0 is installed
+ *
+ * @param bit_field specifies which leds should be turned on when bom_on is called.  Use BOM_ALL to turn on all bom leds.
+ *    Ex. if 0x0005 is passed, leds 0 and 2 will be turned on.
+ *
+ * @return 0 if init succesfull, an error code otherwise
+ *
+ **/
+int bom_set_leds(int bit_field) {
+    int i;
+    unsigned int mask = 1<<(NUM_BOM_LEDS-1);
+
+    if(!bom_initd)
+      return ERROR_LIBRARY_NOT_INITD;
+
+    switch(bom_type) {
+    case BOM10:
+        //TODO: put an assert here to alert the user that this should not be called
+        break;
+		
+    case BOM15:
+	    for(i=NUM_BOM_LEDS; i>0; i--)
+	    {
+		    //set the current bit, sending MSB first
+		    digital_output(BOM_DATA, bit_field&mask);
+		    //then pulse the clock
+		    digital_output(BOM_CLOCK, 1);
+		    digital_output(BOM_CLOCK, 0);
+			mask = mask>>1;
+	    }
+        break;
+		
+    case RBOM:
+        //add rbom code here
+        break;
+    }
+
+    return 0;
+}
+
+
+/**
+ * (DEPRECATED) Returns the direction of the maximum BOM reading,
+ * as an integer in the range 0-15. 0 indicates to the
+ * robot's right, while the rest of the sensors are
+ * numbered counterclockwise. This is useful for determining
+ * the direction of a robot flashing its BOM, of only one
+ * robot is currently doing so. analog_init must be called
+ * before this function can be used.
+ *
+ * @return the direction of the maximum BOM reading
+ *
+ * @see analog_init
+ **/
+int get_max_bom(void) {
+    bom_refresh(BOM_ALL);
+    return bom_get_max();
+}
+
+/**
+ * Flashes the BOM.  If using a BOM1.5, only the emitters that have been enabled using
+ * bom_set_leds will turn on.
+ * 
+ * @return 0 if init succesfull, an error code otherwise
+ *
+ * @see bom_off, bom_set_leds
+ **/
+int bom_on(void)
+{
+  if(!bom_initd)
+    return ERROR_LIBRARY_NOT_INITD;
+
+  switch(bom_type) {
+  case BOM10:
+	digital_output(MONKL, 1);
+	break;
+  case BOM15:
+	digital_output(BOM_STROBE, 1);
+	break;
+  case RBOM:
+	break;
+  }
+
+  return 0;
+}
+
+/**
+ * Turns off all bom leds.
+ * 
+ * @return 0 if init succesfull, an error code otherwise
+ *
+ * @see bom_on
+ **/
+int bom_off(void)
+{
+  if(!bom_initd)
+    return ERROR_LIBRARY_NOT_INITD;
+
+  switch(bom_type) {
+  case BOM10:
+	digital_output(MONKL, 0);
+	break;
+  case BOM15:
+	digital_output(BOM_STROBE, 0);
+	break;
+  case RBOM:
+	break;
+  }
+
+  return 0;
+}
+
+/** @} **/ //end group
+
+//select a detector to read
+static void bom_select(char which) {
+	if(bom_type == BOM10)
+	  which = lookup[(int)which];
+	
+    if (which&8)
+      digital_output(select_pins[3], 1);
+    else
+      digital_output(select_pins[3], 0);
+
+    if (which&4)
+      digital_output(select_pins[2], 1);
+    else
+      digital_output(select_pins[2], 0);
+
+    if (which&2)
+      digital_output(select_pins[1], 1);
+    else
+      digital_output(select_pins[1], 0);
+
+    if (which&1)
+      digital_output(select_pins[0], 1);
+    else
+      digital_output(select_pins[0], 0);
+	
+}
