#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdarg.h>
#include <inttypes.h>
#include <ctype.h>
#include "lux_json_api.h"
#include "lux_system_api.h"
#include "pre_heat.h"
#include <dbus/dbus.h>
#include <stddef.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>


SFscInfo psFscInfo;
INT8U g_u8FSCPresent = FALSE;
INT8U g_u8FSCEnable = 0;

SFscFanReg sSFscFanReg[MAX_DIMM_SLOT] = 
{
    {0,         0x0069},
    {1,         0x0068},
    {2,         0x0067},
    {3,         0x0066},
    {4,         0x0065},
    {5,         0x0064},
    {6,         0x005e},
    {7,         0x005f},
    {8,         0x0060},
    {9,         0x0061},
    {10,         0x0062},
    {11,         0x0063},
    {12,         0x005d},
    {13,         0x005c},
    {14,         0x005b},
    {15,         0x005a},
    {16,         0x0059},
    {17,         0x0058},
    {18,         0x0052},
    {19,         0x0053},
    {20,         0x0054},
    {21,         0x0055},
    {22,         0x0056},
    {23,         0x0057},
};
    

SFscHeatReg sSFscHeatReg[MAX_DIMM_SLOT] = 
{
    {0,         0x008d},
    {1,         0x008c},
    {2,         0x008b},
    {3,         0x008a},
    {4,         0x0089},
    {5,         0x0088},
    {6,         0x0082},
    {7,         0x0083},
    {8,         0x0084},
    {9,         0x0085},
    {10,         0x0086},
    {11,         0x0087},
    {12,         0x0081},
    {13,         0x0080},
    {14,         0x007f},
    {15,         0x007e},
    {16,         0x007d},
    {17,         0x007c},
    {18,         0x0076},
    {19,         0x0077},
    {20,         0x0078},
    {21,         0x0079},
    {22,         0x007a},
    {23,         0x007b},
};

#if 0
SFsc6056FanReg sFsc6056FanReg[FCB_6056_FAN_NUM] = 
{
    {0,         0x008f},
    {1,         0x0090},
    {2,         0x0091},
    {3,         0x0092},
};
#endif

SFsc6056FanReg sFsc6056FanReg[FCB_6056_FAN_NUM] = 
{
    {0,         0x0092},
    {1,         0x0091},
    {2,         0x0090},
    {3,         0x008f},
};

SDIMMDbus sSDIMMDbus[MAX_DIMM_SLOT] = 
{
    {0,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_A_Temp"},
    {1,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_B_Temp"},
    {2,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_C_Temp"},
    {3,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_D_Temp"},
    {4,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_E_Temp"},
    {5,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_F_Temp"},
    {6,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_G_Temp"},
    {7,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_H_Temp"},
    {8,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_I_Temp"},
    {9,         "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_J_Temp"},
    {10,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_K_Temp"},
    {11,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU0_L_Temp"},
    {12,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_A_Temp"},
    {13,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_B_Temp"},
    {14,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_C_Temp"},
    {15,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_D_Temp"},
    {16,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_E_Temp"},
    {17,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_F_Temp"},
    {18,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_G_Temp"},
    {19,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_H_Temp"},
    {20,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_I_Temp"},
    {21,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_J_Temp"},
    {22,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_K_Temp"},
    {23,        "/xyz/openbmc_project/sensors/temperature/DIMM_CPU1_L_Temp"},
};

SDIMMPowerDbus sSDIMMPowerDbus[MAX_DIMM_POWER_SLOT] = 
{
    {0,         "/xyz/openbmc_project/sensors/power/DDR0_Power"},
    {1,         "/xyz/openbmc_project/sensors/power/DDR1_Power"},
    {2,         "/xyz/openbmc_project/sensors/power/DDR2_Power"},
    {3,         "/xyz/openbmc_project/sensors/power/DDR3_Power"},
};


SCPUDbus sSCPUDbus[2] = 
{
    {0,         "/xyz/openbmc_project/sensors/temperature/CPU0_Temp"},
    {1,         "/xyz/openbmc_project/sensors/temperature/CPU1_Temp"},
};

EFuncRetCode check_dbus_error(DBusError *error) 
{
    if (dbus_error_is_set(error))
    {
        //LuxPrintf("D-Bus Error: %s\n", error->message);
        dbus_error_free(error);
        return FUNC_FAILED;
    }
}

EFuncRetCode i2cReadWrite(INT8U bus, INT8U slaveAddr,
                        INT8U* writeData, INT8U writelen,
                        INT8U* readData, INT8U readlen) 
{
    char busPath[32] = {0};
    struct i2c_msg messages[2];
    struct i2c_rdwr_ioctl_data ioctl_data;

    LuxSprintf(busPath, "/dev/i2c-%d", bus);
    int fd = open(busPath, O_RDWR);
    if (fd < 0) 
    {
        return FUNC_FAILED;
    }

    if (writelen > 0) 
    {
        messages[0].addr = slaveAddr;
        messages[0].flags = 0;
        messages[0].len = writelen;
        messages[0].buf = writeData;
    }
    if (readlen > 0) 
    {
        messages[1].addr = slaveAddr;
        messages[1].flags = I2C_M_RD;
        messages[1].len = readlen;
        messages[1].buf = readData;
    }
    ioctl_data.msgs = messages;
    ioctl_data.nmsgs = (writelen == 0 ? 0 : 1) + (readlen > 0 ? 1 : 0);
    if (ioctl(fd, I2C_RDWR, &ioctl_data) < 0) 
    {
        close(fd);
        return FUNC_FAILED;
    }

    close(fd);
    return FUNC_OK;
}


EFuncRetCode LuxFSCDbusGetDIMMValue(char* pcDbusPatch, INT8S* ps8Value, INT8U* pu8Present, INT8U* pu8Status)
{
    const char *bus_name = "xyz.openbmc_project.DIMMTempSensor";
    const char *path = pcDbusPatch;
    const char *iface = "org.freedesktop.DBus.Properties";
    const char *method = "Get";

    const char *intf = "xyz.openbmc_project.Sensor.Value";
    const char *prop = "Value";

    DBusConnection *conn;
    DBusError err;
    DBusMessage *msg, *reply;
    DBusMessageIter args;

    dbus_error_init(&err);
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    check_dbus_error(&err);
    if (!conn) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }
    msg = dbus_message_new_method_call(bus_name, path, iface, method);
    if (!msg) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }
    dbus_message_iter_init_append(msg, &args);
    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &intf)) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }
    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &prop)) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }

    reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
    check_dbus_error(&err);
    if (!reply) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }

    if (!dbus_message_iter_init(reply, &args))
    {
        //LuxPrintf("Message has no arguments!\n");
    }
    else if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&args)) 
    {
    } 
    else if (DBUS_TYPE_VARIANT == dbus_message_iter_get_arg_type(&args)) 
    {
        DBusMessageIter variant_iter;
        dbus_message_iter_recurse(&args, &variant_iter);
        int type = dbus_message_iter_get_arg_type(&variant_iter);
        switch (type) 
        {
            case DBUS_TYPE_STRING: 
            {
                const char *str_value;
                dbus_message_iter_get_basic(&variant_iter, &str_value);
                //printf("Parsed string value from variant: %s\n", str_value);
                break;
            }
            case DBUS_TYPE_DOUBLE: 
            {
                double double_value;
                dbus_message_iter_get_basic(&variant_iter, &double_value);
                //printf("Parsed double value from variant: %f\n", double_value);
                *ps8Value = (INT8U)double_value;
                *pu8Present = FSC_SENSOR_PRESENT;
                *pu8Status = FSC_SENSOR_NORMAL;
                break;
            }
            case DBUS_TYPE_BOOLEAN: 
            {
                dbus_bool_t bool_value;
                dbus_message_iter_get_basic(&variant_iter, &bool_value);
                //printf("Parsed boolean value from variant: %d\n", bool_value);
                break;
            }
            default:
                break;
        }
    }
    dbus_message_unref(reply);
    dbus_message_unref(msg);
    dbus_connection_unref(conn);
    return FUNC_OK;
}

EFuncRetCode LuxFSCDbusGetCPUValue(char* pcDbusPatch, INT8S* ps8Value, INT8U* pu8Present, INT8U* pu8Status)
{
    const char *bus_name = "xyz.openbmc_project.IntelCPUSensor";
    const char *path = pcDbusPatch;
    const char *iface = "org.freedesktop.DBus.Properties";
    const char *method = "Get";

    const char *intf = "xyz.openbmc_project.Sensor.Value";
    const char *prop = "Value";

    DBusConnection *conn;
    DBusError err;
    DBusMessage *msg, *reply;
    DBusMessageIter args;

    dbus_error_init(&err);
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    check_dbus_error(&err);
    if (!conn) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }
    msg = dbus_message_new_method_call(bus_name, path, iface, method);
    if (!msg) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }
    dbus_message_iter_init_append(msg, &args);
    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &intf)) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }
    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &prop)) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }

    reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
    check_dbus_error(&err);
    if (!reply) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }

    if (!dbus_message_iter_init(reply, &args))
    {
        //LuxPrintf("Message has no arguments!\n");
    }
    else if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&args)) 
    {
    } 
    else if (DBUS_TYPE_VARIANT == dbus_message_iter_get_arg_type(&args)) 
    {
        DBusMessageIter variant_iter;
        dbus_message_iter_recurse(&args, &variant_iter);
        int type = dbus_message_iter_get_arg_type(&variant_iter);
        switch (type) 
        {
            case DBUS_TYPE_STRING: 
            {
                const char *str_value;
                dbus_message_iter_get_basic(&variant_iter, &str_value);
                //printf("Parsed string value from variant: %s\n", str_value);
                break;
            }
            case DBUS_TYPE_DOUBLE: 
            {
                double double_value;
                dbus_message_iter_get_basic(&variant_iter, &double_value);
                //printf("Parsed double value from variant: %f\n", double_value);
                *ps8Value = (INT8U)double_value;
                *pu8Present = FSC_SENSOR_PRESENT;
                *pu8Status = FSC_SENSOR_NORMAL;
                break;
            }
            case DBUS_TYPE_BOOLEAN: 
            {
                dbus_bool_t bool_value;
                dbus_message_iter_get_basic(&variant_iter, &bool_value);
                //printf("Parsed boolean value from variant: %d\n", bool_value);
                break;
            }
            default:
                break;
        }
    }
    dbus_message_unref(reply);
    dbus_message_unref(msg);
    dbus_connection_unref(conn);
    return FUNC_OK;
}

