/* ========================================================================= */ /* 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, " ", 1); } } } 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; if (type == 0U) // Eng Char { uiCharWidth = (Uint16)TXT_ENG_WIDTH; ch -= 0x20U; // font offset ch = (ch > 95U) ? 0U : ch; pFontData = EngFontTable[ch]; } 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]; 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); }