Skip to content

RDKEMW-17873: HDMI-CEC Polaris HAL Migration#57

Open
IshvarKR wants to merge 9 commits into
support/AIDLfrom
feature/factoryImpl
Open

RDKEMW-17873: HDMI-CEC Polaris HAL Migration#57
IshvarKR wants to merge 9 commits into
support/AIDLfrom
feature/factoryImpl

Conversation

@IshvarKR

@IshvarKR IshvarKR commented Jun 2, 2026

Copy link
Copy Markdown

No description provided.

Comment thread ccec/src/factoryImpl/HDMICecHalFactory.h Outdated
Comment thread ccec/src/factoryImpl/HDMICecHalFactory.cpp Outdated

@apatel859 apatel859 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you cimpile this code in normal build and vdevice build and see if you face any compilation issue?

@Sid2001-maker Sid2001-maker force-pushed the feature/factoryImpl branch 2 times, most recently from 876022c to 1c009ec Compare June 3, 2026 09:34
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@IshvarKR IshvarKR force-pushed the feature/factoryImpl branch from 02757ea to ba51587 Compare June 9, 2026 10:51
@vinodtel vinodtel marked this pull request as ready for review June 9, 2026 16:55
@vinodtel vinodtel requested a review from a team as a code owner June 9, 2026 16:55
Copilot AI review requested due to automatic review settings June 9, 2026 16:55
@vinodtel vinodtel changed the title Feature/factory impl VDevice : HDMI-CEC Middleware component Jun 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a HAL abstraction + factory to switch the CCEC driver between a legacy C HAL backend (vHAL) and an Android Binder/AIDL backend (AidlHAL), and updates the build to produce/link the new backend libraries.

Changes:

  • Added HDMICecHal interface and HDMICecHalFactory to select AIDL vs legacy backend at runtime.
  • Implemented vHAL (legacy C driver wrapper) and AidlHAL (binder/AIDL implementation).
  • Updated DriverImpl to route all HAL operations through the new interface; updated Makefiles to build/link backend shared libraries.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
ccec/src/Makefile.am Builds libvHAL.la + libAidlHAL.la and links them into libRCEC.la.
ccec/src/Makefile Builds libvHAL.so + libAidlHAL.so and links them into libRCEC.so; adds binder/AIDL include/link plumbing.
ccec/src/factoryImpl/HDMICecHal.h New abstract HAL interface used by DriverImpl.
ccec/src/factoryImpl/HDMICecHalFactory.h Declares factory for backend selection.
ccec/src/factoryImpl/HDMICecHalFactory.cpp Implements backend selection via binder service discovery.
ccec/src/factoryImpl/vHAL.h Declares legacy backend wrapper.
ccec/src/factoryImpl/vHAL.cpp Implements legacy backend wrapper via HdmiCec* C APIs.
ccec/src/factoryImpl/AidlHAL.h Declares AIDL/binder backend.
ccec/src/factoryImpl/AidlHAL.cpp Implements AIDL/binder backend + poll ACK emulation + frame length filtering.
ccec/src/DriverImpl.hpp Stores std::unique_ptr<HDMICecHal> for the selected backend.
ccec/src/DriverImpl.cpp Uses HDMICecHal for open/close/read/write operations and AIDL-specific behaviors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ccec/src/DriverImpl.cpp Outdated
Comment thread ccec/src/DriverImpl.cpp Outdated
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/factoryImpl/AidlHAL.cpp Outdated
Comment thread ccec/src/Makefile
Comment thread ccec/src/factoryImpl/HDMICecHal.h Outdated
Comment thread ccec/src/factoryImpl/AidlHAL.cpp Outdated
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Copilot AI review requested due to automatic review settings June 11, 2026 09:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 11 comments.

