Skip to content

Commit

Permalink
Test apa102
Browse files Browse the repository at this point in the history
  • Loading branch information
pawelirh committed Sep 4, 2024
1 parent ce92e45 commit aab6fa3
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 69 deletions.
62 changes: 59 additions & 3 deletions panther_lights/include/panther_lights/apa102.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
#ifndef PANTHER_LIGHTS_APA102_HPP_
#define PANTHER_LIGHTS_APA102_HPP_

#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <cstdint>
#include <memory>
#include <string>
Expand All @@ -23,6 +28,50 @@
namespace panther_lights
{

class SPIDeviceInterface
{
public:
virtual ~SPIDeviceInterface() = default;

/**
* @brief Open SPI device
*
* @param device Name of the device
*/
virtual int Open(const std::string & device) = 0;

/**
* @brief Perform an I/O control operation on the device
*
* @param fd File descriptor
* @param request Request code
* @param arg Argument
*/
virtual int IOControl(int fd, unsigned long request, const void * arg) = 0;

/**
* @brief Close the device
*
* @param fd File descriptor
*/
virtual int Close(int fd) = 0;

using SharedPtr = std::shared_ptr<SPIDeviceInterface>;
};

class SPIDevice : public SPIDeviceInterface
{
public:
int Open(const std::string & device) override { return ::open(device.c_str(), O_WRONLY); }

int IOControl(int fd, unsigned long request, const void * arg) override
{
return ::ioctl(fd, request, arg);
}

int Close(int fd) override { return ::close(fd); }
};

class APA102Interface
{
public:
Expand All @@ -40,12 +89,18 @@ class APA102Interface
*
* This class provides methods to control the APA102 LED panel, including setting the global
* brightness, setting the LED panel based on a given frame.
*
* @param spi_device SPI Device object
* @param device_name name of the device
* @param speed Speed of the SPI communication
* @param cs_high Chip select high flag
*/
class APA102 : public APA102Interface
{
public:
APA102(
const std::string & device, const std::uint32_t speed = 800000, const bool cs_high = false);
SPIDeviceInterface::SharedPtr spi_device, const std::string & device_name,
const std::uint32_t speed = 800000, const bool cs_high = false);
~APA102();

/**
Expand Down Expand Up @@ -104,9 +159,10 @@ class APA102 : public APA102Interface
static constexpr std::uint16_t kCorrGreen = 200;
static constexpr std::uint16_t kCorrBlue = 62;

const int fd_;
const std::string device_;
SPIDeviceInterface::SharedPtr spi_device_;
const std::string device_name_;
const std::uint32_t speed_;
const int file_descriptor_;
};

} // namespace panther_lights
Expand Down
46 changes: 23 additions & 23 deletions panther_lights/src/apa102.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@

#include "panther_lights/apa102.hpp"

#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <cmath>
#include <cstdint>
#include <cstring>
Expand All @@ -30,44 +25,49 @@
namespace panther_lights
{

APA102::APA102(const std::string & device, const std::uint32_t speed, const bool cs_high)
: fd_(open(device.c_str(), O_WRONLY)), device_(device), speed_(speed)
APA102::APA102(
SPIDeviceInterface::SharedPtr spi_device, const std::string & device_name,
const std::uint32_t speed, const bool cs_high)
: spi_device_(spi_device),
device_name_(device_name),
speed_(speed),
file_descriptor_(spi_device->Open(device_name))
{
if (fd_ < 0) {
throw std::ios_base::failure("Failed to open " + device_ + ".");
if (file_descriptor_ < 0) {
throw std::ios_base::failure("Failed to open " + device_name_ + ".");
}

static std::uint8_t mode = cs_high ? SPI_MODE_3 : SPI_MODE_3 | SPI_CS_HIGH;
if (ioctl(fd_, SPI_IOC_WR_MODE32, &mode) == -1) {
close(fd_);
throw std::ios_base::failure("Failed to set mode for " + device_ + ".");
if (spi_device_->IOControl(file_descriptor_, SPI_IOC_WR_MODE32, &mode) == -1) {
spi_device_->Close(file_descriptor_);
throw std::ios_base::failure("Failed to set mode for " + device_name_ + ".");
}

if (ioctl(fd_, SPI_IOC_WR_BITS_PER_WORD, &kBits) == -1) {
close(fd_);
throw std::ios_base::failure("Can't set bits per word for " + device_ + ".");
if (spi_device_->IOControl(file_descriptor_, SPI_IOC_WR_BITS_PER_WORD, &kBits) == -1) {
spi_device_->Close(file_descriptor_);
throw std::ios_base::failure("Can't set bits per word for " + device_name_ + ".");
}

if (ioctl(fd_, SPI_IOC_WR_MAX_SPEED_HZ, &speed_) == -1) {
close(fd_);
throw std::ios_base::failure("Can't set speed for " + device_ + ".");
if (spi_device_->IOControl(file_descriptor_, SPI_IOC_WR_MAX_SPEED_HZ, &speed_) == -1) {
spi_device_->Close(file_descriptor_);
throw std::ios_base::failure("Can't set speed for " + device_name_ + ".");
}
}

APA102::~APA102() { close(fd_); }
APA102::~APA102() { spi_device_->Close(file_descriptor_); }

void APA102::SetGlobalBrightness(const float brightness)
{
if (brightness < 0.0f || brightness > 1.0f) {
throw std::out_of_range("Brightness out of range <0.0,1.0>.");
throw std::out_of_range("Brightness out of range [0.0, 1.0].");
}
SetGlobalBrightness(std::uint8_t(ceil(brightness * 31.0f)));
}

void APA102::SetGlobalBrightness(const std::uint8_t brightness)
{
if (brightness > 31) {
throw std::out_of_range("Brightness out of range <0,31>.");
throw std::out_of_range("Brightness out of range [0, 31].");
}
global_brightness_ = std::uint16_t(brightness);
}
Expand Down Expand Up @@ -119,10 +119,10 @@ void APA102::SPISendBuffer(const std::vector<std::uint8_t> & buffer) const
tr.delay_usecs = 0;
tr.bits_per_word = kBits;

const int ret = ioctl(fd_, SPI_IOC_MESSAGE(1), &tr);
const int ret = spi_device_->IOControl(file_descriptor_, SPI_IOC_MESSAGE(1), &tr);

if (ret < 1) {
throw std::ios_base::failure("Failed to send data over SPI " + device_ + ".");
throw std::ios_base::failure("Failed to send data over SPI " + device_name_ + ".");
}
}

Expand Down
4 changes: 2 additions & 2 deletions panther_lights/src/lights_driver_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ LightsDriverNode::LightsDriverNode(const rclcpp::NodeOptions & options)
led_control_granted_(false),
led_control_pending_(false),
initialization_attempt_(0),
channel_1_(std::make_shared<APA102>("/dev/spiled-channel1")),
channel_2_(std::make_shared<APA102>("/dev/spiled-channel2")),
channel_1_(std::make_shared<APA102>(std::make_shared<SPIDevice>(), "/dev/spiled-channel1")),
channel_2_(std::make_shared<APA102>(std::make_shared<SPIDevice>(), "/dev/spiled-channel2")),
diagnostic_updater_(this)
{
RCLCPP_INFO(this->get_logger(), "Constructing node.");
Expand Down
Loading

0 comments on commit aab6fa3

Please sign in to comment.