From ac74d913e9371a2e92f753bbdb67f37171b4b835 Mon Sep 17 00:00:00 2001 From: hosu Date: Tue, 14 Apr 2026 14:14:40 +0900 Subject: [PATCH] first commit --- .vscode/c_cpp_properties.json | 16 + Comm.c | 1436 ++++++++++++++++++++++++ Comm.h | 696 ++++++++++++ Display.c | 1979 +++++++++++++++++++++++++++++++++ Display.h | 156 +++ Oper.c | 647 +++++++++++ Oper.h | 63 ++ State.c | 1296 +++++++++++++++++++++ State.h | 219 ++++ main.c | 730 ++++++++++++ main.h | 254 +++++ 11 files changed, 7492 insertions(+) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 Comm.c create mode 100644 Comm.h create mode 100644 Display.c create mode 100644 Display.h create mode 100644 Oper.c create mode 100644 Oper.h create mode 100644 State.c create mode 100644 State.h create mode 100644 main.c create mode 100644 main.h diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..b1f27e8 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/Comm.c b/Comm.c new file mode 100644 index 0000000..e4c2839 --- /dev/null +++ b/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/Comm.h b/Comm.h new file mode 100644 index 0000000..ac6c5f1 --- /dev/null +++ b/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/Display.c b/Display.c new file mode 100644 index 0000000..8f9a561 --- /dev/null +++ b/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/Display.h b/Display.h new file mode 100644 index 0000000..b726996 --- /dev/null +++ b/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/Oper.c b/Oper.c new file mode 100644 index 0000000..dd67862 --- /dev/null +++ b/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/Oper.h b/Oper.h new file mode 100644 index 0000000..249ad5b --- /dev/null +++ b/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/State.c b/State.c new file mode 100644 index 0000000..b4627d6 --- /dev/null +++ b/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/State.h b/State.h new file mode 100644 index 0000000..20a2214 --- /dev/null +++ b/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/main.c b/main.c new file mode 100644 index 0000000..80e80f2 --- /dev/null +++ b/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/main.h b/main.h new file mode 100644 index 0000000..4e4edfd --- /dev/null +++ b/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_ */