EFuncRetCode LuxFSCDbusGetDIMMPowerValue(char* pcDbusPatch, INT8S* ps8Value, INT8U* pu8Present, INT8U* pu8Status)
{
    const char *bus_name = "xyz.openbmc_project.PSUSensor";
    const char *path = pcDbusPatch;
    const char *iface = "org.freedesktop.DBus.Properties";
    const char *method = "Get";

    const char *intf = "xyz.openbmc_project.Sensor.Value";
    const char *prop = "Value";

    DBusConnection *conn;
    DBusError err;
    DBusMessage *msg, *reply;
    DBusMessageIter args;

    dbus_error_init(&err);
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    check_dbus_error(&err);
    if (!conn) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }
    msg = dbus_message_new_method_call(bus_name, path, iface, method);
    if (!msg) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }
    dbus_message_iter_init_append(msg, &args);
    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &intf)) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }
    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &prop)) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }

    reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
    check_dbus_error(&err);
    if (!reply) 
    {
        if(reply)
            dbus_message_unref(reply);
        if(msg)
            dbus_message_unref(msg);
        if(conn)
            dbus_connection_unref(conn);

        return FUNC_FAILED;
    }

    if (!dbus_message_iter_init(reply, &args))
    {
        //LuxPrintf("Message has no arguments!\n");
    }
    else if (DBUS_TYPE_ARRAY == dbus_message_iter_get_arg_type(&args)) 
    {
    } 
    else if (DBUS_TYPE_VARIANT == dbus_message_iter_get_arg_type(&args)) 
    {
        DBusMessageIter variant_iter;
        dbus_message_iter_recurse(&args, &variant_iter);
        int type = dbus_message_iter_get_arg_type(&variant_iter);
        switch (type) 
        {
            case DBUS_TYPE_STRING: 
            {
                const char *str_value;
                dbus_message_iter_get_basic(&variant_iter, &str_value);
                //printf("Parsed string value from variant: %s\n", str_value);
                break;
            }
            case DBUS_TYPE_DOUBLE: 
            {
                double double_value;
                dbus_message_iter_get_basic(&variant_iter, &double_value);
                //printf("Parsed double value from variant: %f\n", double_value);
                *ps8Value = (INT8U)double_value;
                *pu8Present = FSC_SENSOR_PRESENT;
                *pu8Status = FSC_SENSOR_NORMAL;
                break;
            }
            case DBUS_TYPE_BOOLEAN: 
            {
                dbus_bool_t bool_value;
                dbus_message_iter_get_basic(&variant_iter, &bool_value);
                //printf("Parsed boolean value from variant: %d\n", bool_value);
                break;
            }
            default:
                break;
        }
    }
    dbus_message_unref(reply);
    dbus_message_unref(msg);
    dbus_connection_unref(conn);
    return FUNC_OK;
}

EFuncRetCode LuxFSCGetPreHeatTempFromFile(INT8S* ps8Setpoint)
{
    FILE* fp = NULL;
    char acCmdbuff[512] = {0};
    char acCmdstr[1024] = {0};
    INT8U u8Value = 0;

    if(0 != LuxAccess(COVER_SETPOINT_PATH, F_OK))
    {
        return FUNC_FAILED;
    }

    LuxSprintf(acCmdstr, "cat %s",COVER_SETPOINT_PATH);
    if ((fp = LuxPopen(acCmdstr, "r")) != NULL)
    {
        fgets(acCmdbuff, sizeof(acCmdbuff), fp);
        u8Value = strtoul(acCmdbuff, NULL, 10);
        LuxPclose(fp);
        if (u8Value > 120)
        {
            return FUNC_FAILED;
        }
        else
        {
            *ps8Setpoint = (INT8S)u8Value;
            return FUNC_OK;
        }
    }
    else
    {
        return FUNC_FAILED;
    }

    return FUNC_OK;
}

EFuncRetCode LuxFSCCheckFanTableExist(char* pcName)
{
    /*check fan table file exist */
    if(LuxAccess(pcName,F_OK) != 0)
    {
        LuxPrintf("Fan table file %s is not exist!!!\n",pcName);
        return FUNC_FAILED;
    }
    return FUNC_OK;
}

EFuncRetCode LuxFSCLoadHeader(cJSON* psCJSONRoot, SFscHeader* psFSCHeader)
{
    char acTemp[MAX_JSON_CHARACTER_SIZE] = {0};

    LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
    if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONRoot, "Project", acTemp)))
    {
        LuxPrintf("Parse fan table Project fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
        {
            LuxPrintf("Project value error %s\n",acTemp);
            return FUNC_FAILED;
        }
        else
        {
            LuxMemcpy(psFSCHeader->acProject, acTemp, LuxStrlen(acTemp));
        }
    }

    LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
    if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONRoot, "Customer", psFSCHeader->acCustomer)))
    {
        LuxPrintf("Parse fan table Customer fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
        {
            LuxPrintf("Customer value error %s\n",acTemp);
            return FUNC_FAILED;
        }
        else
        {
            LuxMemcpy(psFSCHeader->acCustomer, acTemp, LuxStrlen(acTemp));
        }
    }

    LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
    if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONRoot, "Version", psFSCHeader->acVersion)))
    {
        LuxPrintf("Parse fan table Version fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
        {
            LuxPrintf("Version value error %s\n",acTemp);
            return FUNC_FAILED;
        }
        else
        {
            LuxMemcpy(psFSCHeader->acVersion, acTemp, LuxStrlen(acTemp));
        }
    }

    LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
    if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONRoot, "platform", psFSCHeader->acPlatform)))
    {
        LuxPrintf("Parse fan table platform fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
        {
            LuxPrintf("platform value error %s\n",acTemp);
            return FUNC_FAILED;
        }
        else
        {
            LuxMemcpy(psFSCHeader->acPlatform, acTemp, LuxStrlen(acTemp));
        }
    }

    return FUNC_OK;
}

EFuncRetCode LuxFSCLoadGlobalConfig(cJSON* psCJSONRoot, SFscGlobalConfig* psFscGlobalConfig)
{
    cJSON* psCJSONGlobalConfigRoot = NULL;
    int iTemp = 0;
    char acTemp[MAX_JSON_CHARACTER_SIZE] = {0};

    psCJSONGlobalConfigRoot = LuxcJSONGetObjectItem(psCJSONRoot, "GlobalConfig");
    if(NULL == psCJSONGlobalConfigRoot)
    {
        LuxPrintf("Can't get GlobalConfig cJSONRoot\n");
        return FUNC_FAILED; 
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONGlobalConfigRoot, "MaxSensorReadingCache", &iTemp)))
    {
        LuxPrintf("Parse fan table MaxSensorReadingCache fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscGlobalConfig->u8MaxReadingCache = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONGlobalConfigRoot, "Elevation", &iTemp)))
    {
        LuxPrintf("Parse fan table Elevation fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscGlobalConfig->u16Elevation = iTemp;
    }

    LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
    if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONGlobalConfigRoot, "FanType", acTemp)))
    {
        LuxPrintf("Parse fan table FanType fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
        {
            LuxPrintf("FanType value error %s\n",acTemp);
            return FUNC_FAILED;
        }
        else
        {
            LuxMemcpy(psFscGlobalConfig->acFanType, acTemp, LuxStrlen(acTemp));
        }
    }

    LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
    if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONGlobalConfigRoot, "WorkDCOff", acTemp)))
    {
        LuxPrintf("Parse fan table WorkDCOff fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
        {
            LuxPrintf("WorkDCOff value error %s\n",acTemp);
            return FUNC_FAILED;
        }
        else
        {
            LuxMemcpy(psFscGlobalConfig->acWorkDCOff, acTemp, LuxStrlen(acTemp));
        }
    }

    return FUNC_OK;
}

