feat: Recipe 작업 화면 상단에 PLC 지시 Recipe/Page 표시

bit15(M70515) 팝업은 상승엣지 1회라 닫으면 값이 사라져, 현장에서 작업자가
레시피/페이지를 잊는 문제가 있었다. 팝업과 같은 기준·같은 워드를 화면 상단
전폭 띠로 ON 구간 내내 표시한다(Collapsed 시 높이 0이라 평소 화면 영향 없음).

공용(WeldingCommon)은 Status만 읽고 PTOP을 참조하지 않는다 —
값을 넣지 않는 타 설비는 분기문 없이 자동 미표시.
This commit is contained in:
노도연 2026-08-21 00:06:30 +09:00
parent 83018da4ac
commit c054439c19
4 changed files with 89 additions and 9 deletions

View File

@ -109,8 +109,10 @@ namespace ILSOS_PrismaticRD_PTOP.Views
CMD_VisibleChanged = new DelegateCommand(VisibleChanged);
CMD_RunSequenceAutoRun = new DelegateCommand(OnAutoRunStartRequest); // 260511 이곳 시퀸스
CMD_StopSequenceAutoRun = new DelegateCommand(OnStopSequenceAutoRun);
// 260813: 자동시작 요청 출처를 넘긴다 — OnAutoRunStartRequest 는 버튼/PLC 이벤트 공용 진입점이라
// 진입부 로그가 출처를 단정하면 안 된다(기존 문구가 버튼 클릭도 "AUTO_REQ"로 찍었다).
CMD_RunSequenceAutoRun = new DelegateCommand(o => OnAutoRunStartRequest("Button")); // 260511 이곳 시퀸스
CMD_StopSequenceAutoRun = new DelegateCommand(OnStopSequenceAutoRun); // 260813: 정지 시 에코 워드 0 초기화 재적용(조건부) — ResumeMode/M70515 구간만 보존, SeqAutoRunPTOP.OnSeqActionStop 260813 region
CMD_Reset = new DelegateCommand(PerformCmdReset);
CMD_AutoRunResume = new DelegateCommand(OnAutoRunResume);
@ -121,7 +123,7 @@ namespace ILSOS_PrismaticRD_PTOP.Views
//이벤트로 AUTORUN 스타트 요청에 대한 메소드 실행 오면 그때 동작함. 시퀸스 돔
_Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_AUTO_RUN_START_REQUEST)
.ObserveOnDispatcher()
.Subscribe(x => OnAutoRunStartRequest());
.Subscribe(x => OnAutoRunStartRequest("PLC_AUTO_REQ")); // 260813: 출처 명시(발행처는 PLCController.MonitorPlcInterfaceMap 뿐)
// Stop 요청 시 정지 로직 실행
_Aurora.EventObservable.AsObservable(CommonEventIds.EVENT_AUTO_RUN_STOP_REQUEST)
@ -208,6 +210,25 @@ namespace ILSOS_PrismaticRD_PTOP.Views
// 음극/양극 어느 쪽이 줘도 트리거 (AutoRun이 두 극을 함께 쓰는 구조와 동일)
bool bit15 = _Plc.ReadBit(eBitInput.PLC_WELD_READY_REQ).data;
IsModeChangeActive = bit15; // bit15 살아있을 때만 [AutoRun Resume] 버튼 표시
#region 260820 bit15 구간 Recipe/Page 를 Recipe 작업 화면에도 표시 (원복: 이 region 삭제)
// 팝업은 상승엣지 1회라 [확인] 을 누르면 값이 사라진다. 현장 소음 속에서 작업자가
// 몇 번 레시피 몇 페이지였는지 잊는다는 요청으로, Recipe 작업 화면 상단에도 같은 값을 띄운다.
// · 트리거: 팝업과 같은 bit15. 단 팝업은 엣지 1회, 표시는 ON 구간 내내 레벨 유지.
// · 값: 팝업이 읽는 두 워드 그대로(PLC 원본 입력). PC 에코(PC_*)가 아니다.
// 공용(WeldingCommon)은 Status 만 읽고 PTOP 을 참조하지 않는다 — 타 설비는 값이 없어 자동 미표시.
// 분석: docs/분석/2026/08/20/RecipePage_현장표시_레이아웃_분석.md
if (bit15)
{
Status.PlcGuideRecipeNo = _Plc.ReadWord(eWordInput.PLC_RECIPE_NO).data;
Status.PlcGuidePageNo = _Plc.ReadWord(eWordInput.PLC_PAGE_NO).data;
}
else if (Status.PlcGuideRecipeNo != null)
{
Status.PlcGuideRecipeNo = null;
Status.PlcGuidePageNo = null;
}
#endregion
if (bit15 && !_prevBit15 && !_isPopupOpen)
{
short r = _Plc.ReadWord(eWordInput.PLC_RECIPE_NO).data;
@ -292,7 +313,9 @@ namespace ILSOS_PrismaticRD_PTOP.Views
// 이어하기는 전용 [AutoRun Resume] 버튼(OnAutoRunResume) 경로라 이 가드와 무관.)
if (_Plc != null && !_Plc.IsSimul && _Plc.ReadBit(eBitInput.PLC_WELD_READY_REQ).data)
{
Log.I("[Bit15] bit15 ON 중 → AUTO_REQ 자동시작 무시 (Manual 유지)");
// 260813: 출처를 같이 남긴다. 이 메서드는 [운전 시작] 버튼과 PLC 이벤트가 공용으로 쓰는
// 진입점이라, 여기서 "AUTO_REQ"로 단정하면 버튼 클릭도 PLC 신호로 오독된다.
Log.I($"[Bit15] bit15 ON 중 → 자동시작 요청 무시 (요청출처:{obj ?? "unknown"}, Manual 유지)");
return;
}
@ -428,9 +451,6 @@ namespace ILSOS_PrismaticRD_PTOP.Views
//if (_SeqAutoRun.RunState == SequenceRunState.Running)
// _SeqAutoRun.Stop();
if (_SeqAutoRunPTOP.RunState == SequenceRunState.Running)
_SeqAutoRunPTOP.Stop();

View File

@ -52,5 +52,15 @@ namespace WeldingCommon
}
public static bool RMSUse { get; set; } = false;
#region 260820 PLC 지시 Recipe/Page (원복: 이 region 삭제)
// 설비별 시퀀스/VM 이 값을 넣고, 공용 Recipe 작업 화면이 읽어서 상단 띠에 표시한다.
// PTOP: UCMainAutoRunViewModel.OnMonitoring() 에서 bit15(M70515) ON 구간에만 대입, OFF 면 null.
// 여기에 두는 이유 — 공용 화면이 설비(PTOP)를 참조하지 않게 하려면 의존 방향을 뒤집어야 한다.
// 값을 넣지 않는 설비는 계속 null 이므로 분기문 없이 자동으로 미표시된다.
// ※ null = 표시 안 함. 0 은 "PLC 가 0을 줬다"는 유효한 상태라 null 과 구분한다.
public static short? PlcGuideRecipeNo { get; set; }
public static short? PlcGuidePageNo { get; set; }
#endregion
}
}

