/* * Module_PowerSharing.c * * Created on: 2020/12/07 * Author: foluswen */ #include "Module_PowerSharing.h" //----------------------------------------------------------------------------- #define MODPS_FW_VER_TYPE_FORMAL //V0.XX //#define MODPS_FW_VER_TYPE_TEST //T0.XX //#define MODPS_FW_VER_NUM (1) //V/T0.01 //#define MODPS_FW_DATE ("20220730") //#define MODPS_FW_VER_NUM (2) //V/T0.02 //#define MODPS_FW_DATE ("20220815") #define MODPS_FW_VER_NUM (3) //V/T0.03 #define MODPS_FW_DATE ("20220908") //----------------------------------------------------------------------------- #if (MODPS_FW_VER_NUM >= 1) #define MODIFY_MODPS_BALANCE_CHECK_LOOP #define FUNC_MODPS_APPEND_LOG #endif //----------------------------------------------------------------------------- #if (MODPS_FW_VER_NUM >= 2) #define MODIFY_MODPS_LET_ON_HAND_ALL_USED #define MODIFY_MODPS_REDUCE_DEBUG_LOG #define FUNC_MODPS_WATCH_MODE #endif //----------------------------------------------------------------------------- #if (MODPS_FW_VER_NUM >= 3) //Fix: Variable used by DC Model (PresentChargingPower), unit of it is kW, not W #endif //----------------------------------------------------------------------------- #define HTK_USE_XPRINT #define HTK_BUILD_IN_LINUX #ifdef HTK_BUILD_IN_LINUX #define HTK_PREPROCESSOR_STRING_FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #else #define HTK_PREPROCESSOR_STRING_FILE (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) #endif #ifdef HTK_USE_XPRINT #define XP(FMT, ARGS...) (printf(FMT, ##ARGS)) //#define XPH(FMT, ARGS...) (printf("[%s:%d:%s] "FMT, __FILE__, __LINE__, __FUNCTION__, ##ARGS)) #define XPH(FMT, ARGS...) (printf("[%s:%d:%s] "FMT, HTK_PREPROCESSOR_STRING_FILE, __LINE__, __FUNCTION__, ##ARGS)) #else #define XP(FMT, ARGS...) #endif //----------------------------------------------------------------------------- char Version_And_Date[2][10] = { 0 }; //----------------------------------------------------------------------------- struct SysConfigAndInfo *ShmSysConfigAndInfo; struct StatusCodeData *ShmStatusCodeData; struct OCPP16Data *ShmOCPP16Data; struct OCPP20Data *ShmOCPP20Data; struct POWER_SHARING *ShmPowerSharing; ParsingRatedCur modelnameInfo = {0}; uint8_t gunType[4] = {0}; uint8_t gunTotalNumber = 0; //========================================== // Common routine //========================================== int StoreLogMsg(const char *fmt, ...) { char Buf[4096+256]; char buffer[4096]; time_t CurrentTime; struct tm *tm; struct timeval tv; 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((time_t*)NULL); tm=localtime(&CurrentTime); gettimeofday(&tv, NULL); // get microseconds, 10^-6 sprintf(Buf,"echo -n \"[%04d.%02d.%02d %02d:%02d:%02d.%03ld]%s\" >> /Storage/SystemLog/[%04d.%02d]Module_PowerSharingServerLog", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,tv.tv_usec/1000, buffer, tm->tm_year+1900,tm->tm_mon+1); #ifdef SystemLogMessage system(Buf); #endif #ifdef ConsloePrintLog printf("[%04d.%02d.%02d %02d:%02d:%02d.%03ld]%s", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,tv.tv_usec/1000, buffer); #endif return rc; } int StoreLogMsgClient(const char *fmt, ...) { char Buf[4096+256]; char buffer[4096]; time_t CurrentTime; struct tm *tm; struct timeval tv; 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((time_t*)NULL); tm=localtime(&CurrentTime); gettimeofday(&tv, NULL); // get microseconds, 10^-6 sprintf(Buf,"echo -n \"[%04d.%02d.%02d %02d:%02d:%02d.%03ld]%s\" >> /Storage/SystemLog/[%04d.%02d]Module_PowerSharingClientLog", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,tv.tv_usec/1000, buffer, tm->tm_year+1900,tm->tm_mon+1); #ifdef SystemLogMessage system(Buf); #endif #ifdef ConsloePrintLog printf("[%04d.%02d.%02d %02d:%02d:%02d.%03ld]%s", tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,tv.tv_usec/1000, buffer); #endif return rc; } 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); } long long DiffTimebWithNow(struct timeb ST) { //return milli-second struct timeb ET; long long StartTime,StopTime; ftime(&ET); StartTime=(long long)ST.time; StopTime=(long long)ET.time; return ((StopTime-StartTime)*1000) + (ET.millitm-ST.millitm); } 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 refreshStartTimer(struct timespec *timer) { clock_gettime(CLOCK_MONOTONIC, timer); } int getDiffSecNow(struct timespec timer) { struct timespec timerNow; clock_gettime(CLOCK_MONOTONIC, &timerNow); return (int)((((unsigned long)(timerNow.tv_sec - timer.tv_sec) * 1000) + ((unsigned long)((timerNow.tv_nsec / 1000000) - (timer.tv_nsec / 1000000))))/1000); } int getDiffSecBetween(struct timespec start, struct timespec end) { return (int)((((unsigned long)(end.tv_sec - start.tv_sec) * 1000) + ((unsigned long)((end.tv_nsec / 1000000) - (start.tv_nsec / 1000000))))/1000); } void dM(uint8_t *data, uint16_t len, uint8_t isRX) { #ifdef DEBUG uint8_t output[8192]; if(isRX) { DEBUG_INFO_CLIENT("- RX --------------------------------------------\n"); } else { DEBUG_INFO_CLIENT("- TX --------------------------------------------\n"); } memset(output, 0x00, ARRAY_SIZE(output)); for(uint16_t idx=0;idx<16;idx++) sprintf((char*)output, "%s %02X", output, idx); DEBUG_INFO_CLIENT("%s\n", output); DEBUG_INFO_CLIENT("-------------------------------------------------\n"); for(uint16_t idx = 0;idx0) { sprintf((char*)output, "%s %02X", output, data[idx]); } else { if(idx != 0) DEBUG_INFO("%s\n", output); memset(output, 0x00, ARRAY_SIZE(output)); sprintf((char*)output, "%s %02X", output, data[idx]); } } DEBUG_INFO_CLIENT("%s\n", output); DEBUG_INFO_CLIENT("-------------------------------------------------\n"); #endif } int isValidCheckSum(struct Message *message) { uint8_t chksum = 0x00; for(int idx=0;idx<((message->buffer[1]+3)>ARRAY_SIZE(message->buffer)?ARRAY_SIZE(message->buffer):(message->buffer[1]+3));idx++) { chksum ^= message->buffer[idx]; } return ((chksum == message->buffer[((message->buffer[1]+3)>ARRAY_SIZE(message->buffer)?ARRAY_SIZE(message->buffer):(message->buffer[1]+3))]) ? PASS : FAIL); } uint8_t chksumCal(struct Message *message) { uint8_t chksum=0; for(int idx=0;idx<((message->buffer[1]+3)>ARRAY_SIZE(message->buffer)?ARRAY_SIZE(message->buffer):(message->buffer[1]+3));idx++) { chksum ^= message->buffer[idx]; } return chksum & 0xff; } uint8_t ocpp_get_maxcharging_profileId() { uint8_t result = 0; if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) { result = ShmOCPP16Data->MaxChargingProfile.ChargingProfileId; } else if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) { result = ShmOCPP20Data->MaxChargingProfile.id; } return result; } int getMaxScheduleStart() { int result = -1; struct tm tmScheduleStart;; struct timeb tbScheduleStart; if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) { if((sscanf((char*)ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.StartSchedule, "%4d-%2d-%2dT%2d:%2d:%2d", &tmScheduleStart.tm_year, &tmScheduleStart.tm_mon, &tmScheduleStart.tm_mday, &tmScheduleStart.tm_hour, &tmScheduleStart.tm_min, &tmScheduleStart.tm_sec) == 6)) { tmScheduleStart.tm_year -= 1900; tmScheduleStart.tm_mon -= 1; tbScheduleStart.time = mktime(&tmScheduleStart); tbScheduleStart.millitm = 0; result = DiffTimebWithNow(tbScheduleStart)/1000; //DEBUG_INFO("Max schedule start compare Now(seconds): %d\n", result); } else { DEBUG_WARN("Max schedule start date parsing error.\n"); } } else if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) { if((sscanf((char*)ShmOCPP20Data->MaxChargingProfile.chargingSchedule[0].startSchedule, "%4d-%2d-%2dT%2d:%2d:%2d", &tmScheduleStart.tm_year, &tmScheduleStart.tm_mon, &tmScheduleStart.tm_mday, &tmScheduleStart.tm_hour, &tmScheduleStart.tm_min, &tmScheduleStart.tm_sec) == 6)) { tmScheduleStart.tm_year -= 1900; tmScheduleStart.tm_mon -= 1; tbScheduleStart.time = mktime(&tmScheduleStart); tbScheduleStart.millitm = 0; result = DiffTimebWithNow(tbScheduleStart)/1000; //DEBUG_INFO("Max schedule start compare Now(seconds): %d\n", result); } else { DEBUG_WARN("Max schedule start date parsing error.\n"); } } return result; } uint16_t checkChargingProfileLimit() { /* * TODO: * 1. Default capacity check */ uint16_t targetMaxCurrent = ((ShmSysConfigAndInfo->SysConfig.PowerSharingCapacityPower==0)?(modelnameInfo.ratedPower/220):(ShmSysConfigAndInfo->SysConfig.PowerSharingCapacityPower/220)); if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_16) { // Get max charging profile limit if((ocpp_get_maxcharging_profileId() > 0)) { // Checking limitation for(uint8_t idx_period=0;idx_periodMaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod);idx_period++) { if((getMaxScheduleStart() >= ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[idx_period].StartPeriod) && ((idx_period == 0) || (ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[idx_period].StartPeriod > 0)) ) { targetMaxCurrent = (mystrcmp((char*)ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingRateUnit,"W")==PASS?ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[idx_period].Limit/(220*ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[idx_period].NumberPhases):ShmOCPP16Data->MaxChargingProfile.ChargingSchedule.ChargingSchedulePeriod[idx_period].Limit); //DEBUG_INFO("targetMaxCurrent on period[%d]: %d\n", idx_period, targetMaxCurrent); } else break; } } } else if(ShmSysConfigAndInfo->SysInfo.OcppRunningVer == OCPP_RUNNING_VERSION_20) { // Get max charging profile limit if((ocpp_get_maxcharging_profileId() > 0)) { // Checking limitation for(uint8_t idx_period=0;idx_periodMaxChargingProfile.chargingSchedule[0].chargingSchedulePeriod);idx_period++) { if((getMaxScheduleStart() >= ShmOCPP20Data->MaxChargingProfile.chargingSchedule[0].chargingSchedulePeriod[idx_period].startPeriod) && ((idx_period == 0) || (ShmOCPP20Data->MaxChargingProfile.chargingSchedule[0].chargingSchedulePeriod[idx_period].startPeriod > 0)) ) { targetMaxCurrent = (mystrcmp((char*)ShmOCPP20Data->MaxChargingProfile.chargingSchedule[0].chargingRateUnit,"W")==PASS?ShmOCPP20Data->MaxChargingProfile.chargingSchedule[0].chargingSchedulePeriod[idx_period].limit/(220*ShmOCPP20Data->MaxChargingProfile.chargingSchedule[0].chargingSchedulePeriod[idx_period].numberPhases):ShmOCPP20Data->MaxChargingProfile.chargingSchedule[0].chargingSchedulePeriod[idx_period].limit); //DEBUG_INFO("targetMaxCurrent on period[%d]: %d\n", idx_period, targetMaxCurrent); } else break; } } } return targetMaxCurrent; } void getClientp(int socketFd) { char clientip[20]; struct sockaddr_in addr; socklen_t addr_size = sizeof(struct sockaddr_in); getpeername(socketFd, (struct sockaddr *)&addr, &addr_size); strcpy(clientip, inet_ntoa(addr.sin_addr)); DEBUG_INFO("Client IP address: %s\n", clientip); } //========================================== // Init all share memory //========================================== int InitShareMemory() { int result = PASS; int MeterSMId; //Initial ShmSysConfigAndInfo if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo), 0777)) < 0) { DEBUG_ERROR("shmget ShmSysConfigAndInfo NG\n"); result = FAIL; } else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1) { DEBUG_ERROR("shmat ShmSysConfigAndInfo NG\n"); result = FAIL; } else {} //Initial ShmStatusCodeData if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData), 0777)) < 0) { DEBUG_ERROR("shmget ShmStatusCodeData NG\n"); result = FAIL; } else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1) { DEBUG_ERROR("shmat ShmStatusCodeData NG\n"); result = FAIL; } else {} //Initial ShmOCPP16Data if ((MeterSMId = shmget(ShmOcppModuleKey, sizeof(struct OCPP16Data), 0777)) < 0) { DEBUG_ERROR("shmget ShmOCPP16Data NG"); result = FAIL; } else if ((ShmOCPP16Data = shmat(MeterSMId, NULL, 0)) == (void *) -1) { DEBUG_ERROR("shmat ShmOCPP16Data NG"); result = FAIL; } else {} //Initial ShmOCPP20Data if ((MeterSMId = shmget(ShmOcpp20ModuleKey, sizeof(struct OCPP20Data), 0777)) < 0) { DEBUG_ERROR("shmget ShmOCPP20Data NG"); result = FAIL; } else if ((ShmOCPP20Data = shmat(MeterSMId, NULL, 0)) == (void *) -1) { DEBUG_ERROR("shmat ShmOCPP20Data NG"); result = FAIL; } else {} //Create ShmPowerSharing if ((MeterSMId = shmget(ShmPowerShargingKey, sizeof(struct POWER_SHARING), IPC_CREAT | 0777)) < 0) { DEBUG_ERROR("shmget ShmPowerShargingKey NG\n"); result = FAIL; } else if ((ShmPowerSharing = shmat(MeterSMId, NULL, 0)) == (void *) -1) { DEBUG_ERROR("shmat ShmPowerShargingKey NG\n"); result = FAIL; } memset(ShmPowerSharing,0,sizeof(struct POWER_SHARING)); for(uint8_t idx=0;idxConnection_Info[idx].socketFd = (idx+1); // Model name parsing if(RatedCurrentParsing((char*)ShmSysConfigAndInfo->SysConfig.ModelName, &modelnameInfo) != -1) { DEBUG_INFO("Model name rated power: %d\n", modelnameInfo.ratedPower); if((ShmSysConfigAndInfo->SysConfig.ModelName[0]=='D') && ((ShmSysConfigAndInfo->SysConfig.ModelName[1]=='B') || (ShmSysConfigAndInfo->SysConfig.ModelName[1]=='K') || (ShmSysConfigAndInfo->SysConfig.ModelName[1]=='O')) ) // 'D' means DC { // DO series for(int gun_index=0; gun_indexConnection_Info[idx].isSocketConnected) { result = ShmPowerSharing->Connection_Info[idx].socketFd; break; } } return result; } int conn_register(int socketFd) { int result = FAIL; for(uint8_t idx=0;idxConnection_Info[idx].isSocketConnected) { DEBUG_INFO("Dupfd-%d register to conn-%d.\n", socketFd, idx); ShmPowerSharing->Connection_Info[idx].isSocketConnected = TRUE; ShmPowerSharing->Connection_Info[idx].socketFd = socketFd; refreshStartTimer(&ShmPowerSharing->Connection_Info[idx].timer[POWERSHARING_TMR_IDX_HEARTBEAT]); result = PASS; break; } } return result; } int conn_reject(int socketFd) { int result = FAIL; for(uint8_t idx=0;idxConnection_Info[idx].socketFd == socketFd) { DEBUG_INFO("Dupfd-%d register from conn_info-%d.\n", socketFd, idx); ShmPowerSharing->Connection_Info[idx].isSocketConnected = FALSE; for(uint8_t gun_index=0;gun_indexConnection_Info[idx].connectorInfo);gun_index++) ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected = FALSE; result = PASS; break; } } return result; } int conn_getConectedQuantity(void) { int result = 0; for(uint8_t idx=0;idxConnection_Info[idx].isSocketConnected) { result += 1; } } if(ShmPowerSharing->connectedConnectionQty != result) { DEBUG_INFO("Connection quantity: %d\n", result); ShmPowerSharing->connectedConnectionQty = result; } return result; } int conn_getConectedConnector(void) { int result = 0; for(uint8_t idx=0;idxConnection_Info[idx].connectorCount;gun_index++) { if(ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected) { result += 1; } } } if(ShmPowerSharing->connectedConnectorQty != result) { DEBUG_INFO("Connected connector quantity: %d\n", result); ShmPowerSharing->connectedConnectorQty = result; } return result; } int conn_updateHeartBeatTime(int socketFd) { int result = FAIL; for(uint8_t idx=0;idxConnection_Info[idx].socketFd == socketFd) { //DEBUG_INFO("Dupfd-%d register from conn_info-%d update heart beat time.\n", socketFd, idx); refreshStartTimer(&ShmPowerSharing->Connection_Info[idx].timer[POWERSHARING_TMR_IDX_HEARTBEAT]); result = PASS; break; } } return result; } struct timespec conn_getStatusStarttime(int socketFd) { struct timespec result; refreshStartTimer(&result); for(uint8_t idx=0;idxConnection_Info[idx].socketFd == socketFd) { result = ShmPowerSharing->Connection_Info[idx].timer[POWERSHARING_TMR_IDX_GET_STATUS]; break; } } return result; } int conn_getStatusStarttimeUpdate(int socketFd) { int result = FAIL; for(uint8_t idx=0;idxConnection_Info[idx].socketFd == socketFd) { refreshStartTimer(&ShmPowerSharing->Connection_Info[idx].timer[POWERSHARING_TMR_IDX_GET_STATUS]); result = PASS; break; } } return result; } struct timespec conn_setCapacityStarttime(int socketFd) { struct timespec result; refreshStartTimer(&result); for(uint8_t idx=0;idxConnection_Info[idx].socketFd == socketFd) { result = ShmPowerSharing->Connection_Info[idx].timer[POWERSHARING_TMR_IDX_SET_CAPACITY]; break; } } return result; } int conn_setCapacityStarttimeUpdate(int socketFd) { int result = FAIL; for(uint8_t idx=0;idxConnection_Info[idx].socketFd == socketFd) { refreshStartTimer(&ShmPowerSharing->Connection_Info[idx].timer[POWERSHARING_TMR_IDX_SET_CAPACITY]); result = PASS; break; } } return result; } int conn_update_status(int socketFd, Connector_Info *connectorInfo, uint8_t connectorCount) { int result = FAIL; for(uint8_t idx=0;idxConnection_Info[idx].socketFd == socketFd) { ShmPowerSharing->Connection_Info[idx].connectorCount = connectorCount; for(uint8_t gun_index=0;gun_indexConnection_Info[idx].connectorInfo[gun_index].isGunConnected && connectorInfo[gun_index].isGunConnected) { ShmPowerSharing->isDetectNewConnected = YES; } if((ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected != connectorInfo[gun_index].isGunConnected?YES:NO) || (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent != connectorInfo[gun_index].availableSharingCurrent) || (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].presentOutputCurrent != connectorInfo[gun_index].presentOutputCurrent)) { #ifdef MODIFY_MODPS_REDUCE_DEBUG_LOG const char* GUN_TYPE[] = { "AC", "AC3", "DC" }; char GunType[8] = { 0 }; char s[64] = { 0 }; Connector_Info* pGun = &connectorInfo[gun_index]; strcpy(GunType, pGun->connectorType >= 0 && pGun->connectorType <= 2 ? GUN_TYPE[pGun->connectorType] : "-"); sprintf(s, "C%d, G%d, %s, %d, %d, %d", idx, gun_index, GunType, pGun->isGunConnected ? 1 : 0, pGun->presentOutputCurrent, pGun->availableSharingCurrent); DEBUG_INFO("%s\n", s); #else //MODIFY_MODPS_REDUCE_DEBUG_LOG switch(connectorInfo[gun_index].connectorType) { case CONNECTOR_TYPE_AC: DEBUG_INFO("Conn-%d gun_%d type: AC signle phase.\n", idx, gun_index); break; case CONNECTOR_TYPE_AC_THREE: DEBUG_INFO("Conn-%d gun_%d type: AC three phase.\n", idx, gun_index); break; case CONNECTOR_TYPE_DC: DEBUG_INFO("Conn-%d gun_%d type: DC.\n", idx, gun_index); break; } DEBUG_INFO("Conn-%d gun_%d connected: %s\n", idx, gun_index, (connectorInfo[gun_index].isGunConnected?"Yes":"No")); DEBUG_INFO("Conn-%d gun_%d available current: %d\n", idx, gun_index, connectorInfo[gun_index].availableSharingCurrent); DEBUG_INFO("Conn-%d gun_%d preset output current: %d\n", idx, gun_index, connectorInfo[gun_index].presentOutputCurrent); DEBUG_INFO("==================================\n"); #endif //MODIFY_MODPS_REDUCE_DEBUG_LOG } ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].connectorType = connectorInfo[gun_index].connectorType; ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected = connectorInfo[gun_index].isGunConnected; ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].presentOutputCurrent = connectorInfo[gun_index].presentOutputCurrent; } result = PASS; } } return result; } #ifdef MODIFY_MODPS_LET_ON_HAND_ALL_USED int conn_getOnHandCurrent(BOOL bUpdateChargingProfileLimit) { static uint16_t ChargingProfileLimit = 0; if (bUpdateChargingProfileLimit || ChargingProfileLimit == 0) { ChargingProfileLimit = checkChargingProfileLimit(); } int result = 0; for(uint8_t idx=0;idxConnection_Info[idx].isSocketConnected) { for(uint8_t gun_index=0;gun_indexConnection_Info[idx].connectorCount;gun_index++) { //if (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected) { result += (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].connectorType == CONNECTOR_TYPE_AC_THREE? ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent*3: ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent); } } } } result = ChargingProfileLimit - result; if(ShmPowerSharing->onHandCurrent != result) { DEBUG_INFO("Total available current: %d\n", result); ShmPowerSharing->onHandCurrent = result; } return result; } #else //MODIFY_MODPS_LET_ON_HAND_ALL_USED int conn_getOnHandCurrent(void) { int result = 0; for(uint8_t idx=0;idxConnection_Info[idx].isSocketConnected) { for(uint8_t gun_index=0;gun_indexConnection_Info[idx].connectorCount;gun_index++) { result += (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].connectorType == CONNECTOR_TYPE_AC_THREE? ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent*3: ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent); } } } result = checkChargingProfileLimit() - result; if(ShmPowerSharing->onHandCurrent != result) { DEBUG_INFO("Total available current: %d\n", result); ShmPowerSharing->onHandCurrent = result; } return result; } #endif //MODIFY_MODPS_LET_ON_HAND_ALL_USED void create_cmd_getStatus(struct Message *out) { memset(out->buffer, 0, ARRAY_SIZE(out->buffer)); out->size = 4; out->buffer[0] = 0x55; out->buffer[1] = 0x00; out->buffer[2] = SHARING_CMD_GET_STATUS; out->buffer[out->size-1] = chksumCal(out); //dM(out->buffer, out->size, FALSE); } void create_cmd_SetAvailableCurrent(struct Message *out, int socketFd) { memset(out->buffer, 0, ARRAY_SIZE(out->buffer)); for(uint8_t idx=0;idxConnection_Info[idx].socketFd == socketFd) { out->size = ShmPowerSharing->Connection_Info[idx].connectorCount*2 + 5; out->buffer[0] = 0x55; out->buffer[1] = ShmPowerSharing->Connection_Info[idx].connectorCount*2 + 1; out->buffer[2] = SHARING_CMD_SET_CAPACITY; out->buffer[3] = ShmPowerSharing->Connection_Info[idx].connectorCount; for(uint8_t gun_index=0;gun_indexConnection_Info[idx].connectorCount;gun_index++) { out->buffer[4+(gun_index*2)] = (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent>>8)&0xff; out->buffer[4+(gun_index*2)+1] = (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent>>0)&0xff; } } } out->buffer[out->size-1] = chksumCal(out); //dM(out->buffer, out->size, FALSE); } int tcpSocketServer(void) { int sockFd = 0; int clientSockFd = 0; int dupFd = 0; struct Message input; struct Message output; struct sockaddr_in serverInfo, clientInfo; socklen_t addrlen = sizeof(clientInfo); sockFd = socket(AF_INET , SOCK_STREAM , 0); if(sockFd == -1) { DEBUG_ERROR("TCP service socket create fail.\n"); sleep(5); return FAIL; } bzero(&serverInfo,sizeof(serverInfo)); serverInfo.sin_family = PF_INET; serverInfo.sin_addr.s_addr = htonl(INADDR_ANY); serverInfo.sin_port = htons(LISTEN_PORT_TCP); #ifdef FUNC_MODULE_POWER_SHARING_APPEND_LOG DEBUG_INFO("==========[ tcpSocketServer begin ]==========\n"); #endif if(bind(sockFd, (struct sockaddr *)&serverInfo, sizeof(serverInfo)) < 0) DEBUG_ERROR("TCP server socket bind fail.\n"); if(listen(sockFd, CONNECTION_LIMIT) < 0) DEBUG_ERROR("TCP server socket listen fail.\n"); else DEBUG_INFO("Power sharing TCP server initial listen on port %d.\n", LISTEN_PORT_TCP); // Main loop for(;;) { clientSockFd = accept(sockFd, (struct sockaddr*) &clientInfo, &addrlen); fcntl(clientSockFd, F_SETFD, FD_CLOEXEC); DEBUG_INFO("Client connect in.\n"); DEBUG_INFO("clientSockFd : %d\n", clientSockFd); getClientp(clientSockFd); if(clientSockFd > 0) { if(ShmPowerSharing->connectedConnectionQty < CONNECTION_LIMIT) { // Fork a child process to handle the new conn if(fork()==0) { uint8_t idxStep = 0; uint8_t socketEnable = YES; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 500000; setsockopt(clientSockFd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv); // Assign socket handle as available handle in conn info pool dupFd = dup2(clientSockFd, conn_getDupFd()); conn_register(dupFd); while(socketEnable) { if((input.size = recv(dupFd, input.buffer, sizeof(input.buffer), 0)) > 0) { //dM(input.buffer, input.size, YES); if(isValidCheckSum(&input)) { Connector_Info connectorInfo[4]; conn_updateHeartBeatTime(dupFd); memset(output.buffer, 0x00, ARRAY_SIZE(output.buffer)); switch(input.buffer[2]) { case SHARING_CMD_GET_STATUS: for(uint8_t gun_index=0;gun_index= INTERVAL_SPEC_POLLING_CMD)) { create_cmd_getStatus(&output); conn_getStatusStarttimeUpdate(dupFd); send(clientSockFd, output.buffer, output.size, 0); } idxStep++; break; default: if((getDiffSecNow(conn_setCapacityStarttime(dupFd)) >= INTERVAL_SPEC_POLLING_CMD)) { create_cmd_SetAvailableCurrent(&output, dupFd); conn_setCapacityStarttimeUpdate(dupFd); send(clientSockFd, output.buffer, output.size, 0); } idxStep = 0; break; } } } exit(0); } else { // if parent, close the socket and go back to listening new requests close(clientSockFd); } } else { DEBUG_WARN("Connection is over limit.\n"); output.size = 4; output.buffer[0] = 0x55; output.buffer[1] = 0x00; output.buffer[2] = SHARING_CMD_CONNECTION_FULL; output.buffer[3] = chksumCal(&output); send(clientSockFd, output.buffer, output.size, 0); close(clientSockFd); } } usleep(500000); } return FAIL; } //========================================== // Client routine //========================================== int tcpSocketClient(void) { int sockfd; struct sockaddr_in info; struct hostent *ghbn; struct timeval tv; uint8_t socketEnable; uint8_t cntSocketErr; struct Message input; struct Message output; bzero(&info,sizeof(info)); if(ShmSysConfigAndInfo->SysConfig.isEnableLocalPowerSharing == 1) { ghbn = gethostbyname((char*)"127.0.0.1"); } else { if(strlen((char*)ShmSysConfigAndInfo->SysConfig.PowerSharingServerIP) > 0) ghbn = gethostbyname((char*)ShmSysConfigAndInfo->SysConfig.PowerSharingServerIP); else ghbn = gethostbyname((char*)"192.168.10.10"); } info.sin_family = PF_INET; info.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)ghbn->h_addr_list[0])); info.sin_port = htons(LISTEN_PORT_TCP); ShmSysConfigAndInfo->SysInfo.localSharingInfo.isConnectedSharingServer = OFF; DEBUG_INFO_CLIENT("Connect to %s:%d\n", inet_ntoa(*(struct in_addr *)ghbn->h_addr_list[0]), LISTEN_PORT_TCP); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { DEBUG_ERROR_CLIENT("Fail to create a socket."); return 0; } if(connect(sockfd, (struct sockaddr *)&info,sizeof(info)) ==-1) { DEBUG_ERROR_CLIENT("Connection error.\n"); ShmSysConfigAndInfo->SysInfo.localSharingInfo.isConnectedSharingServer = OFF; socketEnable = OFF; } else { DEBUG_INFO_CLIENT("Connect success.\n"); tv.tv_sec = 0; tv.tv_usec = 500000; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv); socketEnable = ON; cntSocketErr = 0; ShmSysConfigAndInfo->SysInfo.localSharingInfo.isConnectedSharingServer = ON; } while(socketEnable) { memset(input.buffer, 0, ARRAY_SIZE(input.buffer)); if((input.size = recv(sockfd, input.buffer, ARRAY_SIZE(input.buffer), 0)) > 0) { //DEBUG_INFO("Receive size: %d.\n", input.size); dM(input.buffer, input.size, YES); if(isValidCheckSum(&input)) { switch(input.buffer[2]) { case SHARING_CMD_GET_STATUS: output.size = 5 + (gunTotalNumber*6); output.buffer[0] = 0x55; output.buffer[1] = 1 + (gunTotalNumber*6); output.buffer[2] = input.buffer[2]; output.buffer[3] = gunTotalNumber; for(uint8_t gun_index=0;gun_indexSysConfig.AcPhaseCount==3?CONNECTOR_TYPE_AC_THREE:CONNECTOR_TYPE_AC):CONNECTOR_TYPE_DC); switch(gunType[gun_index]) { case GUN_TYPE_CHAdeMO: if(ShmSysConfigAndInfo->SysConfig.ModelName[8] != '0') { tempIndex = ((gun_index==2) ? 1: 0); } else { tempIndex = gun_index; } for (int index = 0; index < CHAdeMO_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.ChademoChargingData[index].Index == tempIndex) { output.buffer[4+(gun_index*6)+1] = ShmSysConfigAndInfo->SysInfo.ChademoChargingData[tempIndex].ConnectorPlugIn; output.buffer[4+(gun_index*6)+2] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>8)&0xff; output.buffer[4+(gun_index*6)+3] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>0)&0xff; output.buffer[4+(gun_index*6)+4] = ((int)(ShmSysConfigAndInfo->SysInfo.ChademoChargingData[gun_index].PresentChargingPower*1000/220)>>8)&0xff; output.buffer[4+(gun_index*6)+5] = ((int)(ShmSysConfigAndInfo->SysInfo.ChademoChargingData[gun_index].PresentChargingPower*1000/220)>>0)&0xff; } } break; case GUN_TYPE_CCS: if(ShmSysConfigAndInfo->SysConfig.ModelName[8] != '0') { tempIndex = ((gun_index==2) ? 1: 0); } else { tempIndex = gun_index; } for (int index = 0; index < CCS_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.CcsChargingData[index].Index == tempIndex) { output.buffer[4+(gun_index*6)+1] = ShmSysConfigAndInfo->SysInfo.CcsChargingData[tempIndex].ConnectorPlugIn; output.buffer[4+(gun_index*6)+2] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>8)&0xff; output.buffer[4+(gun_index*6)+3] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>0)&0xff; output.buffer[4+(gun_index*6)+4] = ((int)(ShmSysConfigAndInfo->SysInfo.CcsChargingData[gun_index].PresentChargingPower*1000/220)>>8)&0xff; output.buffer[4+(gun_index*6)+5] = ((int)(ShmSysConfigAndInfo->SysInfo.CcsChargingData[gun_index].PresentChargingPower*1000/220)>>0)&0xff; } } break; case GUN_TYPE_GBT: if(ShmSysConfigAndInfo->SysConfig.ModelName[8] != '0') { tempIndex = ((gun_index==2) ? 1: 0); } else { tempIndex = gun_index; } for (int index = 0; index < GB_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.GbChargingData[index].Index == tempIndex) { output.buffer[4+(gun_index*6)+1] = ShmSysConfigAndInfo->SysInfo.GbChargingData[tempIndex].ConnectorPlugIn; output.buffer[4+(gun_index*6)+2] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>8)&0xff; output.buffer[4+(gun_index*6)+3] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>0)&0xff; output.buffer[4+(gun_index*6)+4] = ((int)(ShmSysConfigAndInfo->SysInfo.GbChargingData[gun_index].PresentChargingPower*1000/220)>>8)&0xff; output.buffer[4+(gun_index*6)+5] = ((int)(ShmSysConfigAndInfo->SysInfo.GbChargingData[gun_index].PresentChargingPower*1000/220)>>0)&0xff; } } break; case GUN_TYPE_DO: tempIndex = gun_index; for (int index = 0; index < GENERAL_GUN_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.ConnectorInfo[index].GeneralChargingData.Index == tempIndex) { output.buffer[4+(gun_index*6)+1] = ShmSysConfigAndInfo->SysInfo.ConnectorInfo[tempIndex].GeneralChargingData.ConnectorPlugIn; output.buffer[4+(gun_index*6)+2] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>8)&0xff; output.buffer[4+(gun_index*6)+3] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>0)&0xff; output.buffer[4+(gun_index*6)+4] = ((int)(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].GeneralChargingData.PresentChargingPower*1000/220)>>8)&0xff; output.buffer[4+(gun_index*6)+5] = ((int)(ShmSysConfigAndInfo->SysInfo.ConnectorInfo[gun_index].GeneralChargingData.PresentChargingPower*1000/220)>>0)&0xff; } } break; case GUN_TYPE_AC: if(ShmSysConfigAndInfo->SysConfig.ModelName[0]=='D') { tempIndex = 2; } else { tempIndex = gun_index; } for (int index = 0; index < AC_QUANTITY; index++) { if (ShmSysConfigAndInfo->SysInfo.AcChargingData[index].Index == tempIndex) { output.buffer[4+(gun_index*6)+1] = ShmSysConfigAndInfo->SysInfo.AcChargingData[tempIndex].PilotState; output.buffer[4+(gun_index*6)+2] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>8)&0xff; output.buffer[4+(gun_index*6)+3] = (ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]>>0)&0xff; output.buffer[4+(gun_index*6)+4] = ((int)ShmSysConfigAndInfo->SysInfo.AcChargingData[gun_index].PresentChargingCurrent>>8)&0xff; output.buffer[4+(gun_index*6)+5] = ((int)ShmSysConfigAndInfo->SysInfo.AcChargingData[gun_index].PresentChargingCurrent>>0)&0xff; } } break; default: break; } } output.buffer[output.size-1] = chksumCal(&output); break; case SHARING_CMD_SET_CAPACITY: output.size = 5; output.buffer[0] = 0x55; output.buffer[1] = 0x01; output.buffer[2] = input.buffer[2]; output.buffer[3] = 0x01; output.buffer[output.size-1] = chksumCal(&output); for(uint8_t gun_index=0;gun_indexSysInfo.localSharingInfo.AvailableShargingCurrent[gun_index] != ((input.buffer[4+(gun_index*2)]<<8) | (input.buffer[4+(gun_index*2)+1]))) { ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index] = ((input.buffer[4+(gun_index*2)]<<8) | (input.buffer[4+(gun_index*2)+1])); DEBUG_INFO_CLIENT("Get available current from server: %d\n", ShmSysConfigAndInfo->SysInfo.localSharingInfo.AvailableShargingCurrent[gun_index]); } } break; default: DEBUG_WARN_CLIENT("Receive unknown command.\n"); output.size = 4; output.buffer[0] = 0x55; output.buffer[1] = 0x00; output.buffer[2] = SHARING_CMD_UNKNOWN; output.buffer[3] = chksumCal(&output); break; } } else { DEBUG_WARN_CLIENT("Receive command check sum error.\n"); output.size = 4; output.buffer[0] = 0x55; output.buffer[1] = 0x00; output.buffer[2] = SHARING_CMD_CHKSUM_ERROR; output.buffer[3] = chksumCal(&output); } dM(output.buffer, output.size, NO); send(sockfd, output.buffer, output.size, 0); } else if(input.size == 0) { DEBUG_INFO_CLIENT("DisSocketConnected.\n"); fflush(stdout); socketEnable = OFF; ShmSysConfigAndInfo->SysInfo.localSharingInfo.isConnectedSharingServer = OFF; } else if(input.size == -1) { if(cntSocketErr > 5) { socketEnable = OFF; DEBUG_ERROR_CLIENT("Socket error occur\n"); } else { cntSocketErr++; } } usleep(500000); } close(sockfd); return FAIL; } //========================================== // Local loading balance check //========================================== #ifdef MODIFY_MODPS_BALANCE_CHECK_LOOP Connector_Info* GetIsetMaxGun(void) { struct CONNECTION_INFO* pDev = NULL; Connector_Info* pGun = NULL; uint16_t* pIset = NULL; uint16_t* pIout = NULL; uint16_t Imin = 0; uint16_t IsetMax = 6; Connector_Info* pGunIsetMax = NULL; uint16_t RealIset = 0; for (uint8_t i = 0; i < CONNECTION_LIMIT; i++) { pDev = &ShmPowerSharing->Connection_Info[i]; if (pDev->isSocketConnected) { for (uint8_t j = 0; j < pDev->connectorCount; j++) { pGun = &pDev->connectorInfo[j]; if (pGun->isGunConnected) { pIset = &pGun->availableSharingCurrent; pIout = &pGun->presentOutputCurrent; Imin = pGun->connectorType == CONNECTOR_TYPE_DC ? SHARE_MIN_DC : SHARE_MIN_AC; RealIset = (pGun->connectorType == CONNECTOR_TYPE_AC_THREE ? *pIset * 3 : *pIset); if (*pIset > Imin && *pIout > Imin && RealIset > IsetMax) { IsetMax = RealIset; pGunIsetMax = pGun; } } } } } // if (pGunIsetMax) // { // DEBUG_INFO("GunIsetMax: %d / %d (%d)\n", pGunIsetMax->presentOutputCurrent, // pGunIsetMax->availableSharingCurrent, pGunIsetMax->connectorType); // } return pGunIsetMax; } Connector_Info* GetIsetMinGun(void) { struct CONNECTION_INFO* pDev = NULL; Connector_Info* pGun = NULL; uint16_t* pIset = NULL; uint16_t* pIout = NULL; uint16_t Imin = 0; uint16_t IsetMin = 1000; Connector_Info* pGunIsetMin = NULL; uint16_t RealIset = 0; for (uint8_t i = 0; i < CONNECTION_LIMIT; i++) { pDev = &ShmPowerSharing->Connection_Info[i]; if (pDev->isSocketConnected) { for (uint8_t j = 0; j < pDev->connectorCount; j++) { pGun = &pDev->connectorInfo[j]; if (pGun->isGunConnected) { pIset = &pGun->availableSharingCurrent; pIout = &pGun->presentOutputCurrent; Imin = pGun->connectorType == CONNECTOR_TYPE_DC ? SHARE_MIN_DC : SHARE_MIN_AC; RealIset = (pGun->connectorType == CONNECTOR_TYPE_AC_THREE ? *pIset * 3 : *pIset); if (*pIset > Imin && *pIout > Imin && RealIset < IsetMin) { IsetMin = RealIset; pGunIsetMin = pGun; } } } } } // if (pGunIsetMin) // { // DEBUG_INFO("GunIsetMin: %d / %d (%d)\n", pGunIsetMin->presentOutputCurrent, // pGunIsetMin->availableSharingCurrent, pGunIsetMin->connectorType); // } return pGunIsetMin; } typedef struct _GunInfoEx { BOOL m_bIncreasing: 1; BOOL m_bDecreasing: 1; //uint16_t m_IoutMax; } GunInfoEx, *PGunInfoEx; #define CONNECTOR_LIMIT (4) //struct CONNECTION_INFO: connectorInfo[4] GunInfoEx g_GunInfoEx[CONNECTION_LIMIT][CONNECTOR_LIMIT]; void ResetGunInfoEx(void) { PGunInfoEx p = NULL; for (uint8_t i = 0; i < CONNECTION_LIMIT; i++) { for (uint8_t j = 0; j < CONNECTOR_LIMIT; j++) { p = &g_GunInfoEx[i][j]; p->m_bIncreasing = FALSE; p->m_bDecreasing = FALSE; } } //DEBUG_INFO("#ResetGunInfoEx\n"); } int balance_check_loop(void) { DEBUG_INFO("==========[ balance_check_loop begin ]==========\n"); for(;;) { // Get connection info conn_getConectedQuantity(); conn_getOnHandCurrent(TRUE); conn_getConectedConnector(); // Check conn heart beat for(uint8_t idx=0;idxConnection_Info[idx].isSocketConnected && (getDiffSecNow(ShmPowerSharing->Connection_Info[idx].timer[POWERSHARING_TMR_IDX_HEARTBEAT]) > TIMEOUT_SPEC_HEARTBEAT)) { DEBUG_INFO("SocketFd-%d heart beat is over %d seconds.\n", ShmPowerSharing->Connection_Info[idx].socketFd, TIMEOUT_SPEC_HEARTBEAT); for(uint8_t gun_index=0;gun_indexConnection_Info[idx].connectorCount;gun_index++) ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected = FALSE; ShmPowerSharing->Connection_Info[idx].isSocketConnected = FALSE; } } // Check available power if(ShmPowerSharing->isDetectNewConnected || (ShmPowerSharing->onHandCurrent < 0)) { for(uint8_t idx=0;idxConnection_Info[idx].connectorCount;gun_index++) { if(ShmPowerSharing->Connection_Info[idx].isSocketConnected && ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected) { ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent = (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].connectorType==CONNECTOR_TYPE_DC?SHARE_MIN_DC:SHARE_MIN_AC); } else { ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent = 0; } } } if(ShmPowerSharing->onHandCurrent < 0) DEBUG_INFO("On hand current < 0 re-allocate available current to each connection.\n"); if(ShmPowerSharing->isDetectNewConnected) { DEBUG_INFO("Detect gun connected re-allocate available current to each connection.\n"); ShmPowerSharing->isDetectNewConnected = NO; } ResetGunInfoEx(); } else { struct CONNECTION_INFO* pDev = NULL; Connector_Info* pGun = NULL; uint16_t* pIset = NULL; uint16_t* pIout = NULL; uint16_t Imin = 0; PGunInfoEx pGunInfoEx = NULL; for(uint8_t idx = 0; idx < CONNECTION_LIMIT; idx++) { pDev = &ShmPowerSharing->Connection_Info[idx]; for(uint8_t gun_index = 0; gun_index < pDev->connectorCount; gun_index++) { pGun = &pDev->connectorInfo[gun_index]; pIset = &pGun->availableSharingCurrent; uint16_t PreIset = pGun->availableSharingCurrent; pIout = &pGun->presentOutputCurrent; Imin = (pGun->connectorType == CONNECTOR_TYPE_DC ? SHARE_MIN_DC : SHARE_MIN_AC); pGunInfoEx = &g_GunInfoEx[idx][gun_index]; if(pDev->isSocketConnected && pGun->isGunConnected) { if((getDiffSecNow(pGun->tmrCheckCapacity) >= INTERVAL_SPEC_CHECK_CAPACITY)) { int16_t Idiff = *pIset - *pIout; if(Idiff > 3) { int32_t IsetAdd = - (Idiff >> 1); uint16_t IsetNext = *pIset + IsetAdd; if(IsetNext >= Imin) *pIset = IsetNext; else *pIset = Imin; pGunInfoEx->m_bIncreasing = FALSE; pGunInfoEx->m_bDecreasing = TRUE; } else if((abs(Idiff) <= 1) && (ShmPowerSharing->onHandCurrent > 0)) { int AvgCurr = ShmPowerSharing->onHandCurrent / (ShmPowerSharing->connectedConnectorQty == 0 ? 1 : ShmPowerSharing->connectedConnectorQty); #ifdef MODIFY_MODPS_LET_ON_HAND_ALL_USED if (pGun->connectorType == CONNECTOR_TYPE_AC_THREE) { int32_t IsetAdd = AvgCurr / 3; if (IsetAdd >= 1) { *pIset += IsetAdd; } else if (ShmPowerSharing->onHandCurrent >= 3) { *pIset += 1; } } else { if (ShmPowerSharing->onHandCurrent <= 2) { *pIset += 1; } else { *pIset += AvgCurr; } } pGunInfoEx->m_bIncreasing = TRUE; pGunInfoEx->m_bDecreasing = FALSE; #else *pIset += (pGun->connectorType == CONNECTOR_TYPE_AC_THREE ? AvgCurr / 3 : AvgCurr); #endif } else { pGunInfoEx->m_bIncreasing = FALSE; pGunInfoEx->m_bDecreasing = FALSE; } //----------------------------------------------------------------------------- if (*pIset != PreIset) { PreIset = *pIset; conn_getOnHandCurrent(FALSE); } Connector_Info* pGunIsetMax = GetIsetMaxGun(); Connector_Info* pGunIsetMin = GetIsetMinGun(); // uint16_t RealIsetMax = pGunIsetMax->connectorType == CONNECTOR_TYPE_AC_THREE ? pGunIsetMax->availableSharingCurrent * 3 : pGunIsetMax->availableSharingCurrent; // uint16_t RealIsetMin = pGunIsetMin->connectorType == CONNECTOR_TYPE_AC_THREE ? pGunIsetMin->availableSharingCurrent * 3 : pGunIsetMin->availableSharingCurrent; // BOOL bBalance = abs(RealIsetMax - RealIsetMin) <= 3; if (pGun == pGunIsetMax && pGunIsetMax == pGunIsetMin) { if (pGun->connectorType == CONNECTOR_TYPE_AC_THREE) { if (ShmPowerSharing->onHandCurrent >= 3) { *pIset += 1; } } else { if (ShmPowerSharing->onHandCurrent >= 1) { *pIset += 1; } } } else if (pGun == pGunIsetMin) { if (pGunInfoEx->m_bDecreasing == TRUE) { } else { if (pGun->connectorType == CONNECTOR_TYPE_AC_THREE) { if (ShmPowerSharing->onHandCurrent >= 3) { *pIset += 1; } } else { if (ShmPowerSharing->onHandCurrent >= 1) { *pIset += 1; } } } } else if (pGun == pGunIsetMax) { if (pGunInfoEx->m_bIncreasing == TRUE) { } else { if (pGun->connectorType == CONNECTOR_TYPE_AC_THREE) { *pIset -= 1; } else { *pIset -= 1; } } } refreshStartTimer(&ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].tmrCheckCapacity); } } else { if(*pIset != 0) { DEBUG_INFO("Dupfd-%d on conn-%d available current reset to 0A\n", ShmPowerSharing->Connection_Info[idx].socketFd, idx); } *pIset = 0; } if (*pIset != PreIset) { PreIset = *pIset; conn_getOnHandCurrent(FALSE); } } } } usleep(100000); } return FAIL; } #else //MODIFY_MODPS_BALANCE_CHECK_LOOP int balance_check_loop(void) { for(;;) { // Get connection info conn_getConectedQuantity(); conn_getOnHandCurrent(); conn_getConectedConnector(); // Check conn heart beat for(uint8_t idx=0;idxConnection_Info[idx].isSocketConnected && (getDiffSecNow(ShmPowerSharing->Connection_Info[idx].timer[POWERSHARING_TMR_IDX_HEARTBEAT]) > TIMEOUT_SPEC_HEARTBEAT)) { DEBUG_INFO("SocketFd-%d heart beat is over %d seconds.\n", ShmPowerSharing->Connection_Info[idx].socketFd, TIMEOUT_SPEC_HEARTBEAT); for(uint8_t gun_index=0;gun_indexConnection_Info[idx].connectorCount;gun_index++) ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected = FALSE; ShmPowerSharing->Connection_Info[idx].isSocketConnected = FALSE; } } // Check available power if(ShmPowerSharing->isDetectNewConnected || (ShmPowerSharing->onHandCurrent < 0)) { for(uint8_t idx=0;idxConnection_Info[idx].connectorCount;gun_index++) { if(ShmPowerSharing->Connection_Info[idx].isSocketConnected && ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected) { ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent = (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].connectorType==CONNECTOR_TYPE_DC?SHARE_MIN_DC:SHARE_MIN_AC); } else { ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent = 0; } } } if(ShmPowerSharing->onHandCurrent < 0) DEBUG_INFO("On hand current < 0 re-allocate available current to each connection.\n"); if(ShmPowerSharing->isDetectNewConnected) { DEBUG_INFO("Detect gun connected re-allocate available current to each connection.\n"); ShmPowerSharing->isDetectNewConnected = NO; } } for(uint8_t idx=0;idxConnection_Info[idx].connectorCount;gun_index++) { if(ShmPowerSharing->Connection_Info[idx].isSocketConnected && ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].isGunConnected) { if((getDiffSecNow(ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].tmrCheckCapacity) >= INTERVAL_SPEC_CHECK_CAPACITY)) { if((ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent-ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].presentOutputCurrent) > 3) { if((ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent - ((ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent-ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].presentOutputCurrent)>>1)) >= (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].connectorType==CONNECTOR_TYPE_DC?SHARE_MIN_DC:SHARE_MIN_AC)) ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent -= (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent-ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].presentOutputCurrent)>>1; else ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent = (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].connectorType==CONNECTOR_TYPE_DC?SHARE_MIN_DC:SHARE_MIN_AC); } else if((abs(ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].presentOutputCurrent-ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent) <= 1) && (ShmPowerSharing->onHandCurrent > 0)) { ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent += (ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].connectorType==CONNECTOR_TYPE_AC_THREE?(ShmPowerSharing->onHandCurrent/(ShmPowerSharing->connectedConnectorQty==0?1:ShmPowerSharing->connectedConnectorQty))/3:ShmPowerSharing->onHandCurrent/(ShmPowerSharing->connectedConnectorQty==0?1:ShmPowerSharing->connectedConnectorQty)); } else {} refreshStartTimer(&ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].tmrCheckCapacity); } } else { if(ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent != 0) { DEBUG_INFO("Dupfd-%d on conn-%d available current reset to 0A\n", ShmPowerSharing->Connection_Info[idx].socketFd, idx); } ShmPowerSharing->Connection_Info[idx].connectorInfo[gun_index].availableSharingCurrent = 0; } } } usleep(100000); } return FAIL; } #endif //MODIFY_MODPS_BALANCE_CHECK_LOOP #ifdef FUNC_MODPS_WATCH_MODE void SetCursorPos(int XPos, int YPos) { printf("\033[%d;%dH", YPos + 1, XPos + 1); } int WatchMode(void) { int MeterSMId; if ((MeterSMId = shmget(ShmPowerShargingKey, sizeof(struct POWER_SHARING), 0777)) < 0) { XP("shmget ShmPowerShargingKey NG\n"); return FAIL; } else if ((ShmPowerSharing = shmat(MeterSMId, NULL, 0)) == (void *) -1) { XP("shmat ShmPowerShargingKey NG\n"); return FAIL; } //--------------------------------------- struct CONNECTION_INFO* pDev = NULL; Connector_Info* pGun = NULL; int result = 0; int Iset = 0; struct winsize CurConsoleSize, PreConsoleSize; ioctl(STDOUT_FILENO, TIOCGWINSZ, &CurConsoleSize); //same with command: #stty size int CurRowCountOutp = 0; int PreRowCountOutp = 0; system("reset"); const char* sbar = "================================\n"; //--------------------------------------- while (1) { ioctl(STDOUT_FILENO, TIOCGWINSZ, &CurConsoleSize); if (CurConsoleSize.ws_col != PreConsoleSize.ws_col || CurConsoleSize.ws_row != PreConsoleSize.ws_row || CurRowCountOutp != PreRowCountOutp ) { memcpy(&PreConsoleSize, &CurConsoleSize, sizeof(CurConsoleSize)); PreRowCountOutp = CurRowCountOutp; system("reset"); } CurRowCountOutp = 0; SetCursorPos(0, 0); XP("%s", sbar); XP("ConsoleSize: %d x %d\n", CurConsoleSize.ws_col, CurConsoleSize.ws_row); XP("Version: %s\n", Version_And_Date[0]); XP("Update: %s\n", Version_And_Date[1]); XP("Build: %s %s\n", __DATE__, __TIME__); XP("%s", sbar); result = 0; for(uint8_t idx = 0; idx < CONNECTION_LIMIT; idx++) { pDev = &ShmPowerSharing->Connection_Info[idx]; if(pDev->isSocketConnected) { for(uint8_t gun_index = 0; gun_index < pDev->connectorCount; gun_index++) { pGun = &pDev->connectorInfo[gun_index]; Iset = pGun->availableSharingCurrent; if (pGun->connectorType == CONNECTOR_TYPE_AC_THREE) { XP("[C:%2d][G:%2d]: %3d / %3d (x3=%3d) (%d)\n", idx, gun_index, pGun->presentOutputCurrent, Iset, Iset * 3, pGun->connectorType ); result += (Iset * 3); } else { XP("[C:%2d][G:%2d]: %3d / %3d (%d)\n", idx, gun_index, pGun->presentOutputCurrent, Iset, pGun->connectorType ); result += Iset; } CurRowCountOutp++; } } } XP("Sum of Iset = %-4d\n", result); XP("TotalLimitCurr = %-4d\n", ShmPowerSharing->onHandCurrent + result); XP("OnHandCurr = %-4d\n", ShmPowerSharing->onHandCurrent); XP("Connection = %-2d\n", ShmPowerSharing->connectedConnectionQty); XP("Connector = %-2d\n", ShmPowerSharing->connectedConnectorQty); XP("%s", sbar); usleep(500000); } } #endif //FUNC_MODPS_WATCH_MODE //----------------------------------------------------------------------------- void Init_FW_Info(void) { #ifdef MODPS_FW_VER_TYPE_FORMAL sprintf(Version_And_Date[0], "V%4.2f", MODPS_FW_VER_NUM * 0.01); #endif #ifdef MODPS_FW_VER_TYPE_TEST sprintf(Version_And_Date[0], "T%4.2f", MODPS_FW_VER_NUM * 0.01); #endif sprintf(Version_And_Date[1], "%s", MODPS_FW_DATE); } //----------------------------------------------------------------------------- //========================================== // Main process //========================================== #ifdef FUNC_MODPS_WATCH_MODE int main(int argc, char *argv[]) #else int main(void) #endif { signal(SIGCHLD,SIG_IGN); Init_FW_Info(); #ifdef FUNC_MODPS_WATCH_MODE if (argc == 2 && strcmp(argv[1], "-watch") == 0) { return WatchMode(); } #endif DEBUG_INFO("\n\n"); DEBUG_INFO("Version: %s\n", Version_And_Date[0]); DEBUG_INFO("Update: %s\n", Version_And_Date[1]); DEBUG_INFO("Build: %s %s\n", __DATE__, __TIME__); // Initial share memory if(InitShareMemory() == FAIL) { DEBUG_ERROR("InitShareMemory NG\n"); if(ShmStatusCodeData!=NULL) { ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory=ON; } sleep(5); return 0; } // Enable server if rotary switch not slave mode if(ShmSysConfigAndInfo->SysConfig.isEnableLocalPowerSharing == 1) { // TCP socket server start if(fork() == 0) { if(tcpSocketServer() == FAIL) { DEBUG_ERROR("TCP socket server down.\n"); return 0; } } // Connection check loop if(fork() == 0) { if(balance_check_loop() == FAIL) { DEBUG_ERROR("Local loading balance check loop fail.\n"); return 0; } } } sleep(10); for(;;) { // Slave logic tcpSocketClient(); usleep(100000); } return FAIL; }