Эх сурвалжийг харах

2022-07-08 / Wendell

Actions
1. [add] record final cost and resend to dispenser when communication lost
2. [add] clean credit card info when remote start
3. [add] ocpp Offline_MaxChargingPower key
4. [add] default price for 24 hour for tcc
5. [add] connector type: S, Y, Z, J
6. [add] default MaintainServerURL value
7. [mod] line status logic (status 7, 8, 9)
8. [mod] modify Capability logic
9. [mod] PresentChargingPower logic
10.[fix] update function maybe fail when AvailableMemory is less then 200 MB
11.[fix] keep 2000 data in database
12.[fix] relay not open when emergency button pressed in charging mode

Files
1. As follow commit history

Image version : V2.03.XX.XXXX.XX
Wendell 2 жил өмнө
parent
commit
af7f5289b7

+ 182 - 0
EVSE/Projects/DO360/Apps/Common.c

@@ -143,6 +143,32 @@ int StoreEvCommMsg(const char *fmt, ...)
 
     return rc;
 }
+
+int StoreDbMsg(const char *fmt, ...)
+{
+    char Buf[4096+256];
+    char buffer[4096];
+    va_list args;
+    struct timeb  SeqEndTime;
+    struct tm *tm;
+
+    va_start(args, fmt);
+    int rc = vsnprintf(buffer, sizeof(buffer), fmt, args);
+    va_end(args);
+
+    memset(Buf,0,sizeof(Buf));
+    ftime(&SeqEndTime);
+    SeqEndTime.time = time(NULL);
+    tm=localtime(&SeqEndTime.time);
+
+    sprintf(Buf,"echo \'%04d-%02d-%02d %02d:%02d:%02d:%03d - %s\' >> /Storage/SystemLog/[%04d.%02d]DbLog",
+        tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,SeqEndTime.millitm,
+        buffer,
+        tm->tm_year+1900,tm->tm_mon+1);
+    system(Buf);
+
+    return rc;
+}
 
 void GetClockTime(struct timespec *_now_time)
 {
@@ -517,3 +543,159 @@ int GetShellReceiptInfo(char *finalCostString, char *receiptInfo)
 
     return length;
 }
+
+float DefaultPriceParsing(char *StringItem)
+{
+    char *ptrSave, *ptrToken;
+    char strSource[128];
+    float fee = 0;
+
+    memcpy(strSource, StringItem, 128);
+
+    ptrToken = strtok_r(strSource, ",", &ptrSave);
+    while(ptrToken != NULL)
+    {
+        char *strFee = strstr(ptrToken, "$");
+        if(strFee != NULL)
+        {
+            strFee++;
+            fee = atof(strFee);
+
+            break;
+        }
+        else
+        {
+            fee = atof(ptrToken);
+            break;
+        }
+        ptrToken = strtok_r(NULL, ",", &ptrSave);
+    }
+    return fee;
+}
+
+float GetNowTimePricing(float *price)
+{
+    float fee = 0;
+
+    time_t CurrentTime;
+    struct tm *tm;
+
+    CurrentTime = time(NULL);
+    tm=localtime(&CurrentTime);
+
+    fee = price[tm->tm_hour];
+
+    return fee;
+}
+
+// Shell RunningCost Parsing
+float TccDefaultPriceParsing(char *costString, float *price)
+{
+    int splitCnt = 0;
+    float fee = 0;
+
+    char *splitStringList[128];
+    char strSource[1024];
+
+    memset(strSource, 0x00, sizeof(strSource));
+    strcpy(strSource, costString);
+    splitCnt = Split(splitStringList, strSource, "|");
+
+    if(splitCnt == 24)
+    {
+        for(int i = 0; i < splitCnt; i++)
+        {
+            Trim_String(splitStringList[i], strlen(splitStringList[i]));
+            price[i] = atof(splitStringList[i]);
+        }
+        fee = GetNowTimePricing(price);
+    }
+
+    return fee;
+}
+
+unsigned short ParsingRatingPower(char *modelname)
+{
+    char strVal[3], strExp[2];
+    unsigned short value = 0, exponent = 0;
+
+    memset(strVal, 0x00, sizeof(strVal));
+    memset(strExp, 0x00, sizeof(strExp));
+
+    memcpy(strVal, &modelname[4], 2);
+    memcpy(strExp, &modelname[6], 1);
+
+    value = atoi(strVal);
+    exponent = atoi(strExp);
+
+    if(value < 0 || exponent < 0)
+    {
+        return 0;
+    }
+
+    for(int i = 0; i < exponent; i++)
+    {
+        value *= 10;
+    }
+
+    return value;
+}
+
+
+//***************************************** No Use *****************************************
+float TariffParsing(char *StringItem, char *TariffCode)
+{
+    char *ptrSave, *ptrToken;
+    char strSource[128];
+    float fee = 0;
+
+    memcpy(strSource, StringItem, 128);
+
+    ptrToken = strtok_r(strSource, ";", &ptrSave);
+    while(ptrToken != NULL)
+    {
+        char *strTariff = strstr(ptrToken, TariffCode);
+        if(strTariff != NULL)
+        {
+            char *strFee = strstr(strTariff, "$");
+            if(strFee != NULL)
+            {
+                strFee++;
+                fee = atof(strFee);
+
+                break;
+            }
+        }
+        ptrToken = strtok_r(NULL, ";", &ptrSave);
+    }
+    return fee;
+}
+
+float PhTariffParsing(char *StringItem, char *TariffCode)
+{
+    char *ptrSave, *ptrToken;
+    char strSource[128];
+    float fee = 0;
+
+    memcpy(strSource, StringItem, 128);
+
+    ptrToken = strtok_r(strSource, ",", &ptrSave);
+    while(ptrToken != NULL)
+    {
+        char *strTariff = strstr(ptrToken, TariffCode);
+        if(strTariff != NULL)
+        {
+            char *strFee = strstr(strTariff, ":");
+            if(strFee != NULL)
+            {
+                strFee++;
+                fee = atof(strFee);
+
+                break;
+            }
+        }
+        ptrToken = strtok_r(NULL, ",", &ptrSave);
+    }
+    return fee;
+}
+//***************************************** No Use *****************************************

+ 14 - 0
EVSE/Projects/DO360/Apps/Common.h

@@ -35,6 +35,7 @@
 #define LOG_EVENT(format, args...) StoreEventLogMsg("[%s:%4d][%s][Info] "format, (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__, __FUNCTION__, ##args)
 #define AUTH_INFO(format, args...) StoreAuthLogMsg("[%s:%4d][%s][Info] "format, (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__, __FUNCTION__, ##args)
 #define EvMsg_INFO(format, args...) StoreEvCommMsg("[%s:%4d][%s][EvMsg] "format, (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__, __FUNCTION__, ##args)
+#define Database_INFO(format, args...) StoreDbMsg("[%s:%4d][%s][DB] "format, (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__), __LINE__, __FUNCTION__, ##args)
 
 #define DB_FILE                     "/Storage/ChargeLog/localCgargingRecord.db"
 #define NETWORK_DB_FILE             "/Storage/EventLog/Eventlog.db"
@@ -44,6 +45,8 @@ int StorePsuLogMsg(const char *fmt, ...);
 int StoreEventLogMsg(const char *fmt, ...);
 int StoreAuthLogMsg(const char *fmt, ...);
 int StoreEvCommMsg(const char *fmt, ...);
+int StoreDbMsg(const char *fmt, ...);
+
 void GetClockTime(struct timespec *_now_time);
 unsigned long GetTimeoutValue(struct timespec _start_time);
 unsigned long GetSecTimeoutValue(struct timespec _start_time);
@@ -67,4 +70,15 @@ float ShellRunningCostParsing(char *runningCostString);
 float ShellFinalCostParsing(char *finalCostString);
 int GetShellReceiptInfo(char *finalCostString, char *receiptInfo);
 
+float DefaultPriceParsing(char *StringItem);
+float GetNowTimePricing(float *price);
+float TccDefaultPriceParsing(char *costString, float *price);
+
+unsigned short ParsingRatingPower(char *modelname);
+
+//***************************************** No Use *****************************************
+float TariffParsing(char *StringItem, char *TariffCode);
+float PhTariffParsing(char *StringItem, char *TariffCode);
+//***************************************** No Use *****************************************
+
 #endif /* COMMON_H_ */

+ 73 - 4
EVSE/Projects/DO360/Apps/Config.h

@@ -120,6 +120,9 @@ typedef unsigned char               byte;
 #define STR_MODE_UPDATE             "Update"
 #define STR_MODE_NONE               "None"
 
+#define GUN_IDLE_TYPE_NORMAL        0
+#define GUN_IDLE_TYPE_WHOLE         1
+
 enum _SYSTEM_STATUS
 {
 	S_BOOTING =                         0,
@@ -426,7 +429,8 @@ typedef union
         unsigned int FastStandbyTime:1;             // 0: no effect,                1: enable fast standby time
         unsigned int ChargingSimulation:1;          // 0: no effect,                1: enable charging simulation
         unsigned int FChargingReleaseExtend:1;      // 0: no effect,                1: enable Release and Extend when Force Charging
-        unsigned int res:28;
+        unsigned int TryUndisposedBill:1;           // 0: no effect,                1: enable TryUndisposedBill
+        unsigned int res:27;
     }bits;
 }TestControl;
 
@@ -879,6 +883,7 @@ typedef struct
     unsigned short          GunLoading;                         // gun output loading, unit: 0.01%
     unsigned char           GunPsuQuantity;                     // record psu quantity at this gun
     unsigned char           ExtendQuantityLimit;                // limit of extend psu group quantity
+    float                   MaxOutputRatio;                     // max output ratio (gun psu quantity / total psu in using)
     float                   DiffPower_Capability;               // unit: 1kW, different power between output power and Capability power
     float                   DiffPower_Available;                // unit: 1kW, different power between output power and Available power
     float                   DiffPower_PhysicalLimit;            // unit: 1kW, different power between output power and PhysicalLimit power
