/*

 * Copyright (c) 2021 Huawei Device Co., Ltd.

 *

 * HDF is dual licensed: you can use it either under the terms of

 * the GPL, or the BSD license, at your option.

 * See the LICENSE file in the root of this repository for complete details.

 */



#include "hdf_encoder.h"

#include "event_hub.h"

#include "gpio_if.h"

#include "hdf_device_desc.h"

#include "hdf_log.h"

#include "osal_mem.h"

#include "osal_timer.h"



#define TIMER_INTERVAL_ENCODER  5



static void EncoderTimerFunc(uintptr_t arg)

{

    int32_t ret;

    EncoderDriver *encoderDrv = (EncoderDriver *)arg;

    uint16_t gpioClk = encoderDrv->encoderCfg->gpioClk;

    uint16_t gpioData = encoderDrv->encoderCfg->gpioData;

    uint16_t gpioSW = encoderDrv->encoderCfg->gpioSW;



    ret = GpioRead(gpioClk, &encoderDrv->encoderClkNowSta);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: gpio read failed, ret %d", __func__, ret);

        return;

    }

    ret = GpioRead(gpioData, &encoderDrv->encoderDataNowSta);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: gpio read failed, ret %d", __func__, ret);

        return;

    }

    ret = GpioRead(gpioSW, &encoderDrv->encoderSWNowSta);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: gpio read failed, ret %d", __func__, ret);

        return;

    }



    if (encoderDrv->encoderClkNowSta != encoderDrv->encoderClkPreSta) {

        if (encoderDrv->encoderClkNowSta == 0) {

            if (encoderDrv->encoderDataNowSta == 1) {

                input_report_rel(encoderDrv->inputDev, REL_WHEEL, 1);

            } else {

                input_report_rel(encoderDrv->inputDev, REL_WHEEL, -1);

            }

            input_sync(encoderDrv->inputDev);

        }

        encoderDrv->encoderClkPreSta = encoderDrv->encoderClkNowSta;

        encoderDrv->encoderDataPreSta  = encoderDrv->encoderDataNowSta;

    }

    if (encoderDrv->encoderSWPreSta != encoderDrv->encoderSWNowSta) {

        if (encoderDrv->encoderSWNowSta == 0) {

            input_report_key(encoderDrv->inputDev, KEY_OK, 0);

        } else {

            input_report_key(encoderDrv->inputDev, KEY_OK, 1);

        }

        encoderDrv->encoderSWPreSta = encoderDrv->encoderSWNowSta;

        input_sync(encoderDrv->inputDev);

    }

}



static EncoderCfg *EncoderConfigInstance(struct HdfDeviceObject *device)

{

    int32_t ret;

    EncoderCfg *encoderCfg = (EncoderCfg *)OsalMemAlloc(sizeof(EncoderCfg));

    if (encoderCfg == NULL) {

        HDF_LOGE("%s: malloc encoder config failed", __func__);

        return NULL;

    }

    ret = memset_s(encoderCfg, sizeof(EncoderCfg), 0, sizeof(EncoderCfg));

    if (ret != 0) {

        HDF_LOGE("%s: memset_s encoder config failed", __func__);

        OsalMemFree(encoderCfg);

        return NULL;

    }

    encoderCfg->hdfEncoderDev = device;



    if (ParseEncoderConfig(device->property, encoderCfg) != HDF_SUCCESS) {

        HDF_LOGE("%s: parse encoder config failed", __func__);

        OsalMemFree(encoderCfg);

        return NULL;

    }

    return encoderCfg;

}



static EncoderDriver *EncoderDriverInstance(EncoderCfg *encoderCfg)

{

    int32_t ret;

    EncoderDriver *encoderDrv = (EncoderDriver *)OsalMemAlloc(sizeof(EncoderDriver));

    if (encoderDrv == NULL) {

        HDF_LOGE("%s: malloc key driver failed", __func__);

        return NULL;

    }

    ret = memset_s(encoderDrv, sizeof(EncoderDriver), 0, sizeof(EncoderDriver));

    if (ret != 0) {

        HDF_LOGE("%s: memset encoder driver failed", __func__);

        OsalMemFree(encoderDrv);

        return NULL;

    }



    encoderDrv->devType = encoderCfg->devType;

    encoderDrv->encoderCfg = encoderCfg;



    return encoderDrv;

}



static int32_t EncoderInit(EncoderDriver *EncoderDrv)

{

    int32_t ret;

    uint16_t gpioClk = EncoderDrv->encoderCfg->gpioClk;

    uint16_t gpioData = EncoderDrv->encoderCfg->gpioData;

    uint16_t gpioSW = EncoderDrv->encoderCfg->gpioSW;

    GpioSetDir(gpioClk, GPIO_DIR_IN);

    GpioSetDir(gpioData, GPIO_DIR_IN);

    GpioSetDir(gpioSW, GPIO_DIR_IN);



    ret = OsalTimerCreate(&EncoderDrv->timer, TIMER_INTERVAL_ENCODER, EncoderTimerFunc, EncoderDrv);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: create timer failed, ret = %d\n", __func__, ret);

        return HDF_FAILURE;

    }

    ret = OsalTimerStartLoop(&EncoderDrv->timer);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: start timer failed, ret = %d\n", __func__, ret);

        return HDF_FAILURE;

    }



    ret = GpioRead(gpioClk, &EncoderDrv->encoderClkNowSta);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: gpio read failed, ret %d", __func__, ret);

        return HDF_FAILURE;

    }

    ret = GpioRead(gpioData, &EncoderDrv->encoderDataNowSta);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: gpio read failed, ret %d", __func__, ret);

        return HDF_FAILURE;

    }

    ret = GpioRead(gpioSW, &EncoderDrv->encoderSWNowSta);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: gpio read failed, ret %d", __func__, ret);

        return HDF_FAILURE;

    }



    EncoderDrv->encoderClkPreSta = EncoderDrv->encoderClkNowSta;

    EncoderDrv->encoderDataPreSta = EncoderDrv->encoderDataNowSta;



    return HDF_SUCCESS;

}



static InputDevice *InputDeviceInstance(EncoderDriver *encoderDrv)

{

    int32_t ret;

    InputDevice *inputDev = (InputDevice *)OsalMemAlloc(sizeof(InputDevice));

    if (inputDev == NULL) {

        HDF_LOGE("%s: malloc input device failed", __func__);

        return NULL;

    }

    ret = memset_s(inputDev, sizeof(InputDevice), 0, sizeof(InputDevice));

    if (ret != 0) {

        HDF_LOGE("%s: memset encoder driver failed", __func__);

        OsalMemFree(inputDev);

        return NULL;

    }



    ret = OsalMutexInit(&inputDev->mutex);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: Init mutex error", __func__);

        OsalMemFree(inputDev);

        return NULL;

    }



    inputDev->pvtData = (void *)encoderDrv;

    inputDev->devType = encoderDrv->devType;

    inputDev->hdfDevObj = encoderDrv->encoderCfg->hdfEncoderDev;

    encoderDrv->inputDev = inputDev;



    return inputDev;

}



static int32_t RegisterEncoderDevice(EncoderCfg *encoderCfg, struct HdfDeviceObject *device)

{

    int32_t ret;

    EncoderDriver *encoderDrv = EncoderDriverInstance(encoderCfg);

    if (encoderDrv == NULL) {

        HDF_LOGE("%s: instance encoder driver failed", __func__);

        return HDF_ERR_MALLOC_FAIL;

    }

    device->priv = (void *)encoderDrv;



    ret = EncoderInit(encoderDrv);

    if (ret != HDF_SUCCESS) {

        HDF_LOGE("%s: key driver init failed, ret %d", __func__, ret);

        goto EXIT;

    }



    InputDevice *inputDev = InputDeviceInstance(encoderDrv);

    if (inputDev == NULL) {

        HDF_LOGE("%s: instance input device failed", __func__);

        goto EXIT;

    }



    ret = RegisterInputDevice(inputDev);

    if (ret != HDF_SUCCESS) {

        goto EXIT1;

    }

    return HDF_SUCCESS;



EXIT1:

    OsalMemFree(inputDev->pkgBuf);

    OsalMemFree(inputDev);

EXIT:

    OsalMemFree(encoderDrv);

    return HDF_FAILURE;

}



static int32_t HdfEnCoderDriverInit(struct HdfDeviceObject *device)

{

    int32_t ret;

    if (device == NULL) {

        HDF_LOGE("%s: param is null", __func__);

        return HDF_ERR_INVALID_PARAM;

    }



    EncoderCfg *encoderCfg = EncoderConfigInstance(device);

    if (encoderCfg == NULL) {

        HDF_LOGE("%s: instance encoder config failed", __func__);

        return HDF_ERR_MALLOC_FAIL;

    }



    ret = RegisterEncoderDevice(encoderCfg, device);

    if (ret != HDF_SUCCESS) {

        goto EXIT;

    }



    HDF_LOGI("%s: exit succ!", __func__);

    return HDF_SUCCESS;



EXIT:

    OsalMemFree(encoderCfg);

    return HDF_FAILURE;

}



static int32_t HdfEnCoderDispatch(struct HdfDeviceIoClient *client, int cmd,

                                  struct HdfSBuf *data, struct HdfSBuf *reply)

{

    (void)cmd;

    if (client == NULL || data == NULL || reply == NULL) {

        HDF_LOGE("%s: param is null", __func__);

        return HDF_FAILURE;

    }

    return HDF_SUCCESS;

}



static void HdfEncoderDriverRelease(struct HdfDeviceObject *device)

{

    EncoderDriver *driver = NULL;

    InputDevice *inputDev = NULL;



    if (device == NULL || device->priv == NULL) {

        HDF_LOGE("%s: param is null", __func__);

        return;

    }

    driver = (EncoderDriver *)device->priv;

    inputDev = driver->inputDev;

    if (inputDev != NULL) {

        UnregisterInputDevice(inputDev);

        driver->inputDev = NULL;

    }

    OsalMemFree(driver);

}



static int32_t HdfEnCoderDriverBind(struct HdfDeviceObject *device)

{

    if (device == NULL) {

        return HDF_ERR_INVALID_PARAM;

    }

    static struct IDeviceIoService enCoderService = {

        .object.objectId = 1,

        .Dispatch = HdfEnCoderDispatch,

    };

    device->service = &enCoderService;

    return HDF_SUCCESS;

}



struct HdfDriverEntry g_hdfEnCoderEntry = {

    .moduleVersion = 1,

    .moduleName = "HDF_ENCODER",

    .Bind = HdfEnCoderDriverBind,

    .Init = HdfEnCoderDriverInit,

    .Release = HdfEncoderDriverRelease,

};



HDF_INIT(g_hdfEnCoderEntry);