#include <stdio.h>      /*標準輸入輸出定義*/
#include <stdlib.h>     /*標準函數庫定義*/
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>

//------------------------------------------------------------------------------
int opcc_chk_reserve_expired(byte gun_index)
{
    int result = NO;
    struct tm expiredDate;
    struct timeb expiredTime;

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (sscanf((char *) ShmOCPP16Data->ReserveNow[gun_index].ExpiryDate,
                   "%4d-%2d-%2dT%2d:%2d:%2d", &expiredDate.tm_year,
                   &expiredDate.tm_mon, &expiredDate.tm_mday, &expiredDate.tm_hour,
                   &expiredDate.tm_min, &expiredDate.tm_sec) == 6) {
            expiredDate.tm_year -= 1900;
            expiredDate.tm_mon -= 1;

            expiredTime.time = mktime(&expiredDate);
            if (!CheckTimeOut(expiredTime)) {
                result = YES;
            }
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (sscanf((char *) ShmOCPP20Data->ReserveNow[gun_index].expiryDateTime,
                   "%4d-%2d-%2dT%2d:%2d:%2d", &expiredDate.tm_year,
                   &expiredDate.tm_mon, &expiredDate.tm_mday, &expiredDate.tm_hour,
                   &expiredDate.tm_min, &expiredDate.tm_sec) == 6) {
            expiredDate.tm_year -= 1900;
            expiredDate.tm_mon -= 1;

            expiredTime.time = mktime(&expiredDate);
            if (!CheckTimeOut(expiredTime)) {
                result = YES;
            }
        }
    }

    return result;
}

//===============================================
// OCPP routine
//===============================================
void ocpp_process_start()
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        system("/root/OcppBackend &");
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        system("/root/OcppBackend20 &");
    }
}

void ocpp_auto_response_BootNotification()
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (ShmOCPP16Data->SpMsg.bits.BootNotificationConf == YES) {
            ShmOCPP16Data->SpMsg.bits.BootNotificationConf = NO;
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (ShmOCPP20Data->SpMsg.bits.BootNotificationConf == YES) {
            ShmOCPP20Data->SpMsg.bits.BootNotificationConf = NO;
        }
    }
}

bool ocpp_is_resPass_StartTransationConf(byte gun_index)
{
    bool result = false;

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        result = ShmOCPP16Data->CpMsg.bits[gun_index].StartTransactionConf;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        result = ShmOCPP20Data->CpMsg.bits[gun_index].TransactionEventConf;
    }

    return result;
}

void ocpp_auto_response_StartTransationConf(byte gun_index)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (ShmOCPP16Data->CpMsg.bits[gun_index].StartTransactionConf) {
            ShmOCPP16Data->CpMsg.bits[gun_index].StartTransactionConf = NO;
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (ShmOCPP20Data->CpMsg.bits[gun_index].TransactionEventConf) {
            ShmOCPP20Data->CpMsg.bits[gun_index].TransactionEventConf = NO;
        }
    }
}

void ocpp_auto_response_ReserveConf(byte gun_index)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        ShmOCPP16Data->CsMsg.bits[gun_index].ReserveNowConf = YES;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        ShmOCPP20Data->CsMsg.bits[gun_index].ReserveNowConf = YES;
    }
}

bool ocpp_chk_authrization_cmd()
{
    char buf2[16] = "";
    memset(buf2, 0, ARRAY_SIZE(buf2));

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        sprintf(buf2, "%s",   ShmOCPP16Data->Authorize.ResponseIdTagInfo.Status);
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        sprintf(buf2, "%s",   ShmOCPP20Data->Authorize.Response_idTokenInfo.status);
    }
    // 因為無法得知實際的長度,所以只能用搜尋的方式
    if (strcmp(buf2, "Accepted") == EQUAL) {
        return true;
    }

    return false;
}

bool opcc_sub_get_reset_req()
{
    bool result = false;

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        result = ShmOCPP16Data->MsMsg.bits.ResetReq;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        result = ShmOCPP20Data->MsMsg.bits.ResetReq;
    }

    return result;
}

void ocpp_sub_run_reset(bool canReset)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (canReset && strcmp((char *)ShmOCPP16Data->Reset.Type, "Hard") == EQUAL) {
            DEBUG_ERROR_MSG("****** Hard Reboot ****** \n");
            sprintf((char *)ShmOCPP16Data->Reset.ResponseStatus, "Accepted");
            ShmOCPP16Data->MsMsg.bits.ResetReq = NO;
            ShmOCPP16Data->MsMsg.bits.ResetConf = YES;
            sleep(3);
            system("reboot -f");
        } else if (canReset && strcmp((char *)ShmOCPP16Data->Reset.Type, "Soft") == EQUAL) {
            DEBUG_ERROR_MSG("****** Soft Reboot ****** \n");
            sprintf((char *)ShmOCPP16Data->Reset.ResponseStatus, "Accepted");
            ShmOCPP16Data->MsMsg.bits.ResetReq = NO;
            ShmOCPP16Data->MsMsg.bits.ResetConf = YES;
            sleep(3);
            KillAllTask();
            system("/usr/bin/run_evse_restart.sh");
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (canReset && strcmp((char *)ShmOCPP20Data->Reset.type, "Immediate") == EQUAL) {
            DEBUG_ERROR_MSG("****** Hard Reboot ****** \n");
            sprintf((char *)ShmOCPP20Data->Reset.Response_status, "Accepted");
            ShmOCPP20Data->MsMsg.bits.ResetReq = NO;
            ShmOCPP20Data->MsMsg.bits.ResetConf = YES;
            sleep(3);
            system("reboot -f");
        } else if (canReset && strcmp((char *)ShmOCPP20Data->Reset.type, "OnIdle") == EQUAL) {
            DEBUG_ERROR_MSG("****** Soft Reboot ****** \n");
            sprintf((char *)ShmOCPP20Data->Reset.Response_status, "Accepted");
            ShmOCPP20Data->MsMsg.bits.ResetReq = NO;
            ShmOCPP20Data->MsMsg.bits.ResetConf = YES;
            sleep(3);
            KillAllTask();
            system("/usr/bin/run_evse_restart.sh");
        }
    }
}

