#pragma GCC diagnostic ignored "-Wmissing-field-initializers" #include "PCM.h" #include "NetworkCommunication/CANSessionMux.h" #include // memset #include // usleep static const UINT32 kFullMessageIDMask = 0x1fffffff; /* This can be a constant, as long as nobody needs to updatie solenoids within 1/50 of a second. */ static const INT32 kCANPeriod = 20; /* PCM Constructor - Clears all vars, establishes default settings, starts PCM background process * * @Return - void * * @Param - deviceNumber - Device ID of PCM to be controlled */ PCM::PCM(UINT8 deviceNumber) { memset(&_PcmDebug, 0, sizeof(_PcmDebug)); memset(&_PcmControl, 0, sizeof(_PcmControl)); memset(&_PcmStatus, 0, sizeof(_PcmStatus)); memset(&_PcmStatusFault,0, sizeof(_PcmStatusFault)); /* setup arbids */ SetDeviceNumber(deviceNumber); /* clear error info */ _timeSinceLastRx = 0; _timeSinceLastTx = 0; _numFailedRxs = 0; _numFailedTxs = 0; /* start thread */ _threadIsRunning = 1; _threadErr = pthread_create( &_thread, NULL, ThreadFunc, (void*) this); } /* PCM D'tor */ PCM::~PCM() { /* wait for thread to finish */ _threadIsRunning = 0; pthread_join( _thread, NULL); _thread = 0; } /* Set PCM Device Number and according CAN frame IDs * * @Return - void * * @Param - deviceNumber - Device number of PCM to control */ void PCM::SetDeviceNumber(UINT8 deviceNumber) { PCM_settings.deviceNumber = deviceNumber; PCM_settings.controlFrameID = 0x9041C00 + (deviceNumber) + (UINT32) (0 * BIT6); PCM_settings.statusFrameID = 0x9041400 + (deviceNumber) + (UINT32) (0 * BIT6); PCM_settings.statusFaultFrameID = 0x9041400 + (deviceNumber) + (UINT32) (1 * BIT6); PCM_settings.debugFrameID = 0x9041400 + (deviceNumber) + (UINT32) (2 * BIT6); } /* Set PCM solenoid state * * @Return - CTR_Code - Error code (if any) for setting solenoid * * @Param - idx - ID of solenoid (1-8) * @Param - en - Enable / Disable identified solenoid */ CTR_Code PCM::SetSolenoid(unsigned char idx, bool en) { idx--; /* make it zero based */ if (en) _PcmControl.solenoidBits |= (1ul << (7-idx)); else _PcmControl.solenoidBits &= ~(1ul << (7-idx)); if (GetTimeSinceLastTx() >= 50) return CTR_TxTimeout; return CTR_OKAY; } /* Clears PCM sticky faults (indicators of past faults * * @Return - CTR_Code - Error code (if any) for setting solenoid * * @Param - clr - Clear / do not clear faults */ CTR_Code PCM::ClearStickyFaults(bool clr) { _PcmControl.clearStickyFaults = clr; if (GetTimeSinceLastTx() >= 50) return CTR_TxTimeout; return CTR_OKAY; } /* Enables PCM Closed Loop Control of Compressor via pressure switch * * @Return - CTR_Code - Error code (if any) for setting solenoid * * @Param - en - Enable / Disable Closed Loop Control */ CTR_Code PCM::SetClosedLoopControl(bool en) { _PcmControl.closedLoopEnable = en; if (GetTimeSinceLastTx() >= 50) return CTR_TxTimeout; return CTR_OKAY; } /* Get solenoid state * * @Return - True/False - True if solenoid enabled, false otherwise * * @Param - idx - ID of solenoid (1-8) to return status of */ CTR_Code PCM::GetSolenoid(UINT8 idx, bool &status) { idx--; status = (_PcmStatus.SolenoidBits & (1ul<<(7-idx))) ? 1 : 0; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get pressure switch state * * @Return - True/False - True if pressure adequate, false if low */ CTR_Code PCM::GetPressure(bool &status) { status = _PcmStatus.pressureSwitchEn; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get compressor state * * @Return - True/False - True if enabled, false if otherwise */ CTR_Code PCM::GetCompressor(bool &status) { status = _PcmStatus.compressorOn; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get closed loop control state * * @Return - True/False - True if closed loop enabled, false if otherwise */ CTR_Code PCM::GetClosedLoopControl(bool &status) { status = _PcmStatus.isCloseloopEnabled; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get compressor current draw * * @Return - Amperes - Compressor current */ CTR_Code PCM::GetCompressorCurrent(float &status) { uint16_t bt = _PcmStatus.compressorCurrentTop6; bt <<= 4; bt |= _PcmStatus.compressorCurrentBtm4; status = 0.0201612903225806 * bt; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get voltage across solenoid rail * * @Return - Volts - Voltage across solenoid rail */ CTR_Code PCM::GetSolenoidVoltage(float &status) { uint32_t raw = _PcmStatus.solenoidVoltageTop8; raw <<= 2; raw |= _PcmStatus.solenoidVoltageBtm2; status = (double) raw * 24.7800586510264 / 1000; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get hardware fault value * * @Return - True/False - True if hardware failure detected, false if otherwise */ CTR_Code PCM::GetHardwareFault(bool &status) { status = _PcmStatus.faultHardwareFailure; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get compressor fault value * * @Return - True/False - True if shorted compressor detected, false if otherwise */ CTR_Code PCM::GetCompressorFault(bool &status) { status = _PcmStatus.faultCompCurrentTooHigh; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get solenoid fault value * * @Return - True/False - True if shorted solenoid detected, false if otherwise */ CTR_Code PCM::GetSolenoidFault(bool &status) { status = _PcmStatus.faultFuseTripped; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } // Past Faults /* Get compressor sticky fault value * * @Return - True/False - True if solenoid had previously been shorted * (and sticky fault was not cleared), false if otherwise */ CTR_Code PCM::GetCompressorStickyFault(bool &status) { status = _PcmStatus.stickyFaultCompCurrentTooHigh; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get solenoid sticky fault value * * @Return - True/False - True if compressor had previously been shorted * (and sticky fault was not cleared), false if otherwise */ CTR_Code PCM::GetSolenoidStickyFault(bool &status) { /* fix this */ status = _PcmStatus.stickyFaultFuseTripped; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get battery voltage * * @Return - Volts - Voltage across PCM power ports */ CTR_Code PCM::GetBatteryVoltage(float &status) { status = (float)_PcmStatus.battVoltage * ((59.0420332355816) / 1000.0);; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get number of total failed PCM Control Frame * * @Return - Failed Control Frames - Number of failed control frames (tokenization fails) * * @WARNING - Return only valid if [SeekDebugFrames] is enabled * See function SeekDebugFrames * See function EnableSeekDebugFrames */ CTR_Code PCM::GetNumberOfFailedControlFrames(UINT16 &status) { status = _PcmDebug.tokFailsTop8; status <<= 8; status |= _PcmDebug.tokFailsBtm8; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get raw Solenoid Blacklist * * @Return - BINARY - Raw binary breakdown of Solenoid Blacklist * BIT7 = Solenoid 1, BIT6 = Solenoid 2, etc. * * @WARNING - Return only valid if [SeekStatusFaultFrames] is enabled * See function SeekStatusFaultFrames * See function EnableSeekStatusFaultFrames */ CTR_Code PCM::GetSolenoidBlackList(UINT8 &status) { status = _PcmStatusFault.SolenoidBlacklist; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Get solenoid Blacklist status * - Blacklisted solenoids cannot be enabled until PCM is power cycled * * @Return - True/False - True if Solenoid is blacklisted, false if otherwise * * @Param - idx - ID of solenoid * * @WARNING - Return only valid if [SeekStatusFaultFrames] is enabled * See function SeekStatusFaultFrames * See function EnableSeekStatusFaultFrames */ CTR_Code PCM::IsSolenoidBlacklisted(UINT8 idx, bool &status) { idx--; if(_PcmStatusFault.SolenoidBlacklist & (1ul<<(7-idx))) status = 1; else status = 0; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } /* Return status of module enable/disable * * @Return - bool - Returns TRUE if PCM is enabled, FALSE if disabled */ CTR_Code PCM::isModuleEnabled(bool &status) { status = _PcmStatus.moduleEnabled; if (GetTimeSinceLastRx() >= 50) return CTR_RxTimeout; return CTR_OKAY; } void PCM::GetErrorInfo( uint32_t * timeSinceLastRx, uint32_t * timeSinceLastTx, uint32_t * numFailedRxs, uint32_t * numFailedTxs) { if(timeSinceLastRx) *timeSinceLastRx = _timeSinceLastRx; if(timeSinceLastTx) *timeSinceLastTx = _timeSinceLastTx; if(numFailedRxs) *numFailedRxs = _numFailedRxs; if(numFailedTxs) *numFailedTxs = _numFailedTxs; } //------------------ CAN interface and thread --------------------------------------------// /* Search for PCM Status Frame on CAN bus */ void PCM::ReadStatusFrame(void) { PcmStatus_t frame = {0}; UINT8 size = 0; INT32 status = 0; UINT32 timeStamp = 0; FRC_NetworkCommunication_CANSessionMux_receiveMessage(&PCM_settings.statusFrameID, kFullMessageIDMask, (uint8_t *)&frame, &size, &timeStamp, &status); if (status == 0) { _timeSinceLastRx = 0; _PcmStatus = frame; } else { ++_numFailedRxs; } } /* Search for PCM Status Fault Frame on CAN bus */ void PCM::ReadStatusFaultFrame(void) { PcmStatusFault_t frame= {0}; UINT8 size = 0; INT32 status = 0; UINT32 timeStamp = 0; FRC_NetworkCommunication_CANSessionMux_receiveMessage(&PCM_settings.statusFaultFrameID, kFullMessageIDMask, (uint8_t *)&frame, &size, &timeStamp, &status); if (status == 0) { _timeSinceLastRx = 0; _PcmStatusFault = frame; } else { ++_numFailedRxs; } } /* Search for PCM Debug Frame on CAN bus */ void PCM::ReadDebugFrame(void) { PcmDebug_t frame= {0}; UINT8 size = 0; INT32 status = 0; UINT32 timeStamp = 0; FRC_NetworkCommunication_CANSessionMux_receiveMessage(&PCM_settings.debugFrameID, kFullMessageIDMask, (uint8_t *)&frame, &size, &timeStamp, &status); if (status == 0) { _timeSinceLastRx = 0; _PcmDebug = frame; } else { ++_numFailedRxs; } } void * PCM::ThreadFunc() { while(_threadIsRunning){ int32_t status = 0; FRC_NetworkCommunication_CANSessionMux_sendMessage(PCM_settings.controlFrameID, (const uint8_t *)&_PcmControl, sizeof(_PcmControl), kCANPeriod, &status); if(status == 0){ /* success */ _timeSinceLastTx = 0; }else { /* something is wrong */ ++_numFailedTxs; } /* reads */ ReadStatusFrame(); ReadStatusFaultFrame(); ReadDebugFrame(); /* yield for 25ms */ usleep(25e3); /* incrememnt times since comm without overflow */ if(_timeSinceLastTx < 60000) _timeSinceLastTx += 25; if(_timeSinceLastRx < 60000) _timeSinceLastRx += 25; } return 0; } void * PCM::ThreadFunc( void *ptr ) { return ((PCM*)ptr)->ThreadFunc(); } //------------------ C interface --------------------------------------------// extern "C" { void * c_PCM_Init(void) { return new PCM(); } CTR_Code c_SetSolenoid(void * handle, unsigned char idx, INT8 param) { return ((PCM*) handle)->SetSolenoid(idx, param); } CTR_Code c_SetClosedLoopControl(void * handle, INT8 param) { return ((PCM*) handle)->SetClosedLoopControl(param); } CTR_Code c_ClearStickyFaults(void * handle, INT8 param) { return ((PCM*) handle)->ClearStickyFaults(param); } CTR_Code c_GetSolenoid(void * handle, UINT8 idx, INT8 * status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->GetSolenoid(idx, bstatus); *status = bstatus; return retval; } CTR_Code c_GetPressure(void * handle, INT8 * status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->GetPressure(bstatus); *status = bstatus; return retval; } CTR_Code c_GetCompressor(void * handle, INT8 * status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->GetCompressor(bstatus); *status = bstatus; return retval; } CTR_Code c_GetClosedLoopControl(void * handle, INT8 * status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->GetClosedLoopControl(bstatus); *status = bstatus; return retval; } CTR_Code c_GetCompressorCurrent(void * handle, float * status) { CTR_Code retval = ((PCM*) handle)->GetCompressorCurrent(*status); return retval; } CTR_Code c_GetSolenoidVoltage(void * handle, float*status) { return ((PCM*) handle)->GetSolenoidVoltage(*status); } CTR_Code c_GetHardwareFault(void * handle, INT8*status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->GetHardwareFault(bstatus); *status = bstatus; return retval; } CTR_Code c_GetCompressorFault(void * handle, INT8*status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->GetCompressorFault(bstatus); *status = bstatus; return retval; } CTR_Code c_GetSolenoidFault(void * handle, INT8*status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->GetSolenoidFault(bstatus); *status = bstatus; return retval; } CTR_Code c_GetCompressorStickyFault(void * handle, INT8*status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->GetCompressorStickyFault(bstatus); *status = bstatus; return retval; } CTR_Code c_GetSolenoidStickyFault(void * handle, INT8*status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->GetSolenoidStickyFault(bstatus); *status = bstatus; return retval; } CTR_Code c_GetBatteryVoltage(void * handle, float*status) { CTR_Code retval = ((PCM*) handle)->GetBatteryVoltage(*status); return retval; } void c_SetDeviceNumber_PCM(void * handle, UINT8 deviceNumber) { return ((PCM*) handle)->SetDeviceNumber(deviceNumber); } CTR_Code c_GetNumberOfFailedControlFrames(void * handle, UINT16*status) { return ((PCM*) handle)->GetNumberOfFailedControlFrames(*status); } CTR_Code c_GetSolenoidBlackList(void * handle, UINT8 *status) { return ((PCM*) handle)->GetSolenoidBlackList(*status); } CTR_Code c_IsSolenoidBlacklisted(void * handle, UINT8 idx, INT8*status) { bool bstatus; CTR_Code retval = ((PCM*) handle)->IsSolenoidBlacklisted(idx, bstatus); *status = bstatus; return retval; } }