View File

@ -18,13 +18,35 @@
<behavior:InvokeCommandAction Command="{Binding CMD_VisibleChanged}" CommandParameter="{Binding IsVisible, ElementName=uc}"/>
</behavior:PropertyChangedTrigger>
</behavior:Interaction.Triggers>-->
<!-- 260820 PLC 지시 Recipe/Page 띠에서 사용 (원복: 이 Resources 블록 삭제) -->
<UserControl.Resources>
<view:BoolConverter x:Key="convTrueVisible" TrueValue="Visible" FalseValue="Collapsed"/>
</UserControl.Resources>
<Grid IsEnabled="{Binding IsManualStatus}">
<Grid.RowDefinitions>
<!-- 260820: Height="Auto" 라 띠가 Collapsed 면 높이 0 → 평소 화면은 종전과 동일하다 -->
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"></ColumnDefinition>
<ColumnDefinition Width="4*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<local:UCScannerObjectTeachingControlBox Grid.Column="0" Margin="0 0 0 0" DataContext="{Binding DataContext.ScannerObjectTeachingControlBoxViewModel, ElementName=uc}"></local:UCScannerObjectTeachingControlBox>
<WindowsFormsHost Grid.Column="1">
<!-- 260820 PLC 지시 Recipe/Page 띠 (원복: 이 Border 와 위 RowDefinitions 제거, 아래 Grid.Row 속성 제거)
bit15(M70515) ON 구간에만 표시된다. 값은 PLC 원본 워드이고 PC 에코가 아니다.
DataContext 는 바깥 VM(UCScannerObjectTeachingViewModel) 이라 ControlBox VM 을 경유해 바인딩한다.
분석: docs/분석/2026/08/20/RecipePage_현장표시_레이아웃_분석.md -->
<Border Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
Background="#2E7D46" BorderBrush="#7ED492" BorderThickness="0 0 0 2" Padding="12 7"
Visibility="{Binding ScannerObjectTeachingControlBoxViewModel.IsPlcGuideVisible, Converter={StaticResource convTrueVisible}}">
<TextBlock Text="{Binding ScannerObjectTeachingControlBoxViewModel.PlcGuideText}"
FontSize="22" FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<local:UCScannerObjectTeachingControlBox Grid.Row="1" Grid.Column="0" Margin="0 0 0 0" DataContext="{Binding DataContext.ScannerObjectTeachingControlBoxViewModel, ElementName=uc}"></local:UCScannerObjectTeachingControlBox>
<WindowsFormsHost Grid.Row="1" Grid.Column="1">
<lasa:MainPage x:Name="MainPageView" IsMdiContainer="False" TopLevel="False" />
</WindowsFormsHost>
</Grid>

