From 28740cdb3bd31cdd27ec3359bcf0a44171b69d87 Mon Sep 17 00:00:00 2001 From: HosuKim Date: Tue, 14 Apr 2026 00:43:29 +0900 Subject: [PATCH] first commit --- Source/Comm.c | 1436 +++++++++++++++++++++++++++++++++ Source/Comm.h | 696 ++++++++++++++++ Source/Display.c | 1979 ++++++++++++++++++++++++++++++++++++++++++++++ Source/Display.h | 156 ++++ Source/Oper.c | 647 +++++++++++++++ Source/Oper.h | 63 ++ Source/State.c | 1296 ++++++++++++++++++++++++++++++ Source/State.h | 219 +++++ Source/main.c | 730 +++++++++++++++++ Source/main.h | 254 ++++++ 10 files changed, 7476 insertions(+) create mode 100644 Source/Comm.c create mode 100644 Source/Comm.h create mode 100644 Source/Display.c create mode 100644 Source/Display.h create mode 100644 Source/Oper.c create mode 100644 Source/Oper.h create mode 100644 Source/State.c create mode 100644 Source/State.h create mode 100644 Source/main.c create mode 100644 Source/main.h diff --git a/Source/Comm.c b/Source/Comm.c new file mode 100644 index 0000000..e2725c6 --- /dev/null +++ b/Source/Comm.c @@ -0,0 +1,1436 @@ +/* ========================================================================= */ +/* 1. Includes */ +/* ========================================================================= */ +#include "main.h" + +/* ========================================================================= */ +/* 2. Local Macros & Constants (내부 전용 매크로 및 상수) */ +/* ========================================================================= */ + +/* ========================================================================= */ +/* 3. Local Typedefs & Structures (내부 전용 사용자 정의 자료형) */ +/* ========================================================================= */ +static CTx100 Tx100; +static CTx101 Tx101; +static CTx102 Tx102; // Command Data +static CTx103 Tx103; // Command Data +static CTx110 Tx110; +static CTx120 Tx120; +static CTx121 Tx121; +static CTx122 Tx122; +static CTx123 Tx123; +static CTx124 Tx124; + +static CTx700 Tx700; +static CTx701 Tx701; +static CTx710 Tx710; +static CTx720 Tx720; +static CTx730 Tx730; +static CTx731 Tx731; +static CTx732 Tx732; +static CTx733 Tx733; +static CTx734 Tx734; +static CTx740 Tx740; +static CTx741 Tx741; +static CTx750 Tx750; +static CTx751 Tx751; +static CTx752 Tx752; + +static CRx201 Rx201; + +/* ========================================================================= */ +/* 4. Internal Linkage Function Declarations (내부 동작용 Static 함수 선언) */ +/* ========================================================================= */ +static void CInitECanA(void); +static void CInitECanB(void); +static void CECanASetMbox(void); +static void CECanBSetMbox(void); +static void CInitECanStructure(void); +static inline Uint16 CPackBit(Uint16 data, Uint16 pos); +static inline Uint16 CPackField(Uint16 data, Uint16 mask, Uint16 pos); + +/* ========================================================================= */ +/* 5. Global Variables & Structure Initialization (전역 변수 및 구조체 초기화) */ +/* ========================================================================= */ +CCommCheck CommCheck; + +// Rx - GCU +CRx200 Rx200; +CRx210 Rx210; +CRx220 Rx220; +CRx221 Rx221; + +// Rx - ECU +CRx300 Rx300; +CRx301 Rx301; +CRx310 Rx310; +CRx320 Rx320; +CRx321 Rx321; +CRx322 Rx322; + +#ifdef AUX_TEST +// Rx - For Aux Test +CRx400 Rx400; +#endif + +/* ========================================================================= */ +/* Function Definitions */ +/* ========================================================================= */ +interrupt void CECanInterruptA(void) +{ + struct ECAN_REGS ECanShadow; + ECanShadow.CANRMP.all = ECanaRegs.CANRMP.all; + + GeneralOperValue.Conection.CarComputer = 1U; // 한번이라도 통신이 수신되었다면 해당 장치가 연결되었다고 판단. + CommCheck.CarComputer = 0U; // 송신 시 타임아웃 카운트 클리어 + + ECanaRegs.CANRMP.all = ECanShadow.CANRMP.all; +} + +static inline Uint32 CPackMboxData(Uint16 b0, Uint16 b1, Uint16 b2, Uint16 b3) +{ + return (((Uint32)b0 << 24U) | ((Uint32)b1 << 16U) | ((Uint32)b2 << 8U) | (Uint32)b3); +} + +void CSendECanDataA(void) +{ + Uint16 uiTemp = 0U; + float32 fTemp = 0.0F; + + // --------------------------------------------------------- + // [700h - MBOX0] + // --------------------------------------------------------- + Tx700.HeartBit = (Tx700.HeartBit + 1U) % 65535U; + + // BYTE 0~1(HeartBit), BYTE 2(DCUversionMajor), BYTE 3(DCUversionMinor), BYTE 4(GCUversionMajor), BYTE 5(GCUversionMinor), BYTE 6(ECUversionMajor), BYTE 7(ECUversionMinor) + ECanaMboxes.MBOX0.MDL.all = CPackMboxData((Uint16)((Tx700.HeartBit >> 0U) & 0xFFU), (Uint16)((Tx700.HeartBit >> 8U) & 0xFFU), + (Uint16)FIRMWARE_VERSION_MAJOR, (Uint16)FIRMWARE_VERSION_MINOR); + ECanaMboxes.MBOX0.MDH.all = CPackMboxData(Rx200.VersionMajor, Rx200.VersionMinor, Rx300.VersionMajor, Rx300.VersionMinor); + + // --------------------------------------------------------- + // [701h - MBOX1] + // --------------------------------------------------------- + Tx701.DcuPlayState = (Uint16)(GeneralOperValue.uiApuState & 0x7U); + + uiTemp = 0U; + uiTemp |= CPackBit(GeneralOperValue.uiFaultOccured, 0U); + uiTemp |= CPackBit(GeneralOperValue.uiEmergency, 1U); + uiTemp |= CPackBit(KeyOperValue.KeyList.MainPower, 2U); + uiTemp |= CPackBit((GPIO_FAIL_SAFE_READ() == false) ? 1U : 0U, 3U); + Tx701.DcuState = uiTemp; + + Tx701.GcuPlayState = Rx201.PlayState; + Tx701.GcuState = Rx201.State; + Tx701.EcuState = Rx301.State; + + // BYTE 0(DcuPlayState), BYTE 1(DcuState), BYTE 2(GcuPlayState), BYTE 3(GcuState), BYTE 4(EcuState), BYTE 5~7(Rsvd) + ECanaMboxes.MBOX1.MDL.all = CPackMboxData(Tx701.DcuPlayState, Tx701.DcuState, Tx701.GcuPlayState, Tx701.GcuState); + ECanaMboxes.MBOX1.MDH.all = CPackMboxData(Tx701.EcuState, 0U, 0U, 0U); + + // --------------------------------------------------------- + // [710h - MBOX5] + // --------------------------------------------------------- + Tx710.GcuWarning = Rx210.GcuWarning; + Tx710.EcuWarning = Rx310.EcuWarning; + + // BYTE 0(GcuWarning), BYTE 1(EcuWarning), BYTE 2~7(Rsvd) + ECanaMboxes.MBOX5.MDL.all = CPackMboxData(Tx710.GcuWarning, Tx710.EcuWarning, 0U, 0U); + ECanaMboxes.MBOX5.MDH.all = CPackMboxData(0U, 0U, 0U, 0U); + + // --------------------------------------------------------- + // [720h - MBOX10] + // --------------------------------------------------------- + Tx720.DcuFault0 = (Uint16)((ulDcuTotalAlarm >> 0U) & 0xFFU); + Tx720.DcuFault1 = (Uint16)((ulDcuTotalAlarm >> 8U) & 0xFFU); + Tx720.DcuFault2 = (Uint16)((ulDcuTotalAlarm >> 16U) & 0xFFU); + Tx720.DcuFault3 = (Uint16)((ulDcuTotalAlarm >> 24U) & 0xFFU); + + Tx720.GcuFault0 = (Uint16)((Rx210.GcuFault >> 0U) & 0xFFU); + Tx720.GcuFault1 = (Uint16)((Rx210.GcuFault >> 8U) & 0xFFU); + Tx720.EcuFault = Rx310.EcuFault; + + // BYTE 0~3(DcuFault0~3), BYTE 4~5(GcuFault0~1), BYTE 6(Rsvd), BYTE 7(EcuFault) + ECanaMboxes.MBOX10.MDL.all = CPackMboxData(Tx720.DcuFault0, Tx720.DcuFault1, Tx720.DcuFault2, Tx720.DcuFault3); + ECanaMboxes.MBOX10.MDH.all = CPackMboxData(Tx720.GcuFault0, Tx720.GcuFault1, 0U, Tx720.EcuFault); + + // --------------------------------------------------------- + // [730h - MBOX15] + // --------------------------------------------------------- + Tx730.AuxState = (Uint16)GET_ALL_AUX_STATUS(); + + // BYTE 0(AuxState), BYTE 1~7(Rsvd) + ECanaMboxes.MBOX15.MDL.all = CPackMboxData(Tx730.AuxState, 0U, 0U, 0U); + ECanaMboxes.MBOX15.MDH.all = CPackMboxData(0U, 0U, 0U, 0U); + + // --------------------------------------------------------- + // [731h - MBOX16] + // --------------------------------------------------------- + fTemp = Adc_EngineHeater_V.fLpfValue * 10.0F; + Tx731.EngineHeaterVoltage = (Uint16)fTemp; + + fTemp = Adc_EngineHeater_I.fLpfValue * 10.0F; + Tx731.EngineHeaterCurrent = (Uint16)fTemp; + + fTemp = Adc_GlowPlug_V.fLpfValue * 10.0F; + Tx731.GlowPlugVoltage = (Uint16)fTemp; + + fTemp = Adc_GlowPlug_I.fLpfValue * 10.0F; + Tx731.GlowPlugCurrent = (Uint16)fTemp; + + // BYTE 0~1(EngineHeaterVoltage), BYTE 2~3(EngineHeaterCurrent), BYTE 4~5(GlowPlugVoltage), BYTE 6~7(GlowPlugCurrent) + ECanaMboxes.MBOX16.MDL.all = CPackMboxData((Uint16)((Tx731.EngineHeaterVoltage >> 0U) & 0xFFU), (Uint16)((Tx731.EngineHeaterVoltage >> 8U) & 0xFFU), + (Uint16)((Tx731.EngineHeaterCurrent >> 0U) & 0xFFU), (Uint16)((Tx731.EngineHeaterCurrent >> 8U) & 0xFFU)); + ECanaMboxes.MBOX16.MDH.all = CPackMboxData((Uint16)((Tx731.GlowPlugVoltage >> 0U) & 0xFFU), (Uint16)((Tx731.GlowPlugVoltage >> 8U) & 0xFFU), + (Uint16)((Tx731.GlowPlugCurrent >> 0U) & 0xFFU), (Uint16)((Tx731.GlowPlugCurrent >> 8U) & 0xFFU)); + + // --------------------------------------------------------- + // [732h - MBOX17] + // --------------------------------------------------------- + fTemp = Adc_Solenoid_V.fLpfValue * 10.0F; + Tx732.SolenoidVoltage = (Uint16)fTemp; + + fTemp = Adc_Solenoid_I.fLpfValue * 10.0F; + Tx732.SolenoidCurrent = (Uint16)fTemp; + + fTemp = Adc_FuelPump_V.fLpfValue * 10.0F; + Tx732.FuelPumpVoltage = (Uint16)fTemp; + + fTemp = Adc_FuelPump_I.fLpfValue * 10.0F; + Tx732.FuelPumpCurrent = (Uint16)fTemp; + + // BYTE 0~1(SolenoidVoltage), BYTE 2~3(SolenoidCurrent), BYTE 4~5(FuelPumpVoltage), BYTE 6~7(FuelPumpCurrent) + ECanaMboxes.MBOX17.MDL.all = CPackMboxData((Uint16)((Tx732.SolenoidVoltage >> 0U) & 0xFFU), (Uint16)((Tx732.SolenoidVoltage >> 8U) & 0xFFU), + (Uint16)((Tx732.SolenoidCurrent >> 0U) & 0xFFU), (Uint16)((Tx732.SolenoidCurrent >> 8U) & 0xFFU)); + ECanaMboxes.MBOX17.MDH.all = CPackMboxData((Uint16)((Tx732.FuelPumpVoltage >> 0U) & 0xFFU), (Uint16)((Tx732.FuelPumpVoltage >> 8U) & 0xFFU), + (Uint16)((Tx732.FuelPumpCurrent >> 0U) & 0xFFU), (Uint16)((Tx732.FuelPumpCurrent >> 8U) & 0xFFU)); + + // --------------------------------------------------------- + // [733h - MBOX18] + // --------------------------------------------------------- + fTemp = Adc_CoolantPump_V.fLpfValue * 10.0F; + Tx733.CoolantPumpVoltage = (Uint16)fTemp; + + fTemp = Adc_CoolantPump_I.fLpfValue * 10.0F; + Tx733.CoolantPumpCurrent = (Uint16)fTemp; + + fTemp = Adc_Fan1_V.fLpfValue * 10.0F; + Tx733.Fan1Voltage = (Uint16)fTemp; + + fTemp = Adc_Fan1_I.fLpfValue * 10.0F; + Tx733.Fan1Current = (Uint16)fTemp; + + // BYTE 0~1(CoolantPumpVoltage), BYTE 2~3(CoolantPumpCurrent), BYTE 4~5(Fan1Voltage), BYTE 6~7(Fan1Current) + ECanaMboxes.MBOX18.MDL.all = CPackMboxData((Uint16)((Tx733.CoolantPumpVoltage >> 0U) & 0xFFU), (Uint16)((Tx733.CoolantPumpVoltage >> 8U) & 0xFFU), + (Uint16)((Tx733.CoolantPumpCurrent >> 0U) & 0xFFU), (Uint16)((Tx733.CoolantPumpCurrent >> 8U) & 0xFFU)); + ECanaMboxes.MBOX18.MDH.all = CPackMboxData((Uint16)((Tx733.Fan1Voltage >> 0U) & 0xFFU), (Uint16)((Tx733.Fan1Voltage >> 8U) & 0xFFU), + (Uint16)((Tx733.Fan1Current >> 0U) & 0xFFU), (Uint16)((Tx733.Fan1Current >> 8U) & 0xFFU)); + + // --------------------------------------------------------- + // [734h - MBOX19] + // --------------------------------------------------------- + fTemp = Adc_Fan2_V.fLpfValue * 10.0F; + Tx734.Fan2Voltage = (Uint16)fTemp; + + fTemp = Adc_Fan2_I.fLpfValue * 10.0F; + Tx734.Fan2Current = (Uint16)fTemp; + + // BYTE 0~1(Fan2Voltage), BYTE 2~3(Fan2Current), BYTE 4~7(Rsvd) + ECanaMboxes.MBOX19.MDL.all = CPackMboxData((Uint16)((Tx734.Fan2Voltage >> 0U) & 0xFFU), (Uint16)((Tx734.Fan2Voltage >> 8U) & 0xFFU), + (Uint16)((Tx734.Fan2Current >> 0U) & 0xFFU), (Uint16)((Tx734.Fan2Current >> 8U) & 0xFFU)); + ECanaMboxes.MBOX19.MDH.all = CPackMboxData(0U, 0U, 0U, 0U); + + // --------------------------------------------------------- + // [740h - MBOX20] + // --------------------------------------------------------- + Tx740.Voltage = Rx220.DcVoltage; + Tx740.Current = Rx220.DcCurrent; + Tx740.Rpm = Rx220.Rpm; + Tx740.Power = Rx220.Power; + + // BYTE 0~1(Voltage), BYTE 2~3(Current), BYTE 4~5(Rpm), BYTE 6~7(Power) + ECanaMboxes.MBOX20.MDL.all = CPackMboxData((Uint16)((Tx740.Voltage >> 0U) & 0xFFU), (Uint16)((Tx740.Voltage >> 8U) & 0xFFU), + (Uint16)((Tx740.Current >> 0U) & 0xFFU), (Uint16)((Tx740.Current >> 8U) & 0xFFU)); + ECanaMboxes.MBOX20.MDH.all = CPackMboxData((Uint16)((Tx740.Rpm >> 0U) & 0xFFU), (Uint16)((Tx740.Rpm >> 8U) & 0xFFU), + (Uint16)((Tx740.Power >> 0U) & 0xFFU), (Uint16)((Tx740.Power >> 8U) & 0xFFU)); + + // --------------------------------------------------------- + // [741h - MBOX21] + // --------------------------------------------------------- + Tx741.PcbTemperature = Rx221.PcbTemperature; + Tx741.FetTemperature = Rx221.FetTemperature; + Tx741.Winding1Temperature = Rx221.GenTemperature1; + Tx741.Winding2Temperature = Rx221.GenTemperature2; + + // BYTE 0(PcbTemperature), BYTE 1(FetTemperature), BYTE 2(Winding1Temperature), BYTE 3(Winding2Temperature), BYTE 4~7(Rsvd) + ECanaMboxes.MBOX21.MDL.all = CPackMboxData(Tx741.PcbTemperature, Tx741.FetTemperature, Tx741.Winding1Temperature, Tx741.Winding2Temperature); + ECanaMboxes.MBOX21.MDH.all = CPackMboxData(0U, 0U, 0U, 0U); + + // --------------------------------------------------------- + // [750h - MBOX25] + // --------------------------------------------------------- + Tx750.ActualRpm = Rx320.ActualRpm; + Tx750.SetRpm = Rx320.SetRpm; + Tx750.ActualTorque = Rx320.ActualTorque; + Tx750.SetTorque = Rx320.SetTorque; + Tx750.SystemVoltage = Rx320.SystemVoltage; + + // BYTE 0~1(ActualRpm), BYTE 2~3(SetRpm), BYTE 4(ActualTorque), BYTE 5(SetTorque), BYTE 6~7(SystemVoltage) + ECanaMboxes.MBOX25.MDL.all = CPackMboxData((Uint16)((Tx750.ActualRpm >> 0U) & 0xFFU), (Uint16)((Tx750.ActualRpm >> 8U) & 0xFFU), + (Uint16)((Tx750.SetRpm >> 0U) & 0xFFU), (Uint16)((Tx750.SetRpm >> 8U) & 0xFFU)); + ECanaMboxes.MBOX25.MDH.all = CPackMboxData(Tx750.ActualTorque, Tx750.SetTorque, + (Uint16)((Tx750.SystemVoltage >> 0U) & 0xFFU), (Uint16)((Tx750.SystemVoltage >> 8U) & 0xFFU)); + + // --------------------------------------------------------- + // [751h - MBOX26] + // --------------------------------------------------------- + Tx751.CoolantTemperature = Rx321.CoolantTemperature; + Tx751.Fan1Speed = Rx321.Fan1Speed; + Tx751.Fan2Speed = Rx321.Fan2Speed; + Tx751.CoolantPumpSpeed = Rx321.CoolantPumpSpeed; + Tx751.Barometric = Rx321.BarometricPressure; + + // BYTE 0(CoolantTemperature), BYTE 1(Fan1Speed), BYTE 2(Fan2Speed), BYTE 3(CoolantPumpSpeed), BYTE 4~5(Barometric), BYTE 6~7(Rsvd) + ECanaMboxes.MBOX26.MDL.all = CPackMboxData(Tx751.CoolantTemperature, Tx751.Fan1Speed, Tx751.Fan2Speed, Tx751.CoolantPumpSpeed); + ECanaMboxes.MBOX26.MDH.all = CPackMboxData((Uint16)((Tx751.Barometric >> 0U) & 0xFFU), (Uint16)((Tx751.Barometric >> 8U) & 0xFFU), 0U, 0U); + + // --------------------------------------------------------- + // [752h - MBOX27] + // --------------------------------------------------------- + Tx752.OperationTimeL = Rx322.TotalOperTimeL; + Tx752.OperationTimeH = Rx322.TotalOperTimeH; + + // BYTE 0~1(OperationTimeL), BYTE 2~3(OperationTimeH), BYTE 4~7(Rsvd) + ECanaMboxes.MBOX27.MDL.all = CPackMboxData((Uint16)((Tx752.OperationTimeL >> 0U) & 0xFFU), (Uint16)((Tx752.OperationTimeL >> 8U) & 0xFFU), + (Uint16)((Tx752.OperationTimeH >> 0U) & 0xFFU), (Uint16)((Tx752.OperationTimeH >> 8U) & 0xFFU)); + ECanaMboxes.MBOX27.MDH.all = CPackMboxData(0U, 0U, 0U, 0U); + + // --------------------------------------------------------- + // 송신 메일박스 마스크 설정 및 전송 트리거 + // MBOX 마스크 (0, 1, 5, 10, 15, 16, 17, 18, 19, 20, 21, 25, 26, 27) + // --------------------------------------------------------- + Uint32 ulTxMask = 0x0E3F8423UL; + + ECanaRegs.CANTRS.all = ulTxMask; + ECanaRegs.CANTA.all = ulTxMask; +} + +static void CInitECanA(void) +{ + /* Create a shadow register structure for the CAN control registers. This is + needed, since only 32-bit access is allowed to these registers. 16-bit access + to these registers could potentially corrupt the register contents or return + false data. This is especially true while writing to/reading from a bit + (or group of bits) among bits 16 - 31 */ + + struct ECAN_REGS ECanaShadow = {}; + + EALLOW; // EALLOW enables access to protected bits + + /* Enable internal pull-up for the selected CAN pins */ + // Pull-ups can be enabled or disabled by the user. + // This will enable the pullups for the specified pins. + // Comment out other unwanted lines. + + GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0x00U; // Enable pull-up CANRXA + GpioCtrlRegs.GPAPUD.bit.GPIO19 = 0x00U; // Enable pull-up CANTXA + + /* Set qualification for selected CAN pins to asynch only */ + // Inputs are synchronized to SYSCLKOUT by default. + // This will select asynch (no qualification) for the selected pins. + + GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 0x03U; // Asynch qual for CANRXA + + /* Configure eCAN-A pins using GPIO regs*/ + // This specifies which of the possible GPIO pins will be eCAN functional pins. + + GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 0x03U; // Configure CANRXA operation + GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 0x03U; // Configure CANTXA operation + + /* Configure eCAN RX and TX pins for CAN operation using eCAN regs*/ + + ECanaShadow.CANTIOC.all = ECanaRegs.CANTIOC.all; + ECanaShadow.CANTIOC.bit.TXFUNC = 1U; + ECanaRegs.CANTIOC.all = ECanaShadow.CANTIOC.all; + + ECanaShadow.CANRIOC.all = ECanaRegs.CANRIOC.all; + ECanaShadow.CANRIOC.bit.RXFUNC = 1U; + ECanaRegs.CANRIOC.all = ECanaShadow.CANRIOC.all; + + /* Configure eCAN for HECC mode - (reqd to access mailboxes 16 thru 31) */ + // HECC mode also enables time-stamping feature + + ECanaShadow.CANMC.all = ECanaRegs.CANMC.all; + ECanaShadow.CANMC.bit.SCB = 1; + ECanaRegs.CANMC.all = ECanaShadow.CANMC.all; + + // TAn, RMPn, GIFn bits are all zero upon reset and are cleared again + // as a matter of precaution. + + ECanaRegs.CANTA.all = 0xFFFFFFFFU; /* Clear all TAn bits */ + ECanaRegs.CANRMP.all = 0xFFFFFFFFU; /* Clear all RMPn bits */ + ECanaRegs.CANGIF0.all = 0xFFFFFFFFU; /* Clear all interrupt flag bits */ + ECanaRegs.CANGIF1.all = 0xFFFFFFFFU; + + /* Configure bit timing parameters for eCANB*/ + ECanaShadow.CANMC.all = ECanaRegs.CANMC.all; + ECanaShadow.CANMC.bit.CCR = 1U; // Set CCR = 1 + ECanaRegs.CANMC.all = ECanaShadow.CANMC.all; + + ECanaShadow.CANES.all = ECanaRegs.CANES.all; + + do + { + ECanaShadow.CANES.all = ECanaRegs.CANES.all; + } while(ECanaShadow.CANES.bit.CCE != 1U); // Wait for CCE bit to be set.. + + ECanaShadow.CANBTC.all = 0U; + + // 250 [Kbps] + ECanaShadow.CANBTC.bit.BRPREG = 19U; + ECanaShadow.CANBTC.bit.TSEG1REG = 10U; + ECanaShadow.CANBTC.bit.TSEG2REG = 2U; + + ECanaShadow.CANBTC.bit.SAM = 1U; + ECanaShadow.CANBTC.bit.SJWREG = 2U; + ECanaRegs.CANBTC.all = ECanaShadow.CANBTC.all; + + ECanaShadow.CANMC.all = ECanaRegs.CANMC.all; + ECanaShadow.CANMC.bit.CCR = 0U; + ECanaRegs.CANMC.all = ECanaShadow.CANMC.all; + + ECanaShadow.CANES.all = ECanaRegs.CANES.all; + + do + { + ECanaShadow.CANES.all = ECanaRegs.CANES.all; + } while (ECanaShadow.CANES.bit.CCE != 0U); // Wait for CCE bit to be cleared.. + + /* Disable all Mailboxes */ + ECanaRegs.CANME.all = 0U; // Required before writing the MSGIDs + + EDIS; + CECanASetMbox(); +} + +static void CECanASetMbox(void) +{ + struct ECAN_REGS ECanShadow = {}; + + /* Tx Can MBox */ + ECanaMboxes.MBOX0.MSGID.bit.IDE = 0U; // ID ECANa 식별자 - 11bit ID 스탠다드 + ECanaMboxes.MBOX0.MSGID.bit.STDMSGID = 0x700U; + ECanaMboxes.MBOX0.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX0.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX0.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX0.MDH.all = 0x00000000U; + ECanaMboxes.MBOX0.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX1.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX1.MSGID.bit.STDMSGID = 0x701U; + ECanaMboxes.MBOX1.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX1.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX1.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX1.MDH.all = 0x00000000U; + ECanaMboxes.MBOX1.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX5.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX5.MSGID.bit.STDMSGID = 0x710U; + ECanaMboxes.MBOX5.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX5.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX5.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX5.MDH.all = 0x00000000U; + ECanaMboxes.MBOX5.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX10.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX10.MSGID.bit.STDMSGID = 0x720U; + ECanaMboxes.MBOX10.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX10.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX10.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX10.MDH.all = 0x00000000U; + ECanaMboxes.MBOX10.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX15.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX15.MSGID.bit.STDMSGID = 0x730U; + ECanaMboxes.MBOX15.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX15.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX15.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX15.MDH.all = 0x00000000U; + ECanaMboxes.MBOX15.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX16.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX16.MSGID.bit.STDMSGID = 0x731U; + ECanaMboxes.MBOX16.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX16.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX16.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX16.MDH.all = 0x00000000U; + ECanaMboxes.MBOX16.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX17.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX17.MSGID.bit.STDMSGID = 0x732U; + ECanaMboxes.MBOX17.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX17.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX17.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX17.MDH.all = 0x00000000U; + ECanaMboxes.MBOX17.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX18.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX18.MSGID.bit.STDMSGID = 0x733U; + ECanaMboxes.MBOX18.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX18.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX18.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX18.MDH.all = 0x00000000U; + ECanaMboxes.MBOX18.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX19.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX19.MSGID.bit.STDMSGID = 0x734U; + ECanaMboxes.MBOX19.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX19.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX19.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX19.MDH.all = 0x00000000U; + ECanaMboxes.MBOX19.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX20.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX20.MSGID.bit.STDMSGID = 0x740U; + ECanaMboxes.MBOX20.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX20.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX20.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX20.MDH.all = 0x00000000U; + ECanaMboxes.MBOX20.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX21.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX21.MSGID.bit.STDMSGID = 0x741U; + ECanaMboxes.MBOX21.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX21.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX21.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX21.MDH.all = 0x00000000U; + ECanaMboxes.MBOX21.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX25.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX25.MSGID.bit.STDMSGID = 0x750U; + ECanaMboxes.MBOX25.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX25.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX25.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX25.MDH.all = 0x00000000U; + ECanaMboxes.MBOX25.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX26.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX26.MSGID.bit.STDMSGID = 0x751U; + ECanaMboxes.MBOX26.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX26.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX26.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX26.MDH.all = 0x00000000U; + ECanaMboxes.MBOX26.MDL.all = 0x00000000U; + + ECanaMboxes.MBOX27.MSGID.bit.IDE = 0U; + ECanaMboxes.MBOX27.MSGID.bit.STDMSGID = 0x752U; + ECanaMboxes.MBOX27.MSGID.bit.AME = 0U; + ECanaMboxes.MBOX27.MSGCTRL.bit.DLC = 8U; + ECanaMboxes.MBOX27.MSGCTRL.bit.RTR = 0U; + ECanaMboxes.MBOX27.MDH.all = 0x00000000U; + ECanaMboxes.MBOX27.MDL.all = 0x00000000U; + + // Transe, Receive, 0 is Transe, 1 is Receive + ECanShadow.CANMD.all = ECanaRegs.CANMD.all; + ECanShadow.CANMD.all = 0x0U; // USE MBOX0, MBOX1, MBOX5, MBOX10, MBOX15, MBOX16, MBOX17, MBOX18, MBOX19, MBOX20, MBOX21, MBOX25, MBOX26, MBOX27 + ECanaRegs.CANMD.all = ECanShadow.CANMD.all; + + // MailBox Enable/Disable, 0 is Disable, 1 is Enable + ECanShadow.CANME.all = ECanaRegs.CANME.all; + ECanShadow.CANME.all = 0xE3F8413UL; // USE MBOX0, MBOX1, MBOX5, MBOX10, MBOX15, MBOX16, MBOX17, MBOX18, MBOX19, MBOX20, MBOX21, MBOX25, MBOX26, MBOX27 + ECanaRegs.CANME.all = ECanShadow.CANME.all; + + EALLOW; + ECanShadow.CANMC.all = ECanaRegs.CANMC.all; + ECanShadow.CANMC.bit.STM = 0U; // '1' CAN Self-test Mode ¼³A¤ + ECanShadow.CANMC.bit.ABO = 1U; // '1' CAN Auto Bus On + ECanaRegs.CANMC.all = ECanShadow.CANMC.all; + + // Groble Interrupt + ECanShadow.CANGIM.all = ECanaRegs.CANGIM.all; + ECanShadow.CANGIM.bit.I0EN = 1U; // Line 0 Interrupt Enable + ECanShadow.CANGIM.bit.GIL = 0U; // All global interrupts are mapped to the ECAN0INT interrupt line. + ECanaRegs.CANGIM.all = ECanShadow.CANGIM.all; + EDIS; +} + +interrupt void CECanInterruptB(void) +{ + Uint32 ECanRMPbit; + Uint32 uiMBOXMdl = 0UL; + Uint32 uiMBOXMdh = 0UL; + + ECanRMPbit = ECanbRegs.CANRMP.all; + + // --------------------------------------------------------- + // MBOX15 - 200h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 15U)) != 0U) + { + GeneralOperValue.Conection.Gcu = 1U; + CommCheck.Gcu = 0U; // GCU 타임아웃 카운트 초기화 + + uiMBOXMdl = ECanbMboxes.MBOX15.MDL.all; + uiMBOXMdh = ECanbMboxes.MBOX15.MDH.all; + + Uint16 uiByte0 = (Uint16)((uiMBOXMdl >> 24U) & 0xFFU); + Uint16 uiByte1 = (Uint16)((uiMBOXMdl >> 16U) & 0xFFU); + + Rx200.HeartBit = uiByte0 | (uiByte1 << 8U); + + Rx200.VersionMajor = (Uint16)((uiMBOXMdh >> 16U) & 0xFFU); // Byte 5 + Rx200.VersionMinor = (Uint16)((uiMBOXMdh >> 8U) & 0xFFU); // Byte 6 + Rx200.VersionPatch = (Uint16)((uiMBOXMdh >> 0U) & 0xFFU); // Byte 7 + } + + // --------------------------------------------------------- + // MBOX16 - 201h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 16U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX16.MDL.all; + + Rx201.PlayState = (Uint16)((uiMBOXMdl >> 24U) & 0x7U); + Rx201.State = (Uint16)((uiMBOXMdl >> 16U) & 0xFFU); + } + // --------------------------------------------------------- + // MBOX17 - 210h (비트 필드 매핑 반전) + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 17U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX17.MDL.all; + + Rx210.GcuWarning = (Uint16)(((uiMBOXMdl >> 24U) & 0xFFU) | (((uiMBOXMdl >> 16U) & 0xFFU) << 8U)); + Rx210.GcuFault = (Uint16)(((uiMBOXMdl >> 8U) & 0xFFU) | ((uiMBOXMdl & 0xFFU) << 8U)); + } + + // --------------------------------------------------------- + // MBOX18 - 220h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 18U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX18.MDL.all; + uiMBOXMdh = ECanbMboxes.MBOX18.MDH.all; + + // [Reverse] + // Byte 0(>>24), Byte 1(>>16) + Uint16 uiVoltL = (Uint16)((uiMBOXMdl >> 24U) & 0xFFU); + Uint16 uiVoltH = (Uint16)((uiMBOXMdl >> 16U) & 0xFFU); + Rx220.DcVoltage = uiVoltL | (uiVoltH << 8U); + + // Byte 2(>>8), Byte 3(>>0) + Uint16 uiCurrL = (Uint16)((uiMBOXMdl >> 8U) & 0xFFU); + Uint16 uiCurrH = (Uint16)((uiMBOXMdl >> 0U) & 0xFFU); + Rx220.DcCurrent = uiCurrL | (uiCurrH << 8U); + + // Byte 4(>>24), Byte 5(>>16) + Uint16 uiRpmL = (Uint16)((uiMBOXMdh >> 24U) & 0xFFU); + Uint16 uiRpmH = (Uint16)((uiMBOXMdh >> 16U) & 0xFFU); + Rx220.Rpm = uiRpmL | (uiRpmH << 8U); + + // Byte 6(>>24), Byte 7(>>16) + Uint16 uiPwrL = (Uint16)((uiMBOXMdh >> 8U) & 0xFFU); + Uint16 uiPwrH = (Uint16)((uiMBOXMdh >> 0U) & 0xFFU); + Rx220.Power = uiPwrL | (uiPwrH << 8U); + } + + // --------------------------------------------------------- + // MBOX19 - 221h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 19U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX19.MDL.all; + + // [Reverse] 0(24), 1(16), 2(8), 3(0) + Rx221.PcbTemperature = (Uint16)((uiMBOXMdl >> 24U) & 0xFFU); + Rx221.FetTemperature = (Uint16)((uiMBOXMdl >> 16U) & 0xFFU); + Rx221.GenTemperature1 = (Uint16)((uiMBOXMdl >> 8U) & 0xFFU); + Rx221.GenTemperature2 = (Uint16)((uiMBOXMdl >> 0U) & 0xFFU); + } + + // --------------------------------------------------------- + // MBOX25 - 300h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 25U)) != 0U) + { + GeneralOperValue.Conection.Ecu = 1U; + CommCheck.Ecu = 0U; // ECU 타임아웃 카운트 초기화 + uiMBOXMdl = ECanbMboxes.MBOX25.MDL.all; + + // [Reverse] + Rx300.VersionMajor = (Uint8)((uiMBOXMdl >> 24U) & 0xFFU); + Rx300.VersionMinor = (Uint8)((uiMBOXMdl >> 16U) & 0xFFU); + Rx300.VersionPatch = (Uint8)((uiMBOXMdl >> 8U) & 0xFFU); + } + + // --------------------------------------------------------- + // MBOX26 - 301h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 26U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX26.MDL.all; + + // [Reverse] Byte 0 -> >> 24U + Rx301.State = (Uint16)((uiMBOXMdl >> 24U) & 0xFFU); + } + + // --------------------------------------------------------- + // MBOX27 - 310h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 27U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX27.MDL.all; + + // [Reverse] Byte 0 -> >> 24 + Rx310.EcuWarning = (Uint16)((uiMBOXMdl >> 24U) & 0xFFU); + Rx310.EcuFault = (Uint16)((uiMBOXMdl >> 8U) & 0x3FU); + } + + // --------------------------------------------------------- + // MBOX28 - 320h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 28U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX28.MDL.all; + uiMBOXMdh = ECanbMboxes.MBOX28.MDH.all; + + // [Reverse] Byte 0(>>24), 1(>>16) + Uint16 uiActRpmL = (Uint16)((uiMBOXMdl >> 24U) & 0xFFU); + Uint16 uiActRpmH = (Uint16)((uiMBOXMdl >> 16U) & 0xFFU); + Rx320.ActualRpm = uiActRpmL | (uiActRpmH << 8U); + + // [Reverse] Byte 2(>>8), 3(>>0) + Uint16 uiSetRpmL = (Uint16)((uiMBOXMdl >> 8U) & 0xFFU); + Uint16 uiSetRpmH = (Uint16)((uiMBOXMdl >> 0U) & 0xFFU); + Rx320.SetRpm = uiSetRpmL | (uiSetRpmH << 8U); + + // [Reverse] Byte 4(>>24), 5(>>16) (MDH) + Rx320.ActualTorque = (Uint16)((uiMBOXMdh >> 24U) & 0xFFU); + Rx320.SetTorque = (Uint16)((uiMBOXMdh >> 16U) & 0xFFU); + + // [Reverse] Byte 6(>>8), 7(>>0) + Uint16 uiSysVoltL = (Uint16)((uiMBOXMdh >> 8U) & 0xFFU); + Uint16 uiSysVoltH = (Uint16)((uiMBOXMdh >> 0U) & 0xFFU); + Rx320.SystemVoltage = uiSysVoltL | (uiSysVoltH << 8U); + } + + // --------------------------------------------------------- + // MBOX29 - 321h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 29U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX29.MDL.all; + uiMBOXMdh = ECanbMboxes.MBOX29.MDH.all; + + // [Reverse] + Rx321.CoolantTemperature = (Uint16)((uiMBOXMdl >> 24U) & 0xFFU); + Rx321.Fan1Speed = (Uint16)((uiMBOXMdl >> 16U) & 0xFFU); + Rx321.Fan2Speed = (Uint16)((uiMBOXMdl >> 8U) & 0xFFU); + Rx321.CoolantPumpSpeed = (Uint16)((uiMBOXMdl >> 0U) & 0xFFU); + + // Byte 4(>>24), 5(>>16) + Uint16 uiBarL = (Uint16)((uiMBOXMdh >> 24U) & 0xFFU); + Uint16 uiBarH = (Uint16)((uiMBOXMdh >> 16U) & 0xFFU); + Rx321.BarometricPressure = uiBarL | (uiBarH << 8U); + } + + // --------------------------------------------------------- + // MBOX30 - 322h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 30U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX30.MDL.all; + + // [Reverse] Byte 0(>>24), 1(>>16) -> TimeL + Uint16 uiTimeLL = (Uint16)((uiMBOXMdl >> 24U) & 0xFFU); + Uint16 uiTimeLH = (Uint16)((uiMBOXMdl >> 16U) & 0xFFU); + Rx322.TotalOperTimeL = uiTimeLL | (uiTimeLH << 8U); + + // [Reverse] Byte 2(>>8), 3(>>0) -> TimeH + Uint16 uiTimeHL = (Uint16)((uiMBOXMdl >> 8U) & 0xFFU); + Uint16 uiTimeHH = (Uint16)((uiMBOXMdl >> 0U) & 0xFFU); + Rx322.TotalOperTimeH = uiTimeHL | (uiTimeHH << 8U); + } + +#ifdef AUX_TEST + // --------------------------------------------------------- + // MBOX31 - 400h + // --------------------------------------------------------- + if ((ECanRMPbit & (1UL << 31U)) != 0U) + { + uiMBOXMdl = ECanbMboxes.MBOX31.MDL.all; + + // [Reverse] Byte 0 -> >> 24 + Rx400.AuxControl.EngineHeater = (Uint16)((uiMBOXMdl >> 24U) & 0x1U); + Rx400.AuxControl.GlowPlug = (Uint16)((uiMBOXMdl >> 25U) & 0x1U); + Rx400.AuxControl.Solenoid = (Uint16)((uiMBOXMdl >> 26U) & 0x1U); + Rx400.AuxControl.FuelPump = (Uint16)((uiMBOXMdl >> 27U) & 0x1U); + Rx400.AuxControl.CoolantPump = (Uint16)((uiMBOXMdl >> 28U) & 0x1U); + Rx400.AuxControl.Fan1 = (Uint16)((uiMBOXMdl >> 29U) & 0x1U); + Rx400.AuxControl.Fan2 = (Uint16)((uiMBOXMdl >> 30U) & 0x1U); + Rx400.AuxControl.AuxTestStart = (Uint16)((uiMBOXMdl >> 31U) & 0x1U); + } +#endif + + ECanbRegs.CANRMP.all = ECanRMPbit; + PieCtrlRegs.PIEACK.all = PIEACK_GROUP9; +} + +void CSendECanDataB(void) +{ + struct ECAN_REGS ECanShadow; + static Uint16 uiTxDivid = 0U; // 분산 송신 + float32 fTemp = 0.0F; + Uint16 uiTemp = 0U; + + Uint16 EmergencySig = ((GeneralOperValue.uiEmergency > 0U) || (KeyOperValue.KeyList.Emergency > 0U)) ? 1U : 0U; + + // 10ms + // [101h] + // --- BYTE 0 --- + Tx101.PlayState = GeneralOperValue.uiApuState; + + // --- BYTE 1 --- + uiTemp = 0U; + uiTemp |= CPackBit(GeneralOperValue.uiFaultOccured, 0U); + uiTemp |= CPackBit(GeneralOperValue.uiEmergency, 1U); + uiTemp |= CPackBit(KeyOperValue.KeyList.MainPower, 2U); + uiTemp |= CPackBit((GPIO_FAIL_SAFE_READ() == false) ? 1U : 0U, 3U); + Tx101.DcuState = uiTemp; + + ECanbMboxes.MBOX1.MDL.byte.BYTE0 = Tx101.PlayState; + ECanbMboxes.MBOX1.MDL.byte.BYTE1 = Tx101.DcuState; + ECanbMboxes.MBOX1.MDL.byte.BYTE2 = 0x0U; + ECanbMboxes.MBOX1.MDL.byte.BYTE3 = 0x0U; + ECanbMboxes.MBOX1.MDH.byte.BYTE4 = 0x0U; + ECanbMboxes.MBOX1.MDH.byte.BYTE5 = 0x0U; + ECanbMboxes.MBOX1.MDH.byte.BYTE6 = 0x0U; + ECanbMboxes.MBOX1.MDH.byte.BYTE7 = 0x0U; + + // [102h] + // --- BYTE 0 --- + uiTemp = 0U; + uiTemp |= CPackField(GeneralOperValue.GcuCommand.PlayCmd, 0xFU, 0U); + uiTemp |= CPackBit(GeneralOperValue.uiAlarmReset, 4U); + uiTemp |= CPackBit(EmergencySig, 5U); + Tx102.GcuCommand = uiTemp; + + ECanbMboxes.MBOX2.MDL.byte.BYTE0 = Tx102.GcuCommand; + ECanbMboxes.MBOX2.MDL.byte.BYTE1 = 0x0U; + ECanbMboxes.MBOX2.MDL.byte.BYTE2 = 0x0U; + ECanbMboxes.MBOX2.MDL.byte.BYTE3 = 0x0U; + ECanbMboxes.MBOX2.MDH.byte.BYTE4 = 0x0U; + ECanbMboxes.MBOX2.MDH.byte.BYTE5 = 0x0U; + ECanbMboxes.MBOX2.MDH.byte.BYTE6 = 0x0U; + ECanbMboxes.MBOX2.MDH.byte.BYTE7 = 0x0U; + + // [103h] + // --- BYTE 0~7 --- + uiTemp = 0U; + Tx103.EngineStart = GeneralOperValue.EcuCommand.EngineStart; + Tx103.EngineStop = GeneralOperValue.EcuCommand.EngineStop; + Tx103.FaultReset = GeneralOperValue.uiAlarmReset; + Tx103.RpmSetpoint = GeneralOperValue.EcuCommand.RpmSetPoint; + Tx103.ActiveOverride = KeyOperValue.KeyList.BattleMode; + Tx103.EmergencyStop = EmergencySig; + + ECanbMboxes.MBOX3.MDL.byte.BYTE0 = Tx103.EngineStart; + ECanbMboxes.MBOX3.MDL.byte.BYTE1 = Tx103.EngineStop; + ECanbMboxes.MBOX3.MDL.byte.BYTE2 = Tx103.FaultReset; + ECanbMboxes.MBOX3.MDL.byte.BYTE3 = 0x0U; + ECanbMboxes.MBOX3.MDH.byte.BYTE4 = ((Tx103.RpmSetpoint >> 0U) & 0xFFU); + ECanbMboxes.MBOX3.MDH.byte.BYTE5 = ((Tx103.RpmSetpoint >> 8U) & 0xFFU); + ECanbMboxes.MBOX3.MDH.byte.BYTE6 = Tx103.ActiveOverride; + ECanbMboxes.MBOX3.MDH.byte.BYTE7 = Tx103.EmergencyStop; + + ECanShadow.CANTRS.all = ECanbRegs.CANTRS.all; + ECanShadow.CANTRS.bit.TRS1 = 1U; // 101h + ECanShadow.CANTRS.bit.TRS2 = 1U; // 102h + ECanShadow.CANTRS.bit.TRS3 = 1U; // 103h + ECanbRegs.CANTRS.all = ECanShadow.CANTRS.all; + + ECanShadow.CANTA.all = ECanbRegs.CANTA.all; + ECanShadow.CANTA.bit.TA1 = 1U; // 101h + ECanShadow.CANTA.bit.TA2 = 1U; // 102h + ECanShadow.CANTA.bit.TA3 = 1U; // 103h + ECanbRegs.CANTA.all = ECanShadow.CANTA.all; + + ECanShadow.CANTRS.all = ECanbRegs.CANTRS.all; + ECanShadow.CANTA.all = ECanbRegs.CANTA.all; + + switch (uiTxDivid) + { + case 0U: + { + // [100h] + Tx100.Heartbit = (Tx100.Heartbit + 1U) % 65535U; + Tx100.VersionMajor = (Uint16)FIRMWARE_VERSION_MAJOR; + Tx100.VersionMinor = (Uint16)FIRMWARE_VERSION_MINOR; + Tx100.VersionPatch = (Uint16)FIRMWARE_VERSION_PATCH; + + ECanbMboxes.MBOX0.MDL.byte.BYTE0 = ((Tx100.Heartbit >> 0U) & 0xFFU); + ECanbMboxes.MBOX0.MDL.byte.BYTE1 = ((Tx100.Heartbit >> 8U) & 0xFFU); + ECanbMboxes.MBOX0.MDL.byte.BYTE2 = 0x0U; + ECanbMboxes.MBOX0.MDL.byte.BYTE3 = 0x0U; + ECanbMboxes.MBOX0.MDH.byte.BYTE4 = 0x0U; + ECanbMboxes.MBOX0.MDH.byte.BYTE5 = Tx100.VersionMajor; + ECanbMboxes.MBOX0.MDH.byte.BYTE6 = Tx100.VersionMinor; + ECanbMboxes.MBOX0.MDH.byte.BYTE7 = Tx100.VersionPatch; + + ECanShadow.CANTRS.bit.TRS0 = 1U; + ECanShadow.CANTA.bit.TA0 = 1U; + break; + } + case 1U: + { + // [110h] + Tx110.DcuFaultB0 = ((Uint16)(ulDcuTotalAlarm >> 0U) & 0xFFU); // Apu Fault Byte 0 + Tx110.DcuFaultB1 = ((Uint16)(ulDcuTotalAlarm >> 8U) & 0xFFU); // Apu Fault Byte 1 + Tx110.DcuFaultB2 = ((Uint16)(ulDcuTotalAlarm >> 16U) & 0xFFU); // Apu Fault Byte 2 + Tx110.DcuFaultB3 = ((Uint16)(ulDcuTotalAlarm >> 24U) & 0xFFU); // Apu Fault Byte 3 + + ECanbMboxes.MBOX4.MDL.byte.BYTE0 = Tx110.DcuFaultB0; + ECanbMboxes.MBOX4.MDL.byte.BYTE1 = Tx110.DcuFaultB1; + ECanbMboxes.MBOX4.MDL.byte.BYTE2 = Tx110.DcuFaultB2; + ECanbMboxes.MBOX4.MDL.byte.BYTE3 = Tx110.DcuFaultB3; + ECanbMboxes.MBOX4.MDH.byte.BYTE4 = 0x0U; + ECanbMboxes.MBOX4.MDH.byte.BYTE5 = 0x0U; + ECanbMboxes.MBOX4.MDH.byte.BYTE6 = 0x0U; + ECanbMboxes.MBOX4.MDH.byte.BYTE7 = 0x0U; + + ECanShadow.CANTRS.bit.TRS4 = 1U; + ECanShadow.CANTA.bit.TA4 = 1U; + break; + } + case 2U: + { + // [120h] + Tx120.AuxTotal = (Uint16)GET_ALL_AUX_STATUS(); + + ECanbMboxes.MBOX5.MDL.byte.BYTE0 = Tx120.AuxTotal; + ECanbMboxes.MBOX5.MDL.byte.BYTE1 = 0x0U; + ECanbMboxes.MBOX5.MDL.byte.BYTE2 = 0x0U; + ECanbMboxes.MBOX5.MDL.byte.BYTE3 = 0x0U; + ECanbMboxes.MBOX5.MDH.byte.BYTE4 = 0x0U; + ECanbMboxes.MBOX5.MDH.byte.BYTE5 = 0x0U; + ECanbMboxes.MBOX5.MDH.byte.BYTE6 = 0x0U; + ECanbMboxes.MBOX5.MDH.byte.BYTE7 = 0x0U; + + ECanShadow.CANTRS.bit.TRS5 = 1U; + ECanShadow.CANTA.bit.TA5 = 1U; + break; + } + case 3U: + { + // [121h] + fTemp = Adc_EngineHeater_V.fLpfValue * 10.0F; + Tx121.EngHeatVoltage = (Uint16)fTemp; + + fTemp = Adc_EngineHeater_I.fLpfValue * 10.0F; + Tx121.EngHeatCurrent = (Uint16)fTemp; + + fTemp = Adc_GlowPlug_V.fLpfValue * 10.0F; + Tx121.GlowPlugVoltage = (Uint16)fTemp; + + fTemp = Adc_GlowPlug_I.fLpfValue * 10.0F; + Tx121.GlowPlugCurrent = (Uint16)fTemp; + + ECanbMboxes.MBOX6.MDL.byte.BYTE0 = ((Tx121.EngHeatVoltage >> 0U) & 0xFFU); + ECanbMboxes.MBOX6.MDL.byte.BYTE1 = ((Tx121.EngHeatVoltage >> 8U) & 0xFFU); + ECanbMboxes.MBOX6.MDL.byte.BYTE2 = ((Tx121.EngHeatCurrent >> 0U) & 0xFFU); + ECanbMboxes.MBOX6.MDL.byte.BYTE3 = ((Tx121.EngHeatCurrent >> 8U) & 0xFFU); + ECanbMboxes.MBOX6.MDH.byte.BYTE4 = ((Tx121.GlowPlugVoltage >> 0U) & 0xFFU); + ECanbMboxes.MBOX6.MDH.byte.BYTE5 = ((Tx121.GlowPlugVoltage >> 8U) & 0xFFU); + ECanbMboxes.MBOX6.MDH.byte.BYTE6 = ((Tx121.GlowPlugCurrent >> 0U) & 0xFFU); + ECanbMboxes.MBOX6.MDH.byte.BYTE7 = ((Tx121.GlowPlugCurrent >> 8U) & 0xFFU); + + ECanShadow.CANTRS.bit.TRS6 = 1U; + ECanShadow.CANTA.bit.TA6 = 1U; + break; + } + case 4U: + { + // [122h] + fTemp = Adc_Solenoid_V.fLpfValue * 10.0F; + Tx122.SolenoidVoltage = (Uint16)fTemp; + + fTemp = Adc_Solenoid_I.fLpfValue * 10.0F; + Tx122.SolenoidCurrent = (Uint16)fTemp; + + fTemp = Adc_FuelPump_V.fLpfValue * 10.0F; + Tx122.FuelPumpVoltage = (Uint16)fTemp; + + fTemp = Adc_FuelPump_I.fLpfValue * 10.0F; + Tx122.FuelPumpCurrent = (Uint16)fTemp; + + ECanbMboxes.MBOX7.MDL.byte.BYTE0 = ((Tx122.SolenoidVoltage >> 0U) & 0xFFU); + ECanbMboxes.MBOX7.MDL.byte.BYTE1 = ((Tx122.SolenoidVoltage >> 8U) & 0xFFU); + ECanbMboxes.MBOX7.MDL.byte.BYTE2 = ((Tx122.SolenoidCurrent >> 0U) & 0xFFU); + ECanbMboxes.MBOX7.MDL.byte.BYTE3 = ((Tx122.SolenoidCurrent >> 8U) & 0xFFU); + ECanbMboxes.MBOX7.MDH.byte.BYTE4 = ((Tx122.FuelPumpVoltage >> 0U) & 0xFFU); + ECanbMboxes.MBOX7.MDH.byte.BYTE5 = ((Tx122.FuelPumpVoltage >> 8U) & 0xFFU); + ECanbMboxes.MBOX7.MDH.byte.BYTE6 = ((Tx122.FuelPumpCurrent >> 0U) & 0xFFU); + ECanbMboxes.MBOX7.MDH.byte.BYTE7 = ((Tx122.FuelPumpCurrent >> 8U) & 0xFFU); + + ECanShadow.CANTRS.bit.TRS7 = 1U; + ECanShadow.CANTA.bit.TA7 = 1U; + break; + } + case 5U: + { + // [123h] + fTemp = Adc_CoolantPump_V.fLpfValue * 10.0F; + Tx123.CoolantPumpVoltage = (Uint16)fTemp; + + fTemp = Adc_CoolantPump_I.fLpfValue * 10.0F; + Tx123.CoolantPumpCurrent = (Uint16)fTemp; + + fTemp = Adc_Fan1_V.fLpfValue * 10.0F; + Tx123.Fan1Voltage = (Uint16)fTemp; + + fTemp = Adc_Fan1_I.fLpfValue * 10.0F; + Tx123.Fan1Current = (Uint16)fTemp; + + ECanbMboxes.MBOX8.MDL.byte.BYTE0 = ((Tx123.CoolantPumpVoltage >> 0U) & 0xFFU); + ECanbMboxes.MBOX8.MDL.byte.BYTE1 = ((Tx123.CoolantPumpVoltage >> 8U) & 0xFFU); + ECanbMboxes.MBOX8.MDL.byte.BYTE2 = ((Tx123.CoolantPumpCurrent >> 0U) & 0xFFU); + ECanbMboxes.MBOX8.MDL.byte.BYTE3 = ((Tx123.CoolantPumpCurrent >> 8U) & 0xFFU); + ECanbMboxes.MBOX8.MDH.byte.BYTE4 = ((Tx123.Fan1Voltage >> 0U) & 0xFFU); + ECanbMboxes.MBOX8.MDH.byte.BYTE5 = ((Tx123.Fan1Voltage >> 8U) & 0xFFU); + ECanbMboxes.MBOX8.MDH.byte.BYTE6 = ((Tx123.Fan1Current >> 0U) & 0xFFU); + ECanbMboxes.MBOX8.MDH.byte.BYTE7 = ((Tx123.Fan1Current >> 8U) & 0xFFU); + + ECanShadow.CANTRS.bit.TRS8 = 1U; + ECanShadow.CANTA.bit.TA8 = 1U; + break; + } + default: + { + if (uiTxDivid == 6U) + { + // [124h] + fTemp = Adc_Fan2_V.fLpfValue * 10.0F; + Tx124.Fan2Voltage = (Uint16)fTemp; + + fTemp = Adc_Fan2_I.fLpfValue * 10.0F; + Tx124.Fan2Current = (Uint16)fTemp; + + ECanbMboxes.MBOX9.MDL.byte.BYTE0 = ((Tx124.Fan2Voltage >> 0U) & 0xFFU); + ECanbMboxes.MBOX9.MDL.byte.BYTE1 = ((Tx124.Fan2Voltage >> 8U) & 0xFFU); + ECanbMboxes.MBOX9.MDL.byte.BYTE2 = ((Tx124.Fan2Current >> 0U) & 0xFFU); + ECanbMboxes.MBOX9.MDL.byte.BYTE3 = ((Tx124.Fan2Current >> 8U) & 0xFFU); + ECanbMboxes.MBOX9.MDH.byte.BYTE4 = 0x0U; + ECanbMboxes.MBOX9.MDH.byte.BYTE5 = 0x0U; + ECanbMboxes.MBOX9.MDH.byte.BYTE6 = 0x0U; + ECanbMboxes.MBOX9.MDH.byte.BYTE7 = 0x0U; + + ECanShadow.CANTRS.bit.TRS9 = 1U; + ECanShadow.CANTA.bit.TA9 = 1U; + } + break; + } + } + ECanbRegs.CANTRS.all = ECanShadow.CANTRS.all; + ECanbRegs.CANTA.all = ECanShadow.CANTA.all; + + uiTxDivid = (uiTxDivid + 1U) % 10U; +} + +static void CInitECanB(void) +{ + /* Create a shadow register structure for the CAN control registers. This is + needed, since only 32-bit access is allowed to these registers. 16-bit access + to these registers could potentially corrupt the register contents or return + false data. This is especially true while writing to/reading from a bit + (or group of bits) among bits 16 - 31 */ + + struct ECAN_REGS ECanbShadow = {}; + + EALLOW; // EALLOW enables access to protected bits + + /* Enable internal pull-up for the selected CAN pins */ + // Pull-ups can be enabled or disabled by the user. + // This will enable the pullups for the specified pins. + // Comment out other unwanted lines. + + GpioCtrlRegs.GPAPUD.bit.GPIO20 = 0x00U; // Enable pull-up CANTXB + GpioCtrlRegs.GPAPUD.bit.GPIO21 = 0x00U; // Enable pull-up CANRXB + + /* Set qualification for selected CAN pins to asynch only */ + // Inputs are synchronized to SYSCLKOUT by default. + // This will select asynch (no qualification) for the selected pins. + + GpioCtrlRegs.GPAQSEL2.bit.GPIO21 = 0x03U; // Asynch qual for CANRXB + + /* Configure eCAN-A pins using GPIO regs*/ + // This specifies which of the possible GPIO pins will be eCAN functional pins. + + GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 0x03U; // Configure CANTXB operation + GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 0x03U; // Configure CANRXB operation + + /* Configure eCAN RX and TX pins for CAN operation using eCAN regs*/ + + ECanbShadow.CANTIOC.all = ECanbRegs.CANTIOC.all; + ECanbShadow.CANTIOC.bit.TXFUNC = 1U; + ECanbRegs.CANTIOC.all = ECanbShadow.CANTIOC.all; + + ECanbShadow.CANRIOC.all = ECanbRegs.CANRIOC.all; + ECanbShadow.CANRIOC.bit.RXFUNC = 1U; + ECanbRegs.CANRIOC.all = ECanbShadow.CANRIOC.all; + + /* Configure eCAN for HECC mode - (reqd to access mailboxes 16 thru 31) */ + // HECC mode also enables time-stamping feature + + ECanbShadow.CANMC.all = ECanbRegs.CANMC.all; + ECanbShadow.CANMC.bit.SCB = 1; + ECanbRegs.CANMC.all = ECanbShadow.CANMC.all; + + // TAn, RMPn, GIFn bits are all zero upon reset and are cleared again + // as a matter of precaution. + + ECanbRegs.CANTA.all = 0xFFFFFFFFU; /* Clear all TAn bits */ + ECanbRegs.CANRMP.all = 0xFFFFFFFFU; /* Clear all RMPn bits */ + ECanbRegs.CANGIF0.all = 0xFFFFFFFFU; /* Clear all interrupt flag bits */ + ECanbRegs.CANGIF1.all = 0xFFFFFFFFU; + + /* Configure bit timing parameters for eCANB*/ + ECanbShadow.CANMC.all = ECanbRegs.CANMC.all; + ECanbShadow.CANMC.bit.CCR = 1U; // Set CCR = 1 + ECanbRegs.CANMC.all = ECanbShadow.CANMC.all; + + ECanbShadow.CANES.all = ECanbRegs.CANES.all; + + do + { + ECanbShadow.CANES.all = ECanbRegs.CANES.all; + } while(ECanbShadow.CANES.bit.CCE != 1U); // Wait for CCE bit to be set.. + + ECanbShadow.CANBTC.all = 0U; + + // 250 [kbps] + ECanbShadow.CANBTC.bit.BRPREG = 19U; + ECanbShadow.CANBTC.bit.TSEG1REG = 10U; + ECanbShadow.CANBTC.bit.TSEG2REG = 2U; + + ECanbShadow.CANBTC.bit.SAM = 1U; + ECanbShadow.CANBTC.bit.SJWREG = 2U; + ECanbRegs.CANBTC.all = ECanbShadow.CANBTC.all; + + ECanbShadow.CANMC.all = ECanbRegs.CANMC.all; + ECanbShadow.CANMC.bit.CCR = 0U; + ECanbRegs.CANMC.all = ECanbShadow.CANMC.all; + + ECanbShadow.CANES.all = ECanbRegs.CANES.all; + + do + { + ECanbShadow.CANES.all = ECanbRegs.CANES.all; + } while (ECanbShadow.CANES.bit.CCE != 0U); // Wait for CCE bit to be cleared.. + + /* Disable all Mailboxes */ + ECanbRegs.CANME.all = 0U; // Required before writing the MSGIDs + + EDIS; + CECanBSetMbox(); +} + +static void CECanBSetMbox(void) +{ + struct ECAN_REGS ECanShadow = {}; + + /* Tx Can MBox */ + ECanbMboxes.MBOX0.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX0.MSGID.bit.STDMSGID = 0x100U; + ECanbMboxes.MBOX0.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX0.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX0.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX0.MDH.all = 0x00000000U; + ECanbMboxes.MBOX0.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX1.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX1.MSGID.bit.STDMSGID = 0x101U; + ECanbMboxes.MBOX1.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX1.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX1.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX1.MDH.all = 0x00000000U; + ECanbMboxes.MBOX1.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX2.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX2.MSGID.bit.STDMSGID = 0x102U; + ECanbMboxes.MBOX2.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX2.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX2.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX2.MDH.all = 0x00000000U; + ECanbMboxes.MBOX2.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX3.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX3.MSGID.bit.STDMSGID = 0x103U; + ECanbMboxes.MBOX3.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX3.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX3.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX3.MDH.all = 0x00000000U; + ECanbMboxes.MBOX3.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX4.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX4.MSGID.bit.STDMSGID = 0x110U; + ECanbMboxes.MBOX4.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX4.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX4.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX4.MDH.all = 0x00000000U; + ECanbMboxes.MBOX4.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX5.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX5.MSGID.bit.STDMSGID = 0x120U; + ECanbMboxes.MBOX5.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX5.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX5.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX5.MDH.all = 0x00000000U; + ECanbMboxes.MBOX5.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX6.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX6.MSGID.bit.STDMSGID = 0x121U; + ECanbMboxes.MBOX6.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX6.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX6.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX6.MDH.all = 0x00000000U; + ECanbMboxes.MBOX6.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX7.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX7.MSGID.bit.STDMSGID = 0x122U; + ECanbMboxes.MBOX7.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX7.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX7.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX7.MDH.all = 0x00000000U; + ECanbMboxes.MBOX7.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX8.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX8.MSGID.bit.STDMSGID = 0x123U; + ECanbMboxes.MBOX8.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX8.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX8.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX8.MDH.all = 0x00000000U; + ECanbMboxes.MBOX8.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX9.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX9.MSGID.bit.STDMSGID = 0x124U; + ECanbMboxes.MBOX9.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX9.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX9.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX9.MDH.all = 0x00000000U; + ECanbMboxes.MBOX9.MDL.all = 0x00000000U; + + /* Rx Can MBox(GCU)*/ + ECanbMboxes.MBOX15.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX15.MSGID.bit.STDMSGID = 0x200U; + ECanbMboxes.MBOX15.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX15.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX15.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX15.MDH.all = 0x00000000U; + ECanbMboxes.MBOX15.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX16.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX16.MSGID.bit.STDMSGID = 0x201U; + ECanbMboxes.MBOX16.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX16.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX16.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX16.MDH.all = 0x00000000U; + ECanbMboxes.MBOX16.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX17.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX17.MSGID.bit.STDMSGID = 0x210U; + ECanbMboxes.MBOX17.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX17.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX17.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX17.MDH.all = 0x00000000U; + ECanbMboxes.MBOX17.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX18.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX18.MSGID.bit.STDMSGID = 0x220U; + ECanbMboxes.MBOX18.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX18.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX18.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX18.MDH.all = 0x00000000U; + ECanbMboxes.MBOX18.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX19.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX19.MSGID.bit.STDMSGID = 0x221U; + ECanbMboxes.MBOX19.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX19.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX19.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX19.MDH.all = 0x00000000U; + ECanbMboxes.MBOX19.MDL.all = 0x00000000U; + + /* Rx Can MBox(ECU)*/ + ECanbMboxes.MBOX25.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX25.MSGID.bit.STDMSGID = 0x300U; + ECanbMboxes.MBOX25.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX25.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX25.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX25.MDH.all = 0x00000000U; + ECanbMboxes.MBOX25.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX26.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX26.MSGID.bit.STDMSGID = 0x301U; + ECanbMboxes.MBOX26.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX26.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX26.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX26.MDH.all = 0x00000000U; + ECanbMboxes.MBOX26.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX27.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX27.MSGID.bit.STDMSGID = 0x310U; + ECanbMboxes.MBOX27.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX27.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX27.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX27.MDH.all = 0x00000000U; + ECanbMboxes.MBOX27.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX28.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX28.MSGID.bit.STDMSGID = 0x320U; + ECanbMboxes.MBOX28.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX28.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX28.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX28.MDH.all = 0x00000000U; + ECanbMboxes.MBOX28.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX29.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX29.MSGID.bit.STDMSGID = 0x321U; + ECanbMboxes.MBOX29.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX29.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX29.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX29.MDH.all = 0x00000000U; + ECanbMboxes.MBOX29.MDL.all = 0x00000000U; + + ECanbMboxes.MBOX30.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX30.MSGID.bit.STDMSGID = 0x322U; + ECanbMboxes.MBOX30.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX30.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX30.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX30.MDH.all = 0x00000000U; + ECanbMboxes.MBOX30.MDL.all = 0x00000000U; +#ifdef AUX_TEST // ! Auxiliary Test + ECanbMboxes.MBOX31.MSGID.bit.IDE = 0U; + ECanbMboxes.MBOX31.MSGID.bit.STDMSGID = 0x400U; + ECanbMboxes.MBOX31.MSGID.bit.AME = 0U; + ECanbMboxes.MBOX31.MSGCTRL.bit.DLC = 8U; + ECanbMboxes.MBOX31.MSGCTRL.bit.RTR = 0U; + ECanbMboxes.MBOX31.MDH.all = 0x00000000U; + ECanbMboxes.MBOX31.MDL.all = 0x00000000U; +#endif + + //0 is Transe, 1 is Receive + ECanShadow.CANMD.all = ECanbRegs.CANMD.all; + ECanShadow.CANMD.all = 0x7E0F8000UL; // USE MBOX15~19, 25~30 (31 제외) +#ifdef AUX_TEST // ! Auxiliary Test + ECanShadow.CANMD.bit.MD31 = 1U; +#endif + ECanbRegs.CANMD.all = ECanShadow.CANMD.all; + + // MailBox Enable/Disable, 0 is Disable, 1 is Enable + ECanShadow.CANME.all = ECanbRegs.CANME.all; + ECanShadow.CANME.all = 0x7E0F83FFUL; // USE MBOX0~9, 15~19, 25~30 (31 제외) +#ifdef AUX_TEST // ! Auxiliary Test + ECanShadow.CANME.bit.ME31 = 1U; +#endif + ECanbRegs.CANME.all = ECanShadow.CANME.all; + + EALLOW; + ECanShadow.CANMC.all = ECanbRegs.CANMC.all; + ECanShadow.CANMC.bit.STM = 0U; // '1' CAN Self-test Mode ¼³A¤ + ECanShadow.CANMC.bit.ABO = 1U; // '1' CAN Auto Bus On + ECanbRegs.CANMC.all = ECanShadow.CANMC.all; + + // Interrupt Enable(Receive Interrupt), 0 is Disable, 1 is Enable + ECanShadow.CANMIM.all = ECanbRegs.CANMIM.all; + ECanShadow.CANMIM.bit.MIM15 = 1U; + ECanShadow.CANMIM.bit.MIM16 = 1U; + ECanShadow.CANMIM.bit.MIM17 = 1U; + ECanShadow.CANMIM.bit.MIM18 = 1U; + ECanShadow.CANMIM.bit.MIM19 = 1U; + ECanShadow.CANMIM.bit.MIM25 = 1U; + ECanShadow.CANMIM.bit.MIM26 = 1U; + ECanShadow.CANMIM.bit.MIM27 = 1U; + ECanShadow.CANMIM.bit.MIM28 = 1U; + ECanShadow.CANMIM.bit.MIM29 = 1U; + ECanShadow.CANMIM.bit.MIM30 = 1U; +#ifdef AUX_TEST // ! Auxiliary Test + ECanShadow.CANMIM.bit.MIM31 = 1U; +#endif + ECanbRegs.CANMIM.all = ECanShadow.CANMIM.all; + + // Groble Interrupt + ECanShadow.CANGIM.all = ECanbRegs.CANGIM.all; + ECanShadow.CANGIM.bit.I0EN = 1U; // Line 0 Interrupt Enable + ECanShadow.CANGIM.bit.GIL = 0U; // All global interrupts are mapped to the ECAN0INT interrupt line. + ECanbRegs.CANGIM.all = ECanShadow.CANGIM.all; + EDIS; +} + +void CInitEcan(void) +{ + CInitECanA(); + CInitECanB(); + + CInitECanStructure(); +} + +static void CInitECanStructure(void) +{ + // Tx + (void)memset(&Tx100, 0, sizeof(CTx100)); + (void)memset(&Tx101, 0, sizeof(CTx101)); + (void)memset(&Tx102, 0, sizeof(CTx102)); + (void)memset(&Tx103, 0, sizeof(CTx103)); + (void)memset(&Tx110, 0, sizeof(CTx110)); + (void)memset(&Tx120, 0, sizeof(CTx120)); + (void)memset(&Tx121, 0, sizeof(CTx121)); + (void)memset(&Tx122, 0, sizeof(CTx122)); + (void)memset(&Tx123, 0, sizeof(CTx123)); + (void)memset(&Tx124, 0, sizeof(CTx124)); + + (void)memset(&Tx700, 0, sizeof(CTx700)); + (void)memset(&Tx701, 0, sizeof(CTx701)); + (void)memset(&Tx710, 0, sizeof(CTx710)); + (void)memset(&Tx720, 0, sizeof(CTx720)); + (void)memset(&Tx730, 0, sizeof(CTx730)); + (void)memset(&Tx731, 0, sizeof(CTx731)); + (void)memset(&Tx732, 0, sizeof(CTx732)); + (void)memset(&Tx733, 0, sizeof(CTx733)); + (void)memset(&Tx734, 0, sizeof(CTx734)); + (void)memset(&Tx740, 0, sizeof(CTx740)); + (void)memset(&Tx741, 0, sizeof(CTx741)); + (void)memset(&Tx750, 0, sizeof(CTx750)); + (void)memset(&Tx751, 0, sizeof(CTx751)); + (void)memset(&Tx752, 0, sizeof(CTx752)); + + // Rx - GCU + (void)memset(&Rx200, 0, sizeof(CRx200)); + (void)memset(&Rx201, 0, sizeof(CRx201)); + (void)memset(&Rx210, 0, sizeof(CRx210)); + (void)memset(&Rx220, 0, sizeof(CRx220)); + (void)memset(&Rx221, 0, sizeof(CRx221)); + + // Rx - ECU + (void)memset(&Rx300, 0, sizeof(CRx300)); + (void)memset(&Rx301, 0, sizeof(CRx301)); + (void)memset(&Rx310, 0, sizeof(CRx310)); + (void)memset(&Rx320, 0, sizeof(CRx320)); + (void)memset(&Rx321, 0, sizeof(CRx321)); + (void)memset(&Rx322, 0, sizeof(CRx322)); + +#ifdef AUX_TEST // ! Auxiliary Test + // Rx - Auxiliary Test + (void)memset(&Rx400, 0, sizeof(CRx400)); +#endif +} + +static inline Uint16 CPackBit(Uint16 data, Uint16 pos) +{ + Uint16 result = (data != 0U) ? 1U : 0U; + + return result << pos; +} + +static inline Uint16 CPackField(Uint16 data, Uint16 mask, Uint16 pos) +{ + return ((data & mask) << pos); +} diff --git a/Source/Comm.h b/Source/Comm.h new file mode 100644 index 0000000..5fcdbd5 --- /dev/null +++ b/Source/Comm.h @@ -0,0 +1,696 @@ +#ifndef SOURCE_COMM_H_ +#define SOURCE_COMM_H_ + +typedef struct ClassCommCheck +{ + Uint16 CarComputer; + Uint16 Gcu; + Uint16 Ecu; +} CCommCheck; + +typedef struct ClassTx100 +{ + /* BYTE 0~1 */ + Uint16 Heartbit; + + /* BYTE 2~4 Reserved */ + + /* BYTE 5 */ + Uint16 VersionMajor; + + /* BYTE 6 */ + Uint16 VersionMinor; + + /* BYTE 7 */ + Uint16 VersionPatch; +} CTx100; + +typedef struct ClassTx101 +{ + /* BYTE 0 */ + Uint16 PlayState; // 0~3 bit + + /* BYTE 1 */ + Uint16 DcuState; // bit 0:AlarmOccured, 1:Emergency, 2:PowerSwitch, 3:EcuFailSafe + + /* BYTE 2~7 Reserved */ + +} CTx101; + +typedef struct ClassTx102 +{ + /* BYTE 0 */ + Uint16 GcuCommand; // bit 0~3:PlayCommand, 4:FaultReset, 5:Emergency + + /* BYTE 1~7 Reserved */ + +} CTx102; + + +typedef struct ClassTx103 +{ + /* BYTE 0 */ + Uint16 EngineStart; + + /* BYTE 1 */ + Uint16 EngineStop; + + /* BYTE 2 */ + Uint16 FaultReset; + + /* BYTE 3 Reserved */ + + /* BYTE 4~5 */ + Uint16 RpmSetpoint; + + /* BYTE 6 */ + Uint16 ActiveOverride; + + /* BYTE 7 */ + Uint16 EmergencyStop; + +} CTx103; + +typedef struct ClassTx110 +{ + /* BYTE 0~3 */ + Uint16 DcuFaultB0; + Uint16 DcuFaultB1; + Uint16 DcuFaultB2; + Uint16 DcuFaultB3; + + /* BYTE 4~7 - Reserved */ + +} CTx110; + +typedef struct ClassTx120 +{ + /* BYTE 0 */ + Uint16 AuxTotal; // bit 0:EngineHeater, 1:GlowPlug, 2:Solenoid, 3:FuelPump, 4:CoolantPump, 5:Fan1, 6:Fan2 + + /* BYTE 1~7 - Reserved */ + +} CTx120; + +typedef struct ClassTx121 +{ + /* BYTE 0~1 */ + Uint16 EngHeatVoltage; + + /* BYTE 2~3 */ + Uint16 EngHeatCurrent; + + /* BYTE 4~5 */ + Uint16 GlowPlugVoltage; + + /* BYTE 6~7 */ + Uint16 GlowPlugCurrent; +} CTx121; + +typedef struct ClassTx122 +{ + /* BYTE 0~1 */ + Uint16 SolenoidVoltage; + + /* BYTE 2~3 */ + Uint16 SolenoidCurrent; + + /* BYTE 4~5 */ + Uint16 FuelPumpVoltage; + + /* BYTE 6~7 */ + Uint16 FuelPumpCurrent; +} CTx122; + +typedef struct ClassTx123 +{ + /* BYTE 0~1 */ + Uint16 CoolantPumpVoltage; + + /* BYTE 2~3 */ + Uint16 CoolantPumpCurrent; + + /* BYTE 4~5 */ + Uint16 Fan1Voltage; + + /* BYTE 6~7 */ + Uint16 Fan1Current; +} CTx123; + +typedef struct ClassTx124 +{ + /* BYTE 0~1 */ + Uint16 Fan2Voltage; + + /* BYTE 2~3 */ + Uint16 Fan2Current; + + /* BYTE 4~7 - Reserved */ + +} CTx124; + +typedef struct ClassRx200 +{ + /* BYTE 0~1 */ + Uint16 HeartBit; + + /* BYTE 2~4 - Reserved */ + + /* BYTE 5 */ + Uint16 VersionMajor; + + /* BYTE 6 */ + Uint16 VersionMinor; + + /* BYTE 7 */ + Uint16 VersionPatch; +} CRx200; + +typedef struct ClassRx201 +{ + /* BYTE 0 */ + Uint16 PlayState; // 0:3 bit PlayState + + /* BYTE 1 */ + Uint16 State; // bit 0:AlarmOccured, 1:Shutdown + + /* BYTE 2~7 - Reserved */ + +} CRx201; + +typedef struct ClassRx210 +{ + /* BYTE 0~1 */ + /* + * bit description + * 0:PcbOverHeat + * 1:FetOverHeat + * 2:GenOverHeat1 + * 3:GenOverHeat2 + */ + Uint16 GcuWarning; + + /* BYTE 2~3 */ + /* + * bit description + * 0:HwTrip + * 1:HwIgbt + * 2:HwDc + * 3:GenOverCurrentU + * 4:GenOverCurrentV + * 5:GenOverCurrentW + * 6:DcOverVoltage + * 7:DcOverCurrent + * + * 8:CrankningOverCurrent + * 9:PcbOverHeat + * 10:FetOverHeat + * 11:GenTempOverHeat1 + * 12:GenTempOverHeat2 + * 13:GenOverSpeed + * 14:ResolverIC + * 15:ResolverParity + */ + Uint16 GcuFault; + + /* BYTE 4~7 - Reserved*/ + +} CRx210; + +typedef struct ClassRx220 +{ + /* BYTE 0~1 */ + Uint16 DcVoltage; + + /* BYTE 2~3 */ + Uint16 DcCurrent; + + /* BYTE 4~5 */ + Uint16 Rpm; + + /* BYTE 6~7 */ + Uint16 Power; +} CRx220; + +typedef struct ClassRx221 +{ + /* BYTE 0 */ + Uint16 PcbTemperature; + + /* BYTE 1 */ + Uint16 FetTemperature; + + /* BYTE 2 */ + Uint16 GenTemperature1; + + /* BYTE 3 */ + Uint16 GenTemperature2; + + /* BYTE 4~7 - Reserved */ + +} CRx221; + +typedef struct ClassRx300 +{ + /* BYTE 0 */ + Uint16 VersionMajor; + + /* BYTE 1 */ + Uint16 VersionMinor; + + /* BYTE 2 */ + Uint16 VersionPatch; + + /* BYTE 3~7 - Reserved */ + +} CRx300; + +typedef struct ClassRx301 +{ + + /* BYTE 0 */ + /* + * bit description + * 0:AlarmOccured + * 1~3:PlayState + * 4:OverrideActive + * 5:GlowPlugActive + * 6:HeaterActive + * 7:OilPressureMissing + */ + Uint16 State; + + /* BYTE 1~7 - Reserved */ + +} CRx301; + +typedef struct ClassRx310 +{ + /* BYTE 0 */ + /* + * bit description + * 0:EngineOverHeat + * 1:Reserved + * 2:LoOilPressure + * 3:IntakeOverHeat + * 4:IntakeLoPressure + * 5:EngineLoTemperature + * 6:EngineSensor + * 7:DefaltValueActive + */ + Uint16 EcuWarning; + + /* BYTE 1 - Reserved */ + + /* BYTE 2 */ + /* + * bit description + * 0:OilPressureMissing + * 1:IntakeOverHeat + * 2:EngineOverHeat + * 3:Actuator + * 4:RpmSignal + * 5:EngineStartFail + * 6:Reserved + * 7:Reserved + */ + Uint16 EcuFault; + + /* BYTE 3~7 - Reserved */ + +} CRx310; + +typedef struct ClassRx320 +{ + /* BYTE 0~1 */ + Uint16 ActualRpm; + + /* BYTE 2~3 */ + Uint16 SetRpm; + + /* BYTE 4 */ + Uint16 ActualTorque; + + /* BYTE 5 */ + Uint16 SetTorque; + + /* BYTE 6~7 */ + Uint16 SystemVoltage; +} CRx320; + +typedef struct ClassRx321 +{ + /* BYTE 0 */ + Uint16 CoolantTemperature; + + /* BYTE 1 */ + Uint16 Fan1Speed; + + /* BYTE 2 */ + Uint16 Fan2Speed; + + /* BYTE 3 */ + Uint16 CoolantPumpSpeed; + + /* BYTE 4~5 */ + Uint16 BarometricPressure; + + /* BYTE 6~7 - Reserved */ + +} CRx321; + +typedef struct ClassRx322 +{ + /* BYTE 0~1 */ + Uint16 TotalOperTimeL : 16; + + /* BYTE 2~3 */ + Uint16 TotalOperTimeH : 16; + + /* BYTE 4~7 - Reserved*/ + +} CRx322; + +typedef struct ClassTx700 +{ + /* BYTE 0~1 */ + Uint16 HeartBit; + + /* BYTE 2 */ + Uint16 DCUversionMajor; + + /* BYTE 3 */ + Uint16 DCUversionMinor; + + /* BYTE 4 */ + Uint16 GCUversionMajor; + + /* BYTE 5 */ + Uint16 GCUversionMinor; + + /* BYTE 6 */ + Uint16 ECUversionMajor; + + /* BYTE 7 */ + Uint16 ECUversionMinor; +} CTx700; + +typedef struct ClassTx701 +{ + /* BYTE 0 */ + Uint16 DcuPlayState; // bit 0~3:PlayState + + /* BYTE 1 */ + /* + * bit description + * 0:DcuAlarmOccured + * 1:DcuEmergencyStop + * 2:PowerSwitchPush + * 3:EcuFailSafe + */ + Uint16 DcuState; + + /* BYTE 2 */ + Uint16 GcuPlayState; // bit 0~2:GcuPlayState + + /* BYTE 3 */ + /* + * bit description + * 0:GcuAlarmOccured + * 1:GcuShutdown + */ + Uint16 GcuState; + + /* BYTE 4 */ + /* + * bit description + * 0:EcuAlarmOccured + * 1~3:EcuPlayState + * 4:ActiveOverride + * 5:ActiveGlowPlug + * 6:ActiveEngHeater + * 7:OilPressureMissing + */ + Uint16 EcuState; + + /* BYTE 5~7 - Reserved */ + +} CTx701; + +typedef struct ClassTx710 +{ + /* BYTE 0 - GCU Warning */ + /* + * bit description + * 0:PcbOverHeat + * 1:FetOverHeat + * 2:Winding1OverHeat + * 3:Winding2OverHeat + */ + Uint16 GcuWarning; + + /* BYTE 1 - ECU Warning */ + /* + * bit description + * 0:EngineOverHeat + * 1:Reserved + * 2:LoOilPressure + * 3:IntakeOverHeat + * 4:IntakeLoPressure + * 5:EngineLoTemperature + * 6:EngineSensorFault + * 7:DefaultValueActive + */ + Uint16 EcuWarning; + + /* BYTE 2~7 - Reserved */ + +} CTx710; + +typedef struct ClassTx720 +{ + /* BYTE 0~3 - DCU Fault */ + Uint16 DcuFault0; + Uint16 DcuFault1; + Uint16 DcuFault2; + Uint16 DcuFault3; + + /* BYTE 4~5 - GCU Fault */ + Uint16 GcuFault0; + Uint16 GcuFault1; + + /* BYTE 6 - Reserved */ + + /* BYTE 7 */ + Uint16 EcuFault; +} CTx720; + +typedef struct ClassTx730 +{ + /* BYTE 0 */ + /* + * bit description + * 0:EngineHeater + * 1:GlowPlug + * 2:Solenoid + * 3:FuelPump + * 4:CoolantPump + * 5:Fan1 + * 6:Fan2 + * 7:Reserved + */ + Uint16 AuxState; + + /* BYTE 1~7 - Reserved */ + +} CTx730; + +typedef struct ClassTx731 +{ + /* BYTE 0~1 */ + Uint16 EngineHeaterVoltage; + + /* BYTE 2~3 */ + Uint16 EngineHeaterCurrent; + + /* BYTE 4~5 */ + Uint16 GlowPlugVoltage; + + /* BYTE 6~7 */ + Uint16 GlowPlugCurrent; +} CTx731; + +typedef struct ClassTx732 +{ + /* BYTE 0~1 */ + Uint16 SolenoidVoltage; + + /* BYTE 2~3 */ + Uint16 SolenoidCurrent; + + /* BYTE 4~5 */ + Uint16 FuelPumpVoltage; + + /* BYTE 6~7 */ + Uint16 FuelPumpCurrent; +} CTx732; + +typedef struct ClassTx733 +{ + /* BYTE 0~1 */ + Uint16 CoolantPumpVoltage; + + /* BYTE 2~3 */ + Uint16 CoolantPumpCurrent; + + /* BYTE 4~5 */ + Uint16 Fan1Voltage; + + /* BYTE 6~7 */ + Uint16 Fan1Current; +} CTx733; + +typedef struct ClassTx734 +{ + /* BYTE 0~1 */ + Uint16 Fan2Voltage; + + /* BYTE 2~3 */ + Uint16 Fan2Current; + + /* BYTE 4~7 - Reserved */ + +} CTx734; + +typedef struct ClassTx740 +{ + /* BYTE 0~1 */ + Uint16 Voltage; + + /* BYTE 2~3 */ + Uint16 Current; + + /* BYTE 4~5 */ + Uint16 Rpm; + + /* BYTE 6~7 */ + Uint16 Power; +} CTx740; + +typedef struct ClassTx741 +{ + /* BYTE 0 */ + Uint16 PcbTemperature; + + /* BYTE 1 */ + Uint16 FetTemperature; + + /* BYTE 2 */ + Uint16 Winding1Temperature; + + /* BYTE 3 */ + Uint16 Winding2Temperature; + + /* BYTE 4~7 - Reserved */ + +} CTx741; + +typedef struct ClassTx750 +{ + /* BYTE 0~1 */ + Uint16 ActualRpm; + + /* BYTE 2~3 */ + Uint16 SetRpm; + + /* BYTE 4 */ + Uint16 ActualTorque; + + /* BYTE 5 */ + Uint16 SetTorque; + + /* BYTE 6~7 */ + Uint16 SystemVoltage; +} CTx750; + +typedef struct ClassTx751 +{ + /* BYTE 0 */ + Uint16 CoolantTemperature; + + /* BYTE 1 */ + Uint16 Fan1Speed; + + /* BYTE 2 */ + Uint16 Fan2Speed; + + /* BYTE 3 */ + Uint16 CoolantPumpSpeed; + + /* BYTE 4~5 */ + Uint16 Barometric; + + /* BYTE 6~7 - Reserved */ + +} CTx751; + +typedef struct ClassTx752 +{ + /* BYTE 0~1 */ + Uint16 OperationTimeL; + + /* BYTE 2~3 */ + Uint16 OperationTimeH; + + /* BYTE 4~7 - Reserved */ + +} CTx752; + +interrupt void CECanInterruptA(void); +interrupt void CECanInterruptB(void); +void CSendECanDataA(void); +void CSendECanDataB(void); +void CInitEcan(void); + +extern CCommCheck CommCheck; +extern CRx200 Rx200; +extern CRx210 Rx210; +extern CRx220 Rx220; +extern CRx221 Rx221; +extern CRx300 Rx300; +extern CRx301 Rx301; +extern CRx310 Rx310; +extern CRx320 Rx320; +extern CRx321 Rx321; +extern CRx322 Rx322; + +typedef struct ClassRx400 +{ + struct + { + Uint16 BYTE0 : 8; + Uint16 BYTE1 : 8; + Uint16 BYTE2 : 8; + Uint16 BYTE3 : 8; + Uint16 BYTE4 : 8; + Uint16 BYTE5 : 8; + Uint16 BYTE6 : 8; + Uint16 BYTE7 : 8; + } Bytes; + struct + { + Uint16 EngineHeater : 1; + Uint16 GlowPlug : 1; + Uint16 Solenoid : 1; + Uint16 FuelPump : 1; + Uint16 CoolantPump : 1; + Uint16 Fan1 : 1; + Uint16 Fan2 : 1; + Uint16 AuxTestStart : 1; + Uint16 rsvd_padding : 8; + } AuxControl; +} CRx400; + +extern CRx400 Rx400; + +#endif /* SOURCE_COMM_H_ */ diff --git a/Source/Display.c b/Source/Display.c new file mode 100644 index 0000000..72f3250 --- /dev/null +++ b/Source/Display.c @@ -0,0 +1,1979 @@ +/* ========================================================================= */ +/* 1. Includes */ +/* ========================================================================= */ +#include "main.h" + +/* ========================================================================= */ +/* 2. Local Macros & Constants (내부 전용 매크로 및 상수) */ +/* ========================================================================= */ +#pragma DATA_SECTION(CommandBus,"ZONE6_COM"); +#pragma DATA_SECTION(DataBus,"ZONE6_DAT"); + +#define ASCII_NULL ((int8)0) // NULL '\0' +#define ASCII_BLANK ((int8)32) // 공백 ' ' +#define ASCII_L_PAREN ((int8)40) // 여는 소괄호 '(' +#define ASCII_R_PAREN ((int8)41) // 닫는 소괄호 ')' +#define ASCII_MINUS ((int8)45) // 마이너스 '-' +#define ASCII_DOT ((int8)46) // 소수점 '.' + +#define ASCII_0 ((int8)48) // '0' + +#define ASCII_E ((int8)69) // 'E' +#define ASCII_R ((int8)82) // 'R' +#define ASCII_T ((int8)84) // 'T' +#define ASCII_Y ((int8)89) // 'Y' + +/* ========================================================================= */ +/* 3. Local Typedefs & Structures (내부 전용 사용자 정의 자료형) */ +/* ========================================================================= */ +static volatile Uint16 CommandBus, DataBus; + +/* ========================================================================= */ +/* 4. Internal Linkage Function Declarations (내부 동작용 Static 함수 선언) */ +/* ========================================================================= */ +static void CPageApu1(void); +static void CPageApu2(void); +static void CPageMenu1(void); +static void CPageMenu2(void); +static void CPageTemp(void); +static void CPageSensor1(void); +static void CPageSensor2(void); +static void CPageSensor3(void); +static void CPageSensor4(void); +static void CPageWarning1(void); +static void CPageWarning2(void); +static void CPageFault1(void); +static void CPageFault2(void); +static void CPageFault3(void); +static void CPageFault4(void); +static void CPageFault5(void); +static void CPageFault6(void); +static void CPageFault7(void); +static void CPageAlarmReset(void); +static void CPagePassword(void); +static void CPageMaintenance(void); +static void CPageVersion(void); +static void CPageKeyTest(void); +static void CPageShutdown(void); +static Uint16 CStrLen(const int8 *s); +static void CInitOledModule(void); +static void CDrawChar(Uint16 x, Uint16 y, Uint16 ch, Uint16 type); +static void CInitProgress(void); +static void CDrawStr(Uint16 x, Uint16 y, const int8* str); +static void CTextAlign(int8 *buffer, const int8 *str); +static inline void CPutPixel(Uint16 x, Uint16 y, Uint16 Color); +static void CDrawBox(Uint16 x, Uint16 y, Uint16 w, Uint16 h); +static void CDrawLine(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2); +static void CSetDrawRegion(Uint16 x, Uint16 y); +static void CSetPageAddress(Uint16 Address); +static void CSetColumnAddress(Uint16 x); +static void COledWrite(Uint16 Data, Uint16 Command); +static void CInitOledStructure(void); +static void CStrncpy(int8 *pTarget, const int8 *pSource, Uint16 Size); +static void CStrncat(int8 *pTarget, const int8 *pSource, Uint16 Size); +static void CDecToString(int16 Data, int8 *Array, Uint16 ArrayLen); +static void CFloatToString(float32 Data, int8 *Array, Uint16 ArrayLen); +static void CLineFocus(Uint16 isFocus); +static void CHourToString(int32 num, int8 *str); +static void CMakeVersionString(int8 Buffer[], int16 v1, int16 v2, int16 v3); +static void CAddLineIndent(int8 *buffer, const int8 *str); +static const int8* CGetApuStateString(Uint16 idx); +static void CDrawTitleBox(Uint16 TitleLen); +static void CDrawCenteredLine(Uint16 y, const int8* text); +static void CCopyStr(int8 *pTarget, const int8 *pSource); +static void CAppendStr(int8 *pTarget, const int8 *pSource); +static void CDrawLineText(Uint16 x, Uint16 y, const int8* str); +static void CDrawFaultStatusLine(Uint16 row, const int8* label1, Uint16 status1, const int8* label2, Uint16 status2); +static void CDrawSimpleLine(Uint16 row, const int8* label); +static void CDrawStatusTitle(const int8* title, const int8* pageNumStr); +static void CDrawSensorTitle(const int8* title, const int8* pageNumStr); +static void CDrawFaultTitle(const int8* title, const int8* pageNumStr); + +/* ========================================================================= */ +/* 5. Global Variables & Structure Initialization (전역 변수 및 구조체 초기화) */ +/* ========================================================================= */ +COledOperValue OledOperValue; + +/* ========================================================================= */ +/* Function Definitions */ +/* ========================================================================= */ +static void CDrawPageTitle(const int8* title, const int8* pageNumStr) +{ + Uint16 uiTitleLen = 0U; + + CCopyStr(OledOperValue.cStrBuff[IDX_OLED_ROW_0], title); + CDrawStr(10U, (Uint16)IDX_OLED_LINE_TITLE, OledOperValue.cStrBuff[IDX_OLED_ROW_0]); + + if (title != NULL) + { + while ((title[uiTitleLen] != ASCII_NULL) && (uiTitleLen < (Uint16)TXT_MAX_LEN)) + { + uiTitleLen++; + } + } + CDrawTitleBox(uiTitleLen * 6U); + + if (pageNumStr != NULL) + { + CCopyStr(OledOperValue.cStrBuff[IDX_OLED_ROW_0], pageNumStr); + CDrawStr(100U, (Uint16)IDX_OLED_LINE_TITLE, OledOperValue.cStrBuff[IDX_OLED_ROW_0]); + } +} + +static void CDrawPageLine(Uint16 row, const int8* label, const int8* valueStr, const int8* unitStr) +{ + Uint16 drawY; + Uint16 len = 0U; + + drawY = (row == (Uint16)IDX_OLED_ROW_1) ? (Uint16)IDX_OLED_LINE_1 : ((row == (Uint16)IDX_OLED_ROW_2) ? (Uint16)IDX_OLED_LINE_2 : ((row == (Uint16)IDX_OLED_ROW_3) ? (Uint16)IDX_OLED_LINE_3 : (Uint16)IDX_OLED_LINE_4)); + + CCopyStr(OledOperValue.cStrBuff[row], label); + + if (valueStr != NULL) + { + CAppendStr(OledOperValue.cStrBuff[row], valueStr); + } + + if (unitStr != NULL) + { + CAppendStr(OledOperValue.cStrBuff[row], unitStr); + } + + while ((OledOperValue.cStrBuff[row][len] != ASCII_NULL) && (len < (Uint16)(TXT_MAX_LEN - 1U))) + { + len++; + } + + while (len < (Uint16)(TXT_MAX_LEN - 1U)) + { + OledOperValue.cStrBuff[row][len] = ASCII_BLANK; // ' ' + len++; + } + + OledOperValue.cStrBuff[row][len] = ASCII_NULL; + + CDrawLineText(0U, drawY, (const int8*)OledOperValue.cStrBuff[row]); +} + +static void CDrawPageLineFloat(Uint16 row, const int8* label, float32 value, const int8* unitStr) +{ + int8 tempBuff[16]; + + CFloatToString(value, tempBuff, sizeof(tempBuff)); + CDrawPageLine(row, label, (const int8*)tempBuff, unitStr); +} + +static void CDrawPageLineTwoFloat(Uint16 row, const int8* label, float32 value1, float32 value2) +{ + int8 finalBuf[32]; + Uint16 j = 0U; + Uint32 intPart; + Uint32 decPart; + Uint16 uiTmp; /* 복합 수식 연산 결과를 담을 임시 변수 */ + float32 fTmp; /* 부동소수점 연산 결과를 담을 임시 변수 */ + + /* --- Value 1 처리 --- */ + intPart = (Uint32)value1; + fTmp = ((value1 - (float32)intPart) * 10.0F) + 0.5F; + decPart = (Uint32)fTmp; + + if (decPart >= 10U) + { + intPart++; + decPart = 0U; + } + + /* 십의 자리 */ + uiTmp = (Uint16)((intPart / 10U) + 48U); + finalBuf[j] = (intPart >= 10U) ? (int8)uiTmp : ASCII_BLANK; + j++; + + /* 일의 자리 */ + uiTmp = (Uint16)((intPart % 10U) + 48U); + finalBuf[j] = (int8)uiTmp; + j++; + + finalBuf[j] = ASCII_DOT; /* '.' */ + j++; + + /* 소수점 첫째 자리 */ + uiTmp = (Uint16)(decPart + 48U); + finalBuf[j] = (int8)uiTmp; + j++; + + /* 구분자들 */ + finalBuf[j] = (int8)86; /* 'V' */ + j++; + finalBuf[j] = (int8)44; /* ',' */ + j++; + finalBuf[j] = ASCII_BLANK; /* ' ' */ + j++; + + + /* --- Value 2 처리 --- */ + intPart = (Uint32)value2; + fTmp = ((value2 - (float32)intPart) * 10.0F) + 0.5F; + decPart = (Uint32)fTmp; + + if (decPart >= 10U) + { + intPart++; + decPart = 0U; + } + + if (intPart > 99U) + { + intPart = 99U; + } + + /* 십의 자리 */ + uiTmp = (Uint16)((intPart / 10U) + 48U); + finalBuf[j] = (intPart >= 10U) ? (int8)uiTmp : ASCII_BLANK; + j++; + + /* 일의 자리 */ + uiTmp = (Uint16)((intPart % 10U) + 48U); + finalBuf[j] = (int8)uiTmp; + j++; + + finalBuf[j] = ASCII_DOT; /* '.' */ + j++; + + /* 소수점 첫째 자리 */ + uiTmp = (Uint16)(decPart + 48U); + finalBuf[j] = (int8)uiTmp; + j++; + + finalBuf[j] = ASCII_NULL; /* '\0' */ + + CDrawPageLine(row, label, finalBuf, (const int8*)"A"); +} + +static void CDrawPageLineInt(Uint16 row, const int8* label, int32 value, const int8* unitStr) +{ + int8 tempBuff[16]; + + CDecToString((int16)value, tempBuff, sizeof(tempBuff)); + CDrawPageLine(row, label, (const int8*)tempBuff, unitStr); +} + +static void CDrawTwoStatusLine(Uint16 row, const int8* label1, Uint16 status1, const int8* label2, Uint16 status2) +{ + const int8* statusStr1 = (status1 == 1U) ? (const int8*)"1" : (const int8*)"0"; + const int8* statusStr2 = (status2 == 1U) ? (const int8*)"1" : (const int8*)"0"; + Uint16 drawY = 0U; + + if (row == (Uint16)IDX_OLED_ROW_1) + { + drawY = (Uint16)IDX_OLED_LINE_1; + } + else if (row == (Uint16)IDX_OLED_ROW_2) + { + drawY = (Uint16)IDX_OLED_LINE_2; + } + else if (row == (Uint16)IDX_OLED_ROW_3) + { + drawY = (Uint16)IDX_OLED_LINE_3; + } + else + { + drawY = (Uint16)IDX_OLED_LINE_4; + } + + // Label 1 + CStrncpy(OledOperValue.cStrBuff[row], label1, CStrLen(label1)); + + // Status 1 + CStrncat(OledOperValue.cStrBuff[row], statusStr1, CStrLen(statusStr1)); + + // Spacing + CStrncat(OledOperValue.cStrBuff[row], (const int8*)" ", 7U); + + // Label 2 + CStrncat(OledOperValue.cStrBuff[row], label2, CStrLen(label2)); + + // Status 2 + CStrncat(OledOperValue.cStrBuff[row], statusStr2, CStrLen(statusStr2)); + + CDrawLineText(0U, drawY, OledOperValue.cStrBuff[row]); +} + +static void CPageApu1(void) +{ + static Uint16 uiDummyRun = 1U; + + int16 iTemp; + const int8 *cTemp = (const int8*)""; + float32 fTemp; + + /* TITLE */ + CDrawStatusTitle((const int8*)"APU Status", (const int8*)"1/2"); + + /* LINE 1: DC Voltage */ + fTemp = (float32)Rx220.DcVoltage / 10.0F; + + //if ((isfinite(fTemp) != 0) && (uiDummyRun == 0U)) + if (1) + { + CDrawPageLineFloat(IDX_OLED_ROW_1, (const int8*)"DC Voltage ", fTemp, (const int8*)" V"); + } + else + { + CDrawPageLineFloat(IDX_OLED_ROW_1, (const int8*)"DC Voltage ", 0.0F, (const int8*)" V"); + } + + /* LINE 2: Power */ + fTemp = (float32)Rx220.Power / 10.0F; + + //if ((isfinite(fTemp) != 0) && (uiDummyRun == 0U)) + if (1) + { + CDrawPageLineFloat(IDX_OLED_ROW_2, (const int8*)"Power ", fTemp, (const int8*)" kW"); + } + else + { + CDrawPageLineFloat(IDX_OLED_ROW_2, (const int8*)"Power ", 0.0F, (const int8*)" kW"); + } + + /* LINE 3: Speed */ + iTemp = (int16)Rx320.ActualRpm; + CDrawPageLineInt(IDX_OLED_ROW_3, (const int8*)"Speed ", (int32)iTemp, (const int8*)" rpm"); + + /* LINE 4: Status */ + cTemp = CGetApuStateString(GeneralOperValue.uiApuState); + + CStrncpy(OledOperValue.cStrBuff[IDX_OLED_ROW_4], (const int8*)"Status", CStrLen((const int8*)"Status")); + CAddLineIndent(OledOperValue.cStrBuff[IDX_OLED_ROW_4], cTemp); + + if (cTemp != NULL) + { + CStrncat(OledOperValue.cStrBuff[IDX_OLED_ROW_4], cTemp, CStrLen(cTemp)); + } + + CDrawLineText(0U, (Uint16)IDX_OLED_LINE_4, OledOperValue.cStrBuff[IDX_OLED_ROW_4]); + + uiDummyRun = (uiDummyRun == 1U) ? 0U : uiDummyRun; +} + +static void CPageApu2(void) +{ + int8 tempBuff[16]; + int16 iTemp; + + // TITLE + CDrawStatusTitle("APU Status", "2/2"); + + // LINE 1 + iTemp = CGetEngCoolantTemperature(); + CDrawPageLineInt((Uint16)IDX_OLED_ROW_1, "Coolant ", (int32)iTemp, " \xA1\xC9"); + + // LINE 2 + iTemp = (int16)Rx320.ActualTorque; + CDrawPageLineInt((Uint16)IDX_OLED_ROW_2, "Torque ", (int32)iTemp, " %"); + + // LINE 3 + GeneralOperValue.ulTotalOperationHour = ((Uint32)Rx322.TotalOperTimeL) | ((Uint32)Rx322.TotalOperTimeH << 16U); + CHourToString((int32)GeneralOperValue.ulTotalOperationHour, tempBuff); + CDrawPageLine((Uint16)IDX_OLED_ROW_3, (const int8*)"ENG.Hour ", (const int8*)tempBuff, (const int8*)" Hr"); +} + +static void CPageMenu1(void) +{ + /* TITLE */ + CDrawStatusTitle((const int8*)"Menu", (const int8*)"1/2"); + + /* LINE 1 */ + CLineFocus((OledOperValue.uiFocusLine == 0U) ? 1U : 0U); + CDrawSimpleLine((Uint16)IDX_OLED_ROW_1, (const int8*)"1. APU Status "); + + /* LINE 2 */ + CLineFocus((OledOperValue.uiFocusLine == 1U) ? 1U : 0U); + CDrawSimpleLine((Uint16)IDX_OLED_ROW_2, (const int8*)"2. Temperature "); + + /* LINE 3 */ + CLineFocus((OledOperValue.uiFocusLine == 2U) ? 1U : 0U); + CDrawSimpleLine((Uint16)IDX_OLED_ROW_3, (const int8*)"3. Sensor "); + + /* LINE 4 */ + CLineFocus((OledOperValue.uiFocusLine == 3U) ? 1U : 0U); + CDrawSimpleLine((Uint16)IDX_OLED_ROW_4, (const int8*)"4. Warning "); +} + +static void CPageMenu2(void) +{ + /* TITLE */ + CDrawStatusTitle((const int8*)"Menu", (const int8*)"2/2"); + + /* LINE 1 */ + CLineFocus((OledOperValue.uiFocusLine == 0U) ? 1U : 0U); + CDrawSimpleLine((Uint16)IDX_OLED_ROW_1, (const int8*)"5. Fault "); + + /* LINE 2 */ + CLineFocus((OledOperValue.uiFocusLine == 1U) ? 1U : 0U); + CDrawSimpleLine((Uint16)IDX_OLED_ROW_2, (const int8*)"6. Alarm Reset "); + + /* LINE 3 */ + CLineFocus((OledOperValue.uiFocusLine == 2U) ? 1U : 0U); + CDrawSimpleLine((Uint16)IDX_OLED_ROW_3, (const int8*)"7. Maintenance "); + + /* LINE 4 */ + CLineFocus((OledOperValue.uiFocusLine == 3U) ? 1U : 0U); + CDrawSimpleLine((Uint16)IDX_OLED_ROW_4, (const int8*)"8. Version "); +} + +static void CPageTemp(void) +{ + int16 iTemp; + + // TITLE + CDrawStatusTitle("Temperature", "1/1"); + + // LINE 1 + iTemp = (int16)((int16)Rx221.PcbTemperature - 40); + CDrawPageLineInt(IDX_OLED_ROW_1, "PCB Temp. ", (int32)iTemp, " \xA1\xC9"); + + // LINE 2 + iTemp = (int16)((int16)Rx221.FetTemperature - 40); + CDrawPageLineInt(IDX_OLED_ROW_2, "FET Temp. ", (int32)iTemp, " \xA1\xC9"); + + // LINE 3 + iTemp = (int16)((int16)Rx221.GenTemperature1 - 40); + CDrawPageLineInt(IDX_OLED_ROW_3, "Gen.Temp1. ", (int32)iTemp, " \xA1\xC9"); + + // LINE4 + iTemp = (int16)((int16)Rx221.GenTemperature2 - 40); + CDrawPageLineInt(IDX_OLED_ROW_4, "Gen.Temp2. ", (int32)iTemp, " \xA1\xC9"); +} +static void CPageSensor1(void) +{ + float32 fTemp1, fTemp2; + + // TITLE + CDrawSensorTitle("APU Sensor", "1/4"); + + // LINE 1 + fTemp1 = (Adc_EngineHeater_V.fLpfValue < 0.0F) ? 0.0F : Adc_EngineHeater_V.fLpfValue; + fTemp2 = (Adc_EngineHeater_I.fLpfValue < 0.0F) ? 0.0F : Adc_EngineHeater_I.fLpfValue; + CDrawPageLineTwoFloat(IDX_OLED_ROW_1, "EngHeat ", fTemp1, fTemp2); + + // LINE 2 + fTemp1 = (Adc_GlowPlug_V.fLpfValue < 0.0F) ? 0.0F : Adc_GlowPlug_V.fLpfValue; + fTemp2 = (Adc_GlowPlug_I.fLpfValue < 0.0F) ? 0.0F : Adc_GlowPlug_I.fLpfValue; + CDrawPageLineTwoFloat(IDX_OLED_ROW_2, "GlowPlg ", fTemp1, fTemp2); + + // LINE 3 + fTemp1 = (Adc_Solenoid_V.fLpfValue < 0.0F) ? 0.0F : Adc_Solenoid_V.fLpfValue; + fTemp2 = (Adc_Solenoid_I.fLpfValue < 0.0F) ? 0.0F : Adc_Solenoid_I.fLpfValue; + CDrawPageLineTwoFloat(IDX_OLED_ROW_3, "Solnoid ", fTemp1, fTemp2); + + // LINE 4 + fTemp1 = (Adc_FuelPump_V.fLpfValue < 0.0F) ? 0.0F : Adc_FuelPump_V.fLpfValue; + fTemp2 = (Adc_FuelPump_I.fLpfValue < 0.0F) ? 0.0F : Adc_FuelPump_I.fLpfValue; + CDrawPageLineTwoFloat(IDX_OLED_ROW_4, "FuelPmp ", fTemp1, fTemp2); +} + +static void CPageSensor2(void) +{ + float32 fTemp1, fTemp2; + + // TITLE + CDrawSensorTitle("APU Sensor", "2/4"); + + // LINE 1 + fTemp1 = (Adc_CoolantPump_V.fLpfValue < 0.0F) ? 0.0F : Adc_CoolantPump_V.fLpfValue; + fTemp2 = (Adc_CoolantPump_I.fLpfValue < 0.0F) ? 0.0F : Adc_CoolantPump_I.fLpfValue; + CDrawPageLineTwoFloat(IDX_OLED_ROW_1, "CoolPmp ", fTemp1, fTemp2); + + // LINE 2 + fTemp1 = (Adc_Fan1_V.fLpfValue < 0.0F) ? 0.0F : Adc_Fan1_V.fLpfValue; + fTemp2 = (Adc_Fan1_I.fLpfValue < 0.0F) ? 0.0F : Adc_Fan1_I.fLpfValue; + CDrawPageLineTwoFloat(IDX_OLED_ROW_2, "Fan1 ", fTemp1, fTemp2); + + // LINE 3 + fTemp1 = (Adc_Fan2_V.fLpfValue < 0.0F) ? 0.0F : Adc_Fan2_V.fLpfValue; + fTemp2 = (Adc_Fan2_I.fLpfValue < 0.0F) ? 0.0F : Adc_Fan2_I.fLpfValue; + CDrawPageLineTwoFloat(IDX_OLED_ROW_3, "Fan2 ", fTemp1, fTemp2); +} + +static void CPageSensor3(void) +{ + int16 iTemp; + + // TITLE + CDrawSensorTitle("ECU Sensor", "3/4"); + + // LINE 1 + iTemp = (int16)Rx321.BarometricPressure; + CDrawPageLineInt(IDX_OLED_ROW_1, "Barometric ", (int32)iTemp, " mb"); + + // LINE 2 + iTemp = (int16)Rx321.Fan1Speed; + CDrawPageLineInt(IDX_OLED_ROW_2, "Fan1 Speed ", (int32)iTemp, " %"); + + // LINE 3 + iTemp = (int16)Rx321.Fan2Speed; + CDrawPageLineInt(IDX_OLED_ROW_3, "Fan2 Speed ", (int32)iTemp, " %"); + + // LINE 4 + iTemp = (int16)Rx321.CoolantPumpSpeed; + CDrawPageLineInt(IDX_OLED_ROW_4, "C.Pump Speed ", (int32)iTemp, " %"); +} + +static void CPageSensor4(void) +{ + int16 iTemp; + + // TITLE + CDrawSensorTitle("GCU Sensor", "4/4"); + + // LINE 1 + iTemp = (int16)Rx220.Rpm; + CDrawPageLineInt(IDX_OLED_ROW_1, "GEN.RPM ", (int32)iTemp, " rpm"); +} +static void CDrawPageLineStatus(Uint16 row, const int8* label, Uint16 status) +{ + const int8* statusStr = (status == 1U) ? (const int8*)"1" : (const int8*)"0"; + CDrawPageLine(row, label, statusStr, NULL); +} + +static void CPageWarning1(void) +{ + // TITLE + CDrawPageTitle("Warning", "1/2"); + + // LINE 1 + CDrawTwoStatusLine(IDX_OLED_ROW_1, "PCBOT:", CIsBitSet((Uint32)Rx210.GcuWarning, (Uint16)IDX_WARNING_GCU_PCB_OT), "FETOT:", CIsBitSet((Uint32)Rx210.GcuWarning, (Uint16)IDX_WARNING_GCU_FET_OT)); + + // LINE 2 + CDrawTwoStatusLine(IDX_OLED_ROW_2, "GEOT1:", CIsBitSet((Uint32)Rx210.GcuWarning, (Uint16)IDX_WARNING_GCU_WINDING1_OH), "GEOT2:", CIsBitSet((Uint32)Rx210.GcuWarning, (Uint16)IDX_WARNING_GCU_WINDING2_OH)); + + // LINE 3 + CDrawTwoStatusLine(IDX_OLED_ROW_3, "ENGOT:", CIsBitSet((Uint32)Rx310.EcuWarning, (Uint16)IDX_WARNING_ECU_ENGINE_OH), "LOILP:", CIsBitSet((Uint32)Rx310.EcuWarning, (Uint16)IDX_WARNING_ECU_LO_OIL_PRESS)); + + // LINE 4 + CDrawTwoStatusLine(IDX_OLED_ROW_4, "INTOT:", CIsBitSet((Uint32)Rx310.EcuWarning, (Uint16)IDX_WARNING_ECU_INTAKE_OH), "INTLP:", CIsBitSet((Uint32)Rx310.EcuWarning, (Uint16)IDX_WARNING_ECU_INTAKE_LO_PRESS)); +} + +static void CPageWarning2(void) +{ + /* TITLE */ + CDrawPageTitle("Warning", "2/2"); + + /* LINE 1 */ + CDrawTwoStatusLine((Uint16)IDX_OLED_ROW_1, (const int8*)"ENGLT:", CIsBitSet((Uint32)Rx310.EcuWarning, (Uint16)IDX_WARNING_ECU_ENGINE_LO_TEMP), (const int8*)"ENGSF:", CIsBitSet((Uint32)Rx310.EcuWarning, (Uint16)IDX_WARNING_ECU_ENGINE_SENSOR)); + + /* LINE 2 */ + CDrawPageLineStatus((Uint16)IDX_OLED_ROW_2, (const int8*)"DEFAC:", CIsBitSet((Uint32)Rx310.EcuWarning, (Uint16)IDX_WARNING_ECU_DEFAULT_ACTIVE)); +} + +static void CPageFault1(void) +{ + // TITLE + CDrawFaultTitle("APU Fault", "1/7"); + + // LINE 1 + CDrawTwoStatusLine(IDX_OLED_ROW_1, "CARCT:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_CAR_COMM), "GCUCT:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_GCU_COMM)); + + // LINE 2 + CDrawTwoStatusLine(IDX_OLED_ROW_2, "ECUCT:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_ECU_COMM), "RPMER:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_RPM_ERR)); + + // LINE 3 + CDrawTwoStatusLine(IDX_OLED_ROW_3, "EHLOC:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OC), "GPLOC:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_GLOW_PLUG_OC)); + + // LINE 4 + CDrawTwoStatusLine(IDX_OLED_ROW_4, "SOLOC:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_SOLENOID_OC), "FPLOC:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FUEL_PUMP_OC)); +} + +static void CPageFault2(void) +{ + // TITLE + CDrawFaultTitle("APU Fault", "2/7"); + + // LINE 1 + CDrawTwoStatusLine(IDX_OLED_ROW_1, "CPLOC:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OC), "F1LOC:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN1_OC)); + + // LINE 2 + CDrawTwoStatusLine(IDX_OLED_ROW_2, "F2LOC:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN2_OC), "EHVUV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_ENGINE_HEAT_UV)); + + // LINE 3 + CDrawTwoStatusLine(IDX_OLED_ROW_3, "EHVOV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OV), "GPVUV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_GLOW_PLUG_UV)); + + // LINE 4 + CDrawTwoStatusLine(IDX_OLED_ROW_4, "GPVOV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_GLOW_PLUG_OV), "SLVUV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_SOLENOID_UV)); +} + +static void CPageFault3(void) +{ + // TITLE + CDrawFaultTitle("APU Fault", "3/7"); + + // LINE 1 + CDrawTwoStatusLine(IDX_OLED_ROW_1, "SLVOV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_SOLENOID_OV), "FPVUV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FUEL_PUMP_UV)); + + // LINE 2 + CDrawTwoStatusLine(IDX_OLED_ROW_2, "FPVOV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FUEL_PUMP_OV), "CPVUV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_COOLANT_PUMP_UV)); + + // LINE 3 + CDrawTwoStatusLine(IDX_OLED_ROW_3, "CPVOV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OV), "F1VUV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN1_UV)); + + // LINE 4 + CDrawTwoStatusLine(IDX_OLED_ROW_4, "F1VOV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN1_OV), "F2VUV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN2_UV)); +} + +static void CPageFault4(void) +{ + /* TITLE */ + CDrawFaultTitle((const int8*)"APU Fault", (const int8*)"4/7"); + + /* LINE 1: */ + CDrawFaultStatusLine((Uint16)IDX_OLED_ROW_1, (const int8*)"F2VOV:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN2_OV), (const int8*)"CRKFL:", CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_CRANKING_FAIL)); +} + +static void CPageFault5(void) +{ + // TITLE + CDrawFaultTitle("GCU Fault", "5/7"); + + // LINE 1 + CDrawFaultStatusLine(IDX_OLED_ROW_1, "HTRIP:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_HWTRIP), "HIGBT:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_HWIGBT)); + + // LINE 2 + CDrawFaultStatusLine(IDX_OLED_ROW_2, "HDCOV:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_HW_DC), "GNOCU:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_GEN_OCU)); + + // LINE 3 + CDrawFaultStatusLine(IDX_OLED_ROW_3, "GNOCV:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_GEN_OCW), "GNOCW:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_GEN_OCW)); + + // LINE 4 + CDrawFaultStatusLine(IDX_OLED_ROW_4, "SDCOV:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_DC_OV), "SDCOC:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_DC_OC)); +} + +static void CPageFault6(void) +{ + // TITLE + CDrawFaultTitle("GCU Fault", "6/7"); + + // LINE 1 + CDrawFaultStatusLine(IDX_OLED_ROW_1, "SMOOC:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_CRANK_OC), "PCBOT:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_PCB_OT)); + + // LINE 2 + CDrawFaultStatusLine(IDX_OLED_ROW_2, "FETOT:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_FET_OT), "GW1OT:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_WINDING1_OH)); + + // LINE 3 + CDrawFaultStatusLine(IDX_OLED_ROW_3, "GW2OT:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_WINDING2_OH), "GENOS:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_GEN_OS)); + + // LINE 4 + CDrawFaultStatusLine(IDX_OLED_ROW_4, "RSICF:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_RES_IC), "RSPRT:", CIsBitSet(ulGcuTotalAlarm, (Uint16)IDX_FAULT_GCU_RES_PRTY)); +} + +static void CPageFault7(void) +{ + // TITLE + CDrawFaultTitle("ECU Fault", "7/7"); + + // LINE 1 + CDrawFaultStatusLine(IDX_OLED_ROW_1, "OILMS:", CIsBitSet(ulEcuTotalAlarm, (Uint16)IDX_FAULT_ECU_OIL_MS), "INTOT:", CIsBitSet(ulEcuTotalAlarm, (Uint16)IDX_FAULT_ECU_INT_OH)); + + // LINE 2 + CDrawFaultStatusLine(IDX_OLED_ROW_2, "ENGOH:", CIsBitSet(ulEcuTotalAlarm, (Uint16)IDX_FAULT_ECU_ENG_OH), "ACTUA:", CIsBitSet(ulEcuTotalAlarm, (Uint16)IDX_FAULT_ECU_ACTUATOR)); + + // LINE 3 + CDrawFaultStatusLine(IDX_OLED_ROW_3, "RPMSG:", CIsBitSet(ulEcuTotalAlarm, (Uint16)IDX_FAULT_ECU_RPM_SIG), "ENGSF:", CIsBitSet(ulEcuTotalAlarm, (Uint16)IDX_FAULT_ECU_ENG_SF)); +} + +static void CDrawAlarmBox(void) +{ + CDrawLine(5U, 10U, 122U, 10U); // Top + CDrawLine(5U, 10U, 5U, 58U); // Left + CDrawLine(5U, 59U, 122U, 59U); // Bottom + CDrawLine(122U, 10U, 122U, 58U); // Right +} + +static void CDrawPostStatusLine(Uint16 row, const int8* l1, Uint16 s1, const int8* l2, Uint16 s2, const int8* l3, Uint16 s3) +{ + Uint16 y = 0U; + const int8* pPrintStr = NULL; // 실제 출력할 문자열을 가리킬 포인터 + + OledOperValue.cStrBuff[row][0] = ASCII_NULL; // '\0' + + // Label 1 + Status 1 + if (l1 != NULL) + { + CStrncat(OledOperValue.cStrBuff[row], l1, CStrLen(l1)); + CStrncat(OledOperValue.cStrBuff[row], (s1 == 0U) ? (const int8*)"P" : (const int8*)"F", 1U); + } + + // Label 2 + Status 2 + if (l2 != NULL) + { + if (OledOperValue.cStrBuff[row][0] != ASCII_NULL) // '\0' + { + CStrncat(OledOperValue.cStrBuff[row], (const int8*)" ", 1U); + } + CStrncat(OledOperValue.cStrBuff[row], l2, CStrLen(l2)); + CStrncat(OledOperValue.cStrBuff[row], (s2 == 0U) ? (const int8*)"P" : (const int8*)"F", 1U); + } + + // Label 3 + Status 3 + if (l3 != NULL) + { + if (OledOperValue.cStrBuff[row][0] != ASCII_NULL) // '\0' + { + CStrncat(OledOperValue.cStrBuff[row], (const int8*)" ", 1U); + } + CStrncat(OledOperValue.cStrBuff[row], l3, CStrLen(l3)); + CStrncat(OledOperValue.cStrBuff[row], (s3 == 0U) ? (const int8*)"P" : (const int8*)"F", 1U); + } + + if (row == (Uint16)IDX_OLED_ROW_4) + { + pPrintStr = OledOperValue.cStrBuff[row]; + } + else + { + CTextAlign(OledOperValue.cAlignBuffer, OledOperValue.cStrBuff[row]); + pPrintStr = OledOperValue.cAlignBuffer; + } + + // Y 좌표 설정 + if (row == (Uint16)IDX_OLED_ROW_2) + { + y = (Uint16)IDX_OLED_LINE_2; + } + else if (row == (Uint16)IDX_OLED_ROW_3) + { + y = (Uint16)IDX_OLED_LINE_3; + } + else + { + if (row == (Uint16)IDX_OLED_ROW_4) + { + y = (Uint16)IDX_OLED_LINE_4; + } + } + + if (pPrintStr != NULL) + { + CDrawLineText(0U, y, (const int8*)pPrintStr); + } +} + +static void CPageAlarmReset(void) +{ + const int8 *cTemp = ""; + + // LINE 1 + CDrawCenteredLine((Uint16)IDX_OLED_LINE_1, "Reset all faults?"); + + // LINE 2 + CDrawCenteredLine((Uint16)IDX_OLED_LINE_2, "(no clear warnings)"); + + // LINE 3 + cTemp = (OledOperValue.uiResetAlarmAnswer == 1U) ? (int8*)"YES" : (int8*)" NO"; + CDrawCenteredLine((Uint16)IDX_OLED_LINE_3 + 5U, cTemp); + + // BOX + CDrawAlarmBox(); +} + +static void CPagePassword(void) +{ + const int8 *cTemp = ""; + int8 maskBuffer[16]; + Uint16 uiTemp[2] = { 0, '\0' }; + + // TITLE + CDrawStatusTitle("Input Password", NULL); + + switch (OledOperValue.uiFocusDigit) + { + case (Uint16)IDX_OLED_PASS_DIGIT_1: + { + uiTemp[0] = GeneralOperValue.uiPassword[IDX_OLED_PASS_DIGIT_1] + 48U; // 48 : '0' + cTemp = (int8*)uiTemp; + CStrncpy(maskBuffer, "[", 2); + CStrncat(maskBuffer, cTemp, 1); + CStrncat(maskBuffer, "][*][*][*]", 10); + break; + } + case (Uint16)IDX_OLED_PASS_DIGIT_2: + { + uiTemp[0] = GeneralOperValue.uiPassword[IDX_OLED_PASS_DIGIT_2] + 48U; // 48 : '0' + cTemp = (int8*)uiTemp; + CStrncpy(maskBuffer, "[*][", 4); + CStrncat(maskBuffer, cTemp, 1); + CStrncat(maskBuffer, "][*][*]", 7); + break; + } + case (Uint16)IDX_OLED_PASS_DIGIT_3: + { + uiTemp[0] = GeneralOperValue.uiPassword[IDX_OLED_PASS_DIGIT_3] + 48U; // 48 : '0' + cTemp = (int8*)uiTemp; + CStrncpy(maskBuffer, "[*][*][", 7); + CStrncat(maskBuffer, cTemp, 1); + CStrncat(maskBuffer, "][*]", 4); + break; + } + default: + { + uiTemp[0] = GeneralOperValue.uiPassword[IDX_OLED_PASS_DIGIT_4] + 48U; // 48 : '0' + cTemp = (int8*)uiTemp; + CStrncpy(maskBuffer, "[*][*][*][", 10); + CStrncat(maskBuffer, cTemp, 1); + CStrncat(maskBuffer, "]", 1); + break; + } + } + + CDrawCenteredLine((Uint16)IDX_OLED_LINE_2, (const int8*)maskBuffer); +} +static void CPageMaintenance(void) +{ + const int8 *cTemp = ""; + + // TITLE + CDrawStatusTitle("Maintenance", "1/1"); + + // LINE 1 + CLineFocus((OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_1) ? 1U : 0U); + cTemp = (GeneralOperValue.Maintenance.ManualCranking > 0U) ? (int8*)"ON " : (int8*)"OFF"; + CDrawPageLine(IDX_OLED_ROW_1, "Manual Cranking ", cTemp, NULL); + + // LINE 2 + CLineFocus((OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_2) ? 1U : 0U); + cTemp = (GeneralOperValue.Maintenance.LampTest > 0U) ? (int8*)"ON " : (int8*)"OFF"; + CDrawPageLine(IDX_OLED_ROW_2, "Lamp Test ", cTemp, NULL); + + // LINE 3 + CLineFocus((OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_3) ? 1U : 0U); + CDrawPageLine(IDX_OLED_ROW_3, "Switch Test ", NULL, NULL); +} + +static void CPageVersion(void) +{ + int8 cTemp[16]; + + // TITLE + CDrawStatusTitle("Version", "1/1"); + + // LINE 1 is blank + + // LINE 2 + CMakeVersionString(cTemp, (int16)FIRMWARE_VERSION_MAJOR, (int16)FIRMWARE_VERSION_MINOR, (int16)FIRMWARE_VERSION_PATCH); + CDrawPageLine(IDX_OLED_ROW_2, " DCU : ", cTemp, NULL); + + // LINE 3 + CMakeVersionString(cTemp, (int16)Rx200.VersionMajor, (int16)Rx200.VersionMinor, (int16)Rx200.VersionPatch); + CDrawPageLine(IDX_OLED_ROW_3, " GCU : ", cTemp, NULL); + + // LINE 4 + CMakeVersionString(cTemp, (int16)Rx300.VersionMajor, (int16)Rx300.VersionMinor, (int16)Rx300.VersionPatch); + CDrawPageLine(IDX_OLED_ROW_4, " ECU : ", cTemp, NULL); +} + +static void CDrawCenteredLine(Uint16 y, const int8* text) +{ + CStrncpy(OledOperValue.cStrBuff[IDX_OLED_ROW_0], text, CStrLen(text)); + CTextAlign(OledOperValue.cAlignBuffer, OledOperValue.cStrBuff[IDX_OLED_ROW_0]); + CDrawStr(0U, y, OledOperValue.cAlignBuffer); +} + +static void CDrawKeyTestBox(void) +{ + CDrawLine(0U, 0U, 125U, 0U); // Top + CDrawLine(0U, 0U, 0U, 22U); // Left + CDrawLine(0U, 23U, 2U, 25U); // Left diag + CDrawLine(3U, 25U, 123U, 25U); // Bottom + CDrawLine(124U, 25U, 126U, 23U); // Right diag + CDrawLine(126U, 0U, 126U, 22U); // Right +} + +static void CDrawKeyStatusLine(Uint16 row, const int8* l1, Uint16 s1, const int8* l2, Uint16 s2, const int8* l3, Uint16 s3) +{ + const int8* s1Str = (s1 == 1U) ? (const int8*)"1" : (const int8*)"0"; + Uint16 y = 0U; + + // Label 1 + Status 1 + CStrncpy(OledOperValue.cStrBuff[row], l1, CStrLen(l1)); + CStrncat(OledOperValue.cStrBuff[row], s1Str, 1U); + + // Label 2 + Status 2 + if (l2 != NULL) + { + CStrncat(OledOperValue.cStrBuff[row], (const int8*)" ", 1U); + CStrncat(OledOperValue.cStrBuff[row], l2, CStrLen(l2)); + CStrncat(OledOperValue.cStrBuff[row], (s2 == 1U) ? (const int8*)"1" : (const int8*)"0", 1U); + } + + // Label 3 + Status 3 + if (l3 != NULL) + { + CStrncat(OledOperValue.cStrBuff[row], (const int8*)" ", 1U); + CStrncat(OledOperValue.cStrBuff[row], l3, CStrLen(l3)); + CStrncat(OledOperValue.cStrBuff[row], (s3 == 1U) ? (const int8*)"1" : (const int8*)"0", 1U); + } + + // Determine Y based on row + if (row == (Uint16)IDX_OLED_ROW_2) + { + y = (Uint16)IDX_OLED_LINE_2; + } + else if (row == (Uint16)IDX_OLED_ROW_3) + { + y = (Uint16)IDX_OLED_LINE_3; + } + else + { + if (row == (Uint16)IDX_OLED_ROW_4) + { + y = (Uint16)IDX_OLED_LINE_4; + } + } + + CDrawLineText(0U, y, OledOperValue.cStrBuff[row]); +} + +static void CPageKeyTest(void) +{ + // TITLE1 + CDrawCenteredLine((Uint16)IDX_OLED_LINE_TITLE + 2U, "Button input Test"); + + // TITLE2 + CDrawCenteredLine((Uint16)IDX_OLED_LINE_1 - 1U, "(Back to Up&Down)"); + + // BOX + CDrawKeyTestBox(); + + // LINE 2 + CDrawKeyStatusLine((Uint16)IDX_OLED_ROW_2, " Stat:", ((GPIO_KEY_START() | GPIO_KEY_REMOTE_START() | GPIO_KEY_REMOTE_STOP()) == 0U) ? 1U : 0U, NULL, 0, NULL, 0); + + // LINE 3 + CDrawKeyStatusLine((Uint16)IDX_OLED_ROW_3, " Up:", (GPIO_KEY_UP() == 0U) ? 1U : 0U, "Entr:", (GPIO_KEY_ENTER() == 0U) ? 1U : 0U, "Powr:", (GPIO_KEY_POWER() == 0U) ? 1U : 0U); + + // LINE 4 + CDrawKeyStatusLine((Uint16)IDX_OLED_ROW_4, "Down:", (GPIO_KEY_DOWN() == 0U) ? 1U : 0U, "Menu:", (GPIO_KEY_MENU() == 0U) ? 1U : 0U, "Emgc:", ((GPIO_KEY_EMERGENCY() | GPIO_KEY_REMOTE_EMERGENCY()) == 0U) ? 1U : 0U); +} + +static void CPageShutdown(void) +{ + // LINE 1 + CDrawCenteredLine((Uint16)IDX_OLED_LINE_1, "System"); + + // LINE 2 + CDrawCenteredLine((Uint16)IDX_OLED_LINE_2, "Shutting down..."); +} + +void CSetPage(Uint16 PageNum) +{ + static const CPageHandler PageTable[IDX_OLED_PAGE_MAX] = + { + { IDX_OLED_PAGE_APU1, &CPageApu1 }, + { IDX_OLED_PAGE_APU2, &CPageApu2 }, + { IDX_OLED_PAGE_MENU1, &CPageMenu1 }, + { IDX_OLED_PAGE_MENU2, &CPageMenu2 }, + { IDX_OLED_PAGE_TEMP, &CPageTemp }, + { IDX_OLED_PAGE_SENSOR1, &CPageSensor1 }, + { IDX_OLED_PAGE_SENSOR2, &CPageSensor2 }, + { IDX_OLED_PAGE_SENSOR3, &CPageSensor3 }, + { IDX_OLED_PAGE_SENSOR4, &CPageSensor4 }, + { IDX_OLED_PAGE_WARNING1, &CPageWarning1 }, + { IDX_OLED_PAGE_WARNING2, &CPageWarning2 }, + { IDX_OLED_PAGE_FAULT1, &CPageFault1 }, + { IDX_OLED_PAGE_FAULT2, &CPageFault2 }, + { IDX_OLED_PAGE_FAULT3, &CPageFault3 }, + { IDX_OLED_PAGE_FAULT4, &CPageFault4 }, + { IDX_OLED_PAGE_FAULT5, &CPageFault5 }, + { IDX_OLED_PAGE_FAULT6, &CPageFault6 }, + { IDX_OLED_PAGE_FAULT7, &CPageFault7 }, + { IDX_OLED_PAGE_RESET_ALARM, &CPageAlarmReset }, + { IDX_OLED_PAGE_PASSWORD, &CPagePassword }, + { IDX_OLED_PAGE_MAINTENANCE, &CPageMaintenance }, + { IDX_OLED_PAGE_VERSION, &CPageVersion }, + { IDX_OLED_PAGE_KEY_TEST, &CPageKeyTest }, + { IDX_OLED_PAGE_SHUTDOWN, &CPageShutdown } + }; + + Uint16 i; + + if (OledOperValue.uiOldPageNum != PageNum) + { + COledBufferReset(); + OledOperValue.uiOldPageNum = PageNum; + } + + for (i = 0U; i < (Uint16)IDX_OLED_PAGE_MAX; i++) + { + if (OledOperValue.uiPageNum == i) + { + CLineFocus(0U); + PageTable[i].pAction(); // CPageHandler 참조 + } + } +} + +void COledBufferReset(void) +{ + (void)memset(OledOperValue.uiBuff, 0, sizeof(int8) * OLED_WIDTH * OLED_PAGE); + (void)memset(OledOperValue.cStrBuff, 0, sizeof(int8) * TXT_LINE_LEN * TXT_MAX_LEN); +} + +static void CDrawTitleBox(Uint16 TitleLen) +{ + CDrawLine(8U, 0U, 8U, 9U); // 왼쪽 + CDrawLine(8U, 10U, 10U, 12U); // 왼쪽 모서리 + CDrawLine(11U, 12U, (TitleLen + 9U), 12U); // 아래쪽 + CDrawLine((TitleLen + 10U), 12U, (TitleLen + 12U), 10U); // 오른쪽 모서리 + CDrawLine((TitleLen + 12U), 0U, (TitleLen + 12U), 9U); // 오른쪽 + + if (OledOperValue.uiPageNum != (Uint16)IDX_OLED_PAGE_PASSWORD) + { + // 서브 타이틀 박스 + CDrawLine(98U, 0U, 98U, 9U); // 왼쪽 + CDrawLine(98U, 10U, 100U, 12U); // 왼쪽 모서리 + CDrawLine(101U, 12U, 118U, 12U); // 아래쪽 + CDrawLine(119U, 12U, 121U, 10U); // 오른쪽 모서리 + CDrawLine(121U, 0U, 121U, 9U); // 오른쪽 + } +} + +void COledReflash(Uint16 x, Uint16 y, Uint16 width, Uint16 height) +{ + Uint16 i, j; + + for (j = (y / 8U); j < ((y + height) / 8U); j++) + { + for (i = x; i < (x + width); i++) + { + CSetPageAddress(j); + CSetColumnAddress(i); + COledWrite(OledOperValue.uiBuff[i][j], MODE_DATA); + } + } +} + +void CInitOled(void) +{ + Uint16 uiPageNum; + Uint16 i; + + CInitOledModule(); + + for(uiPageNum = 0U; uiPageNum < 8U; uiPageNum++) + { + COledWrite((Uint16)(0xB0U | uiPageNum), (Uint16)MODE_COMMAND); + + for(i = 0U; i < (Uint16)OLED_WIDTH; i++) + { + COledWrite((Uint16)0x00, (Uint16)MODE_DATA); + } + } + + CInitProgress(); +} + +static void CInitProgress(void) +{ + OledOperValue.Color.TxtColor = 1U; + + CTextAlign(OledOperValue.cAlignBuffer, "K2 APU"); + CDrawStr(0, (Uint16)IDX_OLED_LINE_TITLE, OledOperValue.cAlignBuffer); + + CDrawBox(OLED_LOAD_PROGRESS_X, OLED_LOAD_PROGRESS_Y, OLED_LOAD_PROGRESS_W, OLED_LOAD_PROGRESS_H); + + (void)memset(OledOperValue.cAlignBuffer, 0, sizeof(char) * TXT_MAX_LEN); + + CTextAlign(OledOperValue.cAlignBuffer, "Initializing System"); + CDrawStr(0, (Uint16)IDX_OLED_LINE_2, OledOperValue.cAlignBuffer); +} + +static void CAddLineIndent(int8 *buffer, const int8 *str) +{ + Uint16 i; + Uint16 uiSpaceNeeded = ((Uint16)TXT_MAX_LEN - 1U) - CStrLen(buffer) - CStrLen(str); + + if (uiSpaceNeeded > 0U) + { + for (i = 0U; i < uiSpaceNeeded; i++) + { + CStrncat(buffer, " ", 1U); + } + } +} + +static void CTextAlign(int8 *buffer, const int8 *str) +{ + Uint16 uiIndent, uiLen, i, j; + + uiLen = 0U; + i = 0U; + + while (str[i] != ASCII_NULL) // str은 int8* 이므로, int8 타입의 널 종료 값(0) 찾음 + { + uiLen++; + i++; + } + + if (uiLen >= (Uint16)TXT_MAX_LEN) + { + uiIndent = 0U; + } + else + { + uiIndent = (((Uint16)TXT_MAX_LEN - 1U) - uiLen) / 2U; + } + + if ((uiIndent > 0U) && (uiIndent < (Uint16)TXT_MAX_LEN)) // 리소스 과도 소비 방지 + { + for (i = 0U; i < uiIndent; i++) + { + buffer[i] = ASCII_BLANK; + } + + for (j = 0U; j < uiLen; j++) + { + buffer[i + j] = str[j]; + } + } + + buffer[i + uiLen] = ASCII_NULL; +} + +static void CDrawBox(Uint16 x, Uint16 y, Uint16 w, Uint16 h) +{ + CDrawLine(x, y, w, y); // 윗변 + CDrawLine(x, (y + 1U), x, (y + h)); // 좌측 막대 + CDrawLine(x, (y + h), w, (y + h)); // 아랫 변 + CDrawLine(w, (y + 1U), w, (h > 0U) ? (y + h - 1U) : y); // 우측 막대 +} + +static void CSetDrawRegion(Uint16 x, Uint16 y) +{ + if (x > OledOperValue.Point.X) + { + OledOperValue.Point.X = x; + } + if (y > OledOperValue.Point.Y) + { + OledOperValue.Point.Y = y; + } +} + +static void CDrawLine(Uint16 x1, Uint16 y1, Uint16 x2, Uint16 y2) +{ + Uint16 uiX1 = x1; + Uint16 uiY1 = y1; + Uint16 uiX2 = x2; + Uint16 uiY2 = y2; + + Uint16 tmp = 0U, x = 0U, y = 0U, dx = 0U, dy = 0U, swapxy = 0U; + Uint16 loop_end = 0U; + Uint16 minor_limit = 0U; /* 보조축(y) 한계값 */ + + int16 err = 0; + int16 ystep = 0; + + dx = uiX2 - uiX1; + dy = (uiY1 > uiY2) ? (uiY1 - uiY2) : (uiY2 - uiY1); + + if (dy > dx) + { + swapxy = 1U; + tmp = dx; dx = dy; dy = tmp; + + tmp = uiX1; uiX1 = uiY1; uiY1 = tmp; + tmp = uiX2; uiX2 = uiY2; uiY2 = tmp; + + loop_end = (Uint16)OLED_HEIGHT - 1U; + minor_limit = (Uint16)OLED_WIDTH - 1U; + } + else + { + loop_end = (Uint16)OLED_WIDTH - 1U; + minor_limit = (Uint16)OLED_HEIGHT - 1U; + } + + if (uiX2 > loop_end) + { + uiX2 = loop_end; + } + + err = (int16)((Uint16)(dx >> 1U)); + ystep = (uiY2 > uiY1) ? (int16)1 : (int16)-1; + y = uiY1; + + if (swapxy == 0U) + { + for (x = uiX1; x <= uiX2; x++) + { + if (y > minor_limit) + { + break; + } + + CPutPixel(x, y, OledOperValue.Color.TxtColor); + + err = err - (int16)dy; + if (err < 0) + { + y = (ystep > 0) ? (y + (Uint16)ystep) : (y - (Uint16)(-ystep)); + err = err + (int16)dx; + } + } + } + else + { + for (x = uiX1; x <= uiX2; x++) + { + if (y > minor_limit) + { + break; + } + + CPutPixel(y, x, OledOperValue.Color.TxtColor); + + err = err - (int16)dy; + if (err < 0) + { + y = (ystep > 0) ? (y + (Uint16)ystep) : (y - (Uint16)(-ystep)); + err = err + (int16)dx; + } + } + } +} + +static inline void CPutPixel(Uint16 x, Uint16 y, Uint16 Color) +{ + Uint16 uiPage; + Uint16 uiOffset; + + if ((x < (Uint16)OLED_WIDTH) && (y < (Uint16)OLED_HEIGHT)) + { + uiPage = y / 8U; + uiOffset = y % 8U; + + if (Color == 1U) + { + OledOperValue.uiBuff[x][uiPage] = (Uint8)(OledOperValue.uiBuff[x][uiPage] | (Uint8)(1U << uiOffset)); + } + else + { + OledOperValue.uiBuff[x][uiPage] = (Uint8)(OledOperValue.uiBuff[x][uiPage] & (Uint8)(~(Uint8)(1U << uiOffset))); + } + } +} + +static void CSetPageAddress(Uint16 Address) +{ + COledWrite((Uint16)(Address | 0xB0U), (Uint16)MODE_COMMAND); +} + +static void CSetColumnAddress(Uint16 x) +{ + Uint16 HighAddress; + Uint16 LowAddress; + + x += 0U; // ER_OLEDM024-1G is +2, ER_OLEDM024-2G is +0 + HighAddress = ((x >> 4) & 0x0FU) | 0x10U; + LowAddress = x & 0x0FU; + + COledWrite(LowAddress, (Uint16)MODE_COMMAND); + COledWrite(HighAddress, (Uint16)MODE_COMMAND); +} + +void CInitXintf(void) +{ + /* for All Zones Timing for all zones based on XTIMCLK = SYSCLKOUT (150MHz) */ + EALLOW; + XintfRegs.XINTCNF2.bit.XTIMCLK = 1; + XintfRegs.XINTCNF2.bit.WRBUFF = 0; /* No write buffering */ + XintfRegs.XINTCNF2.bit.CLKOFF = 0; /* XCLKOUT is enabled */ + XintfRegs.XINTCNF2.bit.CLKMODE = 1; /* XCLKOUT = XTIMCLK */ + + /* Zone write timing */ + XintfRegs.XTIMING6.bit.XWRLEAD = 2; + XintfRegs.XTIMING6.bit.XWRACTIVE = 12; + XintfRegs.XTIMING6.bit.XWRTRAIL = 2; + + /* Zone read timing */ + XintfRegs.XTIMING6.bit.XRDLEAD = 2; + XintfRegs.XTIMING6.bit.XRDACTIVE = 12; + XintfRegs.XTIMING6.bit.XRDTRAIL = 2; + + XintfRegs.XTIMING6.bit.X2TIMING = 0; + XintfRegs.XTIMING6.bit.USEREADY = 0; + XintfRegs.XTIMING6.bit.READYMODE = 0; + XintfRegs.XTIMING6.bit.XSIZE = 3; + + GpioCtrlRegs.GPCMUX1.bit.GPIO79 = 3; // OLED_D0 XD0 + GpioCtrlRegs.GPCMUX1.bit.GPIO78 = 3; // OLED_D1 XD1 + GpioCtrlRegs.GPCMUX1.bit.GPIO77 = 3; // OLED_D2 XD2 + GpioCtrlRegs.GPCMUX1.bit.GPIO76 = 3; // OLED_D3 XD3 + GpioCtrlRegs.GPCMUX1.bit.GPIO75 = 3; // OLED_D4 XD4 + GpioCtrlRegs.GPCMUX1.bit.GPIO74 = 3; // OLED_D5 XD5 + GpioCtrlRegs.GPCMUX1.bit.GPIO73 = 3; // OLED_D6 XD6 + GpioCtrlRegs.GPCMUX1.bit.GPIO72 = 3; // OLED_D7 XD7 + + GpioCtrlRegs.GPAMUX2.bit.GPIO28 = 3; // OLED_CS_C XZCS6 + GpioCtrlRegs.GPBMUX1.bit.GPIO38 = 3; // OLED_WR_C XWE0 + GpioCtrlRegs.GPBMUX1.bit.GPIO40 = 3; // OLED_A0_C XWE1 + + EDIS; +} + +static void CDrawStr(Uint16 x, Uint16 y, const int8* str) +{ + Uint16 i = 0U; + + if (str != NULL) + { + /* 널 문자를 만나거나 최대 한계에 도달할 때까지 그리기 수행 */ + while ((str[i] != ASCII_NULL) && (i < (Uint16)TXT_MAX_LEN)) + { + if (((Uint8)str[i] & 0x80U) != 0U) + { + CDrawChar(x, y, (Uint16)(((Uint16)str[i] << 8U) | (Uint16)str[i + 1U]), TXT_TYPE_ETC); + i++; + x += (TXT_ENG_WIDTH * 2U); + } + else + { + CDrawChar(x, y, (Uint16)str[i], TXT_TYPE_ENG); + x += TXT_ENG_WIDTH; + } + i++; + } + } +} + +static void CDrawChar(Uint16 x, Uint16 y, Uint16 ch, Uint16 type) +{ + // 영문 폰트 테이블 인덱스에 따른 값은 Description\font.txt 참조 + static const Uint16 EngFontTable[96][9] = + { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x10, 0x41, 0x04, 0x10, 0x41, 0x00, 0x10, 0x40, 0x00 }, { 0x28, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x14, 0x57, 0xCA, 0x28, 0xAF, 0xD4, 0x51, 0x40, 0x00 }, { 0x10, 0xE5, 0x54, 0x30, 0x61, 0x45, 0x54, 0xE1, 0x00 }, { 0x25, 0x55, 0x8A, 0x10, 0x42, 0x8D, 0x55, 0x20, 0x00 }, + { 0x31, 0x24, 0x92, 0x31, 0x54, 0x92, 0x48, 0xD0, 0x00 }, { 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x08, 0x41, 0x08, 0x20, 0x82, 0x08, 0x20, 0x41, 0x02 }, + { 0x20, 0x41, 0x02, 0x08, 0x20, 0x82, 0x08, 0x41, 0x08 }, { 0x00, 0x00, 0x04, 0x11, 0xF1, 0x0A, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x04, 0x11, 0xF1, 0x04, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x42, 0x00 }, { 0x00, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00 }, + { 0x04, 0x10, 0x82, 0x10, 0x42, 0x08, 0x41, 0x00, 0x00 }, { 0x39, 0x14, 0x51, 0x45, 0x14, 0x51, 0x44, 0xE0, 0x00 }, { 0x10, 0xC1, 0x04, 0x10, 0x41, 0x04, 0x10, 0x40, 0x00 }, + { 0x39, 0x14, 0x41, 0x08, 0x42, 0x10, 0x41, 0xF0, 0x00 }, { 0x39, 0x14, 0x41, 0x18, 0x10, 0x51, 0x44, 0xE0, 0x00 }, { 0x08, 0x61, 0x8A, 0x29, 0x24, 0x9F, 0x08, 0x20, 0x00 }, + { 0x7D, 0x04, 0x10, 0x79, 0x10, 0x41, 0x44, 0xE0, 0x00 }, { 0x39, 0x14, 0x10, 0x79, 0x14, 0x51, 0x44, 0xE0, 0x00 }, { 0x7D, 0x14, 0x41, 0x08, 0x21, 0x04, 0x10, 0x40, 0x00 }, + { 0x39, 0x14, 0x51, 0x39, 0x14, 0x51, 0x44, 0xE0, 0x00 }, { 0x39, 0x14, 0x51, 0x44, 0xF0, 0x41, 0x44, 0xE0, 0x00 }, { 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00 }, + { 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x10, 0x80, 0x00 }, { 0x00, 0x00, 0x42, 0x31, 0x03, 0x02, 0x04, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x7C, 0x07, 0xC0, 0x00, 0x00, 0x00 }, + { 0x00, 0x04, 0x08, 0x18, 0x11, 0x88, 0x40, 0x00, 0x00 }, { 0x39, 0x14, 0x41, 0x08, 0x41, 0x00, 0x10, 0x40, 0x00 }, { 0x18, 0x94, 0xD5, 0x55, 0x55, 0x57, 0x40, 0xE0, 0x00 }, + { 0x10, 0x41, 0x0A, 0x28, 0xA7, 0xD1, 0x45, 0x10, 0x00 }, { 0x79, 0x14, 0x51, 0x79, 0x14, 0x51, 0x45, 0xE0, 0x00 }, { 0x39, 0x14, 0x50, 0x41, 0x04, 0x11, 0x44, 0xE0, 0x00 }, + { 0x79, 0x14, 0x51, 0x45, 0x14, 0x51, 0x45, 0xE0, 0x00 }, { 0x7D, 0x04, 0x10, 0x7D, 0x04, 0x10, 0x41, 0xF0, 0x00 }, { 0x7D, 0x04, 0x10, 0x79, 0x04, 0x10, 0x41, 0x00, 0x00 }, + { 0x39, 0x14, 0x50, 0x5D, 0x14, 0x51, 0x4C, 0xD0, 0x00 }, { 0x45, 0x14, 0x51, 0x7D, 0x14, 0x51, 0x45, 0x10, 0x00 }, { 0x10, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x40, 0x00 }, + { 0x08, 0x20, 0x82, 0x08, 0x20, 0x92, 0x48, 0xC0, 0x00 }, { 0x45, 0x24, 0x94, 0x61, 0x45, 0x12, 0x49, 0x10, 0x00 }, { 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x41, 0xF0, 0x00 }, + { 0x45, 0x16, 0xDB, 0x6D, 0x55, 0x55, 0x45, 0x10, 0x00 }, { 0x45, 0x16, 0x59, 0x55, 0x54, 0xD3, 0x45, 0x10, 0x00 }, { 0x39, 0x14, 0x51, 0x45, 0x14, 0x51, 0x44, 0xE0, 0x00 }, + { 0x79, 0x14, 0x51, 0x45, 0xE4, 0x10, 0x41, 0x00, 0x00 }, { 0x39, 0x14, 0x51, 0x45, 0x14, 0x51, 0x54, 0xE0, 0x40 }, { 0x79, 0x14, 0x51, 0x45, 0xE4, 0x91, 0x45, 0x10, 0x00 }, + { 0x39, 0x14, 0x48, 0x10, 0x20, 0x51, 0x44, 0xE0, 0x00 }, { 0x7C, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x40, 0x00 }, { 0x45, 0x14, 0x51, 0x45, 0x14, 0x51, 0x44, 0xE0, 0x00 }, + { 0x45, 0x14, 0x51, 0x28, 0xA2, 0x84, 0x10, 0x40, 0x00 }, { 0x55, 0x55, 0x55, 0x55, 0x55, 0x4A, 0x28, 0xA0, 0x00 }, { 0x45, 0x12, 0x8A, 0x10, 0x42, 0x8A, 0x45, 0x10, 0x00 }, + { 0x45, 0x14, 0x4A, 0x28, 0x41, 0x04, 0x10, 0x40, 0x00 }, { 0x7C, 0x10, 0x82, 0x10, 0x42, 0x08, 0x41, 0xF0, 0x00 }, { 0x30, 0x82, 0x08, 0x20, 0x82, 0x08, 0x20, 0x82, 0x0C }, + { 0x55, 0x55, 0x7F, 0x55, 0x55, 0x4A, 0x28, 0xA0, 0x00 }, { 0x30, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x41, 0x0C }, { 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xC0 }, { 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x0C, 0x48, 0xE4, 0x92, 0x48, 0xD0, 0x00 }, + { 0x41, 0x04, 0x1E, 0x45, 0x14, 0x51, 0x45, 0xE0, 0x00 }, { 0x00, 0x00, 0x0E, 0x45, 0x04, 0x10, 0x44, 0xE0, 0x00 }, { 0x04, 0x10, 0x4F, 0x45, 0x14, 0x51, 0x44, 0xF0, 0x00 }, + { 0x00, 0x00, 0x0E, 0x45, 0x17, 0xD0, 0x44, 0xE0, 0x00 }, { 0x10, 0x82, 0x1C, 0x20, 0x82, 0x08, 0x20, 0x80, 0x00 }, { 0x00, 0x00, 0x0F, 0x45, 0x14, 0x4F, 0x05, 0x13, 0x80 }, + { 0x41, 0x04, 0x1E, 0x45, 0x14, 0x51, 0x45, 0x10, 0x00 }, { 0x10, 0x40, 0x04, 0x10, 0x41, 0x04, 0x10, 0x40, 0x00 }, { 0x10, 0x40, 0x04, 0x10, 0x41, 0x04, 0x10, 0x46, 0x00 }, + { 0x41, 0x04, 0x11, 0x49, 0x46, 0x14, 0x49, 0x10, 0x00 }, { 0x00, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x40, 0x00 }, { 0x00, 0x00, 0x1A, 0x55, 0x55, 0x55, 0x55, 0x50, 0x00 }, + { 0x00, 0x00, 0x1E, 0x45, 0x14, 0x51, 0x45, 0x10, 0x00 }, { 0x00, 0x00, 0x0E, 0x45, 0x14, 0x51, 0x44, 0xE0, 0x00 }, { 0x00, 0x00, 0x1E, 0x45, 0x14, 0x51, 0x79, 0x04, 0x00 }, + { 0x00, 0x00, 0x0F, 0x45, 0x14, 0x51, 0x3C, 0x10, 0x40 }, { 0x00, 0x00, 0x0B, 0x30, 0x82, 0x08, 0x20, 0x80, 0x00 }, { 0x00, 0x00, 0x0E, 0x45, 0x03, 0x81, 0x44, 0xE0, 0x00 }, + { 0x00, 0x82, 0x1E, 0x20, 0x82, 0x08, 0x20, 0x60, 0x00 }, { 0x00, 0x00, 0x11, 0x45, 0x14, 0x51, 0x44, 0xF0, 0x00 }, { 0x00, 0x00, 0x11, 0x45, 0x12, 0x8A, 0x10, 0x40, 0x00 }, + { 0x00, 0x00, 0x15, 0x55, 0x55, 0x4E, 0x28, 0xA0, 0x00 }, { 0x00, 0x00, 0x11, 0x44, 0xA1, 0x0A, 0x45, 0x10, 0x00 }, { 0x00, 0x00, 0x11, 0x45, 0x12, 0x8A, 0x10, 0x46, 0x00 }, + { 0x00, 0x00, 0x1F, 0x04, 0x21, 0x08, 0x41, 0xF0, 0x00 }, { 0x08, 0x41, 0x04, 0x11, 0x81, 0x04, 0x10, 0x41, 0x02 }, { 0x10, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x41, 0x04 }, + { 0x40, 0x82, 0x08, 0x20, 0x62, 0x08, 0x20, 0x82, 0x10 }, { 0x00, 0x00, 0x00, 0x00, 0xD4, 0x80, 0x00, 0x00, 0x00 }, { 0x01, 0xE4, 0x92, 0x49, 0x24, 0x92, 0x49, 0xE0, 0x00 }, + }; + + static const Uint16 TemperatureFont[18] = { 0x00, 0x02, 0x00, 0x53, 0x82, 0x44, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x04, 0x40, 0x38, 0x00, 0x00, 0x00 }; // ℃, A1C9 + static const Uint16 uiBitMask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + const Uint16* pFontData; + Uint16 uiFontIndex = 0; + Uint16 i, j; + Uint16 uiCharWidth; + Uint16 uiCh = ch; + + if (type == 0U) // Eng Char + { + uiCharWidth = (Uint16)TXT_ENG_WIDTH; + uiCh -= 0x20U; // font offset + uiCh = (uiCh > 95U) ? 0U : uiCh; + pFontData = EngFontTable[uiCh]; + } + else + { + uiCharWidth = (Uint16)TXT_ENG_WIDTH * 2U; + pFontData = TemperatureFont; + } + + CSetDrawRegion((x + (Uint16)TXT_ENG_WIDTH), (y + (Uint16)TXT_ENG_HEIGHT)); + + for(j = 0U; j < (Uint16)TXT_ENG_HEIGHT; j++) + { + for(i = 0U; i < uiCharWidth; i++) + { + if (((Uint8)pFontData[uiFontIndex / 8U] & uiBitMask[uiFontIndex % 8U]) != 0U) + { + CPutPixel((x + i), (y + j), OledOperValue.Color.TxtColor); + } + else + { + CPutPixel((x + i), (y + j), OledOperValue.Color.BgColor); + } + uiFontIndex++; + } + } +} + +static void CInitOledModule(void) +{ + GpioDataRegs.GPBSET.bit.GPIO37 = 1U; // GPIO_OLED_RESET + DELAY_USEC(2000); + GpioDataRegs.GPBCLEAR.bit.GPIO37 = 1U; // GPIO_OLED_RESET + DELAY_USEC(2000); + GpioDataRegs.GPBSET.bit.GPIO37 = 1U; // GPIO_OLED_RESET + DELAY_USEC(2000); + + COledWrite((Uint16)0xFD, (Uint16)MODE_COMMAND); // Command Lock + COledWrite((Uint16)0x12, (Uint16)MODE_COMMAND); // + COledWrite((Uint16)0xAE, (Uint16)MODE_COMMAND); // oled off + COledWrite((Uint16)0xA1, (Uint16)MODE_COMMAND); // 1U segment column address high to low + + COledWrite((Uint16)0xC8, (Uint16)MODE_COMMAND); // COM output scan from high to low + + COledWrite((Uint16)0x81, (Uint16)MODE_COMMAND); // 1U contrast + COledWrite((Uint16)0xFF, (Uint16)MODE_COMMAND); + + COledWrite((Uint16)0xAF, (Uint16)MODE_COMMAND); // oled on + + CInitOledStructure(); + OledOperValue.uiProgressValue = (Uint16)OLED_LOAD_PROGRESS_X + 1U; +} + +void CDisplayAntiNoiseRefresh(void) +{ + COledWrite((Uint16)0xFD, (Uint16)MODE_COMMAND); + COledWrite((Uint16)0x12, (Uint16)MODE_COMMAND); + + /* 화면 방향 및 스캔 방향 재설정 (뒤집힘 방지) */ + COledWrite((Uint16)0xA1, (Uint16)MODE_COMMAND); /* Segment Remap: Column Address high to low */ + COledWrite((Uint16)0xC8, (Uint16)MODE_COMMAND); /* COM Output Scan: high to low */ + + /* 명암비(Contrast) 재설정 */ + COledWrite((Uint16)0x81, (Uint16)MODE_COMMAND); + COledWrite((Uint16)0xFF, (Uint16)MODE_COMMAND); + + /* Display ON 유지 확인 (노이즈로 화면이 꺼졌을 경우) */ + COledWrite((Uint16)0xAF, (Uint16)MODE_COMMAND); +} + +static void COledWrite(Uint16 Data, Uint16 Command) +{ + if (Command == (Uint16)MODE_COMMAND) + { + CommandBus = Data; + } + else + { + DataBus = Data; + } +} + +static void CInitOledStructure(void) +{ + (void)memset(&OledOperValue, 0, sizeof(COledOperValue)); + + OledOperValue.uiResetAlarmAnswer = 1U; +} + +void CInitKeyOperValue(void) +{ + (void)memset(&KeyOperValue, 0, sizeof(CKeyOperValue)); +} + +static Uint16 CStrLen(const int8 *s) +{ + Uint16 uiLen = 0U; + + if (s != NULL) + { + while (s[uiLen] != ASCII_NULL) + { + uiLen++; + } + } + + return uiLen; +} +static void CStrncpy(int8 *pTarget, const int8 *pSource, Uint16 Size) +{ + Uint16 i; + Uint16 uiSafeLimit; + + uiSafeLimit = (Size >= TXT_MAX_LEN) ? (TXT_MAX_LEN - 1U) : Size; + + //for (i = 0U; i < uiSafeLimit; i++) + for (i = 0U; (i < uiSafeLimit) && (i < (TXT_MAX_LEN - 1U)); i++) + { + pTarget[i] = pSource[i]; + } + + pTarget[i] = ASCII_NULL; +} + +static void CStrncat(int8 *pTarget, const int8 *pSource, Uint16 Size) +{ + Uint16 i; + Uint16 uiTargetSize; + Uint16 uiRemainSpace; + Uint16 uiSafeLimit; + + uiTargetSize = 0U; + + if (pTarget != NULL) + { + /* 함수를 부르지 않고, 해당 위치에서 직접 널 문자를 찾을 때까지 카운트 (FUNCR 증가 없음) */ + while (pTarget[uiTargetSize] != ASCII_NULL) + { + uiTargetSize++; + } + } + + if (uiTargetSize < (Uint16)(TXT_MAX_LEN - 1U)) + { + uiRemainSpace = (Uint16)((Uint16)(TXT_MAX_LEN - 1U) - uiTargetSize); + + uiSafeLimit = (Size >= uiRemainSpace) ? uiRemainSpace : Size; + + for (i = 0U; (i < uiSafeLimit) && ((uiTargetSize + i) < (Uint16)(TXT_MAX_LEN - 1U)); i++) + { + pTarget[uiTargetSize + i] = pSource[i]; + } + + pTarget[uiTargetSize + i] = ASCII_NULL; + } +} + +static void CDecToString(int16 Data, int8 *Array, Uint16 ArrayLen) +{ + Uint16 uiSign = 0U; // 음수 여부 플래그 (1이면 음수) + Uint16 uiSignLocate = 0U; // '-' 부호가 들어갈 배열 인덱스 위치 + Uint16 i; + Uint16 x = 0U; // cTmp에 추출된 숫자의 개수 (자릿수 카운트) + Uint16 y = 0U; // 최종 문자열 Array에 값을 써넣을 인덱스 + + int32 lData = (int32)Data * 10; + + // 추출된 각 자리의 숫자를 임시로 저장할 버퍼 (역순으로 저장됨) + int8 cTmp[6] = { ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL }; + + // 출력할 배열 전체를 공백(ASCII 32 = ' ')으로 초기화 + for (i = 0U; (i < ArrayLen) && (i < TXT_MAX_LEN); i++) + { + Array[i] = ASCII_BLANK; + } + + // 음수 판별 및 절대값(양수) 변환 + if (lData < 0) + { + uiSign = 1U; + lData = -lData; + } + + // 1의 자리부터 역순으로 숫자를 추출하여 ASCII 문자(ASCII 48 = '0')로 변환 + while ((lData > 0) && (x < 6U)) + { + cTmp[x] = (int8)((lData % 10) + 48); + x++; + lData /= 10; + } + + // 추출한 숫자를 최종 배열에 배치 (우측 정렬 적용) + if (x == 0U) + { + // 수치가 0인 경우, 지정된 고정 위치(y=3)에 '0' 표시 + y = 4U; + if (y < ArrayLen) + { + Array[y] = ASCII_0; + y++; + } + } + else + { + if (x > 0U) + { + // 앞서 '* 10'으로 부풀리며 추가되었던 최하위 숫자(0)를 버리기 위해 인덱스를 1 감소시킴 + x = (Uint16)(x - 1U); + } + + // 전체 폭(5칸 기준)에서 자릿수를 빼서, 문자가 쓰이기 시작할 시작 위치(y) 계산 + y = (x <= 5U) ? (Uint16)(5U - x) : 0U; + + // 부호('-')가 들어갈 자리 지정 (숫자가 시작되는 곳의 바로 앞 칸) + if (y < 1U) + { + uiSignLocate = 0U; + } + else if (y <= 5U) + { + uiSignLocate = (Uint16)(y - 1U); + } + else + { + uiSignLocate = 0U; + } + + // 계산된 부호 위치에 '-' 또는 공백 삽입 + if (uiSign == 1U) + { + if ((uiSignLocate > 0U) && (uiSignLocate < 6U) && (uiSignLocate < ArrayLen)) + { + Array[uiSignLocate] = ASCII_MINUS; // '-' + } + } + else + { + if (uiSignLocate < ArrayLen) + { + Array[uiSignLocate] = ASCII_BLANK; // ' ' + } + } + + while ((x > 0U) && (x < 6U) && (y < ArrayLen) && (y < TXT_MAX_LEN)) + { + Array[y] = cTmp[x]; + y++; + x = (Uint16)(x - 1U); // 인덱스 감소 + } + } + + // 문자열의 끝을 알리는 널(NULL, ASCII 0) 문자 삽입하여 문자열 완성 + if ((y < ArrayLen) && (y < TXT_MAX_LEN)) + { + Array[y] = ASCII_NULL; + } + else + { + if (ArrayLen > 0U) + { + Array[(Uint16)(ArrayLen - 1U)] = ASCII_NULL; + } + } +} + +static void CFloatToString(float32 Data, int8 *Array, Uint16 ArrayLen) +{ + int32 iTemp; // 음수 처리를 위해 signed int32 사용 (범위 확보) + Uint16 isNegative = 0U; // 음수 여부 플래그 + int8 cTmp[10]; // 임시 변환 버퍼 + Uint16 len = 0U; // 현재 변환된 문자 길이 + Uint16 i; + Uint16 startIdx; // 최종 배열에 복사할 시작 위치 + + for (i = 0U; (i < ArrayLen) && (i < TXT_MAX_LEN); i++) + { + Array[i] = ASCII_BLANK; // ' ' + } + + // 음수 확인 및 양수 변환 + if (Data < 0.0F) + { + isNegative = 1U; + Data = -Data; // 절대값으로 변환 + } + + // 소수점 1자리 정수로 변환 (예: 12.34 -> 123.4 -> 123) + iTemp = (int32)((float32)((Data * 10.0F) + 0.5F)); + + // 소수점 첫째 자리 추출 + cTmp[len++] = (int8)((int8)(iTemp % 10) + ASCII_0); // '0' + iTemp /= 10; + + // 소수점 문자 추가 + cTmp[len++] = ASCII_DOT; // '.' + + // 정수부 추출 + if (iTemp == 0) + { + cTmp[len++] = ASCII_0; // 0.x 인 경우 정수부 '0' 추가 + } + else + { + while (iTemp > 0) + { + cTmp[len++] = (int8)((int32)(iTemp % 10) + (int32)ASCII_0); + iTemp /= 10; + } + } + + // 부호 추가 + if (isNegative == 1U) + { + cTmp[len++] = ASCII_MINUS; // '-' + } + + // 최종 배열에 복사 (우측 정렬, 총 6자리 제한) + + // 만약 변환된 길이가 6자리를 넘으면 6자리로 자름 + if (len > 6U) + { + len = 6U; + } + + if (ArrayLen >= 7U) // ArrayLen 보호 + { + startIdx = 6U - len; + + for (i = 0U; i < len; i++) + { + Array[startIdx + i] = cTmp[len - 1U - i]; // cTmp는 역순이므로 len-1-i 로 접근 + } + + Array[6] = ASCII_NULL; + } +} + +void CInitializePage(void) +{ + CDrawLine((Uint16)(OledOperValue.uiProgressValue + 1U), (Uint16)(OLED_LOAD_PROGRESS_Y + 2U), (Uint16)(OledOperValue.uiProgressValue + 1U), (Uint16)(OLED_LOAD_PROGRESS_Y + 8U)); + if (OledOperValue.uiProgressValue < (Uint16)OLED_LOAD_PROGRESS_W - 3U) // -3은 프로그래스 바의 좌우측 1픽셀 공간 줌. + { + OledOperValue.uiProgressValue++; + } + else + { + OledOperValue.uiProgressDone = 1U; + } +} + +void CDisplayPostFail(void) +{ + CDrawCenteredLine(IDX_OLED_LINE_TITLE, "Power On Self-Test"); + CDrawCenteredLine(IDX_OLED_LINE_1, "(P:PASS F:FAIL)"); + + // LINE 2 + CDrawPostStatusLine(IDX_OLED_ROW_2, "EHT:", PowerOnCheckSensor[(Uint16)IDX_SENSOR_ENGINE_HEATER], "GPL:", PowerOnCheckSensor[(Uint16)IDX_SENSOR_GLOW_PLUG], "SOL:", PowerOnCheckSensor[(Uint16)IDX_SENSOR_SOLENOID]); + + // LINE 3 + CDrawPostStatusLine(IDX_OLED_ROW_3, "FUP:", PowerOnCheckSensor[(Uint16)IDX_SENSOR_FUEL_PUMP], "CLP:", PowerOnCheckSensor[(Uint16)IDX_SENSOR_COOLANT_PUMP], "FN1:", PowerOnCheckSensor[(Uint16)IDX_SENSOR_FAN1]); + + // LINE 4 + // Only FN2 + CDrawPostStatusLine(IDX_OLED_ROW_4, " FN2:", PowerOnCheckSensor[(Uint16)IDX_SENSOR_FAN2], NULL, 0, NULL, 0); +} +static void CLineFocus(Uint16 isFocus) +{ + if (isFocus == 1U) + { + OledOperValue.Color.TxtColor = 0U; + OledOperValue.Color.BgColor = 1U; + } + else + { + OledOperValue.Color.TxtColor = 1U; + OledOperValue.Color.BgColor = 0U; + } +} + +static void CMakeVersionString(int8 Buffer[], int16 v1, int16 v2, int16 v3) +{ + int16 verArray[3]; + int16 i, k; + int16 num; + int8 tempArr[6] = { ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL, ASCII_NULL }; + int16 tempIdx; + Uint16 currentIdx = 0U; // 함수 내부에서 0부터 시작 + + verArray[0] = v1; + verArray[1] = v2; + verArray[2] = v3; + + for (i = 0; i < 3; i++) + { + num = verArray[i]; + tempIdx = 0; + + // 숫자 -> 문자 변환 + if (num == 0) + { + tempArr[tempIdx++] = ASCII_0; // '0' + } + else + { + if (num < 0) { num = -num; } + while (num > 0) + { + tempArr[tempIdx++] = (int8)((num % 10) + ASCII_0); // '0' + num /= 10; + } + } + + // 2. 버퍼에 기록 + for (k = (tempIdx - 1); k >= 0; k--) + { + Buffer[currentIdx++] = tempArr[k]; + } + + // 3. 점(.) 찍기 (마지막 아닐 때만) + if (i < 2) + { + Buffer[currentIdx++] = ASCII_DOT; // '.' + } + } + + // ★ 문자열 끝 처리 (함수 안으로 이동됨) + Buffer[currentIdx] = ASCII_NULL; +} + +static void CHourToString(int32 num, int8 *str) +{ + Uint16 i = 0U; + Uint16 end; + Uint32 temp = (Uint32)num; // 입력받은 값 (예: 1234567 -> "12345.67") + + // 소수점 둘째 자리 (100분의 1) + str[i++] = (int8)((Uint32)((temp % 10U) + (Uint32)ASCII_0)); + temp = temp / 10U; + + // 소수점 첫째 자리 (10분의 1) + str[i++] = (int8)((Uint32)((temp % 10U) + (Uint32)ASCII_0)); + temp = temp / 10U; + + // 소수점 삽입 + str[i++] = ASCII_DOT; + + // 정수부 변환, 입력이 0이어도 최소 "0"은 찍히도록 do-while 사용 + do + { + str[i++] = (int8)((Uint32)((temp % 10U) + (Uint32)ASCII_0)); + temp = temp / 10U; + } + while (temp != 0U); + + // 공백 채우기 (자리수 맞춤), 정수5자리 + 점1자리 + 소수2자리 = 총 8자리 + while (i < 8U) + { + str[i++] = ASCII_BLANK; + } + + str[i] = ASCII_NULL; // 문자열 끝 + + end = i - 1U; + i = 0U; + + while (i < end) + { + int8 swapTemp = str[i]; + str[i] = str[end]; + str[end] = swapTemp; + i++; + end--; + } +} + +static const int8* CGetApuStateString(Uint16 idx) +{ + static const int8* const strTable[] = + { + "BOOT", // 0 + "INIT", // 1 + "POST", // 2 + "EMERGENCY", // 3 + "STANDBY", // 4 + "READY", // 5 + "PREHEAT", // 6 + "CRANKING", // 7 + "", // 8: RETRY (동적 처리) + "IDLE", // 9 + "GENERATING", // 10 + "COOLDOWN", // 11 + "STOPPING" // 12 + }; + + static int8 strBuffer[12]; + const int8* pRetVal = strTable[idx]; + + if (idx == (Uint16)IDX_APU_OPER_RETRY_CRANKING) + { + Uint16 count = GeneralOperValue.uiRetryCrankingCount + 1U; + + strBuffer[0] = ASCII_R; // 'R' + strBuffer[1] = ASCII_E; // 'E' + strBuffer[2] = ASCII_T; // 'T' + strBuffer[3] = ASCII_R; // 'R' + strBuffer[4] = ASCII_Y; // 'Y' + strBuffer[5] = ASCII_L_PAREN; // '(' + strBuffer[6] = (ASCII_0 + (int8)count); + strBuffer[7] = ASCII_R_PAREN; // ')' + strBuffer[8] = ASCII_NULL; //'\0' + + pRetVal = (const int8*)strBuffer; + } + + return pRetVal; +} + +static void CCopyStr(int8 *pTarget, const int8 *pSource) +{ + Uint16 i = 0U; + + if ((pTarget != NULL) && (pSource != NULL)) + { + while ((pSource[i] != ASCII_NULL) && (i < (Uint16)(TXT_MAX_LEN - 1U))) + { + pTarget[i] = pSource[i]; + i++; + } + pTarget[i] = ASCII_NULL; + } +} + +static void CAppendStr(int8 *pTarget, const int8 *pSource) +{ + Uint16 i = 0U; + Uint16 j = 0U; + + if ((pTarget != NULL) && (pSource != NULL)) + { + while ((pTarget[i] != ASCII_NULL) && (i < (Uint16)(TXT_MAX_LEN - 1U))) + { + i++; + } + + while ((pSource[j] != ASCII_NULL) && ((i + j) < (Uint16)(TXT_MAX_LEN - 1U))) + { + pTarget[i + j] = pSource[j]; + j++; + } + pTarget[i + j] = ASCII_NULL; + } +} + +static void CDrawLineText(Uint16 x, Uint16 y, const int8* str) +{ + CDrawStr(x, y, str); +} + +static void CDrawFaultStatusLine(Uint16 row, const int8* label1, Uint16 status1, const int8* label2, Uint16 status2) +{ + CDrawTwoStatusLine(row, label1, status1, label2, status2); +} + +static void CDrawSimpleLine(Uint16 row, const int8* label) +{ + CDrawPageLine(row, label, NULL, NULL); +} + +static void CDrawStatusTitle(const int8* title, const int8* pageNumStr) +{ + CDrawPageTitle(title, pageNumStr); +} + +static void CDrawSensorTitle(const int8* title, const int8* pageNumStr) +{ + CDrawPageTitle(title, pageNumStr); +} + +static void CDrawFaultTitle(const int8* title, const int8* pageNumStr) +{ + CDrawPageTitle(title, pageNumStr); +} diff --git a/Source/Display.h b/Source/Display.h new file mode 100644 index 0000000..3cdec6d --- /dev/null +++ b/Source/Display.h @@ -0,0 +1,156 @@ +#ifndef SOURCE_DISPLAY_H_ +#define SOURCE_DISPLAY_H_ + +#define ZONE6_DAT *(volatile Uint16*)0x00100001 +#define ZONE6_COM *(volatile Uint16*)0x00100000 + +#define OLED_WIDTH (128U) // ER-OLEDM024 Vertical Pixel 0~127 +#define OLED_HEIGHT (64U) +#define OLED_PAGE (8U) // ER-OLEDM024 Page 0~7 + +#define TXT_ENG_WIDTH (6U) +#define TXT_ENG_HEIGHT (12U) + +#define TXT_TYPE_ENG (0U) +#define TXT_TYPE_ETC (1U) + +#define TXT_MAX_LEN (22U) +#define TXT_LINE_LEN (5U) + +#define OLED_LOAD_PROGRESS_X (14U) +#define OLED_LOAD_PROGRESS_Y (52U) +#define OLED_LOAD_PROGRESS_W (114U) +#define OLED_LOAD_PROGRESS_H (10U) + +#define MODE_COMMAND (0U) +#define MODE_DATA (1U) + +#define DIR_UP (1U) +#define DIR_DOWN (0U) + +typedef signed char int8; +typedef unsigned char Uint8; + +typedef enum +{ + IDX_OLED_LINE_TITLE = 0U, + IDX_OLED_LINE_1 = 14U, + IDX_OLED_LINE_2 = 27U, + IDX_OLED_LINE_3 = 40U, + IDX_OLED_LINE_4 = 53U +} E_IDX_OLED_LINE; + +typedef enum +{ + IDX_OLED_ROW_0 = 0U, + IDX_OLED_ROW_1, + IDX_OLED_ROW_2, + IDX_OLED_ROW_3, + IDX_OLED_ROW_4 +} E_IDX_OLED_ROW; + +typedef enum +{ + IDX_OLED_PASS_DIGIT_1 = 0U, + IDX_OLED_PASS_DIGIT_2, + IDX_OLED_PASS_DIGIT_3, + IDX_OLED_PASS_DIGIT_4 +} E_IDX_OLED_PASS; + +typedef enum +{ + IDX_OLED_PAGE_APU1 = 0U, // 0 + IDX_OLED_PAGE_APU2, // 1 + IDX_OLED_PAGE_MENU1, // 2 + IDX_OLED_PAGE_MENU2, // 3 + IDX_OLED_PAGE_TEMP, // 4 + IDX_OLED_PAGE_SENSOR1, // 5 + IDX_OLED_PAGE_SENSOR2, // 6 + IDX_OLED_PAGE_SENSOR3, // 7 + IDX_OLED_PAGE_SENSOR4, // 8 + IDX_OLED_PAGE_WARNING1, // 9 + IDX_OLED_PAGE_WARNING2, // 10 + IDX_OLED_PAGE_FAULT1, // 11 + IDX_OLED_PAGE_FAULT2, // 12 + IDX_OLED_PAGE_FAULT3, // 13 + IDX_OLED_PAGE_FAULT4, // 14 + IDX_OLED_PAGE_FAULT5, // 15 + IDX_OLED_PAGE_FAULT6, // 16 + IDX_OLED_PAGE_FAULT7, // 17 + IDX_OLED_PAGE_RESET_ALARM, // 18 + IDX_OLED_PAGE_PASSWORD, // 19 + IDX_OLED_PAGE_MAINTENANCE, // 20 + IDX_OLED_PAGE_VERSION, // 21 + IDX_OLED_PAGE_KEY_TEST, // 21 + IDX_OLED_PAGE_SHUTDOWN, // 23 + IDX_OLED_PAGE_MAX +} E_IDX_OLED_PAGE; + +typedef enum +{ + IDX_OLED_MENU_APU = 0U, // 0 + IDX_OLED_MENU_TEMP, // 1 + IDX_OLED_MENU_SENSOR, // 2 + IDX_OLED_MENU_WARNING, // 3 +} E_IDX_OLED_MENU1; + +typedef enum +{ + IDX_OLED_MENU_FAULT = 0U, // 0 + IDX_OLED_MENU_RESET, // 1 + IDX_OLED_MENU_DEBUG // 2 +} E_IDX_OLED_MENU2; + +typedef enum +{ + IDX_OLED_LINE_FOCUS_1 = 0U, + IDX_OLED_LINE_FOCUS_2, + IDX_OLED_LINE_FOCUS_3, + IDX_OLED_LINE_FOCUS_4 +} E_IDX_OLED_LINE_FOCUS; + +typedef struct ClassPageHandler +{ + Uint16 uiPage; + void (*pAction) (void); // PageTable 참조 +} CPageHandler; + +typedef struct ClassOledOperValue +{ + Uint16 uiBuff[OLED_WIDTH][OLED_PAGE]; + Uint16 uiPageNum; + Uint16 uiOldPageNum; + Uint16 uiFocusLine; + Uint16 uiPrevFocusLine; + Uint16 uiFocusDigit; + Uint16 uiProgressValue; + Uint16 uiProgressDone; + Uint16 uiResetAlarmAnswer; + Uint16 uiResetHourAnswer; + int8 cStrBuff[TXT_LINE_LEN][TXT_MAX_LEN]; + int8 cAlignBuffer[TXT_MAX_LEN]; + struct + { + Uint16 TxtColor; + Uint16 BgColor; + } Color; + struct + { + Uint16 X; + Uint16 Y; + } Point; +} COledOperValue; + +void CInitXintf(void); +void CInitOled(void); +void COledReflash(Uint16 x, Uint16 y, Uint16 width, Uint16 height); +void CDisplayPostFail(void); +void CSetPage(Uint16 PageNum); +void CInitKeyOperValue(void); +void CInitializePage(void); +void COledBufferReset(void); +void CDisplayAntiNoiseRefresh(void); + +extern COledOperValue OledOperValue; + +#endif /* SOURCE_DISPLAY_H_ */ diff --git a/Source/Oper.c b/Source/Oper.c new file mode 100644 index 0000000..d66952c --- /dev/null +++ b/Source/Oper.c @@ -0,0 +1,647 @@ +/* ========================================================================= */ +/* 1. Includes */ +/* ========================================================================= */ +#include "main.h" + +/* ========================================================================= */ +/* 2. Local Macros & Constants (내부 전용 매크로 및 상수) */ +/* ========================================================================= */ +#define ENGINE_MAXIMUM_SPEED (2800U) +#define ENGINE_OPERATION_SPEED (2400U) +#define ENGINE_DIFF_SPEED (400U) // 2800 - 2400 + +// IDLE_SEQ_MOD +#define RPM_RAMP_START (1500U) +#define RPM_RAMP_END (2400U) +#define RPM_RAMP_RANGE (RPM_RAMP_END - RPM_RAMP_START) // 900 +#define TIME_RAMP_UP (TIME_1SEC * 3UL) // 3초 + +#define LED_OFF (0U) +#define LED_ON (1U) +#define LED_BLINK (2U) + +/* ========================================================================= */ +/* 3. Local Typedefs & Structures (내부 전용 사용자 정의 자료형) */ +/* ========================================================================= */ +// No Code + +/* ========================================================================= */ +/* 4. Internal Linkage Function Declarations (내부 동작용 Static 함수 선언) */ +/* ========================================================================= */ +static void CInitialStandby(void); +static void CEmergencyStop(void); +static void CProcessApuStateReady(void); +static void CProcessApuStatePreheat(void); +static void CProcessApuStateCranking(void); +static void CProcessApuStateRetryCranking(void); +static void CProcessApuStateEngineIdle(void); +static void CProcessApuStateGenerating(void); +static void CProcessApuStateCooldown(void); +static void CProcessApuStateStopping(void); +static void CProcessApuStateTransition(void); // 비상/시동/정지 전이 판별용 +static void CSetEngineActualRpm(Uint16 Rpm); +static float32 CGetGcuLoadPower(void); +static Uint16 CDynamicRpmControl(void); +static void CLedControl(Uint16 idx, Uint16 state); + +/* ========================================================================= */ +/* 5. Global Variables & Structure Initialization (전역 변수 및 구조체 초기화) */ +/* ========================================================================= */ +// No Code + +/* ========================================================================= */ +/* Function Definitions */ +/* ========================================================================= */ +static void CProcessApuStateReady(void) +{ + // 냉각수 펌프 및 냉각팬 시작 + CSetAuxCtrlPin(IDX_CS_COOLANT_PUMP, 1U); + CSetAuxCtrlPin(IDX_CS_FAN1, 1U); + CSetAuxCtrlPin(IDX_CS_FAN2, 1U); + + // ECU 동작 명령 송신, 2400 RPM 설정 + CSetEcuCommand((Uint16)IDX_ECU_CMD_START); + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_PREHEAT; +} + +static void CProcessApuStatePreheat(void) +{ + if (((Rx301.State >> 1U) & 0x07U) == (Uint16)IDX_ECU_STAT_STARTING) + { + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_CRANKING; + } + else + { + // PRE HEAT 상태가 60초 이상 지속 될 경우 알람처리 + if (CSoftWaitCountProcedure(SOFTTIMER_WAIT_PREHEAT, TIME_60SEC) == (Uint16)TIME_OVER) + { + // 알람처리를 할지 무기한 대기 할 지 검토 필요 + } + } +} + +static void CProcessApuStateCranking(void) +{ + CSetGcuCommand((Uint16)IDX_GCU_CMD_CRANKING); + + if (((Rx301.State >> 1U) & 0x07U) == (Uint16)IDX_ECU_STAT_IDLE) + { + CSetGcuCommand((Uint16)IDX_GCU_CMD_STOP_CRANKING); + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_ENGINE_IDLE; + GeneralOperValue.uiRetryCrankingCount = 0U; + CSoftWaitCountClear(SOFTTIMER_WAIT_CRANKING); + } + else + { + // 10초간 시동 시도 → 5초 동안 휴식 → 3회 반복 + if (CSoftWaitCountProcedure(SOFTTIMER_WAIT_CRANKING, TIME_10SEC) == (Uint16)TIME_OVER) + { + CSetGcuCommand((Uint16)IDX_GCU_CMD_STOP_CRANKING); + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_RETRY_CRANKING; + CSoftWaitCountClear(SOFTTIMER_WAIT_RETRY_CRANKING); + } + } +} + +static void CProcessApuStateRetryCranking(void) +{ + if (GeneralOperValue.uiRetryCrankingCount < 3U) + { + // 5초 대기 후 재시도 + if (CSoftWaitCountProcedure(SOFTTIMER_WAIT_RETRY_CRANKING, (TIME_1SEC * 5UL)) == (Uint16)TIME_OVER) + { + GeneralOperValue.uiRetryCrankingCount++; + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_CRANKING; + CSoftWaitCountClear(SOFTTIMER_WAIT_CRANKING); + } + } + else + { + ulDcuTotalAlarm = (1UL << (Uint32)(Uint16)IDX_FAULT_DCU_CRANKING_FAIL); + } +} + +static void CProcessApuStateEngineIdle(void) +{ +#if 0 // '0' - 기존 코드, '1' - IDLE_SEQ_MOD + if (((Rx301.State >> 1U) & 0x07U) == (Uint16)IDX_ECU_STAT_OPERATION) + { + // 보조엔진제어기의 상태가 OPERATION이고 보조엔진의 속도가 2300 RPM 이상 5초 유지 시 발전상태로 전환 + if (CGetEngineActualRpm() >= (ENGINE_OPERATION_SPEED - 100U)) // 2300 RPM + { + if (CSoftWaitCountProcedure(SOFTTIMER_WAIT_OPERATION, TIME_5SEC) == (Uint16)TIME_OVER) + { + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_GENERATING; + } + } + else + { + CSoftWaitCountClear(SOFTTIMER_WAIT_OPERATION); + } + } +#else + if (((Rx301.State >> 1U) & 0x07U) == (Uint16)IDX_ECU_STAT_OPERATION) + { + // ECU OPERATION 확인 즉시 발전 상태로 전환 (RPM Ramp는 CProcessApuStateGenerating에서 수행) + GeneralOperValue.ulRampStartClock = 0UL; + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_GENERATING; + } +#endif +} + +static void CProcessApuStateGenerating(void) +{ +#if 0 // '0' - 기존 코드, '1' - IDLE_SEQ_MOD + CSetGcuCommand((Uint16)IDX_GCU_CMD_GENERATING); // 발전 명령 송신 + GeneralOperValue.uiDynamicRPM = CDynamicRpmControl(); + CSetEngineActualRpm(GeneralOperValue.uiDynamicRPM); // RPM 가변 제어 시작 +#else + Uint32 ulElapsed; + Uint16 uiRampRpm; + + CSetGcuCommand((Uint16)IDX_GCU_CMD_GENERATING); + + if (GeneralOperValue.uiRampComplete == 1U) + { + GeneralOperValue.uiDynamicRPM = CDynamicRpmControl(); + CSetEngineActualRpm(GeneralOperValue.uiDynamicRPM); + } + else + { + if (GeneralOperValue.ulRampStartClock == 0UL) + { + GeneralOperValue.ulRampStartClock = CGetSoftClock(); + CSetEngineActualRpm(RPM_RAMP_START); + } + else + { + ulElapsed = (CGetSoftClock() + SYSTEM_10MIN_TIME - GeneralOperValue.ulRampStartClock) % SYSTEM_10MIN_TIME; + + if (ulElapsed < TIME_RAMP_UP) + { + uiRampRpm = (Uint16)(RPM_RAMP_START + (Uint16)(((Uint32)RPM_RAMP_RANGE * ulElapsed) / TIME_RAMP_UP)); + CSetEngineActualRpm(uiRampRpm); + } + else + { + GeneralOperValue.uiRampComplete = 1U; + GeneralOperValue.uiDynamicRPM = CDynamicRpmControl(); + CSetEngineActualRpm(GeneralOperValue.uiDynamicRPM); + } + } + } +#endif +} + +static void CProcessApuStateCooldown(void) +{ + Uint16 IsRpmZero; + Uint16 IsTimeout; + + // 쿨다운: 발전 중지 -> 엔진 IDLE로 변경 + CSetGcuCommand((Uint16)IDX_GCU_CMD_STOP); + CSetEcuCommand((Uint16)IDX_ECU_CMD_STOP); + + IsRpmZero = (CGetEngineActualRpm() == 0U) ? 1U : 0U; + IsTimeout = (CSoftWaitCountProcedure(SOFTTIMER_WAIT_AFTER_COOLDOWN, TIME_60SEC) == 1U) ? 1U : 0U; + + if ((IsRpmZero == 1U) || (IsTimeout == 1U)) + { + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_STOPPING; + } +} + +static void CProcessApuStateStopping(void) +{ + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_STOPPING) + { + CInitialStandby(); + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_STANDBY; + } +} + +static void CProcessApuStateTransition(void) +{ + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_EMERGENCY) + { + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_STANDBY; + CInitialStandby(); + } + + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_STANDBY) + { + if (KeyOperValue.KeyList.EngineStartStop == 1U) + { + GeneralOperValue.uiRetryCrankingCount = 0U; + if ((GeneralOperValue.Conection.Gcu == 1U) && (GeneralOperValue.Conection.Ecu == 1U)) + { + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_READY; + } + else + { + CommCheck.Gcu = (GeneralOperValue.Conection.Gcu == 0U) ? COMM_TIME_OUT_COUNT : 0U; + CommCheck.Ecu = (GeneralOperValue.Conection.Ecu == 0U) ? COMM_TIME_OUT_COUNT : 0U; + } + } + } + else + { + if ((GeneralOperValue.uiApuState >= (Uint16)IDX_APU_OPER_READY) && (GeneralOperValue.uiApuState <= (Uint16)IDX_APU_OPER_GENERATING)) + { + if (KeyOperValue.KeyList.EngineStartStop == 0U) + { + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_GENERATING) + { + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_COOLDOWN; + } + else + { + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_STOPPING; + } + } + } + } +} + +void CApuOperProcedure(void) +{ + // 입력 신호 Lo Active + Uint16 EngineHeaterSig = (GPIO_ENGINE_HEATER_ACTIVE() == false) ? 1U : 0U; + Uint16 FuelPumpSig = (GPIO_FUEL_PUMP_ACTIVE() == false) ? 1U : 0U; + Uint16 GlowPlugSig = (GPIO_GLOW_PLUG_ACTIVE() == false) ? 1U : 0U; + Uint16 SolenoidSig = (GPIO_SOLENOID_ACTIVE() == false) ? 1U : 0U; + Uint16 FailSafeSig = (GPIO_FAIL_SAFE_READ() == false) ? 1U : 0U; + + // 비상 상황 체크 + if ((GeneralOperValue.uiFaultOccured > 0U) || (KeyOperValue.KeyList.Emergency == 1U) || (FailSafeSig == 1U)) + { + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_EMERGENCY; + CEmergencyStop(); + } + else + { + // 외부 조작에 의한 상태 변경 확인 + CProcessApuStateTransition(); + + // ECU Aux Bypass 제어 + if (GeneralOperValue.uiApuState > (Uint16)IDX_APU_OPER_STANDBY) + { + CSetAuxCtrlPin(IDX_CS_ENG_HEATER, EngineHeaterSig); + CSetAuxCtrlPin(IDX_CS_GLOW_PLUG, GlowPlugSig); + CSetAuxCtrlPin(IDX_CS_SOLENOID, SolenoidSig); + CSetAuxCtrlPin(IDX_CS_FUEL_PUMP, FuelPumpSig); + } + + // 각 상태별 동작 수행 + switch (GeneralOperValue.uiApuState) + { + case (Uint16)IDX_APU_OPER_READY: + { + CProcessApuStateReady(); + break; + } + case (Uint16)IDX_APU_OPER_PREHEAT: + { + CProcessApuStatePreheat(); + break; + } + case (Uint16)IDX_APU_OPER_CRANKING: + { + CProcessApuStateCranking(); + break; + } + case (Uint16)IDX_APU_OPER_RETRY_CRANKING: + { + CProcessApuStateRetryCranking(); + break; + } + case (Uint16)IDX_APU_OPER_ENGINE_IDLE: + { + CProcessApuStateEngineIdle(); + break; + } + case (Uint16)IDX_APU_OPER_GENERATING: + { + CProcessApuStateGenerating(); + break; + } + case (Uint16)IDX_APU_OPER_COOLDOWN: + { + CProcessApuStateCooldown(); + break; + } + default: + { + CProcessApuStateStopping(); + break; + } + } + } +} + +static Uint16 CDynamicRpmControl(void) +{ + float32 TargetRPM; + Uint16 ReturnRpm; + + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_GENERATING) + { + // 0.0kW~17.0kW 부하량에 따라 목표 RPM 실시간 계산 + TargetRPM = (float32)ENGINE_OPERATION_SPEED + ((CGetGcuLoadPower() * 0.058823F) * (float32)ENGINE_DIFF_SPEED); // 0.058823 = 1/17kw + + ReturnRpm = (Uint16)((float32)(TargetRPM + 0.5F)); // 소수점 반올림 + } + else + { + // 발전 상태가 아닐 때는 기본 2400 RPM 반환 + ReturnRpm = ENGINE_OPERATION_SPEED; + } + + ReturnRpm = (ENGINE_MAXIMUM_SPEED > ReturnRpm) ? ReturnRpm : ENGINE_MAXIMUM_SPEED; + + return ReturnRpm; +} + +static void CInitialStandby(void) +{ + CSetGcuCommand((Uint16)IDX_GCU_CMD_STOP); + + CSetEcuCommand((Uint16)IDX_ECU_CMD_STOP); + + COffChipSelect(); + + CSoftWaitCountClear(SOFTTIMER_WAIT_CRANKING); + + CSoftWaitCountClear(SOFTTIMER_WAIT_RETRY_CRANKING); + + CSoftWaitCountClear(SOFTTIMER_WAIT_PREHEAT); + + CSoftWaitCountClear(SOFTTIMER_WAIT_PREHEAT); + + CSoftWaitCountClear(SOFTTIMER_WAIT_OPERATION); + + CSoftWaitCountClear(SOFTTIMER_WAIT_AFTER_COOLDOWN); + + GeneralOperValue.uiEmergency = 0U; + + GeneralOperValue.ulRampStartClock = 0UL; // IDLE_SEQ_MOD + + GeneralOperValue.uiRampComplete = 0U; // IDLE_SEQ_MOD + + GpioDataRegs.GPBCLEAR.bit.GPIO55 = 1U; // GPIO_FAULT_CMD +} + +static void CEmergencyStop(void) +{ + KeyOperValue.KeyList.EngineStartStop = 0U; // 비상정지 상황에서는 시동/정지 키 초기화 + + CSetGcuCommand((Uint16)IDX_GCU_CMD_STOP); + + CSetEcuCommand((Uint16)IDX_ECU_CMD_EMERGENCY); + + COffChipSelect(); + + CSoftWaitCountClear(SOFTTIMER_WAIT_CRANKING); + + CSoftWaitCountClear(SOFTTIMER_WAIT_RETRY_CRANKING); + + CSoftWaitCountClear(SOFTTIMER_WAIT_AFTER_COOLDOWN); + + GeneralOperValue.uiEmergency = 1U; + + GeneralOperValue.ulRampStartClock = 0UL; // IDLE_SEQ_MOD + + GeneralOperValue.uiRampComplete = 0U; // IDLE_SEQ_MOD + + GpioDataRegs.GPBSET.bit.GPIO55 = 1U; //GPIO_FAULT_CMD +} + +static void CSetEngineActualRpm(Uint16 Rpm) +{ + GeneralOperValue.EcuCommand.RpmSetPoint = Rpm; +} + +Uint16 CGetEngineActualRpm(void) +{ + return (Uint16)Rx320.ActualRpm; +} + +static float32 CGetGcuLoadPower(void) +{ + float32 power = ((float32)Rx220.Power * 0.1F); + + // 범위를 0.0 ~ 17.0 으로 제한 + if (power > 17.0F) + { + power = 17.0F; + } + else + { + if (power < 0.0F) + { + power = 0.0; + } + } + return power; +} + +Uint16 CGetGeneratorRpm(void) +{ + return Rx220.Rpm; +} + +void CSetGcuCommand(Uint16 Command) +{ + GeneralOperValue.GcuCommand.PlayCmd = Command; +} + +void CSetEcuCommand(Uint16 Command) +{ + if ((Command == (Uint16)IDX_ECU_CMD_STOP) || (Command == (Uint16)IDX_ECU_CMD_EMERGENCY)) + { + GeneralOperValue.EcuCommand.EngineStart = 0U; + GeneralOperValue.EcuCommand.EngineStop = 1U; + CSetEngineActualRpm(0U); + } + else + { + // [ECU_OPER_CMD_START] + GeneralOperValue.EcuCommand.EngineStart = 1U; + GeneralOperValue.EcuCommand.EngineStop = 0U; +#if 0 // RPM 테스트 + CSetEngineActualRpm(Rx400.SetRPM.PCAN_RPM); +#else + //CSetEngineActualRpm(2400U); + CSetEngineActualRpm(1500U); // Target Idle +#endif + } +} + +int16 CGetEngCoolantTemperature(void) +{ + return (int16) Rx321.CoolantTemperature - 40; // 온도 오프셋 -40도 +} + +void CDebugModeProcedure(void) +{ + if (GeneralOperValue.Maintenance.ManualCranking == 1U) + { + if (GeneralOperValue.uiFaultOccured == 0U) + { + // 알람이 없을 경우만 동작 하도록 함. + CSetGcuCommand((Uint16)IDX_GCU_CMD_CRANKING); + } + } + else + { + CSetGcuCommand((Uint16)IDX_GCU_CMD_STOP); + } + + if (GeneralOperValue.Maintenance.LampTest == 1U) + { + CLedControl(0U, 1U); + CLedControl(1U, 1U); + CLedControl(2U, 1U); + } + else + { + CLedControl(0U, 0U); + CLedControl(1U, 0U); + CLedControl(2U, 0U); + } + + if (GeneralOperValue.Maintenance.KeyTest == 1U) + { + Uint16 uiKeyUp = (GPIO_KEY_UP() == 0U) ? 1U : 0U; + Uint16 uiKeyDn = (GPIO_KEY_DOWN() == 0U) ? 1U : 0U; + + if ((uiKeyUp == 1U) && (uiKeyDn == 1U)) + { + GeneralOperValue.Maintenance.KeyTest = 0U; + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_MAINTENANCE; + } + } +} + +void CLedControlProcedure(void) +{ + static const CLedPattern APU_LED_TABLE[] = // LED 룩업 테이블 + { + // FAULT, OPER, STOP + {LED_OFF, LED_OFF, LED_ON }, // 0: BOOT + {LED_OFF, LED_OFF, LED_ON }, // 1: INITIAL + {LED_OFF, LED_OFF, LED_ON }, // 2: POST + {LED_ON, LED_OFF, LED_ON }, // 3: EMERGENCY + {LED_OFF, LED_OFF, LED_ON }, // 4: STANDBY + + // --- OPER 깜빡임 구간 (준비~예열) --- + {LED_OFF, LED_BLINK, LED_OFF }, // 5: READY + {LED_OFF, LED_BLINK, LED_OFF }, // 6: PREPARE_START + {LED_OFF, LED_BLINK, LED_OFF }, // 7: CRANKING + {LED_OFF, LED_BLINK, LED_OFF }, // 8: RETRY_CRANKING + {LED_OFF, LED_BLINK, LED_OFF }, // 9: ENGINE_WARM_UP + + {LED_OFF, LED_ON, LED_OFF }, // 10: GENERATING (정상 운전) + + // --- STOP 깜빡임 구간 (APU 정지 시) --- + {LED_OFF, LED_ON, LED_BLINK }, // 11: COOLDOWN (STOP 깜빡임, OPER는 켜둠) + {LED_OFF, LED_ON, LED_BLINK } // 12: STOPPING (COOLDWON이 순식간에 지나가기 때문에 점멸로 수정) + }; + + CLedPattern TargetLeds = {0, 0, 0}; + + Uint64 SoftClock = CGetSoftClock(); + Uint16 IsBlinkOn = ((SoftClock % 10000U) < 5000U) ? 1U : 0U; // 0.5s 점멸을 위함 + Uint16 WarningValue = 0U; + + TargetLeds = APU_LED_TABLE[GeneralOperValue.uiApuState]; + + // 발전상태에서 경고 발생시 FAULT LED 깜빡이도록 설정 + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_GENERATING) + { + WarningValue = ((((Uint16)Rx210.GcuWarning & (Uint16)MASK_LOW_NIBBLE) | ((Uint16)Rx310.EcuWarning & 0xFDU)) > 0U) ? 1U : 0U; + } + + // 비상정지 상태가 아닌 경우에만 경고비트에 점멸 대응 + if ((GeneralOperValue.uiApuState != (Uint16)IDX_APU_OPER_EMERGENCY) && (WarningValue == 1U)) + { + TargetLeds.Fault = (Uint16)LED_BLINK; + } + + // FAULT LED 제어 + if (TargetLeds.Fault == (Uint16)LED_BLINK) + { + CLedControl(0U, IsBlinkOn); + } + else + { + CLedControl(0U, TargetLeds.Fault); + } + + // OPERATION LED 제어 + if (TargetLeds.Operation == (Uint16)LED_BLINK) + { + CLedControl(1U, IsBlinkOn); + } + else + { + CLedControl(1U, TargetLeds.Operation); + } + + // STOP LED 제어 + if (TargetLeds.Stop == (Uint16)LED_BLINK) + { + CLedControl(2U, IsBlinkOn); + } + else + { + CLedControl(2U, TargetLeds.Stop); + } +} + +static void CLedControl(Uint16 idx, Uint16 state) +{ + /* + * idx + * 0 : FAULT LED + * 1 : OPER LED + * 2 : STOP LED + */ + + if (idx == 0U) + { + // GPIO_CPU_LED_FAULT + if (state == 0U) + { + GpioDataRegs.GPACLEAR.bit.GPIO14 = 1U; + } + else + { + GpioDataRegs.GPASET.bit.GPIO14 = 1U; + } + } + else if (idx == 1U) + { + // GPIO_CPU_LED_OPERATION + if (state == 0U) + { + GpioDataRegs.GPACLEAR.bit.GPIO13 = 1U; + } + else + { + GpioDataRegs.GPASET.bit.GPIO13 = 1U; + } + } + else + { + // GPIO_CPU_LED_STOP + if (state == 0U) + { + GpioDataRegs.GPACLEAR.bit.GPIO12 = 1U; + } + else + { + GpioDataRegs.GPASET.bit.GPIO12 = 1U; + } + } +} diff --git a/Source/Oper.h b/Source/Oper.h new file mode 100644 index 0000000..b77e1da --- /dev/null +++ b/Source/Oper.h @@ -0,0 +1,63 @@ +#ifndef SOURCE_OPER_H_ +#define SOURCE_OPER_H_ + +typedef struct ClassLedPattern +{ + Uint16 Fault; + Uint16 Operation; + Uint16 Stop; +} CLedPattern; + +typedef enum +{ + IDX_APU_OPER_BOOT = 0U, // 0 부팅 + IDX_APU_OPER_INITIAL, // 1 하드웨어 초기화 + IDX_APU_OPER_POST, // 2 자체 진단 + IDX_APU_OPER_EMERGENCY, // 3 비상 정지 + IDX_APU_OPER_STANDBY, // 4 대기 + IDX_APU_OPER_READY, // 5 준비 상태 + IDX_APU_OPER_PREHEAT, // 6 연료 펌프 구동 및 예열 + IDX_APU_OPER_CRANKING, // 7 스타터 모터 구동 + IDX_APU_OPER_RETRY_CRANKING, // 8 시동 재시도 + IDX_APU_OPER_ENGINE_IDLE, // 9 시동 성공 후 RPM 안정화 대기 + IDX_APU_OPER_GENERATING, // 10 발전 시작 + IDX_APU_OPER_COOLDOWN, // 11 엔진 냉각(정지 시) + IDX_APU_OPER_STOPPING, // 12 연료 펌프 및 솔레노이드, 냉각팬 차단 +} E_IDX_APU_OPER; + +typedef enum +{ + IDX_ECU_STAT_STANDBY = 0U, // 0 + IDX_ECU_STAT_STARTING, // 1 + IDX_ECU_STAT_IDLE, // 2 + IDX_ECU_STAT_OPERATION, // 3 + IDX_ECU_STAT_DERATING, // 4 + IDX_ECU_STAT_COOLDOWN, // 5 + IDX_ECU_STAT_STOP // 6 +} E_IDX_ECU_STAT; + +typedef enum +{ + IDX_GCU_CMD_STOP = 0U, // 0 + IDX_GCU_CMD_CRANKING, // 1 + IDX_GCU_CMD_STOP_CRANKING, // 2 + IDX_GCU_CMD_GENERATING // 3 +} E_IDX_GCU_CMD; + +typedef enum +{ + IDX_ECU_CMD_STOP = 0U, // 0 + IDX_ECU_CMD_START, // 1 + IDX_ECU_CMD_EMERGENCY // 2 +} E_IDX_ECU_CMD; + +void CApuOperProcedure(void); +void CDebugModeProcedure(void); +void CLedControlProcedure(void); +int16 CGetEngCoolantTemperature(void); +Uint16 CGetGeneratorRpm(void); +Uint16 CGetEngineActualRpm(void); +void CSetGcuCommand(Uint16 Command); +void CSetEcuCommand(Uint16 Command); + +#endif /* SOURCE_OPER_H_ */ diff --git a/Source/State.c b/Source/State.c new file mode 100644 index 0000000..01097bd --- /dev/null +++ b/Source/State.c @@ -0,0 +1,1296 @@ +/* ========================================================================= */ +/* 1. Includes */ +/* ========================================================================= */ +#include "main.h" + +/* ========================================================================= */ +/* 2. Local Macros & Constants (내부 전용 매크로 및 상수) */ +/* ========================================================================= */ +#define ALARM_UNDER_CHECK (0U) +#define ALARM_OVER_CHECK (1U) + +#define LONG_KEY_TIME (500UL) +#define KEY_POWER_MASK (0x0001UL) // 0x0001 - LOCAL POWER +#define KEY_START_MASK (0x01A0UL) // 0x0100 - REMOTE STOP, 0x0080 - REMOTE START, 0x0020 - LOCAL START/STOP + +/* ========================================================================= */ +/* 3. Local Typedefs & Structures (내부 전용 사용자 정의 자료형) */ +/* ========================================================================= */ +static CAlarmOperValue AlarmOperValue[(Uint16)IDX_FAULT_DCU_MAX]; + +/* ========================================================================= */ +/* 4. Internal Linkage Function Declarations (내부 동작용 Static 함수 선언) */ +/* ========================================================================= */ +static void CInitAlarmOperValue(void); +static void CKeyMainPowerProcess(void); +static void CProcessArrowUpFocusChange(void); +static void CProcessArrowUpPageChange(void); +static void CKeyArrowUpProcess(void); +static void CKeyArrowDownProcess(void); +static void CProcessArrowDownPageChange(void); +static void CProcessArrowDownFocusChange(void); +static void CProcessEnterMenu1(void); +static void CProcessEnterMenu2(void); +static void CProcessEnterPassword(void); +static void CProcessEnterMaintenance(void); +static void CKeyEnterProcess(void); +static void CKeyMenuProcess(void); +static void CKeyEngineStartStopProcess(void); +static void CKeyRemoteEngineStartProcess(void); +static void CKeyRemoteEngineStopProcess(void); +static void CKeyEmergencyProcess(void); +static void CKeyBattleModeProcess(void); +static void CInitAdcStructure(void); +static Uint16 CAlarmCheck(E_IDX_DCU_FAULT Idx, float32 fValue, Uint16 uiCheckDetectTime, Uint16 uiCheckType); +static void CApuSystemAlarmCheck(void); +static Uint32 CGetKey(void); +static void CKeyCheck(Uint32 ulChangeKey, Uint32 ulKeyRead); +static void CMoveFocusLine(Uint16 maxLines, Uint16 direction); +static void CChangePasswordDigit(Uint16 direction); +static inline void CCalcAdcSum(CAdcCalcValue *AdcBuff); + +/* ========================================================================= */ +/* 5. Global Variables & Structure Initialization (전역 변수 및 구조체 초기화) */ +/* ========================================================================= */ +CAdcCalcValue Adc_EngineHeater_V; +CAdcCalcValue Adc_GlowPlug_V; +CAdcCalcValue Adc_Solenoid_V; +CAdcCalcValue Adc_FuelPump_V; +CAdcCalcValue Adc_CoolantPump_V; +CAdcCalcValue Adc_Fan1_V; +CAdcCalcValue Adc_Fan2_V; + +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; + +CKeyOperValue KeyOperValue; + +Uint32 ulDcuTotalAlarm = 0UL; +Uint32 ulGcuTotalAlarm = 0UL; +Uint32 ulEcuTotalAlarm = 0UL; + +/* ========================================================================= */ +/* Function Definitions */ +/* ========================================================================= */ +interrupt void CAdcInterrupt(void) +{ + Uint16 uiTemp[(Uint16)IDX_ADC_MAX]; + Uint16 i; + + const volatile Uint16 *pAdcAddress = &AdcRegs.ADCRESULT0; + + for (i = 0U; i < (Uint16)IDX_ADC_MAX; i++) + { + uiTemp[i] = (*(pAdcAddress++) >> 4); + } + + Adc_EngineHeater_V.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_ENGINE_HEATER_V]; + Adc_GlowPlug_V.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_GLOW_PLUG_V]; + Adc_Solenoid_V.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_SOLENOID_V]; + Adc_FuelPump_V.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_FUEL_PUMP_V]; + Adc_CoolantPump_V.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_COOLANT_PUMP_V]; + Adc_Fan1_V.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_FAN1_V]; + Adc_Fan2_V.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_FAN2_V]; + + Adc_EngineHeater_I.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_ENGINE_HEATER_I]; + Adc_GlowPlug_I.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_GLOW_PLUG_I]; + Adc_Solenoid_I.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_SOLENOID_I]; + Adc_FuelPump_I.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_FUEL_PUMP_I]; + Adc_CoolantPump_I.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_COOLANT_PUMP_I]; + Adc_Fan1_I.iAdcValue = (int16) uiTemp[(Uint16)IDX_ADC_FAN1_I]; + Adc_Fan2_I.iAdcValue = (int16) uiTemp[(Uint16)IDX_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; + } + } + else + { + CCalcAdcSum(&Adc_EngineHeater_V); + CCalcAdcSum(&Adc_GlowPlug_V); + CCalcAdcSum(&Adc_Solenoid_V); + CCalcAdcSum(&Adc_FuelPump_V); + CCalcAdcSum(&Adc_CoolantPump_V); + CCalcAdcSum(&Adc_Fan1_V); + CCalcAdcSum(&Adc_Fan2_V); + + 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); + } + + // 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) +{ + static Uint64 PrevFaultValue = 0U; + static Uint32 PrevWarningValue = 0U; + + // FaultValue는 랫치상태 + Uint64 FaultValue = ((Uint64)ulDcuTotalAlarm & MASK_26BIT) | (((Uint64)ulGcuTotalAlarm & MASK_WORD) << 26UL) | (((Uint64)ulEcuTotalAlarm & MASK_6BIT) << 42UL); + + // WarningValue는 경고가 사라질수 있기 때문에 랫치 하지 않음 + Uint32 WarningValue = (((Uint32)Rx210.GcuWarning & (Uint32)MASK_LOW_NIBBLE) | (((Uint32)Rx310.EcuWarning & 0xFDU) << 4U)); + + // 0 → 1로 바뀐 비트만 추출 + Uint64 NewFault = FaultValue & (~PrevFaultValue); + Uint32 NewWarning = WarningValue & (~PrevWarningValue); + + // 현재 값 저장 + PrevFaultValue = FaultValue; + PrevWarningValue = WarningValue; + + Uint16 i; + Uint16 UpdatePage = 0U; // 0: 유지, 1: Fault 이동, 2: Warning 이동 + Uint64 TargetFault = 0U; // 검색할 대상 변수 (Fault) + Uint32 TargetWarning = 0U; // 검색할 대상 변수 (Warning) + + if (NewFault > 0ULL) + { + TargetFault = NewFault; // 새로 뜬 Fault만 검색 대상 + UpdatePage = 1U; + } + else + { + if (NewWarning > 0U) + { + TargetWarning = NewWarning; // 새로 뜬 Warning만 검색 대상 + UpdatePage = 2U; + } + } + + // [페이지 이동 로직] + if (UpdatePage > 0U) + { + /* Fault 처리 */ + if (UpdatePage == 1U) + { + for (i = 0U; i < 64U; i++) + { + /* 비트 추출 시 Essential Type 일치를 위해 1ULL(또는 명시적 캐스팅) 사용 */ + if (((TargetFault >> i) & 1ULL) == 1ULL) + { + if (i < (Uint16)IDX_FAULT_DCU_MAX) + { + Uint16 uiCalcPage = (Uint16)((i / 8U) + (Uint16)IDX_OLED_PAGE_FAULT1); + OledOperValue.uiPageNum = (uiCalcPage <= (Uint16)IDX_OLED_PAGE_FAULT4) ? uiCalcPage : (Uint16)IDX_OLED_PAGE_FAULT4; + } + else + { + Uint16 uiCalcPage = (Uint16)((Uint16)IDX_OLED_PAGE_FAULT5 + ((i - (Uint16)IDX_FAULT_DCU_MAX) / 8U)); + OledOperValue.uiPageNum = (uiCalcPage <= (Uint16)IDX_OLED_PAGE_FAULT7) ? uiCalcPage : (Uint16)IDX_OLED_PAGE_FAULT7; + } + break; /* 가장 낮은 비트(새로 발생한 것) 찾으면 즉시 이동 */ + } + } + } + else + { + /* 발전상태에서만 경고 처리, 고장 발생시 경고 페이지 이동 무시 */ + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_GENERATING) + { + if ((NewWarning > 0U) && (FaultValue == 0U)) + { + for (i = 0U; i < 16U; i++) + { + if (((TargetWarning >> i) & 1U) == 1U) + { + Uint16 uiCalcPage = (Uint16)((i / 9U) + (Uint16)IDX_OLED_PAGE_WARNING1); + OledOperValue.uiPageNum = (uiCalcPage <= (Uint16)IDX_OLED_PAGE_WARNING2) ? uiCalcPage : (Uint16)IDX_OLED_PAGE_WARNING2; + break; + } + } + } + } + } + } +} + +void CAlarmProcedure(void) +{ + int16 iDiffRpm = 0; + + /* 통신 상태 업데이트 */ + CommCheck.CarComputer = ((GeneralOperValue.Conection.CarComputer == 1U) && (CommCheck.CarComputer <= COMM_TIME_OUT_COUNT)) ? (CommCheck.CarComputer + 1U) : CommCheck.CarComputer; + CommCheck.Gcu = ((GeneralOperValue.Conection.Gcu == 1U) && (CommCheck.Gcu <= COMM_TIME_OUT_COUNT)) ? (CommCheck.Gcu + 1U) : CommCheck.Gcu; + CommCheck.Ecu = ((GeneralOperValue.Conection.Ecu == 1U) && (CommCheck.Ecu <= COMM_TIME_OUT_COUNT)) ? (CommCheck.Ecu + 1U) : CommCheck.Ecu; + + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_EMERGENCY) + { + /* Emergency 상태 시 처리 로직 (필요 시 작성) */ + } + else + { + if (GeneralOperValue.uiApuState > (Uint16)IDX_APU_OPER_EMERGENCY) + { + /* 통신 타임아웃 체크 및 비트 업데이트 */ + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_CAR_COMM, CAlarmCheck(IDX_FAULT_DCU_CAR_COMM, (float32)CommCheck.CarComputer, AlarmOperValue[(Uint16)IDX_FAULT_DCU_CAR_COMM].uiCheckTime, ALARM_OVER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_GCU_COMM, CAlarmCheck(IDX_FAULT_DCU_GCU_COMM, (float32)CommCheck.Gcu, AlarmOperValue[(Uint16)IDX_FAULT_DCU_GCU_COMM].uiCheckTime, ALARM_OVER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_ECU_COMM, CAlarmCheck(IDX_FAULT_DCU_ECU_COMM, (float32)CommCheck.Ecu, AlarmOperValue[(Uint16)IDX_FAULT_DCU_ECU_COMM].uiCheckTime, ALARM_OVER_CHECK)); + + /* 타임아웃 발생 시 연결 비트 클리어 */ + GeneralOperValue.Conection.CarComputer = (CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_CAR_COMM) == 1U) ? 0U : GeneralOperValue.Conection.CarComputer; + GeneralOperValue.Conection.Gcu = (CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_GCU_COMM) == 1U) ? 0U : GeneralOperValue.Conection.Gcu; + GeneralOperValue.Conection.Ecu = (CIsBitSet(ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_ECU_COMM) == 1U) ? 0U : GeneralOperValue.Conection.Ecu; + + /* 과전류 알람 체크 */ + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OC, CAlarmCheck(IDX_FAULT_DCU_ENGINE_HEAT_OC, Adc_EngineHeater_I.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OC].uiCheckTime, ALARM_OVER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_GLOW_PLUG_OC, CAlarmCheck(IDX_FAULT_DCU_GLOW_PLUG_OC, Adc_GlowPlug_I.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_OC].uiCheckTime, ALARM_OVER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_SOLENOID_OC, CAlarmCheck(IDX_FAULT_DCU_SOLENOID_OC, Adc_Solenoid_I.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_OC].uiCheckTime, ALARM_OVER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FUEL_PUMP_OC, CAlarmCheck(IDX_FAULT_DCU_FUEL_PUMP_OC, Adc_FuelPump_I.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_OC].uiCheckTime, ALARM_OVER_CHECK)); +#if 0 // IDLE_SEQ_MOD + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OC, CAlarmCheck(IDX_FAULT_DCU_COOLANT_PUMP_OC, Adc_CoolantPump_I.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OC].uiCheckTime, ALARM_OVER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN1_OC, CAlarmCheck(IDX_FAULT_DCU_FAN1_OC, Adc_Fan1_I.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_OC].uiCheckTime, ALARM_OVER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN2_OC, CAlarmCheck(IDX_FAULT_DCU_FAN2_OC, Adc_Fan2_I.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_OC].uiCheckTime, ALARM_OVER_CHECK)); +#endif + /* 개별 전압 알람 체크 */ + /* Engine Heater */ + if (ENGINE_HEATER_OUT() == 1U) + { + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_ENGINE_HEAT_UV, CAlarmCheck(IDX_FAULT_DCU_ENGINE_HEAT_UV, Adc_EngineHeater_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_UV].uiCheckTime, ALARM_UNDER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OV, CAlarmCheck(IDX_FAULT_DCU_ENGINE_HEAT_OV, Adc_EngineHeater_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OV].uiCheckTime, ALARM_OVER_CHECK)); + } + else + { + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_UV].uiCheckCount = 0U; + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OV].uiCheckCount = 0U; + } + + /* Glow Plug */ + if (GLOW_PLUG_OUT() == 1U) + { + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_GLOW_PLUG_UV, CAlarmCheck(IDX_FAULT_DCU_GLOW_PLUG_UV, Adc_GlowPlug_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_UV].uiCheckTime, ALARM_UNDER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_GLOW_PLUG_OV, CAlarmCheck(IDX_FAULT_DCU_GLOW_PLUG_OV, Adc_GlowPlug_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_OV].uiCheckTime, ALARM_OVER_CHECK)); + } + else + { + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_UV].uiCheckCount = 0U; + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_OV].uiCheckCount = 0U; + } + + /* Solenoid */ + if (SOLENOID_OUT() == 1U) + { + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_SOLENOID_UV, CAlarmCheck(IDX_FAULT_DCU_SOLENOID_UV, Adc_Solenoid_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_UV].uiCheckTime, ALARM_UNDER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_SOLENOID_OV, CAlarmCheck(IDX_FAULT_DCU_SOLENOID_OV, Adc_Solenoid_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_OV].uiCheckTime, ALARM_OVER_CHECK)); + } + else + { + AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_UV].uiCheckCount = 0U; + AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_OV].uiCheckCount = 0U; + } + + /* Fuel Pump */ + if (FUEL_PUMP_OUT() == 1U) + { + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FUEL_PUMP_UV, CAlarmCheck(IDX_FAULT_DCU_FUEL_PUMP_UV, Adc_FuelPump_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_UV].uiCheckTime, ALARM_UNDER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FUEL_PUMP_OV, CAlarmCheck(IDX_FAULT_DCU_FUEL_PUMP_OV, Adc_FuelPump_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_OV].uiCheckTime, ALARM_OVER_CHECK)); + } + else + { + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_UV].uiCheckCount = 0U; + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_OV].uiCheckCount = 0U; + } + + /* Coolant Pump */ + if (COOLANT_PUMP_OUT() == 1U) + { + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_COOLANT_PUMP_UV, CAlarmCheck(IDX_FAULT_DCU_COOLANT_PUMP_UV, Adc_CoolantPump_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_UV].uiCheckTime, ALARM_UNDER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OV, CAlarmCheck(IDX_FAULT_DCU_COOLANT_PUMP_OV, Adc_CoolantPump_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OV].uiCheckTime, ALARM_OVER_CHECK)); + } + else + { + AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_UV].uiCheckCount = 0U; + AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OV].uiCheckCount = 0U; + } + + /* Fan1 */ + if (FAN1_OUT() == 1U) + { + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN1_UV, CAlarmCheck(IDX_FAULT_DCU_FAN1_UV, Adc_Fan1_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_UV].uiCheckTime, ALARM_UNDER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN1_OV, CAlarmCheck(IDX_FAULT_DCU_FAN1_OV, Adc_Fan1_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_OV].uiCheckTime, ALARM_OVER_CHECK)); + } + else + { + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_UV].uiCheckCount = 0U; + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_OV].uiCheckCount = 0U; + } + + /* Fan2 */ + if (FAN2_OUT() == 1U) + { + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN2_UV, CAlarmCheck(IDX_FAULT_DCU_FAN2_UV, Adc_Fan2_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_UV].uiCheckTime, ALARM_UNDER_CHECK)); + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_FAN2_OV, CAlarmCheck(IDX_FAULT_DCU_FAN2_OV, Adc_Fan2_V.fLpfValue, AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_OV].uiCheckTime, ALARM_OVER_CHECK)); + } + else + { + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_UV].uiCheckCount = 0U; + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_OV].uiCheckCount = 0U; + } + + /* RPM Error 체크 */ + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_GENERATING) + { + if ((GeneralOperValue.Conection.Gcu == 1U) && (GeneralOperValue.Conection.Ecu == 1U)) + { + iDiffRpm = (int16)CGetGeneratorRpm() - (int16)CGetEngineActualRpm(); + iDiffRpm = (iDiffRpm < 0) ? -iDiffRpm : iDiffRpm; + CUpdateFault(&ulDcuTotalAlarm, (Uint16)IDX_FAULT_DCU_RPM_ERR, CAlarmCheck(IDX_FAULT_DCU_RPM_ERR, (float32)iDiffRpm, AlarmOperValue[(Uint16)IDX_FAULT_DCU_RPM_ERR].uiCheckTime, ALARM_OVER_CHECK)); + } + } + } + } + + /* 알람 리셋 처리 */ + if (GeneralOperValue.uiAlarmReset == 1U) + { + CInitAlarmOperValue(); + ulDcuTotalAlarm = 0UL; /* 전체 비트 클리어 */ + + if (CSoftWaitCountProcedure(SOFTTIMER_WAIT_ALARM_RESET, TIME_1SEC) == (Uint16)TIME_OVER) + { + GeneralOperValue.uiAlarmReset = 0U; + } + } + + CApuSystemAlarmCheck(); +} + +static Uint16 CAlarmCheck(E_IDX_DCU_FAULT 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 void CApuSystemAlarmCheck(void) +{ + Uint32 TotalFault = 0UL; + Uint16 GcuCurrentFault; + Uint16 EcuCurrentFault; + + /* 각 바이트를 Uint16으로 먼저 승격시킨 후 연산 수행 */ + + GcuCurrentFault = Rx210.GcuFault; + EcuCurrentFault = Rx310.EcuFault; + + ulGcuTotalAlarm = ulGcuTotalAlarm | (Uint32)GcuCurrentFault; + ulEcuTotalAlarm = ulEcuTotalAlarm | (Uint32)EcuCurrentFault; + + TotalFault = (Uint32)ulDcuTotalAlarm | (Uint32)ulGcuTotalAlarm | (Uint32)ulEcuTotalAlarm; + + if (TotalFault > 0U) + { + GeneralOperValue.uiFaultOccured = 1U; + } + else + { + GeneralOperValue.uiFaultOccured = 0U; + } +} + +static void CInitAlarmOperValue(void) +{ + Uint16 i; + + for (i = 0U; i < (Uint16)IDX_FAULT_DCU_MAX; i++) + { + (void)memset((void*)&AlarmOperValue[i], 0, sizeof(CAlarmOperValue)); + } + + (void)memset(&CommCheck, 0, sizeof(CCommCheck)); + + // 체계/GCU/ECU 통신 및 신호 단선은 다른 함수에서 처리 + /* + * Alarm Check Standard Value + * Alarm Count per 1mS + */ + AlarmOperValue[(Uint16)IDX_FAULT_DCU_CAR_COMM].fCheckLimit = (float32)(COMM_TIME_OUT_COUNT); // 3 Seconds + AlarmOperValue[(Uint16)IDX_FAULT_DCU_CAR_COMM].uiCheckTime = 1U; // 시간을 감지 하므로 즉시 검출 + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GCU_COMM].fCheckLimit = (float32)(COMM_TIME_OUT_COUNT); // 3 Seconds + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GCU_COMM].uiCheckTime = 1U; // 시간을 감지 하므로 즉시 검출 + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ECU_COMM].fCheckLimit = (float32)(COMM_TIME_OUT_COUNT); // 3 Seconds + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ECU_COMM].uiCheckTime = 1U; // 시간을 감지 하므로 즉시 검출 + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_RPM_ERR].fCheckLimit = 300.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_RPM_ERR].uiCheckTime = 10U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OC].fCheckLimit = 30.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OC].uiCheckTime = 100U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_OC].fCheckLimit = 30.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_OC].uiCheckTime = 100U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_OC].fCheckLimit = 10.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_OC].uiCheckTime = 100U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_OC].fCheckLimit = 5.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_OC].uiCheckTime = 100U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OC].fCheckLimit = 7.5F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OC].uiCheckTime = 100U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_OC].fCheckLimit = 35.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_OC].uiCheckTime = 100U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_OC].fCheckLimit = 35.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_OC].uiCheckTime = 100U; // Value + + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_UV].fCheckLimit = 18.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_UV].uiCheckTime = 1000U; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OV].fCheckLimit = 31.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_ENGINE_HEAT_OV].uiCheckTime = 1000U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_UV].fCheckLimit = 18.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_UV].uiCheckTime = 1000U; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_OV].fCheckLimit = 31.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_GLOW_PLUG_OV].uiCheckTime = 1000U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_UV].fCheckLimit = 18.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_UV].uiCheckTime = 1000U; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_OV].fCheckLimit = 31.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_SOLENOID_OV].uiCheckTime = 1000U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_UV].fCheckLimit = 18.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_UV].uiCheckTime = 1000U; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_OV].fCheckLimit = 31.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FUEL_PUMP_OV].uiCheckTime = 1000U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_UV].fCheckLimit = 18.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_UV].uiCheckTime = 1000U; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OV].fCheckLimit = 31.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_COOLANT_PUMP_OV].uiCheckTime = 1000U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_UV].fCheckLimit = 18.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_UV].uiCheckTime = 1000U; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_OV].fCheckLimit = 31.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN1_OV].uiCheckTime = 1000U; // Value + + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_UV].fCheckLimit = 18.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_UV].uiCheckTime = 1000U; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_OV].fCheckLimit = 31.0F; // Value + AlarmOperValue[(Uint16)IDX_FAULT_DCU_FAN2_OV].uiCheckTime = 1000U; // 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_V + AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 0x1; // Glow_Plug_V + AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 0x2; // Solenoid_V + AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 0x3; // Fuel_Pump_V + AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 0x4; // Cooling_Pump_V + AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 0x5; // Fan1_V + AdcRegs.ADCCHSELSEQ2.bit.CONV06 = 0x6; // Fan2_V + AdcRegs.ADCCHSELSEQ2.bit.CONV07 = 0x8; // Engine_Heater_I + AdcRegs.ADCCHSELSEQ3.bit.CONV08 = 0x9; // Glow_Plug_I + AdcRegs.ADCCHSELSEQ3.bit.CONV09 = 0xA; // Solenoid_I + AdcRegs.ADCCHSELSEQ3.bit.CONV10 = 0xB; // Fuel_Pump_I + AdcRegs.ADCCHSELSEQ3.bit.CONV11 = 0xC; // Cooling_Pump_I + AdcRegs.ADCCHSELSEQ4.bit.CONV12 = 0xD; // Fan1_I + AdcRegs.ADCCHSELSEQ4.bit.CONV13 = 0xE; // Fan2_I + + AdcRegs.ADCMAXCONV.all = ((Uint16)IDX_ADC_MAX - 1U); // 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(); +} + +static void CInitAdcStructure(void) +{ + (void)memset(&AdcOperValue, 0, sizeof(CAdcOperValue)); + + (void)memset(&Adc_EngineHeater_V, 0, sizeof(CAdcCalcValue)); + (void)memset(&Adc_GlowPlug_V, 0, sizeof(CAdcCalcValue)); + (void)memset(&Adc_Solenoid_V, 0, sizeof(CAdcCalcValue)); + (void)memset(&Adc_FuelPump_V, 0, sizeof(CAdcCalcValue)); + (void)memset(&Adc_CoolantPump_V, 0, sizeof(CAdcCalcValue)); + (void)memset(&Adc_Fan1_V, 0, sizeof(CAdcCalcValue)); + (void)memset(&Adc_Fan2_V, 0, sizeof(CAdcCalcValue)); + + (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_V.fGain = 0.026726F; + Adc_GlowPlug_V.fGain = 0.026726F; + Adc_Solenoid_V.fGain = 0.026726F; + Adc_FuelPump_V.fGain = 0.026726F; + Adc_CoolantPump_V.fGain = 0.026726F; + Adc_Fan1_V.fGain = 0.026726F; + Adc_Fan2_V.fGain = 0.026726F; + + Adc_EngineHeater_V.fOffset = -71.157F; + Adc_GlowPlug_V.fOffset = -71.157F; + Adc_Solenoid_V.fOffset = -71.157F; + Adc_FuelPump_V.fOffset = -71.157F; + Adc_CoolantPump_V.fOffset = -71.157F; + Adc_Fan1_V.fOffset = -71.157F; + Adc_Fan2_V.fOffset = -71.157F; + + Adc_EngineHeater_I.fGain = 0.027778F; // 40A Limit + Adc_GlowPlug_I.fGain = 0.027778F; // 40A Limit + Adc_Solenoid_I.fGain = 0.027778F; // 20A Limit + Adc_FuelPump_I.fGain = 0.027778F; // 20A Limit + Adc_CoolantPump_I.fGain = 0.027778F; // 20A Limit + Adc_Fan1_I.fGain = 0.027778F; // 40A Limit + Adc_Fan2_I.fGain = 0.027778F; // 40A Limit + + Adc_EngineHeater_I.fOffset = -62.277778F; + Adc_GlowPlug_I.fOffset = -62.277778F; + Adc_Solenoid_I.fOffset = -62.277778F; + Adc_FuelPump_I.fOffset = -62.277778F; + Adc_CoolantPump_I.fOffset = -62.277778F; + Adc_Fan1_I.fOffset = -62.277778F; + Adc_Fan2_I.fOffset = -62.277778F; +} + +static inline void CCalcAdcSum(CAdcCalcValue *AdcBuff) +{ + AdcBuff->fSampledValue = ((float32) AdcBuff->iAdcValue * AdcBuff->fGain) + AdcBuff->fOffset; + AdcBuff->fSampledSum += AdcBuff->fSampledValue; + AdcBuff->uiSamplingCount++; + if (AdcBuff->uiSamplingCount >= 20U) + { + AdcBuff->uiSamplingCount = 0U; + AdcBuff->fSampledSum = AdcBuff->fSampledSum / 20.0F; + AdcBuff->fLpfValue = (0.01884955F * AdcBuff->fSampledSum) + ((1.0F - 0.01884955F) * AdcBuff->fLpfValue); // 0.01884955f = (PI2 * ADC_LPF_COFF * (1.0F / ADC_FREQ)) + AdcBuff->fLpfValue = (AdcBuff->fLpfValue < 0.0F) ? 0.0F : AdcBuff->fLpfValue; + AdcBuff->fSampledSum = 0.0F; + } +} + +static Uint32 CGetKey(void) +{ + const Uint16 uiKeyGpioList[(Uint16)IDX_KEY_MAX] = { 67U, 39U, 31U, 30U, 29U, 66U, 64U, 58U, 57U, 56U, 54U }; + + Uint16 i, ucDiv, ucMod; + Uint32 ulGpioData = 0UL, ulKeyRead = 0UL; + + /* + * ------GPIO Key List------ + * + * GPIO67 - POWER + * GPIO39 - UP Arrow + * GPIO31 - DOWN Arrow + * GPIO30 - ENTER + * GPIO29 - MENU + * GPIO66 - START + * GPIO64 - EMERGENCY + * GPIO58 - REMOTE START + * GPIO57 - REMOTE STOP + * GPIO56 - REMOTE EMERGENCY + * GPIO54 - REMOTE BATTLE MODE + * ------------------------- + */ + for (i = 0U; i < (Uint16)IDX_KEY_MAX; i++) + { + ucDiv = (Uint16)((Uint16)uiKeyGpioList[i] / 32U); + ucMod = (Uint16)((Uint16)uiKeyGpioList[i] % 32U); + + 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 = 1U; // 전원 켤 때 한번 무시 + + // [StartStop키용 변수 추가] + static Uint32 ulStartKeyCnt = 0UL; // StartStop 롱키 카운트 + static Uint16 uiStartKeyProcessed = 0U; // StartStop 롱키 처리 플래그 + + static Uint32 ulPrevKey = 0UL; + Uint32 ulChangeKey; + Uint32 ulReadKey = CGetKey(); + + // 전원키(KEY_POWER_MASK)와 StartStop키(KEY_START_MASK) 둘 다 일반 변화 감지에서 제외 + ulChangeKey = (ulPrevKey ^ ulReadKey) & ~(KEY_POWER_MASK | KEY_START_MASK); + + if (ulChangeKey > 0UL) + { + if (KeyOperValue.uiKeyWait == 0U) // 채터링 무시 시작 + { + KeyOperValue.uiKeyWait = 1U; + KeyOperValue.uiKeyWaitCount = 20; // 20ms + } + else + { + if ((KeyOperValue.uiKeyWaitCount == 0U) && (GeneralOperValue.uiApuState > (Uint16)IDX_APU_OPER_POST)) + { + // ulPrevKey 갱신 시, 롱키 처리되는 비트들(Power, StartStop)은 기존 상태를 유지하고 나머지만 갱신 + ulPrevKey = (ulPrevKey & (KEY_POWER_MASK | KEY_START_MASK)) | (ulReadKey & ~(KEY_POWER_MASK | KEY_START_MASK)); + + CKeyCheck(ulChangeKey, ulReadKey); // 일반 키 동작 + } + } + } + else + { + // 변화가 없으면 채터링 대기 초기화 (일반 키용) + if ((KeyOperValue.uiKeyWait != 0U) && (KeyOperValue.uiKeyWaitCount == 0U)) + { + KeyOperValue.uiKeyWait = 0U; + } + } + + // --------------------------------------------------------- + // 전원키 (Power Key) 롱키 처리 (로컬 & 리모트 모두 포함) + // --------------------------------------------------------- + Uint32 ulPressedPowerKey = ulReadKey & KEY_POWER_MASK; + + if (ulPressedPowerKey != 0UL) + { + if (uiLongKeyProcessed == 0U) + { + ulLongKeyCnt++; + + // 롱키 시간 도달 시 동작 수행 + if (ulLongKeyCnt >= LONG_KEY_TIME) + { + // KEY_POWER_MASK 전체가 아닌 '실제로 눌린 키(ulPressedPowerKey)'를 전달 + CKeyCheck(ulPressedPowerKey, ulReadKey); + + uiLongKeyProcessed = 1U; // 처리 완료 플래그 + ulLongKeyCnt = LONG_KEY_TIME; // 오버플로우 방지 + } + } + } + else + { + // 키를 뗐을 때 초기화 + ulLongKeyCnt = 0UL; + uiLongKeyProcessed = 0U; + + // ulPrevKey의 로컬 전원 키 비트를 모두 0으로 동기화 + ulPrevKey &= ~KEY_POWER_MASK; + } + + // --------------------------------------------------------- + // 시동/정지 키 (StartStop) 롱키 처리 (로컬 & 리모트 모두 포함) + // --------------------------------------------------------- + Uint32 ulPressedStartKey = ulReadKey & KEY_START_MASK; + + if (ulPressedStartKey != 0UL) + { + if (uiStartKeyProcessed == 0U) + { + ulStartKeyCnt++; // 카운트 증가 + + // 0.5초(500ms) 도달 시 동작 수행 + if (ulStartKeyCnt >= LONG_KEY_TIME) + { + // KEY_START_MASK가 아닌 '실제로 눌린 키(ulPressedStartKey)'를 전달 + CKeyCheck(ulPressedStartKey, ulReadKey); + + uiStartKeyProcessed = 1U; // 처리 완료 플래그 + ulStartKeyCnt = LONG_KEY_TIME; // 오버플로우 방지 + } + } + } + else + { + // 키를 뗐을 때 초기화 + ulStartKeyCnt = 0UL; + uiStartKeyProcessed = 0U; + + // ulPrevKey의 해당 비트(Bit 5, Bit 8) 모두 0으로 동기화 + ulPrevKey &= ~KEY_START_MASK; + } +} + +void CKeyWaitCount(void) +{ + if (KeyOperValue.uiKeyWait == 1U) + { + if (KeyOperValue.uiKeyWaitCount > 0U) + { + KeyOperValue.uiKeyWaitCount--; + } + else + { + KeyOperValue.uiKeyWait = 0U; + } + } +} + +static void CKeyCheck(Uint32 ulChangeKey, Uint32 ulKeyRead) +{ + static const CKeyHandler KeyTable[(Uint16)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 }, + { IDX_KEY_REMOTE_START, &CKeyRemoteEngineStartProcess }, + { IDX_KEY_REMOTE_STOP, &CKeyRemoteEngineStopProcess }, + { IDX_KEY_REMOTE_EMERGENCY, &CKeyEmergencyProcess }, + { IDX_KEY_BATTLE_MODE, &CKeyBattleModeProcess } + }; + + Uint16 i; + + for (i = 0U; i < (Uint16)IDX_KEY_MAX; i++) + { + if ((ulChangeKey & (0x1UL << i)) > 0U) + { + if ((ulKeyRead & (0x1UL << i)) > 0U) + { + KeyTable[i].pAction(); + } + } + } +} + +static void CProcessArrowUpPageChange(void) +{ + if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_APU2) + { + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_APU1; + } + else if ((OledOperValue.uiPageNum > (Uint16)IDX_OLED_PAGE_SENSOR1) && (OledOperValue.uiPageNum <= (Uint16)IDX_OLED_PAGE_SENSOR4)) + { + OledOperValue.uiPageNum = OledOperValue.uiPageNum - 1U; + } + else if ((OledOperValue.uiPageNum > (Uint16)IDX_OLED_PAGE_WARNING1) && (OledOperValue.uiPageNum <= (Uint16)IDX_OLED_PAGE_WARNING2)) + { + OledOperValue.uiPageNum = OledOperValue.uiPageNum - 1U; + } + else + { + if ((OledOperValue.uiPageNum > (Uint16)IDX_OLED_PAGE_FAULT1) && (OledOperValue.uiPageNum <= (Uint16)IDX_OLED_PAGE_FAULT7)) + { + OledOperValue.uiPageNum = OledOperValue.uiPageNum - 1U; + } + } +} + +static void CProcessArrowUpFocusChange(void) +{ + if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_MENU1) + { + if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_1) + { + OledOperValue.uiFocusLine = (Uint16)IDX_OLED_LINE_FOCUS_1; + } + else + { + CMoveFocusLine(4U, DIR_UP); + } + } + else if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_MENU2) + { + if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_1) + { + // Go back to Menu 1 + OledOperValue.uiFocusLine = (Uint16)IDX_OLED_LINE_FOCUS_4; + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_MENU1; + } + else + { + CMoveFocusLine(4U, DIR_UP); + } + } + else if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_PASSWORD) + { + CChangePasswordDigit(DIR_UP); + } + else if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_RESET_ALARM) + { + OledOperValue.uiResetAlarmAnswer = (OledOperValue.uiResetAlarmAnswer == 1U) ? 0U : 1U; + } + else + { + if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_MAINTENANCE) + { + if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_1) + { + OledOperValue.uiFocusLine = (Uint16)IDX_OLED_LINE_FOCUS_1; + } + else + { + CMoveFocusLine(3U, DIR_UP); + } + } + } +} + +static void CKeyArrowUpProcess(void) +{ + CProcessArrowUpPageChange(); + CProcessArrowUpFocusChange(); +} + +static void CProcessArrowDownPageChange(void) +{ + if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_APU1) + { + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_APU2; + } + else if ((OledOperValue.uiPageNum >= (Uint16)IDX_OLED_PAGE_SENSOR1) && (OledOperValue.uiPageNum < (Uint16)IDX_OLED_PAGE_SENSOR4)) + { + OledOperValue.uiPageNum = OledOperValue.uiPageNum + 1U; + } + else if ((OledOperValue.uiPageNum >= (Uint16)IDX_OLED_PAGE_WARNING1) && (OledOperValue.uiPageNum < (Uint16)IDX_OLED_PAGE_WARNING2)) + { + OledOperValue.uiPageNum = OledOperValue.uiPageNum + 1U; + } + else + { + if ((OledOperValue.uiPageNum >= (Uint16)IDX_OLED_PAGE_FAULT1) && (OledOperValue.uiPageNum < (Uint16)IDX_OLED_PAGE_FAULT7)) + { + OledOperValue.uiPageNum = OledOperValue.uiPageNum + 1U; + } + } +} + +static void CProcessArrowDownFocusChange(void) +{ + if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_MENU1) + { + if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_4) + { + OledOperValue.uiFocusLine = (Uint16)IDX_OLED_LINE_FOCUS_1; + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_MENU2; + } + else + { + CMoveFocusLine(4U, DIR_DOWN); + } + } + else if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_MENU2) + { + if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_4) + { + OledOperValue.uiFocusLine = (Uint16)IDX_OLED_LINE_FOCUS_4; + } + else + { + CMoveFocusLine(4U, DIR_DOWN); + } + } + else if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_PASSWORD) + { + CChangePasswordDigit(DIR_DOWN); + } + else if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_RESET_ALARM) + { + OledOperValue.uiResetAlarmAnswer = (OledOperValue.uiResetAlarmAnswer == 1U) ? 0U : 1U; + } + else + { + if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_MAINTENANCE) + { + if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_3) + { + OledOperValue.uiFocusLine = (Uint16)IDX_OLED_LINE_FOCUS_3; + } + else + { + CMoveFocusLine(3U, DIR_DOWN); + } + } + } +} + +static void CKeyArrowDownProcess(void) +{ + CProcessArrowDownPageChange(); + CProcessArrowDownFocusChange(); +} + +static void CChangePasswordDigit(Uint16 direction) +{ + if (OledOperValue.uiFocusDigit <= (Uint16)IDX_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 CMoveFocusLine(Uint16 maxLines, Uint16 direction) +{ + if (maxLines > 0U) + { + if (direction == DIR_UP) + { + OledOperValue.uiFocusLine = (Uint16)((OledOperValue.uiFocusLine + (Uint16)(maxLines - 1U)) % maxLines); + } + else /* DIR_DOWN */ + { + OledOperValue.uiFocusLine = (Uint16)((OledOperValue.uiFocusLine + 1U) % maxLines); + } + } +} + +static void CProcessEnterMenu1(void) +{ + switch (OledOperValue.uiFocusLine) + { + case (Uint16)IDX_OLED_MENU_APU: + { + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_APU1; + break; + } + case (Uint16)IDX_OLED_MENU_TEMP: + { + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_TEMP; + break; + } + case (Uint16)IDX_OLED_MENU_SENSOR: + { + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_SENSOR1; + break; + } + default: + { + if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_MENU_WARNING) + { + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_WARNING1; + } + break; + } + } +} + +static void CProcessEnterMenu2(void) +{ + switch (OledOperValue.uiFocusLine) + { + case (Uint16)IDX_OLED_LINE_FOCUS_1: // Fault + { + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_FAULT1; + break; + } + case (Uint16)IDX_OLED_LINE_FOCUS_2: // Reset + { + OledOperValue.uiPrevFocusLine = OledOperValue.uiFocusLine; + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_RESET_ALARM; + break; + } + case (Uint16)IDX_OLED_LINE_FOCUS_3: // Maintenance + { + OledOperValue.uiPrevFocusLine = OledOperValue.uiFocusLine; + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_PASSWORD; + OledOperValue.uiFocusDigit = (Uint16)IDX_OLED_PASS_DIGIT_1; + break; + } + case (Uint16)IDX_OLED_LINE_FOCUS_4: // Version + { + OledOperValue.uiPrevFocusLine = OledOperValue.uiFocusLine; + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_VERSION; + break; + } + default: + { + break; + } + } +} + +static void CProcessEnterPassword(void) +{ + if (OledOperValue.uiFocusDigit < (Uint16)IDX_OLED_PASS_DIGIT_4) + { + OledOperValue.uiFocusDigit = (OledOperValue.uiFocusDigit + 1U) % 4U; + } + else + { + const Uint16 uiPassword[4] = MAINTENECE_PASSKEY; + Uint16 i; + Uint16 uiIsMatch = 1U; // 1U: 일치함, 0U: 불일치함 + + for (i = 0U; i < (Uint16)(sizeof(uiPassword) / sizeof(uiPassword[0])); i++) + { + if (GeneralOperValue.uiPassword[i] != uiPassword[i]) + { + uiIsMatch = 0U; // 하나라도 다르면 불일치 + break; + } + } + + if (uiIsMatch == 1U) + { + GeneralOperValue.uiMaintenance = 1U; + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_MAINTENANCE; + OledOperValue.uiFocusLine = (Uint16)IDX_OLED_LINE_FOCUS_1; + } + else + { + OledOperValue.uiFocusDigit = (Uint16)IDX_OLED_PASS_DIGIT_1; + } + } +} + +static void CProcessEnterMaintenance(void) +{ + if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_1) + { + GeneralOperValue.Maintenance.ManualCranking = (GeneralOperValue.Maintenance.ManualCranking == 1U) ? 0U : 1U; + } + else if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_2) + { + GeneralOperValue.Maintenance.LampTest = (GeneralOperValue.Maintenance.LampTest == 1U) ? 0U : 1U; + } + else + { + if (OledOperValue.uiFocusLine == (Uint16)IDX_OLED_LINE_FOCUS_3) + { + GeneralOperValue.Maintenance.KeyTest = (GeneralOperValue.Maintenance.KeyTest == 1U) ? 0U : 1U; + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_KEY_TEST; + } + } +} + +static void CKeyEnterProcess(void) +{ + switch (OledOperValue.uiPageNum) + { + case (Uint16)IDX_OLED_PAGE_MENU1: + { + CProcessEnterMenu1(); + break; + } + case (Uint16)IDX_OLED_PAGE_MENU2: + { + CProcessEnterMenu2(); + break; + } + case (Uint16)IDX_OLED_PAGE_PASSWORD: + { + CProcessEnterPassword(); + break; + } + case (Uint16)IDX_OLED_PAGE_MAINTENANCE: + { + CProcessEnterMaintenance(); + break; + } + case (Uint16)IDX_OLED_PAGE_RESET_ALARM: + { + if (OledOperValue.uiResetAlarmAnswer == 1U) + { + GeneralOperValue.uiAlarmReset = 1U; + } + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_MENU2; + break; + } + default: + { + // Fault/Warning page return to main page + if ((OledOperValue.uiPageNum >= (Uint16)IDX_OLED_PAGE_WARNING1) && (OledOperValue.uiPageNum <= (Uint16)IDX_OLED_PAGE_FAULT7)) + { + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_APU1; + } + break; + } + } +} + +static void CKeyMenuProcess(void) +{ + // Return to main menus from sub-pages + if ((OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_MENU1) || (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_MENU2)) + { + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_APU1; + OledOperValue.uiFocusLine = 0U; + } + else + { + if ((OledOperValue.uiPageNum >= (Uint16)IDX_OLED_PAGE_FAULT1) && (OledOperValue.uiPageNum <= (Uint16)IDX_OLED_PAGE_VERSION)) + { + // Return to Menu 2 from Faults or Debug + if (OledOperValue.uiPageNum == (Uint16)IDX_OLED_PAGE_MAINTENANCE) + { + GeneralOperValue.uiMaintenance = 0U; + OledOperValue.uiFocusLine = OledOperValue.uiPrevFocusLine; + } + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_MENU2; + } + else + { + // Return to Menu 1 from others (APU, Temp, Sensor, Warning) + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_MENU1; + } + } +} + +static void CKeyMainPowerProcess(void) +{ + if (GeneralOperValue.uiApuState <= (Uint16)IDX_APU_OPER_STANDBY) + { + // APU가 정지 상태에서만 전원 스위치 입력 가능 + KeyOperValue.KeyList.MainPower = 1U; + OledOperValue.uiPageNum = (Uint16)IDX_OLED_PAGE_SHUTDOWN; + } +} + +static void CKeyEngineStartStopProcess(void) +{ + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_STANDBY) + { + // 스탠바이 상태에서만 시동 시작 스위치 입력 받는다. + KeyOperValue.KeyList.EngineStartStop = 1U; + } + else + { + KeyOperValue.KeyList.EngineStartStop = 0U; + } +} + +static void CKeyRemoteEngineStartProcess(void) +{ + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_STANDBY) + { + // 스탠바이 상태에서만 시동 시작 스위치 입력 받는다. + KeyOperValue.KeyList.EngineStartStop = 1U; + } +} + +static void CKeyRemoteEngineStopProcess(void) +{ + KeyOperValue.KeyList.EngineStartStop = 0U; +} + +static void CKeyEmergencyProcess(void) +{ + KeyOperValue.KeyList.Emergency = KeyOperValue.KeyList.Emergency ^ 1U; +} + +static void CKeyBattleModeProcess(void) +{ + KeyOperValue.KeyList.BattleMode = KeyOperValue.KeyList.BattleMode ^ 1U; +} diff --git a/Source/State.h b/Source/State.h new file mode 100644 index 0000000..d11e0da --- /dev/null +++ b/Source/State.h @@ -0,0 +1,219 @@ +#ifndef SOURCE_STATE_H_ +#define SOURCE_STATE_H_ + +#define COMM_TIME_OUT_COUNT (3000U) // 3sec + +typedef enum +{ + IDX_ADC_ENGINE_HEATER_V = 0U, // 0 + IDX_ADC_GLOW_PLUG_V, // 1 + IDX_ADC_SOLENOID_V, // 2 + IDX_ADC_FUEL_PUMP_V, // 3 + IDX_ADC_COOLANT_PUMP_V, // 4 + IDX_ADC_FAN1_V, // 5 + IDX_ADC_FAN2_V, // 6 + IDX_ADC_ENGINE_HEATER_I, // 7 + IDX_ADC_GLOW_PLUG_I, // 8 + IDX_ADC_SOLENOID_I, // 9 + IDX_ADC_FUEL_PUMP_I, // 10 + IDX_ADC_COOLANT_PUMP_I, // 11 + IDX_ADC_FAN1_I, // 12 + IDX_ADC_FAN2_I, // 13 + IDX_ADC_MAX +} E_IDX_ADC; + +typedef enum +{ + IDX_WARNING_GCU_PCB_OT = 0U, + IDX_WARNING_GCU_FET_OT, + IDX_WARNING_GCU_WINDING1_OH, + IDX_WARNING_GCU_WINDING2_OH, + IDX_WARNING_GCU_MAX +} E_IDX_WARNING_GCU; + +typedef enum +{ + IDX_WARNING_ECU_ENGINE_OH = 0U, + IDX_WARNING_ECU_RESERVED, + IDX_WARNING_ECU_LO_OIL_PRESS, + IDX_WARNING_ECU_INTAKE_OH, + IDX_WARNING_ECU_INTAKE_LO_PRESS, + IDX_WARNING_ECU_ENGINE_LO_TEMP, + IDX_WARNING_ECU_ENGINE_SENSOR, + IDX_WARNING_ECU_DEFAULT_ACTIVE, + IDX_WARNING_ECU_MAX +} E_IDX_WARNING_ECU; + +typedef enum +{ + IDX_FAULT_DCU_CAR_COMM = 0U, // 0 + IDX_FAULT_DCU_GCU_COMM, // 1 + IDX_FAULT_DCU_ECU_COMM, // 2 + IDX_FAULT_DCU_RPM_ERR, // 3 + IDX_FAULT_DCU_ENGINE_HEAT_OC, // 4 + IDX_FAULT_DCU_GLOW_PLUG_OC, // 5 + IDX_FAULT_DCU_SOLENOID_OC, // 6 + IDX_FAULT_DCU_FUEL_PUMP_OC, // 7 + IDX_FAULT_DCU_COOLANT_PUMP_OC, // 8 + IDX_FAULT_DCU_FAN1_OC, // 9 + IDX_FAULT_DCU_FAN2_OC, // 10 + IDX_FAULT_DCU_ENGINE_HEAT_UV, // 11 + IDX_FAULT_DCU_ENGINE_HEAT_OV, // 12 + IDX_FAULT_DCU_GLOW_PLUG_UV, // 13 + IDX_FAULT_DCU_GLOW_PLUG_OV, // 14 + IDX_FAULT_DCU_SOLENOID_UV, // 15 + IDX_FAULT_DCU_SOLENOID_OV, // 16 + IDX_FAULT_DCU_FUEL_PUMP_UV, // 17 + IDX_FAULT_DCU_FUEL_PUMP_OV, // 18 + IDX_FAULT_DCU_COOLANT_PUMP_UV, // 19 + IDX_FAULT_DCU_COOLANT_PUMP_OV, // 20 + IDX_FAULT_DCU_FAN1_UV, // 21 + IDX_FAULT_DCU_FAN1_OV, // 22 + IDX_FAULT_DCU_FAN2_UV, // 23 + IDX_FAULT_DCU_FAN2_OV, // 24 + IDX_FAULT_DCU_CRANKING_FAIL, // 25 + IDX_FAULT_DCU_MAX +} E_IDX_DCU_FAULT; + +typedef enum +{ + IDX_FAULT_GCU_HWTRIP = 0U, // 0 + IDX_FAULT_GCU_HWIGBT, // 1 + IDX_FAULT_GCU_HW_DC, // 2 + IDX_FAULT_GCU_GEN_OCU, // 3 + IDX_FAULT_GCU_GEN_OCV, // 4 + IDX_FAULT_GCU_GEN_OCW, // 5 + IDX_FAULT_GCU_DC_OV, // 6 + IDX_FAULT_GCU_DC_OC, // 7 + + IDX_FAULT_GCU_CRANK_OC, // 8 + IDX_FAULT_GCU_PCB_OT, // 9 + IDX_FAULT_GCU_FET_OT, // 10 + IDX_FAULT_GCU_WINDING1_OH, // 11 + IDX_FAULT_GCU_WINDING2_OH, // 12 + IDX_FAULT_GCU_GEN_OS, // 13 + IDX_FAULT_GCU_RES_IC, // 14 + IDX_FAULT_GCU_RES_PRTY, // 15 + IDX_FAULT_GCU_MAX +} E_IDX_GCU_FAULT; + +typedef enum +{ + IDX_FAULT_ECU_OIL_MS = 0U, // 0 + IDX_FAULT_ECU_INT_OH, // 1 + IDX_FAULT_ECU_ENG_OH, // 2 + IDX_FAULT_ECU_ACTUATOR, // 3 + IDX_FAULT_ECU_RPM_SIG, // 4 + IDX_FAULT_ECU_ENG_SF, // 5 + IDX_FAULT_MAX +} E_IDX_ECU_FAULT; + +typedef enum +{ + IDX_KEY_MAIN_POWER = 0U, // 0 + IDX_KEY_ARR_UP, // 1 + IDX_KEY_ARR_DOWN, // 2 + IDX_KEY_ENTER, // 3 + IDX_KEY_MENU, // 4 + IDX_KEY_ENG_START_STOP, // 5 + IDX_KEY_EMERGENCY, // 6 + IDX_KEY_REMOTE_START, // 7 + IDX_KEY_REMOTE_STOP, // 8 + IDX_KEY_REMOTE_EMERGENCY, // 9 + IDX_KEY_BATTLE_MODE, // 10 + IDX_KEY_MAX // 11 +} E_IDX_KEY; + +typedef struct ClassKeyHandler +{ + E_IDX_KEY eKey; + void (*pAction) (void); +} CKeyHandler; + +typedef struct ClassAdcOperValue +{ + Uint16 uiAdcOffsetIndex; + Uint16 uiOffsetAdjustStart; +} CAdcOperValue; + +typedef struct ClassAdcCalcValue +{ + float32 fLpfValue; + float32 fSampledValue; + float32 fSampledSum; + float32 fTempAdcOffset; + float32 fGain; + float32 fOffset; + Uint16 uiSamplingCount; + int16 iAdcValue; +} CAdcCalcValue; + +typedef struct ClassWarningOperValue +{ + float32 fCheckLimit; // 경고 한계 값 + Uint16 uiWarning; // 0: 정상, 1: 경고 발생 중 + Uint16 uiDetectCount; // 경고 검출 카운터 + Uint16 uiReleaseCount; // 경고 해제 카운터 + Uint16 uiCheckTime; +} CWarningOperValue; + +typedef struct ClassAlarmOperValue +{ + float32 fCheckLimit; + float32 fFaultValue; + Uint16 uiCheck; + Uint16 uiCheckCount; + Uint16 uiCheckTime; +} CAlarmOperValue; + +typedef struct ClassKeyList +{ + Uint16 MainPower; + Uint16 ArrowUp; + Uint16 ArrowDown; + Uint16 Enter; + Uint16 Menu; + Uint16 EngineStartStop; + Uint16 Emergency; + Uint16 BattleMode; +} CKeyList; + +typedef struct ClassKeyOperValue +{ + Uint16 uiKeyWaitCount; + Uint16 uiPreviousKey; + Uint16 uiKeyWait; + CKeyList KeyList; +} CKeyOperValue; + +extern CAdcCalcValue Adc_EngineHeater_V; +extern CAdcCalcValue Adc_GlowPlug_V; +extern CAdcCalcValue Adc_Solenoid_V; +extern CAdcCalcValue Adc_FuelPump_V; +extern CAdcCalcValue Adc_CoolantPump_V; +extern CAdcCalcValue Adc_Fan1_V; +extern CAdcCalcValue Adc_Fan2_V; + +extern CAdcCalcValue Adc_EngineHeater_I; +extern CAdcCalcValue Adc_GlowPlug_I; +extern CAdcCalcValue Adc_Solenoid_I; +extern CAdcCalcValue Adc_FuelPump_I; +extern CAdcCalcValue Adc_CoolantPump_I; +extern CAdcCalcValue Adc_Fan1_I; +extern CAdcCalcValue Adc_Fan2_I; + +extern CAdcOperValue AdcOperValue; +extern CKeyOperValue KeyOperValue; + +extern Uint32 ulDcuTotalAlarm; +extern Uint32 ulGcuTotalAlarm; +extern Uint32 ulEcuTotalAlarm; + +interrupt void CAdcInterrupt(void); +void CAlarmProcedure(void); +void CInitAdc(void); +void CKeyCheckProcedure(void); +void CKeyWaitCount(void); +void CDisplayAlarmPopup(void); + +#endif /* SOURCE_STATE_H_ */ diff --git a/Source/main.c b/Source/main.c new file mode 100644 index 0000000..c545d98 --- /dev/null +++ b/Source/main.c @@ -0,0 +1,730 @@ +/* ========================================================================= */ +/* 1. Includes */ +/* ========================================================================= */ +#include "main.h" + +/* ========================================================================= */ +/* 2. Local Macros & Constants (내부 전용 매크로 및 상수) */ +/* ========================================================================= */ +// No Code + +/* ========================================================================= */ +/* 3. Local Typedefs & Structures (내부 전용 사용자 정의 자료형) */ +/* ========================================================================= */ +// No Code + +/* ========================================================================= */ +/* 4. Internal Linkage Function Declarations (내부 동작용 Static 함수 선언) */ +/* ========================================================================= */ +static void CInitSystem(void); +static void COledDisplay(void); +static void CInitGeneralOperValue(void); +static void CInitGpio(void); +static void CSystemConfigure(void); +static void CMappingInterrupt(void); +static void CProcessSoftTimer(void); +static void CShutdownProcedure(void); +static Uint16 CPowerOnCheck(void); +static void CSoftTimerWorkProcess(void); +static Uint16 CIsStatusSoftTimer(Uint16 uiTimerIndex); +static void CReloadSoftTimer(Uint16 uiTimerIndex); +static void CInitSoftTimers(void); +static void CInitSoftTimer(void); +static void CConfigSoftTimer(Uint16 TimerIndex, Uint32 Delay); +static void CStartSoftTimer(Uint16 uiTimerIndex); +static Uint16 CSoftClockTimeOut(Uint32 ulStartClock, Uint32 ulTimeOutClock); +static void CInitI2C(void); + +/* ========================================================================= */ +/* 5. Global Variables & Structure Initialization (전역 변수 및 구조체 초기화) */ +/* ========================================================================= */ +Uint16 PowerOnCheckSensor[(Uint16)IDX_SENSOR_MAX] = { 0U }; + +CGeneralOperValue GeneralOperValue; + +static CSoftTimer SoftTimer[TIMER_MAX]; +static CWaitTimer WaitTimer[SOFTTIMER_WAIT_MAX]; +static Uint32 ulSoftClock; + +/* ========================================================================= */ +/* Function Definitions */ +/* ========================================================================= */ +int main(void) +{ + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_BOOT; + + CInitSystem(); + + CInitOled(); + + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_INITIAL; + + AdcOperValue.uiOffsetAdjustStart = 1U; // AD 보정 시작 + + for ( ; ; ) + { + CShutdownProcedure(); + + CSoftTimerWorkProcess(); + + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_INITIAL) + { + if (OledOperValue.uiProgressDone == 1U) + { + if (CSoftWaitCountProcedure(SOFTTIMER_WAIT_INIT, TIME_1SEC) == (Uint16)TIME_OVER) + { + COledBufferReset(); + + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_POST; // Adc 보정완료 이 후 POST 시작 + } + } + } + else if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_POST) + { + if (GeneralOperValue.uiSelfTestCheck == 0U) + { + GeneralOperValue.uiSelfTestCheck = 1U; // 한번만 체크하기 위함 + + GeneralOperValue.uiSelfTestPass = CPowerOnCheck(); // 1 : 정상, 0 : 비정상 + } + else + { + if (GeneralOperValue.uiSelfTestPass == 1U) // 1 : 정상 + { + COledBufferReset(); + + GeneralOperValue.uiApuState = (Uint16)IDX_APU_OPER_STANDBY; + } + } + } + else + { +#ifdef AUX_TEST + if (Rx400.AuxControl.AuxTestStart == 1U) + { + CSetAuxCtrlPin(IDX_CS_ENG_HEATER, (Rx400.AuxControl.EngineHeater != 0U) ? 1U : 0U); + CSetAuxCtrlPin(IDX_CS_GLOW_PLUG, (Rx400.AuxControl.GlowPlug != 0U) ? 1U : 0U); + CSetAuxCtrlPin(IDX_CS_SOLENOID, (Rx400.AuxControl.Solenoid != 0U) ? 1U : 0U); + CSetAuxCtrlPin(IDX_CS_FUEL_PUMP, (Rx400.AuxControl.FuelPump != 0U) ? 1U : 0U); + CSetAuxCtrlPin(IDX_CS_COOLANT_PUMP, (Rx400.AuxControl.CoolantPump != 0U) ? 1U : 0U); + CSetAuxCtrlPin(IDX_CS_FAN1, (Rx400.AuxControl.Fan1 != 0U) ? 1U : 0U); + CSetAuxCtrlPin(IDX_CS_FAN2, (Rx400.AuxControl.Fan2 != 0U) ? 1U : 0U); + } + // 정비 모드가 꺼져있어야 시퀀스 동작. + else if (GeneralOperValue.uiMaintenance == 0U) +#else + if (GeneralOperValue.uiMaintenance == 0U) +#endif + { + if (KeyOperValue.KeyList.MainPower == 0U) // 전원 스위치를 눌러서 shutdown 상태면 프로시저 OFF + { + CApuOperProcedure(); // 엔진 운영 프로시저 + + CLedControlProcedure(); // LED 제어 프로시저 + } + } + else + { + CDebugModeProcedure(); + } + } + } +} + +static void CSoftTimerWorkProcess(void) +{ + Uint16 ui01msExcute; + Uint16 ui10msExcute; + Uint16 ui100msExcute; + + ui01msExcute = CIsStatusSoftTimer(TIMER_01MS); + ui10msExcute = CIsStatusSoftTimer(TIMER_10MS); + ui100msExcute = CIsStatusSoftTimer(TIMER_100MS); + + if (ui01msExcute == (Uint16)SOFTTIMER_TIME_OVER) + { + CReloadSoftTimer(TIMER_01MS); + + if (GeneralOperValue.uiApuState > (Uint16)IDX_APU_OPER_POST) // ADC 오프셋 보정 완료 후 감지 + { + //CAlarmProcedure(); + CDisplayAlarmPopup(); + } + + // (정비모드:키테스트)가 아니면 키 입력 처리 시작 함. + if (GeneralOperValue.Maintenance.KeyTest == 0U) + { + CKeyCheckProcedure(); + CKeyWaitCount(); + } + } + + if (ui10msExcute == (Uint16)SOFTTIMER_TIME_OVER) + { + CReloadSoftTimer(TIMER_10MS); + + CSendECanDataB(); + COledDisplay(); + } + + if (ui100msExcute == (Uint16)SOFTTIMER_TIME_OVER) + { + CReloadSoftTimer(TIMER_100MS); + CSendECanDataA(); + CDisplayAntiNoiseRefresh(); + } +} + +static void COledDisplay(void) +{ + static Uint16 RefeshDelay = 0U; + + // 부트 상태 이 후 프로그래스바 화면 표시용 + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_INITIAL) + { + CInitializePage(); + } + else + { + if (RefeshDelay == 0U) // 10ms 주기를 위함 + { + // POST 상태 표시 용 + if (GeneralOperValue.uiApuState == (Uint16)IDX_APU_OPER_POST) + { + CDisplayPostFail(); + } + else + { + // POST 이 후 화면 표시용 + CSetPage(OledOperValue.uiPageNum); + } + } + RefeshDelay = (RefeshDelay + 1U) % 10U; + } + + COledReflash(0, 0, OLED_WIDTH, OLED_HEIGHT); +} + +void CSoftWaitCountClear(Uint16 Index) +{ + WaitTimer[Index].ulCountSoftClock = 0U; + WaitTimer[Index].uiSoftCountTarget = 0U; +} + +static Uint16 CIsStatusSoftTimer(Uint16 uiTimerIndex) +{ + Uint16 isRunning = 1U; + + if (SoftTimer[uiTimerIndex].iStart != -1) + { + if (SoftTimer[uiTimerIndex].iStart == 1) + { + if (SoftTimer[uiTimerIndex].ulDecreaseValue == 0U) + { + isRunning = (Uint16)SOFTTIMER_TIME_OVER; // Success + } + else + { + isRunning = (Uint16)SOFTTIMER_RUNNING; + } + } + } + + return isRunning; +} + +static void CReloadSoftTimer(Uint16 uiTimerIndex) +{ + if (SoftTimer[uiTimerIndex].iTimer != -1) + { + SoftTimer[uiTimerIndex].ulDecreaseValue = SoftTimer[uiTimerIndex].ulSetValue; + } +} + +Uint16 CSoftWaitCountProcedure(Uint16 uiIndex, Uint32 ulWaitTime) +{ + Uint16 isCountOver = 0U; + + switch (WaitTimer[uiIndex].uiSoftCountTarget) + { + case 0U: + { + WaitTimer[uiIndex].ulCountSoftClock = CGetSoftClock(); + WaitTimer[uiIndex].uiSoftCountTarget = 1U; + break; + } + case 1U: + { + if (CSoftClockTimeOut(WaitTimer[uiIndex].ulCountSoftClock, ulWaitTime) == (Uint16)SOFTTIMER_TIME_OVER) + { + WaitTimer[uiIndex].uiSoftCountTarget = 2U; + } + break; + } + default: + { + WaitTimer[uiIndex].ulCountSoftClock = 0U; + WaitTimer[uiIndex].uiSoftCountTarget = 0U; + isCountOver = 1U; + break; + } + } + + return isCountOver; +} + +static Uint16 CSoftClockTimeOut(Uint32 ulStartClock, Uint32 ulTimeOutClock) +{ + Uint16 isRunning = 1U; + Uint32 ulCpuClock = CGetSoftClock(); + + if (((ulCpuClock + SYSTEM_10MIN_TIME - ulStartClock) % SYSTEM_10MIN_TIME) >= ulTimeOutClock) + { + isRunning = 0U; + } + + return isRunning; +} + +Uint32 CGetSoftClock(void) +{ + return ulSoftClock; +} + +static void CInitSystem(void) +{ + DINT; + IER = 0x0000; + IFR = 0x0000; + + InitSysCtrl(); + + CInitGpio(); // GPIO Direction and mux + + InitPieCtrl(); + IER = 0x0000; + IFR = 0x0000; + + InitPieVectTable(); + + InitCpuTimers(); + + ConfigCpuTimer(&CpuTimer0, 150.0F, 100.0F); // 100usec + + CSystemConfigure(); + + EINT; // Enable Global interrupt INTM + ERTM; // Enable Global realtime interrupt DBGM + + CpuTimer0Regs.TCR.all = 0x4001U; // Use write-only instruction to set TSS bit = 0 +} + +static void CInitGpio(void) +{ + EALLOW; + + // GPIO MUX Setting + GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 0x1U; // SCL + GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 0x1U; // SDA + + GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0x0U; // Enable pull-up (SDAA) + GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0x0U; // Enable pull-up (SCLA) + + GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 0x3U; // Asynch input (SDAA) + GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 0x3U; // Asynch input (SCLA) + + // GPIO Direction Setting '1' Output, '0' Input + GpioCtrlRegs.GPADIR.bit.GPIO9 = 0U; // GPIO_FUEL_PUMP_SIG_C + GpioCtrlRegs.GPADIR.bit.GPIO10 = 0U; // GPIO_GLOW_PLUG_SIG_C + GpioCtrlRegs.GPADIR.bit.GPIO11 = 0U; // GPIO_STOP_SOLENOID_SIG_C + GpioCtrlRegs.GPADIR.bit.GPIO24 = 0U; // GPIO_ENGINE_HEATER_SIG_C + GpioCtrlRegs.GPADIR.bit.GPIO25 = 0U; // GPIO_FAIL_SAFE_ENABLE_C + GpioCtrlRegs.GPADIR.bit.GPIO29 = 0U; // CPU_SW_MODE_RESET + GpioCtrlRegs.GPADIR.bit.GPIO30 = 0U; // CPU_SW_MODE_ENT + GpioCtrlRegs.GPADIR.bit.GPIO31 = 0U; // CPU_SW_DOWN + GpioCtrlRegs.GPBDIR.bit.GPIO39 = 0U; // CPU_SW_UP + GpioCtrlRegs.GPBDIR.bit.GPIO54 = 0U; // GPIO_BATTLEMODE_CMD_CS + GpioCtrlRegs.GPBDIR.bit.GPIO56 = 0U; // GPIO_EMERGENCY_CMD_CS + GpioCtrlRegs.GPBDIR.bit.GPIO57 = 0U; // GPIO_STOP_CMD_CS + GpioCtrlRegs.GPBDIR.bit.GPIO58 = 0U; // GPIO_START_CMD_CS + GpioCtrlRegs.GPCDIR.bit.GPIO64 = 0U; // CPU_SW_EMERGENCY + GpioCtrlRegs.GPCDIR.bit.GPIO66 = 0U; // CPU_SW_START + GpioCtrlRegs.GPCDIR.bit.GPIO67 = 0U; // CPU_SW_PWR + + GpioCtrlRegs.GPADIR.bit.GPIO12 = 1U; // GPIO_CPU_LED_SWITCH3 + GpioCtrlRegs.GPADIR.bit.GPIO13 = 1U; // GPIO_CPU_LED_SWITCH2 + GpioCtrlRegs.GPADIR.bit.GPIO14 = 1U; // GPIO_CPU_LED_SWITCH1 + GpioCtrlRegs.GPADIR.bit.GPIO26 = 1U; // GPIO_FUEL_PUMP_CS + GpioCtrlRegs.GPADIR.bit.GPIO27 = 1U; // GPIO_GLOW_PLUG_CS + GpioCtrlRegs.GPADIR.bit.GPIO28 = 1U; // GPIO_OLED_CS + GpioCtrlRegs.GPBDIR.bit.GPIO37 = 1U; // GPIO_OLED_RESET + GpioCtrlRegs.GPBDIR.bit.GPIO48 = 1U; // GPIO_STOP_SOLENOID_CS + GpioCtrlRegs.GPBDIR.bit.GPIO49 = 1U; // GPIO_ENGINE_HEATER_CS + GpioCtrlRegs.GPBDIR.bit.GPIO50 = 1U; // GPIO_COOLING_FAN1_CS + GpioCtrlRegs.GPBDIR.bit.GPIO51 = 1U; // GPIO_COOLING_FAN2_CS + GpioCtrlRegs.GPBDIR.bit.GPIO52 = 1U; // GPIO_COOLING_PUMP_CS + GpioCtrlRegs.GPBDIR.bit.GPIO55 = 1U; // GPIO_FAULT_CMD_CS + GpioCtrlRegs.GPCDIR.bit.GPIO65 = 1U; // GPIO_POWER_HOLD + GpioCtrlRegs.GPCDIR.bit.GPIO68 = 1U; // GPIO_CPU_LED_COM_FAULT + GpioCtrlRegs.GPCDIR.bit.GPIO69 = 1U; // GPIO_CPU_LED_COM_RUN + GpioCtrlRegs.GPCDIR.bit.GPIO70 = 1U; // GPIO_CPU_LED_COM_STA + + // GPAQSEL : 0b00 - Synchronize to SYSCLKOUT, 0b01 - Qualification 3 sample, 0b10 - Qualification 6 sample, 0b11 - Asynchronous + GpioCtrlRegs.GPAQSEL1.all = 0x0000U; // GPIO0-GPIO15 Synch to SYSCLKOUT + GpioCtrlRegs.GPAQSEL2.all = 0x0000U; // GPIO16-GPIO31 Synch to SYSCLKOUT + GpioCtrlRegs.GPBQSEL1.all = 0x0000U; // GPIO32-GPIO47 Synch to SYSCLKOUT + GpioCtrlRegs.GPBQSEL2.all = 0x0000U; // GPIO48-GPIO63 Synch to SYSCLKOUT + + GpioCtrlRegs.GPAQSEL1.bit.GPIO9 = 1U; // 3 Clk Sampling + GpioCtrlRegs.GPAQSEL1.bit.GPIO10 = 1U; // 3 Clk Sampling + GpioCtrlRegs.GPAQSEL1.bit.GPIO11 = 1U; // 3 Clk Sampling + GpioCtrlRegs.GPAQSEL2.bit.GPIO24 = 1U; // 3 Clk Sampling + GpioCtrlRegs.GPAQSEL2.bit.GPIO25 = 1U; // 3 Clk Sampling + + // Gpio Default Value Initial + GpioDataRegs.GPCSET.bit.GPIO65 = 1U; // GPIO_POWER_HOLD + + GpioDataRegs.GPCSET.bit.GPIO68 = 1U; // GPIO_CPU_LED_COM_FAULT_N + GpioDataRegs.GPCSET.bit.GPIO69 = 1U; // GPIO_CPU_LED_COM_RUN_N + GpioDataRegs.GPCSET.bit.GPIO70 = 1U; // GPIO_CPU_LED_COM_STA_N + + EDIS; +} + +void COffChipSelect(void) +{ + CSetAuxCtrlPin(IDX_CS_ENG_HEATER, 0U); + CSetAuxCtrlPin(IDX_CS_GLOW_PLUG, 0U); + CSetAuxCtrlPin(IDX_CS_SOLENOID, 0U); + CSetAuxCtrlPin(IDX_CS_FUEL_PUMP, 0U); + CSetAuxCtrlPin(IDX_CS_COOLANT_PUMP, 0U); + CSetAuxCtrlPin(IDX_CS_FAN1, 0U); + CSetAuxCtrlPin(IDX_CS_FAN2, 0U); +} + +static interrupt void CMainTimer0Interrupt(void) +{ + // Per 100uSec + + DINT; + + ulSoftClock = (ulSoftClock + 1U) % SYSTEM_10MIN_TIME; + + CProcessSoftTimer(); + // Do Something + + AdcRegs.ADCTRL2.bit.SOC_SEQ1 = 0x01U; // Adc Read Start + + PieCtrlRegs.PIEACK.all |= PIEACK_GROUP1; + EINT; +} + +static void CSystemConfigure(void) +{ + CMappingInterrupt(); + + CInitGeneralOperValue(); + + CInitAdc(); + CInitEcan(); + + CInitI2C(); + + CInitXintf(); + + CInitSoftTimers(); + + CInitKeyOperValue(); +} + +static void CInitGeneralOperValue(void) +{ + (void)memset(&GeneralOperValue, 0, sizeof(CGeneralOperValue)); + + GeneralOperValue.uiPassword[IDX_OLED_PASS_DIGIT_1] = 0; + GeneralOperValue.uiPassword[IDX_OLED_PASS_DIGIT_2] = 0; + GeneralOperValue.uiPassword[IDX_OLED_PASS_DIGIT_3] = 0; + GeneralOperValue.uiPassword[IDX_OLED_PASS_DIGIT_4] = 0; + + GeneralOperValue.EcuCommand.EngineStop = 1U; +} + +static void CMappingInterrupt(void) +{ + EALLOW; + + // Interrupt Vector Remapping + PieCtrlRegs.PIEIER1.bit.INTx7 = 0x1U; // TINT0 + PieCtrlRegs.PIEIER1.bit.INTx6 = 0x1U; // ADC + PieCtrlRegs.PIEIER9.bit.INTx5 = 0x1U; // ECAN0INTA + PieCtrlRegs.PIEIER9.bit.INTx7 = 0x1U; // ECAN0INTB + + PieVectTable.TINT0 = &CMainTimer0Interrupt; + PieVectTable.ECAN0INTA = &CECanInterruptA; + PieVectTable.ECAN0INTB = &CECanInterruptB; + PieVectTable.ADCINT = &CAdcInterrupt; + + IER = (Uint16)((Uint16)M_INT1 | (Uint16)M_INT9); + + EDIS; +} + +static void CProcessSoftTimer(void) +{ + Uint16 i; + + for (i = 0U; i < (Uint16)TIMER_MAX; i++) + { + if (SoftTimer[i].iTimer != -1) + { + if (SoftTimer[i].iStart == 1) + { + if (SoftTimer[i].ulDecreaseValue > 0UL) + { + SoftTimer[i].ulDecreaseValue--; + } + } + } + } +} + +static void CInitSoftTimers(void) +{ + CInitSoftTimer(); + CConfigSoftTimer(TIMER_01MS, TIME_01MS); + CConfigSoftTimer(TIMER_10MS, TIME_10MS); + CConfigSoftTimer(TIMER_20MS, TIME_20MS); + CConfigSoftTimer(TIMER_50MS, TIME_50MS); + CConfigSoftTimer(TIMER_100MS, TIME_100MS); + CConfigSoftTimer(TIMER_500MS, TIME_500MS); + + CStartSoftTimer(TIMER_01MS); + CStartSoftTimer(TIMER_10MS); + CStartSoftTimer(TIMER_20MS); + CStartSoftTimer(TIMER_50MS); + CStartSoftTimer(TIMER_100MS); + CStartSoftTimer(TIMER_500MS); +} + +static void CStartSoftTimer(Uint16 uiTimerIndex) +{ + if (SoftTimer[uiTimerIndex].iTimer != -1) + { + SoftTimer[uiTimerIndex].iStart = 1; + } +} + +static void CInitSoftTimer(void) +{ + Uint16 i; + + (void)memset(&SoftTimer, 0, sizeof(SoftTimer)); + (void)memset(&WaitTimer, 0, sizeof(WaitTimer)); + + for (i = 0; i < (Uint16)TIMER_MAX; i++) + { + SoftTimer[i].iTimer = -1; + } +} + +static void CConfigSoftTimer(Uint16 TimerIndex, Uint32 Delay) +{ + SoftTimer[TimerIndex].iTimer = (int16) TimerIndex; + SoftTimer[TimerIndex].ulSetValue = Delay; + SoftTimer[TimerIndex].ulDecreaseValue = Delay; + SoftTimer[TimerIndex].iStart = 0; +} + +static Uint16 CPowerOnCheck(void) +{ + Uint16 result = 1U; + Uint16 uiTemp = 0U; + Uint16 i; + + // Check EngineHeater V/I Sensor + uiTemp = ((Adc_EngineHeater_V.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_EngineHeater_V.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + uiTemp |= ((Adc_EngineHeater_I.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_EngineHeater_I.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + PowerOnCheckSensor[(Uint16)IDX_SENSOR_ENGINE_HEATER] = uiTemp; + + // Check GlowPlug V/I Sensor + uiTemp = ((Adc_GlowPlug_V.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_GlowPlug_V.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + uiTemp |= ((Adc_GlowPlug_I.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_GlowPlug_I.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + PowerOnCheckSensor[(Uint16)IDX_SENSOR_GLOW_PLUG] = uiTemp; + + // Check Solenoid V/I Sensor + uiTemp = ((Adc_Solenoid_V.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_Solenoid_V.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + uiTemp |= ((Adc_Solenoid_I.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_Solenoid_I.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + PowerOnCheckSensor[(Uint16)IDX_SENSOR_SOLENOID] = uiTemp; + + // Check FuelPump V/I Sensor + uiTemp = ((Adc_FuelPump_V.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_FuelPump_V.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + uiTemp |= ((Adc_FuelPump_I.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_FuelPump_I.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + PowerOnCheckSensor[(Uint16)IDX_SENSOR_FUEL_PUMP] = uiTemp; + + // Check CoolantPump V/I Sensor + uiTemp = ((Adc_CoolantPump_V.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_CoolantPump_V.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + uiTemp |= ((Adc_CoolantPump_I.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_CoolantPump_I.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + PowerOnCheckSensor[(Uint16)IDX_SENSOR_COOLANT_PUMP] = uiTemp; + + // Check Fan1 V/I Sensor + uiTemp = ((Adc_Fan1_V.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_Fan1_V.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + uiTemp |= ((Adc_Fan1_I.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_Fan1_I.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + PowerOnCheckSensor[(Uint16)IDX_SENSOR_FAN1] = uiTemp; + + // Check Fan2 V/I Sensor + uiTemp = ((Adc_Fan2_V.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_Fan2_V.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + uiTemp |= ((Adc_Fan2_I.iAdcValue > SENSOR_LOW_LIMIT) && (Adc_Fan2_I.iAdcValue < SENSOR_HIGH_LIMIT)) ? 0U : 1U; + PowerOnCheckSensor[(Uint16)IDX_SENSOR_FAN2] = uiTemp; + + for (i = 0U; i < (Uint16)IDX_SENSOR_MAX; i++) + { + if (PowerOnCheckSensor[i] > 0U) + { + result = 0U; + break; + } + } + return result; // '0' 정상 +} + +static void CInitI2C(void) +{ + /* I2C 모듈 리셋 */ + I2caRegs.I2CMDR.bit.IRS = 0U; + + /* + * 1. I2C 프리스케일러 (I2CPSC) 설정 + * SYSCLKOUT = 150MHz 기준 + * 10MHz = 150MHz / (14 + 1) -> I2CPSC = 14 + */ + I2caRegs.I2CPSC.all = 14U; + + /* + * 2. I2C 마스터 클럭 (SCL) 설정 + * 10MHz / 400kHz = 25 -> (I2CCLKL + 5) + (I2CCLKH + 5) = 25 + */ + //I2caRegs.I2CCLKL = 45U; // 100kHz + //I2caRegs.I2CCLKH = 45U; // 100kHz + I2caRegs.I2CCLKL = 8U; // 400kHz + I2caRegs.I2CCLKH = 7U; // 400kHz + + /* + * 3. I2C 핀 설정 (GPIO32/SDAA, GPIO33/SCLA) + */ + EALLOW; + GpioCtrlRegs.GPBPUD.bit.GPIO32 = 0U; /* Pull-up 활성화 (SDAA) */ + GpioCtrlRegs.GPBPUD.bit.GPIO33 = 0U; /* Pull-up 활성화 (SCLA) */ + + GpioCtrlRegs.GPBQSEL1.bit.GPIO32 = 3U; /* 비동기 입력 설정 */ + GpioCtrlRegs.GPBQSEL1.bit.GPIO33 = 3U; /* 비동기 입력 설정 */ + + GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1U; /* GPIO32를 SDAA로 설정 */ + GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1U; /* GPIO33을 SCLA로 설정 */ + EDIS; + + /* I2C 모듈 활성화 (리셋 해제 및 기본 설정 적용) */ + I2caRegs.I2CMDR.all = 0x0020U; +} + +static void CShutdownProcedure(void) +{ + if (KeyOperValue.KeyList.MainPower == 1U) + { + // 장치의 전원을 끄기 전 모든 제어상태를 정지 한다. + CSetGcuCommand((Uint16)IDX_GCU_CMD_STOP); + CSetEcuCommand((Uint16)IDX_ECU_CMD_EMERGENCY); + COffChipSelect(); + + if (GeneralOperValue.uiWriteEepromDataStart == 0U) + { + GeneralOperValue.uiWriteEepromDataStart = 1U; + } + + // 최대 3초 경과 후 꺼짐 + if (CSoftWaitCountProcedure(SOFTTIMER_WAIT_SHUTDOWN, (TIME_1SEC * 3U)) == (Uint16)TIME_OVER) + { + GpioDataRegs.GPCCLEAR.bit.GPIO65 = 1U; // GPIO_POWER_HOLD + } + } +} + +void CUpdateFault(Uint32 *pData, Uint16 uiIdx, Uint16 uiCond) +{ + Uint32 ulMask; + + if (pData != NULL) + { + ulMask = 1UL << (Uint32)uiIdx; + *pData = (uiCond != 0U) ? (*pData | ulMask) : (*pData & ~ulMask); + } +} + +Uint16 CIsBitSet(Uint32 ulData, Uint16 uiIdx) +{ + Uint32 ulMask; + + ulMask = 1UL << (Uint32)uiIdx; + + return (((ulData & ulMask) != 0UL) ? 1U : 0U); +} + +void DELAY_USEC(Uint32 ulMicroSeconds) +{ + Uint32 ulDelayCount; + + ulDelayCount = (Uint32)((float64)(((((float64)ulMicroSeconds * 1000.0L) / (float64)CPU_RATE) - 9.0L) / 5.0L)); + + DSP28x_usDelay(ulDelayCount); +} + +void CSetAuxCtrlPin(E_AUX_CS_IDX eIdx, Uint16 uiState) +{ + switch (eIdx) + { + case IDX_CS_ENG_HEATER: + { + if (uiState == 1U) { GpioDataRegs.GPBSET.bit.GPIO49 = 1U; } + else { GpioDataRegs.GPBCLEAR.bit.GPIO49 = 1U; } + break; + } + case IDX_CS_GLOW_PLUG: + { + if (uiState == 1U) { GpioDataRegs.GPASET.bit.GPIO27 = 1U; } + else { GpioDataRegs.GPACLEAR.bit.GPIO27 = 1U; } + break; + } + case IDX_CS_SOLENOID: + { + if (uiState == 1U) { GpioDataRegs.GPBSET.bit.GPIO48 = 1U; } + else { GpioDataRegs.GPBCLEAR.bit.GPIO48 = 1U; } + break; + } + case IDX_CS_FUEL_PUMP: + { + if (uiState == 1U) { GpioDataRegs.GPASET.bit.GPIO26 = 1U; } + else { GpioDataRegs.GPACLEAR.bit.GPIO26 = 1U; } + break; + } + case IDX_CS_COOLANT_PUMP: + { + if (uiState == 1U) { GpioDataRegs.GPBSET.bit.GPIO52 = 1U; } + else { GpioDataRegs.GPBCLEAR.bit.GPIO52 = 1U; } + break; + } + case IDX_CS_FAN1: + { + if (uiState == 1U) { GpioDataRegs.GPBSET.bit.GPIO50 = 1U; } + else { GpioDataRegs.GPBCLEAR.bit.GPIO50 = 1U; } + break; + } + default: + { + if (eIdx == IDX_CS_FAN2) + { + if (uiState == 1U) { GpioDataRegs.GPBSET.bit.GPIO51 = 1U; } + else { GpioDataRegs.GPBCLEAR.bit.GPIO51 = 1U; } + } + break; + } + } +} diff --git a/Source/main.h b/Source/main.h new file mode 100644 index 0000000..4ed1fc4 --- /dev/null +++ b/Source/main.h @@ -0,0 +1,254 @@ +#ifndef SOURCE_MAIN_H_ +#define SOURCE_MAIN_H_ + +#include +#include "DSP28x_Project.h" +#include "DSP2833x_Device.h" +#include "State.h" +#include "Oper.h" +#include "Display.h" +#include "Comm.h" + +#define AUX_TEST + +#define true (1U) +#define false (0U) + +// Key Input Port (Lo Active) +#define GPIO_KEY_UP() (GpioDataRegs.GPBDAT.bit.GPIO39) // LOW Active +#define GPIO_KEY_DOWN() (GpioDataRegs.GPADAT.bit.GPIO31) // LOW Active +#define GPIO_KEY_ENTER() (GpioDataRegs.GPADAT.bit.GPIO30) // LOW Active +#define GPIO_KEY_MENU() (GpioDataRegs.GPADAT.bit.GPIO29) // LOW Active +#define GPIO_KEY_POWER() (GpioDataRegs.GPCDAT.bit.GPIO67) // LOW Active +#define GPIO_KEY_START() (GpioDataRegs.GPCDAT.bit.GPIO66) // LOW Active +#define GPIO_KEY_EMERGENCY() (GpioDataRegs.GPCDAT.bit.GPIO64) // LOW Active +#define GPIO_KEY_REMOTE_START() (GpioDataRegs.GPBDAT.bit.GPIO58) // LOW Active +#define GPIO_KEY_REMOTE_STOP() (GpioDataRegs.GPBDAT.bit.GPIO57) // LOW Active +#define GPIO_KEY_REMOTE_EMERGENCY() (GpioDataRegs.GPBDAT.bit.GPIO56) // LOW Active + +// Read ChipSelect State +#define ENGINE_HEATER_OUT() (GpioDataRegs.GPBDAT.bit.GPIO49) // HIGH is Active +#define GLOW_PLUG_OUT() (GpioDataRegs.GPADAT.bit.GPIO27) // HIGH is Active +#define SOLENOID_OUT() (GpioDataRegs.GPBDAT.bit.GPIO48) // HIGH is Active +#define FUEL_PUMP_OUT() (GpioDataRegs.GPADAT.bit.GPIO26) // HIGH is Active +#define COOLANT_PUMP_OUT() (GpioDataRegs.GPBDAT.bit.GPIO52) // HIGH is Active +#define FAN1_OUT() (GpioDataRegs.GPBDAT.bit.GPIO50) // HIGH is Active +#define FAN2_OUT() (GpioDataRegs.GPBDAT.bit.GPIO51) // HIGH is Active + +// Active Read From ECU +#define GPIO_ENGINE_HEATER_ACTIVE() (GpioDataRegs.GPADAT.bit.GPIO24) // LOW is Active +#define GPIO_GLOW_PLUG_ACTIVE() (GpioDataRegs.GPADAT.bit.GPIO10) // LOW is Active +#define GPIO_SOLENOID_ACTIVE() (GpioDataRegs.GPADAT.bit.GPIO11) // LOW is Active +#define GPIO_FUEL_PUMP_ACTIVE() (GpioDataRegs.GPADAT.bit.GPIO9) // LOW is Active + +// Fail-Safe Enable(ECU HW Emergency) +#define GPIO_FAIL_SAFE_READ() (GpioDataRegs.GPADAT.bit.GPIO25) // LOW is Active + +// Auxiliary Read all +#define STATUS_BIT_HEATER (0) +#define STATUS_BIT_GLOW (1) +#define STATUS_BIT_SOLENOID (2) +#define STATUS_BIT_FUEL (3) +#define STATUS_BIT_COOLANT (4) +#define STATUS_BIT_FAN1 (5) +#define STATUS_BIT_FAN2 (6) + +#define GET_ALL_AUX_STATUS() \ +( \ + (GpioDataRegs.GPBDAT.bit.GPIO49 << STATUS_BIT_HEATER) | \ + (GpioDataRegs.GPADAT.bit.GPIO27 << STATUS_BIT_GLOW) | \ + (GpioDataRegs.GPBDAT.bit.GPIO48 << STATUS_BIT_SOLENOID) | \ + (GpioDataRegs.GPADAT.bit.GPIO26 << STATUS_BIT_FUEL) | \ + (GpioDataRegs.GPBDAT.bit.GPIO52 << STATUS_BIT_COOLANT) | \ + (GpioDataRegs.GPBDAT.bit.GPIO50 << STATUS_BIT_FAN1) | \ + (GpioDataRegs.GPBDAT.bit.GPIO51 << STATUS_BIT_FAN2) \ +) + +/* Comment Description + * [!] : 변경시 주의 + * [?] : 결정이 필요 + * [*] : 주의보다 더 엄중 + */ + +/* Firmware 버전 (Semantic Versioning) */ +#define FIRMWARE_VERSION_MAJOR (0) // 하위버전과 호환 되지 않는 변화가 생길 때 증가, 대대적인 변화가 있을 때 +#define FIRMWARE_VERSION_MINOR (1) // 하위버전과 호환 되면서 새로운 기능이 생길 때 증가, 기존 기능이 변경되거나 사용 방법이 변경 될 때 +#define FIRMWARE_VERSION_PATCH (9) // 하위버전과 호환 되면서 버그 수정, 기능적으로 변경된것을 알아차리지 못할 정도의 소소한 변경이 있을 때 + +/* Version History + * [0.0.1] : DCU 프로젝트 생성 + * [0.0.2] : DCU 펌웨어 탑재 성공 + * [0.0.3] : OLED XINTF(BUS) 방식 드라이브단 구현 + * [0.0.4] : OLED 표시 화면 구현 + * [0.0.5] : CAN-B 확인 및 맵핑 + * [0.0.6] : 시동 시퀀스 구현 및 정비 화면 수정 + * [0.1.6] : Suter 보조엔진 시동 완료 시점 + * [0.1.7] : 발전상태 전환 조건 추가 26-02-23 + * [0.1.8] : 장치 운용시간 로직 추가(Eeprom 사용), define USE_EEPROM 26-03-16 <삭제> + * [0.1.9] : IPS 회로 변경으로 전압센싱 추가 및 고장 알람 비트 추가, CAN-A 채널 송신 데이터 추가 26-03-26 + */ + +#define MAINTENECE_PASSKEY {0,0,0,0} + +#define ENABLED (1) +#define DISABLED (!ENABLED) + +/* + * Bit mask + */ +#define MASK_LOW_NIBBLE (0x0FU) +#define MASK_HIGH_NIBBLE (0xF0U) +#define MASK_BYTE (0xFFU) +#define MASK_WORD (0xFFFFU) +#define MASK_6BIT (0x3FU) +#define MASK_26BIT (0x3FFFFFFUL) + +/* +Timer Clock Per 100us +*/ +#define SYSTEM_10MIN_TIME (6000000UL) +#define TIME_01MS (10UL) +#define TIME_10MS (100UL) +#define TIME_20MS (200UL) +#define TIME_50MS (500UL) +#define TIME_100MS (1000UL) +#define TIME_500MS (5000UL) +#define TIME_1SEC (10000UL) +#define TIME_5SEC (50000UL) +#define TIME_10SEC (100000UL) +#define TIME_60SEC (600000UL) + +// 전압/전류센서 AdcRefValue 기준값 전압:2300, 전류:2250 +#define SENSOR_LOW_LIMIT (2000) // 단선 +#define SENSOR_HIGH_LIMIT (4000) // 단락 + +#define TIME_OVER (1U) + +enum +{ + TIMER_01MS = 0U, + TIMER_10MS, + TIMER_20MS, + TIMER_50MS, + TIMER_100MS, + TIMER_500MS, + TIMER_1SEC, + TIMER_MAX +}; + +enum +{ + SOFTTIMER_TIME_OVER = 0U, + SOFTTIMER_RUNNING, + SOFTTIMER_PAUSE, + SOFTTIMER_DONT_EXIST +}; + +enum +{ + SOFTTIMER_WAIT_INIT = 0U, + SOFTTIMER_WAIT_ALARM_RESET, + SOFTTIMER_WAIT_ENG_COOLDOWN, + SOFTTIMER_WAIT_PREHEAT, + SOFTTIMER_WAIT_CRANKING, + SOFTTIMER_WAIT_RETRY_CRANKING, + SOFTTIMER_WAIT_OPERATION, + SOFTTIMER_WAIT_SHUTDOWN, + SOFTTIMER_WAIT_AFTER_COOLDOWN, + SOFTTIMER_WAIT_MAX +}; + +typedef enum +{ + IDX_CS_ENG_HEATER = 0, + IDX_CS_GLOW_PLUG, + IDX_CS_SOLENOID, + IDX_CS_FUEL_PUMP, + IDX_CS_COOLANT_PUMP, + IDX_CS_FAN1, + IDX_CS_FAN2, + IDX_CS_MAX +} E_AUX_CS_IDX; + +typedef struct ClassSoftTimer +{ + Uint32 ulSetValue; + Uint32 ulDecreaseValue; + int16 iTimer; + int16 iStart; +} CSoftTimer; + +typedef struct ClassWaitTimer +{ + Uint32 ulCountSoftClock; + Uint16 uiSoftCountTarget; +} CWaitTimer; + +typedef enum +{ + IDX_SENSOR_ENGINE_HEATER = 0U, // 0 + IDX_SENSOR_GLOW_PLUG, // 1 + IDX_SENSOR_SOLENOID, // 2 + IDX_SENSOR_FUEL_PUMP, // 3 + IDX_SENSOR_COOLANT_PUMP, // 4 + IDX_SENSOR_FAN1, // 5 + IDX_SENSOR_FAN2, // 6 + IDX_SENSOR_MAX // 7 +} E_IDX_SENSOR; + +typedef struct ClassGeneralOperValue +{ + Uint16 uiFaultOccured; + Uint16 uiDynamicRPM; + Uint16 uiPassword[4]; + Uint16 uiSelfTestCheck; + Uint16 uiSelfTestPass; + Uint16 uiEmergency; + Uint16 uiApuStart; + Uint16 uiApuState; + Uint16 uiAlarmReset; + Uint16 uiMaintenance; + Uint16 uiRetryCrankingCount; + Uint16 uiWriteEepromDataStart; + Uint32 ulTotalOperationHour; + Uint32 ulRampStartClock; // IDLE_SEQ_MOD + Uint16 uiRampComplete; // IDLE_SEQ_MOD + struct + { + Uint16 PlayCmd; + } GcuCommand; + struct + { + Uint16 EngineStart; + Uint16 EngineStop; + Uint16 RpmSetPoint; + Uint16 ActiveOverride; + Uint16 EmergencyStop; + } EcuCommand; + struct + { + Uint16 CarComputer; + Uint16 Gcu; + Uint16 Ecu; + } Conection; + struct + { + Uint16 ManualCranking; + Uint16 LampTest; + Uint16 KeyTest; + } Maintenance; +} CGeneralOperValue; + +extern CGeneralOperValue GeneralOperValue; +extern Uint16 PowerOnCheckSensor[IDX_SENSOR_MAX]; + +Uint16 CSoftWaitCountProcedure(Uint16 uiIndex, Uint32 ulWaitTime); +void COffChipSelect(void); +void CSoftWaitCountClear(Uint16 Index); +Uint32 CGetSoftClock(void); +void CUpdateFault(Uint32 *pData, Uint16 uiIdx, Uint16 uiCond); +void DELAY_USEC(Uint32 ulMicroSeconds); +Uint16 CIsBitSet(Uint32 ulData, Uint16 uiIdx); +void CSetAuxCtrlPin(E_AUX_CS_IDX eIdx, Uint16 uiState); + +#endif /* SOURCE_MAIN_H_ */