Comment thread ccec/src/factoryImpl/IHDMICecHal.h
Comment thread ccec/src/factoryImpl/HDMICecHalFactory.cpp Outdated
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/Makefile.am Outdated
Comment thread ccec/src/Makefile.am Outdated
Comment thread ccec/src/Makefile.am Outdated
Comment thread ccec/src/Makefile Outdated
Comment thread ccec/src/Makefile Outdated
Copilot AI review requested due to automatic review settings June 11, 2026 11:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 9 comments.

Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/DriverImpl.cpp Outdated
Comment thread ccec/src/DriverImpl.cpp Outdated
Comment thread ccec/src/Makefile.am Outdated
Comment thread ccec/src/Makefile
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.h
Comment thread ccec/src/factoryImpl/HDMICecHalFactory.cpp
Copilot AI review requested due to automatic review settings June 15, 2026 10:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Comment thread ccec/src/factoryImpl/HDMICecHalFactory.cpp
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp Outdated
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp Outdated
Comment thread ccec/src/Makefile.am Outdated
@vinodtel vinodtel force-pushed the feature/factoryImpl branch from fe826af to 0982342 Compare June 18, 2026 18:36
Copilot AI review requested due to automatic review settings June 18, 2026 18:47
@vinodtel vinodtel force-pushed the feature/factoryImpl branch from 0982342 to f4eeb3a Compare June 18, 2026 18:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 12 comments.

Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp Outdated
Comment on lines +377 to +380
if(emulateAckForPollFrames(buf, length)) {
*result = 0; // HDMI_CEC_IO_SUCCESS
return 0;
}
Comment on lines +61 to +68
android::binder::Status onMessageSent(const std::vector<uint8_t>& message, SendMessageStatus status) override {
if (mAidlHal) {
int result = (status == SendMessageStatus::ACK_STATE_0) ? 1 :
(status == SendMessageStatus::ACK_STATE_1) ? 2 : 3;
mAidlHal->dispatchTx(result);
}
return android::binder::Status::ok();
}
Comment on lines +390 to +399
// Map AIDL SendMessageStatus to HAL error codes
*result = 0; // HDMI_CEC_IO_SUCCESS
if (sendStatus == SendMessageStatus::ACK_STATE_0) {
*result = 1; // HDMI_CEC_IO_SENT_AND_ACKD
} else if (sendStatus == SendMessageStatus::ACK_STATE_1) {
*result = 2; // HDMI_CEC_IO_SENT_BUT_NOT_ACKD
} else if (sendStatus == SendMessageStatus::BUSY){
*result = 3; // HDMI_CEC_IO_SENT_FAILED
throw IOException();
}
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp Outdated
Comment on lines +267 to +270
CCEC_LOG(LOG_WARN,
"DriverImpl::getLogicalAddress no allocated LA from AIDL (statusOk=%d, count=%zu). Trying fallback allocation.\r\n",
status.isOk() ? 1 : 0,
addresses.size());
Comment on lines +82 to +86
// Macro definitions for internal use
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
#define BINDER_WRITE_READ_V7 _IOWR('b', 1, struct binder_write_read_v7)
#define BC_TRANSACTION_V7 _IOW('c', 0, struct binder_transaction_data_v7)

