Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit decd6eb7 authored by Amy's avatar Amy Committed by android-build-merger
Browse files

Merge "Using named pipe as input/output of the CEC hal mock impl" am:...

Merge "Using named pipe as input/output of the CEC hal mock impl" am: 321f443d am: 56cc2ddb am: 568975f0 am: dfe6be6f
am: 10e00fd8

Change-Id: I6dc35dbdc932d462b332779111da770ba8cee082
parents b4aa5a24 10e00fd8
Loading
Loading
Loading
Loading
+173 −12
Original line number Original line Diff line number Diff line
@@ -77,6 +77,7 @@ Return<SendMessageResult> HdmiCecMock::sendMessage(const CecMessage& message) {
    if (message.body.size() == 0) {
    if (message.body.size() == 0) {
        return SendMessageResult::NACK;
        return SendMessageResult::NACK;
    }
    }
    sendMessageToFifo(message);
    return SendMessageResult::SUCCESS;
    return SendMessageResult::SUCCESS;
}
}


@@ -88,6 +89,11 @@ Return<void> HdmiCecMock::setCallback(const sp<IHdmiCecCallback>& callback) {
    if (callback != nullptr) {
    if (callback != nullptr) {
        mCallback = callback;
        mCallback = callback;
        mCallback->linkToDeath(this, 0 /*cookie*/);
        mCallback->linkToDeath(this, 0 /*cookie*/);

        mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR);
        mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR);
        pthread_create(&mThreadId, NULL, __threadLoop, this);
        pthread_setname_np(mThreadId, "hdmi_cec_loop");
    }
    }
    return Void();
    return Void();
}
}
@@ -102,17 +108,8 @@ Return<uint32_t> HdmiCecMock::getVendorId() {
}
}


Return<void> HdmiCecMock::getPortInfo(getPortInfo_cb _hidl_cb) {
Return<void> HdmiCecMock::getPortInfo(getPortInfo_cb _hidl_cb) {
    vector<HdmiPortInfo> portInfos;
    // TODO ready port info from device specific config
    // TODO ready port info from device specific config
    portInfos.resize(mTotalPorts);
    _hidl_cb(mPortInfo);
    for (int i = 0; i < mTotalPorts; ++i) {
        portInfos[i] = {.type = HdmiPortType::INPUT,
                        .portId = static_cast<uint32_t>(i),
                        .cecSupported = true,
                        .arcSupported = (i == 0),
                        .physicalAddress = static_cast<uint16_t>(i << 12)};
    }
    _hidl_cb(portInfos);
    return Void();
    return Void();
}
}


@@ -140,13 +137,177 @@ Return<void> HdmiCecMock::enableAudioReturnChannel(int32_t portId __unused, bool
    return Void();
    return Void();
}
}


Return<bool> HdmiCecMock::isConnected(int32_t portId __unused) {
Return<bool> HdmiCecMock::isConnected(int32_t portId) {
    // maintain port connection status and update on hotplug event
    // maintain port connection status and update on hotplug event
    if (portId < mTotalPorts && portId >= 0) {
        return mPortConnectionStatus[portId];
    }
    return false;
    return false;
}
}


void* HdmiCecMock::__threadLoop(void* user) {
    HdmiCecMock* const self = static_cast<HdmiCecMock*>(user);
    self->threadLoop();
    return 0;
}

int HdmiCecMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
    if (msgCount <= 0 || !buf) {
        return 0;
    }

    int ret = -1;
    /* maybe blocked at driver */
    ret = read(mInputFile, buf, msgCount);
    if (ret < 0) {
        ALOGE("[halimp] read :%s failed, ret:%d\n", CEC_MSG_IN_FIFO, ret);
        return -1;
    }

    return ret;
}

int HdmiCecMock::sendMessageToFifo(const CecMessage& message) {
    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
    int ret = -1;

    memset(msgBuf, 0, sizeof(msgBuf));
    msgBuf[0] = ((static_cast<uint8_t>(message.initiator) & 0xf) << 4) |
                (static_cast<uint8_t>(message.destination) & 0xf);

    size_t length = std::min(static_cast<size_t>(message.body.size()),
                             static_cast<size_t>(MaxLength::MESSAGE_BODY));
    for (size_t i = 0; i < length; ++i) {
        msgBuf[i + 1] = static_cast<unsigned char>(message.body[i]);
    }

    // open the output pipe for writing outgoing cec message
    mOutputFile = open(CEC_MSG_OUT_FIFO, O_WRONLY);
    if (mOutputFile < 0) {
        ALOGD("[halimp] file open failed for writing");
        return -1;
    }

    // write message into the output pipe
    ret = write(mOutputFile, msgBuf, length + 1);
    close(mOutputFile);
    if (ret < 0) {
        ALOGE("[halimp] write :%s failed, ret:%d\n", CEC_MSG_OUT_FIFO, ret);
        return -1;
    }
    return ret;
}

void HdmiCecMock::printCecMsgBuf(const char* msg_buf, int len) {
    char buf[64] = {};
    int i, size = 0;
    memset(buf, 0, sizeof(buf));
    for (i = 0; i < len; i++) {
        size += sprintf(buf + size, " %02x", msg_buf[i]);
    }
    ALOGD("[halimp] %s, msg:%s", __FUNCTION__, buf);
}

void HdmiCecMock::handleHotplugMessage(unsigned char* msgBuf) {
    HotplugEvent hotplugEvent{.connected = ((msgBuf[3]) & 0xf) > 0,
                              .portId = static_cast<uint32_t>(msgBuf[0] & 0xf)};

    if (hotplugEvent.portId >= mPortInfo.size()) {
        ALOGD("[halimp] ignore hot plug message, id %x does not exist", hotplugEvent.portId);
        return;
    }

    ALOGD("[halimp] hot plug port id %x, is connected %x", (msgBuf[0] & 0xf), (msgBuf[3] & 0xf));
    if (mPortInfo[hotplugEvent.portId].type == HdmiPortType::OUTPUT) {
        mPhysicalAddress =
                ((hotplugEvent.connected == 0) ? 0xffff : ((msgBuf[1] << 8) | (msgBuf[2])));
        mPortInfo[hotplugEvent.portId].physicalAddress = mPhysicalAddress;
        ALOGD("[halimp] hot plug physical address %x", mPhysicalAddress);
    }

    // todo update connection status

    if (mCallback != nullptr) {
        mCallback->onHotplugEvent(hotplugEvent);
    }
}

void HdmiCecMock::handleCecMessage(unsigned char* msgBuf, int megSize) {
    CecMessage message;
    size_t length = std::min(static_cast<size_t>(megSize - 1),
                             static_cast<size_t>(MaxLength::MESSAGE_BODY));
    message.body.resize(length);

    for (size_t i = 0; i < length; ++i) {
        message.body[i] = static_cast<uint8_t>(msgBuf[i + 1]);
        ALOGD("[halimp] msg body %x", message.body[i]);
    }

    message.initiator = static_cast<CecLogicalAddress>((msgBuf[0] >> 4) & 0xf);
    ALOGD("[halimp] msg init %x", message.initiator);
    message.destination = static_cast<CecLogicalAddress>((msgBuf[0] >> 0) & 0xf);
    ALOGD("[halimp] msg dest %x", message.destination);

    // messageValidateAndHandle(&event);

    if (mCallback != nullptr) {
        mCallback->onCecMessage(message);
    }
}

void HdmiCecMock::threadLoop() {
    ALOGD("[halimp] threadLoop start.");
    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
    int r = -1;

    // open the input pipe
    while (mInputFile < 0) {
        usleep(1000 * 1000);
        mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY);
    }
    ALOGD("[halimp] file open ok, fd = %d.", mInputFile);

    while (mCecThreadRun) {
        if (!mOptionSystemCecControl) {
            usleep(1000 * 1000);
            continue;
        }

        memset(msgBuf, 0, sizeof(msgBuf));
        // try to get a message from dev.
        // echo -n -e '\x04\x83' >> /dev/cec
        r = readMessageFromFifo(msgBuf, CEC_MESSAGE_BODY_MAX_LENGTH);
        if (r <= 1) {
            // ignore received ping messages
            continue;
        }

        printCecMsgBuf((const char*)msgBuf, r);

        if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
            // the message is a hotplug event
            handleHotplugMessage(msgBuf);
            continue;
        }

        handleCecMessage(msgBuf, r);
    }

    ALOGD("[halimp] thread end.");
    // mCecDevice.mExited = true;
}