View File

@ -82,6 +82,32 @@ namespace WeldingCommon.Views
private bool _IsObjectSelectAll;
public bool IsObjectSelectAll { get => _IsObjectSelectAll; set => SetProperty(ref _IsObjectSelectAll, value); }
#region 260820 PLC 지시 Recipe/Page 표시 (원복: 이 region + OnMonitoring 의 SyncPlcGuide() 호출 삭제)
// 값은 설비별로 Status 에 들어온다(PTOP: bit15 구간에만). 공용은 Status 만 읽으므로 설비 의존이 없다.
// 바인딩은 UCScannerObjectTeaching.xaml 상단 띠 — 그 화면의 DataContext(바깥 VM)가
// ScannerObjectTeachingControlBoxViewModel 을 공개하고 있어 여기 프로퍼티를 그대로 쓴다.
// (바깥 VM 에는 폴링 타이머가 없고 이 VM 에는 100ms 타이머가 이미 돌고 있어 재활용한다)
private bool _IsPlcGuideVisible;
public bool IsPlcGuideVisible { get => _IsPlcGuideVisible; set => SetProperty(ref _IsPlcGuideVisible, value); }
private string _PlcGuideText = string.Empty;
public string PlcGuideText { get => _PlcGuideText; set => SetProperty(ref _PlcGuideText, value); }
private void SyncPlcGuide()
{
var recipeNo = Status.PlcGuideRecipeNo;
var pageNo = Status.PlcGuidePageNo;
if (recipeNo == null || pageNo == null) {
IsPlcGuideVisible = false;
return;
}
PlcGuideText = $"RECIPE {recipeNo} PAGE {pageNo}";
IsPlcGuideVisible = true;
}
#endregion
// 레시피별 Laser 방향 발진 차단 체크 (Recipe_Laser_Interlock.json) — 변경 시 즉시 활성 레시피에 저장
private bool _IsFrontInterlock;
public bool IsFrontInterlock
@ -245,6 +271,8 @@ namespace WeldingCommon.Views
private void OnMonitoring(object sender, EventArgs e)
{
// 260820: 아래 IO 블록은 미연결 시 return 하므로, PLC 지시 표시는 반드시 그 앞에서 갱신한다.
SyncPlcGuide();
// [기존 소스 보존] Laser 디바이스 기반 Pilot 상태 (DO 3=GuideLaserEnable) — 일부 Laser 미구현 시 항상 false
//if (_Laser.GetPilotLaserStatus()) {