Index: lights.h
===================================================================
--- lights.h	(revision 1344)
+++ lights.h	(revision 1345)
@@ -1,4 +1,34 @@
+// FIXME remove
+typedef unsigned char uint8_t;
+
+
 /**
+ * Copyright (c) 2007 Colony Project
+ * 
+ * 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 lights.h
  * @brief Contains declarations for managing the orbs.
  *
@@ -11,13 +41,82 @@
 #ifndef _LIGHTS_H_
 #define _LIGHTS_H_
 
+/**
+ * @addtogroup orbs
+ * @{
+ **/
 
 /**
+ * Quick start: call orb_init_pwm or orb_init_binary, depending on which mode you want to use. Call orb*set or
+ * orb*set_color to set the orbs.
+ * 
+ * The orbs have two modes of operation: PWM mode and binary mode. In PWM mode, a pwm signal is generated by a hardware
+ * timer and the orbs can be set to a value of 0 through 255. In binary mode, the orbs can only be turned on or off and
+ * a value of 0 means "off" and any other value means "on". The mode can be chosen on initialization and can be changed
+ * at runtime using the orb_set_mode function.
+ *
+ * Operation (PWM mode): On timer overflow, all LEDs with a value>0 are turned on and the output compare value for the
+ * first LED is loaded. On compare match, the corresponding LED is turned off and the next output compare value is
+ * loaded. All masks are precomputed and sorted by time when setting the values.
+ *
+ * The data structure (pwm_t) containing the PWM times and masks is triple buffered. This is because the buffer the ISR
+ * is reading from may only be modified on timer overflow before the next PWM sequence is started, because otherwise the
+ * next OCR value might be sed to a value smaller than the current timer value, resulting in the remaining channels not
+ * being turned off in that PWM period (flash to on). When using two buffers, the page flip can only occur on a timer
+ * overflow for the same reason. So after writing a buffer and marking it for page flip, neither of the buffers could be
+ * modified because the front buffer is read by the ISR and the back buffer could be switched at any time. So the
+ * calling thread would have to be delayed by up to one full PWM period (8ms in the current implementation, but
+ * 20ms-50ms would be a reasonable value to expect here). To avoid this, triple buffering is used.
+ *
+ * The code for applying the orbs is fairly optimized. See the apply_orbs function for some time measurements and
+ * further nodes.
+ *
+ * The PWM frequency is 120Hz (8ms period time). The next lower frequency (determined by the prescaler) is 30 Hz which
+ * is too slow (orbs flicker).
+ *
+ * The orbs code is thread safe, which means that the functions may be called from another interrupt handler. If there
+ * are multiple concurrent calls to the orb*set* functions, one of them is ignored and the orbs are never left in an
+ * inconsistent state. For example, if the orbs are set to green by the main thread and to red by an interrupt handler,
+ * the resulting color will be either red or green, but never yellow.
+ * Thread safety is achieved by grabbing a lock at the beginning of all functions that modify the orb code and releasing
+ * the lock at the end. If the lock is already taken, the function just returns doing nothing.
+ *
+ * Some performance measurements:
+ *   - Time for setting new orb values (PWM mode):       35us-72us (depending on the degree to which the array is
+ *                                                                  already in the correct order)
+ *   - Time for setting new orb values (binary mode):        5.5us
+ *
+ *   - Interrupt time (PWM mode only):                         8us (overflow)
+ *                                                            10us (output compare)
+ *                                                             6us (last output compare)
+ *                                                            30us (output compare, all value equal)
+ *
+ *   - Maximum total interrupt time per period:               64us
+ *   - Maximum CPU usage for interrupts (PWM mode only):     <0.8%
+ *
+ *   - Maximum contiguous synchronized block:                 30us (output compare interrupt, all values equal)
+ *
+ * There are some potential optimizations left. See the source code for more information.
+ *
+ * A note on robustness: if the output compare interrupt is disabled for too long, either due to a long ISR or a long
+ * synchronized code block, the orbs will flicker to brighter values for being turned off too late. With software PWM,
+ * there's nothing at all to be done about that. The problem can be alleviated by using a lower PWM frequency, but then
+ * the orbs will start flickering all the time due to the low update frequency.
+ * Some measurements: with 100us synchronized blocks, the flickering is accepptably low. Longer synchronized blocks
+ * mean more flickering. At 1ms synchronized blocks, the flickering is quite bad, especially for low orb values. Note
+ * that orb value 0 never flickers at all because the corresponding channels are not turned on at all.
+ * Test code (note the _delay_us restrictions!)
+ *   orb_set (1,1,1); while (1) { SYNC { for (uint8_t m=0; m<10; ++m) { _delay_us(10); } } }
+ **/
+
+/** @} **/ //end addtogroup
+
+/**
  * @addtogroup orbs
  * @{
  **/
 
-//ORB Colors
+// ***** Predefined colors *****
 /** @brief Red **/
 #define RED       0xE0
 /** @brief Orange **/
@@ -40,34 +139,84 @@
 #define MAGENTA   0xE3
 /** @brief White **/
 #define WHITE     0xFE
-/** @brief Turn the orb off (White) **/
-#define ORB_OFF   0xFE      //ORB_OFF->WHITE
+/** @brief Turn the orb off **/
+#define ORB_OFF   0x00
 
-/** @brief Enables the orbs **/
+
+
+// ***** Initialization *****
+
+/** @brief Enables the orbs in default mode **/
 void orb_init(void);
+
+/** @brief Enables the orbs in binary mode **/
+void orb_init_binary (void);
+
+/** @brief Enables the orbs in PWM mode **/
+void orb_init_pwm (void);
+
+
+
+// ***** Mode setting *****
+
+/** Specification of the orb mode **/
+typedef uint8_t orb_mode_t;
+
+/** @brief PWM mode **/
+#define orb_mode_pwm 0
+
+/** @brief Binary mode **/
+#define orb_mode_binary 1
+
+
+/** @brief Switches the orbs to the specified mode **/
+void orb_set_mode (orb_mode_t mode);
+
+/** @brief Disables the orb timer, but does not change the mode **/
+void orb_disable_timer (void);
+
+/** @brief Enables the orb timer, but does not change the mode **/
+void orb_enable_timer (void);
+
+
+
+// ***** Setting RGB colors *****
+
+/** @brief set the specified orb to a specified color **/
+void orb_n_set (uint8_t num, uint8_t red, uint8_t green, uint8_t blue);
+
 /** @brief Set both orbs to a specified color **/
-void orb_set(unsigned char red_led, unsigned char green_led,
-	unsigned char blue_led);
+void orb_set(uint8_t red, uint8_t green, uint8_t blue);
+
 /** @brief Set orb1 to a specified color **/
-void orb1_set(unsigned char red_led, unsigned char green_led,
-	unsigned char blue_led); 
+void orb1_set(uint8_t red_led, uint8_t green_led, uint8_t blue_led); 
+
 /** @brief Set orb2 to a specified color **/
-void orb2_set(unsigned char red_led, unsigned char green_led,
-	unsigned char blue_led);
+void orb2_set(uint8_t red_led, uint8_t green_led, uint8_t blue_led);
 
-/** @brief Set both orbs to a specified color **/
-void orb_set_color(int col);
+void orbs_set (uint8_t red1, uint8_t green1, uint8_t blue1, uint8_t red2, uint8_t green2, uint8_t blue2);
+
+
+
+// ***** Settings predefined colors *****
+
+/** @brief set the specified orb to the specified color **/
+void orb_n_set_color(uint8_t num, uint8_t col);
+
 /** @brief Set orb1 to a specified color **/
-void orb1_set_color(int col);
+void orb1_set_color(uint8_t col);
+
 /** @brief Set orb2 to a specified color **/
-void orb2_set_color(int col);
+void orb2_set_color(uint8_t col);
 
-/** @brief Disable the orbs **/
-void orb_disable(void);
-/** @brief Enable the orbs **/
-void orb_enable(void);
+/** @brief set the orbs to specified colors **/
+void orbs_set_color(uint8_t col1, uint8_t col2);
 
+/** @brief Set both orbs to a specified color **/
+void orb_set_color(uint8_t col);
+
+
+
 /** @} **/ //end addtogroup
 
 #endif
-