@@ -1243,6 +1248,8 @@ enum DeductResult
 
 typedef struct
 {
+    float CurrentRate;
+    float TimeOfDayPricing[24];
     char DefaultPriceString[512];                       // default price string
     char DispenserPriceString[MAX_GUN_QUANTITY][512];   // dispenser user price string
     char UserPriceString[MAX_GUN_QUANTITY][512];        // connector user price string
@@ -1308,11 +1315,72 @@ typedef union
 
 typedef struct
 {
-    // system
-    int OfflineMaxChargingPower;                        // unit: W
+    int Offline_MaxChargingPower;                       // unit: W, offline max charging power, received from backend
+    int GunOfflineMaxPower[MAX_GUN_QUANTITY];           // unit: W, calculate from Offline_MaxChargingPower
+
+    int GunMaxProfilePower[MAX_GUN_QUANTITY];           // unit: W, calculate from MaxChargingProfilePower
+    int GunMaxProfileCurrent[MAX_GUN_QUANTITY];         // unit: 0.1A, Calculate from MaxChargingProfilePower
+
+    int GunAbsoluteMaxPower[MAX_GUN_QUANTITY];          // unit: W
+    int GunAbsoluteMaxVoltage[MAX_GUN_QUANTITY];        // unit: 0.1V
+    int GunAbsoluteMaxCurrent[MAX_GUN_QUANTITY];        // unit: 0.1A
 
-    int ManualGunLimitPower[MAX_GUN_QUANTITY];          // unit: W
+    int GunOtpMaxPower[MAX_GUN_QUANTITY];               // unit: W
+    int GunOtpMaxCurrent[MAX_GUN_QUANTITY];             // unit: 0.1A
+
+    int GunDynamicMaxPower[MAX_GUN_QUANTITY];           // unit: W
+    int GunDynamicMaxCurrent[MAX_GUN_QUANTITY];         // unit: 0.1A
+
+    int GunManualLimitPower[MAX_GUN_QUANTITY];          // unit: W
+    int GunManualLimitVoltage[MAX_GUN_QUANTITY];        // unit: 0.1V
+    int GunManualLimitCurrent[MAX_GUN_QUANTITY];        // unit: 0.1A
 }OutputLimitation;
+
+typedef enum
+{
+    _BillStatus_Idle            = 0x00,                 // no final cost received
+    _BillStatus_MiscReq         = 0x01,                 // receive final cost and set final cost misc command
+    _BillStatus_WaitMiscClean   = 0x02,                 // wait for dispenser to read misc command
+    _BillStatus_MiscClean       = 0x03,                 // final cost misc command has update to dispenser, timeout: 3s
+    _BillStatus_UpdateDone      = 0x04,                 // dispenser read final cost packet
+    _BillStatus_Completed       = 0x05,                 // stay this status 3s
+    _BillStatus_Fail            = 0x06,                 // clean bill info and return to idle
+    _BillStatus_End             = 0x07,                 // clean bill info and return to idle
+}BillStatus;
+
+#define BILL_SATAUS_UNDISPOSED                          -1
+#define BILL_SATAUS_UPDATED_FAIL                        0
+#define BILL_SATAUS_UPDATED_OK                          1
+#define BILL_SATAUS_Bypass_OK                           2
+
+typedef struct
+{
+    float TotalCost;                                    // connector user's total cost, unit: 1 dollar
+    float AccountBalance;                               // connector user's account balance, unit: 1 dollar
+    float CostDiscount;                                 // connector user's Discount or couponPoint, unit: 1 point
+    float EnergyCost;                                   // connector user's energy cost, unit: 1 dollar
+    float ParkingFee;                                   // connector user's parking fee, unit: 1 dollar
+    float RemainAmount;                                 // connector user's remain amount, unit: 1 dollar
+    float ConnectionFee;                                // connector user's connection fee, unit: 1 dollar
+    float SessionFee;                                   // connector user's session fee, unit: 1 dollar
+
+}FeeInfoData;
+
+typedef struct
+{
+    unsigned char BillStatus;                           // 0: idle, 1: misc request, 2 misc clean, 3: bill update done
+    unsigned char PreStatus;                            // 0: idle, 1: misc request, 2 misc clean, 3: bill update done
+    unsigned short TryCnt;
+    int TxId;
+    FeeInfoData FeeInfo;
+    char Receipt[512];
+}ChargingBillInfoData;
+
+typedef struct
+{
+    ChargingBillInfoData DispBill[MAX_DISPENSER_QUANTITY];
+    ChargingBillInfoData GunBill[MAX_GUN_QUANTITY];
+}AllBillInfoData;
 // ************************************************************************************************* //
 
 typedef struct
@@ -1342,6 +1410,7 @@ typedef struct
     TimestampInfoData Timestamp[MAX_GUN_QUANTITY];
     OutputError ConnectorError[MAX_GUN_QUANTITY];
     OutputLimitation OutputLimit;
+    AllBillInfoData AllBill;
 }ChargerInfoData;
 
 #endif /* CONFIG_H_ */

+ 7 - 7
EVSE/Projects/DO360/Apps/FactoryConfig.c

@@ -252,14 +252,14 @@ int main(int argc,char *argv[])
 	strcpy((char *) SysConfig.OcppServerURL, "");
 	strcpy((char *) SysConfig.ChargeBoxId, "");
 
-	//if(SysConfig.ModelName[12] == 'P' && SysConfig.ModelName[13] == 'H')
-	//{
-	//    strcpy((char *) SysConfig.MaintainServerURL, "wss://ocpp.phihong.com.tw:2013/");
-	//}
-	//else
-	//{
+	if(SysConfig.ModelName[12] == 'P' && SysConfig.ModelName[13] == 'H')
+	{
+	    strcpy((char *) SysConfig.MaintainServerURL, "wss://ocpp.phihong.com.tw:2013/");
+	}
+	else
+	{
 	    strcpy((char *) SysConfig.MaintainServerURL, "");
-	//}
+	}
 
 	SysConfig.LedInfo.Intensity = 2;
 

+ 1 - 1
EVSE/Projects/DO360/Apps/Makefile

@@ -13,7 +13,7 @@ Lib_SQLite3 = "-L../../../Modularization/ocppfiles" -lsqlite3
 all: CopyFile apps Clean
 #apps: Module_CSU Module_EvComm Module_EventLogging Module_InternalComm Module_LcmControl Module_PrimaryComm Module_PsuComm 
 # ReadCmdline kill.sh
-apps: Common MainTask CabinetParallel SelfTestTask AuthorizeTask LedIndication EvCommTask EventLoggingTask InternalCommTask LcmControlTask PrimaryCommTask InfyGroup_PsuCommObj PsuCommTask ReadCmdlineTask UnsafetyOutputTool FactoryConfigApp OtherTools
+apps: Common MainTask CabinetParallel SelfTestTask AuthorizeTask LedIndication EvCommTask EventLoggingTask InternalCommTask LcmControlTask PrimaryCommTask InfyGroup_PsuCommObj PsuCommTask ReadCmdlineTask FactoryConfigApp OtherTools
 
 Common:
 	rm -f Common.o

+ 195 - 149
EVSE/Projects/DO360/Apps/Module_EvComm.c

@@ -873,7 +873,7 @@ BOOL IsAvalibleGunType(char name, unsigned char *type)
 	return false;
 }
 
-unsigned char ConnectorQuantityTypeParsing(unsigned char *modelName, unsigned char *type, unsigned char *physical)
+unsigned char ConnectorQuantityTypeParsing(unsigned char *modelName, unsigned char *type, unsigned char *physical, unsigned char *safety)
 {
 	unsigned char quantity = 0;
 
@@ -893,6 +893,8 @@ unsigned char ConnectorQuantityTypeParsing(unsigned char *modelName, unsigned ch
 			}
 		}
 	}
+	*safety = modelName[3];
+
 	return quantity;
 }
 
@@ -1036,142 +1038,29 @@ void DispenserStatusResponse(int socket, struct PACKET_STRUCTURE *packet, unsign
 	SendPacket(socket, &sendBuffer);
 }
 