void ocpp_chk_reset_cmd()
{
    if (opcc_sub_get_reset_req()) {
        bool canReset = true;

        if (ShmSysConfigAndInfo->SysWarningInfo.Level != 2) {
            for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++) {
                if (chargingInfo[_index]->SystemStatus != S_IDLE &&
                        chargingInfo[_index]->SystemStatus != S_RESERVATION &&
                        chargingInfo[_index]->SystemStatus != S_MAINTAIN) {
                    canReset = false;
                    if (chargingInfo[_index]->SystemStatus >= S_REASSIGN &&
                            chargingInfo[_index]->SystemStatus < S_TERMINATING) {
                        // Reset 系統先停止充電
                        ChargingTerminalProcess(_index);
                    }
                }
            }
        }

        if (canReset) {
            // Reset -> change status to maintain.
            for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++) {
                setChargerMode(_index, MODE_MAINTAIN);
            }
            ChangeLcmByIndex(_LCM_FIX);
        }

        ocpp_sub_run_reset(canReset);
    }
}

void ocpp_chk_reserved_cmd(byte gunIndex)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (chargingInfo[gunIndex]->SystemStatus == S_IDLE &&
                ShmOCPP16Data->CsMsg.bits[gunIndex].ReserveNowReq == YES) {
            ShmOCPP16Data->CsMsg.bits[gunIndex].ReserveNowReq = NO;
            if (opcc_chk_reserve_expired(gunIndex)) {
                PRINTF_FUNC("***************ChkOcppStatus : OcppReservedStatus******************** \n");
                DEBUG_ERROR_MSG("***************ChkOcppStatus : OcppReservedStatus******************** \n");
                chargingInfo[gunIndex]->ReservationId = ShmOCPP16Data->ReserveNow[gunIndex].ReservationId;
                chargingInfo[gunIndex]->SystemStatus = S_RESERVATION;
            }
            ShmOCPP16Data->CsMsg.bits[gunIndex].ReserveNowConf = YES;
        }

        if (chargingInfo[gunIndex]->SystemStatus == S_RESERVATION &&
                ShmOCPP16Data->CsMsg.bits[gunIndex].CancelReservationReq == YES) {
            ShmOCPP16Data->CsMsg.bits[gunIndex].CancelReservationReq = NO;
            if (opcc_chk_reserve_expired(gunIndex)) {
                PRINTF_FUNC("***************ChkOcppStatus : Cancel OcppReservedStatus******************** \n");
                DEBUG_ERROR_MSG("***************ChkOcppStatus : Cancel OcppReservedStatus******************** \n");
                chargingInfo[gunIndex]->ReservationId = 0;
                chargingInfo[gunIndex]->SystemStatus = S_IDLE;
            }
            ShmOCPP16Data->CsMsg.bits[gunIndex].CancelReservationConf = YES;
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (chargingInfo[gunIndex]->SystemStatus == S_IDLE &&
                ShmOCPP20Data->CsMsg.bits[gunIndex].ReserveNowReq == YES) {
            ShmOCPP20Data->CsMsg.bits[gunIndex].ReserveNowReq = NO;
            if (opcc_chk_reserve_expired(gunIndex)) {
                PRINTF_FUNC("***************ChkOcppStatus : OcppReservedStatus******************** \n");
                DEBUG_ERROR_MSG("***************ChkOcppStatus : OcppReservedStatus******************** \n");
                chargingInfo[gunIndex]->ReservationId = ShmOCPP20Data->ReserveNow[gunIndex].id;
                chargingInfo[gunIndex]->SystemStatus = S_RESERVATION;
            }
            ShmOCPP20Data->CsMsg.bits[gunIndex].ReserveNowConf = YES;
        }

        if (chargingInfo[gunIndex]->SystemStatus == S_RESERVATION &&
                ShmOCPP20Data->CsMsg.bits[gunIndex].CancelReservationReq == YES) {
            ShmOCPP20Data->CsMsg.bits[gunIndex].CancelReservationReq = NO;
            if (opcc_chk_reserve_expired(gunIndex)) {
                PRINTF_FUNC("***************ChkOcppStatus : Cancel OcppReservedStatus******************** \n");
                DEBUG_ERROR_MSG("***************ChkOcppStatus : Cancel OcppReservedStatus******************** \n");
                chargingInfo[gunIndex]->ReservationId = 0;
                chargingInfo[gunIndex]->SystemStatus = S_IDLE;
            }
            ShmOCPP20Data->CsMsg.bits[gunIndex].CancelReservationConf = YES;
        }
    }
}

