Files
K2_DCU/.staticdata/.previous/20260113_090633/K2DCU/fs/da8070adbba349467ab6d7cf8ce841e4
2026-04-14 00:56:31 +09:00

865 lines
31 KiB
Plaintext

#include "main.h"
void CInitAlarmOperValue(void);
void CKeyMainPowerProcess(void);
void CKeyArrowUpProcess(void);
void CKeyArrowDownProcess(void);
void CKeyEnterProcess(void);
void CKeyMenuProcess(void);
void CKeyEngineStartStopProcess(void);
void CKeyEmergencyProcess(void);
void CInitAdcStructure(void);
Uint16 CAlarmCheck(ALARM_TYPE Idx, float32 fValue, Uint16 uiCheckDetectTime, Uint16 uiCheckType);
static inline Uint16 CheckOpenFault(Uint16 isCsHigh, Uint16 isFuseHigh);
Uint32 CGetKey(void);
void CKeyCheck(Uint32 ulChangeKey, Uint32 ulKeyRead);
static void MoveFocusLine(Uint16 maxLines, Uint16 direction);
static void CChangePasswordDigit(Uint16 direction);
static inline void CCalcAdcSum(CAdcCalcValue *AdcBuff);
CAdcCalcValue Adc_EngineHeater_I;
CAdcCalcValue Adc_GlowPlug_I;
CAdcCalcValue Adc_Solenoid_I;
CAdcCalcValue Adc_FuelPump_I;
CAdcCalcValue Adc_CoolantPump_I;
CAdcCalcValue Adc_Fan1_I;
CAdcCalcValue Adc_Fan2_I;
CAdcOperValue AdcOperValue;
CAlarmOperValue AlarmOperValue[IDX_FAULT_MAX];
CFaultBitValue FaultBitValue;
CKeyOperValue KeyOperValue;
static const CKeyHandler KeyTable[IDX_KEY_MAX] =
{
{ IDX_KEY_MAIN_POWER, CKeyMainPowerProcess },
{ IDX_KEY_ARR_UP, CKeyArrowUpProcess },
{ IDX_KEY_ARR_DOWN, CKeyArrowDownProcess },
{ IDX_KEY_ENTER, CKeyEnterProcess },
{ IDX_KEY_MENU, CKeyMenuProcess },
{ IDX_KEY_ENG_START_STOP, CKeyEngineStartStopProcess },
{ IDX_KEY_EMERGENCY, CKeyEmergencyProcess }
};
interrupt void CAdcInterrupt(void)
{
Uint16 uiTemp[IDX_ADC_MAX];
Uint16 i;
const volatile Uint16 *pAdcAddress = &AdcRegs.ADCRESULT0;
for (i = 0U; i < IDX_ADC_MAX; i++)
{
uiTemp[i] = (*(pAdcAddress++) >> 4);
}
Adc_EngineHeater_I.iAdcValue = (int16) uiTemp[IDX_ADC_ENGINE_HEATER_I];
Adc_GlowPlug_I.iAdcValue = (int16) uiTemp[IDX_ADC_GLOW_PLUG_I];
Adc_Solenoid_I.iAdcValue = (int16) uiTemp[IDX_ADC_SOLENOID_I];
Adc_FuelPump_I.iAdcValue = (int16) uiTemp[IDX_ADC_FUEL_PUMP_I];
Adc_CoolantPump_I.iAdcValue = (int16) uiTemp[IDX_ADC_COOLANT_PUMP_I];
Adc_Fan1_I.iAdcValue = (int16) uiTemp[IDX_ADC_FAN1_I];
Adc_Fan2_I.iAdcValue = (int16) uiTemp[IDX_ADC_FAN2_I];
CCalcAdcSum(&Adc_EngineHeater_I);
CCalcAdcSum(&Adc_GlowPlug_I);
CCalcAdcSum(&Adc_Solenoid_I);
CCalcAdcSum(&Adc_FuelPump_I);
CCalcAdcSum(&Adc_CoolantPump_I);
CCalcAdcSum(&Adc_Fan1_I);
CCalcAdcSum(&Adc_Fan2_I);
if (AdcOperValue.uiOffsetAdjustStart == 1U) // ADC Calibration
{
Adc_EngineHeater_I.fTempAdcOffset += Adc_EngineHeater_I.fSampledValue;
Adc_GlowPlug_I.fTempAdcOffset += Adc_GlowPlug_I.fSampledValue;
Adc_Solenoid_I.fTempAdcOffset += Adc_Solenoid_I.fSampledValue;
Adc_FuelPump_I.fTempAdcOffset += Adc_FuelPump_I.fSampledValue;
Adc_CoolantPump_I.fTempAdcOffset += Adc_CoolantPump_I.fSampledValue;
Adc_Fan1_I.fTempAdcOffset += Adc_Fan1_I.fSampledValue;
Adc_Fan2_I.fTempAdcOffset += Adc_Fan2_I.fSampledValue;
AdcOperValue.uiAdcOffsetIndex--;
if (AdcOperValue.uiAdcOffsetIndex == 0U)
{
Adc_EngineHeater_I.fOffset -= (Adc_EngineHeater_I.fTempAdcOffset / 10000.0f);
Adc_GlowPlug_I.fOffset -= (Adc_GlowPlug_I.fTempAdcOffset / 10000.0f);
Adc_Solenoid_I.fOffset -= (Adc_Solenoid_I.fTempAdcOffset / 10000.0f);
Adc_FuelPump_I.fOffset -= (Adc_FuelPump_I.fTempAdcOffset / 10000.0f);
Adc_CoolantPump_I.fOffset -= (Adc_CoolantPump_I.fTempAdcOffset / 10000.0f);
Adc_Fan1_I.fOffset -= (Adc_Fan1_I.fTempAdcOffset / 10000.0f);
Adc_Fan2_I.fOffset -= (Adc_Fan2_I.fTempAdcOffset / 10000.0f);
AdcOperValue.uiOffsetAdjustStart = 0U;
}
}
// Reinitialize for next ADC sequence
AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1U; // Reset SEQ1
AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1U; // Clear INT SEQ1 bit
PieCtrlRegs.PIEACK.all |= PIEACK_GROUP1; // Acknowledge interrupt to PIE
}
void CDisplayAlarmPopup(void)
{
Uint64 ullFaultValue = ((Uint64)FaultBitValue.ulTotal & 0x3FFFFUL) | (((Uint64)Rx210.GcuFault.uiTotal & 0xFFFFU) << 19UL) | (((Uint64)Rx310.EcuFault.uiTotal & 0x3FU) << 35UL);
Uint32 ulWarningValue = ((Uint32)Rx210.GcuWarning.uiTotal & 0x7U) | (((Uint32)Rx310.EcuWarning.uiTotal & 0xFU) << 4U);
Uint16 i;
if (OledOperValue.uiAlarmPopCheck == 0U)
{
if (ulWarningValue > 0U)
{
for (i = 0U; i < 16U; i++)
{
if ((ulWarningValue >> i) == 1U)
{
OledOperValue.uiAlarmPopCheck = 1U;
OledOperValue.uiPrevAlarmPage = OledOperValue.uiPageNum;
OledOperValue.uiPageNum = ((i / 9U) + OLED_PAGE_WARNING1);
break;
}
}
}
if (ullFaultValue > 0U)
{
for (i = 0U; i < 64U; i++)
{
if ((ullFaultValue >> i) == 1U)
{
OledOperValue.uiAlarmPopCheck = 1U;
OledOperValue.uiPrevAlarmPage = OledOperValue.uiPageNum;
OledOperValue.uiPageNum = (((i % 64U) / 8U) + OLED_PAGE_FAULT1);
break;
}
}
}
}
}
void CAlarmProcedure(void)
{
int16 iDiffRpm = 0U;
if (CGetApuOperIndex() == APU_OPER_IDX_EMERGENCY)
{
// 타임 아웃 발생 시 연결수립 비트는 클리어 한다.
GeneralOperValue.Conection.CarComputer = (FaultBitValue.bit.CarCommTimeout == 1U) ? 0U : GeneralOperValue.Conection.CarComputer;
GeneralOperValue.Conection.Gcu = (FaultBitValue.bit.GcuCommTimeout == 1U) ? 0U : GeneralOperValue.Conection.Gcu;
GeneralOperValue.Conection.Ecu = (FaultBitValue.bit.EcuCommTimeOut == 1U) ? 0U : GeneralOperValue.Conection.Ecu;
if (GeneralOperValue.uiAlarmReset == 1U)
{
GeneralOperValue.uiAlarmReset = 0U;
CInitAlarmOperValue();
}
}
else
{
if (GeneralOperValue.uiApuState > APU_OPER_IDX_EMERGENCY)
{
// Comm Timeout Checks
FaultBitValue.bit.CarCommTimeout = CAlarmCheck(IDX_FAULT_CAR_COMM, (float32)CommCheck.CarComputer, AlarmOperValue[IDX_FAULT_CAR_COMM].uiCheckTime, ALARM_OVER_CHECK);
FaultBitValue.bit.GcuCommTimeout = CAlarmCheck(IDX_FAULT_GCU_COMM, (float32)CommCheck.Gcu, AlarmOperValue[IDX_FAULT_GCU_COMM].uiCheckTime, ALARM_OVER_CHECK);
FaultBitValue.bit.EcuCommTimeOut = CAlarmCheck(IDX_FAULT_ECU_COMM, (float32)CommCheck.Ecu, AlarmOperValue[IDX_FAULT_ECU_COMM].uiCheckTime, ALARM_OVER_CHECK);
if ((GeneralOperValue.Conection.Gcu == 1U) && (GeneralOperValue.Conection.Ecu == 1U))
{
// RPM오류는 보조발전기제어기와 보조엔진제어기의 통신이 연결되었을 때 검출한다.
iDiffRpm = (int16)CGetGeneratorRpm() - (int16)CGetEngineActualRpm();
iDiffRpm = ABS(iDiffRpm);
FaultBitValue.bit.RpmError = CAlarmCheck(IDX_FAULT_RPM_ERR, (float32)iDiffRpm, AlarmOperValue[IDX_FAULT_RPM_ERR].uiCheckTime, ALARM_OVER_CHECK);
}
FaultBitValue.bit.EngineHeatOverCurrent = CAlarmCheck(IDX_FAULT_ENGINE_HEAT_OC, Adc_EngineHeater_I.fLpfValue, AlarmOperValue[IDX_FAULT_ENGINE_HEAT_OC].uiCheckTime, ALARM_OVER_CHECK);
FaultBitValue.bit.GlowPlugOverCurrent = CAlarmCheck(IDX_FAULT_GLOW_PLUG_OC, Adc_GlowPlug_I.fLpfValue, AlarmOperValue[IDX_FAULT_GLOW_PLUG_OC].uiCheckTime, ALARM_OVER_CHECK);
FaultBitValue.bit.SolenoidOverCurrent = CAlarmCheck(IDX_FAULT_SOLENOID_OC, Adc_Solenoid_I.fLpfValue, AlarmOperValue[IDX_FAULT_SOLENOID_OC].uiCheckTime, ALARM_OVER_CHECK);
FaultBitValue.bit.FuelPumpOverCurrent = CAlarmCheck(IDX_FAULT_FUEL_PUMP_OC, Adc_FuelPump_I.fLpfValue, AlarmOperValue[IDX_FAULT_FUEL_PUMP_OC].uiCheckTime, ALARM_OVER_CHECK);
FaultBitValue.bit.CoolantPumpOverCurrent = CAlarmCheck(IDX_FAULT_COOLANT_PUMP_OC, Adc_CoolantPump_I.fLpfValue, AlarmOperValue[IDX_FAULT_COOLANT_PUMP_OC].uiCheckTime, ALARM_OVER_CHECK);
FaultBitValue.bit.Fan1OverCurrent = CAlarmCheck(IDX_FAULT_FAN1_OC, Adc_Fan1_I.fLpfValue, AlarmOperValue[IDX_FAULT_FAN1_OC].uiCheckTime, ALARM_OVER_CHECK);
FaultBitValue.bit.Fan2OverCurrent = CAlarmCheck(IDX_FAULT_FAN2_OC, Adc_Fan2_I.fLpfValue, AlarmOperValue[IDX_FAULT_FAN2_OC].uiCheckTime, ALARM_OVER_CHECK);
// Fuse 신호는 각 장치에 대응하는 CS가 ON 상태에서 작동하므로 CS가 HI일 때, Fuse 신호가 HI면 단선
if (CGetApuOperIndex() > APU_OPER_IDX_STANDBY)
{
FaultBitValue.bit.EngineHeatOpen = CheckOpenFault(GPIO_ENGINE_HEATER_CS_READ(), GPIO_ENGINE_HEATER_FUSE());
FaultBitValue.bit.GlowPlugOpen = CheckOpenFault(GPIO_GLOW_PLUG_CS_READ(), GPIO_GLOW_PLUG_FUSE());
FaultBitValue.bit.SolenoidOpen = CheckOpenFault(GPIO_SOLENOID_CS_READ(), GPIO_SOLENOID_FUSE());
FaultBitValue.bit.FuelPumpOpen = CheckOpenFault(GPIO_FUEL_PUMP_CS_READ(), GPIO_FUEL_PUMP_FUSE());
FaultBitValue.bit.CoolantPumpOpen = CheckOpenFault(GPIO_COOLANT_PUMP_CS_READ(), GPIO_COOLANT_PUMP_FUSE());
FaultBitValue.bit.Fan1Open = CheckOpenFault(GPIO_FAN1_CS_READ(), GPIO_FAN1_FUSE());
FaultBitValue.bit.Fan2Open = CheckOpenFault(GPIO_FAN2_CS_READ(), GPIO_FAN2_FUSE());
}
}
}
}
Uint16 CAlarmCheck(ALARM_TYPE Idx, float32 fValue, Uint16 uiCheckDetectTime, Uint16 uiCheckType)
{
Uint16 uiCheckStatus = 0;
if (AlarmOperValue[Idx].uiCheck == 0U)
{
if (uiCheckType == ALARM_OVER_CHECK)
{
// Over Check !
if (fValue >= AlarmOperValue[Idx].fCheckLimit)
{
uiCheckStatus = 1U;
}
}
else
{
// Under Check !
if (fValue <= AlarmOperValue[Idx].fCheckLimit)
{
uiCheckStatus = 1U;
}
}
if (uiCheckStatus == 1U)
{
if (AlarmOperValue[Idx].uiCheckCount < uiCheckDetectTime)
{
AlarmOperValue[Idx].uiCheckCount++;
}
else
{
AlarmOperValue[Idx].uiCheck = 1U;
AlarmOperValue[Idx].uiCheckCount = 0U;
AlarmOperValue[Idx].fFaultValue = fValue;
}
}
else
{
AlarmOperValue[Idx].uiCheckCount = 0U;
}
}
return AlarmOperValue[Idx].uiCheck;
}
static inline Uint16 CheckOpenFault(Uint16 isCsHigh, Uint16 isFuseHigh)
{
// 두 신호가 모두 1(High)일 때만 1(Fault) 반환
return ((isCsHigh == 1U) && (isFuseHigh == 1U)) ? 1U : 0U;
}
void CInitAlarmOperValue(void)
{
int16 i;
for (i = 0; i < IDX_FAULT_MAX; i++)
{
(void) memset(&AlarmOperValue[i], 0, sizeof(CAlarmOperValue));
}
(void) memset(&FaultBitValue, 0, sizeof(CFaultBitValue));
(void) memset(&CommCheck, 0, sizeof(CCommCheck));
// 체계/GCU/ECU 통신 및 신호 단선은 다른 함수에서 처리
/*
* Alarm Check Standard Value
* Alarm Count per 1mS
*/
AlarmOperValue[IDX_FAULT_CAR_COMM].fCheckLimit = (float32)(COMM_TIME_OUT_COUNT); // 3 Seconds
AlarmOperValue[IDX_FAULT_CAR_COMM].uiCheckTime = 1U; // 시간을 감지 하므로 즉시 검출
AlarmOperValue[IDX_FAULT_GCU_COMM].fCheckLimit = (float32)(COMM_TIME_OUT_COUNT); // 3 Seconds
AlarmOperValue[IDX_FAULT_GCU_COMM].uiCheckTime = 1U; // 시간을 감지 하므로 즉시 검출
AlarmOperValue[IDX_FAULT_ECU_COMM].fCheckLimit = (float32)(COMM_TIME_OUT_COUNT); // 3 Seconds
AlarmOperValue[IDX_FAULT_ECU_COMM].uiCheckTime = 1U; // 시간을 감지 하므로 즉시 검출
AlarmOperValue[IDX_FAULT_RPM_ERR].fCheckLimit = 300.0f; // Value
AlarmOperValue[IDX_FAULT_RPM_ERR].uiCheckTime = 10U; // Value
AlarmOperValue[IDX_FAULT_ENGINE_HEAT_OC].fCheckLimit = 10.0f; // Value
AlarmOperValue[IDX_FAULT_ENGINE_HEAT_OC].uiCheckTime = 10U; // Value
AlarmOperValue[IDX_FAULT_GLOW_PLUG_OC].fCheckLimit = 10.0f; // Value
AlarmOperValue[IDX_FAULT_GLOW_PLUG_OC].uiCheckTime = 10U; // Value
AlarmOperValue[IDX_FAULT_SOLENOID_OC].fCheckLimit = 10.0f; // Value
AlarmOperValue[IDX_FAULT_SOLENOID_OC].uiCheckTime = 10U; // Value
AlarmOperValue[IDX_FAULT_FUEL_PUMP_OC].fCheckLimit = 10.0f; // Value
AlarmOperValue[IDX_FAULT_FUEL_PUMP_OC].uiCheckTime = 10U; // Value
AlarmOperValue[IDX_FAULT_COOLANT_PUMP_OC].fCheckLimit = 10.0f; // Value
AlarmOperValue[IDX_FAULT_COOLANT_PUMP_OC].uiCheckTime = 10U; // Value
AlarmOperValue[IDX_FAULT_FAN1_OC].fCheckLimit = 10.0f; // Value
AlarmOperValue[IDX_FAULT_FAN1_OC].uiCheckTime = 10U; // Value
AlarmOperValue[IDX_FAULT_FAN2_OC].fCheckLimit = 10.0f; // Value
AlarmOperValue[IDX_FAULT_FAN2_OC].uiCheckTime = 10U; // Value
}
void CInitAdc(void)
{
InitAdc(); // ADC Initialize in DSP2833x_Adc.c
AdcRegs.ADCTRL3.bit.ADCCLKPS = 0x0; // No prescaler
AdcRegs.ADCTRL1.bit.CPS = 0x1; // scaler 12.5Mhz
AdcRegs.ADCTRL3.bit.SMODE_SEL = 0x0; // sequentail mode
AdcRegs.ADCTRL1.bit.SEQ_OVRD = 0x0; // EOS
AdcRegs.ADCTRL1.bit.SEQ_CASC = 0x1; // Cascade Sequence Mode
AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0x0; // Engine_Heater_I
AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; // Glow_Plug_I
AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x2; // Solenoid_I
AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x3; // Fuel_Pump_I
AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x4; // Cooling_Pump_I
AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x5; // Fan1_I
AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x6; // Fan2_I
AdcRegs.ADCMAXCONV.all = IDX_ADC_MAX; // Setup 16 channel conversion for cascade sequence mode
AdcRegs.ADCREFSEL.bit.REF_SEL = 0x1; // external Reference 2.048[V], 'b01 - 2.048, b10 - 1.500[V], 'b11 - 1.024[v]
AdcRegs.ADCTRL2.bit.INT_MOD_SEQ1 = 0x0;
AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 0x1; // Enable SEQ1 interrupt (every EOS)
AdcRegs.ADCTRL1.bit.ACQ_PS = 6; // Sample and hold duration(width) = (ACQ_PS + 1)
CInitAdcStructure();
CInitAlarmOperValue();
}
void CInitAdcStructure(void)
{
(void) memset(&AdcOperValue, 0, sizeof(CAdcOperValue));
(void) memset(&Adc_EngineHeater_I, 0, sizeof(CAdcCalcValue));
(void) memset(&Adc_GlowPlug_I, 0, sizeof(CAdcCalcValue));
(void) memset(&Adc_Solenoid_I, 0, sizeof(CAdcCalcValue));
(void) memset(&Adc_FuelPump_I, 0, sizeof(CAdcCalcValue));
(void) memset(&Adc_CoolantPump_I, 0, sizeof(CAdcCalcValue));
(void) memset(&Adc_Fan1_I, 0, sizeof(CAdcCalcValue));
(void) memset(&Adc_Fan2_I, 0, sizeof(CAdcCalcValue));
AdcOperValue.uiAdcOffsetIndex = 10000U;
Adc_EngineHeater_I.fGain = 0.005637f;
Adc_GlowPlug_I.fGain = 0.005637f;
Adc_Solenoid_I.fGain = 0.005637f;
Adc_FuelPump_I.fGain = 0.005637f;
Adc_CoolantPump_I.fGain = 0.005637f;
Adc_Fan1_I.fGain = 0.005637f;
Adc_Fan2_I.fGain = 0.005637f;
Adc_EngineHeater_I.fOffset = -2.333f;
Adc_GlowPlug_I.fOffset = -2.333f;
Adc_Solenoid_I.fOffset = -2.333f;
Adc_FuelPump_I.fOffset = -2.333f;
Adc_CoolantPump_I.fOffset = -2.333f;
Adc_Fan1_I.fOffset = -2.333f;
Adc_Fan2_I.fOffset = -2.333f;
}
static inline void CCalcAdcSum(CAdcCalcValue *AdcBuff)
{
#if 1
AdcBuff->fSampledValue = ((float32) AdcBuff->iAdcValue * AdcBuff->fGain) + AdcBuff->fOffset;
AdcBuff->fSampledSum += AdcBuff->fSampledValue;
AdcBuff->uiSamplingCount++;
if (AdcBuff->uiSamplingCount >= 100)
{
AdcBuff->uiSamplingCount = 0;
AdcBuff->fSampledSum /= 100;
AdcBuff->fLpfValue = (ADC_LPF_GAIN * AdcBuff->fSampledSum) + ((1.0f - ADC_LPF_GAIN) * AdcBuff->fLpfValue);
AdcBuff->fSampledSum = 0.0f;
}
#else
AdcBuff->fSampledValue = ((float32) AdcBuff->iAdcValue * AdcBuff->fGain) + AdcBuff->fOffset;
AdcBuff->fLpfValue = (ADC_LPF_GAIN * AdcBuff->fSampledValue) + ((1.0f - ADC_LPF_GAIN) * AdcBuff->fLpfValue);
#endif
}
Uint32 CGetKey(void)
{
Uint16 i, ucDiv, ucMod;
Uint32 ulGpioData = 0UL, ulKeyRead = 0UL;
Uint16 ucKeyGpioList[7] = { 67, 39, 31, 30, 29, 66, 64};
for (i = 0; i < IDX_KEY_MAX; i++)
{
ucDiv = ucKeyGpioList[i] / 32;
ucMod = ucKeyGpioList[i] % 32;
if (ucDiv == 0U) // GPIO-A
{
ulGpioData = GpioDataRegs.GPADAT.all;
}
else if (ucDiv == 1U)
{
ulGpioData = GpioDataRegs.GPBDAT.all;
}
else
{
ulGpioData = GpioDataRegs.GPCDAT.all;
}
if (((ulGpioData >> ucMod) & 0x01UL) == 0U) // Push Check
{
ulKeyRead |= (0x01UL << i);
}
}
return ulKeyRead;
}
void CKeyCheckProcedure(void)
{
static Uint32 ulLongKeyCnt = 0UL; // 롱키 카운트용 변수
static Uint16 uiLongKeyProcessed = 0U; // 롱키 처리 완료 플래그 (중복 실행 방지)
static Uint32 ulPrevKey = 0UL;
Uint32 ulChangeKey;
Uint32 ulReadKey = CGetKey();
ulChangeKey = (ulPrevKey ^ ulReadKey) & ~KEY_POWER_MASK; // 현재 키와 이전 키를 비교하되, 롱키(Bit 0)는 변화 감지에서 제외함 (& ~KEY_POWER_MASK)
if (ulChangeKey > 0UL)
{
if (KeyOperValue.uiKeyWait == 0U) // 채터링 무시 시작
{
KeyOperValue.uiKeyWait = 1U;
KeyOperValue.uiKeyWaitCount = 20; // 20ms
}
else
{
// 전원키를 제외한 나머지 키들은 POST 단계가 넘어가야지 동작한다.
if ((KeyOperValue.uiKeyWaitCount == 0U) && (CGetApuOperIndex() > APU_OPER_IDX_POST))
{
ulPrevKey = (ulPrevKey & KEY_POWER_MASK) | (ulReadKey & ~KEY_POWER_MASK); // ulPrevKey의 나머지 비트는 유지하고 변경된 비트만 갱신
CKeyCheck(ulChangeKey, ulReadKey); // 일반 키 동작
}
}
}
else
{
// 변화가 없으면 채터링 대기 초기화 (일반 키용)
// 단, 눌려있는 상태 유지를 위해 ulPrevKey 갱신은 필요 없음
if ((KeyOperValue.uiKeyWait) != 0U && (KeyOperValue.uiKeyWaitCount == 0U))
{
KeyOperValue.uiKeyWait = 0U;
}
}
// Bit 0이 눌려 있는지 확인 (1 = 눌림)
if ((ulReadKey & KEY_POWER_MASK) == KEY_POWER_MASK)
{
// 이미 처리가 끝난 상태가 아니라면 카운트 증가
if (uiLongKeyProcessed == 0U)
{
ulLongKeyCnt++;
// 1초(1000ms) 도달 시 동작 수행
if (ulLongKeyCnt >= LONG_KEY_TIME)
{
CKeyCheck(KEY_POWER_MASK, ulReadKey); // 롱키 동작 수행 (CKeyCheck에 롱키 비트만 전달)
uiLongKeyProcessed = 1U; // 떼기 전까지 다시 동작하지 않도록 플래그 설정
ulLongKeyCnt = LONG_KEY_TIME; // 카운트 오버플로우 방지
}
}
}
else
{
// 키를 뗐을 때 변수들 초기화
ulLongKeyCnt = 0UL;
uiLongKeyProcessed = 0U;
// ulPrevKey의 Bit 0 상태도 0으로 동기화 (다음 비교를 위해)
ulPrevKey &= ~KEY_POWER_MASK;
}
}
void CKeyWaitCount(void)
{
if (KeyOperValue.uiKeyWait == 1U)
{
if (KeyOperValue.uiKeyWaitCount > 0U)
{
KeyOperValue.uiKeyWaitCount--;
}
else
{
KeyOperValue.uiKeyWait = 0U;
}
}
}
void CKeyCheck(Uint32 ulChangeKey, Uint32 ulKeyRead)
{
Uint16 i;
for (i = 0U; i < IDX_KEY_MAX; i++)
{
if ((ulChangeKey & (0x1UL << i)) > 0U)
{
if ((ulKeyRead & (0x1UL << i)) > 0U)
{
KeyTable[i].pAction();
}
}
}
}
void CKeyArrowUpProcess(void)
{
if (OledOperValue.uiPageNum == OLED_PAGE_APU2)
{
OledOperValue.uiPageNum = OLED_PAGE_APU1;
}
else if (OledOperValue.uiPageNum == OLED_PAGE_MENU1)
{
if (OledOperValue.uiFocusLine == OLED_LINE_FOCUS_1)
{
OledOperValue.uiFocusLine = OLED_LINE_FOCUS_1;
}
else
{
MoveFocusLine(4U, DIR_UP);
}
}
else if (OledOperValue.uiPageNum == OLED_PAGE_MENU2)
{
if (OledOperValue.uiFocusLine == OLED_LINE_FOCUS_1)
{
// Go back to Menu 1
OledOperValue.uiFocusLine = OLED_LINE_FOCUS_4;
OledOperValue.uiPageNum = OLED_PAGE_MENU1;
}
else
{
MoveFocusLine(3U, DIR_UP);
}
}
else if ((OledOperValue.uiPageNum > OLED_PAGE_SENSOR1) && (OledOperValue.uiPageNum <= OLED_PAGE_SENSOR4))
{
OledOperValue.uiPageNum = OledOperValue.uiPageNum - 1U;
}
else if ((OledOperValue.uiPageNum > OLED_PAGE_WARNING1) && (OledOperValue.uiPageNum <= OLED_PAGE_WARNING2))
{
OledOperValue.uiPageNum = OledOperValue.uiPageNum - 1U;
}
else if ((OledOperValue.uiPageNum > OLED_PAGE_FAULT1) && (OledOperValue.uiPageNum <= OLED_PAGE_FAULT6))
{
OledOperValue.uiPageNum = OledOperValue.uiPageNum - 1U;
}
else if (OledOperValue.uiPageNum == OLED_PAGE_PASSWORD)
{
CChangePasswordDigit(DIR_UP);
}
else if (OledOperValue.uiPageNum == OLED_PAGE_RESET_ALARM)
{
OledOperValue.uiResetAnswer = OledOperValue.uiResetAnswer ^ 1U; // toggle
}
else
{
if (OledOperValue.uiPageNum == OLED_PAGE_MAINTENENCE)
{
if (OledOperValue.uiFocusLine == OLED_LINE_FOCUS_1)
{
OledOperValue.uiFocusLine = OLED_LINE_FOCUS_1;
}
else
{
MoveFocusLine(3U, DIR_UP);
}
}
}
}
void CKeyArrowDownProcess(void)
{
if (OledOperValue.uiPageNum == OLED_PAGE_APU1)
{
OledOperValue.uiPageNum = OLED_PAGE_APU2;
}
else if (OledOperValue.uiPageNum == OLED_PAGE_MENU1)
{
if (OledOperValue.uiFocusLine == OLED_LINE_FOCUS_4)
{
// Bottom of Menu 1 -> Go to Menu 2
OledOperValue.uiFocusLine = OLED_LINE_FOCUS_1;
OledOperValue.uiPageNum = OLED_PAGE_MENU2;
}
else
{
MoveFocusLine(4U, DIR_DOWN);
}
}
else if (OledOperValue.uiPageNum == OLED_PAGE_MENU2)
{
if (OledOperValue.uiFocusLine == OLED_LINE_FOCUS_3)
{
OledOperValue.uiFocusLine = OLED_LINE_FOCUS_3;
}
else
{
MoveFocusLine(3U, DIR_DOWN);
}
}
else if ((OledOperValue.uiPageNum >= OLED_PAGE_SENSOR1) && (OledOperValue.uiPageNum < OLED_PAGE_SENSOR4))
{
OledOperValue.uiPageNum = OledOperValue.uiPageNum + 1U;
}
else if ((OledOperValue.uiPageNum >= OLED_PAGE_WARNING1) && (OledOperValue.uiPageNum < OLED_PAGE_WARNING2))
{
OledOperValue.uiPageNum = OledOperValue.uiPageNum + 1U;
}
else if ((OledOperValue.uiPageNum >= OLED_PAGE_FAULT1) && (OledOperValue.uiPageNum < OLED_PAGE_FAULT6))
{
OledOperValue.uiPageNum = OledOperValue.uiPageNum + 1U;
}
else if (OledOperValue.uiPageNum == OLED_PAGE_PASSWORD)
{
CChangePasswordDigit(DIR_DOWN);
}
else if (OledOperValue.uiPageNum == OLED_PAGE_RESET_ALARM)
{
OledOperValue.uiResetAnswer = OledOperValue.uiResetAnswer ^ 1U; // toggle
}
else
{
if (OledOperValue.uiPageNum == OLED_PAGE_MAINTENENCE)
{
if (OledOperValue.uiFocusLine == OLED_LINE_FOCUS_3)
{
OledOperValue.uiFocusLine = OLED_LINE_FOCUS_3;
}
else
{
MoveFocusLine(3U, DIR_DOWN);
}
}
}
}
static void CChangePasswordDigit(Uint16 direction)
{
// Ensure the focus digit is within valid range to avoid out-of-bounds access
if (OledOperValue.uiFocusDigit <= OLED_PASS_DIGIT_4)
{
Uint16 *pDigit = &GeneralOperValue.uiPassword[OledOperValue.uiFocusDigit];
if (direction == DIR_UP)
{
*pDigit = (*pDigit + 1U) % 10U;
}
else // DIR_DOWN
{
if (*pDigit == 0U)
{
*pDigit = 9U;
}
else
{
*pDigit = (*pDigit - 1U) % 10U;
}
}
}
}
static void MoveFocusLine(Uint16 maxLines, Uint16 direction)
{
if (direction == DIR_UP)
{
OledOperValue.uiFocusLine = (OledOperValue.uiFocusLine + maxLines - 1U) % maxLines;
}
else // DIR_DOWN
{
OledOperValue.uiFocusLine = (OledOperValue.uiFocusLine + 1U) % maxLines;
}
}
void CKeyEnterProcess(void)
{
switch (OledOperValue.uiPageNum)
{
case OLED_PAGE_MENU1:
{
switch (OledOperValue.uiFocusLine)
{
case OLED_MENU_APU:
{
OledOperValue.uiPageNum = OLED_PAGE_APU1;
break;
}
case OLED_MENU_TEMP:
{
OledOperValue.uiPageNum = OLED_PAGE_TEMP;
break;
}
case OLED_MENU_SENSOR:
{
OledOperValue.uiPageNum = OLED_PAGE_SENSOR1;
break;
}
default:
{
if (OledOperValue.uiFocusLine == OLED_MENU_WARNING)
{
OledOperValue.uiPageNum = OLED_PAGE_WARNING1;
}
break;
}
}
break;
}
case OLED_PAGE_MENU2:
{
switch (OledOperValue.uiFocusLine)
{
case OLED_LINE_FOCUS_1: // Fault
{
OledOperValue.uiPageNum = OLED_PAGE_FAULT1;
break;
}
case OLED_LINE_FOCUS_2: // Reset
{
OledOperValue.uiPrevFocusLine = OledOperValue.uiFocusLine;
OledOperValue.uiPageNum = OLED_PAGE_RESET_ALARM;
break;
}
case OLED_LINE_FOCUS_3: // Maintenence
{
OledOperValue.uiPrevFocusLine = OledOperValue.uiFocusLine;
OledOperValue.uiPageNum = OLED_PAGE_PASSWORD;
OledOperValue.uiFocusDigit = OLED_PASS_DIGIT_1;
break;
}
default:
break;
}
break;
}
case OLED_PAGE_PASSWORD:
{
if (OledOperValue.uiFocusDigit < OLED_PASS_DIGIT_4)
{
OledOperValue.uiFocusDigit = (OledOperValue.uiFocusDigit + 1U) % 4U;
}
else
{
// Check password
const Uint16 uiPassword[4] = DEBUG_MENU_PASSWORD;
if (memcmp(GeneralOperValue.uiPassword, uiPassword, sizeof(uiPassword)) == 0U)
{
GeneralOperValue.uiMaintenence = 1U;
OledOperValue.uiPageNum = OLED_PAGE_MAINTENENCE;
OledOperValue.uiFocusLine = OLED_LINE_FOCUS_1;
}
else
{
OledOperValue.uiFocusDigit = OLED_PASS_DIGIT_1;
}
}
break;
}
case OLED_PAGE_RESET_ALARM:
{
// Selected "YES"
if (OledOperValue.uiResetAnswer == 1U)
{
if (CApuSystemAlarmCheck() > 0)
{
GeneralOperValue.uiAlarmReset = 1U;
OledOperValue.uiAlarmPopCheck = 0U;
OledOperValue.uiAlreadyAlarm = 0U;
}
}
OledOperValue.uiPageNum = OLED_PAGE_MENU2;
break;
}
case OLED_PAGE_MAINTENENCE:
{
if (OledOperValue.uiFocusLine == OLED_LINE_FOCUS_1)
{
GeneralOperValue.Maintenence.ManualCranking = GeneralOperValue.Maintenence.ManualCranking ^ 1U; // Toggle
}
else if (OledOperValue.uiFocusLine == OLED_LINE_FOCUS_2)
{
GeneralOperValue.Maintenence.LampTest = GeneralOperValue.Maintenence.LampTest ^ 1U; // Toggle
}
else
{
if (OledOperValue.uiFocusLine == OLED_LINE_FOCUS_3)
{
GeneralOperValue.Maintenence.KeyTest = GeneralOperValue.Maintenence.KeyTest ^ 1U; // Toggle
OledOperValue.uiPageNum = OLED_PAGE_KEY_TEST;
}
}
break;
}
default:
{
// Handle Fault/Warning page return logic
if ((OledOperValue.uiPageNum >= OLED_PAGE_WARNING1) && (OledOperValue.uiPageNum <= OLED_PAGE_FAULT6))
{
if (OledOperValue.uiAlarmPopCheck == 1U)
{
OledOperValue.uiAlreadyAlarm = 1U;
OledOperValue.uiPageNum = OledOperValue.uiPrevAlarmPage;
}
}
break;
}
}
}
void CKeyMenuProcess(void)
{
// Return to main menus from sub-pages
if ((OledOperValue.uiPageNum == OLED_PAGE_MENU1) || (OledOperValue.uiPageNum == OLED_PAGE_MENU2))
{
OledOperValue.uiPageNum = OLED_PAGE_APU1;
OledOperValue.uiFocusLine = 0U;
}
else
{
if ((OledOperValue.uiPageNum >= OLED_PAGE_FAULT1) && (OledOperValue.uiPageNum <= OLED_PAGE_MAINTENENCE))
{
// Return to Menu 2 from Faults or Debug
if (OledOperValue.uiPageNum == OLED_PAGE_MAINTENENCE)
{
GeneralOperValue.uiMaintenence = 0U;
OledOperValue.uiFocusLine = OledOperValue.uiPrevFocusLine;
}
OledOperValue.uiPageNum = OLED_PAGE_MENU2;
}
else
{
// Return to Menu 1 from others (APU, Temp, Sensor, Warning)
OledOperValue.uiPageNum = OLED_PAGE_MENU1;
}
}
}
void CKeyMainPowerProcess(void)
{
if (CGetApuOperIndex() <= APU_OPER_IDX_STANDBY)
{
// APU가 정지 상태에서만 전원 스위치 입력 가능
OledOperValue.uiPageNum = OLED_PAGE_SHUTDOWN;
if (CSoftWaitCountProcedure(SOFTTIMER_WAIT_SHUTDOWN, TIME_1SEC) == TIME_OVER)
{
GPIO_POWER_HOLD(0);
}
}
}
void CKeyEngineStartStopProcess(void)
{
KeyOperValue.KeyList.bit.EngineStartStop = KeyOperValue.KeyList.bit.EngineStartStop ^ 1U; // Toggle
}
void CKeyEmergencyProcess(void)
{
// 비상정지 스위치를 클리어 하기 위해서는 APU 시스템에 알람이 없어야 한다.
KeyOperValue.KeyList.bit.Emergency = KeyOperValue.KeyList.bit.Emergency ^ 1U; // Toggle
}