diff --git a/README.md b/README.md index d3176e8..37efce2 100644 --- a/README.md +++ b/README.md @@ -6,42 +6,60 @@ Windows 기반 Air Leak Test 장비를 위한 제어 및 모니터링 GUI 프로 ```text leak_test_project/ -├── Infrastructure/ # 하드웨어 통신 계층 (Low-Level Communication) +├── Infrastructure/ # 하드웨어 통신 및 DIO 계층 (Low-Level Communication) │ ├── ICommunication.cs # 통신 방식(Serial, TCP) 추상화 인터페이스 -│ └── SerialProvider.cs # RS232 시리얼 통신 구현체 (8N1, IDisposable) +│ ├── SerialProvider.cs # RS232 시리얼 통신 구현체 (8N1, IDisposable) +│ ├── IDioBoard.cs # DIO 보드 추상화 인터페이스 (입출력 제어, 이벤트) +│ ├── RealDioBoard.cs # ADLINK PCI DIO 보드 실제 구현체 (10ms 폴링) +│ └── Dask.cs # ADLINK PCIS-DASK API P/Invoke 래퍼 ├── Models/ # 데이터 모델 -│ ├── AppConfig.cs # 앱 설정 (Port, BaudRate, Spec UL/LL) -│ ├── InOutItem.cs # I/O 항목 모델 (Address, Name, Description) -│ ├── InspectData.cs # 검사 결과 데이터 모델 -│ └── ParsedData.cs # Sentinel C28 파싱 결과 모델 +│ ├── AppConfig.cs # 앱 설정 (Left/Right/SensorPort, Zmdi/SensorBaudRate, SpecUL/LL) +│ ├── DioPoint.cs # DIO 포인트 모델 (Name, IsInput, Value) + DioEventArgs +│ ├── InOutItem.cs # I/O 항목 모델 (Address, Name, Description, Value) +│ ├── InspectData.cs # 검사 결과 데이터 모델 (12개 필드) +│ ├── ParsedData.cs # Sentinel C28 파싱 결과 모델 (MeasuredValue, SensorJudgment 등) +│ └── SensorIdData.cs # ZMDI 센서 ID 데이터 모델 (LowID, Year/Month/Day, Serial 등) ├── Services/ # 비즈니스 로직 및 기기 제어 -│ ├── IoBoardService.cs # I/O 보드 서비스 (더미 데이터, LEFT/RIGHT 구분) -│ └── SentinelC28Service.cs # Sentinel C28 프로토콜 (자동 재연결 포함) +│ ├── DioBoardFactory.cs # DIO 보드 팩토리 (DioConfig.ini 기반 보드 생성) +│ ├── IoBoardService.cs # I/O 보드 서비스 (IDioBoard 연동, 상태 갱신/출력 제어) +│ ├── SentinelC28Service.cs # Sentinel C28 프로토콜 (자동 재연결 포함) +│ ├── TestProcessService.cs # 자동 시험 프로세스 (DIO→센서→시험→판정→출력 사이클) +│ └── ZmdiSensorService.cs # ZMDI 센서 시리얼 통신 (ID 읽기/파싱, 4단계 명령) ├── Utils/ # 유틸리티 -│ ├── ConfigManager.cs # XML 기반 설정 관리 (Load/Save) +│ ├── ConfigManager.cs # XML 기반 설정 관리 (Load/Save, ConfigChanged 이벤트) │ ├── CsvExporter.cs # 범용 CSV 내보내기 +│ ├── DioConfigParser.cs # INI 형식 DIO 설정 파서 (보드 타입, 포인트 매핑) │ ├── FileLogger.cs # 일일 CSV 로그 자동 저장 + 시스템 로그 │ ├── LogParser.cs # CSV 로그 파싱 및 검색 필터링 │ ├── SentinelCrc8.cs # CRC-8 체크섬 계산 -│ └── SentinelParser.cs # C28 데이터 파싱 (스트리밍/최종결과) +│ └── SentinelParser.cs # C28 데이터 파싱 (스트리밍/최종결과/판정) ├── ViewModels/ # MVVM ViewModel │ ├── Core/ │ │ ├── ObservableObject.cs # INotifyPropertyChanged 베이스 클래스 │ │ └── RelayCommand.cs # ICommand 구현 -│ ├── DataViewModel.cs # 데이터 조회/CSV 내보내기 로직 -│ ├── HomeViewModel.cs # 2채널 통신, 측정, 판정, 로그 기록 +│ ├── DataViewModel.cs # 데이터 조회/CSV 내보내기/더미 데이터 로드 +│ ├── HomeViewModel.cs # 2채널 자동 시험, ZMDI/C28 통신, SPEC 교차 검증 │ ├── InOutViewModel.cs # I/O 모니터 페이징 로직 -│ ├── MainViewModel.cs # 화면 전환 및 앱 생명주기 관리 -│ └── ParametersViewModel.cs # 파라미터 설정 (예비) +│ ├── MainViewModel.cs # 화면 전환, DIO 보드 생성, 앱 생명주기 관리 +│ └── ParametersViewModel.cs # 파라미터 설정 (빈 클래스, 로직은 Window에서 직접 처리) ├── Views/ # UI 화면 │ ├── CommunicationWindow.xaml(.cs) # 통신 설정 (포트/보드레이트) │ ├── DataView.xaml(.cs) # 검사 이력 조회/검색/CSV 저장 │ ├── HomeView.xaml(.cs) # 좌/우 2채널 시험 모니터링 -│ ├── InOutView.xaml(.cs) # I/O 모니터 (LEFT/RIGHT 구분) +│ ├── InOutView.xaml(.cs) # I/O 모니터 (INPUT/OUTPUT 구분) │ └── ParametersWindow.xaml(.cs) # SPEC UL/LL 설정 +├── Manual/ # 사용자 매뉴얼 +│ ├── Communication_Manual.md # 통신 설정 매뉴얼 +│ ├── DataView_Manual.md # 데이터 조회 매뉴얼 +│ ├── HomeView_Manual.md # 메인 화면 매뉴얼 +│ ├── IO_Monitor_Manual.md # I/O 모니터 매뉴얼 +│ └── Parameter_Manual.md # 파라미터 설정 매뉴얼 +├── PCI-Dask.dll # ADLINK PCIS-DASK 네이티브 DLL ├── App.xaml # DataTemplate 매핑 + 공통 스타일 ├── MainWindow.xaml # 메인 Shell (상단바 + 하단 메뉴) └── MainWindow.xaml.cs # 시계, 창 관리, 종료 확인 + +leak_test_project.Tests/ # 단위 테스트 프로젝트 (xUnit/NUnit) ``` ## ✨ 주요 기능 @@ -50,64 +68,91 @@ leak_test_project/ - 좌(LEFT) / 우(RIGHT) 독립 2채널 기밀 시험 상태 실시간 표시 - 측정값(sccm), SPEC 범위(UL/LL), 판정(OK/NG) 실시간 확인 - 판정 결과에 따른 배경색 자동 변경 (OK=녹색, NG=빨간색) -- 하단 제품/센서 통신 로그 출력 (최대 500줄 유지, 자동 스크롤) - -### 2. Sentinel C28 통신 제어 -- **RS-232 시리얼 통신**: 기본 115200 baud, 8N1 +- 좌/우 채널별 상태(Status) 및 오류(Error) 메시지 표시 +- ZMDI 센서 ID 정보 (LowID, 제조일, 시리얼, 라인, 제품 구분) 실시간 표시 + +### 2. 자동 시험 프로세스 (TestProcessService) +DIO 시작 신호를 기반으로 좌/우 독립 백그라운드 스레드에서 아래 사이클을 반복합니다: + +1. **DIO 시작 신호 대기**: LEFT_START / RIGHT_START 입력 신호 OFF→ON 감지 +2. **ZMDI 센서 ID 읽기**: 4단계 시리얼 명령 시퀀스로 제품 ID 파싱 +3. **불량 제품 필터링**: 센서의 이전 검사 결과(PrevResult) 확인 +4. **LEAK 시험 수행**: Sentinel C28 최종 결과 수신 대기 (30초 타임아웃) +5. **판정**: 프로그램 SPEC(UL/LL) 기반 OK/NG 판정 +6. **SPEC 교차 검증**: 프로그램 판정과 센서 자체 판정(A/R) 비교, 불일치 시 경고 +7. **로그 기록**: 일일 CSV 파일에 검사 결과 자동 저장 +8. **DIO 출력**: 판정 결과에 따라 OK/NG 출력 신호 전송 + +### 3. DIO 보드 제어 (ADLINK PCI) +- **ADLINK PCI DIO 보드** 연동 (PCIS-DASK API 사용) +- **INI 설정 기반** 입출력 포인트 매핑 (`Settings/DioConfig.ini`) +- **10ms 입력 폴링**: 백그라운드 Task에서 입력 상태 주기적 감시 +- **PC_ON 출력**: 프로그램 시작 시 가동 신호 ON, 종료 시 OFF +- **지원 보드 타입**: PCI_7230, PCI_7432, PCI_7433, PCI_7434, PCI_7250 + +### 4. Sentinel C28 통신 제어 +- **RS-232 시리얼 통신**: 기본 9600 baud, 8N1 - **표준 프로토콜 준수**: 헤더(XXYYZZZ H) + CRC-8 체크섬 자동 생성 - **다중 데이터 처리**: 최종 결과(R), 실시간 스트리밍(S), 메시지(M) 구분 수신 -- **자동 재연결**: 연결 끊김 시 5초 간격 자동 재연결 시도 +- **자동 재연결**: 연결 끊김 시 **1초(1000ms) 간격**으로 모든 통신(C28, ZMDI)의 자동 복구를 시도하여 사용자 개입 최소화 - **확장성**: ICommunication 인터페이스 기반으로 TCP/IP 등 통신 방식 변경 가능 -### 3. 입출력 모니터 (In/Out Monitor) -- INPUT / OUTPUT 신호 상태 확인 (LEFT/RIGHT 구분) +### 5. 입출력 모니터 (In/Out Monitor) +- INPUT / OUTPUT 신호 상태 확인 (실제 DIO 보드 연동) +- **500ms 주기 자동 갱신**: 별도의 새로고침 버튼 없이 DIO 상태가 실시간 업데이트 - 페이지당 30개씩 데이터 표시 및 페이징 기능 (FIRST/PREV/NEXT/LAST) +- 화면 닫기(Close) 시 자동 갱신 타이머 정지 -### 4. 데이터 이력 조회 (Data) +### 6. 데이터 이력 조회 (Data) - 기간별, 판정 결과별(OK/NG/전체), 시리얼 번호별 필터링 검색 - 일일 CSV 로그 자동 저장 (검사 완료 시 `Logs/yyyy-MM-dd.csv`에 즉시 기록) - 조회된 데이터를 별도 CSV 파일로 내보내기 가능 -- 빈 화면에서도 엑셀 시트처럼 항상 표 격자(GridLines)가 유동적으로 유지되도록 표출 전용 패딩 적용 -- 로그 파일이 없는 경우 더미 데이터 자동 생성 +- 빈 화면에서도 엑셀 시트처럼 항상 표 격자(GridLines)가 유동적으로 유지되도록 최소 50행 표출 +- 테스트용 더미 데이터 수동 로드 기능 (버튼 클릭으로 10건 샘플 데이터 생성) -### 5. 설정 관리 +### 7. 설정 관리 - **파라미터 설정**: SPEC UL/LL (sccm) 값 설정 및 저장 -- **통신 설정**: 좌/우 메인(ZMDI) 장비 포트와 센서(Leak Sensor) 포트의 통신 속도를 각각 독립적으로 분리 설정 (ZMDI 기본 19200, 센서 기본 9600) -- **XML 설정 파일**: `config.xml`에 자동 저장/로드, 설정 변경 시 실시간 반영 +- **통신 설정**: 좌/우 ZMDI 장비 포트(기본 COM9/COM8, 보드레이트 공유 19200)와 센서 포트(기본 COM1, 보드레이트 9600)를 각각 독립 설정 +- **XML 설정 파일**: `config.xml`에 자동 저장/로드, 설정 변경 시 `ConfigChanged` 이벤트를 통해 모든 통신 서비스(Sentinel C28, ZMDI 센서)와 자동 시험 프로세스가 재시작되어 즉시 반영 +- **DIO 설정 파일**: `Settings/DioConfig.ini`에서 보드 타입, 입출력 포인트 이름/설명 관리 -### 6. 일일 CSV 로그 자동 저장 +### 8. 일일 CSV 로그 자동 저장 - 검사 완료 시 `Logs/yyyy-MM-dd.csv` 파일에 자동 기록 - CSV 헤더: Date, Time, Channel, ID, Value, Judgment, Mode, LineNo, ProductType, SpecUL, SpecLL, Retest - CSV 값 이스케이프 처리 (쉼표/따옴표/줄바꿈 안전 처리) - 시스템 텍스트 로그는 `yyyy-MM-dd_system.log`로 별도 관리 -### 7. 프로그램 안정성 +### 9. 프로그램 안정성 - 프로그램 종료 전 확인 대화상자 표시 -- 시리얼 포트, 타이머 등 리소스 종료 시 안전 해제 +- 시리얼 포트, DIO 보드, 타이머 등 리소스 종료 시 안전 해제 (IDisposable 패턴) - 모든 통신/파일 I/O 구간에 예외 처리 적용 -- UI 로그 메모리 누수 방지 (최대 500줄 제한) +- ZMDI 통신 명령 실패 시 최대 3회 재시도 +- **포트 연결 알림**: 프로그램 초기화 또는 설정 변경 시 모든 포트(C28, ZMDI Left/Right)의 연결 상태를 즉시 확인하고, 하나라도 실패 시 메인 화면 오류 영역에 즉시 표시 (상세 오류 원인 및 포트 번호 포함) +- **1초 자동 복구**: 모든 통신 포트에 대해 1초 주기로 상시 자동 재연결 시도 (재진입 방지 포함) +- **통신 설정 변경 반영**: 설정 저장 시 즉시 통신 포트와 자동 시험 프로세스를 재시작하여 프로그램 재시작 없이 설정 변경 내용 적용 가능 ## 📡 기기 통신 프로토콜 및 명령어 (Command Details) 프로그램에서 사용하는 주요 하드웨어 통신 명령어 및 절차입니다. ### 1. ZMDI 센서 (ID 읽기 및 파싱) -ZMDI 센서와의 통신은 `19200 Baud, 8N1` 시리얼 통신을 사용하며, 총 4단계의 명령어 시퀀스로 구성됩니다. 모든 명령어는 `\r\n`을 포함하여 전송됩니다. +ZMDI 센서와의 통신은 `19200 Baud, 8N1` 시리얼 통신을 사용하며, 총 4단계의 명령어 시퀀스로 구성됩니다. 모든 명령어는 `\r\n`을 포함하여 전송되며, 최대 3회 재시도합니다. | 단계 | 역할 | 주요 명령어 리스트 | | :--- | :--- | :--- | | **1단계** | 초기화 및 통신 확인 | `V`, `Pr_D7`, `Pr_D6`, `Pr_D5`, `r` | | **2단계** | 메모리 접근 준비 | `tso31150` | -| **3단계** | 데이터 수집 설정 | `os_10`, `t11005`, `OWT7800272D1`, `OR_78002`, `OW_78003...` | -| **4단계** | ID 메모리 읽기 | `OW_7800140`, `OR_78002`, `OW_7800141`, `OR_78002` 등 | +| **3단계** | 데이터 수집 설정 | `os_10`, `t11005`, `OWT7800272D1`, `OR_78002`, `OW_780038AA55A`, `OW_780011A`, `OR_78002`, `OW_780038AFF00`, `OW_78001CF`, `OR_78004` | +| **4단계** | ID 메모리 읽기 | `OW_7800140`, `OR_78002`, `OW_7800141`, `OR_78002`, `OW_7800142`, `OR_78002`, `x9c_990:x` | - **읽기 종료**: 모든 데이터를 읽은 후 `x9c_990:x` 명령으로 세션을 종료합니다. - **데이터 파싱**: `OR_78002`의 응답값들을 조합하여 12자리 이상의 `LowID`를 생성하고, 이를 디코딩 테이블에 따라 년/월/일/시리얼/라인/아이템 정보를 추출합니다. +- **불량 필터링**: 파싱된 `PrevResult` 필드로 이전 검사 결과를 확인하여 불량 제품을 필터링합니다. --- ### 2. Sentinel C28 (Leak Test 장비) -Sentinel C28과의 통신은 `115200 Baud, 8N1` 시리얼 통신을 사용하며, 전용 바이너리/텍스트 혼합 프로토콜을 사용합니다. +Sentinel C28과의 통신은 `9600 Baud, 8N1` 시리얼 통신을 사용하며, 전용 바이너리/텍스트 혼합 프로토콜을 사용합니다. - **명령어 구조**: `[CRC-8][Sequence][Length] [Type][Command]\r\n` - `CRC-8`: 헤더와 페이로드를 포함한 8비트 체크섬 (2자리 Hex) @@ -120,6 +165,31 @@ Sentinel C28과의 통신은 `115200 Baud, 8N1` 시리얼 통신을 사용하며 - `R (Result)`: 최종 검사 완료 후 수신되는 결과 데이터 (채널#, 시리얼, 측정값, 판정 등 포함) - `S (Streaming)`: 시험 진행 중 실시간으로 수신되는 압력/유량 데이터 +- **SPEC 교차 검증**: C28 센서의 자체 판정(A=Accept, R=Reject)과 프로그램의 UL/LL 기반 판정을 비교하여 불일치 시 경고 메시지를 표시합니다. + +--- + +### 3. ADLINK DIO 보드 +ADLINK PCI DIO 보드와의 통신은 PCIS-DASK API(PCI-Dask.dll)를 사용합니다. + +- **설정 파일**: `Settings/DioConfig.ini` (INI 형식) + - `[DIO]`: CompanyName + - `[BOARD_1]`: BoardType, BoardNumber + - `[BOARD_1_IN]`: 입력 포인트 매핑 (LEFT_START, RIGHT_START 등) + - `[BOARD_1_OUT]`: 출력 포인트 매핑 (LEFT_OK, RIGHT_OK, LEFT_NG, RIGHT_NG, PC_ON 등) + +- **기본 입출력 신호**: + +| 구분 | 포인트 이름 | 설명 | +| :--- | :--- | :--- | +| INPUT | `LEFT_START` | 좌측 시험 시작 신호 | +| INPUT | `RIGHT_START` | 우측 시험 시작 신호 | +| OUTPUT | `LEFT_OK` | 좌측 합격 출력 | +| OUTPUT | `RIGHT_OK` | 우측 합격 출력 | +| OUTPUT | `LEFT_NG` | 좌측 불합격 출력 | +| OUTPUT | `RIGHT_NG` | 우측 불합격 출력 | +| OUTPUT | `PC_ON` | PC 가동 신호 | + --- ## 🛠 유지보수 가이드 @@ -129,8 +199,23 @@ Sentinel C28과의 통신은 `115200 Baud, 8N1` 시리얼 통신을 사용하며 - **CRC 알고리즘**: 제조사 사양서에 정확한 다항식이 명시되어 있다면 `Utils/SentinelCrc8.cs` 교체 필요 - **화면 및 스타일**: `Views/`의 `.xaml` 파일과 `App.xaml`에서 통합 관리 - **설정 항목 추가**: `Models/AppConfig.cs`에 프로퍼티 추가 후 해당 설정 화면 UI 수정 +- **DIO 포인트 변경**: `Settings/DioConfig.ini`에서 입출력 포인트 이름/설명을 수정하면 프로그램 재시작 시 반영 +- **DIO 보드 타입 추가**: `Infrastructure/RealDioBoard.cs`의 `GetCardTypeFromConfig()` 메서드에 새 보드 타입 매핑 추가 +- **시험 프로세스 수정**: `Services/TestProcessService.cs`의 `ProcessProc()` 메서드에서 시험 단계 추가/변경 +- **ZMDI 명령 시퀀스 수정**: `Services/ZmdiSensorService.cs`의 `_commandList1~4` 배열 수정 +- **ID 디코딩 테이블 수정**: `Services/ZmdiSensorService.cs`의 `_yearHexList`, `_monthList`, `_dayHexList` 등 업데이트 +- **사용자 매뉴얼**: `Manual/` 폴더에서 각 화면별 사용 설명서 확인 및 수정 가능 + +## 🧪 테스트 + +`leak_test_project.Tests` 프로젝트에서 핵심 서비스의 단위 테스트를 실행할 수 있습니다. + +```bash +dotnet test leak_test_project.Tests/leak_test_project.Tests.csproj +``` ## 🚀 실행 방법 1. Visual Studio에서 `leak_test_project.slnx` 파일을 엽니다. 2. `F5` 키를 눌러 실행하거나 빌드 후 `bin/Debug/leak_test_project.exe`를 실행합니다. 3. 로그 파일은 실행 파일과 동일한 경로의 `Logs/` 폴더에 자동 생성됩니다. +4. DIO 설정 파일은 `Settings/DioConfig.ini`에 자동 생성됩니다 (없을 경우 기본값으로 생성). diff --git a/leak_test_project.Tests/bin/Debug/net472/leak_test_project.Tests.dll b/leak_test_project.Tests/bin/Debug/net472/leak_test_project.Tests.dll index 92ed9b9..e898eb9 100644 Binary files a/leak_test_project.Tests/bin/Debug/net472/leak_test_project.Tests.dll and b/leak_test_project.Tests/bin/Debug/net472/leak_test_project.Tests.dll differ diff --git a/leak_test_project.Tests/bin/Debug/net472/leak_test_project.Tests.pdb b/leak_test_project.Tests/bin/Debug/net472/leak_test_project.Tests.pdb index 60c0c0d..153c6e3 100644 Binary files a/leak_test_project.Tests/bin/Debug/net472/leak_test_project.Tests.pdb and b/leak_test_project.Tests/bin/Debug/net472/leak_test_project.Tests.pdb differ diff --git a/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.AssemblyInfo.cs b/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.AssemblyInfo.cs index a42d018..8dd4eb5 100644 --- a/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.AssemblyInfo.cs +++ b/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.AssemblyInfo.cs @@ -13,7 +13,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("leak_test_project.Tests")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+463b017b2f6c3c93b007d983e892d11a3b467b19")] [assembly: System.Reflection.AssemblyProductAttribute("leak_test_project.Tests")] [assembly: System.Reflection.AssemblyTitleAttribute("leak_test_project.Tests")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.AssemblyInfoInputs.cache b/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.AssemblyInfoInputs.cache index 6afdfae..0113633 100644 --- a/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.AssemblyInfoInputs.cache +++ b/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.AssemblyInfoInputs.cache @@ -1 +1 @@ -845b7ec27b60caf36b7a39a6306fad190b6fe978d5196d358c2ca638ded0577b +2ea65620aa90120c9b7dbe76d8e00969f1b68490ac09214d6e8be837d3b86854 diff --git a/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.dll b/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.dll index 92ed9b9..e898eb9 100644 Binary files a/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.dll and b/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.dll differ diff --git a/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.pdb b/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.pdb index 60c0c0d..153c6e3 100644 Binary files a/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.pdb and b/leak_test_project.Tests/obj/Debug/net472/leak_test_project.Tests.pdb differ diff --git a/leak_test_project/Infrastructure/RealDioBoard.cs b/leak_test_project/Infrastructure/RealDioBoard.cs index 5559d92..b17d847 100644 --- a/leak_test_project/Infrastructure/RealDioBoard.cs +++ b/leak_test_project/Infrastructure/RealDioBoard.cs @@ -148,33 +148,44 @@ namespace leak_test_project.Infrastructure { while (!token.IsCancellationRequested) { - if (_cardNumber >= 0) + try { - ushort port = 0; - uint readValue; - short ret = DASK.DI_ReadPort((ushort)_cardNumber, port, out readValue); - if (ret >= 0) + if (_cardNumber >= 0) { - var inputPoints = new List(_inputs.Values); - for (int i = 0; i < inputPoints.Count; i++) + ushort port = 0; + uint readValue; + short ret = DASK.DI_ReadPort((ushort)_cardNumber, port, out readValue); + if (ret >= 0) { - var point = inputPoints[i]; - bool isCurrentlyOn = (readValue & (1U << i)) != 0; - - // If changed from OFF to ON - if (isCurrentlyOn && !point.Value) - { - point.Value = true; - Console.WriteLine($"[RealDioBoard] Input {point.Name} triggered (OFF→ON)"); - InputChanged?.Invoke(this, new DioEventArgs(point.Name, true)); - } - else if (!isCurrentlyOn && point.Value) + var inputPoints = new List(_inputs.Values); + for (int i = 0; i < inputPoints.Count; i++) { - point.Value = false; + var point = inputPoints[i]; + bool isCurrentlyOn = (readValue & (1U << i)) != 0; + + // If changed from OFF to ON + if (isCurrentlyOn && !point.Value) + { + point.Value = true; + Console.WriteLine($"[RealDioBoard] Input {point.Name} triggered (OFF→ON)"); + InputChanged?.Invoke(this, new DioEventArgs(point.Name, true)); + } + else if (!isCurrentlyOn && point.Value) + { + point.Value = false; + } } } + else + { + FileLogger.Log("ERROR", $"[RealDioBoard] DI_ReadPort Error: {ret}"); + } } } + catch (Exception ex) + { + FileLogger.Log("ERROR", $"[RealDioBoard] Inner Polling Error: {ex.Message}"); + } // 10ms polling rate (approx) await Task.Delay(10, token); @@ -186,7 +197,7 @@ namespace leak_test_project.Infrastructure } catch (Exception ex) { - Console.WriteLine($"[RealDioBoard] Polling error: {ex.Message}"); + FileLogger.Log("ERROR", $"[RealDioBoard] Critical Polling Loop Error: {ex.Message}"); } } diff --git a/leak_test_project/MainWindow.xaml b/leak_test_project/MainWindow.xaml index 27fb4ca..262261c 100644 --- a/leak_test_project/MainWindow.xaml +++ b/leak_test_project/MainWindow.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:viewmodels="clr-namespace:leak_test_project.ViewModels" Title="Pressure Leak Inspect System" Height="800" Width="1024" + MinWidth="1150" MinHeight="700" WindowState="Maximized" Background="#F0F0F0" WindowStyle="None"> @@ -10,105 +11,105 @@ - - - - - + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + diff --git a/leak_test_project/Manual/Communication_Manual.md b/leak_test_project/Manual/Communication_Manual.md index b59880c..e8065df 100644 --- a/leak_test_project/Manual/Communication_Manual.md +++ b/leak_test_project/Manual/Communication_Manual.md @@ -47,13 +47,15 @@ Sentinel C28 기기는 실제 리크 테스트를 수행하고 측정값을 전 ## 5. 설정 저장 및 적용 1. 모든 포트와 속도 설정을 완료한 후 하단의 **[설정 저장]** 버튼을 클릭합니다. 2. 설정값은 루트 폴더의 `config.xml` 파일에 즉시 저장됩니다. -3. 저장과 동시에 통신 서비스가 재시작되어 변경된 설정이 적용됩니다. +3. 저장과 동시에 모든 통신 서비스(Sentinel C28, ZMDI 센서)와 자동 시험 프로세스가 재시작되어 변경된 설정이 즉시 적용됩니다. --- ## 6. 문제 해결 (Troubleshooting) ### 통신 실패(NG) 발생 시 체크리스트 +- **포트 자동 복구 (Auto-Reconnect)**: 모든 통신 포트(Sentinel C28, ZMDI 좌/우)는 연결이 끊어질 경우 **1초(1000ms) 주기**로 연결을 자동 시도합니다. 케이블을 다시 연결하면 별도의 조치 없이 1초 이내에 정상 상태로 복구됩니다. +- **포트 연결 상태 확인**: 프로그램 시작 또는 설정 저장 시 각 포트의 연결 상태를 즉시 확인하며, 실패 시 메인 화면 오류 영역에 관련 정보를 표시합니다. - **물리적 연결**: 케이블이 장치와 PC에 견고하게 연결되어 있는지 확인하십시오. - **포트 충돌**: 선택한 COM 포트가 다른 프로그램에서 사용 중이지 않은지 확인하십시오. - **보드레이트 불일치**: 장치 본체 설정의 BaudRate와 프로그램의 설정값이 일치하는지 확인하십시오. diff --git a/leak_test_project/Manual/HomeView_Manual.md b/leak_test_project/Manual/HomeView_Manual.md index 2a48f2f..370e655 100644 --- a/leak_test_project/Manual/HomeView_Manual.md +++ b/leak_test_project/Manual/HomeView_Manual.md @@ -55,6 +55,8 @@ HomeView는 좌측(LEFT)과 우측(RIGHT) 두 개의 독립적인 채널로 구 - 현재 시험의 진행 단계(`시작 대기`, `센서 정보 읽는 중`, `LEAK 시험중`, `시험 완료` 등)를 파란색으로 표시합니다. 2. **오류 메시지 (Error Message)** - 통신 실패, 센서 데이터 길이 부족 등 비정상 상황 발생 시 상세한 원인을 빨간색으로 표시합니다. + - **포트 연결 오류 및 자동 복구**: 포트 연결 실패 시 즉시 표시되며, 시스템이 **1초 주기**로 자동 재연결을 시도합니다. 케이블을 다시 연결하면 최대 1초 내에 오류가 사라지고 정상 상태로 복구됩니다. + - **다중 오류 표시**: 여러 포트가 동시에 연결 실패한 경우 줄바꿈으로 모든 오류를 동시에 확인할 수 있습니다. --- diff --git a/leak_test_project/Manual/IO_Monitor_Manual.md b/leak_test_project/Manual/IO_Monitor_Manual.md index 5acc90e..f5378c4 100644 --- a/leak_test_project/Manual/IO_Monitor_Manual.md +++ b/leak_test_project/Manual/IO_Monitor_Manual.md @@ -40,8 +40,9 @@ I/O Monitor는 시스템의 **디지털 입력(Digital Input)** 및 **디지털 ## 4. 주요 기능 ### 4.1. 실시간 모니터링 (Real-time Monitoring) -- 하드웨어 DIO 보드로부터 실시간으로 상태를 읽어와 LED 아이콘에 즉시 반영합니다. +- 하드웨어 DIO 보드로부터 **500ms 주기(0.5초)**로 상태를 자동으로 읽어와 LED 아이콘에 반영합니다. - 별도의 새로고침 버튼 없이 자동으로 상태가 업데이트됩니다. +- 화면을 닫으면(Close 버튼) 자동 갱신 타이머가 정지됩니다. ### 4.2. 페이징 처리 (Paging) - 많은 수의 I/O 접점을 효율적으로 확인하기 위해 페이징(Page) 방식을 사용합니다. diff --git a/leak_test_project/Services/SentinelC28Service.cs b/leak_test_project/Services/SentinelC28Service.cs index 904547a..f0cbb57 100644 --- a/leak_test_project/Services/SentinelC28Service.cs +++ b/leak_test_project/Services/SentinelC28Service.cs @@ -36,8 +36,8 @@ namespace leak_test_project.Services if (!isConnected && _shouldBeConnected) StartReconnectTimer(); }; - // 5초마다 연결 상태를 확인하고 재연결 시도 - _reconnectTimer = new Timer(5000); + // 1초(1000ms)마다 연결 상태를 확인하고 재연결 시도 + _reconnectTimer = new Timer(1000); _reconnectTimer.AutoReset = false; // 재진입 방지 _reconnectTimer.Elapsed += (s, e) => { if (_shouldBeConnected && !_communication.IsOpen) @@ -56,10 +56,12 @@ namespace leak_test_project.Services }; } - public void Connect() + public bool Connect() { _shouldBeConnected = true; - _communication.Open(); + bool opened = _communication.Open(); + if (!opened) StartReconnectTimer(); + return opened; } public void Disconnect() @@ -86,12 +88,12 @@ namespace leak_test_project.Services if (!_communication.Write($"{crc}{payload}\r\n")) { - Console.WriteLine("[Service] Failed to send command: Communication channel closed."); + FileLogger.Log("ERROR", "[SentinelC28] Failed to send command: Communication channel closed."); } _sequence = (_sequence >= 255) ? 1 : _sequence + 1; } catch (Exception ex) { - Console.WriteLine($"[Service] Error sending command: {ex.Message}"); + FileLogger.Log("ERROR", $"[SentinelC28] Error sending command: {ex.Message}"); } } @@ -120,11 +122,11 @@ namespace leak_test_project.Services break; case 'M': // 일반 메시지 - Console.WriteLine($"[C28 Message] {body}"); + FileLogger.Log("INFO", $"[SentinelC28 Message] {body}"); break; } } catch (Exception ex) { - Console.WriteLine($"[Service] Error parsing received data: {ex.Message}"); + FileLogger.Log("ERROR", $"[SentinelC28] Error parsing received data: {ex.Message}"); } } diff --git a/leak_test_project/Services/ZmdiSensorService.cs b/leak_test_project/Services/ZmdiSensorService.cs index 0e6f8a8..3c77575 100644 --- a/leak_test_project/Services/ZmdiSensorService.cs +++ b/leak_test_project/Services/ZmdiSensorService.cs @@ -1,22 +1,26 @@ using System; using System.Text; using System.Threading; +using System.Timers; using leak_test_project.Infrastructure; using leak_test_project.Models; +using leak_test_project.Utils; namespace leak_test_project.Services { /// /// ZMDI 센서와 시리얼 통신하여 제품 ID를 읽고 파싱하는 서비스. - /// 레거시 ClsSensorReader를 새 아키텍처로 포팅. - /// 동기식 통신이므로 반드시 백그라운드 스레드에서 호출해야 합니다. + /// 자동 재연결(Auto-Reconnect) 및 예외 처리 포함. /// - public class ZmdiSensorService + public class ZmdiSensorService : IDisposable { private readonly ICommunication _comm; private readonly object _commSync = new object(); private readonly int _sensorIndex; // 0=LEFT, 1=RIGHT + private System.Timers.Timer _reconnectTimer; + private bool _shouldBeConnected = false; + // 레거시 명령 시퀀스 (ClsSensorReader의 commandList1~4) 그대로 유지 private readonly string[] _commandList1 = { "V", "Pr_D7", "Pr_D6", "Pr_D5", "r" }; private readonly string[] _commandList2 = { "tso31150" }; @@ -48,10 +52,62 @@ namespace leak_test_project.Services /// 오류 메시지 이벤트 public event EventHandler ErrorMessage; + /// 연결 상태 변경 이벤트 + public event EventHandler ConnectionChanged; + public ZmdiSensorService(ICommunication communication, int sensorIndex) { _comm = communication; _sensorIndex = sensorIndex; + + _comm.ConnectionStatusChanged += (s, isConnected) => { + ConnectionChanged?.Invoke(this, isConnected); + if (!isConnected && _shouldBeConnected) StartReconnectTimer(); + }; + + // 1초(1000ms)마다 연결 상태를 확인하고 재연결 시도 + _reconnectTimer = new System.Timers.Timer(1000); + _reconnectTimer.AutoReset = false; // 재진입 방지 + _reconnectTimer.Elapsed += (s, e) => { + if (_shouldBeConnected && !_comm.IsOpen) + { + if (!_comm.Open()) + { + if (_shouldBeConnected) _reconnectTimer.Start(); + } + } + else if (_shouldBeConnected) + { + _reconnectTimer.Start(); + } + }; + } + + public bool Connect() + { + _shouldBeConnected = true; + bool opened = _comm.Open(); + if (!opened) StartReconnectTimer(); + return opened; + } + + public void Disconnect() + { + _shouldBeConnected = false; + _reconnectTimer?.Stop(); + _comm.Close(); + } + + private void StartReconnectTimer() + { + if (_reconnectTimer != null && !_reconnectTimer.Enabled) _reconnectTimer.Start(); + } + + public void Dispose() + { + Disconnect(); + _reconnectTimer?.Dispose(); + _reconnectTimer = null; } /// @@ -131,7 +187,7 @@ namespace leak_test_project.Services } catch (Exception ex) { - Console.WriteLine($"[ZMDI] ReadSensor exception: {ex.Message}"); + FileLogger.Log("ERROR", $"[ZMDI] ReadSensor exception: {ex.Message}"); ErrorMessage?.Invoke(this, $"센서 데이터 오류 (Exception: {ex.Message})\r\n[수신값]: {recvData.Trim()}"); return null; } diff --git a/leak_test_project/ViewModels/HomeViewModel.cs b/leak_test_project/ViewModels/HomeViewModel.cs index b05e491..f8bb8ac 100644 --- a/leak_test_project/ViewModels/HomeViewModel.cs +++ b/leak_test_project/ViewModels/HomeViewModel.cs @@ -145,13 +145,29 @@ namespace leak_test_project.ViewModels public void ApplyConfig() { - CleanupCommunication(); + CleanupAll(); var config = ConfigManager.Current; InitializeCommunication(config); + InitializeTestProcess(config); } - private void CleanupCommunication() + private void CleanupAll() { + // 1. 시험 프로세스 정지 (스레드 종료 및 이벤트 해제) + _testProcess?.Dispose(); + _testProcess = null; + + // 2. ZMDI 시리얼 포트 및 서비스 해제 + _leftZmdi?.Dispose(); + _rightZmdi?.Dispose(); + _leftZmdiSerial?.Dispose(); + _rightZmdiSerial?.Dispose(); + _leftZmdi = null; + _rightZmdi = null; + _leftZmdiSerial = null; + _rightZmdiSerial = null; + + // 3. Sentinel C28 해제 _sentinelService?.Disconnect(); _sentinelSerial?.Dispose(); _sentinelService = null; @@ -165,29 +181,43 @@ namespace leak_test_project.ViewModels _sentinelService = new SentinelC28Service(_sentinelSerial); _sentinelService.RawDataReceived += (s, data) => { - // Raw 데이터는 UI 로그 보다는 파일 로그나 디버그 창으로 전송 가능 System.Diagnostics.Debug.WriteLine($"[SENTINEL RAW] {data}"); }; _sentinelService.OnStreamingParsed += (s, data) => UpdateMeasurement(data); _sentinelService.OnFinalResultParsed += (s, data) => ProcessFinalResult(data); - _sentinelService.Connect(); + if (!_sentinelService.Connect()) + { + string msg = $"리크 센서 포트 연결 실패 ({config.SensorPort})"; + LeftError = msg; + RightError = msg; + } } private void InitializeTestProcess(AppConfig config) { // DIO 보드 초기화 (MainViewModel에서 생성된 보드 사용) - // _dioBoard는 생성자에서 이미 할당됨. if (_dioBoard == null) return; - // _dioBoard.Initialize(); // MainViewModel이나 Factory에서 이미 수행됨. // ZMDI 센서 서비스 (LEFT/RIGHT) _leftZmdiSerial = new SerialProvider(config.LeftPort, config.ZmdiBaudRate); _rightZmdiSerial = new SerialProvider(config.RightPort, config.ZmdiBaudRate); + _leftZmdi = new ZmdiSensorService(_leftZmdiSerial, 0); _rightZmdi = new ZmdiSensorService(_rightZmdiSerial, 1); + if (!_leftZmdi.Connect()) + { + string msg = $"ZMDI 센서 포트 연결 실패 ({config.LeftPort})"; + LeftError = string.IsNullOrEmpty(LeftError) ? msg : $"{LeftError}\n{msg}"; + } + if (!_rightZmdi.Connect()) + { + string msg = $"ZMDI 센서 포트 연결 실패 ({config.RightPort})"; + RightError = string.IsNullOrEmpty(RightError) ? msg : $"{RightError}\n{msg}"; + } + _leftZmdi.ProgressMessage += (s, msg) => _dispatcher.Invoke(() => LeftStatus = msg); _leftZmdi.ErrorMessage += (s, msg) => _dispatcher.Invoke(() => { LeftError = msg; @@ -318,8 +348,9 @@ namespace leak_test_project.ViewModels RightValue = data.MeasuredValue.ToString("F3"); else { - // 채널 정보가 없으면 기본적으로 양쪽 모두 또는 로그에 기록 + // 채널 정보가 없으면 양쪽 모두 갱신 LeftValue = data.MeasuredValue.ToString("F3"); + RightValue = data.MeasuredValue.ToString("F3"); } }); } @@ -422,14 +453,8 @@ namespace leak_test_project.ViewModels public void Dispose() { ConfigManager.ConfigChanged -= OnConfigChanged; - - _testProcess?.Dispose(); + CleanupAll(); _dioBoard?.Dispose(); - - _leftZmdiSerial?.Dispose(); - _rightZmdiSerial?.Dispose(); - - CleanupCommunication(); } } } diff --git a/leak_test_project/ViewModels/InOutViewModel.cs b/leak_test_project/ViewModels/InOutViewModel.cs index a661912..dc98b59 100644 --- a/leak_test_project/ViewModels/InOutViewModel.cs +++ b/leak_test_project/ViewModels/InOutViewModel.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Windows.Input; +using System.Windows.Threading; using leak_test_project.Models; using leak_test_project.Services; using leak_test_project.ViewModels.Core; @@ -9,10 +10,11 @@ using leak_test_project.ViewModels.Core; namespace leak_test_project.ViewModels { /// - /// In/Out Monitor 화면의 데이터 페이징 로직을 담당하는 ViewModel. + /// In/Out Monitor 화면의 데이터 페이징 및 실시간 갱신 로직을 담당하는 ViewModel. /// - public class InOutViewModel : ObservableObject + public class InOutViewModel : ObservableObject, IDisposable { + private readonly IoBoardService _ioService; private readonly List _allInputs; private readonly List _allOutputs; private const int PageSize = 30; @@ -20,6 +22,8 @@ namespace leak_test_project.ViewModels private int _inputCurrentPage = 0; private int _outputCurrentPage = 0; + private readonly DispatcherTimer _refreshTimer; + private List _currentInputs = new List(); public List CurrentInputs { get => _currentInputs; set => SetProperty(ref _currentInputs, value); } @@ -43,6 +47,7 @@ namespace leak_test_project.ViewModels public InOutViewModel(Action navigateHome, IoBoardService ioService) { + _ioService = ioService; _allInputs = ioService.Inputs; _allOutputs = ioService.Outputs; @@ -56,10 +61,26 @@ namespace leak_test_project.ViewModels OutputNextCommand = new RelayCommand(o => { if ((_outputCurrentPage + 1) * PageSize < _allOutputs.Count) { _outputCurrentPage++; UpdateOutputs(); } }); OutputLastCommand = new RelayCommand(o => { _outputCurrentPage = Math.Max(0, (_allOutputs.Count - 1) / PageSize); UpdateOutputs(); }); - CloseCommand = new RelayCommand(o => navigateHome?.Invoke()); + CloseCommand = new RelayCommand(o => { + Dispose(); + navigateHome?.Invoke(); + }); UpdateInputs(); UpdateOutputs(); + + // 500ms 주기로 DIO 상태 자동 갱신 + _refreshTimer = new DispatcherTimer + { + Interval = TimeSpan.FromMilliseconds(500) + }; + _refreshTimer.Tick += (s, e) => + { + _ioService.RefreshState(); + UpdateInputs(); + UpdateOutputs(); + }; + _refreshTimer.Start(); } private void UpdateInputs() @@ -71,5 +92,10 @@ namespace leak_test_project.ViewModels { CurrentOutputs = _allOutputs.Skip(_outputCurrentPage * PageSize).Take(PageSize).ToList(); } + + public void Dispose() + { + _refreshTimer?.Stop(); + } } } diff --git a/leak_test_project/Views/DataView.xaml b/leak_test_project/Views/DataView.xaml index 436ecf5..3433b80 100644 --- a/leak_test_project/Views/DataView.xaml +++ b/leak_test_project/Views/DataView.xaml @@ -142,7 +142,7 @@ GridLinesVisibility="All" HorizontalGridLinesBrush="#ECF0F1" VerticalGridLinesBrush="#ECF0F1" AlternatingRowBackground="#F9FBFC" RowHeight="35" CanUserSortColumns="True" CanUserReorderColumns="False" - BorderThickness="0" SelectionMode="Single" SelectionChanged="DataGrid_SelectionChanged"> + BorderThickness="0" SelectionMode="Extended" SelectionChanged="DataGrid_SelectionChanged"> @@ -178,7 +178,7 @@ - + diff --git a/leak_test_project/bin/Release/app.publish/leak_test_project.exe b/leak_test_project/bin/Release/app.publish/leak_test_project.exe index a35007f..f49f53b 100644 Binary files a/leak_test_project/bin/Release/app.publish/leak_test_project.exe and b/leak_test_project/bin/Release/app.publish/leak_test_project.exe differ diff --git a/leak_test_project/bin/Release/config.xml b/leak_test_project/bin/Release/config.xml index ef1d4a3..89d7a35 100644 --- a/leak_test_project/bin/Release/config.xml +++ b/leak_test_project/bin/Release/config.xml @@ -5,6 +5,6 @@ 19200 COM3 9600 - 0.6 - -0.25 + 0.1 + -0.15 \ No newline at end of file diff --git a/leak_test_project/bin/Release/leak_test_project.application b/leak_test_project/bin/Release/leak_test_project.application index 94b83ad..894108c 100644 --- a/leak_test_project/bin/Release/leak_test_project.application +++ b/leak_test_project/bin/Release/leak_test_project.application @@ -14,7 +14,7 @@ - CsrEJe4rTy6CHSF/iN4MvW+2RB9TB5Xx/+uSD4CYW7k= + +tT5TcFav5TEeRJogPVqrD2i+n0zc3NErhzPuBsdAok= diff --git a/leak_test_project/bin/Release/leak_test_project.exe b/leak_test_project/bin/Release/leak_test_project.exe index 61bde9e..597deaa 100644 Binary files a/leak_test_project/bin/Release/leak_test_project.exe and b/leak_test_project/bin/Release/leak_test_project.exe differ diff --git a/leak_test_project/bin/Release/leak_test_project.exe.manifest b/leak_test_project/bin/Release/leak_test_project.exe.manifest index 31a2041..e9d93f4 100644 --- a/leak_test_project/bin/Release/leak_test_project.exe.manifest +++ b/leak_test_project/bin/Release/leak_test_project.exe.manifest @@ -42,14 +42,14 @@ - + - GG2gAseBUorlVcMCNhyGWUc4PX1BrLRis6grr7abydM= + qAkKP87U3yb9EpU29R51sPc1OgjB2lM+2tz7F86u2qI= diff --git a/leak_test_project/bin/Release/leak_test_project.pdb b/leak_test_project/bin/Release/leak_test_project.pdb index bc9d8d1..32a13e7 100644 Binary files a/leak_test_project/bin/Release/leak_test_project.pdb and b/leak_test_project/bin/Release/leak_test_project.pdb differ diff --git a/leak_test_project/obj/Release/GeneratedInternalTypeHelper.g.cs b/leak_test_project/obj/Release/GeneratedInternalTypeHelper.g.cs index c65238f..04dc0b9 100644 --- a/leak_test_project/obj/Release/GeneratedInternalTypeHelper.g.cs +++ b/leak_test_project/obj/Release/GeneratedInternalTypeHelper.g.cs @@ -1,2 +1,62 @@ - +//------------------------------------------------------------------------------ +// +// 이 코드는 도구를 사용하여 생성되었습니다. +// 런타임 버전:4.0.30319.42000 +// +// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면 +// 이러한 변경 내용이 손실됩니다. +// +//------------------------------------------------------------------------------ + +namespace XamlGeneratedNamespace { + + + /// + /// GeneratedInternalTypeHelper + /// + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public sealed class GeneratedInternalTypeHelper : System.Windows.Markup.InternalTypeHelper { + + /// + /// CreateInstance + /// + protected override object CreateInstance(System.Type type, System.Globalization.CultureInfo culture) { + return System.Activator.CreateInstance(type, ((System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic) + | (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.CreateInstance)), null, null, culture); + } + + /// + /// GetPropertyValue + /// + protected override object GetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, System.Globalization.CultureInfo culture) { + return propertyInfo.GetValue(target, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// SetPropertyValue + /// + protected override void SetPropertyValue(System.Reflection.PropertyInfo propertyInfo, object target, object value, System.Globalization.CultureInfo culture) { + propertyInfo.SetValue(target, value, System.Reflection.BindingFlags.Default, null, null, culture); + } + + /// + /// CreateDelegate + /// + protected override System.Delegate CreateDelegate(System.Type delegateType, object target, string handler) { + return ((System.Delegate)(target.GetType().InvokeMember("_CreateDelegate", (System.Reflection.BindingFlags.InvokeMethod + | (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)), null, target, new object[] { + delegateType, + handler}, null))); + } + + /// + /// AddEventHandler + /// + protected override void AddEventHandler(System.Reflection.EventInfo eventInfo, object target, System.Delegate handler) { + eventInfo.AddEventHandler(target, handler); + } + } +} diff --git a/leak_test_project/obj/Release/MainWindow.baml b/leak_test_project/obj/Release/MainWindow.baml index 90ffed2..9d6119f 100644 Binary files a/leak_test_project/obj/Release/MainWindow.baml and b/leak_test_project/obj/Release/MainWindow.baml differ diff --git a/leak_test_project/obj/Release/MainWindow.g.cs b/leak_test_project/obj/Release/MainWindow.g.cs index e236c72..ac1e0db 100644 --- a/leak_test_project/obj/Release/MainWindow.g.cs +++ b/leak_test_project/obj/Release/MainWindow.g.cs @@ -1,4 +1,4 @@ -#pragma checksum "..\..\MainWindow.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "6AF2BA3E5F60C061A914FC5DF6ABFF42B0A79490DBE682D50DF18D57A83F92AD" +#pragma checksum "..\..\MainWindow.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "AC6B63D342AAA60FA134A9381169A7E50CCCC4A249937C592D6EBCFD954C2193" //------------------------------------------------------------------------------ // // 이 코드는 도구를 사용하여 생성되었습니다. @@ -49,7 +49,7 @@ namespace leak_test_project { #line hidden - #line 47 "..\..\MainWindow.xaml" + #line 48 "..\..\MainWindow.xaml" [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] internal System.Windows.Controls.Button btnMaximize; @@ -57,7 +57,7 @@ namespace leak_test_project { #line hidden - #line 48 "..\..\MainWindow.xaml" + #line 49 "..\..\MainWindow.xaml" [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] internal System.Windows.Controls.TextBlock txtMaximizeIcon; @@ -96,7 +96,7 @@ namespace leak_test_project { { case 1: - #line 20 "..\..\MainWindow.xaml" + #line 21 "..\..\MainWindow.xaml" ((System.Windows.Controls.Border)(target)).MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(this.TopBar_MouseLeftButtonDown); #line default @@ -107,7 +107,7 @@ namespace leak_test_project { return; case 3: - #line 44 "..\..\MainWindow.xaml" + #line 45 "..\..\MainWindow.xaml" ((System.Windows.Controls.Button)(target)).Click += new System.Windows.RoutedEventHandler(this.BtnMinimize_Click); #line default @@ -116,7 +116,7 @@ namespace leak_test_project { case 4: this.btnMaximize = ((System.Windows.Controls.Button)(target)); - #line 47 "..\..\MainWindow.xaml" + #line 48 "..\..\MainWindow.xaml" this.btnMaximize.Click += new System.Windows.RoutedEventHandler(this.BtnMaximize_Click); #line default diff --git a/leak_test_project/obj/Release/MainWindow.g.i.cs b/leak_test_project/obj/Release/MainWindow.g.i.cs index e236c72..ac1e0db 100644 --- a/leak_test_project/obj/Release/MainWindow.g.i.cs +++ b/leak_test_project/obj/Release/MainWindow.g.i.cs @@ -1,4 +1,4 @@ -#pragma checksum "..\..\MainWindow.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "6AF2BA3E5F60C061A914FC5DF6ABFF42B0A79490DBE682D50DF18D57A83F92AD" +#pragma checksum "..\..\MainWindow.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "AC6B63D342AAA60FA134A9381169A7E50CCCC4A249937C592D6EBCFD954C2193" //------------------------------------------------------------------------------ // // 이 코드는 도구를 사용하여 생성되었습니다. @@ -49,7 +49,7 @@ namespace leak_test_project { #line hidden - #line 47 "..\..\MainWindow.xaml" + #line 48 "..\..\MainWindow.xaml" [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] internal System.Windows.Controls.Button btnMaximize; @@ -57,7 +57,7 @@ namespace leak_test_project { #line hidden - #line 48 "..\..\MainWindow.xaml" + #line 49 "..\..\MainWindow.xaml" [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] internal System.Windows.Controls.TextBlock txtMaximizeIcon; @@ -96,7 +96,7 @@ namespace leak_test_project { { case 1: - #line 20 "..\..\MainWindow.xaml" + #line 21 "..\..\MainWindow.xaml" ((System.Windows.Controls.Border)(target)).MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(this.TopBar_MouseLeftButtonDown); #line default @@ -107,7 +107,7 @@ namespace leak_test_project { return; case 3: - #line 44 "..\..\MainWindow.xaml" + #line 45 "..\..\MainWindow.xaml" ((System.Windows.Controls.Button)(target)).Click += new System.Windows.RoutedEventHandler(this.BtnMinimize_Click); #line default @@ -116,7 +116,7 @@ namespace leak_test_project { case 4: this.btnMaximize = ((System.Windows.Controls.Button)(target)); - #line 47 "..\..\MainWindow.xaml" + #line 48 "..\..\MainWindow.xaml" this.btnMaximize.Click += new System.Windows.RoutedEventHandler(this.BtnMaximize_Click); #line default diff --git a/leak_test_project/obj/Release/Views/DataView.baml b/leak_test_project/obj/Release/Views/DataView.baml index b797ae7..201ad59 100644 Binary files a/leak_test_project/obj/Release/Views/DataView.baml and b/leak_test_project/obj/Release/Views/DataView.baml differ diff --git a/leak_test_project/obj/Release/Views/DataView.g.cs b/leak_test_project/obj/Release/Views/DataView.g.cs index c08b197..89bbb2f 100644 --- a/leak_test_project/obj/Release/Views/DataView.g.cs +++ b/leak_test_project/obj/Release/Views/DataView.g.cs @@ -1,4 +1,4 @@ -#pragma checksum "..\..\..\Views\DataView.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "D1F2D654C7757653BF2CBCA4196ECE79CF1D243F00B5F870E08DA488B33B02FF" +#pragma checksum "..\..\..\Views\DataView.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "3817A6627B503D085EDFEB1BF6AD88D4A23D1775086B1CA3BC0ADB5F4D94D266" //------------------------------------------------------------------------------ // // 이 코드는 도구를 사용하여 생성되었습니다. diff --git a/leak_test_project/obj/Release/Views/DataView.g.i.cs b/leak_test_project/obj/Release/Views/DataView.g.i.cs index c08b197..89bbb2f 100644 --- a/leak_test_project/obj/Release/Views/DataView.g.i.cs +++ b/leak_test_project/obj/Release/Views/DataView.g.i.cs @@ -1,4 +1,4 @@ -#pragma checksum "..\..\..\Views\DataView.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "D1F2D654C7757653BF2CBCA4196ECE79CF1D243F00B5F870E08DA488B33B02FF" +#pragma checksum "..\..\..\Views\DataView.xaml" "{8829d00f-11b8-4213-878b-770e8597ac16}" "3817A6627B503D085EDFEB1BF6AD88D4A23D1775086B1CA3BC0ADB5F4D94D266" //------------------------------------------------------------------------------ // // 이 코드는 도구를 사용하여 생성되었습니다. diff --git a/leak_test_project/obj/Release/leak_test_project.application b/leak_test_project/obj/Release/leak_test_project.application index 94b83ad..894108c 100644 --- a/leak_test_project/obj/Release/leak_test_project.application +++ b/leak_test_project/obj/Release/leak_test_project.application @@ -14,7 +14,7 @@ - CsrEJe4rTy6CHSF/iN4MvW+2RB9TB5Xx/+uSD4CYW7k= + +tT5TcFav5TEeRJogPVqrD2i+n0zc3NErhzPuBsdAok= diff --git a/leak_test_project/obj/Release/leak_test_project.exe b/leak_test_project/obj/Release/leak_test_project.exe index 61bde9e..597deaa 100644 Binary files a/leak_test_project/obj/Release/leak_test_project.exe and b/leak_test_project/obj/Release/leak_test_project.exe differ diff --git a/leak_test_project/obj/Release/leak_test_project.exe.manifest b/leak_test_project/obj/Release/leak_test_project.exe.manifest index 31a2041..e9d93f4 100644 --- a/leak_test_project/obj/Release/leak_test_project.exe.manifest +++ b/leak_test_project/obj/Release/leak_test_project.exe.manifest @@ -42,14 +42,14 @@ - + - GG2gAseBUorlVcMCNhyGWUc4PX1BrLRis6grr7abydM= + qAkKP87U3yb9EpU29R51sPc1OgjB2lM+2tz7F86u2qI= diff --git a/leak_test_project/obj/Release/leak_test_project.g.resources b/leak_test_project/obj/Release/leak_test_project.g.resources index 08b5a7e..2eeaff0 100644 Binary files a/leak_test_project/obj/Release/leak_test_project.g.resources and b/leak_test_project/obj/Release/leak_test_project.g.resources differ diff --git a/leak_test_project/obj/Release/leak_test_project.pdb b/leak_test_project/obj/Release/leak_test_project.pdb index bc9d8d1..32a13e7 100644 Binary files a/leak_test_project/obj/Release/leak_test_project.pdb and b/leak_test_project/obj/Release/leak_test_project.pdb differ diff --git a/leak_test_project/obj/Release/leak_test_project_MarkupCompile.lref b/leak_test_project/obj/Release/leak_test_project_MarkupCompile.lref index bef503a..ed3694c 100644 --- a/leak_test_project/obj/Release/leak_test_project_MarkupCompile.lref +++ b/leak_test_project/obj/Release/leak_test_project_MarkupCompile.lref @@ -1,4 +1,4 @@ -C:\Users\COMPUTER1\Desktop\mobi\leak_test_project\leak_test_project\obj\Release\GeneratedInternalTypeHelper.g.cs + FC:\Users\COMPUTER1\Desktop\mobi\leak_test_project\leak_test_project\App.xaml;; FC:\Users\COMPUTER1\Desktop\mobi\leak_test_project\leak_test_project\Views\HomeView.xaml;; FC:\Users\COMPUTER1\Desktop\mobi\leak_test_project\leak_test_project\MainWindow.xaml;;