#include "Module_PsuComm.h" #define ARRAY_SIZE(A) (sizeof(A) / sizeof(A[0])) #define PASS 1 #define FAIL -1 #define YES 1 #define NO 0 #define DERATING 10 #define SELF_TEST 0 struct SysConfigAndInfo *ShmSysConfigAndInfo; struct StatusCodeData *ShmStatusCodeData; struct PsuData *ShmPsuData; void trim(char *s); int mystrcmp(char *p1,char *p2); void substr(char *dest, const char* src, unsigned int start, unsigned int cnt); void split(char **arr, char *str, const char *del); bool libInitialize = false; byte gun_count = CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY; byte getAvailableCapOffset = 5; byte deratingKeepCount = 0; float carReqVol = 0; float carReqCur = 0; float evseOutVol = 0; float evseOutCur = 0; int cmdDelayTime = 20000; void PRINTF_FUNC(char *string, ...); int StoreLogMsg(const char *fmt, ...); #define DEBUG_INFO(format, args...) StoreLogMsg("[%s:%d][%s][Info] "format, __FILE__, __LINE__, __FUNCTION__, ##args) #define DEBUG_WARN(format, args...) StoreLogMsg("[%s:%d][%s][Warn] "format, __FILE__, __LINE__, __FUNCTION__, ##args) #define DEBUG_ERROR(format, args...) StoreLogMsg("[%s:%d][%s][Error] "format, __FILE__, __LINE__, __FUNCTION__, ##args) unsigned long GetTimeoutValue(struct timeval _sour_time); unsigned long GetTimeoutValue(struct timeval _sour_time) { struct timeval _end_time; gettimeofday(&_end_time, NULL); return 1000000 * (_end_time.tv_sec - _sour_time.tv_sec) + _end_time.tv_usec - _sour_time.tv_usec; } int StoreLogMsg(const char *fmt, ...) { char Buf[4096+256]; char buffer[4096]; time_t CurrentTime; struct tm *tm; va_list args; va_start(args, fmt); int rc = vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); memset(Buf,0,sizeof(Buf)); CurrentTime = time(NULL); tm=localtime(&CurrentTime); sprintf(Buf,"echo \"%04d-%02d-%02d %02d:%02d:%02d - %s\" >> /Storage/SystemLog/[%04d.%02d]SystemLog", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec, buffer, tm->tm_year+1900,tm->tm_mon+1); system(Buf); return rc; } int DiffTimeb(struct timeb ST, struct timeb ET) { //return milli-second unsigned int StartTime,StopTime; StartTime=(unsigned int)ST.time; StopTime=(unsigned int)ET.time; return (StopTime-StartTime)*1000+ET.millitm-ST.millitm; } void PRINTF_FUNC(char *string, ...) { if (DEBUG) { va_list args; char buffer[4096]; va_start(args, string); vsnprintf(buffer, sizeof(buffer), string, args); va_end(args); printf("%s \n", buffer); } } //================================= // Common routine //================================= char* getTimeString(void) { char *result=malloc(21); time_t timep; struct tm *p; time(&timep); p=gmtime(&timep); sprintf(result, "[%04d-%02d-%02d %02d:%02d:%02d]", (1900+p->tm_year), (1+p->tm_mon), p->tm_mday, p->tm_hour, p->tm_hour, p->tm_sec); return result; } void trim(char *s) { int i=0, j, k, l=0; while((s[i]==' ')||(s[i]=='\t')||(s[i]=='\n')) i++; j = strlen(s)-1; while((s[j]==' ')||(s[j]=='\t')||(s[j]=='\n')) j--; if(i==0 && j==strlen(s)-1) { } else if(i==0) s[j+1] = '\0'; else { for(k=i; k<=j; k++) s[l++] = s[k]; s[l] = '\0'; } } int mystrcmp(char *p1,char *p2) { while(*p1==*p2) { if(*p1=='\0' || *p2=='\0') break; p1++; p2++; } if(*p1=='\0' && *p2=='\0') return(PASS); else return(FAIL); } void substr(char *dest, const char* src, unsigned int start, unsigned int cnt) { strncpy(dest, src + start, cnt); dest[cnt] = 0; } void split(char **arr, char *str, const char *del) { char *s = strtok(str, del); while(s != NULL) { *arr++ = s; s = strtok(NULL, del); } } //================================= // ReAssigned PSU Function //================================= void ReAssignedResource() { int index = 0; struct PsuModuleData PsuModule[ShmPsuData->SystemPresentPsuQuantity]; for (byte i = 0; i < 4; i++) { for(byte psuCount = 0; psuCount < ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity; psuCount++) { memcpy(&PsuModule[index], &ShmPsuData->PsuGroup[i].PsuModule[psuCount], sizeof(struct PsuModuleData)); index++; } ShmPsuData->PsuGroup[i].GroupPresentPsuQuantity = 0; } for(int i = 0; i < ShmPsuData->SystemPresentPsuQuantity; i++) { byte group = PsuModule[i].FireWireIndex; memcpy(&ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity], &PsuModule[i], sizeof(struct PsuModuleData)); PRINTF_FUNC("ReAssignedResource : PhysicalID = %d, Address = %d, group = %d \n", ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].PhysicalID, ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].Address, group); // printf("ReAssignedResource : PhysicalID = %d, Address = %d, group = %d \n", // ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].PhysicalID, // ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].Address, // group); PsuAddressAssignment(ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].PhysicalID, group); ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity++; } } //================================= // Save data to share memory Function //================================= bool FindChargingInfoData(byte target, struct ChargingInfoData **chargingData) { for (byte index = 0; index < CHAdeMO_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index].Index == target) { chargingData[target] = &ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index]; return true; } } for (byte index = 0; index < CCS_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.CcsChargingData[index].Index == target) { chargingData[target] = &ShmSysConfigAndInfo->SysInfo.CcsChargingData[index]; return true; } } for (byte index = 0; index < GB_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.GbChargingData[index].Index == target) { chargingData[target] = &ShmSysConfigAndInfo->SysInfo.GbChargingData[index]; return true; } } return false; } //================================= // Alarm code mapping to share memory Function //================================= // 檢查 Byte 中某個 Bit 的值 // _byte : 欲改變的 byte // _bit : 該 byte 的第幾個 bit unsigned char mask_table[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; unsigned char DetectBitValue(unsigned char _byte, unsigned char _bit) { return ( _byte & mask_table[_bit] ) != 0x00; } void AbnormalStopAnalysis(byte gun_index, int errCode) { for (char i = 0; i < 3; i++) { unsigned char byteIndex = (errCode >> (8 * i)) & 0xff; for (char bitIndex = 0; bitIndex < 8; bitIndex++) { if(DetectBitValue(byteIndex , bitIndex) == 1) { switch(byteIndex) { case 0: { if (bitIndex == 0) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = YES; else if (bitIndex == 5) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = YES; } break; case 1: { if (bitIndex == 1) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFailureAlarm = YES; else if (bitIndex == 2) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = YES; else if (bitIndex == 3) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = YES; else if (bitIndex == 4) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = YES; else if (bitIndex == 5) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = YES; } break; case 2: { if (bitIndex == 1) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = YES; if (bitIndex == 2) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseOnputImbalance = YES; else if (bitIndex == 3) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = YES; else if (bitIndex == 4) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = YES; else if (bitIndex == 5) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = YES; else if (bitIndex == 6) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = YES; } break; } } else { switch (byteIndex) { case 0: { if (bitIndex == 0) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuOutputShortCircuit = NO; else if (bitIndex == 5) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = NO; } break; case 1: { if (bitIndex == 1) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFailureAlarm = NO; else if (bitIndex == 2) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuProtectionAlarm = NO; else if (bitIndex == 3) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuFanFailureAlarm = NO; else if (bitIndex == 4) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuCriticalPointOTP = NO; else if (bitIndex == 5) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDcSideShutDown = NO; } break; case 2: { if (bitIndex == 1) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuDuplicateID = NO; if (bitIndex == 2) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseOnputImbalance = NO; else if (bitIndex == 3) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = NO; else if (bitIndex == 4) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuThreePhaseInputInadequate = NO; else if (bitIndex == 5) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputUVP = NO; else if (bitIndex == 6) ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuInputOVP = NO; } break; } } } } } //================================= // Callback Function //================================= void GetPsuRequestCallback(byte phy_id, char *serial_number) { if (ShmSysConfigAndInfo->SysInfo.AcContactorStatus == NO) return; // ********************** 每次送電後,需判斷要把所有的模塊分配到哪個 Group ********************** byte group = 0; if(ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING || gun_count == 1) { // 初始化狀態,則直接先分配到同個群 group = 0; } else { group = ShmSysConfigAndInfo->SysInfo.CurGunSelected; } bool isNewPsu = true; for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].PhysicalID == phy_id && strncmp((char *)ShmPsuData->PsuGroup[group].PsuModule[index].SerialNumber, serial_number, 7) == 0) { isNewPsu = false; } } if (isNewPsu) { ShmPsuData->SystemPresentPsuQuantity++; PRINTF_FUNC("get psu********Membar = %d, group = %d \n", ShmPsuData->SystemPresentPsuQuantity, group); if (ShmPsuData->Work_Step >= _TEST_LINE_STEP && ShmPsuData->Work_Step <= _TEST_COMPLETE) { // 已經進入火線上的驗證動作 //ShmPsuData->NeedBackTest = YES; } else if (ShmPsuData->Work_Step == _WORK_CHARGING) { // 一旦進入火線,分配一個不會用到的給該模塊 group++; } ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].Address = ShmPsuData->SystemPresentPsuQuantity; ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].PhysicalID = phy_id; ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].AssignID = (group >> 6) + ShmPsuData->SystemPresentPsuQuantity; strcpy((char *)ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].SerialNumber, serial_number); ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity++; byte isFind = false; for (byte index = 0; index < conn_1_count; index++) { PRINTF_FUNC("connector_1[%d] = %d, phy_id = %d \n", index, connector_1[index], phy_id); if (connector_1[index] == phy_id) { isFind = true; ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].FireWireIndex = 0; break; } } if (!isFind) { for (byte index = 0; index < conn_2_count; index++) { PRINTF_FUNC("connector_2[%d] = %d, phy_id = %d \n", index, connector_2[index], phy_id); if (connector_2[index] == phy_id) { isFind = true; ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].FireWireIndex = 1; break; } } } //PsuAddressAssignment(phy_id, serial_number, ShmPsuData->SystemPresentPsuQuantity, group); PsuAddressAssignment(phy_id, group); if (ShmPsuData->Work_Step != _WORK_CHARGING) { ShmPsuData->GroupCount = group + 1; } } } void SaveStatusCallback(byte group, byte address, char cri_temp1, int alarm) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].PhysicalID == address) { ShmPsuData->PsuGroup[group].PsuModule[index].CriticalTemp1 = cri_temp1; ShmPsuData->PsuGroup[group].PsuModule[index].AlarmCode = alarm; AbnormalStopAnalysis(group, alarm); break; } } } //模組三向輸入電壓 void SavePresentInputVoltageCallback(byte address, unsigned short vol1, unsigned short vol2, unsigned short vol3) { //EVSE //search group for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++) { //search id if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address) { //update module msg ShmPsuData->PsuGroup[groupIndex].PsuModule[index].InputVoltageL1 = vol1; ShmPsuData->PsuGroup[groupIndex].PsuModule[index].InputVoltageL2 = vol2; ShmPsuData->PsuGroup[groupIndex].PsuModule[index].InputVoltageL3 = vol3; break; } } } } // 模塊輸出的電壓電流 void SavePresentOutputCallback(byte address, unsigned short out_vol, unsigned short out_cur) { unsigned short outputVol = 0; unsigned short outputCur = 0; unsigned short group = 0; bool isChange = false; // PSU for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { for (int index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address) { //如果英飛源模組不是 ver1.09 版使用模組輸出電壓 /* if(InfyPwrModelVerIs109 == 0) { ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage = out_vol; } */ ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage = out_vol; ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputCurrent = out_cur; for (int loop = 0; loop < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; loop++) { //update voltage if (ShmPsuData->PsuGroup[groupIndex].PsuModule[loop].PresentOutputVoltage > outputVol) { outputVol = ShmPsuData->PsuGroup[groupIndex].PsuModule[loop].PresentOutputVoltage; } //update total current outputCur += ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputCurrent; group = groupIndex; isChange = true; } } /* if (ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputVoltage > outputVol) outputVol = ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputVoltage; outputCur += ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputCurrent; */ } } if (isChange) { // PSU Group // 電壓 ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage = outputVol; // 電流 ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent = outputCur; //EVSE - 槍端的輸出電壓 chargingInfo[group]->PresentChargingVoltage = ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage; //EVSE - 槍端的輸出電流 chargingInfo[group]->PresentChargingCurrent = ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent; } //printf("GroupPresentOutputVoltage = %d \n", ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage); //printf("GroupPresentOutputCurrent = %d \n", ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent); } //PSU able_power = KW (單位 0.1) exp. 300 = 30kw //PSU able_cur = A (單位 0.1) exp. 400 = 40A void SaveAvailableCapCallback(byte address, unsigned short maxv, unsigned short minv, unsigned short able_cur, unsigned short able_power) { unsigned int power = 0; unsigned int current = 0; unsigned int power_derating = 0; unsigned int current_derating = 0; unsigned int group = 0; bool isChange = false; //bool sameGroup = false; //search group //printf("GroupCount = %d \n", ShmPsuData->GroupCount); for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { //printf("GroupPresentPsuQuantity = %d \n", ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity); for (int index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++) { //search group-id //printf("PhysicalID = %d, address = %d \n", ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID, address); if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address) { //先更新該模組資訊 ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailablePower = able_power; //電壓在 150V 時使用額定電流 if(ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage < 1500) { ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailableCurrent = able_cur; } //如果英飛源模組不是 ver1.09 版 或 (如果英飛源模組是 ver1.09 版但回應可輸出電流有誤則使用額定報文可輸出電流) /* if(InfyPwrModelVerIs109 == 0 || (InfyPwrModelVerIs109 == 1 && ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailableCurrent == 0)) { ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailableCurrent = able_cur; } */ //該對應的模組群重新計算總合 for (int loop = 0; loop < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; loop++) { // 降載 // if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP && // ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_COMP) // { // if (ShmPsuData->PsuGroup[group].PsuModule[index].FireWireIndex == group) // { // power_derating += ShmPsuData->PsuGroup[group].PsuModule[index].AvailablePower; // current_derating += ShmPsuData->PsuGroup[group].PsuModule[index].AvailableCurrent; // } // } power += ShmPsuData->PsuGroup[groupIndex].PsuModule[loop].AvailablePower; current += ShmPsuData->PsuGroup[groupIndex].PsuModule[loop].AvailableCurrent; group = groupIndex; isChange = true; } } } } if (current_derating == 0) { current_derating = current; } if (power_derating == 0) { power_derating = power; } if (isChange) { // PSU Group // Available Power ShmPsuData->PsuGroup[group].GroupAvailablePower = power; // Available Current ShmPsuData->PsuGroup[group].GroupAvailableCurrent = current; chargingInfo[group]->MaximumChargingVoltage = maxv; chargingInfo[group]->AvailableChargingCurrent = ShmPsuData->PsuGroup[group].GroupAvailableCurrent; chargingInfo[group]->AvailableChargingPower = ShmPsuData->PsuGroup[group].GroupAvailablePower; chargingInfo[group]->DeratingChargingCurrent = current_derating; chargingInfo[group]->DeratingChargingPower = power_derating; PRINTF_FUNC("group = %d, AvailableChargingCurrent = %f, GroupAvailablePower = %f, DeratingChargingCurrent = %f, DeratingChargingPower = %f \n", group, chargingInfo[group]->AvailableChargingCurrent, chargingInfo[group]->AvailableChargingPower, chargingInfo[group]->DeratingChargingCurrent, chargingInfo[group]->DeratingChargingPower); } } void GetBarCodeCallback(byte address, char *serial_number , unsigned short module_ver) { //EVSE for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address) { ShmPsuData->PsuGroup[groupIndex].PsuModule[index].FwVersion[0] = (module_ver >> 8) & 0xFF; ShmPsuData->PsuGroup[groupIndex].PsuModule[index].FwVersion[1] = (module_ver) & 0xFF; //strcpy((char *)ShmPsuData->PsuGroup[groupIndex].PsuModule[ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity].SerialNumber, serial_number); } } } } void GetMiscInfoCallback(byte address, unsigned short CmdType , unsigned int value) { //EVSE for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address) { if(CmdType == MISC_REQCMD_DC_BOARD_TMP){ //數值未處理 ShmPsuData->PsuGroup[groupIndex].PsuModule[index].CriticalTemp2 = (byte)value; }else if(CmdType == MISC_REQCMD_PFC_BOARD_TMP){ //數值未處理 ShmPsuData->PsuGroup[groupIndex].PsuModule[index].CriticalTemp3 = (byte)value; }else if(CmdType == MISC_REQCMD_FAN_SPEED){ //數值未處理 ShmPsuData->PsuGroup[groupIndex].PsuModule[index].FanSpeed_1 = (unsigned short)value; } } } } //暫定如果有回 misc 就認定英飛源為 1.9 版 //InfyPwrModelVerIs109 = 1; //printf("Get Misc : %d \n",InfyPwrModelVerIs109); } void SaveHardwareVersion(byte group, byte address, int hw_ver) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion[0] = (hw_ver >> 24) & 0xFF; ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion[1] = (hw_ver >> 16) & 0xFF; ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion[2] = (hw_ver >> 8) & 0xFF; ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion[3] = hw_ver & 0xFF; break; } } } //Vext 模組二極體後電壓 //Iavail 模組目前因環境因素的真實能輸出電流 void SavePresentModeleVextIavailCallback(byte address, unsigned short Vext, unsigned short Iavail) { //EVSE //search group for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++) { //search id if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address) { //update module msg //ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage = Vext; // if(ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PresentOutputVoltage >= 1500) { ShmPsuData->PsuGroup[groupIndex].PsuModule[index].AvailableCurrent = Iavail; } //printf("Vext = %d I = %d \n", Vext,Iavail); break; } } } } void GetOutputPowerSwitchStatusCallback(byte address, unsigned char value) { for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { for (byte index = 0; index < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[groupIndex].PsuModule[index].PhysicalID == address) { //printf("PowerSwitch = %d, group = %d, address = %d \n", value, group, address); if(value){ ShmPsuData->PsuGroup[groupIndex].PsuModule[index].OutputPowerSwitch = 0x00; }else{ ShmPsuData->PsuGroup[groupIndex].PsuModule[index].OutputPowerSwitch = 0x01; } break; } } } } //========================================== // Init all share memory //========================================== int InitShareMemory() { int result = PASS; int MeterSMId; //creat ShmSysConfigAndInfo if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0) { #ifdef SystemLogMessage DEBUG_ERROR("shmget ShmSysConfigAndInfo NG %d \n"); #endif result = FAIL; } else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage DEBUG_ERROR("shmat ShmSysConfigAndInfo NG \n"); #endif result = FAIL; } else {} //creat ShmStatusCodeData if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData), 0777)) < 0) { #ifdef SystemLogMessage DEBUG_ERROR("shmget ShmStatusCodeData NG \n"); #endif result = FAIL; } else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage DEBUG_ERROR("shmat ShmStatusCodeData NG \n"); #endif result = FAIL; } else {} //creat ShmPsuData if ((MeterSMId = shmget(ShmPsuKey, sizeof(struct PsuData), 0777)) < 0) { #ifdef SystemLogMessage DEBUG_ERROR("shmget ShmPsuData NG \n"); #endif result = FAIL; } else if ((ShmPsuData = shmat(MeterSMId, NULL, 0)) == (void *) -1) { #ifdef SystemLogMessage DEBUG_ERROR("shmat ShmPsuData NG \n"); #endif result = FAIL; } memset(ShmPsuData,0,sizeof(struct PsuData)); return result; } //================================================ // Main process //================================================ void InitialPsuData() { ShmPsuData->SystemPresentPsuQuantity = 0; for (byte _groupCount = 0; _groupCount < ARRAY_SIZE(ShmPsuData->PsuGroup); _groupCount++) { ShmPsuData->PsuGroup[_groupCount].GroupPresentPsuQuantity = 0; ShmPsuData->PsuGroup[_groupCount].GroupAvailablePower = 0; ShmPsuData->PsuGroup[_groupCount].GroupAvailableCurrent = 0; } ShmPsuData->Work_Step = _INIT_PSU_STATUS; } void Initialization() { bool isPass = false; while(!isPass) { isPass = true; for (byte _index = 0; _index < _gunCount; _index++) { if (!FindChargingInfoData(_index, &chargingInfo[0])) { DEBUG_ERROR("EvComm (main) : FindChargingInfoData false \n"); isPass = false; break; } } } conn_1_count = sizeof(connector_1)/sizeof(connector_1[0]); conn_2_count = sizeof(connector_2)/sizeof(connector_2[0]); } int main(void) { PRINTF_FUNC("Psu Task boot .... \n"); if(InitShareMemory() == FAIL) { #ifdef SystemLogMessage DEBUG_ERROR("InitShareMemory NG\n"); #endif if(ShmStatusCodeData != NULL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory = 1; } sleep(5); return 0; } PRINTF_FUNC("InitShareMemory OK\n"); // register callback function GetPsuAddressReq(&GetPsuRequestCallback); RefreshSerialNumber(&GetBarCodeCallback); RefreshVextAndIavail(&SavePresentModeleVextIavailCallback); RefreshMiscInfo(&GetMiscInfoCallback); RefreshStatus(&SaveStatusCallback); RefreshInputVol(&SavePresentInputVoltageCallback); RefreshGetOutput(&SavePresentOutputCallback); RefreshAvailableCap(&SaveAvailableCapCallback); RefreshOutputPowerSwitch(&GetOutputPowerSwitchStatusCallback); // initial object InitialPsuData(); Initialization(); libInitialize = InitialCommunication(); byte priorityLow = 1; byte isInitialComp = NO; //main loop while (libInitialize) { // 斷電狀態 if (ShmSysConfigAndInfo->SysInfo.AcContactorStatus == NO) { //一但 AC Off PSU 斷電全部的 PSU Group ID 會全部清 0 if (!isInitialComp) { InitialPsuData(); ShmPsuData->Work_Step = ASSIGN_START; isInitialComp = YES; } sleep(1); continue; } else isInitialComp = NO; // update psu fw req // if(psu update req ?) // { // // continue; // } // 自檢失敗 if (ShmPsuData->Work_Step == _NO_WORKING) { PRINTF_FUNC("== PSU == self test fail. \n"); sleep(5); } switch(ShmPsuData->Work_Step) { case ASSIGN_START: { PRINTF_FUNC("== PSU == ASSIGN_COMP \n"); sleep(5); gettimeofday(&_id_assign_time, NULL); ShmPsuData->Work_Step = ASSIGN_COMP; } break; case ASSIGN_COMP: { if (priorityLow == 1) { //如果還未取得模組數量 if(ShmPsuData->SystemPresentPsuQuantity == 0) { EnableDipAddrMode(); usleep(cmdDelayTime); //發送取得目前全部模組數量 (英飛源開機須等待讓模組互相通訊) RequestModuleTotalMumbert(); usleep(cmdDelayTime); } //己取得模組數量 (目前還未分配群組所以都使用預設 0) else { for (byte psuIndex = 0; psuIndex < ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity; psuIndex++) { //get status GetStatus(0, NONE_CARE_ADDRESS); usleep(cmdDelayTime); //get barcode & ver GetSerialNumber(0, NONE_CARE_ADDRESS); usleep(cmdDelayTime); GetMiscInfo(0, NONE_CARE_ADDRESS, MISC_REQCMD_DC_BOARD_TMP); usleep(cmdDelayTime); GetMiscInfo(0, NONE_CARE_ADDRESS, MISC_REQCMD_PFC_BOARD_TMP); usleep(cmdDelayTime); GetMiscInfo(0, NONE_CARE_ADDRESS, MISC_REQCMD_PFC_BOARD_TMP); usleep(cmdDelayTime); } } //printf("Get Misc2 : %d \n",InfyPwrModelVerIs109); } priorityLow >= 20 ? priorityLow = 1 : priorityLow++; // 等待 10 秒 if (GetTimeoutValue(_id_assign_time) >= 10000000) { ShmPsuData->Work_Step = ENABLE_POW; PRINTF_FUNC("INFYPWR Num = %d \n", ShmPsuData->SystemPresentPsuQuantity); PRINTF_FUNC("== PSU == ENABLE_POW \n"); } } break; case ENABLE_POW: { if (ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING) { // 電樁在 Booting 的狀態 - 自檢 PRINTF_FUNC("== PSU == _TEST_LINE_STEP \n"); ShmPsuData->Work_Step = _TEST_LINE_STEP; } else { PRINTF_FUNC("== PSU == _WORK_CHARGING \n"); ShmPsuData->Work_Step = _WORK_CHARGING; gettimeofday(&_workModePriority_time, NULL); } } break; case _TEST_LINE_STEP: { PRINTF_FUNC("cur total psu count = %d \n", ShmPsuData->SystemPresentPsuQuantity); if (ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity <= 0) { sleep(1); // 顯示錯誤 ShmStatusCodeData->AlarmCode.AlarmEvents.bits.PsuNoResource = YES; continue; } ShmPsuData->Work_Step = _TEST_POWER_STEP; } break; case _TEST_POWER_STEP: { if(!_chkTotalCapStart) { _chkTotalCapStart = true; gettimeofday(&_chk_cap_time, NULL); } // 初始化、關閉所有的模塊 //EnableOutputPower(0, NONE_CARE_ADDRESS, SWITCH_OFF); for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { GetStatus(groupIndex, NONE_CARE_ADDRESS); usleep(cmdDelayTime); } for (byte psuCount = 0; psuCount < ShmPsuData->SystemPresentPsuQuantity; psuCount++) { GetAvailableCap(psuCount, NONE_CARE_ADDRESS, 0); } usleep(cmdDelayTime); if (GetTimeoutValue(_chk_cap_time) >= 2000000) { PRINTF_FUNC("AvailableChargingCurrent = %f, AvailableChargingPower = %f \n", chargingInfo[0]->AvailableChargingCurrent, chargingInfo[0]->AvailableChargingPower); for (byte index = 0; index < ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity; index++) { PRINTF_FUNC("index = %d, fire index = %d, phy addr = %d \n", index, recordPsuData[index]._fire_index, recordPsuData[index]._phy_addr); } PRINTF_FUNC("== PSU == TEST_COMPLETE \n"); ShmPsuData->Work_Step = _TEST_COMPLETE; } } break; case _TEST_COMPLETE: { priorityLow = 1; sleep(1); } break; case _WORK_CHARGING: { int time = GetTimeoutValue(_workModePriority_time) / 1000; //printf("GroupCount = %d \n", ShmPsuData->GroupCount); //printf("cur total psu count = %d \n", ShmPsuData->SystemPresentPsuQuantity); // 智能分配 : 檢查該槍是否有模塊有用,有則無須重新分配直接進入充電 if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE) { if (ShmPsuData->PsuGroup[ShmSysConfigAndInfo->SysInfo.CurGunSelected].GroupPresentPsuQuantity > 0) { PRINTF_FUNC("=============Smart Charging : _REASSIGNED_NONE============= Step 0 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE; } else { PRINTF_FUNC("=============Smart Charging : _REASSIGNED_GET_NEW_CAP============= Step 2 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_GET_NEW_CAP; } } if (time > 1000) { for (byte psuCount = 0; psuCount < ShmPsuData->GroupCount; psuCount++) { GetAvailableCap(psuCount, NONE_CARE_ADDRESS, 0); } usleep(cmdDelayTime); } for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { if (time > 1000) { GetStatus(groupIndex, NONE_CARE_ADDRESS); usleep(cmdDelayTime); /* GetMiscInfo(SET_GROUP_CMD, 0, MISC_REQCMD_DC_BOARD_TMP); usleep(cmdDelayTime); GetMiscInfo(SET_GROUP_CMD, 0, MISC_REQCMD_PFC_BOARD_TMP); usleep(cmdDelayTime); GetMiscInfo(SET_GROUP_CMD, 0, MISC_REQCMD_PFC_BOARD_TMP); usleep(cmdDelayTime); */ // if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_GET_NEW_CAP) // { // if (groupIndex != ShmSysConfigAndInfo->SysInfo.CurGunSelected) // { // if (chargingInfo[groupIndex]->SystemStatus >= S_CHARGING && chargingInfo[groupIndex]->SystemStatus <= S_COMPLETE) // { // if (chargingInfo[groupIndex]->DeratingChargingCurrent < chargingInfo[groupIndex]->AvailableChargingCurrent) // { // // 車端需求電流降低至降載的電流 // PRINTF_FUNC("Smart Charging : index = %d, EvBatterytargetCurrent = %f, DeratingChargingCurrent = %f \n", // groupIndex, chargingInfo[groupIndex]->EvBatterytargetCurrent, chargingInfo[groupIndex]->DeratingChargingCurrent); // // if ((chargingInfo[groupIndex]->EvBatterytargetCurrent <= chargingInfo[groupIndex]->DeratingChargingCurrent) || // deratingKeepCount >= DERATING) // { // // 車端降載完成 // PRINTF_FUNC("=============Smart Charging : _REASSIGNED_MAIN============= Step 3 \n"); // ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_MAIN; // } // else // { // deratingKeepCount++; // } // } // } // } // } // else // deratingKeepCount = 0; // // if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_MAIN) // { // PRINTF_FUNC("=============Smart Charging : _REASSIGNED_ADJUST============= Step 4 \n"); // //重新分配模組 // ReAssignedResource(); // gettimeofday(&_derating_time, NULL); // ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_ADJUST; // } gettimeofday(&_workModePriority_time, NULL); } GetPresentOutput(groupIndex, NONE_CARE_ADDRESS); usleep(cmdDelayTime); //GetVextAndIavail(SET_MODULE_CMD, 0); if (chargingInfo[groupIndex]->EvBatterytargetVoltage > 0 && carReqVol != chargingInfo[groupIndex]->EvBatterytargetVoltage) { carReqVol = chargingInfo[groupIndex]->EvBatterytargetVoltage; DEBUG_INFO("ev need vol = %f \n", chargingInfo[groupIndex]->EvBatterytargetVoltage); } if (chargingInfo[groupIndex]->EvBatterytargetCurrent > 0 && carReqCur != chargingInfo[groupIndex]->EvBatterytargetCurrent) { carReqCur = chargingInfo[groupIndex]->EvBatterytargetCurrent; DEBUG_INFO("ev need cur = %f \n", chargingInfo[groupIndex]->EvBatterytargetCurrent); } if (chargingInfo[groupIndex]->FireChargingVoltage > 0 && evseOutVol != chargingInfo[groupIndex]->FireChargingVoltage) { evseOutVol = chargingInfo[groupIndex]->FireChargingVoltage; PRINTF_FUNC("groupIndex = %d, evse output vol = %f \n", groupIndex, chargingInfo[groupIndex]->FireChargingVoltage); } if (chargingInfo[groupIndex]->PresentChargingCurrent > 0 && evseOutCur != chargingInfo[groupIndex]->PresentChargingCurrent) { evseOutCur = chargingInfo[groupIndex]->PresentChargingCurrent; PRINTF_FUNC("groupIndex = %d, evse output cur = %f \n", groupIndex, chargingInfo[groupIndex]->PresentChargingCurrent); } // 針對各槍當前狀態,傳送需要回傳的資料指令 if (((chargingInfo[groupIndex]->SystemStatus >= S_PREPARING_FOR_EVSE && chargingInfo[groupIndex]->SystemStatus <= S_CHARGING) && chargingInfo[groupIndex]->RelayK1K2Status) || chargingInfo[groupIndex]->SystemStatus == S_REASSIGN || (chargingInfo[groupIndex]->SystemStatus >= S_CCS_PRECHARGE_ST0 && chargingInfo[groupIndex]->SystemStatus <= S_CCS_PRECHARGE_ST1)) { if (ShmPsuData->PsuGroup[groupIndex].GroupAvailableCurrent > 0) { // if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST && // ShmSysConfigAndInfo->SysInfo.ReAssignedFlag < _REASSIGNED_COMP ) // { // // 如果車端要求的電流超過降載,則以降載電流為主 // if (chargingInfo[groupIndex]->EvBatterytargetCurrent >= chargingInfo[groupIndex]->DeratingChargingCurrent) // { // chargingInfo[groupIndex]->EvBatterytargetCurrent = chargingInfo[groupIndex]->DeratingChargingCurrent; // } // // if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_ADJUST) // { // deratingTime = GetTimeoutValue(_derating_time) / 1000; // if (deratingTime > 3000) // { // deratingTime = 0; // PRINTF_FUNC("=============Smart Charging : _REASSIGNED_RELAY============= Step 5 \n"); // ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY; // } // // for(int i = 0; i < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; i++) // { // PRINTF_FUNC("*********_REASSIGNED_ADJUST : groupIndex = %d, outputCur = %d, outputVol = %d \n", // groupIndex, // ShmPsuData->PsuGroup[groupIndex].PsuModule[i].PresentOutputCurrent, // ShmPsuData->PsuGroup[groupIndex].PsuModule[i].PresentOutputVoltage); // } // } // // // 該充電槍的目標電壓與目標電流 // SetPresentOutput(groupIndex, NONE_CARE_ADDRESS, // chargingInfo[groupIndex]->EvBatterytargetVoltage, // chargingInfo[groupIndex]->EvBatterytargetCurrent, // chargingInfo[groupIndex]->DeratingChargingCurrent); // usleep(cmdDelayTime); // } // else { // 該充電槍的目標電壓與目標電流 SetPresentOutput(groupIndex, NONE_CARE_ADDRESS, chargingInfo[groupIndex]->EvBatterytargetVoltage, chargingInfo[groupIndex]->EvBatterytargetCurrent, chargingInfo[groupIndex]->AvailableChargingCurrent); usleep(cmdDelayTime); } } if (chargingInfo[groupIndex]->EvBatterytargetVoltage == 0) { EnableOutputPower(groupIndex, NONE_CARE_ADDRESS, SWITCH_OFF); usleep(cmdDelayTime); EnableGreenLedFlash(groupIndex , NONE_CARE_ADDRESS , SWITCH_OFF); usleep(cmdDelayTime); } else { EnableOutputPower(groupIndex, NONE_CARE_ADDRESS, SWITCH_ON); usleep(cmdDelayTime); EnableGreenLedFlash(groupIndex , NONE_CARE_ADDRESS, SWITCH_ON); usleep(cmdDelayTime); } } else if (chargingInfo[groupIndex]->SystemStatus >= S_TERMINATING && chargingInfo[groupIndex]->SystemStatus <= S_COMPLETE) { SetPresentOutput(groupIndex, NONE_CARE_ADDRESS, ZERO_VOL, ZERO_CUR, chargingInfo[groupIndex]->AvailableChargingCurrent); usleep(cmdDelayTime); EnableGreenLedFlash(groupIndex , NONE_CARE_ADDRESS , SWITCH_OFF); usleep(cmdDelayTime); EnableOutputPower(groupIndex, NONE_CARE_ADDRESS, SWITCH_OFF); usleep(cmdDelayTime); } } priorityLow >= 200 ? priorityLow = 1 : priorityLow++; break; } } } return FAIL; }