Skip to content

Commit

Permalink
✨ (drivers): Add CoreDACTouch
Browse files Browse the repository at this point in the history
  • Loading branch information
MMyster committed Jun 28, 2022
1 parent deee23e commit 05b6441
Show file tree
Hide file tree
Showing 7 changed files with 375 additions and 0 deletions.
3 changes: 3 additions & 0 deletions drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ add_subdirectory(${DRIVERS_DIR}/FastLED)

# Touch drivers
add_subdirectory(${DRIVERS_DIR}/CoreIOExpander)
add_subdirectory(${DRIVERS_DIR}/CoreDACTouch)


28 changes: 28 additions & 0 deletions drivers/CoreDACTouch/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Leka - LekaOS
# Copyright 2022 APF France handicap
# SPDX-License-Identifier: Apache-2.0

add_library(CoreDACTouch STATIC)

target_include_directories(CoreDACTouch
PUBLIC
include
)

target_sources(CoreDACTouch
PRIVATE
source/CoreDACTouch.cpp
)

target_link_libraries(CoreDACTouch
mbed-os
CoreI2C
)

if (${CMAKE_PROJECT_NAME} STREQUAL "LekaOSUnitTests")

leka_unit_tests_sources(
tests/CoreDACTouch_test.cpp
)

endif()
36 changes: 36 additions & 0 deletions drivers/CoreDACTouch/include/CoreDACTouch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Leka - LekaOS
// Copyright 2022 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <array>

#include "external/MCP4728.h"
#include "interface/drivers/DACTouch.h"
#include "interface/drivers/I2C.h"

namespace leka {

class CoreDACTouchMCP4728 : public interface::DACTouch
{
public:
CoreDACTouchMCP4728(interface::I2C &i2c, uint8_t address) : _i2c(i2c), _address(address) {};

void writeToAllInputRegister(std::array<uint8_t, 2> value) final;
void writeToSpecificInputRegister(uint8_t channel, std::array<uint8_t, 2> value) final;
void writeToMemoryRegisterUntilChannelD(uint8_t starting_channel, std::array<uint8_t, 2> value) final;
void writeToSpecificMemoryRegister(uint8_t channel, std::array<uint8_t, 2> value) final;

void writeVoltageReference(uint8_t voltageReference) final;
void writePowerMode(uint8_t powerMode) final;
void writeGain(uint8_t gain) final;

void readMemory(std::array<uint8_t, mcp4728::command::readMemory::size> &value) final;

private:
interface::I2C &_i2c;
uint8_t _address;
};

} // namespace leka
112 changes: 112 additions & 0 deletions drivers/CoreDACTouch/include/external/MCP4728.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Leka - LekaOS
// Copyright 2022 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "cstdint"

namespace leka::mcp4728 {

namespace command {

namespace mask {
inline constexpr auto writeFastMode = uint8_t {0xC0};
inline constexpr auto writeInputAndMemoryRegisters = uint8_t {0xF8};
inline constexpr auto writeSelectionBits = uint8_t {0xF0};

} // namespace mask

inline constexpr auto writeAllInputRegister = uint8_t {0x00};
inline constexpr auto writeSpecificInputRegister = uint8_t {0x40};
inline constexpr auto writeMemoryRegisterUntilChannelD = uint8_t {0x50};
inline constexpr auto writeSpecificMemoryRegister = uint8_t {0x60};
inline constexpr auto writeVoltageReference = uint8_t {0x80};
inline constexpr auto writePowerMode = uint8_t {0xA0};
inline constexpr auto writeGain = uint8_t {0xC0};

namespace readMemory {

inline constexpr auto size = uint8_t {24};
}

} // namespace command

namespace channel {

inline constexpr auto A = uint8_t {0x00};
inline constexpr auto B = uint8_t {0x01};
inline constexpr auto C = uint8_t {0x02};
inline constexpr auto D = uint8_t {0x03};

} // namespace channel

namespace data {

namespace voltage_reference {

inline constexpr auto Vdd = uint8_t {0x00};
namespace internal {
inline constexpr auto channel_A = uint8_t {0x08};
inline constexpr auto channel_B = uint8_t {0x04};
inline constexpr auto channel_C = uint8_t {0x02};
inline constexpr auto channel_D = uint8_t {0x01};
inline constexpr auto all_channel = uint8_t {0x0f};

} // namespace internal

} // namespace voltage_reference

namespace power_mode {

inline constexpr auto normal = uint8_t {0x00};

namespace channel_a {
inline constexpr auto normal = uint8_t {0x00};
inline constexpr auto powerDown1K = uint8_t {0x40};
inline constexpr auto powerDown100K = uint8_t {0x80};
inline constexpr auto powerDown500K = uint8_t {0xC0};
} // namespace channel_a

namespace channel_b {
inline constexpr auto normal = uint8_t {0x00};
inline constexpr auto powerDown1K = uint8_t {0x10};
inline constexpr auto powerDown100K = uint8_t {0x20};
inline constexpr auto powerDown500K = uint8_t {0x30};
} // namespace channel_b

namespace channel_c {
inline constexpr auto normal = uint8_t {0x00};
inline constexpr auto powerDown1K = uint8_t {0x04};
inline constexpr auto powerDown100K = uint8_t {0x08};
inline constexpr auto powerDown500K = uint8_t {0x0C};
} // namespace channel_c

namespace channel_d {
inline constexpr auto normal = uint8_t {0x00};
inline constexpr auto powerDown1K = uint8_t {0x01};
inline constexpr auto powerDown100K = uint8_t {0x02};
inline constexpr auto powerDown500K = uint8_t {0x03};
} // namespace channel_d

} // namespace power_mode

namespace gain {

namespace x1 {
inline constexpr auto all = uint8_t {0x00};
}

namespace x2 {
inline constexpr auto channel_A = uint8_t {0x08};
inline constexpr auto channel_B = uint8_t {0x04};
inline constexpr auto channel_C = uint8_t {0x02};
inline constexpr auto channel_D = uint8_t {0x01};
inline constexpr auto all = uint8_t {0x0f};
} // namespace x2

} // namespace gain

} // namespace data

} // namespace leka::mcp4728
82 changes: 82 additions & 0 deletions drivers/CoreDACTouch/source/CoreDACTouch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Leka - LekaOS
// Copyright 2022 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#include "CoreDACTouch.h"
#include <array>