void ocpp_chk_availability_cmd(byte gunIndex)
{
    byte type = 0; // 0 : none, 1 : operative, 2 inoperative

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (ShmOCPP16Data->CsMsg.bits[gunIndex].ChangeAvailabilityReq == YES) {
            PRINTF_FUNC("***************ChkOcppStatus : OcppChangeAvailability******************** \n");
            DEBUG_ERROR_MSG("***************ChkOcppStatus : OcppChangeAvailability******************** \n");
            ShmOCPP16Data->CsMsg.bits[gunIndex].ChangeAvailabilityReq = NO;
            if (strcmp((char *)ShmOCPP16Data->ChangeAvailability[gunIndex].Type, "Operative") == EQUAL) {
                if (isDb_ready) {
                    DB_Update_Operactive(localDb, gunIndex, true);
                }

                type = 1;
            } else if (strcmp((char *)ShmOCPP16Data->ChangeAvailability[gunIndex].Type, "Inoperative") == EQUAL) {
                if (isDb_ready) {
                    DB_Update_Operactive(localDb, gunIndex, false);
                }

                type = 2;
            }
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (ShmOCPP20Data->CsMsg.bits[gunIndex].ChangeAvailabilityReq == YES) {
            PRINTF_FUNC("***************ChkOcppStatus : OcppChangeAvailability******************** \n");
            DEBUG_ERROR_MSG("***************ChkOcppStatus : OcppChangeAvailability******************** \n");
            ShmOCPP20Data->CsMsg.bits[gunIndex].ChangeAvailabilityReq = NO;
            if (strcmp((char *)ShmOCPP20Data->ChangeAvailability[gunIndex].operationalStatus, "Operative") == EQUAL) {
                if (isDb_ready) {
                    DB_Update_Operactive(localDb, gunIndex, true);
                }

                type = 1;
            } else if (strcmp((char *)ShmOCPP20Data->ChangeAvailability[gunIndex].operationalStatus, "Inoperative") == EQUAL) {
                if (isDb_ready) {
                    DB_Update_Operactive(localDb, gunIndex, false);
                }

                type = 2;
            }
        }
    }

    if (type == 1) {
        chargingInfo[gunIndex]->IsAvailable = YES;
        if (chargingInfo[gunIndex]->SystemStatus == S_IDLE ||
                chargingInfo[gunIndex]->SystemStatus == S_RESERVATION ||
                chargingInfo[gunIndex]->SystemStatus == S_MAINTAIN) {
            setChargerMode(gunIndex, MODE_IDLE);
        }
    } else if (type == 2) {
        chargingInfo[gunIndex]->IsAvailable = NO;
        if (chargingInfo[gunIndex]->SystemStatus == S_IDLE ||
                chargingInfo[gunIndex]->SystemStatus == S_RESERVATION ||
                chargingInfo[gunIndex]->SystemStatus == S_MAINTAIN) {
            setChargerMode(gunIndex, MODE_MAINTAIN);
        }
    }
}

void ocpp_chk_unlock_cmd(byte gunIndex)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (ShmOCPP16Data->CsMsg.bits[gunIndex].UnlockConnectorReq == YES) {
            ShmOCPP16Data->CsMsg.bits[gunIndex].UnlockConnectorReq = NO;
            if (chargingInfo[gunIndex]->SystemStatus >= S_REASSIGN_CHECK &&
                    chargingInfo[gunIndex]->SystemStatus <= S_CHARGING) {
                // Unlocked - 充電中,需停止充電
                strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "UnlockCommand");
                ChargingTerminalProcess(gunIndex);
            }
            strcpy((char *)ShmOCPP16Data->UnlockConnector[gunIndex].ResponseStatus, "Unlocked");
            ShmOCPP16Data->CsMsg.bits[gunIndex].UnlockConnectorConf = YES;
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (ShmOCPP20Data->CsMsg.bits[gunIndex].UnlockConnectorReq == YES) {
            ShmOCPP20Data->CsMsg.bits[gunIndex].UnlockConnectorReq = NO;
            if (chargingInfo[gunIndex]->SystemStatus >= S_REASSIGN_CHECK &&
                    chargingInfo[gunIndex]->SystemStatus <= S_CHARGING) {
                // Unlocked - 充電中,需停止充電
                strcpy((char *)ShmOCPP20Data->TransactionEvent[gunIndex].transactionInfo.stoppedReason, "UnlockCommand");
                ChargingTerminalProcess(gunIndex);
            }
            strcpy((char *)ShmOCPP20Data->UnlockConnector[gunIndex].Response_status, "Unlocked");
            ShmOCPP20Data->CsMsg.bits[gunIndex].UnlockConnectorConf = YES;
        }
    }
}

bool ocpp_chk_remoteStop_cmd(byte gunIndex)
{
    byte acDirIndex = ShmSysConfigAndInfo->SysConfig.AcConnectorCount;

    // 有 AC 槍的話
    if (acDirIndex > 0 && gunIndex > 0) {
        gunIndex += acDirIndex;
    }

    bool result = false;

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        result = ShmOCPP16Data->CsMsg.bits[gunIndex].RemoteStopTransactionReq;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        result = ShmOCPP20Data->CsMsg.bits[gunIndex].RequestStopTransactionReq;
    }

    if (result) {
        DEBUG_INFO_MSG("Remote Stop by OCPP (%d) \n", gunIndex);
        if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
            strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "Remote");
            ShmOCPP16Data->CsMsg.bits[gunIndex].RemoteStopTransactionReq = NO;
        } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
            strcpy((char *)ShmOCPP20Data->TransactionEvent[gunIndex].transactionInfo.stoppedReason, "Remote");
            ShmOCPP20Data->CsMsg.bits[gunIndex].RequestStopTransactionReq = NO;
        }
    }

    return result;
}

