Difference between revisions of "Get led code"
From Just in Time
m |
|||
Line 6: | Line 6: | ||
* LED in the string. For a 60 LED string this means that at least 180 bytes | * LED in the string. For a 60 LED string this means that at least 180 bytes | ||
* of memory are required. | * of memory are required. | ||
+ | * | ||
+ | * This type also has a buffer of bytes, but these bytes hold sequences of | ||
+ | * the form: | ||
+ | * <jump>, <count>, G1, R1, B1, G2, R2, B2, <jump>, <count>, G3, R3, B3, etc... | ||
+ | * | ||
+ | * <jump> represents an amount of black pixels, <count> is the number of GRB values | ||
+ | * that follow | ||
+ | * | ||
+ | * A buffer is terminated by a zero <jump> value or a zero <count>. The first <jump> | ||
+ | * never terminates the sequence, even if it is zero. A zero <jump> count at the start | ||
+ | * means the string starts with a lit LED. | ||
*/ | */ | ||
template<uint8_t buffer_size, uint8_t led_string_size> | template<uint8_t buffer_size, uint8_t led_string_size> | ||
Line 11: | Line 22: | ||
{ | { | ||
uint8_t buffer[buffer_size]; | uint8_t buffer[buffer_size]; | ||
+ | |||
+ | /// move the range [begin, end> towards buffer_end. | ||
+ | /// buffer_end must be higher than end, for this function to work correctly. | ||
+ | /// The bytes that become available are filled with zeros. | ||
+ | static void move_right( uint8_t *begin, uint8_t *end, uint8_t *buffer_end) | ||
+ | { | ||
+ | while (begin < end) *(--buffer_end) = *(--end); | ||
+ | while( begin < buffer_end) *(--buffer_end) = 0; | ||
+ | } | ||
}; | }; | ||
− | + | /** | |
+ | * specialization of the led_buffer_traits for sparse buffers. | ||
+ | * | ||
+ | * For regular arrays, the led string size is simply the number of bytes | ||
+ | * divided by three. A sparse buffer has the number of leds encoded in the | ||
+ | * type as a template argument. | ||
+ | */ | ||
template< uint8_t buffer_size, uint8_t led_string_size> | template< uint8_t buffer_size, uint8_t led_string_size> | ||
struct led_buffer_traits<sparse_leds<buffer_size, led_string_size> > | struct led_buffer_traits<sparse_leds<buffer_size, led_string_size> > | ||
Line 21: | Line 47: | ||
}; | }; | ||
+ | /** | ||
+ | * clear a sparse buffer. This fills the buffer with as many | ||
+ | * black leds as there are leds in the string. | ||
+ | */ | ||
template<uint8_t buffer_size, uint8_t led_string_size> | template<uint8_t buffer_size, uint8_t led_string_size> | ||
inline void clear( sparse_leds<buffer_size, led_string_size> &leds) | inline void clear( sparse_leds<buffer_size, led_string_size> &leds) | ||
Line 29: | Line 59: | ||
− | + | /** | |
− | + | * Given a sparse buffer and a position in the LED string, find the position in | |
− | + | * the buffer that corresponds with this LED. If such a position did not exist, it | |
− | + | * will be created by introducing a new block inside the buffer or by appending | |
− | + | * a location for the LED at the start or end of an existing block. | |
− | + | * | |
+ | * This function assumes that the current buffer already covers the complete LED | ||
+ | * string, or in other words, the sum of all <jump> and <count> values must be higher | ||
+ | * than the argument 'position' to this function. This function makes sure that | ||
+ | * the sum of <jump>s and <count>s remains the same. | ||
+ | * | ||
+ | * This function is deliberately not implemented as an operator[] of sparse_leds, because | ||
+ | * using an explicit function call makes it clear that code is being run and that it is | ||
+ | * worthwhile to store the result of this function instead of calling the function twice. | ||
+ | * Measurements have shown that the compiler will not memoize a second call to this function with | ||
+ | * the same arguments. | ||
+ | */ | ||
template<uint8_t buffer_size, uint8_t led_string_size> | template<uint8_t buffer_size, uint8_t led_string_size> | ||
rgb & get( sparse_leds<buffer_size, led_string_size> &leds, uint8_t position) | rgb & get( sparse_leds<buffer_size, led_string_size> &leds, uint8_t position) | ||
Line 52: | Line 93: | ||
// need to add a new block before the one we're pointing at. | // need to add a new block before the one we're pointing at. | ||
*buffer_iterator = (jump_pos - position - 1); | *buffer_iterator = (jump_pos - position - 1); | ||
− | move_right( buffer_iterator, end - 5, end); | + | leds.move_right( buffer_iterator, end - 5, end); |
*buffer_iterator++ = position - current_pos; | *buffer_iterator++ = position - current_pos; | ||
*buffer_iterator++=1; | *buffer_iterator++=1; | ||
Line 66: | Line 107: | ||
++*buffer_iterator; | ++*buffer_iterator; | ||
++buffer_iterator; | ++buffer_iterator; | ||
− | move_right( buffer_iterator, end-3, end); | + | leds.move_right( buffer_iterator, end-3, end); |
break; | break; | ||
} | } | ||
Line 91: | Line 132: | ||
*buffer_iterator += *(buffer_iterator + jump_pos + 1)+1; | *buffer_iterator += *(buffer_iterator + jump_pos + 1)+1; | ||
buffer_iterator += jump_pos; | buffer_iterator += jump_pos; | ||
− | move_right( buffer_iterator, end - 1, end); | + | leds.move_right( buffer_iterator, end - 1, end); |
} | } | ||
else | else | ||
Line 98: | Line 139: | ||
++*buffer_iterator; | ++*buffer_iterator; | ||
buffer_iterator += jump_pos; | buffer_iterator += jump_pos; | ||
− | move_right( buffer_iterator, end - 3, end); | + | leds.move_right( buffer_iterator, end - 3, end); |
} | } | ||
break; | break; | ||
Line 106: | Line 147: | ||
return *(reinterpret_cast<rgb *>(buffer_iterator)); | return *(reinterpret_cast<rgb *>(buffer_iterator)); | ||
− | |||
} | } | ||
</source> | </source> |
Latest revision as of 12:51, 12 April 2014
<source lang='cpp'> /**
* A data structure for a sparse representation of values in a LED string. * * A non-sparse representation of an LED string holds 3 bytes for every * LED in the string. For a 60 LED string this means that at least 180 bytes * of memory are required. * * This type also has a buffer of bytes, but these bytes hold sequences of * the form: * <jump>, <count>, G1, R1, B1, G2, R2, B2, <jump>, <count>, G3, R3, B3, etc... * * <jump> represents an amount of black pixels, <count> is the number of GRB values * that follow * * A buffer is terminated by a zero <jump> value or a zero <count>. The first <jump> * never terminates the sequence, even if it is zero. A zero <jump> count at the start * means the string starts with a lit LED. */
template<uint8_t buffer_size, uint8_t led_string_size> struct sparse_leds { uint8_t buffer[buffer_size];
/// move the range [begin, end> towards buffer_end. /// buffer_end must be higher than end, for this function to work correctly. /// The bytes that become available are filled with zeros. static void move_right( uint8_t *begin, uint8_t *end, uint8_t *buffer_end) { while (begin < end) *(--buffer_end) = *(--end); while( begin < buffer_end) *(--buffer_end) = 0; } };
/**
* specialization of the led_buffer_traits for sparse buffers. * * For regular arrays, the led string size is simply the number of bytes * divided by three. A sparse buffer has the number of leds encoded in the * type as a template argument. */
template< uint8_t buffer_size, uint8_t led_string_size> struct led_buffer_traits<sparse_leds<buffer_size, led_string_size> > { static const uint8_t count = led_string_size; static const uint8_t size = buffer_size; };
/**
* clear a sparse buffer. This fills the buffer with as many * black leds as there are leds in the string. */
template<uint8_t buffer_size, uint8_t led_string_size> inline void clear( sparse_leds<buffer_size, led_string_size> &leds) { leds.buffer[0] = led_string_size; leds.buffer[1] = 0; }
/**
* Given a sparse buffer and a position in the LED string, find the position in * the buffer that corresponds with this LED. If such a position did not exist, it * will be created by introducing a new block inside the buffer or by appending * a location for the LED at the start or end of an existing block. * * This function assumes that the current buffer already covers the complete LED * string, or in other words, the sum of all <jump> and <count> values must be higher * than the argument 'position' to this function. This function makes sure that * the sum of <jump>s and <count>s remains the same. * * This function is deliberately not implemented as an operator[] of sparse_leds, because * using an explicit function call makes it clear that code is being run and that it is * worthwhile to store the result of this function instead of calling the function twice. * Measurements have shown that the compiler will not memoize a second call to this function with * the same arguments. */
template<uint8_t buffer_size, uint8_t led_string_size> rgb & get( sparse_leds<buffer_size, led_string_size> &leds, uint8_t position) {
uint8_t *buffer_iterator = &leds.buffer[0]; uint8_t * const end = buffer_iterator + buffer_size; uint8_t current_pos = 0; while (buffer_iterator < end) { // current_pos pointing one past the previous block // buffer_iterator pointing at a 'jump'
uint8_t jump_pos = current_pos + *buffer_iterator; if (jump_pos > position + 1) { // need to add a new block before the one we're pointing at. *buffer_iterator = (jump_pos - position - 1); leds.move_right( buffer_iterator, end - 5, end); *buffer_iterator++ = position - current_pos; *buffer_iterator++=1; break; } current_pos = jump_pos; // current_pos now pointing at the location of the first led in the block if (current_pos == position + 1) { // prepend the new led to the current block of leds --(*buffer_iterator); ++buffer_iterator; ++*buffer_iterator; ++buffer_iterator; leds.move_right( buffer_iterator, end-3, end); break; } ++buffer_iterator; // pointing at the led block size jump_pos = position - current_pos; if ( jump_pos < *buffer_iterator) { // we're actually pointing to a led that is inside the current block buffer_iterator += (1 + 3 * jump_pos); break; } current_pos += *buffer_iterator; // pointing one past the last led in the string. jump_pos = 3 * (*buffer_iterator) + 1; //buffer_iterator += 3 * (*buffer_iterator); if (position == current_pos) { // decrease distance between this block and the next by one if (--(*(buffer_iterator+jump_pos)) == 0) { // distance is zero, concatenate two blocks.
// new size is the old size plus the size of the next block plus // 1 for the new led. *buffer_iterator += *(buffer_iterator + jump_pos + 1)+1; buffer_iterator += jump_pos; leds.move_right( buffer_iterator, end - 1, end); } else { // distance is non-zero, just enlarge the current block ++*buffer_iterator; buffer_iterator += jump_pos; leds.move_right( buffer_iterator, end - 3, end); } break; } buffer_iterator+=jump_pos; }
return *(reinterpret_cast<rgb *>(buffer_iterator)); } </source>