#include "MemoryUtils.h"

using namespace leka;

void CoreDACTouchMCP4728::writeToAllInputRegister(std::array<uint8_t, 2> value)
{
auto command = std::array<uint8_t, 2> {};
command.at(0) =
static_cast<uint8_t>((mcp4728::command::mask::writeFastMode & mcp4728::command::writeAllInputRegister) |
(~mcp4728::command::mask::writeFastMode & value.at(0)));
command.at(1) = value.at(1);
_i2c.write(_address, command.data(), command.size(), false);
}

void CoreDACTouchMCP4728::writeToSpecificInputRegister(uint8_t channel, std::array<uint8_t, 2> value)
{
auto command = std::array<uint8_t, 3> {};
command.at(0) = static_cast<uint8_t>(
(mcp4728::command::mask::writeInputAndMemoryRegisters & mcp4728::command::writeSpecificInputRegister) |
(~mcp4728::command::mask::writeInputAndMemoryRegisters & ((0x03 & channel) << 1)));
std::copy(value.begin(), value.end(), command.begin() + 1);
_i2c.write(_address, command.data(), command.size(), false);
}

void CoreDACTouchMCP4728::writeToMemoryRegisterUntilChannelD(uint8_t starting_channel, std::array<uint8_t, 2> value)
{
auto command = std::array<uint8_t, 3> {};
command.at(0) = static_cast<uint8_t>(
(mcp4728::command::mask::writeInputAndMemoryRegisters & mcp4728::command::writeMemoryRegisterUntilChannelD) |
(~mcp4728::command::mask::writeInputAndMemoryRegisters & ((0x03 & starting_channel) << 1)));
std::copy(value.begin(), value.end(), command.begin() + 1);
_i2c.write(_address, command.data(), command.size(), false);
}

void CoreDACTouchMCP4728::writeToSpecificMemoryRegister(uint8_t channel, std::array<uint8_t, 2> value)
{
auto command = std::array<uint8_t, 3> {};
command.at(0) = static_cast<uint8_t>(
(mcp4728::command::mask::writeInputAndMemoryRegisters & mcp4728::command::writeSpecificMemoryRegister) |
(~mcp4728::command::mask::writeInputAndMemoryRegisters & ((0x03 & channel) << 1)));
std::copy(value.begin(), value.end(), command.begin() + 1);

_i2c.write(_address, command.data(), command.size(), false);
}

void CoreDACTouchMCP4728::writeVoltageReference(uint8_t voltageReference)
{
auto command =
static_cast<uint8_t>((mcp4728::command::mask::writeSelectionBits & mcp4728::command::writeVoltageReference) |
(~mcp4728::command::mask::writeSelectionBits & voltageReference));
_i2c.write(_address, &command, 1, false);
}

void CoreDACTouchMCP4728::writePowerMode(uint8_t powerMode)
{
auto command = std::array<uint8_t, 2> {};
command.at(0) =
static_cast<uint8_t>((mcp4728::command::mask::writeSelectionBits & mcp4728::command::writePowerMode) |
(~mcp4728::command::mask::writeSelectionBits & (0xF0 & powerMode) >> 4));
command.at(1) = static_cast<uint8_t>((0x0F & powerMode) << 4);

_i2c.write(_address, command.data(), command.size(), false);
}

void CoreDACTouchMCP4728::writeGain(uint8_t gain)
{
auto command = static_cast<uint8_t>((mcp4728::command::mask::writeSelectionBits & mcp4728::command::writeGain) |
(utils::memory::getLowByte(gain)));
_i2c.write(_address, &command, 1, false);
}

void CoreDACTouchMCP4728::readMemory(std::array<uint8_t, mcp4728::command::readMemory::size> &value)
{
_i2c.read(_address, value.data(), value.size(), false);
}
113 changes: 113 additions & 0 deletions drivers/CoreDACTouch/tests/CoreDACTouch_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Leka - LekaOS
// Copyright 2022 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#include "CoreDACTouch.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "mocks/leka/CoreI2C.h"

using namespace leka;

using ::testing::Args;
using ::testing::DoAll;
using ::testing::ElementsAre;
using ::testing::Return;
using ::testing::SetArrayArgument;

class CoreDACTouchTest : public ::testing::Test

{
protected:
// void SetUp() override {}
// void TearDown() override {}

const uint8_t i2c_address {0xC0};
mock::CoreI2C mocki2c;
CoreDACTouchMCP4728 dac {mocki2c, i2c_address};
};

TEST_F(CoreDACTouchTest, initializationDefault)
{
auto new_dac = CoreDACTouchMCP4728 {mocki2c, i2c_address};
ASSERT_NE(&new_dac, nullptr);
}

TEST_F(CoreDACTouchTest, writeToAllInputRegister)
{
auto value_to_write = std::array<uint8_t, 2> {0x0F, 0xA8};

const auto data = ElementsAre(0x0F, 0xA8);
EXPECT_CALL(mocki2c, write).With(Args<1, 2>(data));

dac.writeToAllInputRegister(value_to_write);
}

TEST_F(CoreDACTouchTest, writeToSpecificInputRegister)
{
auto value_to_write = std::array<uint8_t, 2> {0x0F, 0xA8};

const auto data = ElementsAre(0x46, 0x0F, 0xA8);
EXPECT_CALL(mocki2c, write).With(Args<1, 2>(data));

dac.writeToSpecificInputRegister(mcp4728::channel::D, value_to_write);
}

TEST_F(CoreDACTouchTest, writeToMemoryRegisterUntilChannelD)
{
auto value_to_write = std::array<uint8_t, 2> {0xFF, 0xAA};

const auto data = ElementsAre(0x50, 0xFF, 0xAA);
EXPECT_CALL(mocki2c, write).With(Args<1, 2>(data));

dac.writeToMemoryRegisterUntilChannelD(mcp4728::channel::A, value_to_write);
}

TEST_F(CoreDACTouchTest, writeToSpecificMemoryRegister)
{
auto value_to_write = std::array<uint8_t, 2> {0xFF, 0xAA};

const auto data = ElementsAre(0x62, 0xFF, 0xAA);
EXPECT_CALL(mocki2c, write).With(Args<1, 2>(data));

dac.writeToSpecificMemoryRegister(mcp4728::channel::B, value_to_write);
}

TEST_F(CoreDACTouchTest, readMemory)
{
auto data = std::array<uint8_t, 24> {};
auto expected_data = std::array<uint8_t, 24> {0x01, 0x02, 0x03, 0x04};

EXPECT_CALL(mocki2c, read)
.WillOnce(DoAll(SetArrayArgument<1>(begin(expected_data), end(expected_data)), Return(0)));

dac.readMemory(data);

ASSERT_EQ(data, expected_data);
}

TEST_F(CoreDACTouchTest, writeVoltageReference)
{
const auto data = ElementsAre(0x80);
EXPECT_CALL(mocki2c, write).With(Args<1, 2>(data));

dac.writeVoltageReference(mcp4728::data::voltage_reference::Vdd);
}

TEST_F(CoreDACTouchTest, writePowerMode)
{
const auto data = ElementsAre(0xAC, 0x40);
EXPECT_CALL(mocki2c, write).With(Args<1, 2>(data));

dac.writePowerMode(mcp4728::data::power_mode::channel_a::powerDown500K |
mcp4728::data::power_mode::channel_c::powerDown1K);
}

TEST_F(CoreDACTouchTest, writeGain)
{
const auto data = ElementsAre(0xCF);
EXPECT_CALL(mocki2c, write).With(Args<1, 2>(data));

dac.writeGain(mcp4728::data::gain::x2::all);
}
1 change: 1 addition & 0 deletions tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ add_subdirectory(template)
# Register drivers
leka_register_unit_tests_for_driver(CoreBattery)
leka_register_unit_tests_for_driver(CoreBufferedSerial)
leka_register_unit_tests_for_driver(CoreDACTouch)
leka_register_unit_tests_for_driver(CoreEventFlags)
leka_register_unit_tests_for_driver(CoreEventQueue)
leka_register_unit_tests_for_driver(CoreFlashMemory)
Expand Down

0 comments on commit 05b6441

Please sign in to comment.