-void GetPhysicalLimitVoltageAndCurrent(byte index, unsigned short *voltage, unsigned short *currrent)
-{
-    if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].RemoteMaxPhysicalVoltage != 0 &&
-        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].RemoteMaxPhysicalVoltage <= *voltage)
-    {
-        *voltage = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].RemoteMaxPhysicalVoltage;
-    }
-
-    if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].RemoteMaxPhysicalCurrent != 0 &&
-        ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].RemoteMaxPhysicalCurrent <= *currrent)
-    {
-        *currrent = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].RemoteMaxPhysicalCurrent;
-    }
-}
-
-void GetModelNameLimitPower(byte index, unsigned short *power)
+void RestrictAbsoluteLimit(int gunIndex, unsigned short *power, unsigned short *voltage, unsigned short *current)
 {
     unsigned short limitPower = 0;
-    unsigned char inUsingCnt = 0;
-
-    for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
-    {
-        if(ShmChargerInfo->PsuGrouping.GroupCollection[i].Role == _GROLE_MASTER)
-        {
-            inUsingCnt += ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity;
-        }
-    }
 
-    if(ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity != 0 && inUsingCnt != 0 &&
-            ShmChargerInfo->Control.ChargerRatingPower != 0)
+    if(ShmChargerInfo->OutputLimit.GunAbsoluteMaxPower[gunIndex] != 0)
     {
-        limitPower = ShmChargerInfo->Control.ChargerRatingPower;
-        if(ShmChargerInfo->Control.CabinetRole == _CROLE_MASTER)
+        limitPower = ShmChargerInfo->OutputLimit.GunAbsoluteMaxPower[gunIndex] / 100;
+        if(limitPower != 0 && limitPower <= *power)
         {
-            limitPower += ShmChargerInfo->ParallelCabinet.TotalParallelPower;
-        }
-        limitPower = (limitPower * ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity) / inUsingCnt;
-    }
-
-    if(limitPower != 0 && limitPower <= *power)
-    {
-        *power = limitPower;
-    }
-}
-
-void GetConfigLimitPowerAndCurrent(byte index, unsigned short *power, unsigned short *currrent)
-{
-    unsigned short limitPower = 0, limitCurrent = 0;
-    unsigned char inUsingCnt = 0;
-
-    for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
-    {
-        if(ShmChargerInfo->PsuGrouping.GroupCollection[i].Role == _GROLE_MASTER)
-        {
-            inUsingCnt += ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity;
+            *power = limitPower;
         }
     }
 
-    if(ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity != 0 && inUsingCnt != 0 &&
-        ShmSysConfigAndInfo->SysConfig.MaxChargingPower != 0)
-    {
-        limitPower = ShmSysConfigAndInfo->SysConfig.MaxChargingPower * 10;
-        limitPower = (limitPower * ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity) / inUsingCnt;
-    }
-    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].MaxTotalChargingPower = limitPower;
-
-    if(ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity != 0 && inUsingCnt != 0 &&
-        ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent != 0)
+    if(ShmChargerInfo->OutputLimit.GunAbsoluteMaxVoltage[gunIndex] != 0 &&
+        ShmChargerInfo->OutputLimit.GunAbsoluteMaxVoltage[gunIndex] < *voltage)
     {
-        limitCurrent = ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent * 10;
-        limitCurrent = (limitCurrent * ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity) / inUsingCnt;
+        *voltage = ShmChargerInfo->OutputLimit.GunAbsoluteMaxVoltage[gunIndex];
     }
-    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].MaxTotalChargingCurrent = limitCurrent;
 
-    if(limitPower != 0 && limitPower <= *power)
-    {
-        *power = limitPower;
-    }
-    if(limitCurrent != 0 && limitCurrent <= *currrent)
+    if(ShmChargerInfo->OutputLimit.GunAbsoluteMaxCurrent[gunIndex] != 0 &&
+        ShmChargerInfo->OutputLimit.GunAbsoluteMaxCurrent[gunIndex] < *current)
     {
-        *currrent = limitCurrent;
-    }
-}
-
-void GetChargingProfileLimit(byte index, unsigned short *power, unsigned short *currrent)
-{
-    if((chargingInfo[index]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[index]->SystemStatus <= S_CHARGING) ||
-        (chargingInfo[index]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[index]->SystemStatus <= S_CCS_PRECHARGE_ST1))
-    {
-        if(chargingInfo[index]->ChargingProfilePower >= 0 && *power > ((int)chargingInfo[index]->ChargingProfilePower / 100))
-        {
-            *power = (int)chargingInfo[index]->ChargingProfilePower / 100;
-        }
-
-        if(chargingInfo[index]->ChargingProfileCurrent >= 0 && *currrent > (int)chargingInfo[index]->ChargingProfileCurrent)
-        {
-            *currrent = (int)chargingInfo[index]->ChargingProfileCurrent;
-        }
-    }
-}
-
-void GetMaxChargingProfileLimit(byte index, unsigned short *power, unsigned short *currrent)
-{
-    unsigned short limitPower = 0, limitCurrent = 0;
-    unsigned char inUsingCnt = 0;
-
-    for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
-    {
-        if(ShmChargerInfo->PsuGrouping.GroupCollection[i].Role == _GROLE_MASTER)
-        {
-            inUsingCnt += ShmChargerInfo->PsuGrouping.GroupCollection[i].GunPsuQuantity;
-        }
-    }
-
-    // max charging profile
-    if(ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity != 0 && inUsingCnt != 0 &&
-        ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower >= 0)
-    {
-        limitPower = (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower / 100;
-        limitPower = (limitPower * ShmChargerInfo->PsuGrouping.GroupCollection[index].GunPsuQuantity) / inUsingCnt;
-
-        if(*power > limitPower)
-        {
-            *power = limitPower;
-        }
-
-        if (chargingInfo[index]->EvBatterytargetVoltage > 0 &&
-            (int)chargingInfo[index]->PresentChargingVoltage > 0)
-        {
-            limitCurrent = (limitPower * 100 / chargingInfo[index]->PresentChargingVoltage) * 10;
-
-            if(*currrent > limitCurrent)
-            {
-                *currrent = limitCurrent;
-            }
-        }
+        *current = ShmChargerInfo->OutputLimit.GunAbsoluteMaxCurrent[gunIndex];
     }
 }
 
@@ -1186,15 +1075,10 @@ void ChargingCapabilityResponse(int socket, struct PACKET_STRUCTURE *packet)
 	int energyCost = 0, parkingFee = 0, remainAmount = 0;
 
 	memset(&sendBuffer, 0x00, sizeof(sendBuffer));
-	voltage = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.MaximumChargingVoltage;
-	current = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.AvailableChargingCurrent;
-	power = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].GeneralChargingData.AvailableChargingPower;
 
-	GetPhysicalLimitVoltageAndCurrent(packet->Header.id - 1, &voltage, &current);
-	GetModelNameLimitPower(packet->Header.id - 1, &power);
-	GetConfigLimitPowerAndCurrent(packet->Header.id - 1, &power, &current);
-	GetChargingProfileLimit(packet->Header.id - 1, &power, &current);
-	GetMaxChargingProfileLimit(packet->Header.id - 1, &power, &current);
+    voltage = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].CapabilityVoltage;
+    current = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].CapabilityCurrent;
+    power = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].CapabilityPower;
 
 	currency = ShmChargerInfo->CabinetMiscValue.Currency;
 	fPrice = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].UserPrice;
@@ -1268,10 +1152,6 @@ void ChargingCapabilityResponse(int socket, struct PACKET_STRUCTURE *packet)
     ConnectorCapability[packet->Header.id - 1].ParkingFee = parkingFee;
     ConnectorCapability[packet->Header.id - 1].RemainAmount = remainAmount;
 
-    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].CapabilityVoltage = voltage;
-    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].CapabilityCurrent = current;
-    ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].CapabilityPower = power;
-
 	sendBuffer.Header.se = packet->Header.se;
 	sendBuffer.Header.id = packet->Header.id;
 	sendBuffer.Header.op = _Header_Response;
@@ -1508,6 +1388,7 @@ bool Is_DispenserForceChargingTriggerWebApi(int gun_index)
 // LOG_INFO("Cabinet >> Connector %d Line Status  [%d]", packet->Header.id, misc.Value);
 // LOG_INFO("Cabinet >> Connector %d User Price   [Trigger]", packet->Header.id);
 // LOG_INFO("Cabinet >> Connector %d Receipt URL  [Trigger]", packet->Header.id);
+// LOG_INFO("Cabinet >> Connector %d ChargingBill [Trigger]", packet->Header.id);
 // LOG_INFO("Cabinet >> Dispenser %d PlugTimeout  [%d]", dispenserIndex + 1, misc.Value);
 // LOG_INFO("Cabinet >> Dispenser %d DefaultPrice [%d]", dispenserIndex + 1, misc.Value);
 // LOG_INFO("Cabinet >> Dispenser %d Currency     [%d]", dispenserIndex + 1, misc.Value);
@@ -1689,6 +1570,20 @@ void MiscCmdRes(int socket, struct PACKET_STRUCTURE *packet, unsigned char dispe
             AddMiscCommand(&sendBuffer, &misc);
         }
 
