Comran Morshed | 33ad169 | 2015-12-06 18:53:02 +0000 | [diff] [blame] | 1 | #include "frc971/wpilib/LPD8806.h" |
| 2 | |
| 3 | #include "frc971/queues/gyro.q.h" |
| 4 | |
| 5 | #include "SPI.h" |
Brian Silverman | cee260a | 2015-12-24 16:27:51 -0800 | [diff] [blame] | 6 | #undef ERROR |
Comran Morshed | 33ad169 | 2015-12-06 18:53:02 +0000 | [diff] [blame] | 7 | |
| 8 | namespace frc971 { |
| 9 | namespace wpilib { |
| 10 | |
| 11 | LPD8806::LPD8806(int chips) |
| 12 | : chips_(chips), |
| 13 | data_(new LED[chips * 2]), |
| 14 | spi_(new SPI(SPI::kOnboardCS1)) { |
| 15 | memset(data_.get(), 0, sizeof(LED[chips_ * 2])); |
| 16 | |
| 17 | // 2 MHz is the maximum frequency the datasheet recommends. |
| 18 | spi_->SetClockRate(2e6); |
| 19 | spi_->SetChipSelectActiveHigh(); |
| 20 | |
| 21 | // Clock is inverted due to the level translator chip. |
| 22 | spi_->SetClockActiveLow(); |
| 23 | spi_->SetSampleDataOnRising(); |
| 24 | spi_->SetMSBFirst(); |
| 25 | } |
| 26 | |
| 27 | void LPD8806::SetColor(int led, uint32_t hex_color) { |
| 28 | CHECK_LT(led, chips_ * 2); |
| 29 | ::aos::MutexLocker locker(&data_mutex_); |
| 30 | data_[led].red = TranslateColor(hex_color, RED); |
| 31 | data_[led].green = TranslateColor(hex_color, GREEN); |
| 32 | data_[led].blue = TranslateColor(hex_color, BLUE); |
| 33 | } |
| 34 | |
| 35 | uint8_t LPD8806::TranslateColor(uint32_t hex_color, Type type) { |
| 36 | switch (type) { |
| 37 | case RED: |
| 38 | return ((hex_color >> 16) & 0xFF) | 0x01; |
| 39 | case GREEN: |
| 40 | return ((hex_color >> 8) & 0xFF) | 0x01; |
| 41 | case BLUE: |
| 42 | return (hex_color & 0xFF) | 0x01; |
| 43 | } |
| 44 | |
| 45 | LOG(FATAL, "Not sure what color type %d is\n", static_cast<int>(type)); |
| 46 | } |
| 47 | |
| 48 | void LPD8806::operator()() { |
| 49 | // The buffer we're going to send. |
| 50 | // With 64 leds, it takes about 1ms to send them all, which fits within the |
| 51 | // 5ms cycle used by the gyro_reader. |
| 52 | LED buffer[64]; |
| 53 | |
| 54 | while (run_) { |
| 55 | if (next_led_to_send_ < chips_ * 2) { |
| 56 | ::aos::MutexLocker locker(&data_mutex_); |
| 57 | memcpy(buffer, &data_[next_led_to_send_], sizeof(buffer)); |
| 58 | next_led_to_send_ += 64; |
| 59 | } else { |
| 60 | CHECK_EQ(chips_ * 2, next_led_to_send_); |
| 61 | next_led_to_send_ = 0; |
| 62 | memset(buffer, 0, sizeof(buffer)); |
| 63 | } |
| 64 | |
| 65 | // Wait until right after the gyro gets a reading. |
| 66 | ::frc971::sensors::gyro_reading.FetchNextBlocking(); |
| 67 | |
| 68 | int spi_send_result = (spi_->Write( |
| 69 | static_cast<uint8_t *>(static_cast<void *>(buffer)), sizeof(buffer))); |
| 70 | |
| 71 | switch (spi_send_result) { |
| 72 | case -1: |
| 73 | LOG(INFO, "SPI::Write failed\n"); |
| 74 | // Who knows what state it's in now, so start fresh next cycle. |
| 75 | next_led_to_send_ = chips_ * 2; |
| 76 | break; |
| 77 | case sizeof(buffer): |
| 78 | break; |
| 79 | default: |
| 80 | LOG(FATAL, "SPI::Write returned something weird: %d\n", |
| 81 | static_cast<int>(spi_send_result)); |
| 82 | } |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | } // namespace wpilib |
| 87 | } // namespace frc971 |