bool ocpp_sub_get_remote_start_transaction_req(byte gun_index)
{
    bool result = false;

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        result = ShmOCPP16Data->CsMsg.bits[gun_index].RemoteStartTransactionReq;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        result = ShmOCPP20Data->CsMsg.bits[gun_index].RequestStartTransactionReq;
    }

    if (result) {
        strcpy((char *)ShmOCPP16Data->StartTransaction[gun_index].IdTag,
               (char *)ShmOCPP16Data->RemoteStartTransaction[gun_index].IdTag);
    }

    return result;
}

void ocpp_sub_set_remote_start_transaction_req(byte gunIndex, bool result)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        ShmOCPP16Data->CsMsg.bits[gunIndex].RemoteStartTransactionReq = result;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        ShmOCPP20Data->CsMsg.bits[gunIndex].RequestStartTransactionReq = result;
    }
}

void ocpp_chk_remoteStart_cmd()
{
    if (ShmSysConfigAndInfo->SysConfig.OfflinePolicy == _OFFLINE_POLICY_NO_CHARGING)
    {}
    else if (!isDetectPlugin()) {
        // 如果有 AC 槍,則固定是第 2 把槍,所以索引固定為 1
        byte acDirIndex = ShmSysConfigAndInfo->SysConfig.AcConnectorCount;

        for (byte ac_index = 0; ac_index < ShmSysConfigAndInfo->SysConfig.AcConnectorCount; ac_index++) {
            if (ocpp_sub_get_remote_start_transaction_req(acDirIndex)) {
                if (ac_chargingInfo[ac_index]->SystemStatus == S_IDLE ||
                        ac_chargingInfo[ac_index]->SystemStatus == S_RESERVATION) {
                    ac_chargingInfo[ac_index]->RemoteStartFlag = YES;
                    ShmSysConfigAndInfo->SysInfo.OrderCharging = YES;
                    //ShmSysConfigAndInfo->SysInfo.OrderCharging = DEFAULT_AC_INDEX;
                    //ShmOCPP16Data->CsMsg.bits[ShmSysConfigAndInfo->SysConfig.TotalConnectorCount + ac_index].RemoteStartTransactionReq = NO;
                    DetectPluginStart(ac_index);
                    return;
                }
                ocpp_sub_set_remote_start_transaction_req(acDirIndex, NO);
            }
        }

        byte threeGunIndex = 0;
        byte dcIndex = 0;
        bool isGunUsingStatus = false;
        byte scheduleIndex = 0;

        for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++) {
            // 如果有 AC 槍,且 DC 槍也有兩把
            if (acDirIndex == 1 && _index == 1) {
                threeGunIndex = 1;
            }

            if (ocpp_sub_get_remote_start_transaction_req(_index + threeGunIndex)) {
                dcIndex = _index;
            }

            if (chargingInfo[_index]->SystemStatus != S_IDLE) {
                isGunUsingStatus = true;
            }

            if (chargingInfo[_index]->schedule.isTriggerStart) {
                scheduleIndex = _index;
            }
        }

        // 如果是雙槍單模,只認閒置狀態的槍,如果有預約~ 則預約也算被使用
        if (isGunUsingStatus && ShmSysConfigAndInfo->SysInfo.IsAlternatvieConf) {
            if (dcIndex == 0) {
                threeGunIndex = 0;
            }

            ocpp_sub_set_remote_start_transaction_req(dcIndex + threeGunIndex, NO);
            return;
        }

        if (dcIndex == 0) {
            threeGunIndex = 0;
        }

        if (ocpp_sub_get_remote_start_transaction_req(dcIndex + threeGunIndex)) {
            if (chargingInfo[dcIndex]->SystemStatus == S_IDLE ||
                    chargingInfo[dcIndex]->SystemStatus == S_RESERVATION) {
                chargingInfo[dcIndex]->RemoteStartFlag = YES;
                ShmSysConfigAndInfo->SysInfo.OrderCharging = YES;
                //ShmSysConfigAndInfo->SysInfo.OrderCharging = gun_index;
                DetectPluginStart(dcIndex);
            }
            ocpp_sub_set_remote_start_transaction_req(dcIndex + threeGunIndex, NO);
        } else if (chargingInfo[scheduleIndex]->schedule.isTriggerStart) {
            if (chargingInfo[scheduleIndex]->SystemStatus == S_IDLE ||
                    chargingInfo[scheduleIndex]->SystemStatus == S_RESERVATION) {
                chargingInfo[scheduleIndex]->RemoteStartFlag = YES;
                ShmSysConfigAndInfo->SysInfo.OrderCharging = YES;
                DetectPluginStart(scheduleIndex);
            }
            chargingInfo[scheduleIndex]->schedule.isTriggerStart = NO;
        }
    }
}

void ocpp_chk_update_cmd()
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (ShmOCPP16Data->MsMsg.bits.UpdateFirmwareReq == YES) {
            ShmOCPP16Data->MsMsg.bits.UpdateFirmwareReq = NO;

            if (strcmp((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "Downloaded") == EQUAL) {
                DEBUG_INFO_MSG("Backend : update start. \n");
                sleep(2);
                strcpy((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "");
                strcpy((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "Installing");
                ShmOCPP16Data->SpMsg.bits.FirmwareStatusNotificationReq = YES;
                KillTask();

                for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++) {
                    setChargerMode(_index, MODE_UPDATE);
                }
                for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.AcConnectorCount; _index++) {
                    ac_chargingInfo[_index]->SystemStatus = MODE_UPDATE;
                }

                byte updateResult = CheckUpdateProcess();

                if (updateResult == PASS) {
                    DEBUG_INFO_MSG("Backend : update complete. \n");
                    strcpy((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "Installed");
                } else if (updateResult == MODELNAME_FAIL) {
                    DEBUG_INFO_MSG("Backend : model name is none match. \n");
                    strcpy((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "InstallationFailed");
                    ShmOCPP16Data->SpMsg.bits.FirmwareStatusNotificationReq = YES;
                    sleep(5);
                    KillAllTask();
                    system("/usr/bin/run_evse_restart.sh");
                    return;
                } else {
                    DEBUG_INFO_MSG("Backend : update fail. \n");
                    strcpy((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "InstallationFailed");
                }

                strcpy((char *)ShmOCPP16Data->FirmwareStatusNotification.Status, "Installed");
                ShmOCPP16Data->SpMsg.bits.FirmwareStatusNotificationReq = YES;
                sleep(5);
                system("reboot -f");
            }
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (ShmOCPP20Data->MsMsg.bits.UpdateFirmwareReq == YES) {
            ShmOCPP20Data->MsMsg.bits.UpdateFirmwareReq = NO;

            if (strcmp((char *)ShmOCPP20Data->FirmwareStatusNotification.status, "Downloaded") == EQUAL) {
                DEBUG_INFO_MSG("Backend : update start. \n");
                sleep(2);
                strcpy((char *)ShmOCPP20Data->FirmwareStatusNotification.status, "");
                strcpy((char *)ShmOCPP20Data->FirmwareStatusNotification.status, "Installing");
                ShmOCPP20Data->SpMsg.bits.FirmwareStatusNotificationReq = YES;
                KillTask();

                for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.TotalConnectorCount; _index++) {
                    setChargerMode(_index, MODE_UPDATE);
                }
                for (byte _index = 0; _index < ShmSysConfigAndInfo->SysConfig.AcConnectorCount; _index++) {
                    ac_chargingInfo[_index]->SystemStatus = MODE_UPDATE;
                }

                byte updateResult = CheckUpdateProcess();

                if (updateResult == PASS) {
                    DEBUG_INFO_MSG("Backend : update complete. \n");
                    strcpy((char *)ShmOCPP20Data->FirmwareStatusNotification.status, "Installed");
                } else if (updateResult == MODELNAME_FAIL) {
                    DEBUG_INFO_MSG("Backend : model name is none match. \n");
                    strcpy((char *)ShmOCPP20Data->FirmwareStatusNotification.status, "InstallationFailed");
                    ShmOCPP20Data->SpMsg.bits.FirmwareStatusNotificationReq = YES;
                    sleep(5);
                    KillAllTask();
                    system("/usr/bin/run_evse_restart.sh");
                    return;
                } else {
                    DEBUG_INFO_MSG("Backend : update fail. \n");
                    strcpy((char *)ShmOCPP20Data->FirmwareStatusNotification.status, "InstallationFailed");
                }

                strcpy((char *)ShmOCPP20Data->FirmwareStatusNotification.status, "Installed");
                ShmOCPP20Data->SpMsg.bits.FirmwareStatusNotificationReq = YES;
                sleep(5);
                system("reboot -f");
            }
        }
    }
}

bool ocpp_chk_invalid_id_cmd(byte gunIndex)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (strstr((char *) ShmOCPP16Data->ConfigurationTable.CoreProfile[StopTransactionOnInvalidId].ItemData, "TRUE")) {
            if (strcmp((char *)ShmOCPP16Data->StartTransaction[gunIndex].ResponseIdTagInfo.Status, "Blocked") == EQUAL ||
                    strcmp((char *)ShmOCPP16Data->StartTransaction[gunIndex].ResponseIdTagInfo.Status, "Expired") == EQUAL ||
                    strcmp((char *)ShmOCPP16Data->StartTransaction[gunIndex].ResponseIdTagInfo.Status, "Invalid") == EQUAL) {
                return true;
            }
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (strstr((char *) ShmOCPP20Data->ControllerComponentVariable[TxCtrlr_StopTxOnInvalidId].variableAttribute[0].value, "TRUE")) {
            if (strcmp((char *)ShmOCPP20Data->TransactionEvent[gunIndex].Response_idTokenInfo.status, "Blocked") == EQUAL ||
                    strcmp((char *)ShmOCPP20Data->TransactionEvent[gunIndex].Response_idTokenInfo.status, "Expired") == EQUAL ||
                    strcmp((char *)ShmOCPP20Data->TransactionEvent[gunIndex].Response_idTokenInfo.status, "Invalid") == EQUAL ||
                    strcmp((char *)ShmOCPP20Data->TransactionEvent[gunIndex].Response_idTokenInfo.status, "NoCredit") == EQUAL ||
                    strcmp((char *)ShmOCPP20Data->TransactionEvent[gunIndex].Response_idTokenInfo.status, "NotAllowedTypeEVSE") == EQUAL ||
                    strcmp((char *)ShmOCPP20Data->TransactionEvent[gunIndex].Response_idTokenInfo.status, "NotAtThisLocation") == EQUAL ||
                    strcmp((char *)ShmOCPP20Data->TransactionEvent[gunIndex].Response_idTokenInfo.status, "NotAtThisTime") == EQUAL ||
                    strcmp((char *)ShmOCPP20Data->TransactionEvent[gunIndex].Response_idTokenInfo.status, "Unknown") == EQUAL) {
                return true;
            }
        }
    }

    return false;
}

bool ocpp_chk_profileConf_cmd(byte _index)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileConf == YES) {
            ShmOCPP16Data->CSUMsg.bits[_index].ChargingProfileConf = NO;
            return true;
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (ShmOCPP20Data->CSUMsg.bits[_index].ChargingProfileConf == YES) {
            ShmOCPP20Data->CSUMsg.bits[_index].ChargingProfileConf = NO;
            return true;
        }
    }

    return false;
}

void ocpp_lift_profileReq_cmd(byte gunIndex)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (ShmOCPP16Data->CSUMsg.bits[gunIndex].ChargingProfileConf == NO) {
            if (ShmOCPP16Data->CSUMsg.bits[gunIndex].ChargingProfileReq == NO) {
                ShmOCPP16Data->CSUMsg.bits[gunIndex].ChargingProfileReq = YES;
            }
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (ShmOCPP20Data->CSUMsg.bits[gunIndex].ChargingProfileConf == NO) {
            if (ShmOCPP20Data->CSUMsg.bits[gunIndex].ChargingProfileReq == NO) {
                ShmOCPP20Data->CSUMsg.bits[gunIndex].ChargingProfileReq = YES;
            }
        }
    }
}

void ocpp_set_startTransation_cmd(byte gunIndex)
{
    byte _OcppGunIndex = gunIndex;

    // 如果有 AC 槍,而現在是 DC 第二把槍進入充電
    if (ShmSysConfigAndInfo->SysConfig.AcConnectorCount == 1 && gunIndex == 1) {
        _OcppGunIndex = 2;
    }

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (strcmp((char *)chargingInfo[gunIndex]->StartUserId, "") == EQUAL) {
            strcpy((char *)ShmOCPP16Data->StartTransaction[_OcppGunIndex].IdTag, (char *)ShmOCPP16Data->StartTransaction[_OcppGunIndex].IdTag);
        } else {
            strcpy((char *)ShmOCPP16Data->StartTransaction[_OcppGunIndex].IdTag, (char *)chargingInfo[gunIndex]->StartUserId);
        }

        PRINTF_FUNC("IdTag = %s \n", ShmOCPP16Data->StartTransaction[_OcppGunIndex].IdTag);
        ShmOCPP16Data->CpMsg.bits[_OcppGunIndex].StartTransactionReq = YES;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (strcmp((char *)chargingInfo[gunIndex]->StartUserId, "") == EQUAL) {
            strcpy((char *)ShmOCPP20Data->TransactionEvent[_OcppGunIndex].idToken.idToken, (char *)ShmOCPP20Data->TransactionEvent[_OcppGunIndex].idToken.idToken);
        } else {
            strcpy((char *)ShmOCPP20Data->TransactionEvent[_OcppGunIndex].idToken.idToken, (char *)chargingInfo[gunIndex]->StartUserId);
        }

        PRINTF_FUNC("IdTag = %s \n", ShmOCPP20Data->TransactionEvent[_OcppGunIndex].idToken.idToken);
        ShmOCPP20Data->CpMsg.bits[_OcppGunIndex].TransactionEventReq = YES;
    }
}

void ocpp_set_stopTransation_cmd(byte gunIndex)
{
    byte _OcppGunIndex = gunIndex;

    // 如果有 AC 槍,而現在是 DC 第二把槍進入充電
    if (ShmSysConfigAndInfo->SysConfig.AcConnectorCount == 1 && gunIndex == 1) {
        _OcppGunIndex = 2;
    }

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (strcmp((char *)chargingInfo[gunIndex]->StartUserId, "") == EQUAL) {
            strcpy((char *)ShmOCPP16Data->StopTransaction[_OcppGunIndex].IdTag, (char *)ShmOCPP16Data->StopTransaction[_OcppGunIndex].IdTag);
        } else {
            strcpy((char *)ShmOCPP16Data->StopTransaction[_OcppGunIndex].IdTag, (char *)chargingInfo[gunIndex]->StartUserId);
        }

        PRINTF_FUNC("IdTag = %s \n", ShmOCPP16Data->StopTransaction[_OcppGunIndex].IdTag);
        ShmOCPP16Data->CpMsg.bits[_OcppGunIndex].StopTransactionReq = YES;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (strcmp((char *)chargingInfo[gunIndex]->StartUserId, "") == EQUAL) {
            strcpy((char *)ShmOCPP20Data->TransactionEvent[_OcppGunIndex].idToken.idToken, (char *)ShmOCPP20Data->TransactionEvent[_OcppGunIndex].idToken.idToken);
        } else {
            strcpy((char *)ShmOCPP20Data->TransactionEvent[_OcppGunIndex].idToken.idToken, (char *)chargingInfo[gunIndex]->StartUserId);
        }

        PRINTF_FUNC("IdTag = %s \n", ShmOCPP20Data->TransactionEvent[_OcppGunIndex].idToken.idToken);
        ShmOCPP20Data->CpMsg.bits[_OcppGunIndex].TransactionEventReq = YES;
    }
}

void ocpp_set_errorCode_cmd(byte gunIndex, char *errString)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        strcpy((char *)ShmOCPP16Data->StatusNotification[gunIndex].ErrorCode, errString);
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {

    }
}

void ocpp_set_stopReason_by_cmd(byte gunIndex, char *reason)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (strcmp((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, "") == EQUAL) {
            strcpy((char *)ShmOCPP16Data->StopTransaction[gunIndex].StopReason, reason);
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (strcmp((char *)ShmOCPP20Data->TransactionEvent[gunIndex].transactionInfo.stoppedReason, "") == EQUAL) {
            strcpy((char *)ShmOCPP20Data->TransactionEvent[gunIndex].transactionInfo.stoppedReason, reason);
        }
    }
}

void ocpp_set_authorizeReq_cmd(byte value)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        ShmOCPP16Data->SpMsg.bits.AuthorizeReq = value;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        ShmOCPP20Data->SpMsg.bits.AuthorizeReq = value;
    }
}

void ocpp_set_authorizeConf_cmd(byte value)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        ShmOCPP16Data->SpMsg.bits.AuthorizeConf = value;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        ShmOCPP20Data->SpMsg.bits.AuthorizeConf = value;
    }
}

void ocpp_set_errCode_cmd(byte gunIndex)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (strcmp((char *)chargingInfo[gunIndex]->ConnectorAlarmCode, "") != EQUAL) {
            strcpy((char *)ShmOCPP16Data->StatusNotification[gunIndex].ErrorCode, "InternalError");
            strcpy((char *)ShmOCPP16Data->StatusNotification[gunIndex].VendorErrorCode, (char *)chargingInfo[gunIndex]->ConnectorAlarmCode);
        } else if (strcmp((char *)chargingInfo[gunIndex]->EvConnAlarmCode, "") != EQUAL) {
            strcpy((char *)ShmOCPP16Data->StatusNotification[gunIndex].ErrorCode, "OtherError");
            strcpy((char *)ShmOCPP16Data->StatusNotification[gunIndex].VendorErrorCode, (char *)chargingInfo[gunIndex]->EvConnAlarmCode);
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {

    }
}

void ocpp_clear_errorCode_cmd(byte gunIndex)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (strcmp((char *)ShmOCPP16Data->StatusNotification[gunIndex].ErrorCode, "NoError") != EQUAL) {
            strcpy((char *)ShmOCPP16Data->StatusNotification[gunIndex].ErrorCode, "NoError");
        }

        if (strcmp((char *)ShmOCPP16Data->StatusNotification[gunIndex].VendorErrorCode, "") != EQUAL) {
            strcpy((char *)ShmOCPP16Data->StatusNotification[gunIndex].VendorErrorCode, "");
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {

    }
}

void ocpp_clear_idTag_cmd(byte gun_index)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        strcpy((char *)ShmOCPP16Data->StartTransaction[gun_index].ResponseIdTagInfo.Status, "");
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        strcpy((char *)ShmOCPP20Data->TransactionEvent[gun_index].Response_idTokenInfo.status, "");
    }
}

void ocpp_clear_stopReason(byte gun_index)
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        strcpy((char *)ShmOCPP16Data->StopTransaction[gun_index].StopReason, "");
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        strcpy((char *)ShmOCPP20Data->TransactionEvent[gun_index].transactionInfo.stoppedReason, "");
    }
}

unsigned short _ocpp_get_connect_timeout()
{
    uint16_t result = (TIMEOUT_SPEC_HANDSHAKING / 1000);

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (strcmp((char *)ShmOCPP16Data->ConfigurationTable.CoreProfile[ConnectionTimeOut].ItemData, "") != 0) {
            result = atoi((char *)ShmOCPP16Data->ConfigurationTable.CoreProfile[ConnectionTimeOut].ItemData);
        }
    }

    else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (strcmp((char *)ShmOCPP20Data->ControllerComponentVariable[TxCtrlr_EVConnectionTimeOut].variableAttribute[0].value, "") != 0) {
            result = atoi((char *)ShmOCPP20Data->ControllerComponentVariable[TxCtrlr_EVConnectionTimeOut].variableAttribute[0].value);
        }
    }

    return result;
}

bool _ocpp_get_disconnect_policy()
{
    bool result = false;

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (strcmp((char *)ShmOCPP16Data->ConfigurationTable.CoreProfile[AllowOfflineTxForUnknownId].ItemData, "TRUE") == EQUAL &&
                strcmp((char *)ShmOCPP16Data->ConfigurationTable.CoreProfile[LocalAuthorizeOffline].ItemData, "TRUE") == EQUAL) {
            result = true;
        }
    }

    else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (strcmp((char *)ShmOCPP20Data->ControllerComponentVariable[LocalAuthorizeOffline].variableAttribute[0].value, "") == EQUAL &&
                strcmp((char *)ShmOCPP20Data->ControllerComponentVariable[AuthCtrlr_LocalAuthorizeOffline].variableAttribute[0].value, "") == EQUAL) {
            result = true;
        }
    }

    return result;
}

bool ocpp_get_authorize_conf()
{
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        return ShmOCPP16Data->SpMsg.bits.AuthorizeConf;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        return ShmOCPP20Data->SpMsg.bits.AuthorizeConf;
    }

    return false;
}

bool ocpp_get_startTransation_req(byte gunIndex)
{
    bool result = false;

    // 如果有 AC 槍,而現在是 DC 第二把槍進入充電
    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        result = ShmOCPP16Data->CpMsg.bits[gunIndex].StartTransactionReq;
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        result = ShmOCPP20Data->CpMsg.bits[gunIndex].TransactionEventReq;
    }

    return result;
}

