Index: branches/library_refactor/behaviors/library_test/main.c
===================================================================
--- branches/library_refactor/behaviors/library_test/main.c	(revision 1137)
+++ branches/library_refactor/behaviors/library_test/main.c	(revision 1138)
@@ -104,8 +104,46 @@
 		orbs_set (0, 0, 0, 0, 0, 255); delay_ms (500);
 	}
 
+	if (false)
+	{
+		orb_set (1,1,1);
+		while (1)
+		{
+			SYNC
+			{
+				for (uint8_t m=0; m<100; ++m)
+				{
+					_delay_us(10);
+				}
+			}
+		}
+	}
+	
 	if (true)
 	{
+		while (1)
+		{
+			for (uint8_t x=0; x<255; ++x)
+			{
+				orbs_set (x, 1, 2, 3, 4, 5);
+				
+				for (uint8_t n=0; n<80; ++n)
+				{
+					SYNC
+					{ for (uint8_t m=0; m<1; ++m) _delay_us(50); }
+				}
+			}
+
+			for (uint8_t x=255; x>0; --x)
+			{
+				orbs_set (x, 1, 1, 1, 1, 1);
+				delay_ms (4);
+			}
+		}
+	}
+
+	if (true)
+	{
 		if (!button2_read ())
 		{
 			orb_set_mode (orb_mode_pwm);
Index: branches/library_refactor/lib/include/libdragonfly/dragonfly_lib.h
===================================================================
--- branches/library_refactor/lib/include/libdragonfly/dragonfly_lib.h	(revision 1137)
+++ branches/library_refactor/lib/include/libdragonfly/dragonfly_lib.h	(revision 1138)
@@ -103,6 +103,13 @@
 /** @brief shortcut for ATOMIC_BLOCK(ATOMIC_RESTORESTATE) **/
 #define SYNC ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
 
+/** @brief atomically grab a lock if it is free, return otherwise **/
+#define REQUIRE_LOCK_OR_RETURN(LOCK) do { SYNC { if (LOCK) return; LOCK=1; } } while (0)
 
+/** @brief atomically release a lock **/
+#define RELEASE_LOCK(LOCK) do { LOCK=0; } while (0)
+
+
+
 #endif
 
Index: branches/library_refactor/lib/bin/libdragonfly.a
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: branches/library_refactor/projects/libdragonfly/dragonfly_lib.h
===================================================================
--- branches/library_refactor/projects/libdragonfly/dragonfly_lib.h	(revision 1137)
+++ branches/library_refactor/projects/libdragonfly/dragonfly_lib.h	(revision 1138)
@@ -103,6 +103,13 @@
 /** @brief shortcut for ATOMIC_BLOCK(ATOMIC_RESTORESTATE) **/
 #define SYNC ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
 
+/** @brief atomically grab a lock if it is free, return otherwise **/
+#define REQUIRE_LOCK_OR_RETURN(LOCK) do { SYNC { if (LOCK) return; LOCK=1; } } while (0)
 
+/** @brief atomically release a lock **/
+#define RELEASE_LOCK(LOCK) do { LOCK=0; } while (0)
+
+
+
 #endif
 
Index: branches/library_refactor/projects/libdragonfly/lights.c
===================================================================
--- branches/library_refactor/projects/libdragonfly/lights.c	(revision 1137)
+++ branches/library_refactor/projects/libdragonfly/lights.c	(revision 1138)
@@ -77,6 +77,8 @@
  * 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
@@ -87,6 +89,16 @@
  *   - Total CPU use for interrupts (PWM mode only): 0.03%+0.75% max (TODO old values)
  *   - Maximum time spent in synchronized code: TODO
  * There are some possible optimizations. 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 (not the _delay_us restrictions!)
+ *   orb_set (1,1,1); while (1) { SYNC { for (uint8_t m=0; m<10; ++m) { _delay_us(10); } } }
  **/
 
 /*
@@ -98,10 +110,11 @@
 /*
  * Possible optimizations:
  *   - Use pointers instead of indicies for current_pwm_channel
- *   - Optimize the output compare interrupt
+ *   - Optimize output_compare()
  *   - Use a different sorting algorithm (see sort_orbs_buffer for further comments on this issue)
  *   - Use pointers in fill_orbs_buffer
- *   - Optimized orb_set (use the knowledge that there are only 3 distinct values)
+ *   - Optimized orb_set (use the knowledge that there are only 3 distinct values, don't use a loop but unroll the
+ *     sorting, which is no problem for 3 values)
  *   - Use a lower update frequency. The next higher prescaler value leads to a frequency of 30Hz which is too low (the
  *     orbs are flickering). So the timer would have to be reloaded manually after 127 to generate 60Hz. This would
  *     decrease the resolution from 8 to 7 bit, but 128 steps should still be enough.
@@ -109,10 +122,6 @@
 
 
 /*
-  TODO:
-    - Make thread safe
-	- Check delayed interrupts
-	
 	- Timing tests
 	  - How long do the interrupt handlers take?
       - How long may interrupts be blocked?
@@ -250,6 +259,42 @@
 // Not volatile because it is only accessed in the interrupt handler.
 uint8_t current_pwm_channel=0;
 
+
+static void output_compare (void) {
+	// This function is called when an output compare condition may have occured.
+	
+    // If the OC interrupt is executed without delay, TCNT0==time+1 (where time==OCR0), because the interrupt flag is
+	// queued at the next timer clock cycle after an output compare.
+
+    // What may happen here is that the interrupt is delayed for more than one timer clock cycle (33 us). In that case,
+	// the timer has already counted on and TCNT0 is bigger than current_channel_timer. Also, while during the ISR no
+	// other interrupts will occur, the timer may still count on. Thus, we have to check the following channel as well.
+
+	// Some optimization is possible in this function.
+
+    while (1) {
+		// The timer value at which the output compare interrupt should occur (one timer clock cycle after the output
+		// compare condition is detected).
+		uint8_t current_channel_time=pwm_read_buffer->channel[current_pwm_channel].time+1;
+		
+		// If the counter is not at this time yet, we don't have to do anything right now.
+		if (current_channel_time>TCNT0) return;
+		
+		// We have an output compare condition for the current channel.
+		
+        // Turn the current channel off
+        ORBPORT|=pwm_read_buffer->channel[current_pwm_channel].mask;
+
+        // Increment the channel index
+        current_pwm_channel++;
+
+        // If there is a next channel, load its OCR value
+        if (current_pwm_channel<=(num_pwm_channels-1))
+            if (pwm_read_buffer->channel[current_pwm_channel].time<255)
+                OCR0=pwm_read_buffer->channel[current_pwm_channel].time;
+    }
+}
+
 SIGNAL (SIG_OVERFLOW0) {
 #ifdef LIGHTS_DEBUG
     LIGHTS_DEBUG_OVERFLOW_INTERRUPT_START
@@ -275,6 +320,9 @@
     // Load the first OCR
     OCR0=pwm_read_buffer->channel[current_pwm_channel].time;
 
+	// If this interrupt was delayed, we might already have an output compare condition.
+	output_compare ();
+
 #ifdef LIGHTS_DEBUG
     LIGHTS_DEBUG_OVERFLOW_INTERRUPT_END
 #endif
@@ -285,21 +333,8 @@
     LIGHTS_DEBUG_OUTPUT_COMPARE_INTERRUPT_START
 #endif
 
-    // If this interrupt is executed without delay, TCNT0==time+1 (where time==OCR0)
-
-    // TODO delayed interrupt
-    while (TCNT0==pwm_read_buffer->channel[current_pwm_channel].time+1) {
-        // Turn the current channel off
-        ORBPORT|=pwm_read_buffer->channel[current_pwm_channel].mask;
-
-        // Increment the channel
-        current_pwm_channel++;
-
-        // If there is a next channel, load its OCR value
-        if (current_pwm_channel<=(num_pwm_channels-1))
-            if (pwm_read_buffer->channel[current_pwm_channel].time<255)
-                OCR0=pwm_read_buffer->channel[current_pwm_channel].time;
-    }
+	// We have an output compare condition.
+	output_compare ();
     
 #ifdef LIGHTS_DEBUG
     LIGHTS_DEBUG_OUTPUT_COMPARE_INTERRUPT_END
@@ -488,7 +523,10 @@
 // All of these functions use set_orb_values to set the actual values, and then call apply_orbs() to apply the changes.
 // set_orb_values should be used (even though it would be faster to set the array directly) because the binary/pwm mode
 // has to be handled.
+// All of these functions must be 
 
+uint8_t orb_lock=0;
+
 /**
  * Sets the specified orb to the specified color. The orbs must be initialized before this function may be used.
  * Note that, when setting both orbs, using orbs_set is faster then setting the orbs individually because the values are
@@ -501,8 +539,12 @@
  * @see 
  */
 void orb_n_set (uint8_t num, uint8_t red, uint8_t green, uint8_t blue) {
+	REQUIRE_LOCK_OR_RETURN(orb_lock);
+	
     set_orb_values (num, red, green, blue);
     apply_orbs ();
+	
+	RELEASE_LOCK(orb_lock);
 }
 
 /**
@@ -517,8 +559,12 @@
  * @see orb_init
  **/
 void orb1_set (uint8_t red, uint8_t green, uint8_t blue) {
+	REQUIRE_LOCK_OR_RETURN(orb_lock);
+	
     set_orb_values (0, red, green, blue);
     apply_orbs ();
+
+	RELEASE_LOCK(orb_lock);
 }
 
 /**
@@ -533,8 +579,12 @@
  * @see orb_init
  **/
 void orb2_set (uint8_t red, uint8_t green, uint8_t blue) {
+	REQUIRE_LOCK_OR_RETURN(orb_lock);
+	
     set_orb_values (1, red, green, blue);
     apply_orbs ();
+
+	RELEASE_LOCK(orb_lock);
 }
 
 /**
@@ -547,9 +597,13 @@
  * @see orb_init, orb1_set, orb2_set
  **/
 void orb_set (uint8_t red, uint8_t green, uint8_t blue) {
+	REQUIRE_LOCK_OR_RETURN(orb_lock);
+	
     set_orb_values (0, red, green, blue);
     set_orb_values (1, red, green, blue);
     apply_orbs ();
+
+	RELEASE_LOCK(orb_lock);
 }
 
 /**
@@ -570,9 +624,14 @@
 void orbs_set (
     uint8_t red1, uint8_t green1, uint8_t blue1,
     uint8_t red2, uint8_t green2, uint8_t blue2) {
+
+	REQUIRE_LOCK_OR_RETURN(orb_lock);
+
     set_orb_values (0, red1, green1, blue1);
     set_orb_values (1, red2, green2, blue2);
     apply_orbs ();
+
+	RELEASE_LOCK(orb_lock);
 }
 
 
@@ -580,6 +639,10 @@
 // ** Predefined color setting **
 // ******************************
 
+// This functions just call the corresponding orb*_set functions. If the orbs array is accessed in any other way, it
+// must be synchronized on orb_lock (REQUIRE_LOCK_OR_RETURN and RELEASE_LOCK)! Note that one synchronized function
+// cannot call another one with this lock implementation.
+
 // Macros for extracting a color.
 #define C_RED(col)   (((col & 0xE0) >> 5) * 36)
 #define C_GREEN(col) (((col & 0x1C) >> 2) * 36)
@@ -666,7 +729,7 @@
     // Using an 8 bit timer has the added advantage that all the comparisons are faster.
     
     // Normal mode, Compare match output off, Prescaler
-    TCCR0=_BV(CS02) | _BV(CS01); // 1024, 30 Hz
+    TCCR0=_BV(CS02) | _BV(CS01); // 256, 120 Hz
 
     // Enable the interrupts
     TIMSK|= _BV(OCIE0) | _BV(TOIE0);
