/*

 * Copyright (c) 2024-2025 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 * http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



#include "usb_report_sys_event.h"



#include "hilog_wrapper.h"

#include "usb_config.h"

#include "usb_interface.h"

#include "usb_device.h"

#include "usb_host_manager.h"

#include "usb_endpoint.h"

#include "usb_errors.h"

#include "hisysevent.h"



#ifdef USB_PERIPHERAL_FAULT_NOTIFY

#include "driver_ext_mgr_client.h"

#endif



using namespace OHOS::HiviewDFX;



namespace OHOS {

namespace USB {

constexpr int32_t ERR_CODE_TIMEOUT = -7;



void UsbReportSysEvent::ReportTransferFaultSysEvent(const std::string transferType, UsbDevice &usbDev,

    const HDI::Usb::V1_0::UsbPipe &tmpPipe, int32_t ret, const std::string description)

{

    UsbInterface itIF;

    USB_HILOGI(MODULE_USB_UTILS, "report transfor fault sys event");

    if (!GetUsbInterfaceId(usbDev, tmpPipe, tmpPipe.intfId, itIF)) {

        USB_HILOGE(MODULE_USB_UTILS, "GetUsbConfigs failed");

        return;

    }

    int32_t hiRet = HiSysEventWrite(HiSysEvent::Domain::USB, "TRANSFER_FAULT",

        HiSysEvent::EventType::FAULT, "TRANSFER_TYPE", transferType,

        "VENDOR_ID", usbDev.GetVendorId(), "PRODUCT_ID", usbDev.GetProductId(),

        "INTERFACE_CLASS", itIF.GetClass(), "INTERFACE_SUBCLASS", itIF.GetSubClass(),

        "INTERFACE_PROTOCOL", itIF.GetProtocol(),

        "INTF_ID", tmpPipe.intfId, "ENDPOINTT_ID", tmpPipe.endpointId,

        "FAIL_REASON", ret, "FAIL_DESCRIPTION", description);

    if (hiRet != UEC_OK) {

        USB_HILOGE(MODULE_USB_UTILS, "HiSysEventWrite ret: %{public}d", hiRet);

    }



#ifdef USB_PERIPHERAL_FAULT_NOTIFY

    ExternalDeviceManager::DriverExtMgrClient::GetInstance().NotifyUsbPeripheralFault(

        HiSysEvent::Domain::USB, "TRANSFOR_FAULT"); // "TRANSFOR" in external_device code

#endif

}



void UsbReportSysEvent::CheckAttributeReportTransferFaultSysEvent(const std::string transferType,

    UsbDevice &usbDev, const HDI::Usb::V1_0::UsbPipe &tmpPipe, const USBEndpoint &ep,

    int32_t ret, const std::string description)

{

    UsbInterface itIF;

    USB_HILOGI(MODULE_USB_UTILS, "report transfor fault sys event");

    if (ep.GetAttributes() == 0x03 && ret == ERR_CODE_TIMEOUT) {

        USB_HILOGE(MODULE_USB_UTILS, "submitTransfer is timeout");

        return;

    }

    if (!GetUsbInterfaceId(usbDev, tmpPipe, tmpPipe.intfId, itIF)) {

        USB_HILOGE(MODULE_USB_UTILS, "GetUsbConfigs failed");

        return;

    }

    int32_t hiRet = HiSysEventWrite(HiSysEvent::Domain::USB, "TRANSFER_FAULT",

        HiSysEvent::EventType::FAULT, "TRANSFER_TYPE", transferType,

        "VENDOR_ID", usbDev.GetVendorId(), "PRODUCT_ID", usbDev.GetProductId(),

        "INTERFACE_CLASS", itIF.GetClass(), "INTERFACE_SUBCLASS", itIF.GetSubClass(),

        "INTERFACE_PROTOCOL", itIF.GetProtocol(),

        "INTF_ID", tmpPipe.intfId, "ENDPOINTT_ID", tmpPipe.endpointId,

        "FAIL_REASON", ret, "FAIL_DESCRIPTION", description);

    if (hiRet != UEC_OK) {

        USB_HILOGE(MODULE_USB_UTILS, "HiSysEventWrite ret: %{public}d", hiRet);

    }



#ifdef USB_PERIPHERAL_FAULT_NOTIFY

    ExternalDeviceManager::DriverExtMgrClient::GetInstance().NotifyUsbPeripheralFault(

        HiSysEvent::Domain::USB, "TRANSFOR_FAULT"); // "TRANSFOR" in external_device code

#endif

}



bool UsbReportSysEvent::GetUsbInterfaceId(UsbDevice &usbDev, const HDI::Usb::V1_0::UsbPipe &tmpPipe,

    int32_t interfaceId, UsbInterface &itIF)

{

    if (tmpPipe.intfId == 0 && tmpPipe.endpointId == 0) {

        itIF.SetClass(usbDev.GetClass());

        itIF.SetSubClass(usbDev.GetSubclass());

        itIF.SetProtocol(usbDev.GetProtocol());

        return true;

    }



    auto configs = usbDev.GetConfigs();

    for (auto &config : configs) {

        std::vector<UsbInterface> interfaces = config.GetInterfaces();

        for (auto &interface : interfaces) {

            if (interface.GetId() == interfaceId) {

                itIF = interface;

                return true;

            }

        }

    }

    return false;

}

} // OHOS

} // USB