Browse Source

2022-10-26 / Wendell

Actions
1. [add] occupancy fee function for tcc
2. [add] current derating after otp
3. [add] local power sharing
4. [add] misc command for rfid endian
5. [add] support phihong power module library
6. [add] support boost mode gun type
7. [mod] improve calculation of charged energy
8. [mod] improve upgrade logic
9. [mod] improve log content

Files
1. As follow commit history

Image version : V2.05.XX.XXXX.XX
Wendell 2 years ago
parent
commit
80cdcc6887

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

@@ -169,6 +169,32 @@ int StoreDbMsg(const char *fmt, ...)
 
     return rc;
 }
+
+int StoreOccupancyMsg(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]OccupancyLog",
+        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)
 {

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

@@ -12,6 +12,7 @@
 
 #define ARRAY_SIZE(A)               (sizeof(A) / sizeof(A[0]))
 #define PASS                        1
+#define WAIT                        0
 #define FAIL                        -1
 #define YES                         1
 #define NO                          0
@@ -36,6 +37,7 @@
 #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 Occupancy_INFO(format, args...) StoreOccupancyMsg("[%s:%4d][%s][OF] "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"
@@ -46,6 +48,7 @@ int StoreEventLogMsg(const char *fmt, ...);
 int StoreAuthLogMsg(const char *fmt, ...);
 int StoreEvCommMsg(const char *fmt, ...);
 int StoreDbMsg(const char *fmt, ...);
+int StoreOccupancyMsg(const char *fmt, ...);
 
 void GetClockTime(struct timespec *_now_time);
 unsigned long GetTimeoutValue(struct timespec _start_time);

+ 188 - 18
EVSE/Projects/DO360/Apps/Config.h

@@ -315,6 +315,13 @@ enum _ETHERNET_USAGE
 	_ETHERNET_USAGE_3G_4g
 };
 
+enum _SYS_POWER_SHARING_MODE
+{
+    _SYS_POWER_SHARING_MODE_DISABLE = 0,
+    _SYS_POWER_SHARING_MODE_MASTER  = 1,
+    _SYS_POWER_SHARING_MODE_SLAVE   = 2,
+};
+
 #define STR_CONN_DISABLE            "Disable"
 #define STR_CONN_CONNECTED          "Connected"
 #define STR_CONN_DISCONNECTED       "Disconnected"
@@ -421,6 +428,17 @@ typedef union
     }bits;
 }SystemControl;
 
+typedef union
+{
+    unsigned int LibValue;
+    struct
+    {
+        unsigned int InfyPwrLib:1;                  // 0: no effect,                1: infy pwr lib used
+        unsigned int PhPwrLib:1;                    // 0: no effect,                1: phihong pwr lib used
+        unsigned int res:30;
+    }bits;
+}LibUse;
+
 typedef union
 {
     unsigned int CtrlValue;
@@ -713,6 +731,7 @@ typedef struct
     unsigned char   res;
     CommInfoData    CommInfo;
     SystemControl   SysCtrl;
+    LibUse          LibCtrl;
     UpdateControl   UpdateCtrl;
     TestControl     TestCtrl;
     DebugControl    DebugCtrl;
@@ -732,19 +751,55 @@ typedef struct
 // ************************************************************************************************* //
 typedef struct
 {
-    bool          CheckIn;
-    unsigned char Address;
-    unsigned char GroupNo;
-    unsigned char GIndex;
+    bool           CheckIn;
+    unsigned char  res;
+    unsigned short Full_Address;
+    unsigned char  GroupNo;
+    unsigned char  GIndex;
 }PsuAddressInfoData;
 
 typedef struct
 {
-    unsigned char GroupPsuQuantity;
-    unsigned char res;
-    unsigned char PsuSN[MAX_MODULE_PER_GROUP];
+    unsigned char  GroupPsuQuantity;
+    unsigned char  res;
+    unsigned short PsuIndex[MAX_MODULE_PER_GROUP];
 }GroupInfoData;
 
+#define PSU_STATUS_FLAG_OUTPUT                      0x00000001
+#define PSU_STATUS_FLAG_FAULT                       0x00000002
+#define PSU_STATUS_FLAG_ALARM                       0x00000004
+#define PSU_STATUS_FLAG_LOCK                        0x00000008
+
+typedef union
+{
+    unsigned int StatusVal;
+    struct
+    {
+        unsigned int Output:1;                      // 0: no output,                1: psu is output
+        unsigned int Fault:1;                       // 0: no fault,                 1: psu is fault
+        unsigned int Alarm:1;                       // 0: no alarm,                 1: psu is alarm
+        unsigned int Lock:1;                        // 0: no lock,                  1: psu is lock
+        unsigned int res:28;
+    }bits;
+}PsuStatusInfo;
+
+typedef union
+{
+    unsigned int StatusVal;
+    struct
+    {
+        unsigned int Changed:1;                     // 0: no output,                1: psu is output
+        unsigned int res:31;
+    }bits;
+}PsuErrorStatusInfo;
+
+typedef struct
+{
+    int ErrorCount;
+    PsuErrorStatusInfo ErrFlag;
+    unsigned char PsuError[8];
+}PsuErrorCodeInfo;
+
 typedef struct
 {
     bool                PsuLocationInit;
@@ -752,6 +807,8 @@ typedef struct
     unsigned char       TotalPsuQuantity;
     GroupInfoData       GroupLocationInfo[MAX_GROUP_QUANTITY];
     PsuAddressInfoData  PsuAddressInfo[MAX_PSU_MODULE_QUANTITY];
+    PsuStatusInfo       SinglePsuStatus[MAX_PSU_MODULE_QUANTITY];
+    PsuErrorCodeInfo    SinglePsuError[MAX_PSU_MODULE_QUANTITY];
 }PsuPositionInfoData;
 // ************************************************************************************************* //
 typedef enum
@@ -936,6 +993,8 @@ typedef struct
     PsuGroupOutputRelay     OutputRelayConfirmed[MAX_GUN_QUANTITY];
     PsuGroupParallelRelay   ParallelRelayConfig;
     PsuGroupParallelRelay   ParallelRelayConfirmed;
+    PsuStatusInfo           GroupPsuStatus_OR[MAX_GROUP_QUANTITY];
+    PsuStatusInfo           GroupPsuStatus_AND[MAX_GROUP_QUANTITY];
 }PsuGroupingInfoData;
 // ************************************************************************************************* //
 
@@ -1067,6 +1126,9 @@ typedef union
 #define MISC_DISP_STATION_INFO              0x00008000
 #define MISC_DISP_TIME_OFFSET               0x00010000
 #define MISC_DISP_DEFAULT_PRICE_STRING      0x00020000
+#define MISC_DISP_PARKING_PRICE             0x00040000
+#define MISC_DISP_RFID_CARD_ENDIAN          0x00080000
+#define MISC_DISP_RFID_ENABLE               0x00100000
 
 typedef union
 {
@@ -1091,8 +1153,11 @@ typedef union
         unsigned int ChangeLcmInfo:1;                   // msic: 0x0107,    0: no request,  1: change lcm info request
         unsigned int ChargerStationInfo:1;              // msic: 0x0109,    0: no request,  1: charger station info request
         unsigned int TimeOffset:1;                      // msic: 0x0010,    0: no request,  1: time offset request
-        unsigned int DefaultPriceString:1;              // msic: 0x0010,    0: no request,  1: time offset request
-        unsigned int res:14;
+        unsigned int DefaultPriceString:1;              // msic: 0x0010,    0: no request,  1: default price string request
+        unsigned int ParkingPrice:1;                    // msic: 0x0011,    0: no request,  1: parking price request
+        unsigned int RFIDCardEndian:1;                  // msic: 0x0012,    0: no request,  1: RFID card endian request
+        unsigned int RFIDEnable:1;                      // msic: 0x0013,    0: no request,  1: RFID enable request
+        unsigned int res:11;
     }bits;
 }DispenserMiscControl;
 
@@ -1108,6 +1173,7 @@ typedef union
 #define MISC_CONN_USER_PRICE_STRING         0x00000200
 #define MISC_CONN_RECEIPT                   0x00000400
 #define MISC_CONN_CHARGING_BILL             0x00000800
+#define MISC_CONN_PARKING_STATUS            0x00001000
 
 typedef union
 {
@@ -1127,7 +1193,8 @@ typedef union
         unsigned int UserPriceStringRequest:1;          // msic: 0x010D,    0: no request,  1: User Price String request
         unsigned int ReceiptRequest:1;                  // msic: 0x010E,    0: no request,  1: Receipt request
         unsigned int ChargingBillRequest:1;             // msic: 0x010F,    0: no request,  1: charging bill request
-        unsigned int res:20;
+        unsigned int ParkingStatusRequest:1;            // msic: 0x0110,    0: no request,  1: parking status request
+        unsigned int res:19;
     }bits;
 }ConnectorMiscControl;
 
@@ -1148,6 +1215,9 @@ typedef struct
     unsigned int EVCCIDConfig;                  // 0: disable, 1: enable
     unsigned int LEDIntensity;                  // LED intensity, 0: Darkest  1: Medium   2: Brightest
     int          TimeOffset;                    // time offset value, unit: 1 minute
+    float        ParkingPrice;                  // unit: 1 (dollar/minute)
+    unsigned int RfidEndian;                    // 0: little endian,  1: big endian
+    unsigned int RfidReaderEnable;              // 0: disable,  1: enable
 }MiscCommandValue;
 
 typedef union
@@ -1157,7 +1227,8 @@ typedef union
     {
         // dispenser -> cabinet
         unsigned int ChargingCancel:1;                  // cmd: 0x0001,     0: no request,  1: charging cancel request
-        unsigned int res:31;
+        unsigned int ParkingFeeRequest:1;               // cmd: 0x0002,     0: no request,  1: parking fee request
+        unsigned int res:30;
     }bits;
 }ConnectorActionFlag;
 
@@ -1186,6 +1257,7 @@ typedef struct
     int DeductAmount;                       // DeductAmount,        unit = 0.01 dollar
     char ApprovalNumber[9];                 // ApprovalNumber
     char VemData[64];                       // Vem Data
+    char Sn[36];
 }DeductResultInfoData;
 
 typedef struct
@@ -1238,16 +1310,20 @@ typedef struct
 
 enum DeductResult
 {
-    _Deduct_Fail    = 0x0,                  // deduct fail
-    _Deduct_Pass    = 0x1,                  // deduct pass
-    _Deduct_Cancel  = 0x2,                  // pre-auth cancel
-    _Deduct_PreAuth = 0x3,                  // pre-auth
+    _Deduct_PreAuth_Fail    = 0x0,          // pre-auth fail
+    _Deduct_PreAuth_Pass    = 0x1,          // pre-auth pass
+    _Deduct_PreAuth_Cancel  = 0x2,          // pre-auth cancel
+    _Deduct_PreAuth         = 0x3,          // pre-auth
+    _Deduct_Sale_Fail       = 0x4,          // sale fail
+    _Deduct_Sale_Pass       = 0x5,          // sale pass
 };
 
 #define STR_DEDUCT_FAIL             "Deduct Fail"
 #define STR_DEDUCT_PASS             "Deduct Pass"
 #define STR_DEDUCT_CANCEL           "PreAuth Cancel"
 #define STR_DEDUCT_PREAUTH          "PreAuth OK"
+#define STR_SALE_FAIL               "Sale Fail"
+#define STR_SALE_PASS               "Sale Pass"
 
 typedef struct
 {
@@ -1312,9 +1388,16 @@ typedef union
         unsigned int OutputRelayDrivingFault:1;         // 0: no effect,    1: DrivingFault
         unsigned int ParallelRelayWelding:1;            // 0: no effect,    1: Welding
         unsigned int ParallelRelayDrivingFault:1;       // 0: no effect,    1: DrivingFault
-        unsigned int res:28;
+        unsigned int PsuGroupAllAlarmFault:1;           // 0: no effect,    1: psu group all alarm or fault
+        unsigned int res:27;
     }bits;
-}OutputError;
+}GunErrorFlag;
+
+typedef struct
+{
+    GunErrorFlag ErrFlag;
+    char GunAlarmCode[7];
+}GunError;
 
 typedef struct
 {
@@ -1379,10 +1462,97 @@ typedef struct
     char Receipt[512];
 }ChargingBillInfoData;
 
+typedef enum
+{
+    _ParkingAction_None             = 0x00,                 // no action
+    _ParkingAction_DisplayButton    = 0x01,                 // Display Occupancy Fee button
+    _ParkingAction_CancelOccupancy  = 0x02,                 // Cancel Occupancy Fee button
+    _ParkingAction_PaidOnlineOK     = 0x03,                 // Successed to pay occupancy fee with online method, then close Occupancy Fee button
+    _ParkingAction_PaidOnlineFail   = 0x04,                 // Failed to pay occupancy fee with online method
+}OccupancyAction;
+
+#define STR_OCCUPANCY_ACT_NONE      "NoAction"
+#define STR_OCCUPANCY_ACT_DISPLAY   "DisplayButton"
+#define STR_OCCUPANCY_ACT_CANCEL    "CancelOccupancy"
+#define STR_OCCUPANCY_ACT_PAID_OK   "PaidOnlineOK"
+#define STR_OCCUPANCY_ACT_PAID_NG   "PaidOnlineFail"
+
+typedef enum
+{
+    _Parking_NoOccupancy        = 0x00,                 // no occupancy
+    _Parking_SyncOccupancy      = 0x01,                 // sync occupancy with dispenser
+    _Parking_Occupied           = 0x02,                 // occupancy start
+    _Parking_RequestFee         = 0x03,                 // user request occupancy fee
+    _Parking_WaitToPay          = 0x04,                 // wait for user to pay the fee
+    _Parking_PaidOnlineOK       = 0x05,                 // user to paid success via online method
+    _Parking_PaidOnlineFail     = 0x06,                 // user to paid fail via online method
+}OccupancyStatus;
+
+#define STR_NO_OCCUPANCY            "NoOccupancy"
+#define STR_SYNC_OCCUPANCY          "SyncOccupancy"
+#define STR_OCCUPIED                "Occupied"
+#define STR_REQUEST_FEE             "RequestFee"
+#define STR_WAIT_TO_PAY             "WaitToPay"
+#define STR_PAID_ONLINE_OK          "PaidOK"
+#define STR_PAID_ONLINE_FAIL        "PaidFail"
+
+typedef struct
+{
+    unsigned char MiscStatus;                           // 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;
+}MiscRequestStatus;
+
+typedef struct
+{
+    char StartTime[32];
+    unsigned int Duration;
+    float Fee;
+    char Sn[37];
+    char res;
+}OccupancyBillInfo;
+
+typedef struct
+{
+    float Fee;
+    char Sn[37];
+    char res;
+
+    char creditNo[21];
+    char ApprovalNumber[10];                // ApprovalNumber
+    char VemData[65];                       // Vem Data
+}OccupancyDeductInfo;
+
+typedef union
+{
+    unsigned int CtrlValue;
+    struct
+    {
+        unsigned int DeductReq:1;                       // 0: no request,               1: deduct request
+        unsigned int KeepCounting:1;                    // 0: no effect,                1: occupancy keep counting
+        unsigned int SelfReq:1;                         // 0: no request,               1: self request
+        unsigned int res:29;
+    }bits;
+}OccupancyReqFlag;
+
+typedef struct
+{
+    unsigned char Status;                               // 0: NoOccupancy, 1: Occupied, 2: RequestFee, 3: WaitToPay
+    unsigned char PreStatus;                            // 0: NoOccupancy, 1: Occupied, 2: RequestFee, 3: WaitToPay
+    MiscRequestStatus ButtonReqStatus;
+    MiscRequestStatus BillReqStatus;
+    unsigned char ActionId;
+    unsigned char res;
+    OccupancyReqFlag OccupancyReq;                      // 0: no request, 1: deduct request
+    OccupancyBillInfo OccupancyBill;
+    OccupancyDeductInfo OccupancyDeduct;
+}OccupancyInfoData;
+
 typedef struct
 {
     ChargingBillInfoData DispBill[MAX_DISPENSER_QUANTITY];
     ChargingBillInfoData GunBill[MAX_GUN_QUANTITY];
+    OccupancyInfoData OccupancyInfo[MAX_GUN_QUANTITY];
 }AllBillInfoData;
 // ************************************************************************************************* //
 
@@ -1411,7 +1581,7 @@ typedef struct
     PriceReceiptInfoData PriceAndReceiptInfo;
     MeterValueInfoData MeterValue[MAX_GUN_QUANTITY];
     TimestampInfoData Timestamp[MAX_GUN_QUANTITY];
-    OutputError ConnectorError[MAX_GUN_QUANTITY];
+    GunError GunError[MAX_GUN_QUANTITY];
     OutputLimitation OutputLimit;
     AllBillInfoData AllBill;
 }ChargerInfoData;

+ 196 - 34
EVSE/Projects/DO360/Apps/InfyGroup_PsuCommObj.c

@@ -49,64 +49,134 @@ float IEEE_754_to_float(const byte raw[4])
 //================================================
 // Callback function
 //================================================