Comment on lines +239 to +241
const size_t binder_map_size = (version.protocol_version == 7) ? BINDER_MMAP_SIZE_V7 : BINDER_MMAP_SIZE_V8;
void* const mapped_mem = mmap(nullptr, binder_map_size, PROT_READ, MAP_PRIVATE, binder_fd, 0);
if (mapped_mem == MAP_FAILED) {
Comment thread ccec/src/Makefile
Comment on lines +74 to +83
# Binder libraries - link if they exist
ifneq ($(wildcard $(BINDER_BUILD_DIR)/libbinder.a),)
LDFLAGS += -L$(BINDER_BUILD_DIR) -lbinder
endif
ifneq ($(wildcard $(BINDER_BUILD_DIR)/libutils.a),)
LDFLAGS += -L$(BINDER_BUILD_DIR) -lutils
endif
ifneq ($(wildcard $(BINDER_BUILD_DIR)/liblog.a),)
LDFLAGS += -L$(BINDER_BUILD_DIR) -llog
endif
Comment thread ccec/src/Makefile
Comment on lines +38 to +48
# Calculate AIDL include path relative to workspace
AIDL_GEN_DIR := $(shell cd ../../.. && pwd)/aidl/rdk-halif-aidl/gen/hdmicec/current
AIDL_H_DIR := $(AIDL_GEN_DIR)/h
BINDER_IDL_DIR := $(shell cd ../../.. && pwd)/aidl/rdk-halif-aidl/build-tools/linux_binder_idl
BINDER_INCLUDE := $(BINDER_IDL_DIR)/android/native/libs/binder/include
BINDER_NDK_INCLUDE := $(BINDER_IDL_DIR)/android/native/libs/binder/ndk/include_cpp
BINDER_UTILS_INCLUDE := $(BINDER_IDL_DIR)/android/core/libutils/include
BINDER_CUTILS_INCLUDE := $(BINDER_IDL_DIR)/android/core/libcutils/include
BINDER_LOG_INCLUDE := $(BINDER_IDL_DIR)/android/logging/liblog/include
BINDER_BASE_INCLUDE := $(BINDER_IDL_DIR)/android/libbase/include
BINDER_BUILD_DIR := $(BINDER_IDL_DIR)/aidl-generator/out
Comment thread ccec/src/DriverImpl.cpp
Comment on lines 86 to 89
DriverImpl::DriverImpl() : status(CLOSED), nativeHandle(0)
{
mHal = HDMICecHalFactory::Create();
CCEC_LOG( LOG_DEBUG, "Creating DriverImpl done\r\n");
@IshvarKR IshvarKR force-pushed the feature/factoryImpl branch from 93e20d3 to 9e492e8 Compare June 19, 2026 06:09
Comment thread ccec/src/factoryImpl/HDMICecRdkVHAL.cpp Outdated
* -------------------------------------------------------------------- */
int HDMICecRdkVHAL::txAsync(int handle, const unsigned char *buf, int len)
{
CCEC_LOG(LOG_INFO, "HDMICecRdkVHAL::txAsync handle=%d len=%d\r\n", handle, len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can combine two logs to one for all the APIs

Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp Outdated
status.isOk() ? 1 : 0,
addresses.size());
if (mAidlController != nullptr) {
const std::vector<int32_t> preferred = preferredLogicalAddressesForDeviceType(*logicalAddress);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass correct device type

Copilot AI review requested due to automatic review settings June 22, 2026 05:18
Comment thread ccec/src/factoryImpl/HDMICecRdkVHAL.cpp Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 11 comments.

Comment thread ccec/src/factoryImpl/HDMICecRdkVHAL.cpp Outdated
Comment on lines +138 to +139
CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::getPhysicalAddress handle=%d ret=%d addr=0x%x\r\n",
ret, (physicalAddress ? *physicalAddress : 0));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix Copilot comments

Comment on lines +61 to +68
android::binder::Status onMessageSent(const std::vector<uint8_t>& message, SendMessageStatus status) override {
if (mAidlHal) {
int result = (status == SendMessageStatus::ACK_STATE_0) ? 1 :
(status == SendMessageStatus::ACK_STATE_1) ? 2 : 3;
mAidlHal->dispatchTx(result);
}
return android::binder::Status::ok();
}
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp Outdated
Comment on lines +390 to +398
*result = 0; // HDMI_CEC_IO_SUCCESS
if (sendStatus == SendMessageStatus::ACK_STATE_0) {
*result = 1; // HDMI_CEC_IO_SENT_AND_ACKD
} else if (sendStatus == SendMessageStatus::ACK_STATE_1) {
*result = 2; // HDMI_CEC_IO_SENT_BUT_NOT_ACKD
} else if (sendStatus == SendMessageStatus::BUSY){
*result = 3; // HDMI_CEC_IO_SENT_FAILED
throw IOException();
}
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment on lines +270 to +272
if (mAidlController != nullptr) {
const std::vector<int32_t> preferred = preferredLogicalAddressesForDeviceType(*logicalAddress);
for (std::vector<int32_t>::const_iterator it = preferred.begin(); it != preferred.end(); ++it) {
Comment on lines +82 to +85
// Macro definitions for internal use
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
#define BINDER_WRITE_READ_V7 _IOWR('b', 1, struct binder_write_read_v7)
#define BC_TRANSACTION_V7 _IOW('c', 0, struct binder_transaction_data_v7)
CCEC_LOG(LOG_INFO, "[+] Binder protocol version detected: %d\n", version.protocol_version);

const size_t binder_map_size = (version.protocol_version == 7) ? BINDER_MMAP_SIZE_V7 : BINDER_MMAP_SIZE_V8;
void* const mapped_mem = mmap(nullptr, binder_map_size, PROT_READ, MAP_PRIVATE, binder_fd, 0);
Comment thread ccec/src/Makefile.am
Comment on lines +36 to +39
factoryImpl/HDMICecHalFactory.cpp \
factoryImpl/HDMICecRdkVHAL.cpp \
factoryImpl/HDMICecAidlHAL.cpp \
factoryImpl/ServiceManagerCheck.cpp
Comment thread ccec/src/Makefile
Comment on lines +74 to +83
# Binder libraries - link if they exist
ifneq ($(wildcard $(BINDER_BUILD_DIR)/libbinder.a),)
LDFLAGS += -L$(BINDER_BUILD_DIR) -lbinder
endif
ifneq ($(wildcard $(BINDER_BUILD_DIR)/libutils.a),)
LDFLAGS += -L$(BINDER_BUILD_DIR) -lutils
endif
ifneq ($(wildcard $(BINDER_BUILD_DIR)/liblog.a),)
LDFLAGS += -L$(BINDER_BUILD_DIR) -llog
endif
Comment thread ccec/src/DriverImpl.cpp
Comment on lines 86 to 89
DriverImpl::DriverImpl() : status(CLOSED), nativeHandle(0)
{
mHal = HDMICecHalFactory::Create();
CCEC_LOG( LOG_DEBUG, "Creating DriverImpl done\r\n");
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp Outdated
Comment thread ccec/src/DriverImpl.cpp
}

int err = HdmiCecOpen(&nativeHandle);
int err = mHal->open(&nativeHandle);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add NULL check for mHal wherever it is used

Comment thread ccec/src/factoryImpl/HDMICecRdkVHAL.cpp Outdated
Comment on lines +138 to +139
CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::getPhysicalAddress handle=%d ret=%d addr=0x%x\r\n",
ret, (physicalAddress ? *physicalAddress : 0));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix Copilot comments

Comment thread ccec/src/factoryImpl/HDMICecRdkVHAL.cpp Fixed
Copilot AI review requested due to automatic review settings June 23, 2026 08:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.

Comment on lines +46 to +57
class HalFactoryUtility {
enum class BackendType {
UNKNOWN,
LEGACY,
AIDL
};

static BackendType mBackendType;

bool isAidlServiceAvailable(const android::String16 &expectedServiceName)
{
CCEC_LOG(LOG_INFO, "isAidlServiceAvailable invoked\r\n");
{
CCEC_LOG(LOG_INFO, "HDMICecHalFactory::Create invoked\r\n");

if (HalFactoryUtility::isAidlServiceAvailable(IHdmiCec::serviceName().c_str())) {
Comment on lines +239 to +242
const size_t binder_map_size = (version.protocol_version == 7) ? BINDER_MMAP_SIZE_V7 : BINDER_MMAP_SIZE_V8;
void* const mapped_mem = mmap(nullptr, binder_map_size, PROT_READ, MAP_PRIVATE, binder_fd, 0);
if (mapped_mem == MAP_FAILED) {
CCEC_LOG(LOG_ERROR, "[-] Shared address space context instantiation failed\n");
Comment thread ccec/src/factoryImpl/HDMICecRdkVHAL.cpp Outdated
Comment on lines +139 to +140
CCEC_LOG(LOG_DEBUG, "HDMICecRdkVHAL::getPhysicalAddress handle=%d ret=%d addr=0x%x\r\n",
ret, (physicalAddress ? *physicalAddress : 0));
Comment thread ccec/src/factoryImpl/HDMICecAidlHAL.cpp
Comment on lines +304 to +313
int HDMICecAidlHAL::getPhysicalAddress(int handle, unsigned int *physicalAddress)
{
if (physicalAddress != nullptr) {
*physicalAddress = 0;
}

CCEC_LOG( LOG_DEBUG, "HDMICecAidlHAL::getPhysicalAddress completed\r\n");

return 0;
}
Comment thread ccec/src/Makefile.am
Comment on lines +36 to 41
factoryImpl/HDMICecHalFactory.cpp \
factoryImpl/HDMICecRdkVHAL.cpp \
factoryImpl/HDMICecAidlHAL.cpp \
factoryImpl/ServiceManagerCheck.cpp

libRCEC_la_LDFLAGS = -lpthread
Copilot AI review requested due to automatic review settings June 23, 2026 11:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.

Comment thread ccec/src/Makefile.am
Comment on lines +36 to +39
factoryImpl/HDMICecHalFactory.cpp \
factoryImpl/HDMICecRdkVHAL.cpp \
factoryImpl/HDMICecAidlHAL.cpp \
factoryImpl/ServiceManagerCheck.cpp
CCEC_LOG(LOG_INFO, "[+] Binder protocol version detected: %d\n", version.protocol_version);

const size_t binder_map_size = (version.protocol_version == 7) ? BINDER_MMAP_SIZE_V7 : BINDER_MMAP_SIZE_V8;
void* const mapped_mem = mmap(nullptr, binder_map_size, PROT_READ, MAP_PRIVATE, binder_fd, 0);
Comment on lines +82 to +85
// Macro definitions for internal use
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
#define BINDER_WRITE_READ_V7 _IOWR('b', 1, struct binder_write_read_v7)
#define BC_TRANSACTION_V7 _IOW('c', 0, struct binder_transaction_data_v7)
Comment on lines +150 to +155
bwr.write_size = write_size;
bwr.write_consumed = 0;
bwr.write_buffer = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(tx.write_payload.data()));
bwr.read_size = read_size;
bwr.read_consumed = 0;
bwr.read_buffer = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(tx.read_payload.data()));
Comment on lines +463 to +473
/* Probe with a 2-byte directed frame (GiveDevicePowerStatus) */
{
AutoLock lock_(mAidlMutex);
std::vector<uint8_t> probe;
probe.reserve(2);
probe.push_back(buf ? buf[0] : 0);
probe.push_back(0x8F); // GiveDevicePowerStatus

SendMessageStatus probeStatus = SendMessageStatus::BUSY;
android::binder::Status aidlStatus = mAidlController->sendMessage(probe, &probeStatus);
if (aidlStatus.isOk() && probeStatus == SendMessageStatus::ACK_STATE_0) {
Comment on lines +154 to +159
/**
* @brief Get the physical address of the device.
*
* Legacy: calls HdmiCecGetPhysicalAddress().
* AIDL: queries the physical address via binder.
*
Comment on lines +139 to +147
std::unique_ptr<IHDMICecHal> HDMICecHalFactory::Create()
{
CCEC_LOG(LOG_INFO, "HDMICecHalFactory::Create invoked\r\n");

try {
if (HalFactoryUtility::isAidlServiceAvailable(android::String16(IHdmiCec::serviceName().c_str()))) {
CCEC_LOG(LOG_INFO, "HDMICecHalFactory: Aidl Service is available — using HDMICecAidlHAL\r\n");
return std::make_unique<HDMICecAidlHAL>();
}
@anand-ky anand-ky changed the title VDevice : HDMI-CEC Middleware component RDKEMW-17873: HDMI-CEC Polaris HAL Migration Jun 24, 2026
@vinodtel

Copy link
Copy Markdown

I have read the CLA Document and I hereby sign the CLA.

@vinodtel vinodtel changed the base branch from develop to support/AIDL June 26, 2026 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants