지그 체결 테스트기 gui
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

321 lines
17 KiB

# 지그 압력 및 누출 검사 애플리케이션 (Jig Pressure & Leak Test App)
## 1. 프로젝트 개요
본 프로젝트는 특정 지그(Jig)에 제품을 고정하고 압력을 인가한 뒤, 유지 시간 동안 내부 압력의 변화를 측정하여 누출(Leak) 여부를 **자동으로 검사**하는 데스크톱 전용 모니터링 애플리케이션입니다.
| 항목 | 내용 |
|------|------|
| **프레임워크** | C# WPF (.NET Framework 4.7.2) |
| **아키텍처** | MVVM (Model-View-ViewModel) + Service Layer |
| **솔루션 파일** | `jig_test.slnx` |
| **NuGet 패키지** | `System.IO.Ports` (10.0.4), `NModbus` / `NModbus.Serial` (3.0.81) |
### 주요 기능
* **수동 검사**: 물리 스위치(i1, i2) 조작에 의해 자동으로 누출 검사 시퀀스가 트리거됨
* **자동 검사**: 버튼 한 번으로 인가 → 목표 압력 대기 → 고정 → 유지 → 배기까지 전 공정을 자동 수행
* **실시간 모니터링**: 100ms 폴링으로 I/O 상태 및 압력값을 실시간 표시
* **통신 분리 및 안정성**: `ConnectionManager`를 통한 통신 인프라 캡슐화 및 `bool` 기반 상태 관리로 안정성 확보
* **자가 복구**: 통신 끊김 감지 시 독립적 자동 재연결
* **설정 관리**: 통신 포트, 기기 ID, 검사 파라미터를 XML 파일(`config.xml`)로 저장/불러오기
---
## 2. 폴더 구조
```
jig_test/ ← 솔루션 루트
├── jig_test.slnx ← 솔루션 파일
├── README.md ← 본 문서
├── KN-2000W_..._MANUAL_W.pdf ← 압력 센서 매뉴얼
├── SemiIOLite_Manual.pdf ← I/O 보드 매뉴얼
└── jig_test/ ← 프로젝트 폴더
├── jig_test.csproj ← 프로젝트 설정 (.NET 4.7.2, WPF)
├── App.xaml / App.xaml.cs ← 앱 진입점, 글로벌 예외 처리
├── Models/ ← 데이터 모델
│ └── AppConfig.cs ← 모든 설정값 (포트, 속도, 검사파라미터)
├── Services/ ← 핵심 서비스 서비스 (Infrastructure 계층)
│ ├── ConfigService.cs ← XML 직렬화 기반 설정 저장/로드
│ ├── ConnectionManager.cs ← ★ 통신 인프라 (포트 수명, 폴링, 재연결 관리)
│ ├── SemiIOLiteController.cs ← I/O 보드 제어 (LS산전 ASCII 프로토콜)
│ └── PressureSensorController.cs ← 압력 센서 통신 (Modbus RTU)
├── ViewModels/ ← MVVM ViewModel 계층
│ ├── Base/
│ │ ├── ObservableObject.cs ← INotifyPropertyChanged 구현 기반 클래스
│ │ └── RelayCommand.cs ← ICommand 구현 (View 이벤트→ViewModel 바인딩)
│ ├── Converters/
│ │ └── InverseBooleanConverter.cs ← bool 반전 변환기
│ ├── MainViewModel.cs ← ★ 핵심 비즈니스 로직 (검사 시퀀스, UI 바인딩)
│ ├── SettingsViewModel.cs ← 통신 설정 창 로직
│ └── ParameterViewModel.cs ← 검사 파라미터 창 로직
└── Views/ ← MVVM View 계층 (XAML UI)
├── MainWindow.xaml / .cs ← 메인 대시보드 UI
├── SettingsWindow.xaml / .cs ← 통신 설정 다이얼로그
└── ParameterWindow.xaml / .cs ← 검사 파라미터 다이얼로그
```
---
## 3. 아키텍처 (MVVM 패턴)
```
┌──────────────────────────────────────────────────────────────┐
│ App.xaml.cs │
│ (글로벌 예외 처리: UI / AppDomain / Task) │
└──────────────────────┬───────────────────────────────────────┘
│ StartupUri
┌──────────────────────▼───────────────────────────────────────┐
│ VIEW (XAML) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ MainWindow.xaml ← DataBinding → MainViewModel.cs │ │
│ │ SettingsWindow ← DataBinding → SettingsViewModel │ │
│ │ ParameterWindow ← DataBinding → ParameterViewModel │ │
│ └───────────────────┬─────────────────────────────────────┘ │
└──────────────────────┼───────────────────────────────────────┘
│ Event / Method
┌──────────────────────▼───────────────────────────────────────┐
│ INFRASTRUCTURE / SERVICES │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ConnectionManager │ │
│ │ (Timer, SerialPort LifeCycle, Reconnect, Event Dispatch)│ │
│ └───────┬────────────────────────────┬────────────────────┘ │
│ │ Composition │ Composition │
│ ┌───────▼──────────┐ ┌───────▼──────────┐ │
│ │ SemiIOLite │ │ PressureSensor │ │
│ │ Controller │ │ Controller │ │
│ └───────┬──────────┘ └───────┬──────────┘ │
│ │ COM Port │ COM Port │
└──────────┼────────────────────────────┼──────────────────────┘
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Semi IO Lite │ │ KN-2240W │
│ I/O Board │ │ Pressure │
│ (SIO-0201A) │ │ Sensor │
└──────────────┘ └──────────────┘
```
### 데이터 흐름 요약
1. **ConnectionManager → Service**: 100ms 타이머로 각 컨트롤러의 `RequestXxx` 메서드 호출 및 송신 HEX 로그 발행
2. **Service → Hardware**: 시리얼 포트를 통해 실제 물리 레이어로 데이터 송신
3. **Hardware → ConnectionManager**: `DataReceived` 이벤트 발생 시 바이트 버퍼링 및 패킷 완성 검사
4. **ConnectionManager → ViewModel**: 패킷이 완성되면 이벤트를 통해 ViewModel에 전달 (`IOPacketReceived` 등)
5. **ViewModel → View**: 수신 패킷을 파싱하여 `lock` 기반으로 압력값 갱신 및 UI 상태 프로퍼티 변경 → 바인딩 자동 반영
---
## 4. 핵심 파일 상세
### 4.1. `Models/AppConfig.cs`
모든 애플리케이션 설정을 담는 POCO 모델 클래스입니다.
| 프로퍼티 | 타입 | 기본값 | 용도 |
|----------|------|--------|------|
| `PortName` | `string` | `"COM1"` | I/O 보드 COM 포트 |
| `BaudRate` | `int` | `9600` | I/O 보드 통신 속도 |
| `PressurePortName` | `string` | `"COM2"` | 압력 센서 COM 포트 |
| `PressureBaudRate` | `int` | `9600` | 압력 센서 통신 속도 |
| `IOEnabled` | `bool` | `true` | I/O 보드 사용 여부 |
| `IOStationId` | `int` | `2` | I/O 보드 국번 ID |
| `PressureEnabled` | `bool` | `true` | 압력 센서 사용 여부 |
| `PressureSlaveId` | `int` | `1` | Modbus 슬레이브 주소 |
| `HoldTime` | `int` | `30` | 누출 검사 유지 시간 (초) |
| `AllowedErrorRange` | `double` | `0.3` | 허용 압력 오차 (bar) |
| `AutoTestTargetPressure` | `double` | `4.0` | 자동 검사 목표 압력 (bar) |
| `IsLogVisible` | `bool` | `false` | 하단 로그 창 표시 여부 |
### 4.2. `Services/ConfigService.cs`
`AppConfig`를 XML 직렬화 방식으로 저장/로드합니다.
* `Load()`: `config.xml` 파일이 없거나 손상 시 기본 `AppConfig` 반환 (안전한 폴백)
* `Save()`: 실행 파일 위치의 `config.xml`에 현재 설정을 즉시 저장
### 4.3. `Services/ConnectionManager.cs` — ★ 통신 인프라 관리자
`MainViewModel`에서 통신 관련 저수준 책임을 분리하여 캡슐화한 클래스입니다.
| 기능 | 상세 내용 |
|------|-----------|
| **포트 관리** | IO 및 압력 포트의 생성, 오픈, 클로즈, Dispose 주기 관리 |
| **폴링 루프** | 100ms `DispatcherTimer`를 구동하여 장비 상태 체크 명령 주기적 송신 |
| **버퍼 관리** | `DataReceived` 이벤트로 들어오는 단편화된 바이트를 패킷 단위로 조립 |
| **연결 상태** | 응답 타임아웃(1.5초) 감지 시 `bool` 기반 상태 갱신 및 이벤트 발행 |
| **자가 복구** | 포트 닫힘이나 연속 실패(10회) 감지 시 3초 간격 자동 재연결 시도 |
| **이벤트 발행** | 패킷 수신, 로그 발생, 연결 상태 변경 등을 이벤트를 통해 외부에 알림 |
### 4.4. `Services/SemiIOLiteController.cs` — I/O 보드 제어
LS산전 ASCII 프로토콜로 릴레이 출력을 제어하고 입력(i1, i2)을 읽습니다.
#### 릴레이 상태 (`RelayState` enum)
| 값 | 이름 | 동작 |
|----|------|------|
| `0` | `None` | 모든 릴레이 OFF (고정/밀폐 상태) |
| `1` | `Exhaust` | 릴레이1 ON — 배기 밸브 작동 |
| `2` | `Pressurize` | 릴레이2 ON — 인가 밸브 작동 |
| `3` | `Clamp` | 릴레이1+2 ON — 지그 물리 고정 |
#### 주요 메서드
| 메서드 | 역할 |
|--------|------|
| `SetStateAsync(RelayState)` | 릴레이 상태 변경 쓰기 명령 전송 + ACK 응답 대기 (최대 500ms) |
| `RequestInputState(onTx)` | 주소 `0A07`의 입력 상태 읽기 요청 전송 (비동기) |
| `ParseInputBuffer(buffer, out i1, out i2)` | 수신 버퍼를 파싱하여 i1, i2 디지털 입력 감지 |
| `CheckConnectionAsync()` | 주소 `0001` 읽기로 통신 유효성 확인 (핸드셰이크) |
### 4.5. `Services/PressureSensorController.cs` — 압력 센서 통신
KN-2240W 디지털 센서와 **Modbus RTU** 프로토콜로 통신합니다.
#### Modbus RTU 프레임 구조
| 구분 | 바이트 구성 |
|------|-------------|
| **요청 (8바이트)** | `[Slave Addr]` `[Func 0x04]` `[Start Addr Hi]` `[Start Addr Lo]` `[Count Hi]` `[Count Lo]` `[CRC Lo]` `[CRC Hi]` |
| **응답 (7바이트)** | `[Slave Addr]` `[Func 0x04]` `[Byte Count]` `[Data Hi]` `[Data Lo]` `[CRC Lo]` `[CRC Hi]` |
#### 주요 메서드
| 메서드 | 역할 |
|--------|------|
| `RequestCurrentPressure(onTx)` | 레지스터 `0x0000` 1개 읽기 요청 전송 |
| `ParsePressureResponse(buffer, out pressureValue)` | CRC 검증 + 데이터 파싱 후 원시 압력값 반환 |
| `BuildReadRequest(startAddress, count)` | Modbus RTU Read Input Registers 프레임 동적 생성 |
### 4.6. `ViewModels/MainViewModel.cs` — ★ 비즈니스 로직 및 UI 바인딩
통신 인프라를 제외한 순수 검사 시퀀스와 사용자 인터페이스 로직을 담당합니다. (~800줄)
#### 4.6.1. 이벤트 기반 데이터 처리
* `_connManager.IOPacketReceived` 구독: IO 보드 응답 시 `UpdateJigLamps` 호출
* `_connManager.PressurePacketReceived` 구독: 압력 센서 응답 시 압력값 갱신 및 UI 반영
#### 4.6.2. 자가 복구 (Self-Healing) 알고리즘 (ConnectionManager 내 구현)
```
[정상 동작] → 100ms 폴링 중 응답 수신
↓ 1.5초 무응답
[경고] → 램프 Red + 실패 카운터 증가
↓ 10회 연속 무응답
[단절 선언] → 포트 닫기 및 리소스 정리
↓ 즉시
[재연결 시도] → 3초 주기로 포트 재오픈 시도
```
#### 4.6.3. 수동 검사 시퀀스 (StartAutoHoldSequence)
```
[스위치 → 인가 위치] _wasPressurized = true
[스위치 → 고정 위치] && _wasPressurized
StartAutoHoldSequence() 트리거
(1) 현재 압력을 "검사 시작 압력"으로 저장
(2) HoldTime 초 동안 1초 간격 대기
(3) |최종 압력 - 시작 압력| vs AllowedErrorRange 비교
├── 이내 → PASS (LimeGreen)
└── 초과 → FAIL (Red)
```
#### 4.6.4. 자동 검사 시퀀스 (StartAutoCycleSequence)
```
[시작 버튼 클릭] (고정 상태에서만 가능)
단계 1: 인가(Pressurize) → 목표 압력 도달 대기
단계 2: 고정(None) → 밸브 폐쇄
단계 3: HoldTime 초 동안 압력 유지 검사
단계 4: 배기(Exhaust) → 0.0bar 도달 대기 (60초 타임아웃)
단계 5: 다시 고정(None) → 종료
```
#### 4.6.5. 주요 바인딩 프로퍼티 요약
| 카테고리 | 프로퍼티 | 용도 |
|----------|----------|------|
| **장비 램프** | `LampIOStatus`, `LampPressureStatus` | I/O / 압력 센서 연결 표시등 |
| **압력** | `CurrentPressureText`, `CurrentPressureColor` | 실시간 압력값 표시 |
| **수동 결과** | `ResultText`, `ResultColor` | PASS/FAIL 결과 표시 |
| **자동 결과** | `AutoResultText`, `AutoResultColor` | 자동 검사 PASS/FAIL |
| **로그** | `IOLogText`, `PrLogText` | I/O / 압력 센서 HEX 통신 로그 |
### 4.7. `ViewModels/SettingsViewModel` / `ParameterViewModel`
* 설정 복사본(`Clone`)을 사용한 원본 보호 및 취소 기능
* 시스템의 COM 포트 자동 감지 및 폴백 처리
* 입력 유효성 검증 (정규식 필터링 및 범위 체크)
### 4.8. `Views/MainWindow.xaml` — 메인 UI 구조
* `Viewbox Stretch="Uniform"`: 창 크기 변화에도 UI 비율 유지
* 커스텀 타이틀 바 + 탭 컨트롤 기반 화면 구성
* 실시간 로그 창 (I/O 녹색, 압력 파란색) 접이식 구현 및 자동 스크롤
---
## 5. 안정성 메커니즘
### 5.1. `bool` 기반 상태 관리 (Refactoring #11)
기존에는 UI 램프의 `Brush` 색상을 비교하여 통신 상태를 판단했으나, 리액터링을 통해 `_isIOConnected`, `_isPressureConnected` 명시적 필드를 도입하여 로직의 안정성과 가독성을 높였습니다.
### 5.2. 책임 분리 (Refactoring #10)
`ConnectionManager`를 통해 통신 인프라를 캡슐화했습니다. 메인 로직은 장치와의 직접적인 포트 관리에서 자유로워졌으며, 이벤트 기반으로 응답을 처리하여 UI 스레드 정지 현상을 방지합니다.
### 5.3. 글로벌 예외 처리 (`App.xaml.cs`)
`DispatcherUnhandledException`, `AppDomain.UnhandledException`, `TaskScheduler.UnobservedTaskException`을 모두 처리하여 예기치 못한 에러 시에도 프로그램이 강제 종료되지 않도록 보호합니다.
---
## 6. 설정 파일 (`config.xml`)
실행 파일 위치에 XML 형식으로 저장되며, 손상 시 자동으로 기본값으로 복원됩니다.
```xml
<?xml version="1.0" encoding="utf-8"?>
<AppConfig>
<PortName>COM3</PortName>
<BaudRate>9600</BaudRate>
<PressurePortName>COM4</PressurePortName>
<PressureBaudRate>9600</PressureBaudRate>
<IOEnabled>true</IOEnabled>
<IOStationId>2</IOStationId>
<PressureEnabled>true</PressureEnabled>
<HoldTime>30</HoldTime>
<AllowedErrorRange>0.3</AllowedErrorRange>
<AutoTestTargetPressure>4.0</AutoTestTargetPressure>
<IsLogVisible>false</IsLogVisible>
</AppConfig>
```
---
## 7. 유지보수 및 확장 가이드
### 새 검사 파라미터 추가 시
1. `Models/AppConfig.cs` 데이터 추가 및 `Clone()` 메서드 업데이트
2. `Views/ParameterWindow.xaml` 입력 UI 추가
3. `ViewModels/MainViewModel.UpdateParamDisplay()`에 반영
### 새 기기 추가 시
1. `Services/` 컨트롤러 구현 → `ConnectionManager.cs`에 인스턴스/폴링 추가
2. `MainViewModel.cs`에서 이벤트 구독 및 파싱 로직 연결