-void RefreshStatus(void *func)
+void RefreshPsuIndex(int (*func)(byte group, byte address))
 {
-	return_status = func;
+    return_psuIndex = func;
+}
+
+void RefreshGroup(void *func)
+{
+    return_group = func;
+}
+
+void RefreshInfyPwrAlarmFlag(void *func)
+{
+    return_infy_pwr_alarm_flag = func;
+}
+
+void RefreshPhPwrAlarmFlag(void *func)
+{
+    return_ph_pwr_alarm_flag = func;
+}
+
+void RefreshAlarmStatus(void *func)
+{
+    return_alarm_status = func;
+}
+
+void RefreshAmbient(void *func)
+{
+    return_ambient = func;
 }
 
 void RefreshModuleCount(void *func)
 {
-	return_module_count = func;
+    return_module_count = func;
+}
+
+void RefreshSysModuleCount(void *func)
+{
+    return_sys_module_count = func;
 }
 
 void RefreshAvailableCap(void *func)
 {
-	return_available_cap = func;
+    return_available_cap = func;
 }
 
-void RefreshFwVersion(void *func)
+void RefreshFwDcVersion(void *func)
 {
-	return_fw_version = func;
+    return_fw_dc_version = func;
+}
+
+void RefreshFwPfcVersion(void *func)
+{
+    return_fw_pfc_version = func;
 }
 
 void RefreshInputVol(void *func)
 {
-	return_input_vol = func;
+    return_input_vol = func;
+}
+
+void RefreshInputCur(void *func)
+{
+    return_input_cur = func;
 }
 
 void RefreshGetOutput(void *func)
 {
-	return_get_output = func;
+    return_get_output = func;
 }
 
 void RefreshGetOutputF(void *func)
 {
-	return_get_output_float = func;
+    return_get_output_float = func;
 }
 
-void RefreshMisInfo(void *func)
+void RefreshGetModuleOutput(void *func)
 {
-	return_mis_info = func;
+    return_module_output = func;
+}
+
+void RefreshGetErrorRecord(void *func)
+{
+    return_error_record = func;
+}
+
+void RefreshFanSpeedInfo(void *func)
+{
+    return_fan_speed = func;
+}
+
+void RefreshInletTemp(void *func)
+{
+    return_inlet_temp = func;
+}
+
+void RefreshExletTemp(void *func)
+{
+    return_exlet_temp = func;
+}
+
+void RefreshOutletTemp(void *func)
+{
+    return_outlet_temp = func;
+}
+
+void RefreshOtherTemp(void *func)
+{
+    return_other_temp = func;
 }
 
 void RefreshIavailable(void *func)
 {
-	return_iavail_info = func;
+    return_iavail_info = func;
 }
 
 void AutoMode_RefreshOutputAndTemp(void *func)
 {
-	return_output_temp = func;
+    return_output_temp = func;
 }
 
 void AutoMode_RefreshModuleStatus(void *func)
 {
-	return_module_status = func;
+    return_module_status = func;
 }
 
 void AutoMode_RefreshModuleInput(void *func)
 {
-	return_module_input = func;
+    return_module_input = func;
 }
 
 //================================================
@@ -203,7 +273,14 @@ void ReceiveDataFromCanBus()
                         byte count = 0;
                         count = frame.data[2];
 
-                        return_module_count(address, count);
+                        if(address != SYSTEM_CMD)
+                        {
+                            return_module_count(address, count, false);
+                        }
+                        else
+                        {
+                            return_sys_module_count(address, count);
+                        }
                     }
                         break;
 
@@ -213,10 +290,14 @@ void ReceiveDataFromCanBus()
                         // 回傳模組組號及狀態
                         byte SN = address;
                         group = frame.data[2];
-                        char temp = frame.data[4];
-                        unsigned int status = (frame.data[5] << 16) | (frame.data[6] << 8) | frame.data[7];
-
-                        return_status(group, SN, temp, status);
+                        int temp = (signed char)frame.data[4] + 60;
+                        byte state_2 = frame.data[5];
+                        byte state_1 = frame.data[6];
+                        byte state_0 = frame.data[7];
+
+                        return_group(group, SN, SN);
+                        return_infy_pwr_alarm_flag(SN, state_2, state_1, state_0);
+                        return_ambient(SN, temp);
                     }
                         break;
 
@@ -237,9 +318,19 @@ void ReceiveDataFromCanBus()
                     {
                         short dcSwVer = ((frame.data[0] << 8) + frame.data[1]);
                         short pfcSwVer = ((frame.data[2] << 8) + frame.data[3]);
-                        short hwVer = ((frame.data[4] << 8) + frame.data[5]);
+                        //short hwVer = ((frame.data[4] << 8) + frame.data[5]);
+
+                        char dcVersion[32];
+                        char pfcVersion[32];
 
-                        return_fw_version(address, dcSwVer, pfcSwVer, hwVer);
+                        memset(dcVersion, 0x00, sizeof(dcVersion));
+                        memset(pfcVersion, 0x00, sizeof(pfcVersion));
+
+                        sprintf(dcVersion, "DC %d.%02d", (dcSwVer & 0xFF00) >> 8, dcSwVer & 0xFF);
+                        sprintf(pfcVersion, "PFC %d.%02d", (pfcSwVer & 0xFF00) >> 8, pfcSwVer & 0xFF);
+
+                        return_fw_dc_version(address, dcVersion);
+                        return_fw_pfc_version(address, pfcVersion);
                     }
                         break;
 
@@ -294,7 +385,7 @@ void ReceiveDataFromCanBus()
                     // 0x0E
                     case PSU_RCmd_ModuleMiscInfo:
                     {
-                        byte value[4], type = 0;
+                        byte value[4];
                         unsigned short MiscType = (frame.data[0] << 8) | frame.data[1];
                         float MiscInfoValue = 0;
                         memcpy(value, frame.data + 4, sizeof(value));
@@ -302,18 +393,19 @@ void ReceiveDataFromCanBus()
 
                         if(MiscType == FAN_SPEED_CMD)
                         {
-                            type = 1;
+                            return_fan_speed(address, (unsigned int)MiscInfoValue);
                         }
                         if(MiscType == TEMP_DC_CMD)
                         {
-                            type = 2;
+                            MiscInfoValue += 60;
+                            return_exlet_temp(address, (char)MiscInfoValue);
+                            return_outlet_temp(address, (char)MiscInfoValue);
                         }
                         if(MiscType == TEMP_PFC_CMD)
                         {
-                            type = 3;
+                            MiscInfoValue += 60;
+                            return_inlet_temp(address, (char)MiscInfoValue);
                         }
-
-                        return_mis_info(address, MiscInfoValue, type);
                     }
                         break;
 
@@ -337,6 +429,10 @@ void ReceiveDataFromCanBus()
                         char temp = frame.data[6];
 
                         return_output_temp(address, outputVol, outputCur, outputPow, temp);
+
+                        float vol = ((float)outputVol) * 0.1;
+                        float cur = ((float)outputCur) * 0.1;
+                        return_module_output(address, vol, cur);
                     }
                         break;
 
@@ -388,10 +484,10 @@ void SendCmdToPsu(int cmd, byte *data, byte dataLen)
 
     write(CanFd, &frame, sizeof(struct can_frame));
     // 群命令才 delay
-    if (PwrFrameMsg.InfyBits.DestinationAddress == INFY_ADD_BROADCAST)
-    {
+    //if (PwrFrameMsg.InfyBits.DestinationAddress == INFY_ADD_BROADCAST)
+    //{
         usleep(CMD_DELAY_TIME);
-    }
+    //}
 }
 
 void SetPowerOnOff(byte address, byte device, byte value)
@@ -532,6 +628,26 @@ void SinglePsuPower(byte address, byte value)
     SetPowerOnOff(address, DEVICE_NO_SINGLE_MODULE, value);
 }
 
+void SwitchPower_On(byte group)
+{
+    SwitchPower(group, PSU_POWER_ON);
+}
+
+void SwitchPower_Off(byte group)
+{
+    SwitchPower(group, PSU_POWER_OFF);
+}
+
+void SinglePsuPower_On(byte address)
+{
+    SetPowerOnOff(address, DEVICE_NO_SINGLE_MODULE, PSU_POWER_ON);
+}
+
+void SinglePsuPower_Off(byte address)
+{
+    SetPowerOnOff(address, DEVICE_NO_SINGLE_MODULE, PSU_POWER_OFF);
+}
+
 void SleepMode(byte group, byte value)
 {
 	byte data[8];
@@ -575,6 +691,26 @@ void SingleFlashLed(byte address, byte value)
     SetLed(address, DEVICE_NO_SINGLE_MODULE, value);
 }
 
+void FlashLed_Static(byte group)
+{
+    FlashLed(group, PSU_FLASH_NORMAL);
+}
+
+void FlashLed_Blinking(byte group)
+{
+    FlashLed(group, PSU_FLASH_ON);
+}
+
+void SingleFlashLed_Static(byte address)
+{
+    SingleFlashLed(address, PSU_FLASH_NORMAL);
+}
+
+void SingleFlashLed_Blinking(byte address)
+{
+    SingleFlashLed(address, PSU_FLASH_ON);
+}
+
 void PresentOutputVol(byte group, int voltage, int current)
 {
     if(group == INFY_ADD_BROADCAST)
@@ -670,6 +806,12 @@ void SetDipSwitchMode()
 
     SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
 }
+
+void UnlockPsuAlarm(byte full_address)
+{
+    // no function
+}
+
 /**********************************************************************************/
 /***                                                                            ***/
 /***                                   Get                                      ***/
@@ -799,7 +941,12 @@ void GetModuleCount(byte group)
 	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
 }
 
-void GetModuleVer(byte group)
+void GetSysModuleCount(void)
+{
+    GetModuleCount(SYSTEM_CMD);
+}
+
+void GetModuleVer(byte group, byte type)
 {
 	// 無系統廣播功能
 	byte data[8];
@@ -823,6 +970,11 @@ void GetModuleVer(byte group)
 	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
 }
 
+void GetAllModuleVer(byte group)
+{
+    GetModuleVer(group, 0);
+}
+
 void GetModuleCap(byte group)
 {
 	byte data[8];
@@ -870,7 +1022,7 @@ void GetModuleBarCode(byte group)
 	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
 }
 
-void GetModuleInput(byte group)
+void GetModuleInputVol(byte group)
 {
 	// 無系統廣播功能
 	byte data[8];
@@ -894,7 +1046,12 @@ void GetModuleInput(byte group)
 	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
 }
 
-void GetModuleIavailable(byte group)
+void GetModuleInputCur(byte group)
+{
+
+}
+
+void GetModuleIavailable(byte group, unsigned short voltage)
 {
 	byte data[8];
     PwrFrame PwrFrameMsg;
@@ -963,6 +1120,11 @@ void GetModuleOutputF(byte group)
 	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
 }
 
+void GetErrorRecord(byte group)
+{
+    // no function
+}
+
 /**********************************************************************************/
 /***                                                                            ***/
 /***                                 Upgrate                                    ***/

+ 80 - 34
EVSE/Projects/DO360/Apps/InfyGroup_PsuCommObj.h

@@ -19,25 +19,26 @@
 #include <sys/ioctl.h>
 #include <linux/wireless.h>
 #include <linux/can.h>
+#include <linux/can/raw.h>
 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <sys/time.h>
 
-#include 	<stdbool.h>
-#include 	<unistd.h>
-#include 	<stdarg.h>
-#include    <stdio.h>      /*標準輸入輸出定義*/
-#include    <stdlib.h>     /*標準函數庫定義*/
-#include    <unistd.h>     /*Unix 標準函數定義*/
-#include    <fcntl.h>      /*檔控制定義*/
-#include    <termios.h>    /*PPSIX 終端控制定義*/
-#include    <errno.h>      /*錯誤號定義*/
-#include 	<errno.h>
-#include 	<string.h>
-#include	<time.h>
-#include	<ctype.h>
-#include 	<ifaddrs.h>
-#include 	<math.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>      /*標準輸入輸出定義*/
+#include <stdlib.h>     /*標準函數庫定義*/
+#include <unistd.h>     /*Unix 標準函數定義*/
+#include <fcntl.h>      /*檔控制定義*/
+#include <termios.h>    /*PPSIX 終端控制定義*/
+#include <errno.h>      /*錯誤號定義*/
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <ifaddrs.h>
+#include <math.h>
 
 #define SYSTEM_CMD                  0x3F
 #define DEVICE_NO_SINGLE_MODULE     0x0A
@@ -46,8 +47,8 @@
 #define INFY_ADD_CSU                0xF0
 #define NEXTON_ADD                  0xFF
 
-#define ARRAY_SIZE(A)		(sizeof(A) / sizeof(A[0]))
-#define CMD_DELAY_TIME 		25000
+#define ARRAY_SIZE(A)       (sizeof(A) / sizeof(A[0]))
+#define CMD_DELAY_TIME      25000
 #define FAN_SPEED_CMD		0x1201
 #define TEMP_DC_CMD			0x1107
 #define TEMP_PFC_CMD		0x1108
@@ -56,8 +57,8 @@ typedef unsigned char       byte;
 typedef unsigned short      word;
 typedef unsigned int        unit;
 
-int 						CanFd;
-pid_t 						recFork;
+int                         CanFd;
+pid_t                       recFork;
 
 typedef union
 {
@@ -166,19 +167,28 @@ typedef enum
 }SetMiscInfoCommand;
 
 /*Initialization*/
-pid_t InitialCommunication();
+pid_t InitialCommunication(void);
 
 /*Set Cmd*/
 void SwitchPower(byte group, byte value);
 void SinglePsuPower(byte address, byte value);
+void SwitchPower_On(byte group);
+void SwitchPower_Off(byte group);
+void SinglePsuPower_On(byte address);
+void SinglePsuPower_Off(byte address);
 void SleepMode(byte group, byte value);
 void FlashLed(byte group, byte value);
 void SingleFlashLed(byte address, byte value);
+void FlashLed_Static(byte group);
+void FlashLed_Blinking(byte group);
+void SingleFlashLed_Static(byte address);
+void SingleFlashLed_Blinking(byte address);
 void PresentOutputVol(byte group, int voltage, int current);
 void SingleOutputVol(byte address, int voltage, int current);
 void FanNoiseInfo(byte group, byte value);
 void SetWalkInConfig(byte group, byte enable, byte sec);
 void SetDipSwitchMode();
+void UnlockPsuAlarm(byte full_address);
 
 /*Ver : 9.06 used*/
 void SetDirModulePresentOutput(byte group, int voltage, int current, byte _switch, byte _interRelay);
@@ -187,43 +197,79 @@ void GetStatus(byte group);
 void GetFanSpeed(byte group);
 void GetDcTemperature(byte group);
 void GetPfcTemperature(byte group);
-void GetFanSpeed(byte group);
+
 void GetModuleCount(byte group);
-void GetModuleVer(byte group);
+void GetSysModuleCount(void);
+void GetModuleVer(byte group, byte type);
+void GetAllModuleVer(byte group);
 void GetModuleCap(byte group);
 void GetModuleBarCode(byte group);
-void GetModuleInput(byte group);
-void GetModuleIavailable(byte group);
+void GetModuleInputVol(byte group);
+void GetModuleInputCur(byte group);
+void GetModuleIavailable(byte group, unsigned short voltage);
 void GetModuleOutput(byte group);
 void GetModuleOutputF(byte group);
+void GetErrorRecord(byte group);
 
 /*Upgrade*/
 void ChangePsuBaudrate(short baudrate);
 
 /* Callback Function */
-void RefreshStatus(void *func);
-void (*return_status)(byte group, byte address, byte temp, int status);
+void RefreshPsuIndex(int (*func)(byte group, byte gIndex));
+int (*return_psuIndex)(byte group, byte gIndex);
+
+void RefreshGroup(void *func);
+void (*return_group)(byte group, byte psu_index, unsigned short full_address);
+void RefreshInfyPwrAlarmFlag(void *func);
+void (*return_infy_pwr_alarm_flag)(byte address, byte state_2, byte state_1, byte state_0);
+void RefreshPhPwrAlarmFlag(void *func);
+void (*return_ph_pwr_alarm_flag)(byte address, unsigned int status, unsigned int alarm_1, unsigned int alarm_0);
+void RefreshAlarmStatus(void *func);
+void (*return_alarm_status)(byte address, unsigned int status);
+void RefreshAmbient(void *func);
+void (*return_ambient)(byte address, char temp);
 
 void RefreshModuleCount(void *func);
-void (*return_module_count)(byte group, byte count);
+void (*return_module_count)(byte group, byte count, bool summation);
+void RefreshSysModuleCount(void *func);
+void (*return_sys_module_count)(byte group, byte count);
 
 void RefreshAvailableCap(void *func);
 void (*return_available_cap)(byte address, short maxVol, short minVol, short maxCur, short totalPow);
 
-void RefreshFwVersion(void *func);
-void (*return_fw_version)(byte address, short dcSwVer, short pfcSwVer, short hwVer);
+void RefreshFwDcVersion(void *func);
+void (*return_fw_dc_version)(byte address, char *dcSwVer);
+void RefreshFwPfcVersion(void *func);
+void (*return_fw_pfc_version)(byte address, char *pfcSwVer);
 
 void RefreshInputVol(void *func);
 void (*return_input_vol)(byte address, unsigned short vol1, unsigned short vol2, unsigned short vol3);
 
+void RefreshInputCur(void *func);
+void (*return_input_cur)(byte address, unsigned short cur1, unsigned short cur2, unsigned short cur3);
+
 void RefreshGetOutput(void *func);
 void (*return_get_output)(byte address, unsigned short outVol, unsigned short outCur);
 
 void RefreshGetOutputF(void *func);
 void (*return_get_output_float)(byte group, float outVol, float outCur);
 
-void RefreshMisInfo(void *func);
-void (*return_mis_info)(byte address, unsigned int fanSpeed, byte type);
+void RefreshGetModuleOutput(void *func);
+void (*return_module_output)(byte address, float outVol, float outCur);
+
+void RefreshGetErrorRecord(void *func);
+void (*return_error_record)(byte address, byte count_down, byte *error_record);
+
+void RefreshFanSpeedInfo(void *func);
+void (*return_fan_speed)(byte address, unsigned int fanSpeed);
+void RefreshInletTemp(void *func);
+void (*return_inlet_temp)(byte address, char temp);
+void RefreshExletTemp(void *func);
+void (*return_exlet_temp)(byte address, char temp);
+void RefreshOutletTemp(void *func);
+void (*return_outlet_temp)(byte address, char temp);
+void RefreshOtherTemp(void *func);
+void (*return_other_temp)(byte address, char temp1, char temp2, char temp3, char temp4);
 
 void RefreshIavailable(void *func);
 void (*return_iavail_info)(byte address, unsigned short Iavail, unsigned short Vext);
@@ -231,14 +277,14 @@ void (*return_iavail_info)(byte address, unsigned short Iavail, unsigned short V
 /*Test mode used*/
 void AutoMode_RefreshOutputAndTemp(void *func);
 void (*return_output_temp)(byte address, unsigned short outputVol,
-		unsigned short outputCur, unsigned short outputPower, unsigned char Temperature);
+        unsigned short outputCur, unsigned short outputPower, unsigned char Temperature);
 
 void AutoMode_RefreshModuleStatus(void *func);
 void (*return_module_status)(byte address, unsigned char isErr, unsigned char status,
-		unsigned char err1, unsigned char err2, unsigned char err3, unsigned char err4);
+        unsigned char err1, unsigned char err2, unsigned char err3, unsigned char err4);
 
 void AutoMode_RefreshModuleInput(void *func);
 void (*return_module_input)(byte address, unsigned short inputR,
-		unsigned short inputS, unsigned short inputT);
+        unsigned short inputS, unsigned short inputT);
 /* Callback Function end */
 #endif /* INFYPWR_PSUCOMMOBJ_H_ */

+ 13 - 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 FactoryConfigApp OtherTools
+apps: Common MainTask CabinetParallel SelfTestTask AuthorizeTask LedIndication EvCommTask EventLoggingTask InternalCommTask LcmControlTask PrimaryCommTask InfyGroup_PsuCommObj PhGroup_PsuCommObj PsuCommTask PhPsuCommTask ReadCmdlineTask FactoryConfigApp OtherTools
 
 Common:
 	rm -f Common.o
@@ -89,11 +89,23 @@ InfyGroup_PsuCommObj:
 	$(AR) -r libInfyGroup_PsuCommObj.a InfyGroup_PsuCommObj.o
 	rm -f InfyGroup_PsuCommObj.o
 
+PhGroup_PsuCommObj:
+	rm -f libPhGroup_PsuCommObj.a
+	$(CC) -D $(Project) -O0 -g3 -Wall -c -fmessage-length=0 -o PhGroup_PsuCommObj.o PhGroup_PsuCommObj.c
+	$(AR) -r libPhGroup_PsuCommObj.a PhGroup_PsuCommObj.o
+	rm -f PhGroup_PsuCommObj.o
+
 PsuCommTask:
 	rm -f Module_PsuComm; 
 	$(CC) -D $(Project) -includeInfyGroup_PsuCommObj.h -includeConfig.h -O0 -g3 -Wall -c -fmessage-length=0 -o Module_PsuComm.o Module_PsuComm.c
 	$(CC) -o Module_PsuComm Module_PsuComm.o libInfyGroup_PsuCommObj.a Common.o -lrt
 	cp -f Module_PsuComm ../Images/root	
+
+PhPsuCommTask:
+	rm -f Module_PsuComm_PH; 
+	$(CC) -D $(Project) -includePhGroup_PsuCommObj.h -includeConfig.h -O0 -g3 -Wall -c -fmessage-length=0 -o Module_PsuComm_PH.o Module_PsuComm.c
+	$(CC) -o Module_PsuComm_PH Module_PsuComm_PH.o libPhGroup_PsuCommObj.a Common.o -lrt
+	cp -f Module_PsuComm_PH ../Images/root	
 	
 ReadCmdlineTask:
 	rm -f ReadCmdline; 

+ 313 - 30
EVSE/Projects/DO360/Apps/Module_EvComm.c

@@ -54,6 +54,7 @@ PaymentFailResponse ConnectorPaymentFailReason[GENERAL_GUN_QUANTITY];
 char _ConnectorQRCode[GENERAL_GUN_QUANTITY][128];
 StationInfoData _stationInfo[GENERAL_GUN_QUANTITY];
 DeductResultInfoData _deductResult[GENERAL_GUN_QUANTITY];
+OccupancyResponse _OccupancyResponse[GENERAL_GUN_QUANTITY];
 unsigned char _GunSystemStatus[GENERAL_GUN_QUANTITY];
 
 void ShowSocketData(struct PACKET_STRUCTURE *packet)
@@ -1136,7 +1137,7 @@ void ChargingCapabilityResponse(int socket, struct PACKET_STRUCTURE *packet)
         ConnectorCapability[packet->Header.id - 1].CostDiscount != lDiscount)
     {
         LOG_INFO("Gun %d TxId: %d Account: %8.2f, Remain: %8.2f, Discount: %.2f [%s]",
-            packet->Header.id, transaction, fBalance, fDiscount, fRemainAmount, ConnectorCapability[packet->Header.id - 1].CurrencyString);
+            packet->Header.id, transaction, fBalance, fRemainAmount, fDiscount, ConnectorCapability[packet->Header.id - 1].CurrencyString);
     }
 
 	ConnectorCapability[packet->Header.id - 1].MaxOuputVoltage = voltage;
@@ -1389,6 +1390,7 @@ bool Is_DispenserForceChargingTriggerWebApi(int gun_index)
 // 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 >> Connector %d ParkingReq   [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);
@@ -1413,11 +1415,16 @@ bool Is_DispenserForceChargingTriggerWebApi(int gun_index)
 // LOG_INFO("Cabinet >> Dispenser %d Time Offset  [+%d]", dispenserIndex + 1, misc.Value);
 // LOG_INFO("Cabinet >> Dispenser %d Time Offset  [%d]", dispenserIndex + 1, misc.Value);
 // LOG_INFO("Cabinet >> Dispenser %d DefaultPrice [Trigger]", dispenserIndex + 1);
+// LOG_INFO("Cabinet >> Dispenser %d ParkingPrice [%d.%02d]", dispenserIndex + 1, (misc.Value / 100), (misc.Value % 100));
+// LOG_INFO("Cabinet >> Dispenser %d RFID Endian  [%s]", dispenserIndex + 1, strRfidEndian[misc.Value]);
+// LOG_INFO("Cabinet >> Dispenser %d RFID Endian  [%d]", dispenserIndex + 1, (misc.Value));
+// LOG_INFO("Cabinet >> Dispenser %d RFID Reader  [%s]", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
 void MiscCmdRes(int socket, struct PACKET_STRUCTURE *packet, unsigned char dispenserIndex, unsigned char result)
 {
     char *strConnection[] = {STR_CONN_DISABLE, STR_CONN_CONNECTED, STR_CONN_DISCONNECTED};
     char *strIntensity[] = {STR_DARKEST, STR_MEDIUM, STR_BRIGHTEST};
     char *strLcmPage[] = {STR_PAGE_NONE, STR_REMOTE_NO_ID};
+    char *strRfidEndian[] = {STR_LITTLE_ENDIAN, STR_BIG_ENDIAN};
     struct PACKET_STRUCTURE sendBuffer;
 
     memset(&sendBuffer, 0x00, sizeof(sendBuffer));
@@ -1584,6 +1591,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_PARKING_STATUS))
+        {
+            Clean_Connector_MiscCommand(packet->Header.id - 1, MISC_CONN_PARKING_STATUS);
+            misc.Command = _MiscCmd_ParkingRequest;
+            misc.Value = true;
+
+            if(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].ButtonReqStatus.MiscStatus == _BillStatus_WaitMiscClean)
+            {
+                ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].ButtonReqStatus.MiscStatus = _BillStatus_MiscClean;
+            }
+            LOG_INFO("Cabinet >> Connector %d ParkingReq   [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)
         {
@@ -1803,6 +1824,43 @@ void MiscCmdRes(int socket, struct PACKET_STRUCTURE *packet, unsigned char dispe
                 LOG_INFO("Cabinet >> Dispenser %d DefaultPrice [Trigger]", dispenserIndex + 1);
                 AddMiscCommand(&sendBuffer, &misc);
             }
+
+            if(Is_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_PARKING_PRICE))
+            {
+                Clean_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_PARKING_PRICE);
+                misc.Command = _MiscCmd_ParkingPrice;
+                misc.Value = (unsigned int)(ShmChargerInfo->CabinetMiscValue.ParkingPrice * 100);
+
+                LOG_INFO("Cabinet >> Dispenser %d ParkingPrice [%d.%02d]", dispenserIndex + 1, (misc.Value / 100), (misc.Value % 100));
+                AddMiscCommand(&sendBuffer, &misc);
+            }
+
+            if(Is_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_RFID_CARD_ENDIAN))
+            {
+                Clean_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_RFID_CARD_ENDIAN);
+                misc.Command = _MiscCmd_RFIDCardEndian;
+                misc.Value = ShmSysConfigAndInfo->SysConfig.RfidCardNumEndian;
+
+                if(misc.Value <= RFID_ENDIAN_BIG)
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d RFID Endian  [%s]", dispenserIndex + 1, strRfidEndian[misc.Value]);
+                }
+                else
+                {
+                    LOG_INFO("Cabinet >> Dispenser %d RFID Endian  [%d]", dispenserIndex + 1, (misc.Value));
+                }
+                AddMiscCommand(&sendBuffer, &misc);
+            }
+
+            if(Is_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_RFID_ENABLE))
+            {
+                Clean_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_RFID_ENABLE);
+                misc.Command = _MiscCmd_RFIDEnable;
+                misc.Value = ShmSysConfigAndInfo->SysConfig.isRFID;
+
+                LOG_INFO("Cabinet >> Dispenser %d RFID Reader  [%s]", dispenserIndex + 1, misc.Value ? "Enable" : "Disable");
+                AddMiscCommand(&sendBuffer, &misc);
+            }
         }
 
         if(Is_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_CHANGE_LCM_INFO))
@@ -2561,6 +2619,112 @@ void ChargingBillResponse(int socket, struct PACKET_STRUCTURE *packet, unsigned
     SendPacket(socket, &sendBuffer);
 }
 
