/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "AP_Notify/AP_Notify.h"
#include "ProfiLED.h"
#include "SRV_Channel/SRV_Channel.h"
#include
#include
// This limit is from the dshot driver rc out groups limit, we need at least one channel for clock
#define AP_NOTIFY_ProfiLED_MAX_INSTANCES 3
#define ProfiLED_LOW 0x33
#define ProfiLED_MEDIUM 0x7F
#define ProfiLED_HIGH 0xFF
#define ProfiLED_OFF 0x00
extern const AP_HAL::HAL& hal;
ProfiLED::ProfiLED() :
SerialLED(ProfiLED_OFF, ProfiLED_HIGH, ProfiLED_MEDIUM, ProfiLED_LOW)
{
}
uint16_t ProfiLED::init_ports()
{
uint16_t mask = 0;
for (uint16_t i=0; iset_num_profiled(chan+1, (pNotify->get_led_len()));
}
}
return mask;
}
ProfiLED_SPI::ProfiLED_SPI() :
RGBLed(ProfiLED_OFF, ProfiLED_HIGH, ProfiLED_MEDIUM, ProfiLED_LOW) {}
bool ProfiLED_SPI::init()
{
num_leds = pNotify->get_led_len() + 1; // for some reason we have to send an additional LED data
rgb = new ProfiLED_SPI::RGB[num_leds];
if (!rgb) {
return false;
}
memset(rgb, 0, num_leds * sizeof(ProfiLED_SPI::RGB));
_dev = std::move(hal.spi->get_device("profiled"));
if (!_dev) {
return false;
}
WITH_SEMAPHORE(_dev->get_semaphore());
_dev->register_periodic_callback(10000, FUNCTOR_BIND_MEMBER(&ProfiLED_SPI::_timer, void));
_need_update = true;
GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Initialised ProfiLED over SPIs");
return true;
}
void ProfiLED_SPI::rgb_set_id(uint8_t red, uint8_t green, uint8_t blue, uint8_t id)
{
if (id >= num_leds) {
return;
}
rgb[id] = {blue, red, green};
_need_update = true;
}
bool ProfiLED_SPI::hw_set_rgb(uint8_t red, uint8_t green, uint8_t blue)
{
for (uint16_t i = 0; i < num_leds; i++) {
rgb[i] = {blue, red, green};
}
_need_update = true;
return true;
}
void ProfiLED_SPI::_timer(void)
{
_need_update = false;
update_led_strip();
}
void ProfiLED_SPI::update_led_strip() {
const uint32_t min_bits = num_leds*25+50;
const uint8_t num_leading_zeros = 8-min_bits%8 + 50;
const uint32_t output_stream_byte_length = (min_bits+7)/8;
WITH_SEMAPHORE(_dev->get_semaphore());
uint32_t curr_led_idx = 0;
uint8_t send_buf[32];
uint8_t send_buf_len = 0;
union {
ProfiLED_SPI::RGB struct_val;
uint8_t bytes_val[3];
} curr_led_color;
curr_led_color.struct_val = rgb[curr_led_idx];
for (uint32_t i=0; i> (8-in_bit_idx%8)) & 1;
}
byte |= bit_val << (7-bit);
}
send_buf[send_buf_len++] = byte;
if (send_buf_len >= 32) {
_dev->transfer(send_buf, send_buf_len, NULL, 0);
send_buf_len = 0;
}
}
if (send_buf_len > 0) {
_dev->transfer(send_buf, send_buf_len, NULL, 0);
send_buf_len = 0;
}
}