void ocpp_chargingProfile_process(byte _index)
{
    int _time = 0;
    int _startCount = NO_DEFINE;
    int _maxCount = 0;

    if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) {
        if (strcmp((char *)ShmOCPP16Data->SmartChargingProfile[_index].ChargingProfileKind, "Absolute") == EQUAL &&
                ShmOCPP16Data->SmartChargingProfile[_index].ChargingProfileId == YES) {
            _time = GetStartScheduleTime(ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.StartSchedule);
            _maxCount = ARRAY_SIZE(ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod);
            _startCount = NO_DEFINE;

            for (byte _count = 0; _count < _maxCount; _count++) {
                // 預設最小輸出電流 (MIN_OUTPUT_CUR) A
                if (_time >= ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].StartPeriod) {
                    if ((_count == 0 && ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].Limit >= MIN_OUTPUT_CUR) ||
                            ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_count].Limit > MIN_OUTPUT_CUR) {
                        _startCount = _count;
                    }
                }
            }

            PRINTF_FUNC("Gun_%d, Get Profile - Profile Index = %d \n", _index, _startCount);
            if (_startCount < _maxCount) {
                PRINTF_FUNC("Profile Limit = %f \n", ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit);
                chargingInfo[_index]->ChargingProfilePower = ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].Limit * AC_OUTPUT_VOL * ShmOCPP16Data->SmartChargingProfile[_index].ChargingSchedule.ChargingSchedulePeriod[_startCount].NumberPhases;
                if (chargingInfo[_index]->EvBatterytargetVoltage > 0 &&
                        chargingInfo[_index]->PresentChargingVoltage > 0) {
                    chargingInfo[_index]->ChargingProfileCurrent = (chargingInfo[_index]->ChargingProfilePower / chargingInfo[_index]->PresentChargingVoltage) * 10;
                } else {
                    chargingInfo[_index]->ChargingProfileCurrent = 0;
                }
            } else {
                chargingInfo[_index]->ChargingProfilePower = -1;
                chargingInfo[_index]->ChargingProfileCurrent = -1;
            }
        } else {
            chargingInfo[_index]->ChargingProfilePower = -1;
            chargingInfo[_index]->ChargingProfileCurrent = -1;
        }
    } else if (ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) {
        if (strcmp((char *)ShmOCPP20Data->SmartChargingProfile[_index].chargingProfileKind, "Absolute") == EQUAL &&
                ShmOCPP20Data->SmartChargingProfile[_index].id == YES) {
            _time = GetStartScheduleTime(ShmOCPP20Data->SmartChargingProfile[_index].chargingSchedule[0].startSchedule);
            _maxCount = ARRAY_SIZE(ShmOCPP20Data->SmartChargingProfile[_index].chargingSchedule[0].chargingSchedulePeriod);
            _startCount = NO_DEFINE;

            for (byte _count = 0; _count < _maxCount; _count++) {
                // 預設最小輸出電流 (MIN_OUTPUT_CUR) A
                if (_time >= ShmOCPP20Data->SmartChargingProfile[_index].chargingSchedule[0].chargingSchedulePeriod[_count].startPeriod) {
                    if ((_count == 0 && ShmOCPP20Data->SmartChargingProfile[_index].chargingSchedule[0].chargingSchedulePeriod[_count].limit >= MIN_OUTPUT_CUR) ||
                            ShmOCPP20Data->SmartChargingProfile[_index].chargingSchedule[0].chargingSchedulePeriod[_count].limit > MIN_OUTPUT_CUR) {
                        _startCount = _count;
                    }
                }
            }

            PRINTF_FUNC("Gun_%d, Get Profile - Profile Index = %d \n", _index, _startCount);
            if (_startCount < _maxCount) {
                PRINTF_FUNC("Profile Limit = %f \n", ShmOCPP20Data->SmartChargingProfile[_index].chargingSchedule[0].chargingSchedulePeriod[_startCount].limit);
                chargingInfo[_index]->ChargingProfilePower = ShmOCPP20Data->SmartChargingProfile[_index].chargingSchedule[0].chargingSchedulePeriod[_startCount].limit * AC_OUTPUT_VOL;
                if (chargingInfo[_index]->EvBatterytargetVoltage > 0 && chargingInfo[_index]->PresentChargingVoltage > 0) {
                    chargingInfo[_index]->ChargingProfileCurrent = (chargingInfo[_index]->ChargingProfilePower / chargingInfo[_index]->PresentChargingVoltage) * 10;
                } else {
                    chargingInfo[_index]->ChargingProfileCurrent = 0;
                }
            } else {
                chargingInfo[_index]->ChargingProfilePower = -1;
                chargingInfo[_index]->ChargingProfileCurrent = -1;
            }
        } else {
            chargingInfo[_index]->ChargingProfilePower = -1;
            chargingInfo[_index]->ChargingProfileCurrent = -1;
        }
    } else {
        chargingInfo[_index]->ChargingProfilePower = -1;
        chargingInfo[_index]->ChargingProfileCurrent = -1;
    }

    PRINTF_FUNC("Profile : ChargingProfilePower = %f \n", chargingInfo[_index]->ChargingProfilePower);
    PRINTF_FUNC("Profile : ChargingProfileCurrent = %f \n", chargingInfo[_index]->ChargingProfileCurrent);
}