HdmiCecMock::HdmiCecMock() {
HdmiCecMock::HdmiCecMock() {
    ALOGE("Opening a virtual HAL for testing and virtual machine.");
    ALOGE("[halimp] Opening a virtual HAL for testing and virtual machine.");
    mCallback = nullptr;
    mPortInfo.resize(mTotalPorts);
    mPortConnectionStatus.resize(mTotalPorts);
    mPortInfo[0] = {.type = HdmiPortType::OUTPUT,
                    .portId = static_cast<uint32_t>(0),
                    .cecSupported = true,
                    .arcSupported = false,
                    .physicalAddress = mPhysicalAddress};
    mPortConnectionStatus[0] = false;
}
}


}  // namespace implementation
}  // namespace implementation
+26 −1
Original line number Original line Diff line number Diff line
@@ -49,6 +49,9 @@ using ::android::hardware::tv::cec::V1_0::OptionKey;
using ::android::hardware::tv::cec::V1_0::Result;
using ::android::hardware::tv::cec::V1_0::Result;
using ::android::hardware::tv::cec::V1_0::SendMessageResult;
using ::android::hardware::tv::cec::V1_0::SendMessageResult;


#define CEC_MSG_IN_FIFO "/dev/cec_in_pipe"
#define CEC_MSG_OUT_FIFO "/dev/cec_out_pipe"

struct HdmiCecMock : public IHdmiCec, public hidl_death_recipient {
struct HdmiCecMock : public IHdmiCec, public hidl_death_recipient {
    HdmiCecMock();
    HdmiCecMock();
    // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
    // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
@@ -71,21 +74,43 @@ struct HdmiCecMock : public IHdmiCec, public hidl_death_recipient {
    }
    }


    void cec_set_option(int flag, int value);
    void cec_set_option(int flag, int value);
    void printCecMsgBuf(const char* msg_buf, int len);

  private:
    static void* __threadLoop(void* data);
    void threadLoop();
    int readMessageFromFifo(unsigned char* buf, int msgCount);
    int sendMessageToFifo(const CecMessage& message);
    void handleHotplugMessage(unsigned char* msgBuf);
    void handleCecMessage(unsigned char* msgBuf, int length);


  private:
  private:
    sp<IHdmiCecCallback> mCallback;
    sp<IHdmiCecCallback> mCallback;

    // Variables for the virtual cec hal impl
    // Variables for the virtual cec hal impl
    uint16_t mPhysicalAddress = 0xFFFF;
    uint16_t mPhysicalAddress = 0xFFFF;
    vector<CecLogicalAddress> mLogicalAddresses;
    vector<CecLogicalAddress> mLogicalAddresses;
    int32_t mCecVersion = 0;
    int32_t mCecVersion = 0;
    uint32_t mCecVendorId = 0;
    uint32_t mCecVendorId = 0;

    // Port configuration
    // Port configuration
    int mTotalPorts = 4;
    int mTotalPorts = 1;
    hidl_vec<HdmiPortInfo> mPortInfo;
    hidl_vec<bool> mPortConnectionStatus;

    // CEC Option value
    // CEC Option value
    int mOptionWakeUp = 0;
    int mOptionWakeUp = 0;
    int mOptionEnableCec = 0;
    int mOptionEnableCec = 0;
    int mOptionSystemCecControl = 0;
    int mOptionSystemCecControl = 0;
    int mOptionLanguage = 0;
    int mOptionLanguage = 0;

    // Testing variables
    // Input file descriptor
    int mInputFile;
    // Output file descriptor
    int mOutputFile;
    bool mCecThreadRun = true;
    pthread_t mThreadId = 0;
};
};
}  // namespace implementation
}  // namespace implementation
}  // namespace V1_0
}  // namespace V1_0