+        if(Is_Connector_MiscCommand(packet->Header.id - 1, MISC_CONN_CHARGING_BILL))
+        {
+            Clean_Connector_MiscCommand(packet->Header.id - 1, MISC_CONN_CHARGING_BILL);
+            misc.Command = _MiscCmd_ChargingBill;
+            misc.Value = true;
+
+            if(ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].BillStatus == _BillStatus_WaitMiscClean)
+            {
+                ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].BillStatus = _BillStatus_MiscClean;
+            }
+            LOG_INFO("Cabinet >> Connector %d ChargingBill [Trigger]", packet->Header.id);
+            AddMiscCommand(&sendBuffer, &misc);
+        }
+
         // announce misc command to first connector of the dispenser
         if(ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorID[0] == packet->Header.id)
         {
@@ -2576,6 +2471,95 @@ void ChargingTimestampResponse(int socket, struct PACKET_STRUCTURE *packet, unsi
     SendPacket(socket, &sendBuffer);
 }
 
+void ChargingBillResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned char result)
+{
+    struct PACKET_STRUCTURE sendBuffer;
+
+    memset(&sendBuffer, 0x00, sizeof(sendBuffer));
+    sendBuffer.Header.se = packet->Header.se;
+    sendBuffer.Header.id = packet->Header.id;
+    sendBuffer.Header.op = _Header_Response;
+    sendBuffer.Header.len = 30;
+    sendBuffer.Payload.reg = _Reg_ChargingBill;
+    sendBuffer.Payload.data[0] = result;
+
+    int txId = 0;
+    unsigned int lCost = 0, lBalance = 0, lDiscount = 0;
+    int energyCost = 0, parkingFee = 0;
+
+    if(result == _R_OK)
+    {
+        txId = ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].TxId;
+        lCost = (unsigned int)(ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.TotalCost * 100);
+        lBalance = (unsigned int)(ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.AccountBalance * 100);
+        lDiscount = (unsigned int)(ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.CostDiscount * 100);
+        energyCost = ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.EnergyCost >= 0 ?
+            (int)(ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.EnergyCost * 100) : -1;
+        parkingFee = ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.ParkingFee >= 0 ?
+            (int)(ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.ParkingFee * 100) : -1;
+
+        // Total cost
+        sendBuffer.Payload.data[1] = ((lCost >> 24) & 0xFF);
+        sendBuffer.Payload.data[2] = ((lCost >> 16) & 0xFF);
+        sendBuffer.Payload.data[3] = ((lCost >> 8) & 0xFF);
+        sendBuffer.Payload.data[4] = (lCost & 0xFF);
+
+        // Account balance
+        sendBuffer.Payload.data[5] = ((lBalance >> 24) & 0xFF);
+        sendBuffer.Payload.data[6] = ((lBalance >> 16) & 0xFF);
+        sendBuffer.Payload.data[7] = ((lBalance >> 8) & 0xFF);
+        sendBuffer.Payload.data[8] = (lBalance & 0xFF);
+
+        // Cost discount
+        sendBuffer.Payload.data[9] = ((lDiscount >> 24) & 0xFF);
+        sendBuffer.Payload.data[10] = ((lDiscount >> 16) & 0xFF);
+        sendBuffer.Payload.data[11] = ((lDiscount >> 8) & 0xFF);
+        sendBuffer.Payload.data[12] = (lDiscount & 0xFF);
+
+        // Transaction Id
+        sendBuffer.Payload.data[13] = ((txId >> 24) & 0xFF);
+        sendBuffer.Payload.data[14] = ((txId >> 16) & 0xFF);
+        sendBuffer.Payload.data[15] = ((txId >> 8) & 0xFF);
+        sendBuffer.Payload.data[16] = (txId & 0xFF);
+
+        // Energy cost
+        sendBuffer.Payload.data[17] = ((energyCost >> 24) & 0xFF);
+        sendBuffer.Payload.data[18] = ((energyCost >> 16) & 0xFF);
+        sendBuffer.Payload.data[19] = ((energyCost >> 8) & 0xFF);
+        sendBuffer.Payload.data[20] = (energyCost & 0xFF);
+
+        // Parking fee
+        sendBuffer.Payload.data[21] = ((parkingFee >> 24) & 0xFF);
+        sendBuffer.Payload.data[22] = ((parkingFee >> 16) & 0xFF);
+        sendBuffer.Payload.data[23] = ((parkingFee >> 8) & 0xFF);
+        sendBuffer.Payload.data[24] = (parkingFee & 0xFF);
+
+        // Remain Amount
+        char temp[4];
+        memcpy(temp, (char *)&ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.RemainAmount, sizeof(float));
+        sendBuffer.Payload.data[25] = temp[3];
+        sendBuffer.Payload.data[26] = temp[2];
+        sendBuffer.Payload.data[27] = temp[1];
+        sendBuffer.Payload.data[28] = temp[0];
+        if(ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].BillStatus == _BillStatus_MiscClean)
+        {
+            ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].BillStatus = _BillStatus_UpdateDone;
+        }
+
+        Database_INFO("Gun %d TxId[%d]\r\n   Total: %8.2f\r\n Account: %8.2f\r\nDiscount: %8.2f\r\n Energgy: %8.2f\r\n Parking: %8.2f\r\n  Remain: %8.2f",
+            packet->Header.id,
+            txId,
+            ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.TotalCost,
+            ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.AccountBalance,
+            ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.CostDiscount,
+            ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.EnergyCost,
+            ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.ParkingFee,
+            ShmChargerInfo->AllBill.GunBill[packet->Header.id - 1].FeeInfo.RemainAmount);
+    }
+
+    SendPacket(socket, &sendBuffer);
+}
+
 BOOL FindConnectorID(unsigned char dispenserIndex, unsigned char id)
 {
 	BOOL find = false;
@@ -2592,28 +2576,56 @@ BOOL FindConnectorID(unsigned char dispenserIndex, unsigned char id)
 	return find;
 }
 
-void ConnectorPhysicalLimitBindingHandler(unsigned char connectorIndex, unsigned char physical)
+void ConnectorPhysicalLimitBindingHandler(unsigned char connectorIndex, unsigned char physical, unsigned char safety)
 {
     // 20210817 remove type "R"
     //char         modelList[11] = {'J', 'U', 'V', 'E', 'F', 'G', 'T', 'D', 'K', 'P'};
     //unsigned char typeList[11] = {  0,   1,   1,   1,   1,   2,   1,   1,   0,   1}; // 0 : Chademo, 1: CCS, 2: GB
 
+    memset(&ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp, 0x00, sizeof(struct DERATING_BY_OTP));
     switch(physical)
     {
         case 'J':
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CHA_MAX_PHYSICAL_VOLTAGE;
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CHA_NATURAL_J_MAX_CURRENT;
+            if(safety == 'J')
+            {
+                ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CHA_NATURAL_J_JARI_MAX_CURRENT;
+            }
+            break;
+
+        case 'S':
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CHA_MAX_PHYSICAL_VOLTAGE;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CHA_NATURAL_S_MAX_CURRENT;
+            // Boost Mode
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CHA_MAX_PHYSICAL_VOLTAGE;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CHA_NATURAL_S_BOOST_CURRENT;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.isNeedDerating = YES;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingIndex = 0;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[0] = CHA_NATURAL_S_BOOST_CURRENT;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[1] = CHA_NATURAL_S_MAX_CURRENT;
             break;
 
         case 'K':
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CHA_MAX_PHYSICAL_VOLTAGE;
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CHA_NATURAL_K_MAX_CURRENT;
+            // Derating Mode
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.isNeedDerating = YES;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingIndex = 0;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetRate[0] = 1;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetRate[1] = 0.8;
+            break;
+
+        case 'Y':
+        case 'Z':
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_NATURAL_Y_Z_MAX_CURRENT;
             break;
 
         case 'U':
         case 'E':
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
-            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_NATURAL_MAX_CURRENT;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_NATURAL_U_E_MAX_CURRENT;
             break;
 
         case 'G':
@@ -2623,16 +2635,34 @@ void ConnectorPhysicalLimitBindingHandler(unsigned char connectorIndex, unsigned
 
         case 'V':
         case 'F':
-        case 'P':
         //case 'R': // 20210817 remove type "R"
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
-            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_LIQUID_MAX_CURRENT;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_LIQUID_V_F_MAX_CURRENT;
+            // Derating Mode
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.isNeedDerating = YES;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingIndex = 0;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[0] = CCS_LIQUID_V_F_MAX_CURRENT;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[1] = CCS_LIQUID_80_DERATING_1_CUR;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[2] = CCS_LIQUID_85_DERATING_2_CUR;
+            break;
+
+        case 'P':
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_PANTOGRAPH_MAX_CURRENT;
             break;
 
         case 'T':
         case 'D':
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
-            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_NATURAL_REMA_MAX_CURRENT;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_NATURAL_T_D_MAX_CURRENT;
+            // Boost Mode
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_NATURAL_T_D_BOOST_CURRENT;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.isNeedDerating = YES;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingIndex = 0;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[0] = CCS_NATURAL_T_D_BOOST_CURRENT;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[1] = CCS_NATURAL_T_D_MAX_CURRENT;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[2] = CCS_NATURAL_T_D_85_DERATING_CUR;
             break;
 
         default:
@@ -2655,7 +2685,7 @@ void ConnectorPantographBindingHandler(unsigned char connectorIndex, unsigned ch
     }
 }
 
-void ConnectorTypeBindingHandler(unsigned char dispenserIndex, unsigned char *type, unsigned char *physicalType)
+void ConnectorTypeBindingHandler(unsigned char dispenserIndex, unsigned char *type, unsigned char *physicalType, unsigned char safety)
 {
     char *str_gun_type[] = {STR_GUN_TYPE_CHADEMO, STR_GUN_TYPE_CCS, STR_GUN_TYPE_GBT};
 
@@ -2665,7 +2695,7 @@ void ConnectorTypeBindingHandler(unsigned char dispenserIndex, unsigned char *ty
 		ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gunIndex].ParentDispensetIndex = dispenserIndex;
 		ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gunIndex].GeneralChargingData.Index = gunIndex;
 		ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gunIndex].GeneralChargingData.Type = type[i];
-        ConnectorPhysicalLimitBindingHandler(gunIndex, physicalType[i]);
+        ConnectorPhysicalLimitBindingHandler(gunIndex, physicalType[i], safety);
         ConnectorPantographBindingHandler(gunIndex, physicalType[i]);
 
 		LOG_INFO("Dispenser %d Connector %d type: %s, MaxVol: %4d, MaxCur: %4d, %s",
@@ -2776,8 +2806,9 @@ BOOL DispenserIdentificationHandler(struct PACKET_STRUCTURE *packet, unsigned ch
 
 	unsigned char connectorType[2] = {0, 0};
 	unsigned char physicalType[2] = {0, 0};
+	unsigned char safety;
 
-	quantity = ConnectorQuantityTypeParsing(modelName, connectorType, physicalType);
+	quantity = ConnectorQuantityTypeParsing(modelName, connectorType, physicalType, &safety);
 
 	if(quantity > 0)
 	{
@@ -2805,7 +2836,7 @@ BOOL DispenserIdentificationHandler(struct PACKET_STRUCTURE *packet, unsigned ch
 			SetConnectorID(dispenserIndex, quantity);
 			memcpy(ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ModelName, packet->Payload.data, (packet->Header.len - 2));
 
-			ConnectorTypeBindingHandler(dispenserIndex, connectorType, physicalType);
+			ConnectorTypeBindingHandler(dispenserIndex, connectorType, physicalType, safety);
 
 			LOG_INFO("Dispenser id %d identified, Connector quantity: %d\n", dispenserIndex + 1, quantity);
 
@@ -2915,9 +2946,7 @@ BOOL ConnectorChargingTargetHandler(struct PACKET_STRUCTURE *packet, unsigned ch
 		    }
 		}
 
-		GetPhysicalLimitVoltageAndCurrent(packet->Header.id - 1, &voltage, &current);
-		GetModelNameLimitPower(packet->Header.id - 1, &power);
-		GetConfigLimitPowerAndCurrent(packet->Header.id - 1, &power, &current);
+		RestrictAbsoluteLimit(packet->Header.id - 1, &power, &voltage, &current);
 
 		if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteTargetVoltage != voltage ||
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteTargetCurrent != current)
@@ -4091,6 +4120,13 @@ unsigned char ReadChargingTimestampHandler(struct PACKET_STRUCTURE *packet, int
     return find;
 }
 
+unsigned char ReadChargingBillHandler(struct PACKET_STRUCTURE *packet, int dispenserIndex)
+{
+    BOOL find = FindConnectorID(dispenserIndex, packet->Header.id);
+
+    return find;
+}
+
 void DisableConnector(unsigned char dispenserIndex)
 {
 	for(int i = 0; i < ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorQuantity; i++)
@@ -4580,6 +4616,16 @@ void DispenserSocketProcess(int socketFd, struct sockaddr_in clientInfo, unsigne
                         }
                         ChargingTimestampResponse(socketFd, &receiveBuffer, ackResult);
                     }
+
+                    // Reg: 0x26, Read ChargingBill
+                    if(receiveBuffer.Header.op == _Header_Read && receiveBuffer.Payload.reg == _Reg_ChargingBill)
+                    {
+                        if(ReadChargingBillHandler(&receiveBuffer, dispenserIndex))
+                        {
+                            ackResult = _R_OK;
+                        }
+                        ChargingBillResponse(socketFd, &receiveBuffer, ackResult);
+                    }
 				}
 
 				// clean timeout

+ 14 - 4
EVSE/Projects/DO360/Apps/Module_EvComm.h

@@ -28,13 +28,22 @@
 #define MAXIMUM_CONNECT_QUANTITY		4
 
 #define CCS_MAX_PHYSICAL_VOLTAGE        9500
-#define CCS_NATURAL_MAX_CURRENT         2000
-#define CCS_LIQUID_MAX_CURRENT          5000
-#define CCS_NATURAL_REMA_MAX_CURRENT    3000
+#define CCS_NATURAL_U_E_MAX_CURRENT     2000
+#define CCS_LIQUID_V_F_MAX_CURRENT      5000
+#define CCS_LIQUID_80_DERATING_1_CUR    4000
+#define CCS_LIQUID_85_DERATING_2_CUR    3000
+#define CCS_PANTOGRAPH_MAX_CURRENT      5000
+#define CCS_NATURAL_T_D_MAX_CURRENT     3000
+#define CCS_NATURAL_T_D_BOOST_CURRENT   5000
+#define CCS_NATURAL_T_D_85_DERATING_CUR 1000
+#define CCS_NATURAL_Y_Z_MAX_CURRENT     1500
 
 #define CHA_MAX_PHYSICAL_VOLTAGE        5000
 #define CHA_NATURAL_K_MAX_CURRENT       2000
 #define CHA_NATURAL_J_MAX_CURRENT       1200
+#define CHA_NATURAL_J_JARI_MAX_CURRENT  1250
+#define CHA_NATURAL_S_MAX_CURRENT       1250
+#define CHA_NATURAL_S_BOOST_CURRENT     2000
 
 #define GBT_MAX_PHYSICAL_VOLTAGE        7500
 #define GBT_NATURAL_MAX_CURRENT         2500
@@ -93,7 +102,8 @@ enum PAYLOAD_REGISTER
     _Reg_Receipt                    = 0x23,
     _Reg_PowerConsumption           = 0x24,
     _Reg_ChargingTimestamp          = 0x25,
-    _Reg_None                       = 0x26,
+    _Reg_ChargingBill               = 0x26,
+    _Reg_None                       = 0x27,
 };
 
 enum Response_Result

+ 66 - 5
EVSE/Projects/DO360/Apps/Module_PsuComm.c

@@ -105,6 +105,8 @@ byte startModuleFlag = false;
 bool psuReceiveRecovery = false;
 bool isCommStart = false;
 int lostCnt = 0;
+bool _isTriggerShutdown = false;
+bool _isShutdownCompleted = false;
 
 unsigned short evseOutVol[CONNECTOR_QUANTITY] = {0, 0, 0, 0};
 unsigned short evseOutCur[CONNECTOR_QUANTITY] = {0, 0, 0, 0};
@@ -4491,7 +4493,7 @@ void PsuGroupControlProcess(void)
                     ShmPsuGrouping->GroupCollection[group].PreRole = role;
                     ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.MasterCtrlValue = 0;
                     ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.StopChargingCtrlValue = 0;
-                    ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.DeratingCtrlValue = 0;
+                    //ShmPsuGrouping->GroupCollection[group].GroupCtrl.RoleCtrl.DeratingCtrlValue = 0;
                     ShmPsuGrouping->GroupCollection[group].ExtendQuantityLimit = 0;
                     PSU_LOG("===== PSU Group[%02X] ===== Master", group);
                     GetClockTime(&_PsuGroupRole_time[group]);
@@ -4650,7 +4652,7 @@ void PsuGroupControlProcess(void)
                 time = GetTimeoutValue(_PsuGroupRole_time[group]) / uSEC_VAL;
 
                 if(time >= MIN_POWER_OFF_TIME &&
-                    ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent <= MAX_PSU_POWER_OFF_CURRENT)
+                    (ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent <= MAX_PSU_POWER_OFF_CURRENT || _isTriggerShutdown))
                 {
                     SetPsuGroupRole(group, _GROLE_SWITCH_OFF_OK);
                 }
@@ -5110,6 +5112,63 @@ void InitialGunLimitSequence(void)
     }
 }
 
+bool IsShutdownTrigger(void)
+{
+    if(ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByPsu == YES ||
+        ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByEmergency == YES)
+    {
+        if(!_isTriggerShutdown)
+        {
+            PSU_LOG("Psu Shutdown Flag Is Trigger!");
+        }
+        _isTriggerShutdown = true;
+        return true;
+    }
+
+    if(_isTriggerShutdown)
+    {
+        PSU_LOG("Psu Shutdown Flag Recover");
+    }
+    _isTriggerShutdown = false;
+    return false;
+}
+
+bool IsShutdownCompleted(void)
+{
+    bool done = false;
+
+    if(IsShutdownTrigger())
+    {
+        done = true;
+        for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
+        {
+            if(ShmPsuGrouping->GroupCollection[i].Role != _GROLE_IDLE)
+            {
+                done = false;
+                break;
+            }
+        }
+
+        if(done)
+        {
+            if(!_isShutdownCompleted)
+            {
+                PSU_LOG("Psu Shutdown Completed!");
+            }
+            _isShutdownCompleted = true;
+        }
+        return done;
+    }
+
+    if(_isShutdownCompleted)
+    {
+        PSU_LOG("Psu Shutdown Clear!");
+    }
+    _isShutdownCompleted = false;
+
+    return done;
+}
+
 int main(void)
 {
     byte _TotalModuleCount = 0;
@@ -5159,6 +5218,8 @@ int main(void)
 	ShmPsuData->Work_Step = INITIAL_START;
 	isInitialComp = NO;
 	isCommStart = false;
+	_isTriggerShutdown = false;
+	_isShutdownCompleted = false;
 
 	LOG_INFO("PSU Work Status = %d", ShmPsuData->Work_Step);
 
@@ -5171,13 +5232,13 @@ int main(void)
 	while (libInitialize)
 	{
 	    PsuCommLostCheck();
+	    IsShutdownCompleted();
 
 		// 斷電狀態
         if (ShmChargerInfo->Control.RelayCtrl.bits.AcContactor == NO ||
-            ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByPsu == YES ||
-            ShmChargerInfo->Control.RelayCtrl.bits.AcContactorOffByEmergency == YES ||
             ShmChargerInfo->Control.PsuCtrl.bits.NeedSelfTest == YES ||
-            ShmChargerInfo->Control.PsuCtrl.bits.Paused == YES)
+            ShmChargerInfo->Control.PsuCtrl.bits.Paused == YES ||
+            _isShutdownCompleted)
 		{
 			//一但 AC Off PSU 斷電全部的 PSU Group ID 會全部清 0
 			if (!isInitialComp)

+ 437 - 56
EVSE/Projects/DO360/Apps/ReadCmdline.c

@@ -2515,10 +2515,10 @@ void ShowCabinetInfo(char *inputCmd, unsigned int opt)
 void SetTestControl(char *v1, char *v2)
 {
     int testItem = 0;
-    int testItemLen = 4;
+    int testItemLen = 5;
     int enable = 0;
-    char strTest[32][32] = {"tbl", "tfsb", "chgsm", "fcre"};
-    char strItem[32][32] = {"Balance", "Fast Standby Time", "Charging Simulation", "FCharging Release Extend"};
+    char strTest[32][32] = {"tbl", "tfsb", "chgsm", "fcre", "ubill"};
+    char strItem[32][32] = {"Balance", "Fast Standby Time", "Charging Simulation", "FCharging Release Extend", "Undisposed Bill"};
 
     enable = atoi(v2);
 
@@ -3249,30 +3249,50 @@ void EraseWhiteCard(char *v1)
     printf("\r\n\r\n");
 }
 
+// MaxChargingProfile: %s
+//   Offline MaxPower: %s
+//    Max Total Power: XXXX kW, Total Current: XXXX A,       MaxSoc: XXX %
+//       Total Energy: XXXX kWh,     Duration: XXXX Minute(s)
 void ShowMaxLimit(void)
 {
-    printf(" Charger Max ChargingProfile Power: %d kW\r\n", ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower == -1 ?
-        (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower : (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower / 1000);
-    printf(" Max Total Current: %d A, Max Total Power: %d kW, Total Energy: %d kW, Total Duration %d\r\n",
-        ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent, ShmSysConfigAndInfo->SysConfig.MaxChargingPower,
+    char tempString[64];
+
+    //************************************************************************************************
+    memset(tempString, 0x00, sizeof(tempString));
+    if(ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower == -1)
+    {
+        sprintf(tempString, " %s", "Unlimited");
+    }
+    else
+    {
+        sprintf(tempString, " %4d kW", (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower / 1000);
+    }
+    printf(" MaxChargingProfile: %s\r\n", tempString);
+    //************************************************************************************************
+    memset(tempString, 0x00, sizeof(tempString));
+    if(ShmChargerInfo->OutputLimit.Offline_MaxChargingPower <= 0)
+    {
+        sprintf(tempString, " %s", "Unlimited");
+    }
+    else
+    {
+        sprintf(tempString, " %4d kW", ShmChargerInfo->OutputLimit.Offline_MaxChargingPower / 1000);
+    }
+    printf("   Offline MaxPower: %s\r\n", tempString);
+    //************************************************************************************************
+    printf("    Max Total Power: %4d kW, Total Current: %4d A,       MaxSoc: %3d %%\r\n",
+        ShmSysConfigAndInfo->SysConfig.MaxChargingPower,
+        ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent,
+        ShmSysConfigAndInfo->SysConfig.MaxChargingSoc);
+    //************************************************************************************************
+    printf("       Total Energy: %4d kWh,     Duration: %4d Minute(s)\r\n",
         ShmSysConfigAndInfo->SysConfig.MaxChargingEnergy, ShmSysConfigAndInfo->SysConfig.MaxChargingDuration);
 }
 
 void ShowGunLimit(int gun_index)
 {
-    int limitPower = -1;
     char *str_gun_type[] = {STR_GUN_TYPE_CHADEMO, STR_GUN_TYPE_CCS, STR_GUN_TYPE_GBT};
 
-    unsigned char inUsingCnt = 0;
-
-    for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
-    {
-        if(ShmChargerInfo->PsuGrouping.GroupCollection[i].Role == _GROLE_MASTER)
-        {
-            inUsingCnt += ShmChargerInfo->PsuGrouping.GroupCollection[gun_index].GunPsuQuantity;
-        }
-    }
-
     // Gun Enable    Type  Psu  Phy_Vol  Phy_Cur  Config_Ocpp_MaxOcpp_Pow  Config_Ocpp_MaxOcpp_Cur
     //  1    0    CHAdeMO   00   0000 V   0000 A    0000 / 0000 / 0000 kW     0000 / 0000 A
     // Gun 1  Enable, Type: CCS, Psu Cnt: 00, Max Physical Vol: 0000 V, Cur: 0000 A, Max Config Pow: 0000 kW, Cur: 0000 A
@@ -3286,22 +3306,10 @@ void ShowGunLimit(int gun_index)
             (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].RemoteMaxPhysicalVoltage / 10),
             (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].RemoteMaxPhysicalCurrent / 10));
 
-        if(ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower != -1)
-        {
-            limitPower = (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower;
-            if(inUsingCnt > 0)
-            {
-                limitPower = (limitPower * ShmChargerInfo->PsuGrouping.GroupCollection[gun_index].GunPsuQuantity) / inUsingCnt;
-            }
-        }
-        else
-        {
-            limitPower = -1;
-        }
         printf("    %4d / %4d / %4d kW",
             (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxTotalChargingPower / 10),
             _chargingData[gun_index]->ChargingProfilePower == -1 ? (int)_chargingData[gun_index]->ChargingProfilePower : ((int)_chargingData[gun_index]->ChargingProfilePower / 1000),
-            limitPower == -1 ? limitPower : (limitPower / 1000));
+            ShmChargerInfo->OutputLimit.GunMaxProfilePower[gun_index] == 0 ? (int)ShmSysConfigAndInfo->SysInfo.MaxChargingProfilePower : (ShmChargerInfo->OutputLimit.GunMaxProfilePower[gun_index] / 1000));
 
         printf("     %4d / %4d A",
             ((int)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxTotalChargingCurrent / 10),
@@ -3331,7 +3339,7 @@ void ShowChargerLimit(char *inputCmd, unsigned int opt)
         {
             if(reflash)
             {
-                ConsoleReflash(1, 4);
+                ConsoleReflash(1, 6);
                 ConsoleReflash(CONNECTOR_QUANTITY, 1);
             }
 
@@ -3483,32 +3491,154 @@ void ShowWebChargingInfo(void)
     printf(" *Max Charging Power   : %4d kW\r\n", ShmSysConfigAndInfo->SysConfig.MaxChargingPower);
     printf(" *Max Charging Current : %4d A\r\n", ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent);
     printf(" *Max Charging Duration: %4d Minutes\r\n", ShmSysConfigAndInfo->SysConfig.MaxChargingDuration);
+    printf(" *Max Charging Soc     : %4d %%\r\n", ShmSysConfigAndInfo->SysConfig.MaxChargingSoc);
     printf(" *StopCharging By Button[%7s]\r\n", ShmSysConfigAndInfo->SysConfig.StopChargingByButton > 0 ? "Enable" : "Disable");
     printf(" *Billing[%7s]\r\n", ShmSysConfigAndInfo->SysConfig.BillingData.isBilling > 0 ? "Enable" : "Disable");
     printf("  - Currency[%2d]\r\n", ShmSysConfigAndInfo->SysConfig.BillingData.Currency);
 }
 
-void ShowWebNetworkInfo(void)
+// *DHCP Client  [Enable]
+//  - MAC Add    [%s]
+//  - IP Add     [%s]
+//  - Submask    [%s]
+//  - Gateway    [%s]
+void ShowEthernetInfo(void)
+{
+    printf(" *DHCP Client  [%s]\r\n", ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthDhcpClient == 0 ? "Enable" : "Disable");
+    printf("  - MAC Add    [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthMacAddress) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthMacAddress : "NULL");
+    printf("  - IP Add     [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthIpAddress) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthIpAddress : "NULL");
+    printf("  - SubMask    [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthSubmaskAddress) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthSubmaskAddress : "NULL");
+    printf("  - Gateway    [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthGatewayAddress) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthGatewayAddress : "NULL");
+}
+
+// *WiFi Mode    [Station]
+//  - SSID       [%s]
+//  - PWD        [%s]
+//  - TargetMac  [%s]
+//  - RSSI       [%s]
+//  - DHCP       [%s]
+//  - MAC Add    [%s]
+//  - IP Add     [%s]
+//  - Submask    [%s]
+//  - Gateway    [%s]
+//  - ConnStatus [Connected]
+void ShowWiFiInfo(void)
 {
     char *str_wifi_mode[] = {"Disable", "Station", "AP Mode"};
 
-    printf("\r\n");
-    printf("Web [Network]\r\n");
-    printf(" *NetworkStatus[%s]\r\n", ShmSysConfigAndInfo->SysInfo.InternetConn > 0 ? "Connected" : "Disconnected");
-    printf(" *DHCP Client[%7s]\r\n", ShmSysConfigAndInfo->SysConfig.Eth0Interface.EthDhcpClient == 0 ? "Enable" : "Disable");
     if(ShmSysConfigAndInfo->SysConfig.AthInterface.WifiMode <= _SYS_WIFI_MODE_AP)
     {
-        printf(" *WiFi Mode  [%7s]\r\n", str_wifi_mode[ShmSysConfigAndInfo->SysConfig.AthInterface.WifiMode]);
+        printf(" *WiFi Mode    [%s]\r\n", str_wifi_mode[ShmSysConfigAndInfo->SysConfig.AthInterface.WifiMode]);
     }
     else
     {
-        printf(" *WiFi Mode  [%d]\r\n", ShmSysConfigAndInfo->SysConfig.AthInterface.WifiMode);
+        printf(" *WiFi Mode    [%d]\r\n", ShmSysConfigAndInfo->SysConfig.AthInterface.WifiMode);
+    }
+    if(ShmSysConfigAndInfo->SysConfig.AthInterface.WifiMode == _SYS_WIFI_MODE_STATION)
+    {
+        printf("  - SSID       [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiSsid) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiSsid : "NULL");
+        printf("  - PWD        [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiPassword) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiPassword : "NULL");
+        printf("  - TargetMac  [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiTargetBssidMac) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiTargetBssidMac : "NULL");
+        printf("  - RSSI       [%d dBm]\r\n", ShmSysConfigAndInfo->SysConfig.AthInterface.WifiRssi);
+        printf("  - DHCP       [%s]\r\n", ShmSysConfigAndInfo->SysConfig.AthInterface.WifiDhcpClient == 0 ? "Enable" : "Disable");
+        printf("  - MAC Add    [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiMacAddress) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiMacAddress : "NULL");
+        printf("  - IP Add     [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiIpAddress) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiIpAddress : "NULL");
+        printf("  - SubMask    [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiSubmaskAddress) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiSubmaskAddress : "NULL");
+        printf("  - Gateway    [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiGatewayAddress) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.AthInterface.WifiGatewayAddress : "NULL");
+        printf("  - ConnStatus [%s]\r\n", ShmSysConfigAndInfo->SysConfig.AthInterface.WifiNetworkConn == YES ? "Connected" : "Disconnected");
+    }
+}
+
+// *3G/4G Mode   [%s]
+//  - APN        [%s]
+//  - NetworkType[%s]
+//  - RSSI       [%d dBm]
+//  - ChapPapId  [%s]
+//  - ChapPapPwd [%s]
+//  - Modem IMEI [%s]
+//  - SIM IMSI   [%s]
+//  - SIM ICCID  [%s]
+//  - SIM Status [%s]
+//  - Modem Mode [%s]
+//  - IP Add     [%s]
+//  - ConnStatus [%s]
+void Show3G4GInfo(void)
+{
+    char *strNetworkType[] = {"Auto", "CDMA", "WCDMA", "LTE", "TD-SCDMA", "UMTS", "CDMA", "HDR", "CDMA/HDR"};
+    char *strSimStatus[] = {"No SIM Card", "Valid SIM Card", "Invalid SIM Card"};
+    char *strModemMode[] = {"No Services", "CDMA", "GSM/GPRS", "WCDMA", "GSM/WCDMA", "TD_SCDMA", "HSPA", "LTE", "Mode 8", "Unknown"};
+
+    printf(" *3G/4G Mode   [%s]\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomEnabled == YES ? "Enable" : "Disable");
+    if(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomEnabled == YES)
+    {
+        printf("  - APN        [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomApn) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomApn : "NULL");
+        if(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomNetworkType <= 8)
+        {
+            printf("  - NetworkType[%s]\r\n", strNetworkType[ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomNetworkType]);
+        }
+        else
+        {
+            printf("  - NetworkType[%d]\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomNetworkType);
+        }
+        printf("  - RSSI       [%d dBm]\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomRssi);
+        printf("  - ChapPapId  [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapId) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapId : "NULL");
+        printf("  - ChapPapPwd [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapPwd) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapPwd : "NULL");
+        printf("  - Modem IMEI [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemImei) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemImei : "NULL");
+        printf("  - SIM IMSI   [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimImsi) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimImsi : "NULL");
+        printf("  - SIM ICCID  [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimIccid) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimIccid : "NULL");
+        if(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimStatus <= 2)
+        {
+            printf("  - SIM Status [%s]\r\n", strSimStatus[ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimStatus]);
+        }
+        else
+        {
+            printf("  - SIM Status [%d]\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimStatus);
+        }
+        if(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemMode <= 9)
+        {
+            printf("  - Modem Mode [%s]\r\n", strModemMode[ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemMode]);
+        }
+        else
+        {
+            printf("  - Modem Mode [%d]\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemMode);
+        }
+        printf("  - IP Add     [%s]\r\n", strlen((char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomIpAddress) > 0 ? (char *)ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomIpAddress : "NULL");
+        printf("  - ConnStatus [%s]\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomNetworkConn  == YES ? "Connected" : "Disconnected");
     }
-    printf("  - ConnStatus[%s]\r\n", ShmSysConfigAndInfo->SysConfig.AthInterface.WifiNetworkConn == YES ? "Connected" : "Disconnected");
-    printf(" *3G/4G Mode [%7s]\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomEnabled == YES ? "Enable" : "Disable");
-    printf("  - ConnStatus[%s]\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomNetworkConn  == YES ? "Connected" : "Disconnected");
-    printf("  - APN : %s\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomApn);
-    printf("  - RSSI: %d dBm\r\n", ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomRssi);
+}
+
+void ShowWebNetworkInfo(void)
+{
+    printf("\r\n");
+    printf("Web [Network]\r\n");
+    printf(" *NetworkStatus[%s]\r\n", ShmSysConfigAndInfo->SysInfo.InternetConn > 0 ? "Connected" : "Disconnected");
+    ShowEthernetInfo();
+    ShowWiFiInfo();
+    Show3G4GInfo();
+}
+
+void ShowWebEthernetOnly(void)
+{
+    printf("\r\n");
+    printf("Web [Network]\r\n");
+    printf(" *NetworkStatus[%s]\r\n", ShmSysConfigAndInfo->SysInfo.InternetConn > 0 ? "Connected" : "Disconnected");
+    ShowEthernetInfo();
+}
+
+void ShowWebWiFiOnly(void)
+{
+    printf("\r\n");
+    printf("Web [Network]\r\n");
+    printf(" *NetworkStatus[%s]\r\n", ShmSysConfigAndInfo->SysInfo.InternetConn > 0 ? "Connected" : "Disconnected");
+    ShowWiFiInfo();
+}
+
+void ShowWeb3G4GOnly(void)
+{
+    printf("\r\n");
+    printf("Web [Network]\r\n");
+    printf(" *NetworkStatus[%s]\r\n", ShmSysConfigAndInfo->SysInfo.InternetConn > 0 ? "Connected" : "Disconnected");
+    Show3G4GInfo();
 }
 
 void ShowWebBackendInfo(void)
@@ -3594,9 +3724,11 @@ void ShowWebInfo(char *inputCmd, unsigned int opt)
 
     bool find = false;
     int showItem = 0;
-    int itemLen = 5;
-    char strItem[32][32] = {"system", "charging", "network", "backend", "all"};
-    void *actionList[32] = {&ShowWebSystemInfo, &ShowWebChargingInfo, &ShowWebNetworkInfo, &ShowWebBackendInfo, &ShowWebAllInfo};
+    int itemLen = 8;
+    char strItem[32][32] = {"system", "charging", "network", "backend", "all", "eth", "wifi", "4g"};
+    void *actionList[32] = {
+        &ShowWebSystemInfo, &ShowWebChargingInfo, &ShowWebNetworkInfo, &ShowWebBackendInfo,
+        &ShowWebAllInfo, &ShowWebEthernetOnly, &ShowWebWiFiOnly, &ShowWeb3G4GOnly};
     void (*ItemAction)();
 
     for(showItem = 0; showItem < itemLen; showItem++)
@@ -3632,6 +3764,13 @@ void ShowWebInfo(char *inputCmd, unsigned int opt)
 //  Start: [0000-00-00 00:00:00] PSU:  XXXX V,  XXXX A,  Limit: XXXX A, XXXX kW, Local: XXXXXXX.XXX kWh
 //                               Gun:  XXXX V,  XXXX A, Remote: XXXXXXX.XXX kWh, Meter: XXXXXXX.XXX kWh
 //   Stop: [0000-00-00 00:00:00] Gun:  XXXX V,  XXXX A, Remote: XXXXXXX.XXX kWh, Meter: XXXXXXX.XXX kWh
+
+// Gun 1 (  CCS  )               Soc:   XXX %,          Energy: XXXXXXX.XXX kWh, IdTag: [XXXXXXXXXX]
+//  (XX)    (X)               Target:  XXXX V,  XXXX A,    Cap: XXXX A, XXXX kW,  TxId: [XXXXXXXXXX]
+//  Start: [0000-00-00 00:00:00] PSU:  XXXX V,  XXXX A,  Limit: XXXX A, XXXX kW, Ratio: X.XX %
+//   Stop: [0000-00-00 00:00:00] Gun:  XXXX V,  XXXX A,  Power:       XXXX.X kW, FireV: XXXX.X V
+//                            Remote:  XXXXXXX.XXX kWh,  Local: XXXXXXX.XXX kWh, Meter: XXXXXXX.XXX kWh
+
 void ShowGunInfo(int gun)
 {
     char *str_gun_type[] = {"CHAdeMO", "  CCS  ", "  GBT  "};
@@ -3683,12 +3822,12 @@ void ShowGunInfo(int gun)
     {
         printf("                               ");
     }
-    printf("PSU:  %4d V,  %4d A,  Limit: %4d A, %4d kW, Local: %11.3f kWh\r\n",
+    printf("PSU:  %4d V,  %4d A,  Limit: %4d A, %4d kW, Ratio: %4.2f %%\r\n",
         (int)(_chargingData[gun]->PresentChargingVoltage),
         (int)(_chargingData[gun]->PresentChargingCurrent),
         (int)(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].CapabilityCurrent / 10),
         (int)(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].CapabilityPower / 10),
-        ShmChargerInfo->MeterValue[gun].LocalConsumption);
+        ShmPsuGrouping->GroupCollection[gun].MaxOutputRatio);
     //************************************************************************************************
     if(strlen(ShmChargerInfo->Timestamp[gun].StopCharging) > 0)
     {
@@ -3698,10 +3837,16 @@ void ShowGunInfo(int gun)
     {
         printf("                               ");
     }
-    printf("Gun:  %4d V,  %4d A, Remote: %11.3f kWh, Meter: %11.3f kWh\r\n",
+    printf("Gun:  %4d V,  %4d A,  Power:       %6.1f kW, FireV: %6.1f V\r\n",
         (int)(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingVoltage / 10),
         (int)(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingCurrent / 10),
-        ShmChargerInfo->MeterValue[gun].GunConsumption, _chargingData[gun]->PowerConsumption);
+        _chargingData[gun]->PresentChargingPower,
+        (_chargingData[gun]->FireChargingVoltage / 10));
+    //************************************************************************************************
+    printf("                            Remote:  %11.3f kWh,  Local: %11.3f kWh, Meter: %11.3f kWh\r\n",
+        ShmChargerInfo->MeterValue[gun].GunConsumption,
+        ShmChargerInfo->MeterValue[gun].LocalConsumption,
+        _chargingData[gun]->PowerConsumption);
 }
 
 void ShowInfo(char *inputCmd, unsigned int opt)
@@ -3723,7 +3868,7 @@ void ShowInfo(char *inputCmd, unsigned int opt)
         {
             if(reflash)
             {
-                ConsoleReflash(CONNECTOR_QUANTITY, 5);
+                ConsoleReflash(CONNECTOR_QUANTITY, 6);
             }
 
             for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
@@ -4395,6 +4540,96 @@ bool SetLEDIntensity(char *intensity)
     return true;
 }
 
+bool SetMaxChargingEnergy(char *energy)
+{
+    int _energy = 0;
+
+    _energy = atoi(energy);
+
+    if(_energy < 0)
+    {
+        printf("MaxChargingEnergy: [%s] is Illegal\r\n", energy);
+        printf(" [value] > 0\r\n");
+        return false;
+    }
+
+    ShmSysConfigAndInfo->SysConfig.MaxChargingEnergy = _energy;
+    printf("Set MaxChargingEnergy: [%d] OK\r\n", ShmSysConfigAndInfo->SysConfig.MaxChargingEnergy);
+    return true;
+}
+
+bool SetMaxChargingPower(char *power)
+{
+    int _power = 0;
+
+    _power = atoi(power);
+
+    if(_power < 0)
+    {
+        printf("MaxChargingEnergy: [%s] is Illegal\r\n", power);
+        printf(" [value] > 0\r\n");
+        return false;
+    }
+
+    ShmSysConfigAndInfo->SysConfig.MaxChargingPower = _power;
+    printf("Set MaxChargingPower: [%d] OK\r\n", ShmSysConfigAndInfo->SysConfig.MaxChargingPower);
+    return true;
+}
+
+bool SetMaxChargingCurrent(char *current)
+{
+    int _current = 0;
+
+    _current = atoi(current);
+
+    if(_current < 0)
+    {
+        printf("MaxChargingEnergy: [%s] is Illegal\r\n", current);
+        printf(" [value] > 0\r\n");
+        return false;
+    }
+
+    ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent = _current;
+    printf("Set MaxChargingCurrent: [%d] OK\r\n", ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent);
+    return true;
+}
+
+bool SetMaxChargingDuration(char *duration)
+{
+    int _duration = 0;
+
+    _duration = atoi(duration);
+
+    if(_duration < 0)
+    {
+        printf("MaxChargingDuration: [%s] is Illegal\r\n", duration);
+        printf(" [value] > 0\r\n");
+        return false;
+    }
+
+    ShmSysConfigAndInfo->SysConfig.MaxChargingDuration = _duration;
+    printf("Set MaxChargingDuration: [%d] OK\r\n", ShmSysConfigAndInfo->SysConfig.MaxChargingDuration);
+    return true;
+}
+
+bool SetMaxChargingSoc(char *soc)
+{
+    int _soc = 0;
+
+    _soc = atoi(soc);
+
+    if(_soc < 0 || _soc > 100)
+    {
+        printf("MaxChargingSoc: [%s] is Illegal\r\n", soc);
+        printf(" [value] 0 ~ 100\r\n");
+        return false;
+    }
+
+    ShmSysConfigAndInfo->SysConfig.MaxChargingSoc = _soc;
+    printf("Set MaxChargingSoc: [%d] OK\r\n", ShmSysConfigAndInfo->SysConfig.MaxChargingSoc);
+    return true;
+}
+
 bool SetStopChargingByButton(char *btn)
 {
     bool enable = false;
@@ -4559,15 +4794,17 @@ void FlashSetCmd(char *inputCmd, unsigned int opt)
     bool find = false;
     int actIndex = 0;
 
-    int maxLen = 15;
+    int maxLen = 20;
     char strWriteItem[32][32] = {
         "model", "sn", "sysid", "auth", "evccid", "qrmode", "qrcode", "led",
-        "stopbtn", "policy", "backend", "boxid", "vendor", "receipt", "maintain"};
+        "energy", "power", "current", "time", "soc", "stopbtn", "policy", "backend",
+        "boxid", "vendor", "receipt", "maintain"};
     bool (*writeFlashList[32])(char *) = {
         &SetModelName, &SetSerialNumber, &SetSystemID, &SetAuthorisationMode,
         &SetAuthrizeByEVCCID, &SetQRCodeMadeMode, &SetQRCodeContent, &SetLEDIntensity,
-        &SetStopChargingByButton, &SetOfflinePolicy, &SetOcppServerURL, &SetChargeBoxId,
-        &SetChargePointVendor, &SetOcppReceiptrURL, &SetMaintainServerURL};
+        &SetMaxChargingEnergy, &SetMaxChargingPower, &SetMaxChargingCurrent, &SetMaxChargingDuration,
+        &SetMaxChargingSoc, &SetStopChargingByButton, &SetOfflinePolicy, &SetOcppServerURL,
+        &SetChargeBoxId, &SetChargePointVendor, &SetOcppReceiptrURL, &SetMaintainServerURL};
 
     bool (*WriteFlashAct)(char *);
 
@@ -5038,6 +5275,146 @@ void RelayCmd(char *inputCmd, unsigned int opt)
     printf("Input cmd fail ------  relay [abnormal | write | read | autotest] [...]\r\n\r\n");
 }
 
+// Sys CurrentRate: [XX.XX]
+//  TimeOfDayPrice: [00-01: XX.XX] [01-02: XX.XX] [02-03: XX.XX] [03-04: XX.XX] [04-05: XX.XX] [05-06: XX.XX]
+//                : [06-07: XX.XX] [07-08: XX.XX] [08-09: XX.XX] [09-10: XX.XX] [10-11: XX.XX] [11-12: XX.XX]
+//                : [12-13: XX.XX] [13-14: XX.XX] [14-15: XX.XX] [15-16: XX.XX] [16-17: XX.XX] [17-18: XX.XX]
+//                : [18-19: XX.XX] [19-20: XX.XX] [20-21: XX.XX] [21-22: XX.XX] [22-23: XX.XX] [23-24: XX.XX]
+int ShowSysPriceInfo(void)
+{
+    int showLine = 1;
+    char priceString[1024];
+
+    //************************************************************************************************
+    printf(" Sys CurrentRate: [%5.2f]\r\n", ShmChargerInfo->PriceAndReceiptInfo.CurrentRate);
+
+    if(ShmChargerInfo->Control.CustomerCode == _CUSTOMER_CODE_TCC)
+    {
+        //************************************************************************************************
+        memset(priceString, 0x00, sizeof(priceString));
+        for(int i = 0; i < 6; i++)
+        {
+            char strTemp[64];
+            sprintf(strTemp, " [%02d-%02d: %5.2f]", i, i + 1, ShmChargerInfo->PriceAndReceiptInfo.TimeOfDayPricing[i]);
+            strcat(priceString, strTemp);
+        }
+        printf("  TimeOfDayPrice:%s\r\n", priceString);
+        //************************************************************************************************
+        memset(priceString, 0x00, sizeof(priceString));
+        for(int i = 6; i < 12; i++)
+        {
+            char strTemp[64];
+            sprintf(strTemp, " [%02d-%02d: %5.2f]", i, i + 1, ShmChargerInfo->PriceAndReceiptInfo.TimeOfDayPricing[i]);
+            strcat(priceString, strTemp);
+        }
+        printf("                :%s\r\n", priceString);
+        //************************************************************************************************
+        memset(priceString, 0x00, sizeof(priceString));
+        for(int i = 12; i < 18; i++)
+        {
+            char strTemp[64];
+            sprintf(strTemp, " [%02d-%02d: %5.2f]", i, i + 1, ShmChargerInfo->PriceAndReceiptInfo.TimeOfDayPricing[i]);
+            strcat(priceString, strTemp);
+        }
+        printf("                :%s\r\n", priceString);
+        //************************************************************************************************
+        memset(priceString, 0x00, sizeof(priceString));
+        for(int i = 18; i < 24; i++)
+        {
+            char strTemp[64];
+            sprintf(strTemp, " [%02d-%02d: %5.2f]", i, i + 1, ShmChargerInfo->PriceAndReceiptInfo.TimeOfDayPricing[i]);
+            strcat(priceString, strTemp);
+        }
+        printf("                :%s\r\n", priceString);
+        showLine += 4;
+    }
+    return showLine;
+}
+
+// Gun X UserPrice: [%s]
+//         Receipt: [%s]
+int ShowGunPriceInfo(int gun)
+{
+    int showLine = 2;
+    char priceString[1024];
+
+    //************************************************************************************************
+    memset(priceString, 0x00, sizeof(priceString));
+    if(strlen(&ShmChargerInfo->PriceAndReceiptInfo.UserPriceString[gun][0]) > 0)
+    {
+        strcpy(priceString, &ShmChargerInfo->PriceAndReceiptInfo.UserPriceString[gun][0]);
+    }
+    else
+    {
+        strcpy(priceString, "NULL");
+    }
+    printf(" Gun %d UserPrice: [%s]\r\n", gun + 1, priceString);
+
+    //************************************************************************************************
+    memset(priceString, 0x00, sizeof(priceString));
+    if(strlen(&ShmChargerInfo->PriceAndReceiptInfo.ReceiptUrl[gun][0]) > 0)
+    {
+        strcpy(priceString, &ShmChargerInfo->PriceAndReceiptInfo.ReceiptUrl[gun][0]);
+    }
+    else
+    {
+        strcpy(priceString, "NULL");
+    }
+    printf("         Receipt: [%s]\r\n", priceString);
+
+    return showLine;
+}
+
+void ShowPrice(char *inputCmd, unsigned int opt)
+{
+    int totalLine = 0;
+    bool keepRun = false;
+    bool reflash = false;
+    int time = 0;
+    struct timespec _Loop_time;
+
+    if((opt & OPTION_REFLASH) || (opt & OPTION_LOOP) > 0)
+    {
+        keepRun = true;
+    }
+
+    do
+    {
+        time = GetTimeoutValue(_Loop_time) / mSEC_VAL;
+        if(time >= 1000)
+        {
+            if(reflash)
+            {
+                ConsoleReflash(1, totalLine);
+            }
+
+            totalLine = 0;
+            printf("\r\n");
+            totalLine += ShowSysPriceInfo() + 1;
+            printf("\r\n");
+            totalLine += 1;
+
+            for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
+            {
+                totalLine += ShowGunPriceInfo(i);
+            }
+            GetClockTime(&_Loop_time);
+
+            if((opt & OPTION_REFLASH) > 0)
+            {
+                reflash = true;
+            }
+        }
+
+        if(keepRun)
+        {
+            keepRun = IsLoopStopCmd() ? false : true;
+            usleep(10000);
+        }
+    }while(keepRun);
+    printf("\r\n");
+}
+
 int main(void)
 {
     char newString[32][MAX_SUB_CMD_LENGTH];
@@ -5467,6 +5844,10 @@ int main(void)
         else if(strcmp(mainCmd, "relay") == 0)
         {
         	RelayCmd(subCmd, option);
+        }
+        else if(strcmp(mainCmd, "price") == 0)
+        {
+            ShowPrice(subCmd, option);
         }
 		else
 		{

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 478 - 301
EVSE/Projects/DO360/Apps/main.c


BIN
EVSE/Projects/DO360/Images/FactoryDefaultConfig.bin


BIN
EVSE/Projects/DO360/Images/ramdisk.gz


BIN
EVSE/rootfs/root/Module_PowerSharing


Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно