#include "Module_PsuComm.h" #define Debug #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 float maxChargingVol = 5000; // 限制最大充電電壓,如依照模塊則填上 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 getAvailableCapOffset = 5; byte deratingKeepCount = 0; float carReqVol = 0; float carReqCur = 0; float evseOutVol = 0; float evseOutCur = 0; int cmdDelayTime = 60000; int StoreLogMsg(const char *fmt, ...); unsigned long GetTimeoutValue(struct timeval _sour_time); #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) { 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; } //================================= // 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); } } //================================= // Alarm code mapping to share memory Function //================================= void AbnormalStopAnalysis(byte gun_index, byte *errCode) { char string[7]; sprintf(string, "%d%d%d%d%d%d", *(errCode + 5), *(errCode + 4), *(errCode + 3), *(errCode + 2), *(errCode + 1), *(errCode + 0)); // if (gun_index < _gunCount) // { // if (strlen((char *)ShmSysConfigAndInfo->SysStopChargingAlarmCode.StopCode[gun_index]) <= 0) // { // memcpy(&ShmSysConfigAndInfo->SysStopChargingAlarmCode.StopCode[gun_index][0], string, 7); // ShmSysConfigAndInfo->SysStopChargingAlarmCode.Level = 0x00; // } // } printf("PSU Alarm code = %s \n", errCode); } //================================= // 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("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, (char *)ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].SerialNumber, ShmPsuData->PsuGroup[group].PsuModule[ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity].Address, 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; } void GetPsuRequestCallback(byte phy_id, char *serial_number) { if (ShmSysConfigAndInfo->SysInfo.AcContactorStatus == NO) return; // ********************** 每次送電後,需判斷要把所有的模塊分配到哪個 Group ********************** byte group = 0; if(ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING || _gunCount == 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("get psu********id = %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 = 0x03; } 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); byte isFind = false; for (byte index = 0; index < conn_1_count; index++) { printf("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("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; } } } ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity++; PsuAddressAssignment(phy_id, serial_number, ShmPsuData->SystemPresentPsuQuantity, group); ShmPsuData->GroupCount = CHAdeMO_QUANTITY + CCS_QUANTITY + GB_QUANTITY; } } void SaveStatusCallback(byte group, byte address, int alarm, int fault) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].AlarmCode = alarm; ShmPsuData->PsuGroup[group].PsuModule[index].FaultCode = fault; //printf("index = %d, alarm = %d, fault = %d \n", index, alarm, fault); break; } } } void SaveAlarmNotifyCallback(byte group, byte address, unsigned char *alarm) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { AbnormalStopAnalysis(group, alarm); break; } } } void SaveFaultNotifyCallback(byte group, byte address, int fault) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].FaultCode = fault; break; } } } void SaveFirmwareVersion(byte group, byte address, unsigned char packageIndex, unsigned char type , unsigned char *data) { for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { if (packageIndex == 0 || packageIndex == 1) strncpy((char *)ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion + (packageIndex * 6), (char *)data, 6); else strncpy((char *)ShmPsuData->PsuGroup[group].PsuModule[index].FwVersion + (packageIndex * 6), (char *)data, 4); } } if (packageIndex == 1) { char string[3]; memcpy(string, (data + 2), 2); string[2] = '\0'; for (byte i = 0; i < _gunCount; i++) { if (maxChargingVol != 0) { chargingInfo[i]->MaximumChargingVoltage = maxChargingVol; } else { if (strcmp(string, "50") == 0) chargingInfo[i]->MaximumChargingVoltage = 5000; else if (strcmp(string, "70") == 0) chargingInfo[i]->MaximumChargingVoltage = 7000; else if (strcmp(string, "75") == 0) chargingInfo[i]->MaximumChargingVoltage = 7500; else if (strcmp(string, "80") == 0) chargingInfo[i]->MaximumChargingVoltage = 8000; else if (strcmp(string, "95") == 0) chargingInfo[i]->MaximumChargingVoltage = 9500; else if (strcmp(string, "A0") == 0) chargingInfo[i]->MaximumChargingVoltage = 10000; else if (strcmp(string, "C0") == 0) chargingInfo[i]->MaximumChargingVoltage = 12000; else if (strcmp(string, "F0") == 0) chargingInfo[i]->MaximumChargingVoltage = 15000; } printf("index = %d, max vol = %f \n", i, chargingInfo[i]->MaximumChargingVoltage); } } } void SaveFanSpeedCallback(byte group, byte address, byte fan1, byte fan2, byte fan3, byte fan4) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].FanSpeed_1 = fan1; ShmPsuData->PsuGroup[group].PsuModule[index].FanSpeed_2 = fan2; ShmPsuData->PsuGroup[group].PsuModule[index].FanSpeed_3 = fan3; ShmPsuData->PsuGroup[group].PsuModule[index].FanSpeed_4 = fan4; break; } } } void SaveTemperatureCallback(byte group, byte address, char cri_temp1, char cri_temp2, char cri_temp3, char ex_temp, char in_temp1, char in_temp2, char out_temp) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].CriticalTemp1 = cri_temp1; ShmPsuData->PsuGroup[group].PsuModule[index].CriticalTemp2 = cri_temp2; ShmPsuData->PsuGroup[group].PsuModule[index].CriticalTemp3 = cri_temp3; ShmPsuData->PsuGroup[group].PsuModule[index].ExletTemp = ex_temp; ShmPsuData->PsuGroup[group].PsuModule[index].InletTemp_1 = in_temp1; ShmPsuData->PsuGroup[group].PsuModule[index].InletTemp_2 = in_temp2; ShmPsuData->PsuGroup[group].PsuModule[index].OutletTemp = out_temp; break; } } } void SavePresentInputVoltageCallback(byte group, byte address, byte vol_type, unsigned short vol1, unsigned short vol2, unsigned short vol3) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].InputVoltage_Type = vol_type; ShmPsuData->PsuGroup[group].PsuModule[index].InputVoltageL1 = vol1; ShmPsuData->PsuGroup[group].PsuModule[index].InputVoltageL2 = vol2; ShmPsuData->PsuGroup[group].PsuModule[index].InputVoltageL3 = vol3; break; } } } // 模塊輸出的電壓電流 void SavePresentOutputCallback(byte group, byte address, unsigned short out_vol, unsigned short out_cur) { unsigned short outputVol = 0; unsigned short outputCur = 0; bool isChange = false; // PSU for (int index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputVoltage = out_vol; ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputCurrent = out_cur; 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("group = %d, GroupPresentOutputVoltage = %d \n", group, ShmPsuData->PsuGroup[group].GroupPresentOutputVoltage); printf("group = %d, GroupPresentOutputCurrent = %d \n", group, ShmPsuData->PsuGroup[group].GroupPresentOutputCurrent); } void SaveAvailableCapCallback(byte group, byte address, unsigned short able_power, unsigned short able_cur) { unsigned int power = 0; unsigned int current = 0; unsigned int power_derating = 0; unsigned int current_derating = 0; bool isChange = false; for (int index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].AvailablePower = able_power; ShmPsuData->PsuGroup[group].PsuModule[index].AvailableCurrent = able_cur; isChange = true; } // 降載 if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_GET_NEW_CAP) { 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[group].PsuModule[index].AvailablePower; current += ShmPsuData->PsuGroup[group].PsuModule[index].AvailableCurrent; } 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]->AvailableChargingCurrent = ShmPsuData->PsuGroup[group].GroupAvailableCurrent; chargingInfo[group]->AvailableChargingPower = ShmPsuData->PsuGroup[group].GroupAvailablePower; chargingInfo[group]->DeratingChargingCurrent = current_derating; chargingInfo[group]->DeratingChargingPower = power_derating; printf("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 SavePresentInputCurrentCallback(byte group, byte address, unsigned short in_cur1, unsigned short in_cur2, unsigned short in_cur3) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].InputCurrentL1 = in_cur1; ShmPsuData->PsuGroup[group].PsuModule[index].InputCurrentL2 = in_cur2; ShmPsuData->PsuGroup[group].PsuModule[index].InputCurrentL3 = in_cur3; break; } } } 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; } } } void SaveStatusNotifyCallback(byte group, byte address, byte st_machine, unsigned short out_vol, unsigned short out_cur) { //EVSE for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { ShmPsuData->PsuGroup[group].PsuModule[index].StateMachine = st_machine; //ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputVoltage = out_vol; //ShmPsuData->PsuGroup[group].PsuModule[index].PresentOutputCurrent = out_cur; //printf("psu state = %d, vol = %d, cur = %d \n", st_machine, out_vol, out_cur); break; } } } void GetSerialNumberCallback(byte group, byte address, unsigned char packageIndex, unsigned char *data) { for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { strcpy((char *)ShmPsuData->PsuGroup[group].PsuModule[index].SerialNumber + (packageIndex * 7), (char *)data); break; } } } void GetOutputPowerSwitchStatusCallback(byte group, byte address, unsigned char value) { for (byte index = 0; index < ShmPsuData->PsuGroup[group].GroupPresentPsuQuantity; index++) { if (ShmPsuData->PsuGroup[group].PsuModule[index].Address == address) { //printf("PowerSwitch = %d, group = %d, address = %d \n", value, group, address); ShmPsuData->PsuGroup[group].PsuModule[index].OutputPowerSwitch = value; 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; } } 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("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("InitShareMemory OK\n"); // register callback function GetPsuAddressReq(&GetPsuRequestCallback); RefreshStatus(&SaveStatusCallback); RefreshFanSpeed(&SaveFanSpeedCallback); RefreshTemp(&SaveTemperatureCallback); RefreshInputVol(&SavePresentInputVoltageCallback); RefreshGetOutput(&SavePresentOutputCallback); RefreshAvailableCap(&SaveAvailableCapCallback); RefreshInputCur(&SavePresentInputCurrentCallback); RefreshAlarmNotify(&SaveAlarmNotifyCallback); RefreshFaultNotify(&SaveFaultNotifyCallback); RefreshStatusNotify(&SaveStatusNotifyCallback); RefreshSerialNumber(&GetSerialNumberCallback); RefreshOutputPowerSwitch(&GetOutputPowerSwitchStatusCallback); RefreshFWVersion(&SaveFirmwareVersion); //RefreshHWVersion(&SaveHardwareVersion); // initial object InitialPsuData(); Initialization(); libInitialize = InitialCommunication(); byte priorityLow = 1; //main loop while (libInitialize) { // 斷電狀態 if (ShmSysConfigAndInfo->SysInfo.AcContactorStatus == NO) { InitialPsuData(); sleep(1); ShmPsuData->Work_Step = ASSIGN_START; continue; } // update psu fw req // if(psu update req ?) // { // // continue; // } // 自檢失敗 if (ShmPsuData->Work_Step == _NO_WORKING) { DEBUG_ERROR("(PSU) self test fail. \n"); printf("(PSU) self test fail. \n"); sleep(5); } switch(ShmPsuData->Work_Step) { case ASSIGN_START: { printf("PSU ASSIGN_START........ \n"); gettimeofday(&_id_assign_time, NULL); ShmPsuData->Work_Step = ASSIGN_COMP; } break; case ASSIGN_COMP: { if (priorityLow == 1) { for (byte psuIndex = 0; psuIndex < ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity; psuIndex++) { if (ShmPsuData->PsuGroup[0].PsuModule[psuIndex].Address == NONE_CARE_ADDRESS) continue; GetStatus(0, ShmPsuData->PsuGroup[0].PsuModule[psuIndex].Address); usleep(cmdDelayTime); if (strlen((char *)ShmPsuData->PsuGroup[0].PsuModule[psuIndex].FwVersion) == 0 && ShmPsuData->PsuGroup[0].PsuModule[psuIndex].FwVersion[0] == '\0') { GetFwVersion(0, ShmPsuData->PsuGroup[0].PsuModule[psuIndex].Address, 0x02); usleep(cmdDelayTime); } if (strlen((char *)ShmPsuData->PsuGroup[0].PsuModule[psuIndex].SerialNumber) == 0 && ShmSysConfigAndInfo->SysInfo.RelayModuleFwRev[0] == '\0') { GetSerialNumber(0, ShmPsuData->PsuGroup[0].PsuModule[psuIndex].Address); usleep(cmdDelayTime); } } } priorityLow >= 20 ? priorityLow = 1 : priorityLow++; // 等待十秒 if (GetTimeoutValue(_id_assign_time) >= 15000000) { ShmPsuData->Work_Step = ENABLE_POW; } } break; case ENABLE_POW: { if (ShmSysConfigAndInfo->SysInfo.BootingStatus == BOOTTING) { // 電樁在 Booting 的狀態 - 自檢 ShmPsuData->Work_Step = _TEST_LINE_STEP; } else { ShmPsuData->Work_Step = _WORK_CHARGING; gettimeofday(&_workModePriority_time, NULL); } } break; case _TEST_LINE_STEP: { printf("cur total psu count = %d \n", ShmPsuData->SystemPresentPsuQuantity); if (ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity <= 0) { sleep(1); continue; } #if (SELF_TEST) // 對整個 Group 保持通訊 bool isFind = false; while(ShmPsuData->Work_Step != _NO_WORKING && _curCheckPsuIndexForFireLine < ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity) { GetStatus(0, NONE_CARE_ADDRESS); usleep(cmdDelayTime); GetAvailableCap(0, NONE_CARE_ADDRESS, getAvailableCapOffset); usleep(cmdDelayTime); EnableOutputPower(0, NONE_CARE_ADDRESS, OUTPUT_POWER_SWITCH_ON); usleep(cmdDelayTime); if (ShmPsuData->NeedBackTest == YES) { ShmPsuData->NeedBackTest = NO; _curCheckPsuIndexForFireLine = 0x00; } if (isFind) { GetPresentOutput(0, ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].Address); usleep(cmdDelayTime); //printf("stop vor = %d \n", ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].PresentOutputVoltage); if (ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].PresentOutputVoltage <= 200) { // 檢查下一個 _curCheckPsuIndexForFireLine++; isFind = false; } SetPresentOutput(0, ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].Address, ZERO_VOL, ZERO_CUR, chargingInfo[0]->AvailableChargingCurrent, 0x00); usleep(cmdDelayTime); } else { printf("AvailableCurrent = %d \n", ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].AvailableCurrent); if (ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].AvailableCurrent > 0) { if (ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].PresentOutputVoltage == 0) { //printf("set output vol = %d, cur = %d \n", SELF_TEST_VOL, SELF_TEST_CUR); SetPresentOutput(0, ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].Address, SELF_TEST_VOL, SELF_TEST_CUR, chargingInfo[0]->AvailableChargingCurrent, 0x00); usleep(cmdDelayTime); } if(!isCheckOutputTimeStart) { gettimeofday(&_chk_output_time, NULL); isCheckOutputTimeStart = true; } else { // 如果五秒內火線上都沒有偵測到電壓,則代表異常 if (GetTimeoutValue(_chk_output_time) >= 10000000) { // 自檢失敗 printf("self test timeout \n"); EnableOutputPower(0, NONE_CARE_ADDRESS, OUTPUT_POWER_SWITCH_OFF); usleep(cmdDelayTime); ShmPsuData->Work_Step = _NO_WORKING; continue; } } for (byte gunIndex = 0; gunIndex < _gunCount; gunIndex ++) { GetPresentOutput(0, ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].Address); usleep(cmdDelayTime); printf("Cur psu output voltage = %d \n", ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].PresentOutputVoltage); printf("Fire voltage = %f \n", chargingInfo[gunIndex]->FuseChargingVoltage); // 該模組的輸出電壓與火線上的電壓一致 if (chargingInfo[gunIndex]->FuseChargingVoltage >= 50 && ((chargingInfo[gunIndex]->FuseChargingVoltage >= ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].PresentOutputVoltage - 300) && (chargingInfo[gunIndex]->FuseChargingVoltage <= ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].PresentOutputVoltage + 300))) { // 找到火線上的電壓了,這邊紀錄火線是紀錄屬於哪一把槍的火線 if (_curCheckPsuIndexForFireLine < ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity) { // 紀錄當前 PSU 是哪個火線上的 ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].FireWireIndex = gunIndex; //recordPsuData[_curCheckPsuIndexForFireLine]._fire_index = gunIndex; //recordPsuData[_curCheckPsuIndexForFireLine]._phy_addr = ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].PhysicalID; //strcpy(recordPsuData[_curCheckPsuIndexForFireLine]._serial_num, (char *)ShmPsuData->PsuGroup[0].PsuModule[_curCheckPsuIndexForFireLine].SerialNumber); printf("Find Fire Line Number end~~~~~~~~~~~~~~~ = %d \n", gunIndex); usleep(100000); isCheckOutputTimeStart = false; isFind = true; break; } } } } } usleep(100000); } if (ShmPsuData->Work_Step != _NO_WORKING) ShmPsuData->Work_Step = _TEST_POWER_STEP; EnableOutputPower(0, NONE_CARE_ADDRESS, OUTPUT_POWER_SWITCH_OFF); usleep(cmdDelayTime); #else ShmPsuData->Work_Step = _TEST_POWER_STEP; #endif } break; case _TEST_POWER_STEP: { if(!_chkTotalCapStart) { _chkTotalCapStart = true; gettimeofday(&_chk_cap_time, NULL); } for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { GetStatus(groupIndex, NONE_CARE_ADDRESS); usleep(cmdDelayTime); GetAvailableCap(groupIndex, NONE_CARE_ADDRESS, getAvailableCapOffset); usleep(cmdDelayTime); } if (GetTimeoutValue(_chk_cap_time) >= 2000000) { printf("AvailableChargingCurrent = %f, AvailableChargingPower = %f \n", chargingInfo[0]->AvailableChargingCurrent, chargingInfo[0]->AvailableChargingPower); for (byte index = 0; index < ShmPsuData->PsuGroup[0].GroupPresentPsuQuantity; index++) { printf("index = %d, fire index = %d, phy addr = %s \n", index, ShmPsuData->PsuGroup[0].PsuModule[index].FireWireIndex, ShmPsuData->PsuGroup[0].PsuModule[index].SerialNumber); } ShmPsuData->Work_Step = _TEST_COMPLETE; } } break; case _TEST_COMPLETE: { priorityLow = 1; sleep(1); } break; case _WORK_CHARGING: { int time = GetTimeoutValue(_workModePriority_time) / 1000; // 智能分配 : 檢查該槍是否有模塊有用,有則無須重新分配直接進入充電 if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_PREPARE) { if (ShmPsuData->PsuGroup[ShmSysConfigAndInfo->SysInfo.CurGunSelected].GroupPresentPsuQuantity > 0) { printf("=============Smart Charging : _REASSIGNED_NONE============= Step 0 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_NONE; } else { printf("=============Smart Charging : _REASSIGNED_GET_NEW_CAP============= Step 2 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_GET_NEW_CAP; } } //printf("cur total psu count = %d \n", ShmPsuData->SystemPresentPsuQuantity); for (byte groupIndex = 0; groupIndex < ShmPsuData->GroupCount; groupIndex++) { // 每秒 if (time > 1000) { GetStatus(groupIndex, NONE_CARE_ADDRESS); usleep(cmdDelayTime); GetAvailableCap(groupIndex, NONE_CARE_ADDRESS, getAvailableCapOffset); 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("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("=============Smart Charging : _REASSIGNED_MAIN============= Step 3 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_MAIN; } else { deratingKeepCount++; } } } } } else deratingKeepCount = 0; if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_MAIN) { printf("=============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); if (carReqVol != chargingInfo[groupIndex]->EvBatterytargetVoltage) { carReqVol = chargingInfo[groupIndex]->EvBatterytargetVoltage; DEBUG_INFO("ev need vol = %f \n", chargingInfo[groupIndex]->EvBatterytargetVoltage); } if (carReqCur != chargingInfo[groupIndex]->EvBatterytargetCurrent) { carReqCur = chargingInfo[groupIndex]->EvBatterytargetCurrent; DEBUG_INFO("ev need cur = %f \n", chargingInfo[groupIndex]->EvBatterytargetCurrent); } if (evseOutVol != chargingInfo[groupIndex]->FireChargingVoltage) { evseOutVol = chargingInfo[groupIndex]->FireChargingVoltage; printf("evse output v index = %d, vol = %f \n", groupIndex, chargingInfo[groupIndex]->FireChargingVoltage); } if (evseOutCur != chargingInfo[groupIndex]->PresentChargingCurrent) { evseOutCur = chargingInfo[groupIndex]->PresentChargingCurrent; printf("evse output c index = %d, cur = %f \n", groupIndex, chargingInfo[groupIndex]->PresentChargingCurrent); } if (chargingInfo[groupIndex]->AvailableChargingCurrent <= 0) continue; // 針對各槍當前狀態,傳送需要回傳的資料指令 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) ) { EnableOutputPower(groupIndex, NONE_CARE_ADDRESS, OUTPUT_POWER_SWITCH_ON); usleep(cmdDelayTime); if (ShmPsuData->PsuGroup[groupIndex].GroupAvailableCurrent > 0) { if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag >= _REASSIGNED_ADJUST) { // 如果車端要求的電流超過降載,則以降載電流為主 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("=============Smart Charging : _REASSIGNED_RELAY============= Step 5 \n"); ShmSysConfigAndInfo->SysInfo.ReAssignedFlag = _REASSIGNED_RELAY; } } if (ShmSysConfigAndInfo->SysInfo.ReAssignedFlag == _REASSIGNED_ADJUST) { for(int i = 0; i < ShmPsuData->PsuGroup[groupIndex].GroupPresentPsuQuantity; i++) { printf("*********_REASSIGNED_ADJUST : groupIndex = %d, outputCur = %d, outputVol = %d \n", groupIndex, ShmPsuData->PsuGroup[groupIndex].PsuModule[i].PresentOutputCurrent, ShmPsuData->PsuGroup[groupIndex].PsuModule[i].PresentOutputVoltage); } } float targetVol = chargingInfo[groupIndex]->EvBatterytargetVoltage; float targetCur = chargingInfo[groupIndex]->EvBatterytargetCurrent; if (targetVol != 0) { if (targetCur <= 10) targetCur = 10; } else { targetVol = 0; targetCur = 0; } // 該充電槍的目標電壓與目標電流 SetPresentOutput(groupIndex, NONE_CARE_ADDRESS, targetVol, targetCur, chargingInfo[groupIndex]->DeratingChargingCurrent, 0x00); } else { printf("Set Present Output index = %d, V = %f, C = %f \n", groupIndex, chargingInfo[groupIndex]->EvBatterytargetVoltage, chargingInfo[groupIndex]->EvBatterytargetCurrent); float targetVol = chargingInfo[groupIndex]->EvBatterytargetVoltage; float targetCur = chargingInfo[groupIndex]->EvBatterytargetCurrent; if (targetVol != 0) { if (targetCur <= 10) targetCur = 10; } else { targetVol = 0; targetCur = 0; } // 該充電槍的目標電壓與目標電流 SetPresentOutput(groupIndex, NONE_CARE_ADDRESS, targetVol, targetCur, chargingInfo[groupIndex]->AvailableChargingCurrent, 0x00); } 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, 0x00); usleep(cmdDelayTime); } } priorityLow >= 200 ? priorityLow = 1 : priorityLow++; break; } } usleep(45000); } return FAIL; }