+void ParkingStatusResponse(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 = 39;
+    sendBuffer.Payload.reg = _Reg_ParkingStatus;
+    sendBuffer.Payload.data[0] = result;
+
+    char *str_occupancy_status[] = {STR_NO_OCCUPANCY, STR_SYNC_OCCUPANCY, STR_OCCUPIED, STR_REQUEST_FEE, STR_WAIT_TO_PAY, STR_PAID_ONLINE_OK, STR_PAID_ONLINE_FAIL};
+
+    if(result == _R_OK)
+    {
+        // Parking Status
+        sendBuffer.Payload.data[1] = ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status;
+
+        // Occupancy SN
+        memcpy(&sendBuffer.Payload.data[2], &ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Sn[0], sizeof(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Sn) - 1);
+
+        if(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].ButtonReqStatus.MiscStatus == _BillStatus_MiscClean)
+        {
+            ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].ButtonReqStatus.MiscStatus = _BillStatus_UpdateDone;
+        }
+
+        if(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status != _OccupancyResponse[packet->Header.id - 1].ParkingStatus ||
+            strcmp(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Sn, _OccupancyResponse[packet->Header.id - 1].OccupancySn) != EQUAL)
+        {
+            if(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status == _Parking_NoOccupancy)
+            {
+                LOG_INFO("Gun %d ParkingStatus: [%s]",
+                    packet->Header.id,
+                    str_occupancy_status[ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status]);
+            }
+            else
+            {
+                LOG_INFO("Gun %d ParkingStatus: [%s], SN: [%s]",
+                    packet->Header.id,
+                    str_occupancy_status[ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status],
+                    ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Sn);
+            }
+            memcpy(_OccupancyResponse[packet->Header.id - 1].OccupancySn, ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Sn, sizeof(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Sn));
+            _OccupancyResponse[packet->Header.id - 1].ParkingStatus = ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status;
+        }
+
+        if(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status == _Parking_PaidOnlineOK)
+        {
+            ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status = _Parking_NoOccupancy;
+        }
+        else if(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status == _Parking_PaidOnlineFail)
+        {
+            ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status = _Parking_Occupied;
+        }
+    }
+
+    SendPacket(socket, &sendBuffer);
+}
+
+void ParkingBillResponse(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 = 10 + 1;
+    sendBuffer.Payload.reg = _Reg_ParkingBill;
+    sendBuffer.Payload.data[0] = result;
+
+    int timeLen = 0;
+    unsigned int lFee = 0;
+
+    if(result == _R_OK)
+    {
+        // Parking fee
+        lFee = (int)(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Fee * 100);
+        sendBuffer.Payload.data[1] = ((lFee >> 24) & 0xFF);
+        sendBuffer.Payload.data[2] = ((lFee >> 16) & 0xFF);
+        sendBuffer.Payload.data[3] = ((lFee >> 8) & 0xFF);
+        sendBuffer.Payload.data[4] = (lFee & 0xFF);
+
+        // Parking duration
+        sendBuffer.Payload.data[5] = ((ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Duration >> 24) & 0xFF);
+        sendBuffer.Payload.data[6] = ((ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Duration >> 16) & 0xFF);
+        sendBuffer.Payload.data[7] = ((ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Duration >> 8) & 0xFF);
+        sendBuffer.Payload.data[8] = (ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Duration & 0xFF);
+
+        // Parking startTime
+        timeLen = strlen(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.StartTime);
+        memcpy(&sendBuffer.Payload.data[9], ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.StartTime, timeLen);
+        sendBuffer.Payload.data[9 + timeLen] = 0;
+        sendBuffer.Header.len += timeLen;
+
+        LOG_INFO("Gun %d ParkingFee: [%d.%02d], StartTime: [%s], Duration: [%d]",
+            packet->Header.id,
+            (lFee / 100), (lFee % 100),
+            ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.StartTime,
+            ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].OccupancyBill.Duration);
+    }
+
+    SendPacket(socket, &sendBuffer);
+}
+
 BOOL FindConnectorID(unsigned char dispenserIndex, unsigned char id)
 {
 	BOOL find = false;
@@ -2596,15 +2760,15 @@ void ConnectorPhysicalLimitBindingHandler(unsigned char connectorIndex, unsigned
             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;
+            //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':
@@ -2637,14 +2801,14 @@ void ConnectorPhysicalLimitBindingHandler(unsigned char connectorIndex, unsigned
         case 'V':
         case 'F':
         //case 'R': // 20210817 remove type "R"
-            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
-            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_LIQUID_V_F_MAX_CURRENT;
+            //ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
+            //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;
+            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':
@@ -2656,14 +2820,28 @@ void ConnectorPhysicalLimitBindingHandler(unsigned char connectorIndex, unsigned
         case 'D':
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
             ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_NATURAL_T_D_MAX_CURRENT;
+            break;
+
+        case 'I':
+        case 'Q':
             // 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;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CCS_MAX_PHYSICAL_VOLTAGE;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CCS_NATURAL_I_Q_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_I_Q_BOOST_CURRENT;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[1] = CCS_NATURAL_I_Q_MAX_CURRENT;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[2] = CCS_NATURAL_I_Q_85_DERATING_CUR;
+            break;
+
+        case 'O':
+            // Boost Mode
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalVoltage = CHA_MAX_PHYSICAL_VOLTAGE;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].RemoteMaxPhysicalCurrent = CHA_NATURAL_O_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_O_BOOST_CURRENT;
+            ShmSysConfigAndInfo->SysInfo.ConnectorInfo[connectorIndex].GeneralChargingData.deratingByConnOtp.deratingTargetCurrent[1] = CHA_NATURAL_O_MAX_CURRENT;
             break;
 
         default:
@@ -3385,6 +3563,7 @@ unsigned char ChargingPermissionHandler(struct PACKET_STRUCTURE *packet, unsigne
                 break;
 
             case S_PREPARING_FOR_EV:
+#if 0
                 if(chargingInfo[packet->Header.id - 1]->ChargingStopFlag.bits.RemoteStop ||
                     chargingInfo[packet->Header.id - 1]->ChargingStopFlag.bits.UnlockStop)
                 {
@@ -3394,7 +3573,8 @@ unsigned char ChargingPermissionHandler(struct PACKET_STRUCTURE *packet, unsigne
                         LOG_INFO("RemoteStop or UnlockStop, not allow dispenser index %d connector id %d preparing to charge", dispenserIndex, packet->Header.id);
                     }
                 }
-                else if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteStatus >= _CRS_Preparing &&
+#endif
+                if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteStatus >= _CRS_Preparing &&
                     ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteStatus <= _CRS_Charging)
                 {
                     if(!ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].Parameter.bits.PermissionRequest)
@@ -3420,6 +3600,7 @@ unsigned char ChargingPermissionHandler(struct PACKET_STRUCTURE *packet, unsigne
                 break;
 
             case S_CHARGING:
+#if 0
                 if(chargingInfo[packet->Header.id - 1]->ChargingStopFlag.bits.RemoteStop ||
                     chargingInfo[packet->Header.id - 1]->ChargingStopFlag.bits.UnlockStop)
                 {
@@ -3429,7 +3610,8 @@ unsigned char ChargingPermissionHandler(struct PACKET_STRUCTURE *packet, unsigne
                         LOG_INFO("RemoteStop or UnlockStop, not allow dispenser index %d connector id %d charging", dispenserIndex, packet->Header.id);
                     }
                 }
-                else if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteStatus == _CRS_Preparing ||
+#endif
+                if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteStatus == _CRS_Preparing ||
                     ShmSysConfigAndInfo->SysInfo.ConnectorInfo[packet->Header.id - 1].RemoteStatus == _CRS_Charging)
                 {
                     permission = _DAS_Allowed;
@@ -3625,9 +3807,11 @@ unsigned char DispenserWriteChargingInfoHandler(struct PACKET_STRUCTURE *packet,
 
         if(diffVoltage > 10 || diffCurrent > 10 || ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteSoc != soc)
         {
+            int _connectorTemp = (int)chargingInfo[gun]->ConnectorTemp - 60;
+            int _chillerTemp = (int)chargingInfo[gun]->ChillerTemp - 60;
+
             LOG_INFO("Connector %d Charging Info: Voltage: %4d.%d V, Current: %3d.%d A, Soc: %3d, Temp: %3d, Chiller: %3d",
-                packet->Header.id, (voltage / 10), (voltage % 10), (current / 10), (current % 10), soc,
-                chargingInfo[gun]->ConnectorTemp - 60, chargingInfo[gun]->ChillerTemp - 60);
+                packet->Header.id, (voltage / 10), (voltage % 10), (current / 10), (current % 10), soc, _connectorTemp, _chillerTemp);
         }
 
         ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun].RemoteChargingVoltage = voltage;
@@ -3817,6 +4001,24 @@ unsigned char DispenserReqHandler(struct PACKET_STRUCTURE *packet, int dispenser
                         }
                         break;
 
+                    case _DisReq_ParkingFee:
+                        if(connector_req.Value == YES)
+                        {
+                            if(ShmChargerInfo->AllBill.OccupancyInfo[gun].Status == _Parking_Occupied)
+                            {
+                                if(!ShmChargerInfo->ConnectorActReq[gun].Flag.bits.ParkingFeeRequest)
+                                {
+                                    LOG_INFO("Gun %d ParkingFee Request", gun + 1);
+                                }
+                                ShmChargerInfo->ConnectorActReq[gun].Flag.bits.ParkingFeeRequest = true;
+                            }
+                            else
+                            {
+                                LOG_INFO("Gun %d ParkingFee Request, but ParkingStatus is not Occupied", gun + 1);
+                            }
+                        }
+                        break;
+
                     default:
                         break;
                 }
@@ -3935,12 +4137,14 @@ unsigned char WriteDeductResultHandler(struct PACKET_STRUCTURE *packet, int disp
     char appNo[10];
     char vemData[65];
     char cardNo[21];
+    char occupancy_sn[37];
 
-    char *str_ReaderStatus[] = {STR_DEDUCT_FAIL, STR_DEDUCT_PASS, STR_DEDUCT_CANCEL, STR_DEDUCT_PREAUTH};
+    char *str_ReaderStatus[] = {STR_DEDUCT_FAIL, STR_DEDUCT_PASS, STR_DEDUCT_CANCEL, STR_DEDUCT_PREAUTH, STR_SALE_FAIL, STR_SALE_PASS};
 
     memset(appNo, 0x00, sizeof(appNo));
     memset(vemData, 0x00, sizeof(vemData));
     memset(cardNo, 0x00, sizeof(cardNo));
+    memset(occupancy_sn, 0x00, sizeof(occupancy_sn));
 
     if(find || packet->Header.id == AUTO_GUN_SELECTION_ID)
     {
@@ -3972,8 +4176,13 @@ unsigned char WriteDeductResultHandler(struct PACKET_STRUCTURE *packet, int disp
             memcpy(deduct.creditNo, (char *)&packet->Payload.data[83], sizeof(deduct.creditNo));
             memcpy(cardNo, deduct.creditNo, sizeof(deduct.creditNo));
         }
+        if(packet->Header.len >= 140)
+        {
+            memcpy(deduct.Sn, (char *)&packet->Payload.data[103], sizeof(deduct.Sn));
+            memcpy(occupancy_sn, deduct.Sn, sizeof(deduct.Sn));
+        }
 
-        if(deduct.DeductResult == _Deduct_Fail || deduct.DeductResult == _Deduct_Pass)
+        if(deduct.DeductResult == _Deduct_PreAuth_Fail || deduct.DeductResult == _Deduct_PreAuth_Pass)
         {
             if(packet->Header.id != AUTO_GUN_SELECTION_ID)
             {
@@ -4021,7 +4230,7 @@ unsigned char WriteDeductResultHandler(struct PACKET_STRUCTURE *packet, int disp
                 return done;
             }
         }
-        else if(deduct.DeductResult == _Deduct_Cancel || deduct.DeductResult == _Deduct_PreAuth)
+        else if(deduct.DeductResult == _Deduct_PreAuth_Cancel || deduct.DeductResult == _Deduct_PreAuth)
         {
             if(packet->Header.id != AUTO_GUN_SELECTION_ID)
             {
@@ -4045,6 +4254,34 @@ unsigned char WriteDeductResultHandler(struct PACKET_STRUCTURE *packet, int disp
                 find = true;
             }
         }
+        else if(deduct.DeductResult == _Deduct_Sale_Pass)
+        {
+            if(packet->Header.id != AUTO_GUN_SELECTION_ID)
+            {
+                if(!ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyReq.bits.DeductReq)
+                {
+                    memset(&ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyDeduct, 0x00, sizeof(OccupancyDeductInfo));
+
+                    ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyReq.bits.DeductReq = true;
+                    ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyDeduct.Fee = ((float)deduct.DeductAmount / 100);
+                    memcpy(&ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyDeduct.Sn[0], &deduct.Sn[0], sizeof(deduct.Sn));
+                    memcpy(&ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyDeduct.creditNo[0], &deduct.creditNo[0], sizeof(deduct.creditNo));
+                    memcpy(&ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyDeduct.ApprovalNumber[0], &deduct.ApprovalNumber[0], sizeof(deduct.ApprovalNumber));
+                    done = true;
+                }
+                LOG_INFO("Gun %d OccupancyDeduct, SN: [%s] [%s] %s",
+                    gun + 1,
+                    occupancy_sn,
+                    str_ReaderStatus[deduct.DeductResult],
+                    done ? "Done" : "Wait");
+                LOG_INFO("Gun %d OccupancyDeduct, Fee: [%d.%02d], Card: [%s], ApprovalNo: [%s]",
+                        gun + 1,
+                        (deduct.DeductAmount / 100), (deduct.DeductAmount % 100),
+                        cardNo,
+                        appNo);
+                return done;
+            }
+        }
         else
         {
             find = true;
@@ -4128,6 +4365,24 @@ unsigned char ReadChargingBillHandler(struct PACKET_STRUCTURE *packet, int dispe
     return find;
 }
 
+unsigned char ReadParkingStatusHandler(struct PACKET_STRUCTURE *packet, int dispenserIndex)
+{
+    BOOL find = FindConnectorID(dispenserIndex, packet->Header.id);
+
+    return find;
+}
+
+unsigned char ReadParkingBillHandler(struct PACKET_STRUCTURE *packet, int dispenserIndex)
+{
+    BOOL find = FindConnectorID(dispenserIndex, packet->Header.id);
+
+    if(ShmChargerInfo->AllBill.OccupancyInfo[packet->Header.id - 1].Status == _Parking_WaitToPay && find)
+    {
+        return true;
+    }
+    return false;
+}
+
 void DisableConnector(unsigned char dispenserIndex)
 {
 	for(int i = 0; i < ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorQuantity; i++)
@@ -4247,6 +4502,7 @@ void DispenserSocketProcess(int socketFd, struct sockaddr_in clientInfo, unsigne
                                 Set_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_AUTH_MODE_CONFIG);
                                 Set_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_EVCCID_CONFIG);
                                 Set_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_TIME_OFFSET);
+                                Set_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_RFID_ENABLE);
 
                                 if(strlen(ShmChargerInfo->StationInfo.StationName) > 0 ||
                                     ShmChargerInfo->StationInfo.StationID != 0 ||
@@ -4261,6 +4517,12 @@ void DispenserSocketProcess(int socketFd, struct sockaddr_in clientInfo, unsigne
                                     Set_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_DEFAULT_PRICE_STRING);
                                 }
 
+                                if(ShmChargerInfo->Control.CustomerCode == _CUSTOMER_CODE_Phihong ||
+                                    ShmChargerInfo->Control.CustomerCode == _CUSTOMER_CODE_Shell)
+                                {
+                                    Set_Dispenser_MiscCommand(dispenserIndex, MISC_DISP_RFID_CARD_ENDIAN);
+                                }
+
                                 for(int i = 0; i < ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorQuantity; i++)
                                 {
                                     unsigned char gun = ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[dispenserIndex].ConnectorID[i] - 1;
@@ -4627,6 +4889,26 @@ void DispenserSocketProcess(int socketFd, struct sockaddr_in clientInfo, unsigne
                         }
                         ChargingBillResponse(socketFd, &receiveBuffer, ackResult);
                     }
+
+                    // Reg: 0x27 ParkingStatus
+                    if(receiveBuffer.Header.op == _Header_Read && receiveBuffer.Payload.reg == _Reg_ParkingStatus)
+                    {
+                        if(ReadParkingStatusHandler(&receiveBuffer, dispenserIndex))
+                        {
+                            ackResult = _R_OK;
+                        }
+                        ParkingStatusResponse(socketFd, &receiveBuffer, ackResult);
+                    }
+
+                    // Reg: 0x28 ParkingBill
+                    if(receiveBuffer.Header.op == _Header_Read && receiveBuffer.Payload.reg == _Reg_ParkingBill)
+                    {
+                        if(ReadParkingBillHandler(&receiveBuffer, dispenserIndex))
+                        {
+                            ackResult = _R_OK;
+                        }
+                        ParkingBillResponse(socketFd, &receiveBuffer, ackResult);
+                    }
 				}
 
 				// clean timeout
@@ -4970,6 +5252,7 @@ void InitialConnector(void)
         memset(&_ConnectorQRCode[i][0], 0x00, 128);
         memset(&_stationInfo[i], 0x00, sizeof(StationInfoData));
         memset(&_deductResult[i], 0x00, sizeof(DeductResultInfoData));
+        memset(&_OccupancyResponse[i], 0x00, sizeof(OccupancyResponse));
         _GunSystemStatus[i] = 0;
     }
 }

+ 19 - 3
EVSE/Projects/DO360/Apps/Module_EvComm.h

@@ -34,8 +34,9 @@
 #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_I_Q_BOOST_CURRENT   5000
+#define CCS_NATURAL_I_Q_MAX_CURRENT     3000
+#define CCS_NATURAL_I_Q_85_DERATING_CUR 1000
 #define CCS_NATURAL_Y_Z_MAX_CURRENT     1500
 
 #define CHA_MAX_PHYSICAL_VOLTAGE        5000
@@ -44,6 +45,8 @@
 #define CHA_NATURAL_J_JARI_MAX_CURRENT  1250
 #define CHA_NATURAL_S_MAX_CURRENT       1250
 #define CHA_NATURAL_S_BOOST_CURRENT     2000
+#define CHA_NATURAL_O_BOOST_CURRENT     3500
+#define CHA_NATURAL_O_MAX_CURRENT       2000
 
 #define GBT_MAX_PHYSICAL_VOLTAGE        7500
 #define GBT_NATURAL_MAX_CURRENT         2500
@@ -103,7 +106,9 @@ enum PAYLOAD_REGISTER
     _Reg_PowerConsumption           = 0x24,
     _Reg_ChargingTimestamp          = 0x25,
     _Reg_ChargingBill               = 0x26,
-    _Reg_None                       = 0x27,
+    _Reg_ParkingStatus              = 0x27,
+    _Reg_ParkingBill                = 0x28,
+    _Reg_None                       = 0x29,
 };
 
 enum Response_Result
@@ -220,6 +225,9 @@ enum MiscCommand
     _MiscCmd_LEDIntensity       = 0x000E,
     _MiscCmd_AcContactor        = 0x000E,
     _MiscCmd_TimeOffset         = 0x0010,
+    _MiscCmd_ParkingPrice       = 0x0011,
+    _MiscCmd_RFIDCardEndian     = 0x0012,
+    _MiscCmd_RFIDEnable         = 0x0013,
     _MiscCmd_HardwareReboot     = 0x0101,
     _MiscCmd_SoftwareRestart    = 0x0102,
     _MiscCmd_RemoteStart        = 0x0103,
@@ -235,12 +243,14 @@ enum MiscCommand
     _MiscCmd_UserPriceString    = 0x010D,
     _MiscCmd_Receipt            = 0x010E,
     _MiscCmd_ChargingBill       = 0x010F,
+    _MiscCmd_ParkingRequest     = 0x0110,
 };
 
 enum DispenserMisc_Request
 {
     _DisReq_None                = 0x0000,
     _DisReq_ChargingCancel      = 0x0001,
+    _DisReq_ParkingFee          = 0x0002,
 };
 
 typedef struct
@@ -296,4 +306,10 @@ typedef struct
     char Reason[128];                       // reason in string format
 }PaymentFailResponse;
 
+typedef struct
+{
+    unsigned char ParkingStatus;            // index start from 1 ~ 200
+    char OccupancySn[37];                   // reason in string format
+}OccupancyResponse;
+
 #endif /* MODULE_EVCOMM_H_ */

+ 7 - 36
EVSE/Projects/DO360/Apps/Module_InternalComm.c

@@ -1987,38 +1987,6 @@ void CheckRelayWeldingStatus(byte index)
 	}
 }
 
-void GetPsuTempForFanSpeed()
-{
-	char temp = 0;
-
-	for (byte index = 0; index < ShmPsuData->GroupCount; index++)
-	{
-		for (byte count = 0; count < ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity; count++)
-		{
-			if (temp < ShmPsuData->PsuGroup[index].PsuModule[count].ExletTemp)
-				temp = ShmPsuData->PsuGroup[index].PsuModule[count].ExletTemp;
-		}
-	}
-
-	ShmSysConfigAndInfo->SysInfo.SystemAmbientTemp = temp;
-
-	if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == NO)
-	{
-		if (ShmFanModuleData->TestFanSpeed == NORMAL_FAN_SPEED)
-		{
-			if (temp >= ENV_TEMP_MAX)
-				ShmFanModuleData->TestFanSpeed = MAX_FAN_SPEED;
-		}
-		else if (ShmFanModuleData->TestFanSpeed == MAX_FAN_SPEED)
-		{
-			if (temp <= ENV_TEMP_MIN)
-				ShmFanModuleData->TestFanSpeed = NORMAL_FAN_SPEED;
-		}
-		else
-			ShmFanModuleData->TestFanSpeed = NORMAL_FAN_SPEED;
-	}
-}
-
 void GetFanSpeedByFunction()
 {
 	if (ShmSysConfigAndInfo->SysConfig.SwitchDebugFlag == YES)
@@ -2036,15 +2004,19 @@ void GetFanSpeedByFunction()
 	// 當前樁最大功率 KW : ShmPsuData->SystemAvailablePower
 	unsigned int _maxPower = ShmPsuData->SystemAvailablePower;
 	// 當前PSU輸出總 KW & PSU Temp :
-	unsigned char temp = 0;
+	int temp = 0;
 	float power = 0;
 
 	for (byte index = 0; index < ShmPsuData->GroupCount; index++)
 	{
 		for (byte count = 0; count < ShmPsuData->PsuGroup[index].GroupPresentPsuQuantity; count++)
 		{
-			if (temp < ShmPsuData->PsuGroup[index].PsuModule[count].ExletTemp)
-				temp = ShmPsuData->PsuGroup[index].PsuModule[count].ExletTemp;
+            int ExletTemp = (int)ShmPsuData->PsuGroup[index].PsuModule[count].ExletTemp - 60;
+
+            if (temp < ExletTemp)
+            {
+                temp = ExletTemp;
+            }
 		}
 		power += (_chargingData[index]->PresentChargingPower * 10);
 	}
@@ -2331,7 +2303,6 @@ int main(void)
             {
                 if (GetTimeoutValue(_priority_time) / 1000 >= 1000)
                 {
-                    //GetPsuTempForFanSpeed();
                     GetFanSpeedByFunction();
                     GetFanSpeed();
                     ShmSysConfigAndInfo->SysInfo.SystemFanRotaSpeed = _setFanSpeed;

File diff suppressed because it is too large
+ 753 - 134
EVSE/Projects/DO360/Apps/Module_PsuComm.c


+ 6 - 0
EVSE/Projects/DO360/Apps/Module_PsuComm.h

@@ -60,6 +60,12 @@ int connector_2[12];
 byte conn_1_count = 0;
 byte conn_2_count = 0;
 
+enum _PSU_ON_OFF_CMD
+{
+    _PSU_OFF            = 0,
+    _PSU_ON             = 1,
+};
+
 enum _PSU_TEMP_TYPE
 {
     _PSU_TMP_DCDC       = 0,

BIN
EVSE/Projects/DO360/Apps/Module_PsuComm_PH


+ 877 - 0
EVSE/Projects/DO360/Apps/PhGroup_PsuCommObj.c

@@ -0,0 +1,877 @@
+/*
+ * PhGroup_PsuCommObj.c
+ *
+ *  Created on: 2022年02月22日
+ *      Author: 8274
+ */
+
+#include "PhGroup_PsuCommObj.h"
+
+#define ARRAY_SIZE(A)		(sizeof(A) / sizeof(A[0]))
+#define NO		0
+#define YES		1
+
+#define DEBUG_LIB						1
+
+void PRINTF_LIB_FUNC(char *string, ...);
+float IEEE_754_to_float(const byte raw[4]);
+
+//================================================
+// Private function
+//================================================
+void PRINTF_LIB_FUNC(char *string, ...)
+{
+    if (DEBUG_LIB)
+    {
+        va_list args;
+        char buffer[4096];
+
+        va_start(args, string);
+        vsnprintf(buffer, sizeof(buffer), string, args);
+        va_end(args);
+        printf("%s \n", buffer);
+    }
+}
+
+float IEEE_754_to_float(const byte raw[4])
+{
+    float fValue = 0;
+    byte *pbyte = (byte *)&fValue;
+
+    *(pbyte + 0) = raw[3];
+    *(pbyte + 1) = raw[2];
+    *(pbyte + 2) = raw[1];
+    *(pbyte + 3) = raw[0];
+
+    return fValue;
+}
+
+//================================================
+// Callback function
+//================================================
+void RefreshPsuIndex(int (*func)(byte group, byte address))
+{
+    return_psuIndex = func;
+}
+
+void RefreshGroup(void *func)
+{
+    return_group = func;
+}
+
+void RefreshInfyPwrAlarmFlag(void *func)
+{
+    return_infy_pwr_alarm_flag = func;
+}
+
+void RefreshPhPwrAlarmFlag(void *func)
+{
+    return_ph_pwr_alarm_flag = func;
+}
+
+void RefreshAlarmStatus(void *func)
+{
+    return_alarm_status = func;
+}
+
+void RefreshAmbient(void *func)
+{
+    return_ambient = func;
+}
+
+void RefreshModuleCount(void *func)
+{
+    return_module_count = func;
+}
+
+void RefreshSysModuleCount(void *func)
+{
+    return_sys_module_count = func;
+}
+
+void RefreshAvailableCap(void *func)
+{
+    return_available_cap = func;
+}
+
+void RefreshFwDcVersion(void *func)
+{
+    return_fw_dc_version = func;
+}
+
+void RefreshFwPfcVersion(void *func)
+{
+    return_fw_pfc_version = func;
+}
+
+void RefreshInputVol(void *func)
+{
+    return_input_vol = func;
+}
+
+void RefreshInputCur(void *func)
+{
+    return_input_cur = func;
+}
+
+void RefreshGetOutput(void *func)
+{
+    return_get_output = func;
+}
+
+void RefreshGetOutputF(void *func)
+{
+    return_get_output_float = func;
+}
+
+void RefreshGetModuleOutput(void *func)
+{
+    return_module_output = func;
+}
+
+void RefreshGetErrorRecord(void *func)
+{
+    return_error_record = func;
+}
+
+void RefreshFanSpeedInfo(void *func)
+{
+    return_fan_speed = func;
+}
+
+void RefreshInletTemp(void *func)
+{
+    return_inlet_temp = func;
+}
+
+void RefreshExletTemp(void *func)
+{
+    return_exlet_temp = func;
+}
+
+void RefreshOutletTemp(void *func)
+{
+    return_outlet_temp = func;
+}
+
+void RefreshOtherTemp(void *func)
+{
+    return_other_temp = func;
+}
+
+void RefreshIavailable(void *func)
+{
+    return_iavail_info = func;
+}
+
+void AutoMode_RefreshOutputAndTemp(void *func)
+{
+    return_output_temp = func;
+}
+
+void AutoMode_RefreshModuleStatus(void *func)
+{
+    return_module_status = func;
+}
+
+void AutoMode_RefreshModuleInput(void *func)
+{
+    return_module_input = func;
+}
+
+//================================================
+// CANBUS initialization
+//================================================
+int InitCanBus()
+{
+	int 					s0,nbytes;
+	struct timeval			tv;
+	struct ifreq 			ifr0;
+	struct sockaddr_can		addr0;
+	struct can_filter 		rfilter[2];
+
+	system("/sbin/ip link set can1 down");
+	system("/sbin/ip link set can1 type can bitrate 500000 restart-ms 100");
+	system("/sbin/ip link set can1 up");
+
+	s0 = socket(PF_CAN, SOCK_RAW, CAN_RAW);
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 10000;
+   	if (setsockopt(s0, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct	timeval)) < 0)
+	{
+		#ifdef SystemLogMessage
+   		PRINTF_LIB_FUNC("Set SO_RCVTIMEO NG");
+		#endif
+	}
+	nbytes=40960;
+	if (setsockopt(s0, SOL_SOCKET,  SO_RCVBUF, &nbytes, sizeof(int)) < 0)
+	{
+		#ifdef SystemLogMessage
+		PRINTF_LIB_FUNC("Set SO_RCVBUF NG");
+		#endif
+	}
+	nbytes=40960;
+	if (setsockopt(s0, SOL_SOCKET, SO_SNDBUF, &nbytes, sizeof(int)) < 0)
+	{
+		#ifdef SystemLogMessage
+		PRINTF_LIB_FUNC("Set SO_SNDBUF NG");
+		#endif
+	}
+	nbytes=40960;
+
+	//DIR_GrpMaster_to_CSU
+ 	rfilter[0].can_id = 0xE000;
+	rfilter[0].can_mask = 0xE000;
+
+	 //DIR_Slave_to_CSU
+	rfilter[1].can_id = 0xD000;
+	rfilter[1].can_mask = 0xD000;
+
+	if (setsockopt(s0, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)) < 0)
+	{
+		#ifdef SystemLogMessage
+		PRINTF_LIB_FUNC("Set SOL_CAN_RAW NG");
+		#endif
+	}
+
+   	strcpy(ifr0.ifr_name, "can1" );
+	ioctl(s0, SIOCGIFINDEX, &ifr0); /* ifr.ifr_ifindex gets filled with that device's index */
+	addr0.can_family = AF_CAN;
+	addr0.can_ifindex = ifr0.ifr_ifindex;
+	bind(s0, (struct sockaddr *)&addr0, sizeof(addr0));
+	return s0;
+}
+
+void ReceiveDataFromCanBus() //onedollar:可加入err handling(讀取can id的CAN_ERR_FLAG,若有err,繼續由can id其他位看是什麼錯誤)
+{
+	int nbytes;
+	struct can_frame frame;
+	PH_PwrFrame *PH_PwrFrameMsg;
+	byte group_PSU, slv_address, length;
+	unsigned short full_address = 0;
+
+	while(1)
+	{		
+		memset(&frame, 0, sizeof(struct can_frame));
+		nbytes = read(CanFd, &frame, sizeof(struct can_frame));
+		
+		if (nbytes > 0)
+		{
+			PH_PwrFrameMsg = (PH_PwrFrame *)&frame.can_id;
+			length = frame.can_dlc;
+			group_PSU = PH_PwrFrameMsg->PHBits.SlaveGroup;
+			slv_address = PH_PwrFrameMsg->PHBits.SlaveAddress;
+			full_address = (group_PSU << GroupAdd_Position) | slv_address;
+			
+			switch(PH_PwrFrameMsg->PHBits.MessageID)
+			{	
+			    // 0x09
+				case (PH_PSU_RCmd_GetPresentOutput + PH_PSU_Ack_Msg):
+				{
+					byte vol[2], cur[2], maxCur[2];
+					memcpy(vol, frame.data, 2);
+					memcpy(cur, frame.data + 2, 2);
+					memcpy(maxCur, frame.data + 4, 2);
+
+                    // _Vol unit: 1V
+                    // _Cur unit: 1A
+                    float _Vol = ((frame.data[0] << 8) + frame.data[1]) * 0.1;
+                    float _Cur = ((frame.data[2] << 8) + frame.data[3]) * 0.1;
+
+					//[GetModuleOutputF] & [GetMouleIavailable]
+					if(PH_PwrFrameMsg->PHBits.DIR == DIR_GrpMaster_to_CSU)
+					{
+						return_get_output_float(group_PSU, _Vol, _Cur);
+					}
+
+					//[GetMouleIavailable]
+					if(PH_PwrFrameMsg->PHBits.DIR == DIR_Slave_to_CSU)
+					{	
+                        // Iavail unit: 0.1A
+                        // Vext unit: 0.1V
+						unsigned short iAvailCur = (frame.data[4] << 8) + frame.data[5];
+						unsigned short vextVol = (frame.data[0] << 8) + frame.data[1];
+
+	                    int psuIndex = 0;
+	                    psuIndex = return_psuIndex(group_PSU, slv_address - 1);
+
+						return_iavail_info(psuIndex, iAvailCur, vextVol);
+						return_module_output(psuIndex, _Vol, _Cur);
+						return_alarm_status(psuIndex, PH_PwrFrameMsg->PHBits.Status);
+					}
+				}
+				break;
+
+				// 0x03
+				case (PH_PSU_RCmd_GetGroupModuleCount + PH_PSU_Ack_Msg):
+				{						
+					byte count = frame.data[0];
+
+					return_module_count(group_PSU, count, true);
+				}
+				break;
+
+				// 0x04
+				case (PH_PSU_RCmd_GetAlarmFault + PH_PSU_Ack_Msg):
+				{
+					unsigned int alarm_0 = 0, alarm_1 = 0;
+
+					if(length >= 8)
+					{
+                        alarm_1 = (frame.data[0] << 24) | (frame.data[1] << 16) | (frame.data[2] << 8) | frame.data[3];
+                        alarm_0 = (frame.data[4] << 24) | (frame.data[5] << 16) | (frame.data[6] << 8) | frame.data[7];
+					}
+
+                    int psuIndex = 0;
+                    psuIndex = return_psuIndex(group_PSU, slv_address - 1);
+
+                    return_group(group_PSU, psuIndex, full_address);
+                    return_ph_pwr_alarm_flag(psuIndex, PH_PwrFrameMsg->PHBits.Status, alarm_1, alarm_0);
+
+                    short maxVol = 9500;	//950V
+                    short minVol = 1500;	//150V
+                    short maxCur = 1000;	//100A
+                    short totalPow = 300;	//30kW
+                    return_available_cap(psuIndex, maxVol, minVol, maxCur, totalPow);
+				}	
+				break;
+
+				// 0x05
+				case (PH_PSU_RCmd_GetModuleVersion + PH_PSU_Ack_Msg):
+				{
+					//[GetModuleVer]
+				    byte type = 0;
+				    char strVer[6];
+				    unsigned short fwVer = 0;
+
+				    type = frame.data[0];
+				    memset(strVer, 0x00, sizeof(strVer));
+				    memcpy(strVer, &frame.data[1], sizeof(strVer) - 1);
+				    fwVer = (frame.data[6] << 8) | frame.data[7];
+
+                    int psuIndex = 0;
+                    psuIndex = return_psuIndex(group_PSU, slv_address - 1);
+                    char version[32];
+                    memset(version, 0x00, sizeof(version));
+
+                    if(type == PH_FW_DD_App)
+                    {
+                        sprintf(version, "%s_%d.%02d", strVer, (fwVer / 100), (fwVer % 100));
+                        return_fw_dc_version(psuIndex, version);
+                    }
+                    if(type == PH_FW_PFC_App)
+                    {
+                        sprintf(version, "%s%d.%02d", strVer, (fwVer / 100), (fwVer % 100));
+                        return_fw_pfc_version(psuIndex, version);
+                    }
+				}    
+				break;
+						
+				//case (PSU_RCmd_SysOutputVolCur): //APP沒有使用到
+				//case (PSU_RCmd_ModuleBarcode): //APP沒有使用到
+
+				// 0x06
+				case (PH_PSU_RCmd_GetTemperature + PH_PSU_Ack_Msg):
+				{
+					//[GetDcTemperature] and [GetPfcTemperature]
+					char temp[8];
+
+					memset(temp, 0xFF, sizeof(temp));
+					for(int i = 0; i < length; i++)
+					{
+					    temp[i] = (char)frame.data[i];
+					}
+                    int psuIndex = 0;
+                    psuIndex = return_psuIndex(group_PSU, slv_address - 1);
+
+                    // temp[0]: ambient
+                    // temp[1]: reserve
+                    // temp[2]: dd in 1
+                    // temp[3]: dd in 2
+                    // temp[4]: liquid in
+                    // temp[5]: dd out 1
+                    // temp[6]: dd out 2
+                    // temp[7]: liquid out
+                    return_ambient(psuIndex, temp[0]);
+                    return_inlet_temp(psuIndex, temp[4]);
+                    return_outlet_temp(psuIndex, temp[7]);
+                    return_other_temp(psuIndex, temp[2], temp[3], temp[5], temp[6]);
+				}
+				break;
+
+				// 0x07
+				case (PH_PSU_RCmd_GetACInputVoltage + PH_PSU_Ack_Msg):
+                {
+				    unsigned short voltage_L1 = 0, voltage_L2 = 0, voltage_L3 = 0;
+
+				    voltage_L1 = (frame.data[1] << 8) | frame.data[2];
+				    voltage_L2 = (frame.data[3] << 8) | frame.data[4];
+				    voltage_L3 = (frame.data[5] << 8) | frame.data[6];
+
+				    int psuIndex = 0;
+				    psuIndex = return_psuIndex(group_PSU, slv_address - 1);
+				    return_input_vol(psuIndex, voltage_L1, voltage_L2, voltage_L3);
+                }
+				break;
+
+                // 0x08
+                case (PH_PSU_RCmd_GetACInputCurrent + PH_PSU_Ack_Msg):
+                {
+                    // unit: 0.1A
+                    unsigned short current_L1 = 0, current_L2 = 0, current_L3 = 0;
+
+                    current_L1 = (frame.data[0] << 8) | frame.data[1];
+                    current_L2 = (frame.data[2] << 8) | frame.data[3];
+                    current_L3 = (frame.data[4] << 8) | frame.data[5];
+
+                    int psuIndex = 0;
+                    psuIndex = return_psuIndex(group_PSU, slv_address - 1);
+                    return_input_cur(psuIndex, current_L1, current_L2, current_L3);
+                }
+                break;
+
+                case (PH_PSU_RCmd_GetErrorRecord + PH_PSU_Ack_Msg):
+                {
+                    byte countdown = 0;
+                    byte error_record[7];
+
+                    countdown = frame.data[0];
+                    memcpy(error_record, &frame.data[1], sizeof(error_record));
+
+                    int psuIndex = 0;
+                    psuIndex = return_psuIndex(group_PSU, slv_address - 1);
+
+                    return_error_record(psuIndex, countdown, error_record);
+                }
+                break;
+			}
+		}
+		else
+			usleep(10000);
+	}
+}
+
+//================================================
+// Private Function
+//================================================
+void SendCmdToPsu(int cmd, byte *dataPH, byte dataLen)
+{
+	PH_PwrFrame PwrFrameMsg;
+	struct can_frame frame;
+
+	//設定 CANBSU 2.0B 長封包(Extended ID)
+	PwrFrameMsg.PwrMessage = cmd | CAN_EFF_FLAG;
+
+	frame.can_id = PwrFrameMsg.PwrMessage;
+	frame.can_dlc = dataLen;
+	memset(frame.data, 0x00, sizeof(frame.data));
+
+	if(dataLen > 0)
+	{
+	    memcpy(frame.data, dataPH, dataLen);
+	}
+
+	write(CanFd, &frame, sizeof(struct can_frame)); //onedollar:可加入偵錯機制(發送byte數檢驗)
+	/*
+	// 群命令才 delay
+    if (PwrFrameMsg.PHBits.SlaveGroup == PH_ADD_BROADCAST)
+    	usleep(CMD_DELAY_TIME);
+	*/
+    usleep(CMD_DELAY_TIME);
+}
+
+void SetPowerOnOff(byte group, byte slv_address, byte DIR, byte value)
+{
+	byte dataPH = value;
+	//0xA1 ON
+	//0x00 OFF
+	
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_WCmd_ModulePowerOnOff;
+
+	PwrFrameMsg.PHBits.SlaveAddress = slv_address;	
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.DIR = DIR;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, &dataPH, 1);
+}
+
+void SetOutput(byte group, byte slv_address, byte DIR, int voltage, int current)
+{
+	byte dataPH[4] = {0};
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_WCmd_SetOutputCommand;
+
+	dataPH[0] = ((voltage >> 8) & 0xFF);
+	dataPH[1] = (voltage & 0xFF);
+	dataPH[2] = ((current >> 8) & 0xFF);
+	dataPH[3] = (current & 0xFF);
+	
+	PwrFrameMsg.PHBits.SlaveAddress = slv_address;	
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.DIR = DIR;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, dataPH, sizeof(dataPH));
+}
+
+// voltage unit: 0.1V
+void GetModuleIavailable(byte group, unsigned short voltage)
+{
+	byte data[2] = {0};
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetPresentOutput;
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.SlaveAddress = ALL_Slave;
+	PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+	data[0] = (voltage >> 8) & 0xFF;
+	data[1]	= voltage & 0xFF;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, data, sizeof(data));
+}
+
+
+pid_t InitialCommunication(void)
+{
+	CanFd = InitCanBus();
+
+	if(CanFd < 0)
+	{
+		return false;
+	}
+
+	recFork = fork();
+	if(recFork == 0)
+	{
+	    ReceiveDataFromCanBus();
+		return 0;
+	}
+
+	return recFork;
+}
+
+//================================================
+// API Function
+//================================================
+void SwitchPower(byte group, byte value)
+{
+	//對群控制,DIR_CSU_to_GrpMaster,僅需指定group
+	SetPowerOnOff(group, 0, DIR_CSU_to_GrpMaster, value);
+}
+
+void SinglePsuPower(byte full_address, byte value)
+{	
+	//對單控制,DIR_CSU_to_Slave,需指定group + slv_address
+	byte group = (full_address >> GroupAdd_Position) & ALL_Group;
+	byte slv_address = full_address & ALL_Slave;
+	SetPowerOnOff(group, slv_address, DIR_CSU_to_Slave, value);
+}
+
+void SwitchPower_On(byte group)
+{
+    SwitchPower(group, PH_PSU_POWER_ON);
+}
+
+void SwitchPower_Off(byte group)
+{
+    SwitchPower(group, PH_PSU_POWER_OFF);
+}
+
+void SinglePsuPower_On(byte address)
+{
+    SinglePsuPower(address, PH_PSU_POWER_ON);
+}
+
+void SinglePsuPower_Off(byte address)
+{
+    SinglePsuPower(address, PH_PSU_POWER_OFF);
+}
+
+void SleepMode(byte group, byte value)
+{
+    // no function
+}
+
+void FlashLed(byte group, byte value)
+{
+    // no function
+}
+
+void SingleFlashLed(byte address, byte value)
+{
+    // no function
+}
+
+void FlashLed_Static(byte group)
+{
+    FlashLed(group, 0);
+}
+
+void FlashLed_Blinking(byte group)
+{
+    FlashLed(group, 1);
+}
+
+void SingleFlashLed_Static(byte address)
+{
+    SingleFlashLed(address, 0);
+}
+
+void SingleFlashLed_Blinking(byte address)
+{
+    SingleFlashLed(address, 1);
+}
+
+void PresentOutputVol(byte group, int voltage, int current_percent)
+{	
+	//電流命令需換成最大電流之百分比,兩種方式:
+	//(1) API輸入參數多一個Max Current,由此Func內換算百分比
+	//(2) API輸入參數改為current_percent,APP端算出百分比後輸入
+	
+	SetOutput(group, 0, DIR_CSU_to_GrpMaster, voltage, current_percent);
+}
+
+void SingleOutputVol(byte full_address, int voltage, int current_percent)
+{
+	byte group = (full_address >> GroupAdd_Position) & ALL_Group;
+	byte slv_address = full_address & ALL_Slave;
+	
+	SetOutput(group, slv_address, DIR_CSU_to_GrpMaster, voltage, current_percent);
+}
+
+void FanNoiseInfo(byte group, byte value)
+{
+    // no function
+}
+
+void SetWalkInConfig(byte group, byte enable, byte sec)
+{
+    // no function
+}
+
+void SetDirModulePresentOutput(byte group, int voltage, int current, byte _switch, byte _interRelay)
+{
+    // no function
+}
+
+void SetDipSwitchMode()
+{
+    // no function
+}
+
+void UnlockPsuAlarm(byte full_address)
+{
+    byte group = (full_address >> GroupAdd_Position) & ALL_Group;
+    byte slv_address = full_address & ALL_Slave;
+
+    byte dataPH = PUS_UNLOCK_CMD;
+    PH_PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+
+    PwrFrameMsg.PHBits.MessageID = PH_PSU_WCmd_UnlockPsuCommand;
+    PwrFrameMsg.PHBits.SlaveGroup = group;
+    PwrFrameMsg.PHBits.SlaveAddress = slv_address;
+    PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, &dataPH, 1);
+}
+
+/**********************************************************************************/
+/***                                                                            ***/
+/***                                   Get                                      ***/
+/***                                                                            ***/
+/**********************************************************************************/
+// 0x04
+void GetStatus(byte group)
+{
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetAlarmFault;
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.SlaveAddress = ALL_Slave;
+	PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, 0, 0);
+}
+
+
+void GetFanSpeed(byte group)
+{
+}
+
+// 0x06
+void GetDcTemperature(byte group)
+{
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetTemperature;
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.SlaveAddress = ALL_Slave;
+	PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, 0, 0);
+}
+
+// 0x06
+void GetPfcTemperature(byte group)
+{
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetTemperature;
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.SlaveAddress = ALL_Slave;
+	PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, 0, 0);
+}
+
+// 0x03
+void GetModuleCount(byte group)
+{
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+	
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetGroupModuleCount;	
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.DIR = DIR_CSU_to_GrpMaster;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, 0, 0);
+}
+
+void GetSysModuleCount(void)
+{
+
+}
+
+// 0x05
+void GetModuleVer(byte group, byte type)
+{
+    byte dataPH = 0;
+    PH_PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+
+    PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetModuleVersion;
+    PwrFrameMsg.PHBits.SlaveGroup = group;
+    PwrFrameMsg.PHBits.SlaveAddress = ALL_Slave;
+    PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+
+    //DD FW ver.            0x01
+    //PFC FW ver.           0x02
+    //DD Bootloader ver.    0x03
+    //PFC Bootloader ver.   0x04
+
+    dataPH = type;
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, &dataPH, 1);
+}
+
+void GetAllModuleVer(byte group)
+{
+    GetModuleVer(group, PH_FW_DD_App);
+    GetModuleVer(group, PH_FW_PFC_App);
+}
+
+// 0x04
+void GetModuleCap(byte group)
+{	
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetAlarmFault;
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.SlaveAddress = ALL_Slave;
+	PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, 0, 0);
+}
+
+void GetModuleBarCode(byte group)
+{
+    // no function
+}
+
+// 0x07
+void GetModuleInputVol(byte group)
+{
+	PH_PwrFrame PwrFrameMsg;	
+	PwrFrameMsg.PwrMessage = 0;
+	
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetACInputVoltage;
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.SlaveAddress = ALL_Slave;
+	PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, 0, 0);
+}
+
+// 0x08
+void GetModuleInputCur(byte group)
+{
+    PH_PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+
+    PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetACInputCurrent;
+    PwrFrameMsg.PHBits.SlaveGroup = group;
+    PwrFrameMsg.PHBits.SlaveAddress = ALL_Slave;
+    PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, 0, 0);
+}
+
+
+void GetModuleOutput(byte group) //APP未使用此
+{
+	byte dataPH[2] = {0};
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetPresentOutput;
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.SlaveAddress = 0;
+	PwrFrameMsg.PHBits.DIR = DIR_CSU_to_GrpMaster;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, dataPH, sizeof(dataPH));
+}
+
+
+void GetModuleOutputF(byte group)
+{
+	byte dataPH[2] = {0};
+	PH_PwrFrame PwrFrameMsg;
+	PwrFrameMsg.PwrMessage = 0;
+
+	PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetPresentOutput;
+	PwrFrameMsg.PHBits.SlaveGroup = group;
+	PwrFrameMsg.PHBits.SlaveAddress = 0;
+	PwrFrameMsg.PHBits.DIR = DIR_CSU_to_GrpMaster;
+
+	SendCmdToPsu(PwrFrameMsg.PwrMessage, dataPH, sizeof(dataPH));
+}
+
+void GetErrorRecord(byte group)
+{
+    PH_PwrFrame PwrFrameMsg;
+    PwrFrameMsg.PwrMessage = 0;
+
+    PwrFrameMsg.PHBits.MessageID = PH_PSU_RCmd_GetErrorRecord;
+    PwrFrameMsg.PHBits.SlaveGroup = group;
+    PwrFrameMsg.PHBits.SlaveAddress = ALL_Slave;
+    PwrFrameMsg.PHBits.DIR = DIR_CSU_to_Slave;
+
+    SendCmdToPsu(PwrFrameMsg.PwrMessage, 0, 0);
+}
+
+/**********************************************************************************/
+/***                                                                            ***/
+/***                                 Upgrate                                    ***/
+/***                                                                            ***/
+/**********************************************************************************/
+void ChangePsuBaudrate(short baudrate)
+{
+}

+ 238 - 0
EVSE/Projects/DO360/Apps/PhGroup_PsuCommObj.h

@@ -0,0 +1,238 @@
+/*
+ * Phihong_PsuCommObj.h
+ PhGroup_PsuCommObj
+ *  Created on: 2022年02月22日
+ *      Author: 8274
+ */
+
+#ifndef TESTONE_PSUCOMMOBJ_H_
+#define TESTONE_PSUCOMMOBJ_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/wireless.h>
+#include <linux/can.h>
+#include <linux/can/raw.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>      /*標準輸入輸出定義*/
+#include <stdlib.h>     /*標準函數庫定義*/
+#include <unistd.h>     /*Unix 標準函數定義*/
+#include <fcntl.h>      /*檔控制定義*/
+#include <termios.h>    /*PPSIX 終端控制定義*/
+#include <errno.h>      /*錯誤號定義*/
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <ifaddrs.h>
+#include <math.h>
+
+
+#define SYSTEM_CMD             0x3F
+
+#define DIR_CSU_to_Slave       0x5
+#define DIR_CSU_to_GrpMaster   0x6
+#define DIR_GrpMaster_to_CSU   0xE
+#define DIR_Slave_to_CSU       0xD
+
+#define SlaveAdd_Position      0
+#define GroupAdd_Position      6
+#define ALL_Group              0x3F
+#define ALL_Slave              0x3F
+#define PUS_UNLOCK_CMD         0xA5
+
+#define ARRAY_SIZE(A)       (sizeof(A) / sizeof(A[0]))
+#define CMD_DELAY_TIME      25000
+
+
+typedef unsigned char       byte;
+typedef unsigned short      word;
+typedef unsigned int        unit;
+
+int                         CanFd;
+pid_t                       recFork;
+
+extern bool g_GetModuleCap;
+
+
+typedef union
+{
+	unsigned int PwrMessage;
+	struct
+	{
+		unsigned int SlaveAddress:6;    // slave address
+		unsigned int SlaveGroup:6;      // slave group
+		unsigned int DIR:4;             // message direction
+		unsigned int MessageID:8;       // message ID type
+		unsigned int Status:4;          // PSU status
+		unsigned int RDY:1;             // PSU stanby
+	}PHBits;
+}PH_PwrFrame; //onetry
+
+typedef enum //onetry
+{
+	PH_PSU_POWER_ON  =	0xA1,
+	PH_PSU_POWER_OFF =	0x00,
+}PH_Pwr_POWER_CMD;
+
+typedef enum
+{
+	PH_PSU_RCmd_GetGroupModuleCount     = 0x03,
+	PH_PSU_RCmd_GetAlarmFault           = 0x04,
+	PH_PSU_RCmd_GetModuleVersion        = 0x05,
+	PH_PSU_RCmd_GetTemperature          = 0x06,
+    PH_PSU_RCmd_GetACInputVoltage       = 0x07,
+    PH_PSU_RCmd_GetACInputCurrent       = 0x08,
+    PH_PSU_RCmd_GetPresentOutput        = 0x09,
+    PH_PSU_RCmd_GetErrorRecord          = 0x0A,
+	PH_PSU_WCmd_ModulePowerOnOff        = 0x41,
+	PH_PSU_WCmd_SetOutputCommand        = 0x42,
+	PH_PSU_WCmd_UnlockPsuCommand        = 0x43,
+	PH_PSU_Ack_Msg                      = 0x80,
+}PHPwrCommand;
+
+typedef enum
+{
+    PH_FW_DD_App                        = 0x01,
+    PH_FW_PFC_App                       = 0x02,
+    PH_FW_DD_Bootloader                 = 0x03,
+    PH_FW_PFC_Bootloader                = 0x04,
+}PHPwrFwVer;
+
+
+/*Initialization*/
+pid_t InitialCommunication(void);
+
+/*Set Cmd*/
+void SwitchPower(byte group, byte value);
+void SinglePsuPower(byte address, byte value);
+void SwitchPower_On(byte group);
+void SwitchPower_Off(byte group);
+void SinglePsuPower_On(byte address);
+void SinglePsuPower_Off(byte address);
+void SleepMode(byte group, byte value);
+void FlashLed(byte group, byte value);
+void SingleFlashLed(byte address, byte value);
+void FlashLed_Static(byte group);
+void FlashLed_Blinking(byte group);
+void SingleFlashLed_Static(byte address);
+void SingleFlashLed_Blinking(byte address);
+void PresentOutputVol(byte group, int voltage, int current);
+void SingleOutputVol(byte address, int voltage, int current);
+void FanNoiseInfo(byte group, byte value);
+void SetWalkInConfig(byte group, byte enable, byte sec);
+void SetDipSwitchMode();
+void UnlockPsuAlarm(byte full_address);
+
+/*Ver : 9.06 used*/
+void SetDirModulePresentOutput(byte group, int voltage, int current, byte _switch, byte _interRelay);
+/*Get Cmd*/
+void GetStatus(byte group);
+void GetFanSpeed(byte group);
+void GetDcTemperature(byte group);
+void GetPfcTemperature(byte group);
+
+void GetModuleCount(byte group);
+void GetSysModuleCount(void);
+void GetModuleVer(byte group, byte type);
+void GetAllModuleVer(byte group);
+void GetModuleCap(byte group);
+void GetModuleBarCode(byte group);
+void GetModuleInputVol(byte group);
+void GetModuleInputCur(byte group);
+void GetModuleIavailable(byte group, unsigned short voltage);
+void GetModuleOutput(byte group);
+void GetModuleOutputF(byte group);
+void GetErrorRecord(byte group);
+
+/*Upgrade*/
+void ChangePsuBaudrate(short baudrate);
+
+/* Callback Function */
+void RefreshPsuIndex(int (*func)(byte group, byte gIndex));
+int (*return_psuIndex)(byte group, byte gIndex);
+
+void RefreshGroup(void *func);
+void (*return_group)(byte group, byte psu_index, unsigned short full_address);
+void RefreshInfyPwrAlarmFlag(void *func);
+void (*return_infy_pwr_alarm_flag)(byte address, byte state_2, byte state_1, byte state_0);
+void RefreshPhPwrAlarmFlag(void *func);
+void (*return_ph_pwr_alarm_flag)(byte address, unsigned int status, unsigned int alarm_1, unsigned int alarm_0);
+void RefreshAlarmStatus(void *func);
+void (*return_alarm_status)(byte address, unsigned int status);
+void RefreshAmbient(void *func);
+void (*return_ambient)(byte address, char temp);
+
+void RefreshModuleCount(void *func);
+void (*return_module_count)(byte group, byte count, bool summation);
+void RefreshSysModuleCount(void *func);
+void (*return_sys_module_count)(byte group, byte count);
+
+void RefreshAvailableCap(void *func);
+void (*return_available_cap)(byte address, short maxVol, short minVol, short maxCur, short totalPow);
+
+void RefreshFwDcVersion(void *func);
+void (*return_fw_dc_version)(byte address, char *dcSwVer);
+void RefreshFwPfcVersion(void *func);
+void (*return_fw_pfc_version)(byte address, char *pfcSwVer);
+
+void RefreshInputVol(void *func);
+void (*return_input_vol)(byte address, unsigned short vol1, unsigned short vol2, unsigned short vol3);
+
+void RefreshInputCur(void *func);
+void (*return_input_cur)(byte address, unsigned short cur1, unsigned short cur2, unsigned short cur3);
+
+void RefreshGetOutput(void *func);
+void (*return_get_output)(byte address, unsigned short outVol, unsigned short outCur);
+
+void RefreshGetOutputF(void *func);
+void (*return_get_output_float)(byte group, float outVol, float outCur);
+
+void RefreshGetModuleOutput(void *func);
+void (*return_module_output)(byte address, float outVol, float outCur);
+
+void RefreshGetErrorRecord(void *func);
+void (*return_error_record)(byte address, byte count_down, byte *error_record);
+
+void RefreshFanSpeedInfo(void *func);
+void (*return_fan_speed)(byte address, unsigned int fanSpeed);
+void RefreshInletTemp(void *func);
+void (*return_inlet_temp)(byte address, char temp);
+void RefreshExletTemp(void *func);
+void (*return_exlet_temp)(byte address, char temp);
+void RefreshOutletTemp(void *func);
+void (*return_outlet_temp)(byte address, char temp);
+void RefreshOtherTemp(void *func);
+void (*return_other_temp)(byte address, char temp1, char temp2, char temp3, char temp4);
+
+void RefreshIavailable(void *func);
+void (*return_iavail_info)(byte address, unsigned short Iavail, unsigned short Vext);
+
+/*Test mode used*/
+void AutoMode_RefreshOutputAndTemp(void *func);
+void (*return_output_temp)(byte address, unsigned short outputVol,
+        unsigned short outputCur, unsigned short outputPower, unsigned char Temperature);
+
+void AutoMode_RefreshModuleStatus(void *func);
+void (*return_module_status)(byte address, unsigned char isErr, unsigned char status,
+        unsigned char err1, unsigned char err2, unsigned char err3, unsigned char err4);
+
+void AutoMode_RefreshModuleInput(void *func);
+void (*return_module_input)(byte address, unsigned short inputR,
+        unsigned short inputS, unsigned short inputT);
+/* Callback Function end */
+#endif
+

+ 582 - 109
EVSE/Projects/DO360/Apps/ReadCmdline.c

@@ -833,7 +833,7 @@ void GetOrClearId(char *v1)
 	printf("Card Number = %s \n", _chargingData[_index]->StartUserId);
 }
 
-void FwUpdateFlagProc()
+void FwUpdateFlagProc(char *inputCmd, unsigned int opt)
 {
 	ShmSysConfigAndInfo->SysInfo.FirmwareUpdate = 0x01;
 }
@@ -1034,20 +1034,23 @@ void GetTemperature(char *inputCmd, unsigned int opt)
 
                 if(_chargingData[i]->ConnectorTemp != 0 && _chargingData[i]->ConnectorTemp != 0xFF)
                 {
-                    sprintf(strGunTemp, "%3d", _chargingData[i]->ConnectorTemp - 60);
+                    int _connectorTemp = (int)_chargingData[i]->ConnectorTemp - 60;
+                    sprintf(strGunTemp, "%3d", _connectorTemp);
                 }
                 if(_chargingData[i]->ChillerTemp != 0 && _chargingData[i]->ChillerTemp != 0xFF)
                 {
-                    sprintf(strChillerTemp, "%3d", _chargingData[i]->ChillerTemp - 60);
+                    int _chillerTemp = (int)_chargingData[i]->ChillerTemp - 60;
+                    sprintf(strChillerTemp, "%3d", _chillerTemp);
                 }
                 printf("  %d    %s    %s  ", i + 1, strGunTemp, strChillerTemp);
 
                 for(int j = 0; j < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; j++)
                 {
-                    printf("  %3d/%3d/%3d",
-                        ShmPsuData->PsuGroup[i].PsuModule[j].ExletTemp,
-                        ShmPsuData->PsuGroup[i].PsuModule[j].InletTemp,
-                        ShmPsuData->PsuGroup[i].PsuModule[j].CriticalTemp1);
+                    int ExletTemp = (int)ShmPsuData->PsuGroup[i].PsuModule[j].ExletTemp - 60;
+                    int InletTemp = (int)ShmPsuData->PsuGroup[i].PsuModule[j].InletTemp - 60;
+                    int CriticalTemp1 = (int)ShmPsuData->PsuGroup[i].PsuModule[j].CriticalTemp1 - 60;
+
+                    printf("  %3d/%3d/%3d", ExletTemp, InletTemp, CriticalTemp1);
                 }
                 printf("\r\n");
             }
@@ -1113,91 +1116,6 @@ void GetInputVol(char *inputCmd, unsigned int opt)
     printf("\r\n");
 }
 
-void GetPsuInformation(char *v1, char *v2, char *v3)
-{
-	printf("**********************AC Contact needed*************************\n");
-	if(strcmp(v1, "count") == 0)
-	{
-		for (int i = 0; i < 4; i++)
-		{
-			printf("Group Index = %d, Module Count = %d \n", i, ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity);
-		}
-	}
-	else if(strcmp(v1, "ver") == 0)
-	{
-		for (int i = 0; i < ShmPsuData->SystemInitialPsuQuantity; i++)
-		{
-			printf("Psu Index = %d, PriVersion = %s, SecVersion = %s \n",
-					i, ShmPsuData->PsuVersion[i].FwPrimaryVersion, ShmPsuData->PsuVersion[i].FwSecondVersion);
-		}
-
-		for (int i = 0; i < ShmPsuData->GroupCount; i++)
-		{
-			for (int j = 0; j < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; j++)
-			{
-				printf("Group Index = %d, Psu Index = %d, Version = %s \n",
-					i, j, ShmPsuData->PsuGroup[i].PsuModule[j].FwVersion);
-			}
-		}
-	}
-	else if(strcmp(v1, "cap") == 0)
-	{
-		for (int i = 0; i < ShmPsuData->GroupCount; i++)
-		{
-			printf("Group Index = %d, MaxCur = %d, Power = %d \n",
-					i, ShmPsuData->PsuGroup[i].GroupAvailableCurrent, ShmPsuData->PsuGroup[i].GroupAvailablePower);
-		}
-	}
-	else if(strcmp(v1, "input") == 0)
-	{
-		for (int i = 0; i < ShmPsuData->GroupCount; i++)
-		{
-			for (byte count = 0; count < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; count++)
-			{
-				printf("gp = %d, Index = %d, volR = %d, volS = %d, volT = %d \n",
-						i, count,
-						ShmPsuData->PsuGroup[i].PsuModule[count].InputVoltageL1,
-						ShmPsuData->PsuGroup[i].PsuModule[count].InputVoltageL2,
-						ShmPsuData->PsuGroup[i].PsuModule[count].InputVoltageL3);
-			}
-		}
-	}
-	else if (strcmp(v1, "output") == 0)
-	{
-		for (int i = 0; i < ShmPsuData->GroupCount; i++)
-		{
-			printf("Group Index = %d, OutputV = %d, OutputC = %d \n",
-					i, ShmPsuData->PsuGroup[i].GroupPresentOutputVoltage, ShmPsuData->PsuGroup[i].GroupPresentOutputCurrent);
-		}
-	}
-	else if (strcmp(v1, "test") == 0)
-	{
-		int mode = atoi(v2);
-
-		if (mode >= _TEST_MODE && mode <= _TEST_MODE)
-		{
-			ShmPsuData->Work_Step = mode;
-		}
-	}
-	else if (strcmp(v1, "out") == 0)
-	{
-		float vol = atof(v2);
-		float cur = atof(v3);
-
-		if (ShmPsuData->Work_Step >= _TEST_MODE && ShmPsuData->Work_Step <= _TEST_MODE)
-		{
-			if (!FindChargingInfoData(0, &_chargingData[0]))
-			{
-				printf ("FindChargingInfoData error\n");
-				return;
-			}
-			_chargingData[0]->EvBatterytargetVoltage = vol;
-			_chargingData[0]->EvBatterytargetCurrent = cur;
-		}
-	}
-	printf("*************************************************\n");
-}
-
 void GetConnectorCapInfo(char *v1)
 {
 	int _GunIndex = atoi(v1);
@@ -2732,6 +2650,7 @@ void EraseWhiteCard(char *v1)
 
 // MaxChargingProfile: %s
 //   Offline MaxPower: %s
+//  LocalPowerSharing: %s
 //    Max Total Power: XXXX kW, Total Current: XXXX A,       MaxSoc: XXX %
 //       Total Energy: XXXX kWh,     Duration: XXXX Minute(s)
 void ShowMaxLimit(void)
@@ -2761,6 +2680,24 @@ void ShowMaxLimit(void)
     }
     printf("   Offline MaxPower: %s\r\n", tempString);
     //************************************************************************************************
+    memset(tempString, 0x00, sizeof(tempString));
+    if(ShmSysConfigAndInfo->SysConfig.isEnableLocalPowerSharing == _SYS_POWER_SHARING_MODE_DISABLE)
+    {
+        sprintf(tempString, " %s", "Disable");
+    }
+    else
+    {
+        if(ShmSysConfigAndInfo->SysConfig.isEnableLocalPowerSharing == _SYS_POWER_SHARING_MODE_MASTER)
+        {
+            sprintf(tempString, " %s, PowerSharingPower: %d W", "Master", ShmSysConfigAndInfo->SysConfig.PowerSharingCapacityPower);
+        }
+        else
+        {
+            sprintf(tempString, " %s", "Slave");
+        }
+    }
+    printf("  LocalPowerSharing: %s\r\n", tempString);
+    //************************************************************************************************
     printf("    Max Total Power: %4d kW, Total Current: %4d A,       MaxSoc: %3d %%\r\n",
         ShmSysConfigAndInfo->SysConfig.MaxChargingPower,
         ShmSysConfigAndInfo->SysConfig.MaxChargingCurrent,
@@ -2774,9 +2711,8 @@ void ShowGunLimit(int gun_index)
 {
     char *str_gun_type[] = {STR_GUN_TYPE_CHADEMO, STR_GUN_TYPE_CCS, STR_GUN_TYPE_GBT};
 
-    // 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
+    // Gun Enable    Type  Psu  Phy_Vol  Phy_Cur  Config_Ocpp_MaxOcpp_Pow  Config_Ocpp_MaxOcpp_Cur  LocalPowerSharing
+    //  1    0    CHAdeMO   00   0000 V   0000 A    0000 / 0000 / 0000 kW     0000 / 0000 A           0000 >> 0000 A
     printf("  %d    %d   ", gun_index + 1, ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].Enable);
     if(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].Enable)
     {
@@ -2795,6 +2731,8 @@ void ShowGunLimit(int gun_index)
         printf("     %4d / %4d A",
             ((int)ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].MaxTotalChargingCurrent / 10),
             _chargingData[gun_index]->ChargingProfileCurrent == -1 ? (int)_chargingData[gun_index]->ChargingProfileCurrent : ((int)_chargingData[gun_index]->ChargingProfileCurrent / 10));
+
+        printf("           %4d >> %4d A", ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index], (int)_chargingData[gun_index]->LocalPowerLimitCurrent);
     }
     printf("\r\n");
 }
@@ -2820,13 +2758,13 @@ void ShowChargerLimit(char *inputCmd, unsigned int opt)
         {
             if(reflash)
             {
-                ConsoleReflash(1, 6);
+                ConsoleReflash(1, 7);
                 ConsoleReflash(CONNECTOR_QUANTITY, 1);
             }
 
             ShowMaxLimit();
             printf("\r\n");
-            printf(" Gun Enable    Type  Psu  Phy_Vol  Phy_Cur  Config_Ocpp_MaxOcpp_Pow  Config_Ocpp_MaxOcpp_Cur\r\n");
+            printf(" Gun Enable    Type  Psu  Phy_Vol  Phy_Cur  Config_Ocpp_MaxOcpp_Pow  Config_Ocpp_MaxOcpp_Cur  LocalPowerSharing\r\n");
             for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
             {
                 ShowGunLimit(i);
@@ -5029,6 +4967,541 @@ void ShowPrice(char *inputCmd, unsigned int opt)
     printf("\r\n");
 }
 
+void SetOccupancyNotifyDisplay(char *inputCmd)
+{
+    int gun = 0;
+    float fee = 0;
+    int totalCnt = 0;
+
+    char *str_occupancy_status[] = {STR_NO_OCCUPANCY, STR_SYNC_OCCUPANCY, STR_OCCUPIED, STR_REQUEST_FEE, STR_WAIT_TO_PAY, STR_PAID_ONLINE_OK, STR_PAID_ONLINE_FAIL};
+    char _sn[37];
+    char cmdBuf[32];
+    struct timeb nowTime;
+    struct tm *tm;
+
+    memset(_sn, 0x00, sizeof(_sn));
+
+    totalCnt = GetSubCommand(inputCmd);
+
+    if(totalCnt == 3)
+    {
+        gun = atoi(&MultiSubCmd[0][0]);
+        if(gun <= 0 || gun > GENERAL_GUN_QUANTITY)
+        {
+            printf("\r\n");
+            printf("Gun [%s] out of range\r\n\r\n", &MultiSubCmd[0][0]);
+            return;
+        }
+
+        strncpy(_sn, &MultiSubCmd[1][0], strlen(&MultiSubCmd[1][0]) >= (sizeof(_sn) - 1) ? (sizeof(_sn) - 1) : strlen(&MultiSubCmd[1][0]));
+
+        fee = atof(&MultiSubCmd[2][0]);
+        if(fee <= 0)
+        {
+            printf("\r\n");
+            printf("Fee [%s] out of range\r\n\r\n", &MultiSubCmd[2][0]);
+            return;
+        }
+
+        ShmChargerInfo->AllBill.OccupancyInfo[gun - 1].Status = _Parking_Occupied;
+        memcpy(ShmChargerInfo->AllBill.OccupancyInfo[gun - 1].OccupancyBill.Sn, _sn, sizeof(_sn));
+        ShmChargerInfo->AllBill.OccupancyInfo[gun - 1].OccupancyBill.Fee = fee;
+        ShmChargerInfo->AllBill.OccupancyInfo[gun - 1].OccupancyBill.Duration = 5;
+
+        ftime(&nowTime);
+        tm = localtime(&nowTime.time);
+        // StartTime: [2022/09/27 13:50]
+        sprintf(cmdBuf, "%04d//%02d//%02d %02d:%02d",
+            tm->tm_year + 1900,
+            tm->tm_mon + 1,
+            tm->tm_mday,
+            tm->tm_hour,
+            tm->tm_min);
+        memcpy(ShmChargerInfo->AllBill.OccupancyInfo[gun - 1].OccupancyBill.StartTime, cmdBuf, sizeof(cmdBuf));
+
+        ShmChargerInfo->AllBill.OccupancyInfo[gun - 1].OccupancyReq.bits.SelfReq = true;
+
+        printf("\r\n");
+        printf("Set Gun [%s] [%s], SN: [%s], Fee: [%.2f]\r\n\r\n", &MultiSubCmd[0][0], str_occupancy_status[_Parking_Occupied], _sn, fee);
+        return;
+    }
+    printf("\r\n");
+    printf("Input cmd fail ------  parking notify display [gun 1-4] [sn] [fee]\r\n\r\n");
+}
+
+void SetOccupancyNotifyCancel(char *inputCmd)
+{
+    int gun = 0;
+    char subMain[MAX_SUB_CMD_LENGTH];
+    char subSub[MAX_SUB_CMD_LENGTH];
+    char *str_occupancy_status[] = {STR_NO_OCCUPANCY, STR_SYNC_OCCUPANCY, STR_OCCUPIED, STR_REQUEST_FEE, STR_WAIT_TO_PAY, STR_PAID_ONLINE_OK, STR_PAID_ONLINE_FAIL};
+
+    memset(subMain, 0x00, sizeof(subMain));
+    memset(subSub, 0x00, sizeof(subSub));
+
+    if(MainAndSubCommandParsing(inputCmd, subMain, subSub) == 1)
+    {
+        gun = atoi(subMain);
+        if(gun <= 0 || gun > GENERAL_GUN_QUANTITY)
+        {
+            printf("\r\n");
+            printf("Gun [%s] out of range\r\n\r\n", subMain);
+            return;
+        }
+
+        ShmChargerInfo->AllBill.OccupancyInfo[gun - 1].Status = _Parking_NoOccupancy;
+        printf("\r\n");
+        printf("Set Gun [%s] [%s]\r\n\r\n", subMain, str_occupancy_status[_Parking_NoOccupancy]);
+        return;
+    }
+    printf("\r\n");
+    printf("Input cmd fail ------  parking notify cancel [gun 1-4]\r\n\r\n");
+}
+
+void OccupancyNotifyCmd(char *inputCmd, unsigned int opt)
+{
+    char subMain[MAX_SUB_CMD_LENGTH];
+    char subSub[MAX_SUB_CMD_LENGTH];
+
+    memset(subMain, 0x00, sizeof(subMain));
+    memset(subSub, 0x00, sizeof(subSub));
+
+    if(MainAndSubCommandParsing(inputCmd, subMain, subSub) == 2)
+    {
+        if(strcmp(subMain, "display") == 0)
+        {
+            SetOccupancyNotifyDisplay(subSub);
+            return;
+        }
+
+        if(strcmp(subMain, "cancel") == 0)
+        {
+            SetOccupancyNotifyCancel(subSub);
+            return;
+        }
+    }
+    printf("\r\n");
+    printf("Input cmd fail ------  parking notify [display | cancel] [gun 1-4] [...]\r\n\r\n");
+}
+
+void OccupancySetCmd(char *inputCmd, unsigned int opt)
+{
+    char subMain[MAX_SUB_CMD_LENGTH];
+    char subSub[MAX_SUB_CMD_LENGTH];
+
+    memset(subMain, 0x00, sizeof(subMain));
+    memset(subSub, 0x00, sizeof(subSub));
+
+    float _price = 0;
+
+    if(MainAndSubCommandParsing(inputCmd, subMain, subSub) == 1)
+    {
+        _price = atof(subMain);
+        if(_price > 0)
+        {
+            ShmChargerInfo->CabinetMiscValue.ParkingPrice = _price;
+            for(int i = 0; i < MAX_DISPENSER_QUANTITY; i++)
+            {
+                if(ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].LocalStatus != _DS_None &&
+                    ShmSysConfigAndInfo->SysInfo.DispenserInfo.Dispenser[i].LocalStatus != _DS_Timeout)
+                {
+                    ShmChargerInfo->DispenserMiscReq[i].bits.ParkingPrice = true;
+                    printf("Set Dispenser %d Parking price [%s]\r\n\r\n", i + 1, subMain);
+                }
+            }
+            return;
+        }
+        else
+        {
+            printf("\r\n");
+            printf("Parking price [%s] out of range\r\n\r\n", subMain);
+            return;
+        }
+    }
+    printf("\r\n");
+    printf("Input cmd fail ------  parking set [price]\r\n\r\n");
+}
+
+void OccupancyCmd(char *inputCmd, unsigned int opt)
+{
+    char subMain[MAX_SUB_CMD_LENGTH];
+    char subSub[MAX_SUB_CMD_LENGTH];
+
+    memset(subMain, 0x00, sizeof(subMain));
+    memset(subSub, 0x00, sizeof(subSub));
+
+    if(MainAndSubCommandParsing(inputCmd, subMain, subSub) >= 2)
+    {
+        if(strcmp(subMain, "notify") == EQUAL)
+        {
+            OccupancyNotifyCmd(subSub, opt);
+            return;
+        }
+
+        if(strcmp(subMain, "set") == EQUAL)
+        {
+            OccupancySetCmd(subSub, opt);
+            return;
+        }
+    }
+    printf("\r\n");
+    printf("Input cmd fail ------  parking [set | notify] [...]\r\n\r\n");
+}
+
+//          Status                      SN                      Fee       StartTime      Duration
+//                     4fb5beab-c1dc-4fa8-8f80-aee1a26df705  XXXXX.XX
+// Gun 1  NoOccupancy  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX  XXXXX.XX  YYYY/MM/DD HH:MM    XXXX
+int ShowOccupancyInfo(int gun)
+{
+    int showLine = 1;
+    char *str_occupancy_status[] = {STR_NO_OCCUPANCY, STR_SYNC_OCCUPANCY, STR_OCCUPIED, STR_REQUEST_FEE, STR_WAIT_TO_PAY, STR_PAID_ONLINE_OK, STR_PAID_ONLINE_FAIL};
+    char _sn[37], _time[32];
+
+    if(ShmChargerInfo->AllBill.OccupancyInfo[gun].Status == _Parking_NoOccupancy)
+    {
+        sprintf(_sn, "                 N/A                ");
+    }
+    else
+    {
+        sprintf(_sn, "%s", ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyBill.Sn);
+    }
+    if(ShmChargerInfo->AllBill.OccupancyInfo[gun].Status == _Parking_WaitToPay)
+    {
+        sprintf(_time, "%s", ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyBill.StartTime);
+    }
+    else
+    {
+        sprintf(_time, "       N/A      ");
+    }
+
+    //************************************************************************************************
+    printf(" Gun %d  %11s  %36s  %8.2f  %16s    %4d\r\n",
+        gun + 1,
+        str_occupancy_status[ShmChargerInfo->AllBill.OccupancyInfo[gun].Status],
+        _sn,
+        ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyBill.Fee,
+        _time,
+        ShmChargerInfo->AllBill.OccupancyInfo[gun].OccupancyBill.Duration
+        );
+
+    return showLine;
+}
+
+void ShowOccupancy(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;
+    }
+
+    printf("\r\n");
+    do
+    {
+        time = GetTimeoutValue(_Loop_time) / mSEC_VAL;
+        if(time >= 1000)
+        {
+            if(reflash)
+            {
+                ConsoleReflash(1, 2);
+                ConsoleReflash(CONNECTOR_QUANTITY, 1);
+            }
+
+            printf("OccupancyPrice: [%.2f]\r\n", ShmChargerInfo->CabinetMiscValue.ParkingPrice);
+            printf("          Status                      SN                      Fee       StartTime      Duration\r\n");
+
+            for(int i = 0; i < GENERAL_GUN_QUANTITY; i++)
+            {
+                totalLine += ShowOccupancyInfo(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 ShowPsuCount(void)
+{
+    int line = 0;
+    for(int i = 0; i < MAX_GROUP_QUANTITY; i++)
+    {
+        printf("Group Index = %d, Module Count = %2d\r\n", i, ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity);
+        line++;
+    }
+    return line;
+}
+
+int ShowPsuVersion(void)
+{
+    int line = 0;
+    for(int i = 0; i < ShmPsuData->SystemInitialPsuQuantity; i++)
+    {
+        printf("Psu Index = %2d, PriVersion = %s, SecVersion = %s\r\n",
+                i, ShmPsuData->PsuVersion[i].FwPrimaryVersion, ShmPsuData->PsuVersion[i].FwSecondVersion);
+        line++;
+    }
+
+    for(int i = 0; i < ShmPsuData->GroupCount; i++)
+    {
+        for (int j = 0; j < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; j++)
+        {
+            printf("Group Index = %d, Psu Index = %2d, Version = %s\r\n",
+                i, j, ShmPsuData->PsuGroup[i].PsuModule[j].FwVersion);
+            line++;
+        }
+    }
+    return line;
+}
+
+int ShowPsuCap(void)
+{
+    int line = 0;
+    for(int i = 0; i < ShmPsuData->GroupCount; i++)
+    {
+        printf("Group Index = %d, MaxCur = %4d.%d A, Power = %d kW\r\n",
+            i,
+            (ShmPsuData->PsuGroup[i].GroupAvailableCurrent / 10),
+            (ShmPsuData->PsuGroup[i].GroupAvailableCurrent % 10),
+            (ShmPsuData->PsuGroup[i].GroupAvailablePower / 10));
+        line++;
+    }
+    return line;
+}
+
+int ShowPsuInput(void)
+{
+    int line = 0;
+    for(int i = 0; i < ShmPsuData->GroupCount; i++)
+    {
+        for(byte count = 0; count < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; count++)
+        {
+            printf("Group[%d] Index = %2d, VolR = %d, VolS = %d, VolT = %d\r\n",
+                i, count,
+                ShmPsuData->PsuGroup[i].PsuModule[count].InputVoltageL1,
+                ShmPsuData->PsuGroup[i].PsuModule[count].InputVoltageL2,
+                ShmPsuData->PsuGroup[i].PsuModule[count].InputVoltageL3);
+            line++;
+        }
+    }
+    return line;
+}
+
+int ShowPsuOutput(void)
+{
+    int line = 0;
+    for(int i = 0; i < ShmPsuData->GroupCount; i++)
+    {
+        printf("Group Index = %d, OutputV = %4d.%d V, OutputC = %4d.%d A\r\n",
+            i,
+            (ShmPsuData->PsuGroup[i].GroupPresentOutputVoltage / 10),
+            (ShmPsuData->PsuGroup[i].GroupPresentOutputVoltage % 10),
+            (ShmPsuData->PsuGroup[i].GroupPresentOutputCurrent / 10),
+            (ShmPsuData->PsuGroup[i].GroupPresentOutputCurrent % 10));
+        line++;
+    }
+    return line;
+}
+
+int ShowPsuGroupInfo(int group)
+{
+    if(ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity > 0)
+    {
+        printf("  G-%d    %2d  %4d.%d V  %4d.%d A  %4d kW   %4d A  %4d kW",
+            group + 1,
+            ShmPsuPosition->GroupLocationInfo[group].GroupPsuQuantity,
+            (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage / 10),
+            (ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage % 10),
+            (ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent / 10),
+            (ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent % 10),
+            (ShmPsuData->PsuGroup[group].GroupPresentOutputPower / 10),
+            (ShmPsuData->PsuGroup[group].GroupAvailableCurrent / 10),
+            (ShmPsuData->PsuGroup[group].GroupAvailablePower / 10));
+
+        printf("                                                   |   %d%d%d%d  |   %d%d%d%d\r\n",
+            ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR[group].bits.Lock,
+            ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR[group].bits.Alarm,
+            ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR[group].bits.Fault,
+            ShmChargerInfo->PsuGrouping.GroupPsuStatus_OR[group].bits.Output,
+            ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND[group].bits.Lock,
+            ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND[group].bits.Alarm,
+            ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND[group].bits.Fault,
+            ShmChargerInfo->PsuGrouping.GroupPsuStatus_AND[group].bits.Output);
+    }
+    else
+    {
+        printf("  G-%d    %2d     N/A        N/A      N/A      N/A      N/A\r\n", group + 1, ShmPsuPosition->GroupLocationInfo[group].GroupPsuQuantity);
+    }
+    return 1;
+}
+
+int ShowSinglePsuInfo(int psu_index)
+{
+    int group = 0, gIndex = 0;
+    unsigned int _power = 0;
+
+    group = ShmPsuPosition->PsuAddressInfo[psu_index].GroupNo;
+    gIndex = ShmPsuPosition->PsuAddressInfo[psu_index].GIndex;
+
+    printf("  %2d     %2d  %4d.%d V  %4d.%d A  %4d kW   %4d A  %4d kW",
+        gIndex + 1,
+        psu_index,
+        (ShmPsuData->PsuGroup[group].PsuModule[gIndex].PresentOutputVoltage / 10),
+        (ShmPsuData->PsuGroup[group].PsuModule[gIndex].PresentOutputVoltage % 10),
+        (ShmPsuData->PsuGroup[group].PsuModule[gIndex].PresentOutputCurrent / 10),
+        (ShmPsuData->PsuGroup[group].PsuModule[gIndex].PresentOutputCurrent % 10),
+        _power,
+        (ShmPsuData->PsuGroup[group].PsuModule[gIndex].IAvailableCurrent / 10),
+        (ShmPsuData->PsuGroup[group].PsuModule[gIndex].AvailablePower / 10));
+
+    int CriticalTemp1 = 0, CriticalTemp2 = 0, CriticalTemp3 = 0, InletTemp = 0, OutletTemp = 0, InletTemp_1 = 0, InletTemp_2 = 0;
+    CriticalTemp1 = (int)ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp1 - 60;
+    CriticalTemp2 = (int)ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp2 - 60;
+    CriticalTemp3 = (int)ShmPsuData->PsuGroup[group].PsuModule[gIndex].CriticalTemp3 - 60;
+    InletTemp = (int)ShmPsuData->PsuGroup[group].PsuModule[gIndex].InletTemp - 60;
+    OutletTemp = (int)ShmPsuData->PsuGroup[group].PsuModule[gIndex].OutletTemp - 60;
+    InletTemp_1 = (int)ShmPsuData->PsuGroup[group].PsuModule[gIndex].InletTemp_1 - 60;
+    InletTemp_2 = (int)ShmPsuData->PsuGroup[group].PsuModule[gIndex].InletTemp_2 - 60;
+
+    printf("   %4d    %4d / %4d  %4d / %4d   %4d / %4d",
+        CriticalTemp1, InletTemp, OutletTemp, InletTemp_1, InletTemp_2, CriticalTemp2, CriticalTemp3);
+
+    printf("  |   %d%d%d%d\r\n",
+        ShmPsuPosition->SinglePsuStatus[psu_index].bits.Lock,
+        ShmPsuPosition->SinglePsuStatus[psu_index].bits.Alarm,
+        ShmPsuPosition->SinglePsuStatus[psu_index].bits.Fault,
+        ShmPsuPosition->SinglePsuStatus[psu_index].bits.Output);
+
+    return 1;
+}
+
+// Group  Psu   Out_Vol   Out_Cur  Out_Pow  Ava_Cur  Ava_Pow  Ambient   Liq_In_Out  DD_In 1 & 2  DD_Out 1 & 2   OR_LAFO  AND_LAFO
+//  G-X     4  XXXX.X V  XXXX.X A  XXXX kW   XXXX A  XXXX kW                                                   |   XXXX  |   XXXX
+//  G-X     0     N/A        N/A      N/A      N/A      N/A
+//   X      0  XXXX.X V  XXXX.X A  XXXX kW   XXXX A  XXXX kW   XXXX    XXXX / XXXX  XXXX / XXXX   XXXX / XXXX  |   XXXX  |   XXXX
+
+// Group  Out_Vol   Out_Cur  Out_Pow  Ava_Cur  Ava_Pow     Version  Ambient   Liq_In_Out  DD_In 1 & 2  DD_Out 1 & 2   OR_LAFO  AND_LAFO
+//  G-X  XXXX.X V  XXXX.X A  XXXX kW   XXXX A  XXXX kW,  Total: XX                                                   |   XXXX  |   XXXX
+//  G-X    N/A        N/A      N/A      N/A      N/A
+//   X   XXXX.X V  XXXX.X A  XXXX kW   XXXX A  XXXX kW  XXXXXXXXXX   XXXX    XXXX / XXXX  XXXX / XXXX   XXXX / XXXX  |   XXXX  |   XXXX
+int ShowPsuInfo(void)
+{
+    int line = 2;
+    printf("                                                                      PFC  &  DD\r\n");
+    printf(" Group  Psu   Out_Vol   Out_Cur  Out_Pow  Ava_Cur  Ava_Pow  Ambient   Liq_In_Out  DD_In 1 & 2  DD_Out 1 & 2   OR_LAFO  AND_LAFO\r\n");
+
+    for(int i = 0; i < CONNECTOR_QUANTITY; i++)
+    {
+        line += ShowPsuGroupInfo(i);
+        if(ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity > 0)
+        {
+            for(int j = 0; j < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; j++)
+            {
+                int psu_index = ShmPsuPosition->GroupLocationInfo[i].PsuIndex[j];
+                line += ShowSinglePsuInfo(psu_index);
+            }
+        }
+    }
+    return line;
+}
+
+void PsuCmd(char *inputCmd, unsigned int opt)
+{
+    bool keepRun = false;
+    bool reflash = false;
+    int reflashLine = 0;
+    int time = 0;
+    struct timespec _Loop_time;
+
+    if((opt & OPTION_REFLASH) || (opt & OPTION_LOOP) > 0)
+    {
+        keepRun = true;
+    }
+
+    int totalCnt = 0, maxPara = 0;
+
+    maxPara = 1;
+    totalCnt = GetSubCommand(inputCmd);
+
+    if(totalCnt != maxPara)
+    {
+        printf("Input cmd fail ------  psu [count | ver | cap | input | output | info]\r\n\r\n");
+        return;
+    }
+
+    printf("\r\n");
+    do
+    {
+        time = GetTimeoutValue(_Loop_time) / mSEC_VAL;
+        if(time >= 1000)
+        {
+            if(reflash && reflashLine > 0)
+            {
+                ConsoleReflash(1, reflashLine);
+            }
+
+            if(strcmp(&MultiSubCmd[0][0], "info") == EQUAL)
+            {
+                reflashLine = ShowPsuInfo();
+            }
+            else if(strcmp(&MultiSubCmd[0][0], "count") == EQUAL)
+            {
+                reflashLine = ShowPsuCount();
+            }
+            else if(strcmp(&MultiSubCmd[0][0], "ver") == EQUAL)
+            {
+                reflashLine = ShowPsuVersion();
+            }
+            else if(strcmp(&MultiSubCmd[0][0], "cap") == EQUAL)
+            {
+                reflashLine = ShowPsuCap();
+            }
+            else if(strcmp(&MultiSubCmd[0][0], "input") == EQUAL)
+            {
+                reflashLine = ShowPsuInput();
+            }
+            else if(strcmp(&MultiSubCmd[0][0], "output") == EQUAL)
+            {
+                reflashLine = ShowPsuOutput();
+            }
+            else
+            {
+                printf("Input cmd parsing fail ------  psu [count | ver | cap | input | output | info]\r\n");
+                keepRun = false;
+            }
+
+            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];
@@ -5161,10 +5634,10 @@ int main(void)
 			//GetFwVerProc(newString[1]);
 			ShowFwVer();
 		}
-		else if (strcmp(newString[0], "update") == 0)
+        else if(strcmp(mainCmd, "update") == 0)
 		{
 		    // 更新
-			FwUpdateFlagProc(newString[1]);
+			FwUpdateFlagProc(subCmd, option);
 		}
 		else if (strcmp(newString[0], "ac") == 0)
 		{
@@ -5223,17 +5696,9 @@ int main(void)
 		    // 取得三向輸入電壓
 			GetInputVol(subCmd, option);
 		}
-		else if(strcmp(newString[0], "psu") == 0)
+		else if(strcmp(mainCmd, "psu") == 0)
 		{
-		    //如果連一個參數都沒有 (此命令不理會) 加上判斷第二參數
-			if (strcmp(newString[1], "-1") == 0 || strcmp(newString[1], "") == 0)
-			{
-				printf ("PSU : Param fail..Please retry again......\n");
-				continue;
-			}
-
-			// 取得 PSU 資訊
-			GetPsuInformation(newString[1], newString[2], newString[3]);
+		    PsuCmd(subCmd, option);
 		}
 		else if (strcmp(newString[0], "cap") == 0)
 		{
@@ -5432,6 +5897,14 @@ int main(void)
         else if(strcmp(mainCmd, "price") == 0)
         {
             ShowPrice(subCmd, option);
+        }
+        else if(strcmp(mainCmd, "parking") == 0)
+        {
+            OccupancyCmd(subCmd, option);
+        }
+        else if(strcmp(mainCmd, "occupancy") == 0)
+        {
+            ShowOccupancy(subCmd, option);
         }
 		else
 		{

BIN
EVSE/Projects/DO360/Apps/libInfyGroup_PsuCommObj.a


BIN
EVSE/Projects/DO360/Apps/libPhGroup_PsuCommObj.a


File diff suppressed because it is too large
+ 628 - 107
EVSE/Projects/DO360/Apps/main.c


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


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


Some files were not shown because too many files changed in this diff