EFuncRetCode LuxFSCLoadFanConfig(cJSON* psCJSONRoot, SFscFanConfig* psFscFanConfig)
{
    cJSON* psCJSONFanConfigRoot = NULL;
    int aiTemp[MAX_JSON_CHARACTER_SIZE] = {0};
    int iArraySize = 0;
    int iTemp = 0;
    INT8U u8Index = 0;

    psCJSONFanConfigRoot = LuxcJSONGetObjectItem(psCJSONRoot, "FanConfig");
    if(NULL == psCJSONFanConfigRoot)
    {
        LuxPrintf("Can't get FanConfig cJSONRoot\n");
        return FUNC_FAILED; 
    }
    
    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONFanConfigRoot, "MaxPWMNumber", &iTemp)))
    {
        LuxPrintf("Parse fan table MaxPWMNumber fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscFanConfig->u8MaxPwmNum = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONFanConfigRoot, "MaxFanNumber", &iTemp)))
    {
        LuxPrintf("Parse fan table MaxFanNumber fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscFanConfig->u8MaxFanNum = (INT8U)iTemp;
    }

    LuxMemset(aiTemp, 0, MAX_JSON_CHARACTER_SIZE);
    if(FUNC_FAILED == (LuxcJSONGetObjectIntArray(psCJSONFanConfigRoot, "FanSensorNumPWMMatch", aiTemp, &iArraySize)))
    {
        LuxPrintf("Parse fan table FanSensorNumPWMMatch fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(iArraySize > MAX_FAN_COUNT)
        {
            LuxPrintf("FanSensorNumPWMMatch value error %s\n",aiTemp);
            return FUNC_FAILED;
        }
        else
        {
            for(u8Index = 0; u8Index < iArraySize; u8Index++)
            {
                psFscFanConfig->u8FanSensorNumPWMMatch[u8Index] = (INT8U)aiTemp[u8Index];
            }
        }
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONFanConfigRoot, "MaxFanDuty", &iTemp)))
    {
        LuxPrintf("Parse fan table MaxFanDuty fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscFanConfig->u8MaxFanDuty = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONFanConfigRoot, "MinFanDuty", &iTemp)))
    {
        LuxPrintf("Parse fan table MinFanDuty fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscFanConfig->u8MinFanDuty = (INT8U)iTemp;
    }
    
    return FUNC_OK;
}

EFuncRetCode LuxFSCLoadCloseloopSensor(cJSON* psCJSONRoot, SFscCLSensor* psFscCLSensor)
{
    INT8U u8CLSensorCount = 0;
    INT8U u8SensorIndex = 0;
    SFscCLSensorInfo sFscCLSensorInfo;
    cJSON* psCJSONCloseloopRoot = NULL;
    cJSON* psCJSONCloseloopSensorRoot = NULL;
    char acKeyName[MAX_KEY_LENGTH] = {0};
    int iArraySize = 0;
    int iRow = 0;
    int iColumn = 0;
    int iTemp = 0;
    char acTemp[MAX_JSON_CHARACTER_SIZE] = {0};
    int aiTemp[MAX_JSON_CHARACTER_SIZE] = {0};
    char asTemp[MAX_SETPOINT_CASE][MAX_JSON_CHARACTER_SIZE] = {0};
    double adTemp[MAX_JSON_CHARACTER_SIZE][MAX_JSON_CHARACTER_SIZE] = {0};
    INT8U u8RowIndex = 0;
    INT8U u8ColumnIndex =0;
    INT8U u8Index = 0;
    
    psCJSONCloseloopRoot = LuxcJSONGetObjectItem(psCJSONRoot, "CloseLoop");
    if(NULL == psCJSONCloseloopRoot)
    {
        LuxPrintf("Can't get CloseLoop cJSONRoot\n");
        return FUNC_FAILED; 
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopRoot, "MaxCloseloopSensor", &iTemp)))
    {
        LuxPrintf("Parse fan table MaxCloseloopSensor fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscCLSensor->u8MaxCLSensor = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopRoot, "TotalCloseloopSensor", &iTemp)))
    {
        LuxPrintf("Parse fan table TotalCloseloopSensor fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscCLSensor->u8TotalCLSensor = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONCloseloopRoot, "PidAdjustMethod", acTemp)))
    {
        LuxPrintf("Parse fan table PidAdjustMethod fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
        {
            LuxPrintf("PidAdjustMethod value error %s\n",acTemp);
            return FUNC_FAILED;
        }
        else
        {
            LuxMemcpy(psFscCLSensor->acPIDAdjustMethod, acTemp, LuxStrlen(acTemp));
        }
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopRoot, "ESection", &iTemp)))
    {
        LuxPrintf("Parse fan table ESection fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscCLSensor->u8CLSensorESection = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopRoot, "ECSection", &iTemp)))
    {
        LuxPrintf("Parse fan table ECSection fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscCLSensor->u8CLSensorECSection = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopRoot, "SensorSetpointMaxCase", &iTemp)))
    {
        LuxPrintf("Parse fan table SensorSetpointMaxCase fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscCLSensor->u8CLSensorSetpointMaxCase = (INT8U)iTemp;
    }
    
    u8CLSensorCount = psFscCLSensor->u8TotalCLSensor;
    if(u8CLSensorCount > psFscCLSensor->u8MaxCLSensor)
    {
        LuxPrintf("Wrong closeloop sensor count %d\n",u8CLSensorCount);
    }

    for(u8SensorIndex = 0; u8SensorIndex < u8CLSensorCount; u8SensorIndex++)
    {
        LuxMemset(&sFscCLSensorInfo, 0 ,sizeof(SFscCLSensorInfo));
        LuxMemset(acKeyName, 0, MAX_KEY_LENGTH);
        LuxSprintf(acKeyName, "CLSensor%d", u8SensorIndex+1); /*In fsc json file, the sensor index count from 1 */

        psCJSONCloseloopSensorRoot = LuxcJSONGetObjectItem(psCJSONCloseloopRoot, acKeyName);
        if(NULL == psCJSONCloseloopSensorRoot)
        {
            LuxPrintf("Can't get CLSensor%d cJSONRoot\n",u8SensorIndex);
            return FUNC_FAILED; 
        }

        LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONCloseloopSensorRoot, "SensorType", acTemp)))
        {
            LuxPrintf("Parse fan table fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
            {
                LuxPrintf("SensorType value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                LuxMemcpy(sFscCLSensorInfo.acCLSensorType, acTemp, LuxStrlen(acTemp));
            }
        }
        
        LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONCloseloopSensorRoot, "SensorStatus", acTemp)))
        {
            LuxPrintf("Parse fan table SensorStatusfail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
            {
                LuxPrintf("SensorStatus value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                LuxMemcpy(sFscCLSensorInfo.acCLSensorStatus, acTemp, LuxStrlen(acTemp));
            }
        }
        
        if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopSensorRoot, "DT", &iTemp)))
        {
            LuxPrintf("Parse fan table DT fail\n");
            return FUNC_FAILED;
        }
        else
        {
            sFscCLSensorInfo.u8DT = (INT8U)iTemp;
        }
        
        LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONCloseloopSensorRoot, "SensorName", acTemp)))
        {
            LuxPrintf("Parse fan table SensorName fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(LuxStrlen(acTemp) > MAX_SENSOR_NAME_LENGTH)
            {
                LuxPrintf("SensorName value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                LuxMemcpy(sFscCLSensorInfo.acSensorName, acTemp, LuxStrlen(acTemp));
            }
        }
        
        if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopSensorRoot, "VendorSpec", &iTemp)))
        {
            LuxPrintf("Parse fan table VendorSpec fail\n");
            return FUNC_FAILED;
        }
        else
        {
            sFscCLSensorInfo.s8VendorSpec = (INT8U)iTemp;
        }
        
        if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopSensorRoot, "CustomerSpec", &iTemp)))
        {
            LuxPrintf("Parse fan table CustomerSpec fail\n");
            return FUNC_FAILED;
        }
        else
        {
            sFscCLSensorInfo.s8CustomerSpec = (INT8U)iTemp;
        }

        LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONCloseloopSensorRoot, "SetpointType", acTemp)))
        {
            LuxPrintf("Parse fan table SetpointType fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(LuxStrlen(acTemp) > MAX_SENSOR_NAME_LENGTH)
            {
                LuxPrintf("SetpointType value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                LuxMemcpy(sFscCLSensorInfo.acSetpointType, acTemp, LuxStrlen(acTemp));
            }
        }
        
        if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopSensorRoot, "SetpointDefault", &iTemp)))
        {
            LuxPrintf("Parse fan table SetpointDefault fail\n");
            return FUNC_FAILED;
        }
        else
        {
            sFscCLSensorInfo.s8SetpointDefault = (INT8U)iTemp;
        }
        
        if(FUNC_FAILED == (LuxcJSONGetObjectStringArray(psCJSONCloseloopSensorRoot, "SetpointCase", asTemp, &iArraySize)))
        {
            LuxPrintf("Parse fan table SetpointCase fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(iArraySize > MAX_SETPOINT_CASE)
            {
                LuxPrintf("SetpointCase value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                LuxMemcpy(sFscCLSensorInfo.acSetpointCase, (char**)asTemp, sizeof(sFscCLSensorInfo.acSetpointCase));
            }
        }
        
        if(FUNC_FAILED == (LuxcJSONGetObjectIntArray(psCJSONCloseloopSensorRoot, "SetpointValue", aiTemp, &iArraySize)))
        {
            LuxPrintf("Parse fan table SetpointValue fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(iArraySize > MAX_OL_SENSOR_STEPS)
            {
                LuxPrintf("SetpointValue value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                for(u8Index = 0; u8Index < iArraySize; u8Index++)
                {
                    sFscCLSensorInfo.as8SetpointValue[u8Index] = (INT8S)aiTemp[u8Index];
                }
            }
        }
        
        LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONCloseloopSensorRoot, "SetpointCaseUse", acTemp)))
        {
            LuxPrintf("Parse fan table SetpointCaseUse fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(LuxStrlen(acTemp) > MAX_SENSOR_NAME_LENGTH)
            {
                LuxPrintf("SetpointCaseUse value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                LuxMemcpy(sFscCLSensorInfo.acSetpointCaseUse, acTemp, LuxStrlen(acTemp));
            }
        }
        
        LuxMemset(aiTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectIntArray(psCJSONCloseloopSensorRoot, "FanWeighting", aiTemp, &iArraySize)))
        {
            LuxPrintf("Parse fan table FanWeighting fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(iArraySize > MAX_FSC_PWM_CHANNEL)
            {
                LuxPrintf("FanWeighting value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                for(u8Index = 0; u8Index < iArraySize; u8Index++)
                {
                    sFscCLSensorInfo.au8FanWeight[u8Index] = (INT8U)aiTemp[u8Index];
                }
            }
        }
        
        if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONCloseloopSensorRoot, "Hysteresis", &iTemp)))
        {
            LuxPrintf("Parse fan table Hysteresis fail\n");
            return FUNC_FAILED;
        }
        else
        {
            sFscCLSensorInfo.u8Hysteresis = (INT8U)iTemp;
        }
        
        LuxMemset(aiTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectIntArray(psCJSONCloseloopSensorRoot, "E", aiTemp, &iArraySize)))
        {
            LuxPrintf("Parse fan table E fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(iArraySize > MAX_SENSOR_E_SECTION-1)
            {
                LuxPrintf("E value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                for(u8Index = 0; u8Index < iArraySize; u8Index++)
                {
                    sFscCLSensorInfo.as8EValue[u8Index] = (INT8S)aiTemp[u8Index];
                }
            }
        }

        LuxMemset(aiTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectIntArray(psCJSONCloseloopSensorRoot, "EC", aiTemp, &iArraySize)))
        {
            LuxPrintf("Parse fan table EC fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(iArraySize > MAX_SENSOR_EC_SECTION-1)
            {
                LuxPrintf("EC value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                for(u8Index = 0; u8Index < iArraySize; u8Index++)
                {
                    sFscCLSensorInfo.as8ECValue[u8Index] = (INT8S)aiTemp[u8Index];
                }
            }
        }
        
        LuxMemset(adTemp, 0, sizeof(adTemp));
        if(FUNC_FAILED == (LuxcJSONGetObjectDoubleArray2(psCJSONCloseloopSensorRoot, "P", adTemp, &iRow, &iColumn)))
        {
            LuxPrintf("Parse fan table P fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if((iRow > MAX_SENSOR_EC_SECTION) || (iColumn > MAX_SENSOR_E_SECTION))
            {
                LuxPrintf("P value error \n");
                return FUNC_FAILED;
            }
            else
            {
                for(u8RowIndex = 0; u8RowIndex < MAX_SENSOR_EC_SECTION; u8RowIndex++)
                {
                    for(u8ColumnIndex = 0; u8ColumnIndex < MAX_SENSOR_E_SECTION; u8ColumnIndex++)
                    {
                        sFscCLSensorInfo.afPValue[u8RowIndex][u8ColumnIndex] = adTemp[u8RowIndex][u8ColumnIndex];
                    }
                }
            }
        }
        
        LuxMemset(adTemp, 0, sizeof(adTemp));
        if(FUNC_FAILED == (LuxcJSONGetObjectDoubleArray2(psCJSONCloseloopSensorRoot, "I", adTemp, &iRow, &iColumn)))
        {
            LuxPrintf("Parse fan table I fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if((iRow > MAX_SENSOR_EC_SECTION) || (iColumn > MAX_SENSOR_E_SECTION))
            {
                LuxPrintf("I value error \n");
                return FUNC_FAILED;
            }
            else
            {
                for(u8RowIndex = 0; u8RowIndex < MAX_SENSOR_EC_SECTION; u8RowIndex++)
                {
                    for(u8ColumnIndex = 0; u8ColumnIndex < MAX_SENSOR_E_SECTION; u8ColumnIndex++)
                    {
                        sFscCLSensorInfo.afIValue[u8RowIndex][u8ColumnIndex] = adTemp[u8RowIndex][u8ColumnIndex];
                    }
                }
            }
        }
        
        LuxMemset(adTemp, 0, sizeof(adTemp));
        if(FUNC_FAILED == (LuxcJSONGetObjectDoubleArray2(psCJSONCloseloopSensorRoot, "D", adTemp, &iRow, &iColumn)))
        {
            LuxPrintf("Parse fan table D fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if((iRow > MAX_SENSOR_EC_SECTION) || (iColumn > MAX_SENSOR_E_SECTION))
            {
                LuxPrintf("D value error \n");
                return FUNC_FAILED;
            }
            else
            {
                for(u8RowIndex = 0; u8RowIndex < MAX_SENSOR_EC_SECTION; u8RowIndex++)
                {
                    for(u8ColumnIndex = 0; u8ColumnIndex < MAX_SENSOR_E_SECTION; u8ColumnIndex++)
                    {
                        sFscCLSensorInfo.afDValue[u8RowIndex][u8ColumnIndex] = adTemp[u8RowIndex][u8ColumnIndex];
                    }
                }
            }
        }
        
        LuxMemcpy(&psFscCLSensor->asFscCLSensorInfo[u8SensorIndex], &sFscCLSensorInfo, sizeof(SFscCLSensorInfo));
    }
    return FUNC_OK;
}

EFuncRetCode LuxFSCLoadAbnormalConfig(cJSON* psCJSONRoot, SFscAbnormalEvent* psFscAbnormalEvent)
{
    INT8U u8AbnormalSensorCount = 0;
    INT8U u8SensorIndex = 0;
    SFscSensorFailInfo sFscSensorFailInfo;
    cJSON* psCJSONAbnormalEventRoot = NULL;
    cJSON* psCJSONAbnormalSensorRoot = NULL;
    char acKeyName[MAX_KEY_LENGTH] = {0};
    int iTemp = 0;
    char acTemp[MAX_JSON_CHARACTER_SIZE] = {0};

    psCJSONAbnormalEventRoot = LuxcJSONGetObjectItem(psCJSONRoot, "AbnormalEvent");
    if(NULL == psCJSONAbnormalEventRoot)
    {
        LuxPrintf("Can't get AbnormalEvent cJSONRoot\n");
        return FUNC_FAILED; 
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONAbnormalEventRoot, "MaxFailSensor", &iTemp)))
    {
        LuxPrintf("Parse fan table MaxFailSensor fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscAbnormalEvent->u8MaxAbnormalSensor = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONAbnormalEventRoot, "TotalFailSensor", &iTemp)))
    {
        LuxPrintf("Parse fan table TotalFailSensor fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscAbnormalEvent->u8TotalAbnormalSensor = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONAbnormalEventRoot, "FanSensorNumberStart", &iTemp)))
    {
        LuxPrintf("Parse fan table FanSensorNumberStart fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscAbnormalEvent->sFscFanFail.u8FanSensorNumberStart = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONAbnormalEventRoot, "FanFailSingle", acTemp)))
    {
        LuxPrintf("Parse fan table FanFailSingle fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
        {
            LuxPrintf("FanFailSingle value error %s\n",acTemp);
            return FUNC_FAILED;
        }
        else
        {
            LuxMemcpy(psFscAbnormalEvent->sFscFanFail.acFanFailSingle, acTemp, LuxStrlen(acTemp));
        }
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONAbnormalEventRoot, "FanFailTwin_1", &iTemp)))
    {
        LuxPrintf("Parse fan table FanFailTwin_1 fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscAbnormalEvent->sFscFanFail.u8FanFailTwin1 = (INT8U)iTemp;
    }

    if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONAbnormalEventRoot, "FanFailTwin_2_Diff", &iTemp)))
    {
        LuxPrintf("Parse fan table FanFailTwin_2_Diff fail\n");
        return FUNC_FAILED;
    }
    else
    {
        psFscAbnormalEvent->sFscFanFail.u8FanFailTwin2Diff = (INT8U)iTemp;
    }

    LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
    if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONAbnormalEventRoot, "FanFailTwin_2_Same", acTemp)))
    {
        LuxPrintf("Parse fan table FanFailTwin_2_Same fail\n");
        return FUNC_FAILED;
    }
    else
    {
        if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
        {
            LuxPrintf("FanFailTwin_2_Same value error %s\n",acTemp);
            return FUNC_FAILED;
        }
        else
        {
            LuxMemcpy(psFscAbnormalEvent->sFscFanFail.acFanFailTwin2Same, acTemp, LuxStrlen(acTemp));
        }
    }

    u8AbnormalSensorCount = psFscAbnormalEvent->u8TotalAbnormalSensor;
    if(u8AbnormalSensorCount > psFscAbnormalEvent->u8MaxAbnormalSensor)
    {
        LuxPrintf("Wrong abnormal sensor count %d\n",u8AbnormalSensorCount);
    }
    
    for(u8SensorIndex = 0; u8SensorIndex < u8AbnormalSensorCount; u8SensorIndex++)
    {
        LuxMemset(&sFscSensorFailInfo, 0 ,sizeof(SFscSensorFailInfo));
        LuxMemset(acKeyName, 0, MAX_KEY_LENGTH);
        LuxSprintf(acKeyName, "AbnormalSensor%d", u8SensorIndex+1); /*In fsc json file, the sensor index count from 1 */

        psCJSONAbnormalSensorRoot = LuxcJSONGetObjectItem(psCJSONAbnormalEventRoot, acKeyName);
        if(NULL == psCJSONAbnormalSensorRoot)
        {
            LuxPrintf("Can't get AbnormalSensor%d cJSONRoot\n",u8SensorIndex);
            return FUNC_FAILED; 
        }

        LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONAbnormalSensorRoot, "SensorName", acTemp)))
        {
            LuxPrintf("Parse fan table SensorName fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
            {
                LuxPrintf("SensorName value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                LuxMemcpy(sFscSensorFailInfo.acSensorName, acTemp, LuxStrlen(acTemp));
            }
        }

        LuxMemset(acTemp, 0, MAX_JSON_CHARACTER_SIZE);
        if(FUNC_FAILED == (LuxcJSONGetObjectStringValue(psCJSONAbnormalSensorRoot, "Policy", acTemp)))
        {
            LuxPrintf("Parse fan table Policy fail\n");
            return FUNC_FAILED;
        }
        else
        {
            if(LuxStrlen(acTemp) > MAX_KEY_LENGTH)
            {
                LuxPrintf("Policy value error %s\n",acTemp);
                return FUNC_FAILED;
            }
            else
            {
                LuxMemcpy(sFscSensorFailInfo.acFailPolicy, acTemp, LuxStrlen(acTemp));
            }
        }

        if(FUNC_FAILED == (LuxcJSONGetObjectIntValue(psCJSONAbnormalSensorRoot, "FailValue", &iTemp)))
        {
            LuxPrintf("Parse fan table FailValue fail\n");
            return FUNC_FAILED;
        }
        else
        {
            sFscSensorFailInfo.u8FailValue = (INT8U)iTemp;
        }

        LuxMemcpy(&psFscAbnormalEvent->asFscSensorFailInfo[u8SensorIndex], &sFscSensorFailInfo, sizeof(SFscSensorFailInfo));
    }
    return FUNC_OK;
}

EFuncRetCode LuxFSCGetSetpointFromFile(INT8S* ps8Setpoint)
{
    FILE* fp = NULL;
    char acCmdbuff[512] = {0};
    char acCmdstr[1024] = {0};
    INT8U u8Value = 0;

    if(0 != LuxAccess(DIMM_SETPOINT_PATH, F_OK))
    {
        return FUNC_FAILED;
    }

    LuxSprintf(acCmdstr, "cat %s",DIMM_SETPOINT_PATH);
    if ((fp = LuxPopen(acCmdstr, "r")) != NULL)
    {
        fgets(acCmdbuff, sizeof(acCmdbuff), fp);
        u8Value = strtoul(acCmdbuff, NULL, 10);
        LuxPclose(fp);
        if (u8Value > 120)
        {
            return FUNC_FAILED;
        }
        else
        {
            *ps8Setpoint = (INT8S)u8Value;
            return FUNC_OK;
        }
    }
    else
    {
        return FUNC_FAILED;
    }

    return FUNC_OK;
}

EFuncRetCode LuxFSCSetSetpointToFile(INT8S s8Setpoint)
{
    FILE *fp = NULL;
    char buffer[32] = {0};

    fp = LuxFopen(DIMM_SETPOINT_PATH, "wb");
    if(NULL == fp)
    {
        LuxPrintf("Error: LuxFopen %s Failed\n",DIMM_SETPOINT_PATH);
        return FUNC_FAILED;
    }

    snprintf(buffer, sizeof(buffer), "%d", s8Setpoint);
    if (fputs(buffer, fp) == EOF)
    {  
        LuxPrintf("Error: fputs Failed\n");
        LuxFclose(fp);
        return FUNC_FAILED;  
    } 

    LuxFclose(fp);
    return FUNC_OK;
}

EFuncRetCode LuxFSCGetFSCControlMode(SFscInfo* psFscInfo)
{
    SFscControlMode sFscControlMode;
    FILE* fp = NULL;
    char acCmdbuff[512] = {0};
    char acCmdstr[1024] = {0};
    INT8U u8Value = 0;

    if(0 != LuxAccess(FSC_CONTROL_MODE, F_OK))
    {
        psFscInfo->sFscRunningInfo.u8ControlMode = FSC_FAN_TABLE_AUTO;
        return FUNC_FAILED;
    }

    /*Read FSC configuration*/
    fp = LuxFopen(FSC_CONTROL_MODE, "rb");
    if(NULL == fp)
    {
        LuxPrintf("Error: LuxFopen %s Failed\n", FSC_CONTROL_MODE);
        return FUNC_FAILED;
    }
    
    if(1 != LuxFread(&sFscControlMode, sizeof(SFscControlMode), 1, fp))
    {
        LuxPrintf("Error: LuxFread Failed\n");
        LuxFclose(fp);
        return FUNC_FAILED;
    }

    psFscInfo->sFscRunningInfo.u8ControlMode = sFscControlMode.u8ControlMode;
    LuxMemcpy(psFscInfo->sFscRunningInfo.au8ManualPwmOut, sFscControlMode.u8PWM, MAX_FSC_PWM_CHANNEL);
    return FUNC_OK;
}

EFuncRetCode LuxFSCLoadFanTable(cJSON* psCJSONRoot, SFscInfo* psFscInfo)
{
    EFuncRetCode eRetn = FUNC_FAILED;
    
    /*Load fan table header */
    eRetn = LuxFSCLoadHeader(psCJSONRoot, &psFscInfo->sFSCHeader);
    if(FUNC_FAILED == eRetn)
    {
        LuxPrintf("Load fan table header fail !!!\n");
        return FUNC_FAILED;
    }

    /*Load fan table global configuration */
    eRetn = LuxFSCLoadGlobalConfig(psCJSONRoot, &psFscInfo->sFscGlobalConfig);
    if(FUNC_FAILED == eRetn)
    {
        LuxPrintf("Load fan table global config fail !!!\n");
        return FUNC_FAILED;
    }

    /*Load fan table fan configuration */
    eRetn = LuxFSCLoadFanConfig(psCJSONRoot, &psFscInfo->sFscFanConfig);
    if(FUNC_FAILED == eRetn)
    {
        LuxPrintf("Load fan table fan config fail !!!\n");
        return FUNC_FAILED;
    }

    /*Load fan table closeloop sensor information */
    eRetn = LuxFSCLoadCloseloopSensor(psCJSONRoot, &psFscInfo->sFscCLSensor);
    if(FUNC_FAILED == eRetn)
    {
        LuxPrintf("Load fan table fan config fail !!!\n");
        return FUNC_FAILED;
    }
    
    return FUNC_OK;
}


EFuncRetCode LuxFSCInit()
{
    char acFscFileName[64] = {0};
    cJSON* psCJSONRoot = NULL;
    LuxMemset(&psFscInfo, 0, sizeof(SFscInfo));

    LuxSprintf(acFscFileName,"%s",FAN_TABLE_PATH);

    LuxPrintf("Load fan table %s\n",acFscFileName);
    
    /*Check fan table exist*/
    if(FUNC_FAILED == LuxFSCCheckFanTableExist(acFscFileName))
    {
        LuxPrintf("Fan table is not exist !!!\n");
        return FUNC_FAILED;
    }
    
    /* Load fan table */
    psCJSONRoot = LuxcJSONParseJsonFile(acFscFileName);
    if(NULL == psCJSONRoot)
    {
        LuxPrintf("Can't open fan table file %s !!!\n",acFscFileName);
        return FUNC_FAILED;
    }

    if(LuxFSCLoadFanTable(psCJSONRoot, &psFscInfo) != FUNC_OK)
    {
        psFscInfo.sFscRunningInfo.u8FanTableLoadStatus = FSC_FAN_TABLE_LOAD_FAIL;
    }
    else
    {
        psFscInfo.sFscRunningInfo.u8FanTableLoadStatus = FSC_FAN_TABLE_LOAD_SUCCESS;
        //LuxFSCSetSetpointToFile(psFscInfo.sFscCLSensor.asFscCLSensorInfo[0].s8SetpointDefault);
        //LuxFSCSetSetpointToFile(psFscInfo.sFscCLSensor.asFscCLSensorInfo[0].s8SetpointDefault);
    }
    
    if(NULL != psCJSONRoot)
    {
        LuxcJSONDelete(psCJSONRoot);
    }
    
    return FUNC_OK;
}

EFuncRetCode LuxFSCFanTableUpdate(SFscInfo* psFscInfo)
{
    if(FSC_FAN_TABLE_UPDATE == psFscInfo->sFscRunningInfo.u8UpdateFlag)
    {
        LuxPrintf("Fan table need update. re-load fan table.\n");
        if(FUNC_OK != LuxFSCInit())
        {
            LuxPrintf("Reload fan table fail!!!\n");
            if(psFscInfo->sFscRunningInfo.u8LoadTableTries < 3)
            {
                LuxPrintf("Retry !!!\n");
                psFscInfo->sFscRunningInfo.u8LoadTableTries ++;
                return FUNC_OK;
            }
            else
            {
                psFscInfo->sFscRunningInfo.u8UpdateFlag = FSC_FAN_TABLE_NORMAL;
                psFscInfo->sFscRunningInfo.u8FanTableLoadStatus = FSC_FAN_TABLE_LOAD_FAIL;
                psFscInfo->sFscRunningInfo.u8LoadTableTries = 0;
                return FUNC_FAILED;
            }
        }
        else
        {
            psFscInfo->sFscRunningInfo.u8UpdateFlag = FSC_FAN_TABLE_NORMAL;
            psFscInfo->sFscRunningInfo.u8FanTableLoadStatus = FSC_FAN_TABLE_LOAD_SUCCESS;
            return FUNC_OK;
        }
    }

    return FUNC_OK;
}

EFuncRetCode LuxPDKGetPSGood()
{
    FILE* fp = NULL;
    char acCmdbuff[512] = {0};
    char acCmdstr[1024] = {0};
    unsigned long value = 0;

    LuxSprintf(acCmdstr, "devmem 0x1e780088");

    if ((fp = LuxPopen(acCmdstr, "r")) != NULL)
    {
        fgets(acCmdbuff, sizeof(acCmdbuff), fp);
        value = strtoul(acCmdbuff, NULL, 16);
        LuxPclose(fp);
        if ((value & 0x2000) > 0)
        {
            return PS_GOOD_OK;
        }
        else
        {
            return PS_GOOD_FAIL;
        }
    }
    else
    {
        return FUNC_FAILED;
    }
}

EFuncRetCode LuxFSCGetDIMMValue(INT8U u8CPUIndex, INT8U u8DIMMIndex, INT8S* ps8Value, INT8U* pu8Present, INT8U* pu8Status)
{
    FILE* fp = NULL;
    char acCmdbuff[512] = {0};
    char acCmdstr[1024] = {0};
    INT8U u8DIMMValue = 0;

    LuxSprintf(acCmdstr, "peci_cmds raw 0x%x 0x05 0x05 0xa1 0x00 0x0e 0x%x 0x00",(0x30 + u8CPUIndex), u8DIMMIndex);

    if ((fp = LuxPopen(acCmdstr, "r")) != NULL)
    {
        fgets(acCmdbuff, sizeof(acCmdbuff), fp);
        LuxPclose(fp);
        unsigned int byteValue = 0;  
        int count = 0;  
        char *token = strtok(acCmdbuff, " ");
        
        while (token != NULL)
        {
            if (count == 0)
            {
                sscanf(token, "%x", &byteValue);
                *pu8Status = (INT8U)byteValue;
            }  

            if (count == 2)
            {
                sscanf(token, "%x", &byteValue);
                u8DIMMValue = (INT8U)byteValue;
                if(u8DIMMValue != 0)
                {
                    *pu8Present = FSC_SENSOR_PRESENT;
                }
                else
                {
                    *pu8Present = FSC_SENSOR_NOT_PRESENT;
                }
                break;
            }  
            count++;
            token = strtok(NULL, " ");
        }  
        *ps8Value = u8DIMMValue;
    }
    else
    {
        return FUNC_FAILED;
    }

}

EFuncRetCode LuxFSCGetCPUValue(INT8U u8CPUIndex, INT8S* ps8Value, INT8U* pu8Present, INT8U* pu8Status)
{
    FILE *fp = NULL;
    char command[256];
    char output[256];
    float temperature = 0;
    char tempStr[255] = {0};

    sprintf(command, "peci_cmds -a 0x%x GetTemp", (0x30 + u8CPUIndex));  
    if ((fp = popen(command, "r")) != NULL)
    {
        if (fgets(output, sizeof(output), fp) != NULL)
        {
            if (sscanf(output, "%*s (%fC)", &temperature) == 1)
            {  
                // change temperature to int
                if (temperature < -128 || temperature > 127) 
                {
                    LuxPrintf("Temperature out of range for INT8U.\n");
                    pclose(fp);
                    return FUNC_FAILED;
                }
                pclose(fp);
                *ps8Value = (INT8S)temperature;
                *pu8Present = FSC_SENSOR_PRESENT;
                return FUNC_OK;
            }
            else 
            {
                LuxPrintf("Failed to parse temperature.\n");
                pclose(fp);
                return FUNC_FAILED;
            }  
        }  
        else
        {
            pclose(fp);
            return FUNC_FAILED;
        }
    } 
    else 
    {
        LuxPrintf("Failed to execute command.\n");
        return FUNC_FAILED;  
    }
    
}

EFuncRetCode LuxFSCGetCoverTemp(INT8U* pu8Value, INT8U* pu8Present, INT8U* pu8Status)
{
    INT8U au8WriteData[32] = {0};
    INT8U u8WriteLen = 0;
    INT8U au8ReadBuf[32] = {0};
    INT8U u8ReadLen = 0;
    INT8U u8CoverTempSensorIndex = 0;
    INT8U u8SensorTemp = 0;
    INT8U u8CoverMaxTemp = 0;

    for(u8CoverTempSensorIndex = 0; u8CoverTempSensorIndex < 4; u8CoverTempSensorIndex++)
    {
        u8SensorTemp = 0;
        au8WriteData[0] = (u8CoverTempSensorIndex + 1);  //TMP468 sensor channel count from 1
        u8WriteLen = 1;
        u8ReadLen = 2;
        if(FUNC_FAILED == i2cReadWrite(FCB_I2C_BUS, FCB_TMP468_ADDR >> 1, au8WriteData, u8WriteLen, au8ReadBuf, u8ReadLen))
        {
            LuxPrintf("Read Cover TMP468 channel %d fail\n",u8CoverTempSensorIndex);
            return FUNC_FAILED;
        }
        else
        {
            u8SensorTemp = (INT8U)((((INT16U)((au8ReadBuf[0] << 8) +  au8ReadBuf[1])) >> 3) * 0.0625);
            //LuxPrintf("Channel %d temp = %d\n",u8CoverTempSensorIndex+1, u8SensorTemp);
            if(u8CoverMaxTemp < u8SensorTemp)
            {
                u8CoverMaxTemp = u8SensorTemp;
            }
        }
    }

    *pu8Value = u8CoverMaxTemp;
    *pu8Present = TRUE;
    return FUNC_OK;
}

EFuncRetCode LuxFSCCoverMaxTemp(SFscInfo* psFscInfo)
{
    INT8U u8DIMMIndex = 0;
    INT8U u8Status = 0;
    INT8U u8Present = 0;
    INT8S s8Temp = 0;

    if(FUNC_FAILED != LuxFSCGetCoverTemp(&psFscInfo->sFscRunningInfo.u8MaxCoverTemp, &u8Present, &u8Status))
    {
        //LuxPrintf("Cover max temp = %d\n",u8CoverTemp);
    }

    return FUNC_OK;
}

EFuncRetCode LuxFSCGetSensorStatus(SFscInfo* psFscInfo)
{
    INT8U u8SensorIndex = 0;
    INT8U u8SensorNumber = 0;
    INT8U u8ReadingIndex = 0;
    INT8U u8Status = 0;
    INT8U u8Present = 1;

    /*Get closeloop sensor status and reading */
    for(u8SensorIndex = 0; u8SensorIndex < psFscInfo->sFscCLSensor.u8TotalCLSensor ; u8SensorIndex++)
    {
            /*Closeloop sensor need save the all real value. */
            for(u8ReadingIndex = 0; u8ReadingIndex < MAX_READING_CACHE; u8ReadingIndex++)
            {
                if(SENSOR_REAL_VALUE_INITIAL == psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].as8RealValue[u8ReadingIndex])
                {
                    psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].as8RealValue[u8ReadingIndex] = psFscInfo->sFscRunningInfo.u8MaxCoverTemp;
                    break;
                }
            }

            if(MAX_READING_CACHE == u8ReadingIndex)
            {
                for(u8ReadingIndex = 0; u8ReadingIndex < MAX_READING_CACHE; u8ReadingIndex++)
                {
                    if(u8ReadingIndex < (MAX_READING_CACHE - 1))
                    {
                        psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].as8RealValue[u8ReadingIndex] = psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].as8RealValue[u8ReadingIndex + 1];
                    }
                    else
                    {
                        psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].as8RealValue[MAX_READING_CACHE-1] = psFscInfo->sFscRunningInfo.u8MaxCoverTemp;
                    }
                }
            }
            //psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8SensorStatus = psVolatileSensorZone->asLuxSensorInfo[u8SensorNumber].SensorInfo.EventFlags;
            //psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8Health = psVolatileSensorZone->asLuxSensorInfo[u8SensorNumber].SensorInfo.HealthLevel;
            psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8Present = u8Present;
        
    }

    return FUNC_OK;
}

EFuncRetCode LuxFSCGetTruePID(SFscCLSensorInfo* psFscCLSensorInfo, INT8U u8CLSensorESection, INT8U u8CLSensorECSection)
{
    INT8U u8EIndex = 0;
    INT8U u8ECIndex = 0;
    INT8S s8E = 0;
    INT8S s8EC = 0;

    /*E = current_reading - setpoint */
    s8E = psFscCLSensorInfo->as8RealValue[MAX_READING_CACHE-1] - psFscCLSensorInfo->s8Setpoint;

    /*EC = current_reading - last_reading */
    s8EC = psFscCLSensorInfo->as8RealValue[MAX_READING_CACHE-1] - psFscCLSensorInfo->as8RealValue[MAX_READING_CACHE-2];

    /*get true pid parameter by query e and ec value */
    for(u8ECIndex = 0; u8ECIndex < (u8CLSensorECSection - 1); u8ECIndex++)
    {
        if(psFscCLSensorInfo->as8ECValue[u8ECIndex] < s8EC)
        {
            continue;
        }
        else
        {
            /*LuxPrintf("find the EC section, u8ECIndex = %d\n",u8ECIndex);*/
            break;
        }
    }
    if((u8CLSensorECSection - 1) == u8ECIndex)
    {
        /*LuxPrintf("EC chose the max\n");*/
        u8ECIndex = (u8CLSensorECSection - 1);
    }

    for(u8EIndex = 0; u8EIndex < (u8CLSensorESection - 1); u8EIndex++)
    {
        if(psFscCLSensorInfo->as8EValue[u8EIndex] < s8E)
        {
            continue;
        }
        else
        {
            /*LuxPrintf("find the E section, u8EIndex = %d\n",u8EIndex);*/
            break;
        }
    }
    if((u8CLSensorESection - 1) == u8EIndex)
    {
        /*LuxPrintf("E chose the max\n");*/
        u8EIndex = (u8CLSensorESection - 1);
    }

    psFscCLSensorInfo->fP = psFscCLSensorInfo->afPValue[u8ECIndex][u8EIndex];
    psFscCLSensorInfo->fI = psFscCLSensorInfo->afIValue[u8ECIndex][u8EIndex];
    psFscCLSensorInfo->fD = psFscCLSensorInfo->afDValue[u8ECIndex][u8EIndex];

    return FUNC_OK;
}

EFuncRetCode LuxFSCGetSetpointCase(SFscCLSensorInfo* psFscCLSensorInfo)
{
    /*TBD */
    if(0)
    {
        psFscCLSensorInfo = psFscCLSensorInfo;
    }
    return FUNC_OK;
}

EFuncRetCode LuxFSCGetTureSetpoint(SFscCLSensorInfo* psFscCLSensorInfo, INT8U u8SensorIndex)
{
    INT8U u8SetpointCase = 0;
    INT8S s8Setpoint = 0;

    /* Search setpoint */
    if(0 == LuxStrncmp(psFscCLSensorInfo->acSetpointType, SETPOINT_CONSTANT, LuxStrlen(SETPOINT_CONSTANT)))
    {
        if(u8SensorIndex < MAX_DIMM_SLOT)
        {
            if(FUNC_FAILED == LuxFSCGetPreHeatTempFromFile(&s8Setpoint))
            {
                psFscCLSensorInfo->s8Setpoint = psFscCLSensorInfo->s8SetpointDefault;
            }
            else
            {
                psFscCLSensorInfo->s8Setpoint = s8Setpoint;
            }
        }
        else
        {
            psFscCLSensorInfo->s8Setpoint = psFscCLSensorInfo->s8SetpointDefault;
        }
    }
    else if(0 == LuxStrncmp(psFscCLSensorInfo->acSetpointType, SETPOINT_VARIABLE, LuxStrlen(SETPOINT_VARIABLE)))
    {
        /*get variable setpoint sensor's case use*/
        LuxFSCGetSetpointCase(psFscCLSensorInfo);
        
        for(u8SetpointCase = 0; u8SetpointCase < MAX_SETPOINT_CASE; u8SetpointCase++)
        {
            if(0 == LuxStrncmp(psFscCLSensorInfo->acSetpointCaseUse, psFscCLSensorInfo->acSetpointCase[u8SetpointCase], LuxStrlen(psFscCLSensorInfo->acSetpointCaseUse)))
            {
                /*find the setpoint define*/
                psFscCLSensorInfo->s8Setpoint = psFscCLSensorInfo->as8SetpointValue[u8SetpointCase];
                break;
            }
        }

        if(u8SetpointCase == MAX_SETPOINT_CASE)
        {
            /*Can't find setpoint define, use default setpoint*/
            psFscCLSensorInfo->s8Setpoint = psFscCLSensorInfo->s8SetpointDefault;
        }
    }
    else
    {
        /*setpoint type is not correct, use default setpoint*/
        psFscCLSensorInfo->s8Setpoint = psFscCLSensorInfo->s8SetpointDefault;
    }
    
    return FUNC_OK;
}

EFuncRetCode LuxFSCCloseloopCalculateDuty(SFscCLSensorInfo* psFscCLSensorInfo, INT8U u8MaxPwm, INT8U u8MinPwm)
{
    INT8S s8ReadingT = 0;
    INT8S s8ReadingT1 = 0;
    INT8S s8ReadingT2 = 0;
    float fPIncrement = 0;
    float fIIncrement = 0;
    float fDIncrement = 0;
    INT8U u8Pwm = 0;
    INT8U u8FanIndex=0;
    INT8U u8HysteresisIndex = 0;
    INT16S s16PwmSum = 0;
    float fPWMIncrease = 0;

    /*get last three sensor readings */
    s8ReadingT = psFscCLSensorInfo->as8RealValue[MAX_READING_CACHE - 3];
    s8ReadingT1 = psFscCLSensorInfo->as8RealValue[MAX_READING_CACHE - 2];
    s8ReadingT2 = psFscCLSensorInfo->as8RealValue[MAX_READING_CACHE - 1];

    /*calculate pwm by PID formula */
    fPIncrement = (float)(psFscCLSensorInfo->fP * (s8ReadingT2 - s8ReadingT1));
    fIIncrement = (float)(psFscCLSensorInfo->fI * (s8ReadingT2 - psFscCLSensorInfo->s8Setpoint));
    fDIncrement = (float)(psFscCLSensorInfo->fD * (s8ReadingT2 + s8ReadingT - 2*s8ReadingT1));
    fPWMIncrease = fPIncrement + fIIncrement + fDIncrement;
        
    if((psFscCLSensorInfo->s16LastPwmPIDCalculate + fPWMIncrease) < 0)
    {
        u8Pwm = 0;
    }
    else if((psFscCLSensorInfo->s16LastPwmPIDCalculate + fPWMIncrease) > 100)
    {
        u8Pwm = 100;
    }
    else
    {   
        u8Pwm = (INT8U)(psFscCLSensorInfo->s16LastPwmPIDCalculate + fPWMIncrease + 0.5);
    }

    psFscCLSensorInfo->fPIncrement = fPIncrement;
    psFscCLSensorInfo->fIIncrement = fIIncrement;
    psFscCLSensorInfo->fDIncrement = fDIncrement;

    /*judge if greater than max pwm */
    if(u8Pwm >= u8MaxPwm)
    {
        u8Pwm = u8MaxPwm;
    }

    /*judge if less than max pwm */
    if(u8Pwm <= u8MinPwm)
    {
        u8Pwm = u8MinPwm;
    }

    psFscCLSensorInfo->u8PwmPIDCalculate = u8Pwm;
    psFscCLSensorInfo->s16LastPwmPIDCalculate = (INT16S)u8Pwm;

    /*Calculate pwm after weighting*/
    for(u8FanIndex = 0; u8FanIndex < MAX_FSC_PWM_CHANNEL; u8FanIndex++)
    {
        psFscCLSensorInfo->u8PwmAfterWeighting[u8FanIndex] = (INT8U)((float)u8Pwm * ((float)psFscCLSensorInfo->au8FanWeight[u8FanIndex] / 100));
    }
    
    /*Calculate pwm after hysteresis*/
    for(u8FanIndex = 0; u8FanIndex < MAX_FSC_PWM_CHANNEL; u8FanIndex++)
    {
        if(psFscCLSensorInfo->u32CalculateTick < (MAX_FAN_AVERAGE_COUNT-1))
        {
            psFscCLSensorInfo->u8PwmAfterWeightingCache[u8FanIndex][psFscCLSensorInfo->u32CalculateTick] = psFscCLSensorInfo->u8PwmAfterWeighting[u8FanIndex];
        }
        else
        {
            if(MAX_FAN_AVERAGE_COUNT == psFscCLSensorInfo->u32CalculateTick)
            {
                psFscCLSensorInfo->u8PwmAfterWeightingCache[u8FanIndex][MAX_FAN_AVERAGE_COUNT-1] = psFscCLSensorInfo->u8PwmAfterWeighting[u8FanIndex];
            }
            else
            {
                for(u8HysteresisIndex = 0; u8HysteresisIndex < (MAX_FAN_AVERAGE_COUNT - 1); u8HysteresisIndex++)
                {
                    psFscCLSensorInfo->u8PwmAfterWeightingCache[u8FanIndex][u8HysteresisIndex] = psFscCLSensorInfo->u8PwmAfterWeightingCache[u8FanIndex][u8HysteresisIndex+1];
                }
                psFscCLSensorInfo->u8PwmAfterWeightingCache[u8FanIndex][MAX_FAN_AVERAGE_COUNT-1] = psFscCLSensorInfo->u8PwmAfterWeighting[u8FanIndex];
                
            }

            s16PwmSum = 0;
            if(psFscCLSensorInfo->u8Hysteresis != 0)
            {
                for(u8HysteresisIndex = 0; u8HysteresisIndex < psFscCLSensorInfo->u8Hysteresis; u8HysteresisIndex++)
                {
                    s16PwmSum += psFscCLSensorInfo->u8PwmAfterWeightingCache[u8FanIndex][MAX_FAN_AVERAGE_COUNT-1-u8HysteresisIndex];
                }

                psFscCLSensorInfo->u8PwmAfterHysteresis[u8FanIndex] = s16PwmSum / psFscCLSensorInfo->u8Hysteresis;
            }
            else
            {
                psFscCLSensorInfo->u8PwmAfterHysteresis[u8FanIndex] = psFscCLSensorInfo->u8PwmAfterWeightingCache[u8FanIndex][(MAX_FAN_AVERAGE_COUNT - 1)];
            }
        }
    }

    psFscCLSensorInfo->u32CalculateTick ++;
    return FUNC_OK;
}


EFuncRetCode LuxFSCHandleCloseloop(SFscInfo* psFscInfo)
{
    INT8U u8SensorIndex = 0;
    SFscCLSensorInfo* psFscCLSensorInfo = NULL;
    INT32U u32Tick = 0;
    
    u32Tick = psFscInfo->sFscRunningInfo.u32Tick;
    for(u8SensorIndex = 0; u8SensorIndex < psFscInfo->sFscCLSensor.u8TotalCLSensor; u8SensorIndex++)
    {
        psFscCLSensorInfo = &psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex];

        if(0 != LuxStrncmp(psFscCLSensorInfo->acCLSensorStatus, "Enable", LuxStrlen("Enable")))
        {
            /*LuxPrintf("Closeloop sensor %s is not enable, skip\n",psFscCLSensorInfo->acSensorName);*/
            psFscCLSensorInfo->u8PwmPIDCalculate = 0;
            continue;
        }
        
        /*every sensor has it's polling cycles */
        if(0 == (u32Tick % psFscCLSensorInfo->u8DT))
        {
            if(FSC_SENSOR_NOT_PRESENT == psFscCLSensorInfo->u8Present)
            {
                /*no need to do fsc control if sensor is not present */
                /*LuxPrintf("Sensor %s no need to do fsc control because sensor is not preset\n",psFscCLSensorInfo->acSensorName);*/
                psFscCLSensorInfo->u8PwmPIDCalculate=0;
                continue;
            }

            /*if sensor status is abnormal, skip calculate pwm. Abnormal event handle it. */
            if(FSC_SENSOR_ABNORMAL == psFscCLSensorInfo->u8Abnormal)
            {
                /*LuxPrintf("Sensor %s is abnormal, skip.\n",psFscCLSensorInfo->acSensorName);*/
                psFscCLSensorInfo->u8PwmPIDCalculate = 0;
                continue;
            }

            /*Closeloop sensor cache reading need >= 3, because PID need sensor reading at t-2, t-1, t. if buffer is not full, skip*/
            if(SENSOR_REAL_VALUE_INITIAL == psFscCLSensorInfo->as8RealValue[MAX_READING_CACHE - 1])
            {
                /*LuxPrintf("Sensor %s reading cache is less than 3, skip.\n",psFscCLSensorInfo->acSensorName);*/
                psFscCLSensorInfo->u8PwmPIDCalculate = 0;
                continue;
            }

            /*lookup true setpoint */
            LuxFSCGetTureSetpoint(psFscCLSensorInfo, u8SensorIndex);

            /*lookup true PID parameter from e and ec array */
            LuxFSCGetTruePID(psFscCLSensorInfo, psFscInfo->sFscCLSensor.u8CLSensorESection, psFscInfo->sFscCLSensor.u8CLSensorECSection);
            
            /*do openloop sensor pwm calculate */
            LuxFSCCloseloopCalculateDuty(psFscCLSensorInfo, psFscInfo->sFscFanConfig.u8MaxFanDuty, psFscInfo->sFscFanConfig.u8MinFanDuty);
            
        }
        else
        {
            continue;
        }
    }
    return FUNC_OK;
}

EFuncRetCode LuxSetCPLDPTCHeatPWM(INT8U u8PwmNumber, INT8U u8PTCPWM)
{
    char acCmdbuff[512] = {0};
    EFuncRetCode eRet;

    LuxSprintf(acCmdbuff, "i2ctransfer -y -a %d w3@0x%x 0x%x 0x00 0x%x",FCB_I2C_BUS, \
        FCB_CPLD_SLAVE_ADDR, (REG_FCB_PTC_DIMM0_SET_PWM + u8PwmNumber), u8PTCPWM);
    
    LuxPrintf("LuxSetPTCHeatPWM : %s\n",acCmdbuff);
    eRet = LuxSystem(acCmdbuff);

    return eRet;
}

EFuncRetCode LuxSetCPLDHeatPWM(INT8U u8PwmNumber, INT8U u8DutycycleValue)
{
    INT8U au8WriteData[32] = {0};
    INT8U u8WriteLen = 0;
    INT8U au8ReadBuf[32] = {0};
    INT8U u8ReadLen = 0;

    au8WriteData[0] = sSFscHeatReg[u8PwmNumber].u16Reg;
    au8WriteData[1] = 0x00;
    au8WriteData[2] = u8DutycycleValue;
    u8WriteLen = 3;
    if(FUNC_FAILED == i2cReadWrite(FCB_I2C_BUS, FCB_CPLD_SLAVE_ADDR, au8WriteData, u8WriteLen, au8ReadBuf, u8ReadLen))
    {
        LuxPrintf("Write FCB data fail\n");
        return FUNC_FAILED;
    }
    else
    {
        //LuxPrintf("Write CPLD heat Reg 0x%x Data 0x%x \n",au8WriteData[0], u8DutycycleValue);
    }
    return FUNC_OK;
}

EFuncRetCode LuxSetCPLDPWM(INT8U u8PwmNumber, INT8U u8DutycycleValue)
{
    INT8U au8WriteData[32] = {0};
    INT8U u8WriteLen = 0;
    INT8U au8ReadBuf[32] = {0};
    INT8U u8ReadLen = 0;

    au8WriteData[0] = sSFscFanReg[u8PwmNumber].u16Reg;
    au8WriteData[1] = 0x00;
    au8WriteData[2] = u8DutycycleValue;
    u8WriteLen = 3;
    if(FUNC_FAILED == i2cReadWrite(FCB_I2C_BUS, FCB_CPLD_SLAVE_ADDR, au8WriteData, u8WriteLen, au8ReadBuf, u8ReadLen))
    {
        LuxPrintf("Set DIMM Fan Write FCB data fail\n");
        return FUNC_FAILED;
    }
    else
    {
        //LuxPrintf("Set DIMM Fan Write CPLD Reg 0x%x Data 0x%x \n",au8WriteData[0], u8DutycycleValue);
    }
    return FUNC_OK;
}

EFuncRetCode LuxSetCPLD6056FanPWM(INT8U u8PwmNumber, INT8U u8DutycycleValue)
{
    INT8U au8WriteData[32] = {0};
    INT8U u8WriteLen = 0;
    INT8U au8ReadBuf[32] = {0};
    INT8U u8ReadLen = 0;

    au8WriteData[0] = sFsc6056FanReg[u8PwmNumber].u16Reg;
    au8WriteData[1] = 0x00;
    au8WriteData[2] = u8DutycycleValue;
    u8WriteLen = 3;
    if(FUNC_FAILED == i2cReadWrite(FCB_I2C_BUS, FCB_CPLD_SLAVE_ADDR, au8WriteData, u8WriteLen, au8ReadBuf, u8ReadLen))
    {
        LuxPrintf("Set 6056 Fan Write FCB data fail\n");
        return FUNC_FAILED;
    }
    else
    {
        //LuxPrintf("Set 6056 Fan Write CPLD Reg 0x%x Data 0x%x \n",au8WriteData[0], u8DutycycleValue);
    }
    return FUNC_OK;
}

EFuncRetCode LuxFSCOutputPWM(INT8U u8PwmChannel, INT8U u8Pwm)
{
    if(u8Pwm >= PTC_PRE_HEAT_MAX_PWM)
    {
        u8Pwm = PTC_PRE_HEAT_MAX_PWM;
    }

    if(0 == g_u8FSCEnable)
    {
        u8Pwm = 0;
    }

    if(TRUE == g_u8FSCPresent)
    {
        if(FUNC_FAILED == LuxSetCPLDPWM(u8PwmChannel, FCB_6056_PRE_HEAT_PWM))
        {
            LuxPrintf("Set FCB CPLD pwm %d dutycycle to %d failed\n",u8PwmChannel, u8Pwm);
            return FUNC_FAILED;
        }

        if(FUNC_FAILED == LuxSetCPLDHeatPWM(u8PwmChannel, u8Pwm))
        {
            LuxPrintf("Set FCB heat pwm %d dutycycle to %d failed\n",u8PwmChannel, u8Pwm);
            return FUNC_FAILED;
        }
    }

    return FUNC_OK;
}

EFuncRetCode LuxFSCManualOutputPWM(INT8U u8PwmChannel, INT8U u8Pwm)
{
    if(TRUE == g_u8FSCPresent)
    {
        if(FUNC_FAILED == LuxSetCPLDPWM(u8PwmChannel, u8Pwm))
        {
            LuxPrintf("Manual set FCB CPLD pwm %d dutycycle to %d failed\n",u8PwmChannel, u8Pwm);
            return FUNC_FAILED;
        }
    }
    return FUNC_OK;
}


EFuncRetCode LuxFSCCoverPreHeat(SFscInfo* psFscInfo)
{
    INT8U u8DIMMIndex = 0;

    for(u8DIMMIndex = 0; u8DIMMIndex < MAX_DIMM_SLOT; u8DIMMIndex++)
    {
        LuxSetCPLDPTCHeatPWM(u8DIMMIndex, PTC_PRE_HEAT_PWM);
    }

    return FUNC_OK;
}


EFuncRetCode LuxFSCHandlePwmOut(SFscInfo* psFscInfo)
{
    INT8U u8SensorIndex = 0;
    INT8U u8PwmIndex = 0;
    INT8U u8OLPwm = 0;
    INT8U u8AbnormalPwm = 0;
    INT8U u8AbnormalSensorIncreasePwm = 0;
    INT8U u8IncreasePwm[MAX_FSC_PWM_CHANNEL] = {0};
    INT8U au8CLPwm[MAX_FSC_PWM_CHANNEL] = {0};
    INT8U au8PwmTemp[MAX_FSC_PWM_CHANNEL] = {0};
    char acOLMaxPwmSensorName[MAX_SENSOR_NAME_LENGTH] = {0};
    char acCLMaxPwmSensorName[MAX_SENSOR_NAME_LENGTH] = {0};
    char acMaxAbnormalPwmSensorName[MAX_SENSOR_NAME_LENGTH] = {0};

    /*step 1, get closeloop sensor pwm output */
    for(u8PwmIndex = 0; u8PwmIndex < MAX_FSC_PWM_CHANNEL; u8PwmIndex++)
    {
        for(u8SensorIndex = 0; u8SensorIndex < psFscInfo->sFscCLSensor.u8TotalCLSensor; u8SensorIndex++)
        {
            if(psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8PwmAfterHysteresis[u8PwmIndex] > au8CLPwm[u8PwmIndex])
            {
                au8CLPwm[u8PwmIndex] = psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8PwmAfterHysteresis[u8PwmIndex];
                LuxMemset(acCLMaxPwmSensorName, 0, MAX_SENSOR_NAME_LENGTH);
                memcpy(acCLMaxPwmSensorName, psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].acSensorName, \
                LuxStrlen(psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].acSensorName));
            }
        }
    }
    LuxMemcpy(psFscInfo->sFscRunningInfo.au8CLPwm,au8CLPwm, MAX_FSC_PWM_CHANNEL);

    /*step 2, output auto pwm */
    for(u8PwmIndex = 0; u8PwmIndex < MAX_FSC_PWM_CHANNEL; u8PwmIndex++)
    {
        psFscInfo->sFscRunningInfo.au8PwmOut[u8PwmIndex] = psFscInfo->sFscRunningInfo.au8CLPwm[u8PwmIndex];
        if(psFscInfo->sFscRunningInfo.au8PwmOut[u8PwmIndex] > psFscInfo->sFscFanConfig.u8MaxFanDuty)
        {
            psFscInfo->sFscRunningInfo.au8PwmOut[u8PwmIndex] = psFscInfo->sFscFanConfig.u8MaxFanDuty;
        }
        if(psFscInfo->sFscRunningInfo.au8PwmOut[u8PwmIndex] < psFscInfo->sFscFanConfig.u8MinFanDuty)
        {
            psFscInfo->sFscRunningInfo.au8PwmOut[u8PwmIndex] = psFscInfo->sFscFanConfig.u8MinFanDuty;
        }

        LuxFSCOutputPWM(u8PwmIndex, psFscInfo->sFscRunningInfo.au8PwmOut[u8PwmIndex]);
    }
    return FUNC_OK;
}

EFuncRetCode LuxFSCHandleThermalDebug(SFscInfo* psFscInfo)
{
    INT8U u8PwmIndex = 0;
    INT8U u8SensorIndex = 0;

    /*check if thermal debug message opened */
    psFscInfo->sFscRunningInfo.u8ThermalDebug = FSC_OPEN_THERMAL_DEBUG;
    if(FSC_OPEN_THERMAL_DEBUG == psFscInfo->sFscRunningInfo.u8ThermalDebug)
    {
        LuxPrintf("\t************************ Thermal Debug **********************\n");
        LuxPrintf("\tpsFscInfo->sFscRunningInfo.u8ControlMode = %d\n",psFscInfo->sFscRunningInfo.u8ControlMode);
        
        LuxPrintf("\tCloseloop:\n");
        for(u8SensorIndex = 0; u8SensorIndex < psFscInfo->sFscCLSensor.u8TotalCLSensor; u8SensorIndex++)
        {
            LuxPrintf("\tCloseloop sensor %d name: %s\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].acSensorName);
            LuxPrintf("\tCloseloop sensor %d number: 0x%x\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8SensorNumber);
            LuxPrintf("\tCloseloop sensor %d u8Present: %d\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8Present);
            LuxPrintf("\tCloseloop sensor %d u8Abnormal: %d\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8Abnormal);
            LuxPrintf("\tCloseloop sensor %d u8Health: %d\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8Health);
            LuxPrintf("\tCloseloop sensor %d s8Setpoint: %d\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].s8Setpoint);
            LuxPrintf("\tCloseloop sensor %d p: %f\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].fP);
            LuxPrintf("\tCloseloop sensor %d i: %f\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].fI);
            LuxPrintf("\tCloseloop sensor %d d: %f\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].fD);
            LuxPrintf("\tCloseloop sensor %d reading: %d,%d,%d\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].as8RealValue[MAX_READING_CACHE - 3],\
                psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].as8RealValue[MAX_READING_CACHE - 2],\
                psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].as8RealValue[MAX_READING_CACHE - 1]);
            LuxPrintf("\tCloseloop sensor %d s16LastPwmPIDCalculate: %d\n\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].s16LastPwmPIDCalculate);
            LuxPrintf("\tCloseloop sensor %d fPIncrement: %f\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].fPIncrement);
            LuxPrintf("\tCloseloop sensor %d fIIncrement: %f\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].fIIncrement);
            LuxPrintf("\tCloseloop sensor %d fDIncrement: %f\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].fDIncrement);
            LuxPrintf("\tCloseloop sensor %d u8PwmPIDCalculate: %d\n",(u8SensorIndex+1), psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8PwmPIDCalculate);
            LuxPrintf("\tCloseloop sensor %d u8PwmAfterWeighting:",(u8SensorIndex+1));
            for(u8PwmIndex = 0; u8PwmIndex < MAX_FSC_PWM_CHANNEL; u8PwmIndex++)
            {
                LuxPrintf("%d ",psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8PwmAfterWeighting[u8PwmIndex]);
            }
            LuxPrintf("\n");

            LuxPrintf("\tCloseloop sensor %d u8PwmAfterHysteresis:",(u8SensorIndex+1));
            for(u8PwmIndex = 0; u8PwmIndex < MAX_FSC_PWM_CHANNEL; u8PwmIndex++)
            {
                LuxPrintf("%d ",psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8PwmAfterHysteresis[u8PwmIndex]);
            }
            LuxPrintf("\n");

            LuxPrintf("\tCloseloop sensor %d u8PwmAfterHysteresis:",(u8SensorIndex+1));
            for(u8PwmIndex = 0; u8PwmIndex < MAX_FSC_PWM_CHANNEL; u8PwmIndex++)
            {
                LuxPrintf("%d ",psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].u8PwmAfterHysteresis[u8PwmIndex]);
            }
            LuxPrintf("\n\n");
        }
        
        LuxPrintf("\tFinally output:\n");
        for(u8PwmIndex = 0; u8PwmIndex < MAX_FSC_PWM_CHANNEL; u8PwmIndex++)
        {
            LuxPrintf("\tpwm channel %d output: %d\n",u8PwmIndex,psFscInfo->sFscRunningInfo.au8PwmOut[u8PwmIndex]);
        }
        for(u8PwmIndex = 0; u8PwmIndex < MAX_FSC_PWM_CHANNEL; u8PwmIndex++)
        {
            LuxPrintf("\tManual output: %d\n",psFscInfo->sFscRunningInfo.au8ManualPwmOut[u8PwmIndex]);
        }
    }

    return FUNC_OK;
}

EFuncRetCode LuxPrintDIMMTemp(SFscInfo* psFscInfo)
{
    INT8U u8PwmIndex = 0;
    INT8U u8SensorIndex = 0;

    /*check if thermal debug message opened */
    psFscInfo->sFscRunningInfo.u8ThermalDebug = FSC_OPEN_THERMAL_DEBUG;
    if(FSC_OPEN_THERMAL_DEBUG == psFscInfo->sFscRunningInfo.u8ThermalDebug)
    {
        LuxPrintf("\t************************ DIMM Temperature Print **********************\n");
        for(u8SensorIndex = 0; u8SensorIndex < 24; u8SensorIndex++)
        {
            LuxPrintf("\tDIMM Temp sensor %d reading: %d\n",(u8SensorIndex+1),psFscInfo->sFscCLSensor.asFscCLSensorInfo[u8SensorIndex].as8RealValue[MAX_READING_CACHE - 1]);
        }
    }
    LuxPrintf("\n\n");
    return FUNC_OK;
}

EFuncRetCode LuxFSCGetEnableStatus(INT8U* pu8Value)
{
    FILE* fp = NULL;
    char acCmdbuff[512] = {0};
    char acCmdstr[1024] = {0};
    INT8U u8Value = 0;

    if(0 != LuxAccess(FSC_ENABLE_STATUS_PATH, F_OK))
    {
        return FUNC_FAILED;
    }

    LuxSprintf(acCmdstr, "cat %s",FSC_ENABLE_STATUS_PATH);
    if ((fp = LuxPopen(acCmdstr, "r")) != NULL)
    {
        fgets(acCmdbuff, sizeof(acCmdbuff), fp);
        u8Value = strtoul(acCmdbuff, NULL, 10);
        LuxPclose(fp);
        if (u8Value > 1)
        {
            return FUNC_FAILED;
        }
        else
        {
            *pu8Value = (INT8U)u8Value;
            return FUNC_OK;
        }
    }
    else
    {
        return FUNC_FAILED;
    }

    return FUNC_OK;
}

EFuncRetCode LuxCheckFCBPresent()
{
    INT8U au8WriteData[32] = {0};
    INT8U u8WriteLen = 0;
    INT8U au8ReadBuf[32] = {0};
    INT8U u8ReadLen = 0;

    au8WriteData[0] = 0x05;
    au8WriteData[1] = 0x00;
    u8WriteLen = 2;
    u8ReadLen = 1;
    if(FUNC_FAILED == i2cReadWrite(FCB_I2C_BUS, FCB_CPLD_SLAVE_ADDR, au8WriteData, u8WriteLen, au8ReadBuf, u8ReadLen))
    {
        LuxPrintf("FCB is not present!!!\n");
        return FUNC_FAILED;
    }
    else
    {
        LuxPrintf("FCB is present.\n");
    }
    return FUNC_OK;
}

EFuncRetCode LuxFSCGetDIMMTotalPower(INT16U *pu16DIMMTotalPower)
{
    INT8U u8SensorIndex = 0;
    INT8S s8SensorReading = 0;
    INT8U u8Status = 0;
    INT8U u8Present = 0;
    INT16U u16Power = 0;

    for(u8SensorIndex = 0; u8SensorIndex < MAX_DIMM_POWER_SLOT; u8SensorIndex++)
    {
        LuxFSCDbusGetDIMMPowerValue(sSDIMMPowerDbus[u8SensorIndex].acDbusPath, &s8SensorReading, &u8Present, &u8Status);
        LuxPrintf("DIMMPower %d u8Power = %d\n",u8SensorIndex,s8SensorReading);
        u16Power += (INT16U)s8SensorReading;
    }

    *pu16DIMMTotalPower = u16Power;
    LuxPrintf("u8Power = %d\n",*pu16DIMMTotalPower);
    return FUNC_OK;
}


EFuncRetCode LuxFSCHandle6056Fan(SFscInfo* psFscInfo)
{
    INT8U u8PwmChannel = 0;
    INT8U u8Pwm = FCB_6056_PRE_HEAT_PWM;

    for(u8PwmChannel = 0; u8PwmChannel < FCB_6056_FAN_NUM; u8PwmChannel++)
    {
        if(0 == g_u8FSCEnable)
        {
            u8Pwm = 0;
        }
        if(TRUE == g_u8FSCPresent)
        {
            if(FUNC_FAILED == LuxSetCPLD6056FanPWM(u8PwmChannel, u8Pwm))
            {
                LuxPrintf("Set FCB 6056 fan pwm %d dutycycle to %d failed\n",u8PwmChannel, u8Pwm);
                return FUNC_FAILED;
            }
        }
    }
    
    return FUNC_OK;
}

int main(void)
{
    INT32U u32Tick = 0;

    LuxPrintf("******************************************************************************\n");
    LuxPrintf("************************ Luxshare DIMM FSC Task Begin ************************\n");
    LuxPrintf("******************************************************************************\n");
    INT8U u8TurnOnSystemFlag = 0;
    INT8U u8PwmChannel = 0;
    EFuncRetCode eRet;
    INT8U u8DIMMFSCChannnel = 0;
    INT8U u8FSC6056Channnel = 0;
    INT8U u8FSCEnableVaule = 0;
    INT8U u8DIMMIndex = 0;
    INT8U u8PreHeatDone = 0;

    LuxFSCInit();

    if(FUNC_OK == LuxCheckFCBPresent())
    {
        g_u8FSCPresent = TRUE;
    }

    while(1)
    {
        sleep(1);
        /*Check fan table update flag. */
        LuxFSCFanTableUpdate(&psFscInfo);

        /*if fan table load fail, return error */
        if(FSC_FAN_TABLE_LOAD_FAIL == psFscInfo.sFscRunningInfo.u8FanTableLoadStatus)
        {
            LuxPrintf("Fan table load fail, return error.\n");
            return FUNC_FAILED; 
        }

        /*Check fsc enable status, if not enable by OEM command, don't do dimm fsc logic and turn off 6056*/
        eRet = LuxFSCGetEnableStatus(&u8FSCEnableVaule);
        if((FUNC_FAILED == eRet) || (0 == u8FSCEnableVaule))
        {
            g_u8FSCEnable = 0;
        }
        else
        {
            g_u8FSCEnable = 1;
        }

        if(0 == g_u8FSCEnable)
        {
            continue;
        }

        LuxFSCGetFSCControlMode(&psFscInfo);
        /*Check if manual control */
        if(FSC_FAN_TABLE_MANUAL == psFscInfo.sFscRunningInfo.u8ControlMode)
        {
            for(u8PwmChannel = 0; u8PwmChannel < MAX_FSC_PWM_CHANNEL; u8PwmChannel++)
            {
                LuxFSCManualOutputPWM(u8PwmChannel, psFscInfo.sFscRunningInfo.au8ManualPwmOut[u8PwmChannel]);
            }
            continue;
        }

        if(PS_GOOD_OK == LuxPDKGetPSGood())
        {
            if(0 == u8PreHeatDone)
            {
                /*After power on, turn off all DIMM fan and heat */
                for(u8DIMMIndex = 0; u8DIMMIndex < MAX_DIMM_SLOT; u8DIMMIndex++)
                {
                    LuxSetCPLDHeatPWM(u8DIMMIndex, 0);
                    LuxSetCPLDPWM(u8DIMMIndex, 0);
                }
                u8PreHeatDone = 1;
            }
            continue;
        }
        else
        {
            u8PreHeatDone = 0;
            psFscInfo.sFscRunningInfo.u32Tick ++;
            if(psFscInfo.sFscRunningInfo.u32Tick < POWERON_FSC_DELAY)
            {
                continue;
            }
        }

        if(TRUE == g_u8FSCPresent)
        {
            LuxFSCCoverMaxTemp(&psFscInfo);
        }

        /*Get sensor status and reading every second */
        LuxFSCGetSensorStatus(&psFscInfo);

        /*Handle closeloop sensor */
        LuxFSCHandleCloseloop(&psFscInfo);

        /*Handle closeloop sensor */
        LuxFSCHandle6056Fan(&psFscInfo);

        /*Handle output pwm */
        LuxFSCHandlePwmOut(&psFscInfo);

        /*Handle thermal debug */
        //LuxFSCHandleThermalDebug(&psFscInfo);

        //LuxPrintDIMMTemp(&psFscInfo);
    }
    return 0;
}
