initial commit

This commit is contained in:
2025-11-25 20:14:41 +09:00
commit 5cb1ff372c
559 changed files with 149800 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@@ -0,0 +1,14 @@
################################################################################
# 이 .gitignore 파일은 Microsoft(R) Visual Studio에서 자동으로 만들어졌습니다.
################################################################################
/VisionCrevis(WinSock)_Euresys_v22
*.suo
*.user
*.pdb
bin
obj
desktop.ini
.vs
packages
*.zip

24
FrontEnd/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

224
FrontEnd/App.tsx Normal file
View File

@@ -0,0 +1,224 @@
import React, { useState, useEffect, useRef } from 'react';
import { HashRouter, Routes, Route } from 'react-router-dom';
import { Layout } from './components/layout/Layout';
import { HomePage } from './pages/HomePage';
import { IOMonitorPage } from './pages/IOMonitorPage';
import { RecipePage } from './pages/RecipePage';
import { SystemState, Recipe, IOPoint, LogEntry, RobotTarget, ConfigItem } from './types';
import { comms } from './communication';
// --- MOCK DATA ---
const INITIAL_IO: IOPoint[] = [
...Array.from({ length: 32 }, (_, i) => {
let name = `DOUT_${i.toString().padStart(2, '0')}`;
if (i === 0) name = "Tower Lamp Red";
if (i === 1) name = "Tower Lamp Yel";
if (i === 2) name = "Tower Lamp Grn";
return { id: i, name, type: 'output' as const, state: false };
}),
...Array.from({ length: 32 }, (_, i) => {
let name = `DIN_${i.toString().padStart(2, '0')}`;
let initialState = false;
if (i === 0) name = "Front Door Sensor";
if (i === 1) name = "Right Door Sensor";
if (i === 2) name = "Left Door Sensor";
if (i === 3) name = "Back Door Sensor";
if (i === 4) { name = "Main Air Pressure"; initialState = true; }
if (i === 5) { name = "Vacuum Generator"; initialState = true; }
if (i === 6) { name = "Emergency Stop Loop"; initialState = true; }
return { id: i, name, type: 'input' as const, state: initialState };
})
];
// --- MAIN APP ---
export default function App() {
const [activeTab, setActiveTab] = useState<'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null>(null);
const [systemState, setSystemState] = useState<SystemState>(SystemState.IDLE);
const [currentRecipe, setCurrentRecipe] = useState<Recipe>({ id: '0', name: 'No Recipe', lastModified: '-' });
const [robotTarget, setRobotTarget] = useState<RobotTarget>({ x: 0, y: 0, z: 0 });
const [logs, setLogs] = useState<LogEntry[]>([]);
const [ioPoints, setIoPoints] = useState<IOPoint[]>([]);
const [currentTime, setCurrentTime] = useState(new Date());
const [isLoading, setIsLoading] = useState(true);
const [isHostConnected, setIsHostConnected] = useState(false);
const videoRef = useRef<HTMLVideoElement>(null);
// -- COMMUNICATION LAYER --
useEffect(() => {
const unsubscribe = comms.subscribe((msg: any) => {
if (!msg) return;
if (msg.type === 'CONNECTION_STATE') {
setIsHostConnected(msg.connected);
addLog(msg.connected ? "HOST CONNECTED" : "HOST DISCONNECTED", msg.connected ? "info" : "warning");
}
if (msg.type === 'STATUS_UPDATE') {
if (msg.position) {
setRobotTarget({ x: msg.position.x, y: msg.position.y, z: msg.position.z });
}
if (msg.ioState) {
setIoPoints(prev => {
const newIO = [...prev];
msg.ioState.forEach((update: { id: number, type: string, state: boolean }) => {
const idx = newIO.findIndex(p => p.id === update.id && p.type === update.type);
if (idx >= 0) newIO[idx] = { ...newIO[idx], state: update.state };
});
return newIO;
});
}
if (msg.sysState) {
setSystemState(msg.sysState as SystemState);
}
}
});
addLog("COMMUNICATION CHANNEL OPEN", "info");
setIsHostConnected(comms.getConnectionState());
const timer = setInterval(() => setCurrentTime(new Date()), 1000);
return () => {
clearInterval(timer);
unsubscribe();
};
}, []);
// -- INITIALIZATION --
useEffect(() => {
const initSystem = async () => {
addLog("SYSTEM STARTED", "info");
// Initial IO data will be loaded by HomePage when it mounts
try {
const ioStr = await comms.getIOList();
const ioData = JSON.parse(ioStr);
setIoPoints(ioData);
addLog("IO LIST LOADED", "info");
} catch (e) {
addLog("FAILED TO LOAD IO DATA", "error");
}
setIsLoading(false);
};
initSystem();
}, []);
const addLog = (msg: string, type: 'info' | 'warning' | 'error' = 'info') => {
setLogs(prev => [{ id: Date.now() + Math.random(), timestamp: new Date().toLocaleTimeString(), message: msg, type }, ...prev].slice(0, 50));
};
// Logic Helpers
const doorStates = {
front: ioPoints.find(p => p.id === 0 && p.type === 'input')?.state || false,
right: ioPoints.find(p => p.id === 1 && p.type === 'input')?.state || false,
left: ioPoints.find(p => p.id === 2 && p.type === 'input')?.state || false,
back: ioPoints.find(p => p.id === 3 && p.type === 'input')?.state || false,
};
const isLowPressure = !(ioPoints.find(p => p.id === 4 && p.type === 'input')?.state ?? true);
const isEmergencyStop = !(ioPoints.find(p => p.id === 6 && p.type === 'input')?.state ?? true);
// -- COMMAND HANDLERS --
const handleControl = async (action: 'start' | 'stop' | 'reset') => {
if (isEmergencyStop && action === 'start') return addLog('EMERGENCY STOP ACTIVE', 'error');
try {
await comms.sendControl(action.toUpperCase());
addLog(`CMD SENT: ${action.toUpperCase()}`, 'info');
} catch (e) {
addLog('COMM ERROR', 'error');
}
};
const toggleIO = async (id: number, type: 'input' | 'output', forceState?: boolean) => {
if (type === 'output') {
const current = ioPoints.find(p => p.id === id && p.type === type)?.state;
const nextState = forceState !== undefined ? forceState : !current;
await comms.setIO(id, nextState);
}
};
const moveAxis = async (axis: 'X' | 'Y' | 'Z', value: number) => {
if (isEmergencyStop) return;
await comms.moveAxis(axis, value);
addLog(`CMD MOVE ${axis}: ${value}`, 'info');
};
const handleSaveConfig = async (newConfig: ConfigItem[]) => {
try {
await comms.saveConfig(JSON.stringify(newConfig));
addLog("CONFIGURATION SAVED", "info");
} catch (e) {
console.error(e);
addLog("FAILED TO SAVE CONFIG", "error");
}
};
const handleSelectRecipe = async (r: Recipe) => {
try {
addLog(`LOADING: ${r.name}`, 'info');
const result = await comms.selectRecipe(r.id);
if (result.success) {
setCurrentRecipe(r);
addLog(`RECIPE LOADED: ${r.name}`, 'info');
} else {
addLog(`RECIPE LOAD FAILED: ${result.message}`, 'error');
}
} catch (error: any) {
addLog(`RECIPE LOAD ERROR: ${error.message || 'Unknown error'}`, 'error');
console.error('Recipe selection error:', error);
}
};
return (
<HashRouter>
<Layout
currentTime={currentTime}
isHostConnected={isHostConnected}
robotTarget={robotTarget}
onTabChange={setActiveTab}
activeTab={activeTab}
isLoading={isLoading}
>
<Routes>
<Route
path="/"
element={
<HomePage
systemState={systemState}
currentRecipe={currentRecipe}
robotTarget={robotTarget}
logs={logs}
ioPoints={ioPoints}
doorStates={doorStates}
isLowPressure={isLowPressure}
isEmergencyStop={isEmergencyStop}
activeTab={activeTab}
onSelectRecipe={handleSelectRecipe}
onMove={moveAxis}
onControl={handleControl}
onSaveConfig={handleSaveConfig}
onCloseTab={() => setActiveTab(null)}
videoRef={videoRef}
/>
}
/>
<Route
path="/io-monitor"
element={
<IOMonitorPage
onToggle={toggleIO}
/>
}
/>
<Route
path="/recipe"
element={<RecipePage />}
/>
</Routes>
</Layout>
</HashRouter>
);
}

20
FrontEnd/README.md Normal file
View File

@@ -0,0 +1,20 @@
<div align="center">
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
</div>
# Run and deploy your AI Studio app
This contains everything you need to run your app locally.
View your app in AI Studio: https://ai.studio/apps/drive/1WUaQ4phJ_kZujzyiakV5X8RFgCwgaUDq
## Run Locally
**Prerequisites:** Node.js
1. Install dependencies:
`npm install`
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
3. Run the app:
`npm run dev`

10
FrontEnd/build.bat Normal file
View File

@@ -0,0 +1,10 @@
@echo off
echo Building Frontend...
call npm run build
if %ERRORLEVEL% NEQ 0 (
echo Build Failed!
pause
exit /b %ERRORLEVEL%
)
echo Build Success!
pause

289
FrontEnd/communication.ts Normal file
View File

@@ -0,0 +1,289 @@
// Check if running in WebView2
const isWebView = typeof window !== 'undefined' && !!window.chrome?.webview;
// 비동기 프록시 캐싱 (한 번만 초기화) - 매번 접근 시 오버헤드 제거
const machine = isWebView ? window.chrome!.webview!.hostObjects.machine : null;
type MessageCallback = (data: any) => void;
class CommunicationLayer {
private listeners: MessageCallback[] = [];
private ws: WebSocket | null = null;
private isConnected = false;
constructor() {
if (isWebView) {
console.log("[COMM] Running in WebView2 Mode");
this.isConnected = true; // WebView2 is always connected
window.chrome!.webview!.addEventListener('message', (event: any) => {
this.notifyListeners(event.data);
});
} else {
console.log("[COMM] Running in Browser Mode (WebSocket)");
this.connectWebSocket();
}
}
private connectWebSocket() {
this.ws = new WebSocket('ws://localhost:8081');
this.ws.onopen = () => {
console.log("[COMM] WebSocket Connected");
this.isConnected = true;
this.notifyListeners({ type: 'CONNECTION_STATE', connected: true });
};
this.ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
this.notifyListeners(data);
} catch (e) {
console.error("[COMM] JSON Parse Error", e);
}
};
this.ws.onclose = () => {
console.log("[COMM] WebSocket Closed. Reconnecting...");
this.isConnected = false;
this.notifyListeners({ type: 'CONNECTION_STATE', connected: false });
setTimeout(() => this.connectWebSocket(), 2000);
};
this.ws.onerror = (err) => {
console.error("[COMM] WebSocket Error", err);
};
}
private notifyListeners(data: any) {
this.listeners.forEach(cb => cb(data));
}
public subscribe(callback: MessageCallback) {
this.listeners.push(callback);
return () => {
this.listeners = this.listeners.filter(cb => cb !== callback);
};
}
public getConnectionState(): boolean {
return this.isConnected;
}
// --- API Methods ---
public async getConfig(): Promise<string> {
if (isWebView && machine) {
return await machine.GetConfig();
} else {
// WebSocket Request/Response Pattern
return new Promise((resolve, reject) => {
// 1. Wait for Connection (max 2s)
if (!this.isConnected) {
// Simple wait logic (could be improved)
setTimeout(() => {
if (!this.isConnected) reject("WebSocket connection timeout");
}, 2000);
}
// 2. Send Request with Timeout (max 10s)
const timeoutId = setTimeout(() => {
this.listeners = this.listeners.filter(cb => cb !== handler);
reject("Config fetch timeout");
}, 10000);
const handler = (data: any) => {
if (data.type === 'CONFIG_DATA') {
clearTimeout(timeoutId);
this.listeners = this.listeners.filter(cb => cb !== handler);
resolve(JSON.stringify(data.data));
}
};
this.listeners.push(handler);
this.ws?.send(JSON.stringify({ type: 'GET_CONFIG' }));
});
}
}
public async getIOList(): Promise<string> {
if (isWebView && machine) {
return await machine.GetIOList();
} else {
return new Promise((resolve, reject) => {
if (!this.isConnected) {
setTimeout(() => {
if (!this.isConnected) reject("WebSocket connection timeout");
}, 2000);
}
const timeoutId = setTimeout(() => {
this.listeners = this.listeners.filter(cb => cb !== handler);
reject("IO fetch timeout");
}, 10000);
const handler = (data: any) => {
if (data.type === 'IO_LIST_DATA') {
clearTimeout(timeoutId);
this.listeners = this.listeners.filter(cb => cb !== handler);
resolve(JSON.stringify(data.data));
}
};
this.listeners.push(handler);
this.ws?.send(JSON.stringify({ type: 'GET_IO_LIST' }));
});
}
}
public async getRecipeList(): Promise<string> {
if (isWebView && machine) {
return await machine.GetRecipeList();
} else {
return new Promise((resolve, reject) => {
if (!this.isConnected) {
setTimeout(() => {
if (!this.isConnected) reject("WebSocket connection timeout");
}, 2000);
}
const timeoutId = setTimeout(() => {
this.listeners = this.listeners.filter(cb => cb !== handler);
reject("Recipe fetch timeout");
}, 10000);
const handler = (data: any) => {
if (data.type === 'RECIPE_LIST_DATA') {
clearTimeout(timeoutId);
this.listeners = this.listeners.filter(cb => cb !== handler);
resolve(JSON.stringify(data.data));
}
};
this.listeners.push(handler);
this.ws?.send(JSON.stringify({ type: 'GET_RECIPE_LIST' }));
});
}
}
public async saveConfig(configJson: string): Promise<void> {
if (isWebView && machine) {
await machine.SaveConfig(configJson);
} else {
this.ws?.send(JSON.stringify({ type: 'SAVE_CONFIG', data: JSON.parse(configJson) }));
}
}
public async sendControl(command: string) {
if (isWebView && machine) {
await machine.SystemControl(command);
} else {
this.ws?.send(JSON.stringify({ type: 'CONTROL', command }));
}
}
public async moveAxis(axis: string, value: number) {
if (isWebView && machine) {
await machine.MoveAxis(axis, value);
} else {
this.ws?.send(JSON.stringify({ type: 'MOVE', axis, value }));
}
}
public async setIO(id: number, state: boolean) {
if (isWebView && machine) {
await machine.SetIO(id, false, state);
} else {
this.ws?.send(JSON.stringify({ type: 'SET_IO', id, state }));
}
}
public async selectRecipe(recipeId: string): Promise<{ success: boolean; message: string; recipeId?: string }> {
if (isWebView && machine) {
const resultJson = await machine.SelectRecipe(recipeId);
return JSON.parse(resultJson);
} else {
return new Promise((resolve, reject) => {
if (!this.isConnected) {
setTimeout(() => {
if (!this.isConnected) reject({ success: false, message: "WebSocket connection timeout" });
}, 2000);
}
const timeoutId = setTimeout(() => {
this.listeners = this.listeners.filter(cb => cb !== handler);
reject({ success: false, message: "Recipe selection timeout" });
}, 10000);
const handler = (data: any) => {
if (data.type === 'RECIPE_SELECTED') {
clearTimeout(timeoutId);
this.listeners = this.listeners.filter(cb => cb !== handler);
resolve(data.data);
}
};
this.listeners.push(handler);
this.ws?.send(JSON.stringify({ type: 'SELECT_RECIPE', recipeId }));
});
}
}
public async copyRecipe(recipeId: string, newName: string): Promise<{ success: boolean; message: string; newRecipe?: any }> {
if (isWebView && machine) {
const resultJson = await machine.CopyRecipe(recipeId, newName);
return JSON.parse(resultJson);
} else {
return new Promise((resolve, reject) => {
if (!this.isConnected) {
setTimeout(() => {
if (!this.isConnected) reject({ success: false, message: "WebSocket connection timeout" });
}, 2000);
}
const timeoutId = setTimeout(() => {
this.listeners = this.listeners.filter(cb => cb !== handler);
reject({ success: false, message: "Recipe copy timeout" });
}, 10000);
const handler = (data: any) => {
if (data.type === 'RECIPE_COPIED') {
clearTimeout(timeoutId);
this.listeners = this.listeners.filter(cb => cb !== handler);
resolve(data.data);
}
};
this.listeners.push(handler);
this.ws?.send(JSON.stringify({ type: 'COPY_RECIPE', recipeId, newName }));
});
}
}
public async deleteRecipe(recipeId: string): Promise<{ success: boolean; message: string; recipeId?: string }> {
if (isWebView && machine) {
const resultJson = await machine.DeleteRecipe(recipeId);
return JSON.parse(resultJson);
} else {
return new Promise((resolve, reject) => {
if (!this.isConnected) {
setTimeout(() => {
if (!this.isConnected) reject({ success: false, message: "WebSocket connection timeout" });
}, 2000);
}
const timeoutId = setTimeout(() => {
this.listeners = this.listeners.filter(cb => cb !== handler);
reject({ success: false, message: "Recipe delete timeout" });
}, 10000);
const handler = (data: any) => {
if (data.type === 'RECIPE_DELETED') {
clearTimeout(timeoutId);
this.listeners = this.listeners.filter(cb => cb !== handler);
resolve(data.data);
}
};
this.listeners.push(handler);
this.ws?.send(JSON.stringify({ type: 'DELETE_RECIPE', recipeId }));
});
}
}
}
export const comms = new CommunicationLayer();

View File

@@ -0,0 +1,39 @@
import React from 'react';
import { Camera, Crosshair } from 'lucide-react';
import { PanelHeader } from './common/PanelHeader';
interface CameraPanelProps {
videoRef: React.RefObject<HTMLVideoElement>;
}
export const CameraPanel: React.FC<CameraPanelProps> = ({ videoRef }) => (
<div className="h-full flex flex-col">
<PanelHeader title="Vision Feed" icon={Camera} />
<div className="flex-1 bg-black relative overflow-hidden border border-slate-800 group">
<video ref={videoRef} autoPlay playsInline className="w-full h-full object-cover opacity-80" />
{/* HUD OVERLAY */}
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-0 left-0 w-full h-full border-[20px] border-neon-blue/10 clip-tech-inv"></div>
<Crosshair className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-12 h-12 text-neon-blue opacity-50" />
<div className="absolute top-4 right-4 flex flex-col items-end gap-1">
<span className="text-[10px] font-mono text-neon-red animate-pulse"> REC</span>
<span className="text-xs font-mono text-neon-blue">1920x1080 @ 60FPS</span>
</div>
<div className="absolute bottom-4 left-4 text-neon-blue/80 font-mono text-xs">
EXPOSURE: AUTO<br />
GAIN: 12dB<br />
FOCUS: 150mm
</div>
</div>
</div>
<div className="grid grid-cols-4 gap-2 mt-3">
<button className="bg-slate-800 text-slate-400 text-[10px] py-2 hover:bg-neon-blue hover:text-black transition-colors">ZOOM +</button>
<button className="bg-slate-800 text-slate-400 text-[10px] py-2 hover:bg-neon-blue hover:text-black transition-colors">ZOOM -</button>
<button className="bg-slate-800 text-slate-400 text-[10px] py-2 hover:bg-neon-blue hover:text-black transition-colors">SNAP</button>
<button className="bg-slate-800 text-slate-400 text-[10px] py-2 hover:bg-neon-blue hover:text-black transition-colors">SETTINGS</button>
</div>
</div>
);

View File

@@ -0,0 +1,50 @@
import React, { useState } from 'react';
import { Activity } from 'lucide-react';
import { IOPoint } from '../types';
import { PanelHeader } from './common/PanelHeader';
import { TechButton } from './common/TechButton';
interface IOPanelProps {
ioPoints: IOPoint[];
onToggle: (id: number, type: 'input' | 'output') => void;
}
export const IOPanel: React.FC<IOPanelProps> = ({ ioPoints, onToggle }) => {
const [tab, setTab] = useState<'in' | 'out'>('in');
const points = ioPoints.filter(p => p.type === (tab === 'in' ? 'input' : 'output'));
return (
<div className="h-full flex flex-col">
<PanelHeader title="I/O Monitor" icon={Activity} />
<div className="flex gap-2 mb-4">
<TechButton active={tab === 'in'} onClick={() => setTab('in')} className="flex-1">Inputs</TechButton>
<TechButton active={tab === 'out'} onClick={() => setTab('out')} className="flex-1" variant="blue">Outputs</TechButton>
</div>
<div className="grid grid-cols-4 gap-2 overflow-y-auto pr-2 custom-scrollbar pb-4">
{points.map(p => (
<div
key={p.id}
onClick={() => onToggle(p.id, p.type)}
className={`
aspect-square flex flex-col items-center justify-center p-1 cursor-pointer transition-all border
clip-tech
${p.state
? (p.type === 'output'
? 'bg-neon-green/10 border-neon-green text-neon-green shadow-[0_0_10px_rgba(10,255,0,0.3)]'
: 'bg-neon-yellow/10 border-neon-yellow text-neon-yellow shadow-[0_0_10px_rgba(255,230,0,0.3)]')
: 'bg-slate-900/50 border-slate-700 text-slate-600 hover:border-slate-500'}
`}
>
<div className={`w-2 h-2 rounded-full mb-2 ${p.state ? (p.type === 'output' ? 'bg-neon-green' : 'bg-neon-yellow') : 'bg-slate-800'}`}></div>
<span className="font-mono text-[10px] font-bold">
{p.type === 'input' ? 'I' : 'Q'}{p.id.toString().padStart(2, '0')}
</span>
<span className="text-[8px] text-center uppercase leading-tight mt-1 opacity-80 truncate w-full px-1">
{p.name.replace(/(Sensor|Door|Lamp)/g, '')}
</span>
</div>
))}
</div>
</div>
);
};

View File

@@ -0,0 +1,181 @@
import React, { useState, useEffect } from 'react';
import { Target, CheckCircle2, Loader2 } from 'lucide-react';
import { TechButton } from './common/TechButton';
interface InitializeModalProps {
isOpen: boolean;
onClose: () => void;
}
type AxisStatus = 'pending' | 'initializing' | 'completed';
interface AxisState {
name: string;
status: AxisStatus;
progress: number;
}
export const InitializeModal: React.FC<InitializeModalProps> = ({ isOpen, onClose }) => {
const [axes, setAxes] = useState<AxisState[]>([
{ name: 'X-Axis', status: 'pending', progress: 0 },
{ name: 'Y-Axis', status: 'pending', progress: 0 },
{ name: 'Z-Axis', status: 'pending', progress: 0 },
]);
const [isInitializing, setIsInitializing] = useState(false);
// Reset state when modal closes
useEffect(() => {
if (!isOpen) {
setAxes([
{ name: 'X-Axis', status: 'pending', progress: 0 },
{ name: 'Y-Axis', status: 'pending', progress: 0 },
{ name: 'Z-Axis', status: 'pending', progress: 0 },
]);
setIsInitializing(false);
}
}, [isOpen]);
const startInitialization = () => {
setIsInitializing(true);
// Initialize each axis with 3 second delay between them
axes.forEach((axis, index) => {
const delay = index * 3000; // 0s, 3s, 6s
// Start initialization after delay
setTimeout(() => {
setAxes(prev => {
const next = [...prev];
next[index] = { ...next[index], status: 'initializing', progress: 0 };
return next;
});
// Progress animation (3 seconds)
const startTime = Date.now();
const duration = 3000;
const interval = setInterval(() => {
const elapsed = Date.now() - startTime;
const progress = Math.min((elapsed / duration) * 100, 100);
setAxes(prev => {
const next = [...prev];
next[index] = { ...next[index], progress };
return next;
});
if (progress >= 100) {
clearInterval(interval);
setAxes(prev => {
const next = [...prev];
next[index] = { ...next[index], status: 'completed', progress: 100 };
return next;
});
// Check if all axes are completed
setAxes(prev => {
if (prev.every(a => a.status === 'completed')) {
// Auto close after 500ms
setTimeout(() => {
onClose();
}, 500);
}
return prev;
});
}
}, 50);
}, delay);
});
};
if (!isOpen) return null;
const allCompleted = axes.every(a => a.status === 'completed');
return (
<div className="absolute inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
<div className="w-[600px] glass-holo p-8 border border-neon-blue shadow-glow-blue relative flex flex-col">
<button
onClick={onClose}
disabled={isInitializing}
className="absolute top-4 right-4 text-slate-400 hover:text-white disabled:opacity-30 disabled:cursor-not-allowed"
>
</button>
<h2 className="text-2xl font-tech font-bold text-neon-blue mb-8 border-b border-white/10 pb-4 flex items-center gap-3">
<Target className="animate-pulse" /> AXIS INITIALIZATION
</h2>
<div className="space-y-6 mb-8">
{axes.map((axis, index) => (
<div key={axis.name} className="space-y-2">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
{axis.status === 'completed' ? (
<CheckCircle2 className="w-5 h-5 text-neon-green" />
) : axis.status === 'initializing' ? (
<Loader2 className="w-5 h-5 text-neon-blue animate-spin" />
) : (
<div className="w-5 h-5 border-2 border-slate-600 rounded-full" />
)}
<span className="font-tech font-bold text-lg text-white tracking-wider">
{axis.name}
</span>
</div>
<span
className={`font-mono text-sm font-bold ${
axis.status === 'completed'
? 'text-neon-green'
: axis.status === 'initializing'
? 'text-neon-blue'
: 'text-slate-500'
}`}
>
{axis.status === 'completed'
? 'COMPLETED'
: axis.status === 'initializing'
? `${Math.round(axis.progress)}%`
: 'WAITING'}
</span>
</div>
{/* Progress Bar */}
<div className="h-3 bg-black/50 border border-slate-700 overflow-hidden">
<div
className={`h-full transition-all duration-100 ${
axis.status === 'completed'
? 'bg-neon-green shadow-[0_0_10px_rgba(10,255,0,0.5)]'
: 'bg-neon-blue shadow-[0_0_10px_rgba(0,243,255,0.5)]'
}`}
style={{ width: `${axis.progress}%` }}
/>
</div>
</div>
))}
</div>
{allCompleted && (
<div className="mb-6 p-4 bg-neon-green/10 border border-neon-green rounded text-center">
<span className="font-tech font-bold text-neon-green tracking-wider">
ALL AXES INITIALIZED SUCCESSFULLY
</span>
</div>
)}
<div className="flex justify-end gap-4">
<TechButton onClick={onClose} disabled={isInitializing}>
CANCEL
</TechButton>
<TechButton
variant="blue"
active
onClick={startInitialization}
disabled={isInitializing || allCompleted}
>
{isInitializing ? 'INITIALIZING...' : 'START INITIALIZATION'}
</TechButton>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,633 @@
import React, { useRef, useMemo } from 'react';
import { Canvas, useFrame } from '@react-three/fiber';
import { OrbitControls, Grid, PerspectiveCamera, Text, Box, Environment, RoundedBox } from '@react-three/drei';
import * as THREE from 'three';
import { RobotTarget, IOPoint } from '../types';
interface Machine3DProps {
target: RobotTarget;
ioState: IOPoint[];
doorStates: {
front: boolean;
right: boolean;
left: boolean;
back: boolean;
};
}
// -- Parts Components --
const TowerLamp = ({ ioState }: { ioState: IOPoint[] }) => {
// Outputs 0,1,2 mapped to Red, Yellow, Green
const redOn = ioState.find(io => io.id === 0 && io.type === 'output')?.state;
const yellowOn = ioState.find(io => io.id === 1 && io.type === 'output')?.state;
const greenOn = ioState.find(io => io.id === 2 && io.type === 'output')?.state;
const redMat = useRef<THREE.MeshStandardMaterial>(null);
const yelMat = useRef<THREE.MeshStandardMaterial>(null);
const grnMat = useRef<THREE.MeshStandardMaterial>(null);
useFrame((state) => {
const time = state.clock.elapsedTime;
const pulse = (Math.sin(time * 6) * 0.5 + 0.5);
const intensity = 0.5 + (pulse * 3.0);
if (redMat.current) {
redMat.current.emissiveIntensity = redOn ? intensity : 0;
redMat.current.opacity = redOn ? 1.0 : 0.3;
redMat.current.color.setHex(redOn ? 0xff0000 : 0x550000);
}
if (yelMat.current) {
yelMat.current.emissiveIntensity = yellowOn ? intensity : 0;
yelMat.current.opacity = yellowOn ? 1.0 : 0.3;
yelMat.current.color.setHex(yellowOn ? 0xffff00 : 0x555500);
}
if (grnMat.current) {
grnMat.current.emissiveIntensity = greenOn ? intensity : 0;
grnMat.current.opacity = greenOn ? 1.0 : 0.3;
grnMat.current.color.setHex(greenOn ? 0x00ff00 : 0x005500);
}
});
return (
<group position={[1.8, 2.5, -1.8]}>
{/* Pole */}
<mesh position={[0, 0, 0]}>
<cylinderGeometry args={[0.05, 0.05, 0.5]} />
<meshStandardMaterial color="#333" roughness={0.5} />
</mesh>
{/* Green */}
<mesh position={[0, 0.3, 0]}>
<cylinderGeometry args={[0.08, 0.08, 0.15]} />
<meshStandardMaterial
ref={grnMat}
color="#00ff00"
emissive="#00ff00"
transparent
toneMapped={false}
/>
</mesh>
{/* Yellow */}
<mesh position={[0, 0.46, 0]}>
<cylinderGeometry args={[0.08, 0.08, 0.15]} />
<meshStandardMaterial
ref={yelMat}
color="#ffff00"
emissive="#ffff00"
transparent
toneMapped={false}
/>
</mesh>
{/* Red */}
<mesh position={[0, 0.62, 0]}>
<cylinderGeometry args={[0.08, 0.08, 0.15]} />
<meshStandardMaterial
ref={redMat}
color="#ff0000"
emissive="#ff0000"
transparent
toneMapped={false}
/>
</mesh>
</group>
);
};
// -- DIPPING STATION COMPONENTS --
const LiquidBath = ({
position,
label,
liquidColor,
}: {
position: [number, number, number],
label: string,
liquidColor: string,
}) => {
const width = 1.0;
const depth = 0.8;
const height = 0.3;
const wallThick = 0.03;
const SteelMaterial = (
<meshStandardMaterial color="#e2e8f0" metalness={0.95} roughness={0.2} />
);
return (
<group position={position}>
<group position={[0, height / 2, 0]}>
<mesh position={[0, -height/2 + wallThick/2, 0]}>
<boxGeometry args={[width, wallThick, depth]} />
{SteelMaterial}
</mesh>
<mesh position={[0, 0, depth/2 - wallThick/2]}>
<boxGeometry args={[width, height, wallThick]} />
{SteelMaterial}
</mesh>
<mesh position={[0, 0, -depth/2 + wallThick/2]}>
<boxGeometry args={[width, height, wallThick]} />
{SteelMaterial}
</mesh>
<mesh position={[-width/2 + wallThick/2, 0, 0]}>
<boxGeometry args={[wallThick, height, depth - wallThick*2]} />
{SteelMaterial}
</mesh>
<mesh position={[width/2 - wallThick/2, 0, 0]}>
<boxGeometry args={[wallThick, height, depth - wallThick*2]} />
{SteelMaterial}
</mesh>
<mesh position={[0, height/2 - 0.05, 0]} rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[width - wallThick*2, depth - wallThick*2]} />
<meshPhysicalMaterial
color={liquidColor}
transparent
opacity={0.85}
roughness={0.05}
metalness={0.2}
transmission={0.4}
thickness={1}
clearcoat={1}
/>
</mesh>
</group>
<Text
position={[0, 0.6, 0.55]}
fontSize={0.12}
color="white"
anchorX="center"
anchorY="middle"
rotation={[-Math.PI/4, 0, 0]}
>
{label}
</Text>
</group>
);
};
const HakkoFX305 = ({ position }: { position: [number, number, number] }) => {
return (
<group position={position}>
{/* Main Blue Chassis */}
<mesh position={[0, 0.25, 0]}>
<boxGeometry args={[1.3, 0.55, 1.0]} />
<meshStandardMaterial color="#2563eb" metalness={0.1} roughness={0.4} />
</mesh>
<mesh position={[-0.66, 0.25, 0]}>
<boxGeometry args={[0.02, 0.3, 0.6]} />
<meshStandardMaterial color="#1e3a8a" />
</mesh>
<mesh position={[0.66, 0.25, 0]}>
<boxGeometry args={[0.02, 0.3, 0.6]} />
<meshStandardMaterial color="#1e3a8a" />
</mesh>
<mesh position={[0, 0.25, 0.51]}>
<planeGeometry args={[1.25, 0.5]} />
<meshStandardMaterial color="#cbd5e1" metalness={0.6} roughness={0.3} />
</mesh>
<Text
position={[0, 0.42, 0.52]}
fontSize={0.08}
color="#2563eb"
anchorX="center"
anchorY="middle"
fontWeight="bold"
>
HAKKO
</Text>
<Text
position={[0.5, 0.42, 0.52]}
fontSize={0.04}
color="#64748b"
anchorX="right"
anchorY="middle"
>
FX-305
</Text>
<mesh position={[0.15, 0.25, 0.52]}>
<planeGeometry args={[0.35, 0.15]} />
<meshStandardMaterial color="#0f172a" roughness={0.2} />
</mesh>
<group position={[-0.45, 0.25, 0.52]} rotation={[Math.PI/2, 0, 0]}>
<mesh>
<cylinderGeometry args={[0.08, 0.08, 0.02, 32]} />
<meshStandardMaterial color="#1e293b" />
</mesh>
<mesh position={[0, 0.02, 0]} rotation={[0, 0, Math.PI/2]}>
<boxGeometry args={[0.02, 0.08, 0.01]} />
<meshStandardMaterial color="#475569" />
</mesh>
</group>
<group position={[0.15, 0.12, 0.52]}>
{[-0.12, 0, 0.12, 0.24].map((x, i) => (
<mesh key={i} position={[x, 0, 0]} rotation={[Math.PI/2, 0, 0]}>
<cylinderGeometry args={[0.035, 0.035, 0.02, 16]} />
<meshStandardMaterial color="#facc15" />
</mesh>
))}
</group>
<mesh position={[0, 0.55, 0]}>
<boxGeometry args={[0.9, 0.05, 0.7]} />
<meshStandardMaterial color="#94a3b8" metalness={0.8} roughness={0.3} />
</mesh>
<group position={[0, 0.58, 0]}>
<mesh position={[0, 0, -0.3]}>
<boxGeometry args={[0.8, 0.05, 0.05]} />
<meshStandardMaterial color="#64748b" metalness={0.7} />
</mesh>
<mesh position={[0, 0, 0.3]}>
<boxGeometry args={[0.8, 0.05, 0.05]} />
<meshStandardMaterial color="#64748b" metalness={0.7} />
</mesh>
<mesh position={[-0.4, 0, 0]}>
<boxGeometry args={[0.05, 0.05, 0.65]} />
<meshStandardMaterial color="#64748b" metalness={0.7} />
</mesh>
<mesh position={[0.4, 0, 0]}>
<boxGeometry args={[0.05, 0.05, 0.65]} />
<meshStandardMaterial color="#64748b" metalness={0.7} />
</mesh>
</group>
<mesh position={[0, 0.57, 0]} rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[0.75, 0.6]} />
<meshPhysicalMaterial
color="#e2e8f0"
emissive="#cbd5e1"
emissiveIntensity={0.1}
roughness={0.02}
metalness={1.0}
clearcoat={1}
reflectivity={1}
/>
</mesh>
<Text
position={[0, 0.9, 0.6]}
fontSize={0.15}
color="#fbbf24"
anchorX="center"
anchorY="middle"
rotation={[-Math.PI/4, 0, 0]}
>
2. HAKKO SOLDER
</Text>
</group>
);
};
const DippingStations = () => {
return (
<group>
<mesh position={[0, 0.2, 0]}>
<boxGeometry args={[4.5, 0.4, 1.5]} />
<meshStandardMaterial color="#334155" roughness={0.5} metalness={0.5} />
</mesh>
<LiquidBath position={[-1.5, 0.4, 0]} label="1. FLUX" liquidColor="#fef08a" />
<HakkoFX305 position={[0, 0.4, 0]} />
<LiquidBath position={[1.5, 0.4, 0]} label="3. CLEAN" liquidColor="#bae6fd" />
</group>
);
};
const Door = ({
position,
rotation = [0,0,0],
size,
isOpen
}: {
position: [number, number, number],
rotation?: [number, number, number],
size: [number, number],
isOpen: boolean
}) => {
const meshRef = useRef<THREE.Mesh>(null);
useFrame((state, delta) => {
if (!meshRef.current) return;
const targetY = isOpen ? position[1] + 2 : position[1];
meshRef.current.position.y = THREE.MathUtils.lerp(meshRef.current.position.y, targetY, delta * 5);
});
return (
<mesh ref={meshRef} position={position} rotation={rotation as any}>
<planeGeometry args={[size[0], size[1]]} />
<meshPhysicalMaterial
color="#a5f3fc"
transparent
opacity={0.2}
roughness={0}
metalness={0.9}
side={THREE.DoubleSide}
depthWrite={false}
/>
<mesh position={[size[0]/2 - 0.1, 0, 0.02]}>
<boxGeometry args={[0.05, size[1], 0.05]} />
<meshStandardMaterial color="#cbd5e1" />
</mesh>
<mesh position={[-size[0]/2 + 0.1, 0, 0.02]}>
<boxGeometry args={[0.05, size[1], 0.05]} />
<meshStandardMaterial color="#cbd5e1" />
</mesh>
</mesh>
);
};
const MachineFrame = ({ doorStates }: { doorStates: { front: boolean, right: boolean, left: boolean, back: boolean } }) => {
return (
<group>
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.05, 0]}>
<planeGeometry args={[6, 6]} />
<meshStandardMaterial color="#0f172a" roughness={0.8} metalness={0.2} />
</mesh>
<Grid infiniteGrid fadeDistance={15} sectionColor="#475569" cellColor="#1e293b" />
{[[-2, -2], [2, -2], [2, 2], [-2, 2]].map(([x, z], i) => (
<mesh key={i} position={[x, 1.5, z]}>
<boxGeometry args={[0.15, 3, 0.15]} />
<meshStandardMaterial color="#64748b" metalness={0.8} roughness={0.2} />
</mesh>
))}
<group position={[0, 3, 0]}>
<mesh position={[0, 0, -2]}>
<boxGeometry args={[4.15, 0.15, 0.15]} />
<meshStandardMaterial color="#64748b" metalness={0.8} roughness={0.2} />
</mesh>
<mesh position={[0, 0, 2]}>
<boxGeometry args={[4.15, 0.15, 0.15]} />
<meshStandardMaterial color="#64748b" metalness={0.8} roughness={0.2} />
</mesh>
<mesh position={[-2, 0, 0]}>
<boxGeometry args={[0.15, 0.15, 4.15]} />
<meshStandardMaterial color="#64748b" metalness={0.8} roughness={0.2} />
</mesh>
<mesh position={[2, 0, 0]}>
<boxGeometry args={[0.15, 0.15, 4.15]} />
<meshStandardMaterial color="#64748b" metalness={0.8} roughness={0.2} />
</mesh>
</group>
<Door position={[0, 1.5, 2]} size={[4, 3]} isOpen={doorStates.front} />
<Door position={[0, 1.5, -2]} size={[4, 3]} isOpen={doorStates.back} />
<Door position={[-2, 1.5, 0]} rotation={[0, Math.PI/2, 0]} size={[4, 3]} isOpen={doorStates.left} />
<Door position={[2, 1.5, 0]} rotation={[0, Math.PI/2, 0]} size={[4, 3]} isOpen={doorStates.right} />
<DippingStations />
</group>
);
};
// --- MISUMI STYLE INDUSTRIAL ACTUATOR COMPONENT ---
const IndustrialActuatorRail = ({ length, label, hasMotor = true }: { length: number, label?: string, hasMotor?: boolean }) => {
const width = 0.14; // Actuator Width
const height = 0.08; // Actuator Height (Profile)
return (
<group>
{/* 1. Main Aluminum Body (White/Light Grey Matte) */}
<RoundedBox args={[width, height, length]} radius={0.01} smoothness={4}>
<meshStandardMaterial color="#f8fafc" roughness={0.8} metalness={0.1} />
</RoundedBox>
{/* 2. Top Stainless Steel Cover Strip */}
<mesh position={[0, height/2 + 0.001, 0]}>
<boxGeometry args={[width * 0.7, 0.002, length]} />
<meshStandardMaterial color="#cbd5e1" metalness={0.9} roughness={0.2} />
</mesh>
{/* 3. Black Gap/Slit for Slider */}
<mesh position={[0, height/2, 0]}>
<boxGeometry args={[width * 0.8, 0.01, length * 0.98]} />
<meshStandardMaterial color="#0f172a" roughness={0.9} />
</mesh>
{/* 4. End Caps (Plastic White) */}
<group position={[0, 0, length/2 + 0.02]}>
<RoundedBox args={[width + 0.01, height + 0.01, 0.04]} radius={0.02} smoothness={4}>
<meshStandardMaterial color="#e2e8f0" />
</RoundedBox>
</group>
<group position={[0, 0, -length/2 - 0.02]}>
<RoundedBox args={[width + 0.01, height + 0.01, 0.04]} radius={0.02} smoothness={4}>
<meshStandardMaterial color="#e2e8f0" />
</RoundedBox>
</group>
{/* 5. Servo Motor Unit (Black & Silver) */}
{hasMotor && (
<group position={[0, 0, -length/2 - 0.15]}>
{/* Flange */}
<mesh position={[0, 0, 0.08]}>
<boxGeometry args={[0.12, 0.12, 0.05]} />
<meshStandardMaterial color="#475569" metalness={0.8} />
</mesh>
{/* Motor Body */}
<mesh position={[0, 0, 0]} rotation={[Math.PI/2, 0, 0]}>
<cylinderGeometry args={[0.05, 0.05, 0.2, 32]} />
<meshStandardMaterial color="#1e293b" metalness={0.6} roughness={0.4} />
</mesh>
{/* Encoder Cap */}
<mesh position={[0, 0, -0.11]} rotation={[Math.PI/2, 0, 0]}>
<cylinderGeometry args={[0.045, 0.045, 0.05, 32]} />
<meshStandardMaterial color="#000000" />
</mesh>
{/* Cable Gland */}
<mesh position={[0, 0.04, -0.05]}>
<boxGeometry args={[0.03, 0.03, 0.03]} />
<meshStandardMaterial color="#333" />
</mesh>
</group>
)}
{/* 6. Label/Branding */}
{label && (
<Text
position={[width/2 + 0.01, 0, length/2 - 0.2]}
rotation={[0, Math.PI/2, 0]}
fontSize={0.06}
color="#334155"
fontWeight="bold"
anchorX="right"
>
{label}
</Text>
)}
</group>
);
}
// The Moving Block on top of the actuator
const IndustrialSlider = ({ width = 0.16, length = 0.18, height = 0.03 }) => {
return (
<group position={[0, 0.06, 0]}>
<RoundedBox args={[width, height, length]} radius={0.005} smoothness={2}>
<meshStandardMaterial color="#f1f5f9" metalness={0.4} roughness={0.5} />
</RoundedBox>
{/* Mounting Holes (Visual) */}
{[-1, 1].map(x => [-1, 1].map(z => (
<mesh key={`${x}-${z}`} position={[x * 0.06, height/2 + 0.001, z * 0.07]} rotation={[Math.PI/2, 0, 0]}>
<circleGeometry args={[0.008, 16]} />
<meshStandardMaterial color="#94a3b8" />
</mesh>
)))}
</group>
)
}
// -- MAIN ROBOT ASSEMBLY --
const Robot = ({ target }: { target: RobotTarget }) => {
const bridgeGroup = useRef<THREE.Group>(null);
const carriageGroup = useRef<THREE.Group>(null);
const zAxisGroup = useRef<THREE.Group>(null);
useFrame((state, delta) => {
if (bridgeGroup.current) {
// Y-Axis Movement
bridgeGroup.current.position.z = THREE.MathUtils.lerp(bridgeGroup.current.position.z, target.y, delta * 3);
}
if (carriageGroup.current) {
// X-Axis Movement
carriageGroup.current.position.x = THREE.MathUtils.lerp(carriageGroup.current.position.x, target.x, delta * 3);
}
if (zAxisGroup.current) {
// Z-Axis Movement
zAxisGroup.current.position.y = THREE.MathUtils.lerp(zAxisGroup.current.position.y, target.z, delta * 3);
}
});
return (
<group position={[0, 2.0, 0]}>
{/* --- Y-AXIS (Left & Right Fixed Actuators) --- */}
<group>
<group position={[-1.8, 0, 0]}>
<IndustrialActuatorRail length={3.8} label="MISUMI-Y1" />
</group>
<group position={[1.8, 0, 0]}>
<IndustrialActuatorRail length={3.8} label="MISUMI-Y2" />
</group>
</group>
{/* --- MOVING BRIDGE (Y-AXIS CARRIAGE + X-AXIS ACTUATOR) --- */}
<group ref={bridgeGroup}>
{/* Y-Sliders (Connecting Bridge to Y-Rails) */}
<group position={[-1.8, 0, 0]}> <IndustrialSlider /> </group>
<group position={[1.8, 0, 0]}> <IndustrialSlider /> </group>
{/* Bridge Beam Structure */}
<mesh position={[0, 0.08, 0]}>
<boxGeometry args={[4.2, 0.05, 0.25]} />
<meshStandardMaterial color="#cbd5e1" metalness={0.6} roughness={0.4} />
</mesh>
{/* X-AXIS ACTUATOR (Mounted on top of Bridge) */}
<group position={[0, 0.14, 0]} rotation={[0, Math.PI/2, 0]}>
<IndustrialActuatorRail length={3.4} label="MISUMI-X" hasMotor />
</group>
{/* --- MOVING CARRIAGE (X-AXIS SLIDER + Z-AXIS) --- */}
<group ref={carriageGroup}>
{/* X-Slider */}
<group position={[0, 0.14, 0]} rotation={[0, Math.PI/2, 0]}>
<IndustrialSlider />
</group>
{/* --- Z-AXIS ACTUATOR (Vertical) --- */}
<group position={[0, 0.2, 0.12]}>
{/* Z-Actuator Body (Fixed to X-Slider) */}
<group position={[0, 0.4, 0]} rotation={[Math.PI/2, 0, 0]}>
<IndustrialActuatorRail length={0.8} label="MISUMI-Z" hasMotor={false} />
{/* Z-Motor on Top */}
<group position={[0, 0, 0.4 + 0.15]} rotation={[0, Math.PI, 0]}>
<mesh position={[0, 0, -0.05]} rotation={[Math.PI/2, 0, 0]}>
<boxGeometry args={[0.1, 0.1, 0.12]} />
<meshStandardMaterial color="#0f172a" />
</mesh>
</group>
</group>
{/* MOVING Z-HEAD (The Slider of Z-Axis) */}
<group ref={zAxisGroup}>
<group position={[0, 0, 0.08]}>
{/* Connection Plate */}
<mesh position={[0, 0, -0.04]}>
<boxGeometry args={[0.12, 0.15, 0.02]} />
<meshStandardMaterial color="#64748b" />
</mesh>
{/* PICKER MECHANISM */}
<group position={[0, -0.2, 0]}>
<mesh position={[0, 0, 0]}>
<boxGeometry args={[0.3, 0.05, 0.1]} />
<meshStandardMaterial color="#334155" />
</mesh>
{/* Fingers */}
<mesh position={[-0.12, -0.15, 0]}>
<boxGeometry args={[0.02, 0.3, 0.05]} />
<meshStandardMaterial color="#94a3b8" metalness={0.8} />
</mesh>
<mesh position={[0.12, -0.15, 0]}>
<boxGeometry args={[0.02, 0.3, 0.05]} />
<meshStandardMaterial color="#94a3b8" metalness={0.8} />
</mesh>
{/* PCB STRIP */}
<group position={[0, -0.35, 0]}>
<mesh>
<boxGeometry args={[0.28, 0.6, 0.02]} />
<meshStandardMaterial color="#166534" roughness={0.3} />
</mesh>
<mesh position={[0, -0.28, 0.011]}>
<planeGeometry args={[0.24, 0.04]} />
<meshStandardMaterial color="#fbbf24" metalness={1.0} roughness={0.1} />
</mesh>
<mesh position={[0, 0, 0.011]}>
<planeGeometry args={[0.15, 0.15]} />
<meshStandardMaterial color="#0f172a" />
</mesh>
</group>
</group>
</group>
</group>
</group>
</group>
</group>
</group>
);
};
export const Machine3D: React.FC<Machine3DProps> = ({ target, ioState, doorStates }) => {
return (
<Canvas shadows className="w-full h-full bg-slate-900">
<PerspectiveCamera makeDefault position={[5, 5, 6]} fov={45} />
<OrbitControls
maxPolarAngle={Math.PI / 2 - 0.05}
minDistance={3}
maxDistance={12}
/>
<Environment preset="city" />
<ambientLight intensity={0.4} />
<pointLight position={[10, 10, 10]} intensity={1} castShadow />
<pointLight position={[-10, 5, -10]} intensity={0.5} />
<pointLight position={[0, 2, 0]} intensity={0.2} color="#bae6fd" distance={5} />
<MachineFrame doorStates={doorStates} />
<TowerLamp ioState={ioState} />
<Robot target={target} />
</Canvas>
);
};

View File

@@ -0,0 +1,58 @@
import React from 'react';
import { Box, Cpu, Activity } from 'lucide-react';
import { Recipe } from '../types';
import { CyberPanel } from './common/CyberPanel';
interface ModelInfoPanelProps {
currentRecipe: Recipe;
}
export const ModelInfoPanel: React.FC<ModelInfoPanelProps> = ({ currentRecipe }) => {
return (
<CyberPanel className="flex-none">
<div className="mb-3 flex items-center justify-between text-xs text-neon-blue font-bold tracking-widest uppercase border-b border-white/10 pb-2">
<span>Model Information</span>
<Box className="w-3 h-3" />
</div>
<div className="space-y-4">
<div>
<div className="text-[10px] text-slate-500 font-mono mb-1">SELECTED MODEL</div>
<div className="text-xl font-bold text-white tracking-wide truncate flex items-center gap-2">
<Cpu className="w-4 h-4 text-neon-blue" />
{currentRecipe.name}
</div>
</div>
<div className="grid grid-cols-2 gap-2">
<div className="bg-white/5 rounded p-2 border border-white/5">
<div className="text-[9px] text-slate-500 font-mono uppercase">Model ID</div>
<div className="text-sm font-mono text-neon-blue">{currentRecipe.id}</div>
</div>
<div className="bg-white/5 rounded p-2 border border-white/5">
<div className="text-[9px] text-slate-500 font-mono uppercase">Last Mod</div>
<div className="text-sm font-mono text-slate-300">{currentRecipe.lastModified}</div>
</div>
</div>
<div className="space-y-1">
<div className="flex justify-between text-[10px] font-mono text-slate-400">
<span>TARGET CYCLE</span>
<span className="text-neon-green">12.5s</span>
</div>
<div className="w-full h-1 bg-slate-800 rounded-full overflow-hidden">
<div className="h-full w-[85%] bg-neon-green/50"></div>
</div>
<div className="flex justify-between text-[10px] font-mono text-slate-400 mt-2">
<span>EST. YIELD</span>
<span className="text-neon-blue">99.8%</span>
</div>
<div className="w-full h-1 bg-slate-800 rounded-full overflow-hidden">
<div className="h-full w-[99%] bg-neon-blue/50"></div>
</div>
</div>
</div>
</CyberPanel>
);
};

View File

@@ -0,0 +1,67 @@
import React, { useState } from 'react';
import { Move } from 'lucide-react';
import { RobotTarget, AxisPosition } from '../types';
import { PanelHeader } from './common/PanelHeader';
import { TechButton } from './common/TechButton';
const MOCK_POSITIONS: AxisPosition[] = [
{ id: 'p1', name: 'Home Position', axis: 'X', value: 0, speed: 100, acc: 100, dec: 100 },
{ id: 'p2', name: 'Pick Pos A', axis: 'X', value: -1.5, speed: 500, acc: 200, dec: 200 },
{ id: 'p3', name: 'Place Pos B', axis: 'X', value: 1.5, speed: 500, acc: 200, dec: 200 },
{ id: 'p4', name: 'Scan Index', axis: 'X', value: 0.5, speed: 300, acc: 100, dec: 100 },
{ id: 'py1', name: 'Rear Limit', axis: 'Y', value: -1.5, speed: 200, acc: 100, dec: 100 },
{ id: 'pz1', name: 'Safe Height', axis: 'Z', value: 0, speed: 50, acc: 50, dec: 50 },
];
interface MotionPanelProps {
robotTarget: RobotTarget;
onMove: (axis: 'X' | 'Y' | 'Z', val: number) => void;
}
export const MotionPanel: React.FC<MotionPanelProps> = ({ robotTarget, onMove }) => {
const [axis, setAxis] = useState<'X' | 'Y' | 'Z'>('X');
return (
<div className="h-full flex flex-col">
<PanelHeader title="Servo Control" icon={Move} />
<div className="flex gap-2 mb-4">
{['X', 'Y', 'Z'].map(a => (
<button
key={a}
onClick={() => setAxis(a as any)}
className={`flex-1 py-2 font-tech font-bold text-lg border-b-2 transition-all ${axis === a ? 'text-neon-blue border-neon-blue bg-neon-blue/10' : 'text-slate-500 border-slate-700 hover:text-slate-300'}`}
>
{a}-AXIS
</button>
))}
</div>
<div className="bg-black/40 p-4 rounded border border-white/10 mb-4 text-center">
<div className="text-[10px] text-slate-400 uppercase tracking-widest mb-1">Current Position</div>
<div className="font-mono text-3xl text-neon-blue text-shadow-glow-blue">
{robotTarget[axis.toLowerCase() as 'x' | 'y' | 'z'].toFixed(3)}
<span className="text-sm text-slate-500 ml-2">mm</span>
</div>
</div>
<div className="space-y-2 overflow-y-auto flex-1 pr-2 custom-scrollbar">
{MOCK_POSITIONS.filter(p => p.axis === axis).map(p => (
<div key={p.id} className="flex items-center justify-between p-3 bg-white/5 border border-white/5 hover:border-neon-blue/50 transition-all group">
<span className="text-xs font-bold text-slate-300 group-hover:text-white">{p.name}</span>
<button
onClick={() => onMove(axis, p.value)}
className="px-3 py-1 bg-slate-800 hover:bg-neon-blue hover:text-black text-xs font-mono transition-colors"
>
GO {p.value}
</button>
</div>
))}
</div>
<div className="flex gap-2 mt-4">
<TechButton className="flex-1 font-mono text-lg" onClick={() => onMove(axis, robotTarget[axis.toLowerCase() as 'x' | 'y' | 'z'] - 0.1)}>-</TechButton>
<TechButton className="flex-1 font-mono text-lg" onClick={() => onMove(axis, robotTarget[axis.toLowerCase() as 'x' | 'y' | 'z'] + 0.1)}>+</TechButton>
</div>
</div>
);
};

View File

@@ -0,0 +1,119 @@
import React, { useState, useEffect } from 'react';
import { Layers, Check, Settings, X, RotateCw } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { Recipe } from '../types';
import { TechButton } from './common/TechButton';
import { comms } from '../communication';
interface RecipePanelProps {
isOpen: boolean;
currentRecipe: Recipe;
onSelectRecipe: (r: Recipe) => void;
onClose: () => void;
}
export const RecipePanel: React.FC<RecipePanelProps> = ({ isOpen, currentRecipe, onSelectRecipe, onClose }) => {
const navigate = useNavigate();
const [recipes, setRecipes] = useState<Recipe[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [selectedId, setSelectedId] = useState<string>(currentRecipe.id);
// Fetch recipes when panel opens
useEffect(() => {
if (isOpen) {
const fetchRecipes = async () => {
setIsLoading(true);
try {
const recipeStr = await comms.getRecipeList();
const recipeData: Recipe[] = JSON.parse(recipeStr);
setRecipes(recipeData);
} catch (e) {
console.error('Failed to fetch recipes:', e);
}
setIsLoading(false);
};
fetchRecipes();
}
}, [isOpen]);
// Update selected ID when currentRecipe changes
useEffect(() => {
setSelectedId(currentRecipe.id);
}, [currentRecipe.id]);
const handleConfirm = () => {
const selected = recipes.find(r => r.id === selectedId);
if (selected) {
onSelectRecipe(selected);
onClose();
}
};
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm animate-in fade-in duration-200">
<div className="w-[500px] bg-slate-950/90 border border-neon-blue/30 rounded-lg shadow-2xl flex flex-col overflow-hidden">
{/* Header */}
<div className="h-12 bg-white/5 flex items-center justify-between px-4 border-b border-white/10">
<div className="flex items-center gap-2 text-neon-blue font-tech font-bold tracking-wider">
<Layers className="w-4 h-4" /> RECIPE SELECTION
</div>
<button onClick={onClose} className="text-slate-400 hover:text-white transition-colors">
<X className="w-5 h-5" />
</button>
</div>
{/* List (Max height for ~5 items) */}
<div className="p-4 max-h-[320px] overflow-y-auto custom-scrollbar">
{isLoading ? (
<div className="h-64 flex flex-col items-center justify-center gap-4 animate-pulse">
<RotateCw className="w-12 h-12 text-neon-blue animate-spin" />
<div className="text-lg font-tech text-neon-blue tracking-widest">LOADING RECIPES...</div>
</div>
) : (
<div className="space-y-2">
{recipes.map(recipe => (
<div
key={recipe.id}
onClick={() => setSelectedId(recipe.id)}
className={`
p-3 rounded border cursor-pointer transition-all flex items-center justify-between
${selectedId === recipe.id
? 'bg-neon-blue/20 border-neon-blue text-white shadow-[0_0_10px_rgba(0,243,255,0.2)]'
: 'bg-white/5 border-white/10 text-slate-400 hover:bg-white/10 hover:border-white/20'}
`}
>
<div>
<div className="font-bold tracking-wide">{recipe.name}</div>
<div className="text-[10px] font-mono opacity-70">ID: {recipe.id} | MOD: {recipe.lastModified}</div>
</div>
{selectedId === recipe.id && <Check className="w-4 h-4 text-neon-blue" />}
</div>
))}
</div>
)}
</div>
{/* Footer Actions */}
<div className="p-4 border-t border-white/10 flex justify-between gap-4 bg-black/20">
<TechButton
variant="default"
className="flex items-center gap-2 px-4"
onClick={() => navigate('/recipe')}
>
<Settings className="w-4 h-4" /> MANAGEMENT
</TechButton>
<TechButton
variant="blue"
className="flex items-center gap-2 px-8"
onClick={handleConfirm}
>
SELECT
</TechButton>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,166 @@
import React from 'react';
import { Settings, RotateCw, ChevronDown, ChevronRight } from 'lucide-react';
import { ConfigItem } from '../types';
import { comms } from '../communication';
interface SettingsModalProps {
isOpen: boolean;
onClose: () => void;
onSave: (config: ConfigItem[]) => void;
}
const TechButton = ({ children, onClick, active = false, variant = 'blue', className = '' }: any) => {
const colors: any = {
blue: 'from-blue-600 to-cyan-600 hover:shadow-glow-blue border-cyan-400/30',
red: 'from-red-600 to-pink-600 hover:shadow-glow-red border-red-400/30',
amber: 'from-amber-500 to-orange-600 hover:shadow-orange-500/50 border-orange-400/30',
green: 'from-emerald-500 to-green-600 hover:shadow-green-500/50 border-green-400/30'
};
return (
<button
onClick={onClick}
className={`
relative px-4 py-2 font-tech font-bold tracking-wider uppercase transition-all duration-300
clip-tech border-b-2 border-r-2
${active ? `bg-gradient-to-r ${colors[variant]} text-white` : 'bg-slate-800/50 text-slate-400 hover:text-white hover:bg-slate-700/50 border-slate-600'}
${className}
`}
>
{active && <div className="absolute inset-0 bg-white/20 animate-pulse pointer-events-none"></div>}
{children}
</button>
);
};
export const SettingsModal: React.FC<SettingsModalProps> = ({ isOpen, onClose, onSave }) => {
const [localConfig, setLocalConfig] = React.useState<ConfigItem[]>([]);
const [expandedGroups, setExpandedGroups] = React.useState<Set<string>>(new Set());
const [isRefreshing, setIsRefreshing] = React.useState(false);
// Fetch config data when modal opens
React.useEffect(() => {
if (isOpen) {
const fetchConfig = async () => {
setIsRefreshing(true);
try {
const configStr = await comms.getConfig();
const config: ConfigItem[] = JSON.parse(configStr);
setLocalConfig(config);
// Auto-expand all groups initially
const groups = new Set<string>(config.map(c => c.Group));
setExpandedGroups(groups);
} catch (e) {
console.error('Failed to fetch config:', e);
}
setIsRefreshing(false);
};
fetchConfig();
}
}, [isOpen]);
const handleChange = (idx: number, newValue: string) => {
setLocalConfig(prev => {
const next = [...prev];
next[idx] = { ...next[idx], Value: newValue };
return next;
});
};
const toggleGroup = (group: string) => {
setExpandedGroups(prev => {
const next = new Set(prev);
if (next.has(group)) next.delete(group);
else next.add(group);
return next;
});
};
// Group items by category
const groupedConfig = React.useMemo(() => {
const groups: { [key: string]: { item: ConfigItem, originalIdx: number }[] } = {};
localConfig.forEach((item, idx) => {
if (!groups[item.Group]) groups[item.Group] = [];
groups[item.Group].push({ item, originalIdx: idx });
});
return groups;
}, [localConfig]);
if (!isOpen) return null;
return (
<div className="absolute inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
<div className="w-[900px] glass-holo p-8 border border-neon-blue shadow-glow-blue relative flex flex-col max-h-[90vh]">
<button onClick={onClose} className="absolute top-4 right-4 text-slate-400 hover:text-white"></button>
<h2 className="text-2xl font-tech font-bold text-neon-blue mb-8 border-b border-white/10 pb-4 flex items-center gap-3 flex-none">
<Settings className="animate-spin-slow" /> SYSTEM CONFIGURATION
</h2>
{isRefreshing ? (
<div className="h-64 flex flex-col items-center justify-center gap-4 animate-pulse flex-1">
<RotateCw className="w-12 h-12 text-neon-blue animate-spin" />
<div className="text-xl font-tech text-neon-blue tracking-widest">FETCHING CONFIGURATION...</div>
</div>
) : (
<div className="flex-1 overflow-y-auto custom-scrollbar pr-2 mb-8">
<div className="space-y-6">
{Object.entries(groupedConfig).map(([groupName, items]) => (
<div key={groupName} className="border border-white/10 bg-black/20">
<button
onClick={() => toggleGroup(groupName)}
className="w-full flex items-center gap-2 p-3 bg-white/5 hover:bg-white/10 transition-colors text-left"
>
{expandedGroups.has(groupName) ? <ChevronDown className="w-4 h-4 text-neon-blue" /> : <ChevronRight className="w-4 h-4 text-slate-400" />}
<span className="font-tech font-bold text-lg text-white tracking-wider">{groupName}</span>
<span className="text-xs text-slate-500 ml-auto">{items.length} ITEMS</span>
</button>
{expandedGroups.has(groupName) && (
<div className="p-4 space-y-4">
{items.map(({ item, originalIdx }) => (
<div key={originalIdx} className="grid grid-cols-[250px_1fr] gap-6 items-start group">
<div>
<div className="text-sm font-bold text-neon-blue mb-1">{item.Key}</div>
<div className="text-xs text-slate-400 leading-tight">{item.Description}</div>
</div>
<div>
{item.Type === 'Boolean' ? (
<div className="flex items-center gap-3 h-full">
<button
onClick={() => handleChange(originalIdx, item.Value === 'true' ? 'false' : 'true')}
className={`w-12 h-6 rounded-full p-1 transition-colors ${item.Value === 'true' ? 'bg-neon-green' : 'bg-slate-700'}`}
>
<div className={`w-4 h-4 rounded-full bg-white shadow transition-transform ${item.Value === 'true' ? 'translate-x-6' : 'translate-x-0'}`} />
</button>
<span className={`font-mono text-sm font-bold ${item.Value === 'true' ? 'text-neon-green' : 'text-slate-400'}`}>
{item.Value.toUpperCase()}
</span>
</div>
) : (
<input
type={item.Type === 'Number' ? 'number' : 'text'}
value={item.Value}
onChange={(e) => handleChange(originalIdx, e.target.value)}
className="w-full bg-black/50 border border-slate-700 text-white font-mono text-sm px-3 py-2 focus:border-neon-blue focus:outline-none transition-colors hover:border-slate-500"
/>
)}
</div>
</div>
))}
</div>
)}
</div>
))}
</div>
</div>
)}
<div className="flex justify-end gap-4 flex-none pt-4 border-t border-white/10">
<TechButton onClick={onClose}>CANCEL</TechButton>
<TechButton variant="blue" active onClick={() => { onSave(localConfig); onClose(); }}>SAVE CONFIG</TechButton>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,29 @@
import React from 'react';
interface CyberPanelProps {
children?: React.ReactNode;
className?: string;
}
export const CyberPanel: React.FC<CyberPanelProps> = ({ children, className = "" }) => (
<div className={`glass-holo p-1 relative group ${className}`}>
{/* Decorative Corners */}
<svg className="absolute top-0 left-0 w-6 h-6 text-neon-blue opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M2 22V2H22" />
</svg>
<svg className="absolute top-0 right-0 w-6 h-6 text-neon-blue opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M22 22V2H2" />
</svg>
<svg className="absolute bottom-0 left-0 w-6 h-6 text-neon-blue opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M2 2V22H22" />
</svg>
<svg className="absolute bottom-0 right-0 w-6 h-6 text-neon-blue opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M22 2V22H2" />
</svg>
{/* Inner Content */}
<div className="bg-slate-950/40 backdrop-blur-md h-full w-full p-4 relative z-10 clip-tech border border-white/5">
{children}
</div>
</div>
);

View File

@@ -0,0 +1,19 @@
import React from 'react';
import { LucideIcon } from 'lucide-react';
interface PanelHeaderProps {
title: string;
icon: LucideIcon;
}
export const PanelHeader: React.FC<PanelHeaderProps> = ({ title, icon: Icon }) => (
<div className="flex items-center gap-3 mb-6 border-b border-white/10 pb-2">
<div className="text-neon-blue animate-pulse">
<Icon className="w-5 h-5" />
</div>
<h2 className="text-lg font-tech font-bold text-white tracking-[0.1em] uppercase text-shadow-glow-blue">
{title}
</h2>
<div className="flex-1 h-px bg-gradient-to-r from-neon-blue/50 to-transparent"></div>
</div>
);

View File

@@ -0,0 +1,54 @@
import React from 'react';
interface TechButtonProps {
children?: React.ReactNode;
onClick?: () => void;
active?: boolean;
variant?: 'blue' | 'red' | 'amber' | 'green' | 'default' | 'danger';
className?: string;
disabled?: boolean;
title?: string;
}
export const TechButton: React.FC<TechButtonProps> = ({
children,
onClick,
active = false,
variant = 'blue',
className = '',
disabled = false,
title
}) => {
const colors = {
blue: 'from-blue-600 to-cyan-600 hover:shadow-glow-blue border-cyan-400/30',
red: 'from-red-600 to-pink-600 hover:shadow-glow-red border-red-400/30',
amber: 'from-amber-500 to-orange-600 hover:shadow-orange-500/50 border-orange-400/30',
green: 'from-emerald-500 to-green-600 hover:shadow-green-500/50 border-green-400/30',
default: 'from-slate-600 to-slate-500 hover:shadow-slate-500/50 border-slate-400/30',
danger: 'from-red-600 to-pink-600 hover:shadow-glow-red border-red-400/30'
};
const variantKey = variant === 'danger' ? 'red' : (variant === 'default' ? 'blue' : variant);
return (
<button
onClick={onClick}
disabled={disabled}
title={title}
className={`
relative px-4 py-2 font-tech font-bold tracking-wider uppercase transition-all duration-300
clip-tech border-b-2 border-r-2
${disabled
? 'opacity-50 cursor-not-allowed bg-slate-900 text-slate-600 border-slate-800'
: (active
? `bg-gradient-to-r ${colors[variantKey]} text-white`
: 'bg-slate-800/50 text-slate-400 hover:text-white hover:bg-slate-700/50 border-slate-600')
}
${className}
`}
>
{active && !disabled && <div className="absolute inset-0 bg-white/20 animate-pulse pointer-events-none"></div>}
{children}
</button>
);
};

View File

@@ -0,0 +1,31 @@
import React from 'react';
import { RobotTarget } from '../../types';
interface FooterProps {
isHostConnected: boolean;
robotTarget: RobotTarget;
}
export const Footer: React.FC<FooterProps> = ({ isHostConnected, robotTarget }) => {
return (
<footer className="absolute bottom-0 left-0 right-0 h-10 bg-black/80 border-t border-neon-blue/30 flex items-center px-6 justify-between z-40 backdrop-blur text-xs font-mono text-slate-400">
<div className="flex gap-6">
{['PLC', 'MOTION', 'VISION', 'LIGHT'].map(hw => (
<div key={hw} className="flex items-center gap-2">
<div className="w-2 h-2 bg-neon-green rounded-full shadow-[0_0_5px_#0aff00]"></div>
<span className="font-bold text-slate-300">{hw}</span>
</div>
))}
<div className="flex items-center gap-2">
<div className={`w-2 h-2 rounded-full transition-all ${isHostConnected ? 'bg-neon-green shadow-[0_0_5px_#0aff00]' : 'bg-red-500 shadow-[0_0_5px_#ff0000] animate-pulse'}`}></div>
<span className={`font-bold ${isHostConnected ? 'text-slate-300' : 'text-red-400'}`}>HOST</span>
</div>
</div>
<div className="flex gap-8 text-neon-blue">
<span>POS.X: {robotTarget.x.toFixed(3)}</span>
<span>POS.Y: {robotTarget.y.toFixed(3)}</span>
<span>POS.Z: {robotTarget.z.toFixed(3)}</span>
</div>
</footer>
);
};

View File

@@ -0,0 +1,101 @@
import React from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { Activity, Settings, Move, Camera, Layers, Cpu, Target } from 'lucide-react';
interface HeaderProps {
currentTime: Date;
onTabChange: (tab: 'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null) => void;
activeTab: 'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null;
}
export const Header: React.FC<HeaderProps> = ({ currentTime, onTabChange, activeTab }) => {
const navigate = useNavigate();
const location = useLocation();
const isWebView = typeof window !== 'undefined' && !!window.chrome?.webview;
const isIOPage = location.pathname === '/io-monitor';
return (
<header className="absolute top-0 left-0 right-0 h-20 px-6 flex items-center justify-between z-40 bg-gradient-to-b from-black/80 to-transparent pointer-events-none">
<div
className="flex items-center gap-4 pointer-events-auto cursor-pointer group"
onClick={() => {
navigate('/');
onTabChange(null);
}}
>
<div className="w-12 h-12 border-2 border-neon-blue flex items-center justify-center rounded shadow-glow-blue bg-black/50 backdrop-blur group-hover:bg-neon-blue/10 transition-colors">
<Cpu className="text-neon-blue w-8 h-8 animate-pulse-slow" />
</div>
<div>
<h1 className="text-3xl font-tech font-bold text-white tracking-widest uppercase italic text-shadow-glow-blue group-hover:text-neon-blue transition-colors">
EQUI-HANDLER <span className="text-neon-blue text-sm not-italic">PRO</span>
</h1>
<div className="flex gap-2 text-[10px] text-neon-blue/70 font-mono">
<span>SYS.VER 4.2.0</span>
<span>|</span>
<span className={isWebView ? "text-neon-green" : "text-amber-500"}>
LINK: {isWebView ? "NATIVE" : "SIMULATION"}
</span>
</div>
</div>
</div>
{/* Top Navigation */}
<div className="flex items-center gap-2 pointer-events-auto">
{/* IO Tab Switcher (only on IO page) */}
<div className="bg-black/40 backdrop-blur-md p-1 rounded-full border border-white/10 flex gap-1">
{[
{ id: 'recipe', icon: Layers, label: 'RECIPE', path: '/' },
{ id: 'io', icon: Activity, label: 'I/O MONITOR', path: '/io-monitor' },
{ id: 'motion', icon: Move, label: 'MOTION', path: '/' },
{ id: 'camera', icon: Camera, label: 'VISION', path: '/' },
{ id: 'setting', icon: Settings, label: 'CONFIG', path: '/' },
{ id: 'initialize', icon: Target, label: 'INITIALIZE', path: '/' }
].map(item => {
const isActive = item.id === 'io'
? location.pathname === '/io-monitor'
: activeTab === item.id;
return (
<button
key={item.id}
onClick={() => {
if (item.id === 'io') {
navigate('/io-monitor');
onTabChange(null);
} else {
if (location.pathname !== '/') {
navigate('/');
}
onTabChange(activeTab === item.id ? null : item.id as any);
}
}}
className={`
flex items-center gap-2 px-6 py-2 rounded-full font-tech font-bold text-sm transition-all border border-transparent
${isActive
? 'bg-neon-blue/10 text-neon-blue border-neon-blue shadow-glow-blue'
: 'text-slate-400 hover:text-white hover:bg-white/5'}
`}
>
<item.icon className="w-4 h-4" /> {item.label}
</button>
);
})}
</div>
</div>
<div className="text-right pointer-events-auto">
<div className="text-2xl font-mono font-bold text-white text-shadow-glow-blue">
{currentTime.toLocaleTimeString('en-GB')}
</div>
<div className="text-xs font-tech text-slate-400 tracking-[0.3em]">
{currentTime.toLocaleDateString().toUpperCase()}
</div>
</div>
</header>
);
};

View File

@@ -0,0 +1,61 @@
import React from 'react';
import { Header } from './Header';
import { Footer } from './Footer';
import { RobotTarget } from '../../types';
interface LayoutProps {
children: React.ReactNode;
currentTime: Date;
isHostConnected: boolean;
robotTarget: RobotTarget;
onTabChange: (tab: 'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null) => void;
activeTab: 'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null;
isLoading: boolean;
}
export const Layout: React.FC<LayoutProps> = ({
children,
currentTime,
isHostConnected,
robotTarget,
onTabChange,
activeTab,
isLoading
}) => {
return (
<div className="relative w-screen h-screen bg-slate-950 text-slate-100 overflow-hidden font-sans">
{/* Animated Nebula Background */}
<div className="absolute inset-0 bg-gradient-to-br from-slate-950 via-[#050a15] to-[#0a0f20] animate-gradient bg-[length:400%_400%] z-0"></div>
<div className="absolute inset-0 grid-bg opacity-30 z-0"></div>
<div className="absolute inset-0 scanlines z-50 pointer-events-none"></div>
{/* LOADING OVERLAY */}
{isLoading && (
<div className="absolute inset-0 z-[100] bg-black flex flex-col items-center justify-center gap-6">
<div className="relative">
<div className="w-24 h-24 border-4 border-neon-blue/30 rounded-full animate-spin"></div>
<div className="absolute inset-0 border-t-4 border-neon-blue rounded-full animate-spin"></div>
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-neon-blue text-2xl font-tech font-bold"></div>
</div>
<div className="text-center">
<h2 className="text-2xl font-tech font-bold text-white tracking-widest mb-2">SYSTEM INITIALIZING</h2>
<p className="font-mono text-neon-blue text-sm animate-pulse">ESTABLISHING CONNECTION...</p>
</div>
</div>
)}
<Header
currentTime={currentTime}
onTabChange={onTabChange}
activeTab={activeTab}
/>
{/* Main Content Area */}
<div className="absolute inset-0 pt-20 pb-10 z-10">
{children}
</div>
<Footer isHostConnected={isHostConnected} robotTarget={robotTarget} />
</div>
);
};

108
FrontEnd/index.css Normal file
View File

@@ -0,0 +1,108 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 4px;
height: 4px;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.2);
}
::-webkit-scrollbar-thumb {
background: rgba(0, 243, 255, 0.3);
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(0, 243, 255, 0.6);
}
/* Holographic Glass */
.glass-holo {
background: linear-gradient(135deg, rgba(10, 15, 30, 0.7) 0%, rgba(20, 30, 50, 0.5) 100%);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(0, 243, 255, 0.1);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
position: relative;
overflow: hidden;
}
.glass-holo::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, rgba(0, 243, 255, 0.5), transparent);
}
/* Active Element */
.glass-active {
background: rgba(0, 243, 255, 0.1);
border: 1px solid rgba(0, 243, 255, 0.4);
box-shadow: 0 0 15px rgba(0, 243, 255, 0.2);
}
/* Text Glows */
.text-glow-blue {
color: #00f3ff;
text-shadow: 0 0 8px rgba(0, 243, 255, 0.6);
}
.text-glow-purple {
color: #bc13fe;
text-shadow: 0 0 8px rgba(188, 19, 254, 0.6);
}
.text-glow-red {
color: #ff0055;
text-shadow: 0 0 8px rgba(255, 0, 85, 0.6);
}
.text-glow-green {
color: #0aff00;
text-shadow: 0 0 8px rgba(10, 255, 0, 0.6);
}
/* Grid Background */
.grid-bg {
background-size: 50px 50px;
background-image:
linear-gradient(to right, rgba(0, 243, 255, 0.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(0, 243, 255, 0.05) 1px, transparent 1px);
mask-image: radial-gradient(circle at center, black 40%, transparent 100%);
}
/* CRT Scanline Effect */
.scanlines {
background: linear-gradient(to bottom,
rgba(255, 255, 255, 0),
rgba(255, 255, 255, 0) 50%,
rgba(0, 0, 0, 0.2) 50%,
rgba(0, 0, 0, 0.2));
background-size: 100% 4px;
pointer-events: none;
}
/* Tech Clip Path */
.clip-tech {
clip-path: polygon(0 0,
100% 0,
100% calc(100% - 10px),
calc(100% - 10px) 100%,
0 100%);
}
.clip-tech-inv {
clip-path: polygon(10px 0,
100% 0,
100% 100%,
0 100%,
0 10px);
}

197
FrontEnd/index.html Normal file
View File

@@ -0,0 +1,197 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Industrial HMI - Holographic</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500&family=Rajdhani:wght@500;600;700&display=swap" rel="stylesheet">
<script type="importmap">
{
"imports": {
"react-dom/client": "https://esm.sh/react-dom@18.2.0/client",
"react-dom": "https://esm.sh/react-dom@18.2.0",
"react/jsx-runtime": "https://esm.sh/react@18.2.0/jsx-runtime",
"react": "https://esm.sh/react@18.2.0",
"three": "https://esm.sh/three@0.160.0",
"@react-three/fiber": "https://esm.sh/@react-three/fiber@8.15.12?external=react,react-dom,three",
"@react-three/drei": "https://esm.sh/@react-three/drei@9.96.1?external=react,react-dom,three,@react-three/fiber",
"lucide-react": "https://esm.sh/lucide-react@0.303.0?external=react",
"clsx": "https://esm.sh/clsx@2.1.0",
"tailwind-merge": "https://esm.sh/tailwind-merge@2.2.0",
"path": "https://aistudiocdn.com/path@^0.12.7",
"react/": "https://aistudiocdn.com/react@^19.2.0/",
"react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
"vite": "https://aistudiocdn.com/vite@^7.2.4",
"@vitejs/plugin-react": "https://aistudiocdn.com/@vitejs/plugin-react@^5.1.1",
"url": "https://aistudiocdn.com/url@^0.11.4"
}
}
</script>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
mono: ['Rajdhani', 'monospace'],
tech: ['Rajdhani', 'sans-serif'],
},
colors: {
slate: {
850: '#1e293b',
900: '#0f172a',
950: '#020617',
},
neon: {
blue: '#00f3ff',
purple: '#bc13fe',
pink: '#ff0099',
green: '#0aff00',
yellow: '#ffe600',
}
},
boxShadow: {
'glow-blue': '0 0 20px rgba(0, 243, 255, 0.3), inset 0 0 10px rgba(0, 243, 255, 0.1)',
'glow-purple': '0 0 20px rgba(188, 19, 254, 0.4), inset 0 0 10px rgba(188, 19, 254, 0.1)',
'glow-red': '0 0 30px rgba(255, 0, 0, 0.5)',
'hologram': '0 0 15px rgba(6, 182, 212, 0.15), inset 0 0 20px rgba(6, 182, 212, 0.05)',
},
animation: {
'pulse-slow': 'pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite',
'glow': 'glow 2s ease-in-out infinite alternate',
'gradient': 'gradient 15s ease infinite',
'scan': 'scan 4s linear infinite',
'spin-slow': 'spin 10s linear infinite',
},
keyframes: {
glow: {
'0%': { boxShadow: '0 0 5px rgba(0, 243, 255, 0.2)' },
'100%': { boxShadow: '0 0 20px rgba(0, 243, 255, 0.6), 0 0 10px rgba(0, 243, 255, 0.4)' },
},
gradient: {
'0%': { backgroundPosition: '0% 50%' },
'50%': { backgroundPosition: '100% 50%' },
'100%': { backgroundPosition: '0% 50%' },
},
scan: {
'0%': { transform: 'translateY(-100%)' },
'100%': { transform: 'translateY(100%)' },
}
}
}
}
}
</script>
<style>
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 4px;
height: 4px;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0.2);
}
::-webkit-scrollbar-thumb {
background: rgba(0, 243, 255, 0.3);
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(0, 243, 255, 0.6);
}
/* Holographic Glass */
.glass-holo {
background: linear-gradient(135deg, rgba(10, 15, 30, 0.7) 0%, rgba(20, 30, 50, 0.5) 100%);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(0, 243, 255, 0.1);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
position: relative;
overflow: hidden;
}
.glass-holo::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0; height: 1px;
background: linear-gradient(90deg, transparent, rgba(0, 243, 255, 0.5), transparent);
}
/* Active Element */
.glass-active {
background: rgba(0, 243, 255, 0.1);
border: 1px solid rgba(0, 243, 255, 0.4);
box-shadow: 0 0 15px rgba(0, 243, 255, 0.2);
}
/* Text Glows */
.text-glow-blue {
color: #00f3ff;
text-shadow: 0 0 8px rgba(0, 243, 255, 0.6);
}
.text-glow-purple {
color: #bc13fe;
text-shadow: 0 0 8px rgba(188, 19, 254, 0.6);
}
.text-glow-red {
color: #ff0055;
text-shadow: 0 0 8px rgba(255, 0, 85, 0.6);
}
.text-glow-green {
color: #0aff00;
text-shadow: 0 0 8px rgba(10, 255, 0, 0.6);
}
/* Grid Background */
.grid-bg {
background-size: 50px 50px;
background-image:
linear-gradient(to right, rgba(0, 243, 255, 0.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(0, 243, 255, 0.05) 1px, transparent 1px);
mask-image: radial-gradient(circle at center, black 40%, transparent 100%);
}
/* CRT Scanline Effect */
.scanlines {
background: linear-gradient(
to bottom,
rgba(255,255,255,0),
rgba(255,255,255,0) 50%,
rgba(0,0,0,0.2) 50%,
rgba(0,0,0,0.2)
);
background-size: 100% 4px;
pointer-events: none;
}
/* Tech Clip Path */
.clip-tech {
clip-path: polygon(
0 0,
100% 0,
100% calc(100% - 10px),
calc(100% - 10px) 100%,
0 100%
);
}
.clip-tech-inv {
clip-path: polygon(
10px 0,
100% 0,
100% 100%,
0 100%,
0 10px
);
}
</style>
<link rel="stylesheet" href="/index.css">
</head>
<body class="bg-black text-slate-50 overflow-hidden font-sans antialiased selection:bg-neon-blue/30">
<div id="root"></div>
<script type="module" src="/index.tsx"></script>
</body>
</html>

22
FrontEnd/index.tsx Normal file
View File

@@ -0,0 +1,22 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import '@fontsource/inter/300.css';
import '@fontsource/inter/400.css';
import '@fontsource/inter/500.css';
import '@fontsource/rajdhani/500.css';
import '@fontsource/rajdhani/600.css';
import '@fontsource/rajdhani/700.css';
import './index.css';
const rootElement = document.getElementById('root');
if (!rootElement) {
throw new Error("Could not find root element to mount to");
}
const root = ReactDOM.createRoot(rootElement);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

7
FrontEnd/metadata.json Normal file
View File

@@ -0,0 +1,7 @@
{
"name": "Industrial HMI 3D",
"description": "A Next-Gen Human Machine Interface with 3D simulation, motion control, and I/O monitoring.",
"requestFramePermissions": [
"camera"
]
}

3556
FrontEnd/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

35
FrontEnd/package.json Normal file
View File

@@ -0,0 +1,35 @@
{
"name": "industrial-hmi-3d",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@fontsource/inter": "^5.2.8",
"@fontsource/rajdhani": "^5.2.7",
"@react-three/drei": "^9.96.1",
"@react-three/fiber": "^8.15.12",
"clsx": "^2.1.0",
"lucide-react": "^0.303.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^7.9.6",
"tailwind-merge": "^2.2.0",
"three": "^0.160.0"
},
"devDependencies": {
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@types/three": "^0.160.0",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.32",
"tailwindcss": "^3.4.0",
"typescript": "^5.3.3",
"vite": "^5.0.10"
}
}

163
FrontEnd/pages/HomePage.tsx Normal file
View File

@@ -0,0 +1,163 @@
import React, { useState, useEffect } from 'react';
import { Play, Square, RotateCw, AlertTriangle, Siren, Terminal } from 'lucide-react';
import { Machine3D } from '../components/Machine3D';
import { SettingsModal } from '../components/SettingsModal';
import { InitializeModal } from '../components/InitializeModal';
import { RecipePanel } from '../components/RecipePanel';
import { MotionPanel } from '../components/MotionPanel';
import { CameraPanel } from '../components/CameraPanel';
import { CyberPanel } from '../components/common/CyberPanel';
import { TechButton } from '../components/common/TechButton';
import { ModelInfoPanel } from '../components/ModelInfoPanel';
import { SystemState, Recipe, IOPoint, LogEntry, RobotTarget, ConfigItem } from '../types';
interface HomePageProps {
systemState: SystemState;
currentRecipe: Recipe;
robotTarget: RobotTarget;
logs: LogEntry[];
ioPoints: IOPoint[];
doorStates: { front: boolean; right: boolean; left: boolean; back: boolean };
isLowPressure: boolean;
isEmergencyStop: boolean;
activeTab: 'recipe' | 'motion' | 'camera' | 'setting' | 'initialize' | null;
onSelectRecipe: (r: Recipe) => void;
onMove: (axis: 'X' | 'Y' | 'Z', val: number) => void;
onControl: (action: 'start' | 'stop' | 'reset') => void;
onSaveConfig: (config: ConfigItem[]) => void;
onCloseTab: () => void;
videoRef: React.RefObject<HTMLVideoElement>;
}
export const HomePage: React.FC<HomePageProps> = ({
systemState,
currentRecipe,
robotTarget,
logs,
ioPoints,
doorStates,
isLowPressure,
isEmergencyStop,
activeTab,
onSelectRecipe,
onMove,
onControl,
onSaveConfig,
onCloseTab,
videoRef
}) => {
useEffect(() => {
if (activeTab === 'camera' && navigator.mediaDevices?.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true }).then(s => { if (videoRef.current) videoRef.current.srcObject = s });
}
}, [activeTab, videoRef]);
return (
<main className="relative w-full h-full flex gap-6 px-6">
{/* 3D Canvas (Background Layer) */}
<div className="absolute inset-0 z-0">
<Machine3D target={robotTarget} ioState={ioPoints} doorStates={doorStates} />
</div>
{/* Center Alarms */}
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-50 pointer-events-none flex flex-col items-center gap-4">
{isEmergencyStop && (
<div className="bg-red-600/90 text-white p-8 border-4 border-red-500 shadow-glow-red flex items-center gap-6 animate-pulse">
<Siren className="w-16 h-16 animate-spin" />
<div>
<h1 className="text-5xl font-tech font-bold tracking-widest">EMERGENCY STOP</h1>
<p className="text-center font-mono text-lg">SYSTEM HALTED - RELEASE TO RESET</p>
</div>
</div>
)}
{isLowPressure && !isEmergencyStop && (
<div className="bg-amber-500/80 text-black px-8 py-4 rounded font-bold text-2xl tracking-widest flex items-center gap-4 shadow-glow-red animate-bounce">
<AlertTriangle className="w-8 h-8" /> LOW AIR PRESSURE WARNING
</div>
)}
</div>
{/* Floating Panel (Left) */}
{activeTab && activeTab !== 'setting' && activeTab !== 'recipe' && (
<div className="w-[450px] z-20 animate-in slide-in-from-left-20 duration-500 fade-in">
<CyberPanel className="h-full flex flex-col">
{activeTab === 'motion' && <MotionPanel robotTarget={robotTarget} onMove={onMove} />}
{activeTab === 'camera' && <CameraPanel videoRef={videoRef} />}
</CyberPanel>
</div>
)}
{/* Recipe Selection Modal */}
<RecipePanel
isOpen={activeTab === 'recipe'}
currentRecipe={currentRecipe}
onSelectRecipe={onSelectRecipe}
onClose={onCloseTab}
/>
{/* Settings Modal */}
<SettingsModal
isOpen={activeTab === 'setting'}
onClose={onCloseTab}
onSave={onSaveConfig}
/>
{/* Initialize Modal */}
<InitializeModal
isOpen={activeTab === 'initialize'}
onClose={onCloseTab}
/>
{/* Right Sidebar (Dashboard) */}
<div className="w-80 ml-auto z-20 flex flex-col gap-4">
<ModelInfoPanel currentRecipe={currentRecipe} />
<CyberPanel className="flex-none">
<div className="mb-2 text-xs text-neon-blue font-bold tracking-widest uppercase">System Status</div>
<div className={`text-3xl font-tech font-bold mb-4 ${systemState === SystemState.RUNNING ? 'text-neon-green text-shadow-glow-green' : 'text-slate-400'}`}>
{systemState}
</div>
<div className="space-y-3">
<TechButton
variant="green"
className="w-full flex items-center justify-center gap-2"
active={systemState === SystemState.RUNNING}
onClick={() => onControl('start')}
>
<Play className="w-4 h-4" /> START AUTO
</TechButton>
<TechButton
variant="amber"
className="w-full flex items-center justify-center gap-2"
active={systemState === SystemState.PAUSED}
onClick={() => onControl('stop')}
>
<Square className="w-4 h-4 fill-current" /> STOP / PAUSE
</TechButton>
<TechButton
className="w-full flex items-center justify-center gap-2"
onClick={() => onControl('reset')}
>
<RotateCw className="w-4 h-4" /> SYSTEM RESET
</TechButton>
</div>
</CyberPanel>
<CyberPanel className="flex-1 flex flex-col min-h-0">
<div className="mb-2 flex items-center justify-between text-xs text-neon-blue font-bold tracking-widest uppercase border-b border-white/10 pb-2">
<span>Event Log</span>
<Terminal className="w-3 h-3" />
</div>
<div className="flex-1 overflow-y-auto font-mono text-[10px] space-y-1 pr-1 custom-scrollbar">
{logs.map(log => (
<div key={log.id} className={`flex gap-2 ${log.type === 'error' ? 'text-red-500' : log.type === 'warning' ? 'text-amber-400' : 'text-slate-400'}`}>
<span className="opacity-50">[{log.timestamp}]</span>
<span>{log.message}</span>
</div>
))}
</div>
</CyberPanel>
</div>
</main>
);
};

View File

@@ -0,0 +1,125 @@
import React, { useState, useEffect } from 'react';
import { RotateCw } from 'lucide-react';
import { IOPoint } from '../types';
import { comms } from '../communication';
interface IOMonitorPageProps {
onToggle: (id: number, type: 'input' | 'output') => void;
}
export const IOMonitorPage: React.FC<IOMonitorPageProps> = ({ onToggle }) => {
const [ioPoints, setIoPoints] = useState<IOPoint[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [activeIOTab, setActiveIOTab] = useState<'in' | 'out'>('in');
// Fetch initial IO list when page mounts
useEffect(() => {
const fetchIOList = async () => {
setIsLoading(true);
try {
const ioStr = await comms.getIOList();
const ioData: IOPoint[] = JSON.parse(ioStr);
setIoPoints(ioData);
} catch (e) {
console.error('Failed to fetch IO list:', e);
}
setIsLoading(false);
};
fetchIOList();
// Subscribe to real-time IO updates
const unsubscribe = comms.subscribe((msg: any) => {
if (msg?.type === 'STATUS_UPDATE' && msg.ioState) {
setIoPoints(prev => {
const newIO = [...prev];
msg.ioState.forEach((update: { id: number, type: string, state: boolean }) => {
const idx = newIO.findIndex(p => p.id === update.id && p.type === update.type);
if (idx >= 0) newIO[idx] = { ...newIO[idx], state: update.state };
});
return newIO;
});
}
});
return () => {
unsubscribe();
};
}, []);
const points = ioPoints.filter(p => p.type === (activeIOTab === 'in' ? 'input' : 'output'));
return (
<main className="relative w-full h-full px-6 pt-6 pb-20">
<div className="glass-holo p-6 h-full flex flex-col gap-4">
{/* Local Header / Controls */}
<div className="flex items-center justify-between shrink-0">
<div className="flex items-center gap-4">
<h2 className="text-2xl font-tech font-bold text-white tracking-wider">
SYSTEM I/O MONITOR
</h2>
<div className="h-6 w-px bg-white/20"></div>
<div className="text-sm font-mono text-neon-blue">
TOTAL POINTS: {ioPoints.length}
</div>
</div>
<div className="bg-black/40 backdrop-blur-md p-1 rounded-full border border-white/10 flex gap-1">
<button
onClick={() => setActiveIOTab('in')}
className={`px-6 py-2 rounded-full font-tech font-bold text-sm transition-all ${activeIOTab === 'in' ? 'bg-neon-yellow/20 text-neon-yellow border border-neon-yellow shadow-[0_0_15px_rgba(255,230,0,0.3)]' : 'text-slate-400 hover:text-white hover:bg-white/5'}`}
>
INPUTS ({ioPoints.filter(p => p.type === 'input').length})
</button>
<button
onClick={() => setActiveIOTab('out')}
className={`px-6 py-2 rounded-full font-tech font-bold text-sm transition-all ${activeIOTab === 'out' ? 'bg-neon-green/20 text-neon-green border border-neon-green shadow-[0_0_15px_rgba(10,255,0,0.3)]' : 'text-slate-400 hover:text-white hover:bg-white/5'}`}
>
OUTPUTS ({ioPoints.filter(p => p.type === 'output').length})
</button>
</div>
</div>
<div className="bg-slate-950/40 backdrop-blur-md flex-1 overflow-y-auto custom-scrollbar rounded-lg border border-white/5">
{isLoading ? (
<div className="h-full flex flex-col items-center justify-center gap-4 animate-pulse">
<RotateCw className="w-16 h-16 text-neon-blue animate-spin" />
<div className="text-xl font-tech text-neon-blue tracking-widest">LOADING IO POINTS...</div>
</div>
) : (
<div className="grid grid-cols-2 gap-x-8 gap-y-2 p-4">
{points.map(p => (
<div
key={p.id}
onClick={() => onToggle(p.id, p.type)}
className={`
flex items-center gap-4 px-4 py-3 cursor-pointer transition-all border
clip-tech-sm group hover:translate-x-1
${p.state
? (p.type === 'output'
? 'bg-neon-green/10 border-neon-green text-neon-green shadow-[0_0_15px_rgba(10,255,0,0.2)]'
: 'bg-neon-yellow/10 border-neon-yellow text-neon-yellow shadow-[0_0_15px_rgba(255,230,0,0.2)]')
: 'bg-slate-900/40 border-slate-800 text-slate-500 hover:border-slate-600 hover:bg-slate-800/40'}
`}
>
{/* LED Indicator */}
<div className={`w-3 h-3 rounded-full shrink-0 transition-all ${p.state ? (p.type === 'output' ? 'bg-neon-green shadow-[0_0_8px_#0aff00]' : 'bg-neon-yellow shadow-[0_0_8px_#ffe600]') : 'bg-slate-800 border border-slate-700'}`}></div>
{/* ID Badge */}
<div className={`w-12 font-mono font-bold text-lg ${p.state ? 'text-white' : 'text-slate-600'}`}>
{p.type === 'input' ? 'I' : 'Q'}{p.id.toString().padStart(2, '0')}
</div>
{/* Name */}
<div className={`flex-1 font-bold uppercase tracking-wide truncate ${p.state ? 'text-white' : 'text-slate-500'} group-hover:text-white transition-colors`}>
{p.name}
</div>
</div>
))}
</div>
)}
</div>
</div>
</main>
);
};

View File

@@ -0,0 +1,245 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Layers, Plus, Trash2, Copy, Save, ArrowLeft, FileText, Calendar } from 'lucide-react';
import { Recipe } from '../types';
import { comms } from '../communication';
import { TechButton } from '../components/common/TechButton';
export const RecipePage: React.FC = () => {
const navigate = useNavigate();
const [recipes, setRecipes] = useState<Recipe[]>([]);
const [selectedId, setSelectedId] = useState<string | null>(null);
const [editedRecipe, setEditedRecipe] = useState<Recipe | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const loadRecipes = async () => {
try {
const recipeStr = await comms.getRecipeList();
const recipeData = JSON.parse(recipeStr);
setRecipes(recipeData);
if (recipeData.length > 0) {
setSelectedId(recipeData[0].id);
setEditedRecipe(recipeData[0]);
}
} catch (e) {
console.error("Failed to load recipes", e);
}
setIsLoading(false);
};
loadRecipes();
}, []);
const handleSelect = (r: Recipe) => {
setSelectedId(r.id);
setEditedRecipe({ ...r });
};
const handleSave = async () => {
// Mock Save Logic
console.log("Saving recipe:", editedRecipe);
// In real app: await comms.saveRecipe(editedRecipe);
};
const handleCopy = async () => {
if (!selectedId) return;
const selectedRecipe = recipes.find(r => r.id === selectedId);
if (!selectedRecipe) return;
const newName = prompt(`Copy "${selectedRecipe.name}" as:`, `${selectedRecipe.name}_Copy`);
if (!newName || newName.trim() === '') return;
try {
const result = await comms.copyRecipe(selectedId, newName.trim());
if (result.success && result.newRecipe) {
const newRecipeList = [...recipes, result.newRecipe];
setRecipes(newRecipeList);
setSelectedId(result.newRecipe.id);
setEditedRecipe(result.newRecipe);
console.log("Recipe copied successfully:", result.newRecipe);
} else {
alert(`Failed to copy recipe: ${result.message}`);
}
} catch (error: any) {
alert(`Error copying recipe: ${error.message || 'Unknown error'}`);
console.error('Recipe copy error:', error);
}
};
const handleDelete = async () => {
if (!selectedId) return;
const selectedRecipe = recipes.find(r => r.id === selectedId);
if (!selectedRecipe) return;
const confirmed = window.confirm(`Are you sure you want to delete "${selectedRecipe.name}"?`);
if (!confirmed) return;
try {
const result = await comms.deleteRecipe(selectedId);
if (result.success) {
const newRecipeList = recipes.filter(r => r.id !== selectedId);
setRecipes(newRecipeList);
// Select first recipe or clear selection
if (newRecipeList.length > 0) {
setSelectedId(newRecipeList[0].id);
setEditedRecipe(newRecipeList[0]);
} else {
setSelectedId(null);
setEditedRecipe(null);
}
console.log("Recipe deleted successfully");
} else {
alert(`Failed to delete recipe: ${result.message}`);
}
} catch (error: any) {
alert(`Error deleting recipe: ${error.message || 'Unknown error'}`);
console.error('Recipe delete error:', error);
}
};
return (
<div className="w-full h-full p-6 flex flex-col gap-4">
{/* Header */}
<div className="flex items-center justify-between shrink-0">
<div className="flex items-center gap-4">
<button
onClick={() => navigate('/')}
className="p-2 rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition-colors"
>
<ArrowLeft className="w-6 h-6" />
</button>
<h1 className="text-2xl font-tech font-bold text-white tracking-wider flex items-center gap-3">
<Layers className="text-neon-blue" /> RECIPE MANAGEMENT
</h1>
</div>
<div className="text-sm font-mono text-slate-400">
TOTAL: <span className="text-neon-blue">{recipes.length}</span>
</div>
</div>
<div className="flex-1 flex gap-6 min-h-0">
{/* Left: Recipe List */}
<div className="w-80 flex flex-col gap-4">
<div className="bg-slate-950/40 backdrop-blur-md border border-white/10 rounded-lg flex-1 overflow-hidden flex flex-col">
<div className="p-3 border-b border-white/10 bg-white/5 font-bold text-sm tracking-wider text-slate-300">
RECIPE LIST
</div>
<div className="flex-1 overflow-y-auto p-2 space-y-2 custom-scrollbar">
{recipes.map(r => (
<div
key={r.id}
onClick={() => handleSelect(r)}
className={`
p-3 rounded border cursor-pointer transition-all group
${selectedId === r.id
? 'bg-neon-blue/20 border-neon-blue text-white shadow-glow-blue'
: 'bg-white/5 border-white/5 text-slate-400 hover:bg-white/10 hover:border-white/20'}
`}
>
<div className="font-bold text-sm mb-1">{r.name}</div>
<div className="text-[10px] font-mono opacity-60 flex items-center gap-2">
<Calendar className="w-3 h-3" /> {r.lastModified}
</div>
</div>
))}
</div>
{/* List Actions */}
<div className="p-3 border-t border-white/10 bg-black/20 grid grid-cols-3 gap-2">
<TechButton variant="default" className="flex justify-center" title="Add New">
<Plus className="w-4 h-4" />
</TechButton>
<TechButton
variant="default"
className="flex justify-center"
title="Copy Selected"
onClick={handleCopy}
disabled={!selectedId}
>
<Copy className="w-4 h-4" />
</TechButton>
<TechButton
variant="danger"
className="flex justify-center"
title="Delete Selected"
onClick={handleDelete}
disabled={!selectedId}
>
<Trash2 className="w-4 h-4" />
</TechButton>
</div>
</div>
</div>
{/* Right: Editor */}
<div className="flex-1 bg-slate-950/40 backdrop-blur-md border border-white/10 rounded-lg flex flex-col overflow-hidden">
<div className="p-3 border-b border-white/10 bg-white/5 font-bold text-sm tracking-wider text-slate-300 flex justify-between items-center">
<span>RECIPE EDITOR</span>
{editedRecipe && <span className="text-neon-blue font-mono">{editedRecipe.id}</span>}
</div>
<div className="flex-1 p-6 overflow-y-auto custom-scrollbar">
{editedRecipe ? (
<div className="max-w-2xl space-y-6">
<div className="space-y-2">
<label className="text-xs font-bold text-slate-400 uppercase tracking-wider">Recipe Name</label>
<input
type="text"
value={editedRecipe.name}
onChange={(e) => setEditedRecipe({ ...editedRecipe, name: e.target.value })}
className="w-full bg-black/40 border border-white/10 rounded px-4 py-3 text-white focus:border-neon-blue focus:outline-none transition-colors font-mono"
/>
</div>
<div className="space-y-2">
<label className="text-xs font-bold text-slate-400 uppercase tracking-wider">Description</label>
<textarea
className="w-full h-32 bg-black/40 border border-white/10 rounded px-4 py-3 text-white focus:border-neon-blue focus:outline-none transition-colors font-mono resize-none"
placeholder="Enter recipe description..."
></textarea>
</div>
<div className="grid grid-cols-2 gap-6">
<div className="space-y-2">
<label className="text-xs font-bold text-slate-400 uppercase tracking-wider">Process Time (sec)</label>
<input type="number" className="w-full bg-black/40 border border-white/10 rounded px-4 py-3 text-white focus:border-neon-blue focus:outline-none transition-colors font-mono" defaultValue="120" />
</div>
<div className="space-y-2">
<label className="text-xs font-bold text-slate-400 uppercase tracking-wider">Temperature (°C)</label>
<input type="number" className="w-full bg-black/40 border border-white/10 rounded px-4 py-3 text-white focus:border-neon-blue focus:outline-none transition-colors font-mono" defaultValue="24.5" />
</div>
</div>
{/* Placeholder for more parameters */}
<div className="p-4 border border-dashed border-white/10 rounded bg-white/5 text-center text-slate-500 text-sm">
Additional process parameters would go here...
</div>
</div>
) : (
<div className="h-full flex flex-col items-center justify-center text-slate-500">
<FileText className="w-16 h-16 mb-4 opacity-20" />
<p>Select a recipe to edit</p>
</div>
)}
</div>
{/* Editor Actions */}
<div className="p-4 border-t border-white/10 bg-black/20 flex justify-end">
<TechButton
variant="green"
className="flex items-center gap-2 px-8"
onClick={handleSave}
disabled={!editedRecipe}
>
<Save className="w-4 h-4" /> SAVE CHANGES
</TechButton>
</div>
</div>
</div>
</div>
);
};

View File

@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

3
FrontEnd/run.bat Normal file
View File

@@ -0,0 +1,3 @@
@echo off
echo Starting Frontend Dev Server...
call npm run dev

View File

@@ -0,0 +1,59 @@
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'sans-serif'],
mono: ['Rajdhani', 'monospace'],
tech: ['Rajdhani', 'sans-serif'],
},
colors: {
slate: {
850: '#1e293b',
900: '#0f172a',
950: '#020617',
},
neon: {
blue: '#00f3ff',
purple: '#bc13fe',
pink: '#ff0099',
green: '#0aff00',
yellow: '#ffe600',
}
},
boxShadow: {
'glow-blue': '0 0 20px rgba(0, 243, 255, 0.3), inset 0 0 10px rgba(0, 243, 255, 0.1)',
'glow-purple': '0 0 20px rgba(188, 19, 254, 0.4), inset 0 0 10px rgba(188, 19, 254, 0.1)',
'glow-red': '0 0 30px rgba(255, 0, 0, 0.5)',
'hologram': '0 0 15px rgba(6, 182, 212, 0.15), inset 0 0 20px rgba(6, 182, 212, 0.05)',
},
animation: {
'pulse-slow': 'pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite',
'glow': 'glow 2s ease-in-out infinite alternate',
'gradient': 'gradient 15s ease infinite',
'scan': 'scan 4s linear infinite',
'spin-slow': 'spin 10s linear infinite',
},
keyframes: {
glow: {
'0%': { boxShadow: '0 0 5px rgba(0, 243, 255, 0.2)' },
'100%': { boxShadow: '0 0 20px rgba(0, 243, 255, 0.6), 0 0 10px rgba(0, 243, 255, 0.4)' },
},
gradient: {
'0%': { backgroundPosition: '0% 50%' },
'50%': { backgroundPosition: '100% 50%' },
'100%': { backgroundPosition: '0% 50%' },
},
scan: {
'0%': { transform: 'translateY(-100%)' },
'100%': { transform: 'translateY(100%)' },
}
}
}
},
plugins: [],
}

22
FrontEnd/tsconfig.json Normal file
View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["vite.config.ts", "node_modules"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

77
FrontEnd/types.ts Normal file
View File

@@ -0,0 +1,77 @@
export enum SystemState {
IDLE = 'IDLE',
RUNNING = 'RUNNING',
ERROR = 'ERROR',
PAUSED = 'PAUSED',
}
export interface AxisPosition {
id: string;
name: string;
axis: 'X' | 'Y' | 'Z';
value: number;
speed: number;
acc: number;
dec: number;
}
export interface Recipe {
id: string;
name: string;
lastModified: string;
}
export interface IOPoint {
id: number;
name: string;
type: 'input' | 'output';
state: boolean;
}
export interface LogEntry {
id: number;
timestamp: string;
message: string;
type: 'info' | 'warning' | 'error';
}
export interface RobotTarget {
x: number;
y: number;
z: number;
}
// WebView2 Native Bridge Types
export interface ConfigItem {
Key: string;
Value: string;
Group: string;
Type: 'String' | 'Number' | 'Boolean';
Description: string;
}
declare global {
interface Window {
chrome?: {
webview?: {
hostObjects: {
machine: {
MoveAxis(axis: string, value: number): Promise<void>;
SetIO(id: number, isInput: boolean, state: boolean): Promise<void>;
SystemControl(command: string): Promise<void>;
SelectRecipe(recipeId: string): Promise<string>;
CopyRecipe(recipeId: string, newName: string): Promise<string>;
DeleteRecipe(recipeId: string): Promise<string>;
GetConfig(): Promise<string>;
GetIOList(): Promise<string>;
GetRecipeList(): Promise<string>;
SaveConfig(configJson: string): Promise<void>;
}
};
addEventListener(type: string, listener: (event: any) => void): void;
removeEventListener(type: string, listener: (event: any) => void): void;
postMessage(message: any): void;
}
}
}
}

20
FrontEnd/vite.config.ts Normal file
View File

@@ -0,0 +1,20 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
build: {
outDir: 'dist',
emptyOutDir: true,
}
});

View File

@@ -0,0 +1,14 @@
{
"permissions": {
"allow": [
"Bash(git add:*)",
"Bash(git checkout:*)",
"Bash(build.bat)",
"Bash(cmd /c:*)",
"Bash(git commit:*)",
"Bash(msbuild:*)",
"Bash(dotnet build:*)"
],
"deny": []
}
}

9
Handler/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
*.suo
*.user
*.pdb
bin
obj
desktop.ini
.vs
packages
*.zip

99
Handler/CLAUDE.md Normal file
View File

@@ -0,0 +1,99 @@
# CLAUDE.md
이 파일은 Claude Code (claude.ai/code)가 이 저장소에서 코드 작업을 할 때 지침을 제공합니다.
## 프로젝트 개요
이것은 ATV (Automatic Test Vehicle) 릴 라벨 부착, 수정 및 전송 작업을 위한 산업 자동화 시스템입니다. 시스템은 Windows Forms를 사용하여 C# (.NET Framework 4.8)로 구축되었으며, 모션 컨트롤러, 바코드 리더, 프린터 및 PLC를 포함한 다양한 하드웨어 구성 요소와 통합됩니다.
## 빌드 명령어
- **윈도우 환경 cmd 로 실행필요
"C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\msbuild.exe" "C:\Data\Source\(5815) ATV Reel Label Attach Modify & Transfer (WMS)\Source\Handler\Project\STDLabelAttach(ATV).csproj" /v:quiet
## 아키텍처 개요
### 핵심 구성 요소
- **Project/**: UI 및 비즈니스 로직이 포함된 메인 애플리케이션
- 기본 Windows Forms 애플리케이션 포함 (`fMain.cs`)
- `RunCode/StateMachine/``RunCode/Step/`에서 상태 머신 로직 구현
- `Device/` 폴더의 디바이스 인터페이스 (KeyenceBarcode, SATOPrinter, TowerLamp 등)
- 사용자 상호작용을 위한 다이얼로그 폼
- **Project_form2/**: 데이터 처리를 위한 보조 수신기 애플리케이션
- SID (Serial ID) 변환 및 처리 담당
- 고객 정보 관리
- 가져오기/내보내기 기능
- **Sub/**: 공유 라이브러리 및 유틸리티
- `arCtl/`: 사용자 정의 UI 컨트롤 및 구성 요소
- `arAzinAxt/`: 모션 컨트롤러 인터페이스 (AzinAxt 하드웨어)
- `arRS232/`: 시리얼 통신 라이브러리
- `AmkorRestfulService/`: 외부 통합을 위한 RESTful API 서비스
- `CommSM/`: 상태 머신 통신 라이브러리
- `CommUtil/`: 공통 유틸리티 및 다이얼로그
### 주요 기술
- **하드웨어 통합**: 모션 컨트롤러 (AzinAxt), 바코드 리더 (Keyence), SATO 프린터
- **데이터베이스**: SQL Server를 사용한 Entity Framework 6.2.0
- **통신**: 시리얼 (RS232), RESTful API, WebSocket
- **비전**: 이미지 처리를 위한 EmguCV
- **프로토콜**: 장비 제어를 위한 사용자 정의 상태 머신 구현
### 상태 머신 아키텍처
애플리케이션은 포괄적인 상태 머신 패턴을 사용합니다:
- `RunCode/Step/`: 주요 작업 단계 (INIT, IDLE, RUN, HOME, FINISH)
- `RunCode/StateMachine/`: 핵심 상태 머신 로직 및 이벤트 처리
- `RunCode/RunSequence/`: 특정 작업 시퀀스 (바코드 읽기, 인쇄, 피킹)
### 디바이스 관리
- 위치 검증이 포함된 `arAzinAxt` 라이브러리를 통한 모션 제어
- Keyence 스캐너 통합을 통한 바코드 읽기
- SATO 프린터 API를 통한 라벨 인쇄
- 안전 및 I/O 제어를 위한 PLC 통신
## 개발 패턴
### 구성 관리
- 수정을 위한 UI 폼이 포함된 `Setting/` 클래스에 설정 저장
- `System_Setting.cs``System_MotParameter.cs`의 시스템 매개변수
- `UserSetting.cs`의 사용자별 설정
### 데이터 관리
- `Model1.edmx`의 Entity Framework 모델
- 다양한 데이터 유형을 위한 `Manager/` 폴더의 데이터베이스 관리자
- 릴 정보, 결과 및 SID 변환을 위한 구성 요소 클래스
### UI 패턴
- `UIControl/` 폴더의 사용자 정의 컨트롤
- `Dialog/` 폴더의 일관된 다이얼로그 패턴
- 포함된 이미지 및 아이콘을 사용한 리소스 관리
## 중요 사항
- 시스템에는 특정 하드웨어 드라이버가 필요합니다 (AzinAxt 모션 컨트롤러, Keyence SDK, SATO 프린터 드라이버)
- 데이터베이스 연결 문자열은 `app.config`에서 구성됩니다
- 모션 매개변수는 `MotParam/``.swpp``.usrs` 파일에 저장됩니다
- 애플리케이션은 서로 다른 출력 경로를 가진 Debug 및 Release 구성을 모두 지원합니다
- 플랫폼 대상은 일반적으로 하드웨어 호환성을 위해 x64입니다
## 테스트
공식적인 단위 테스트 프로젝트는 없습니다. 테스트는 일반적으로 다음을 통해 수행됩니다:
- 메인 애플리케이션을 사용한 수동 작업
- 실제 장비를 사용한 하드웨어 인 더 루프 테스트
- 애플리케이션의 디버그 다이얼로그 및 모니터링 폼
## 종속성
주요 외부 종속성은 다음과 같습니다:
- Entity Framework 6.2.0
- Newtonsoft.Json 13.0.3
- EmguCV 4.5.1
- 웹 서비스를 위한 Microsoft OWIN 스택
- 다양한 하드웨어별 SDK 및 드라이버

BIN
Handler/DLL/ArLog.Net4.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Handler/DLL/libxl.dll Normal file

Binary file not shown.

BIN
Handler/DLL/libxl.net.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,256 @@
File-Spec,2
FileType,User Parameters Data File
Made-by,YASKAWA SigmaWin+ Ver.7
DateTime,12/23/2020 11:45:35 AM
SERVO-TYPE,SGD7S-2R8A00A
SERVO-ID,112
SERVO-YMOD,0
SERVO-SPEC,00
SERVO-SOFT,47
SERVO-CAPACITY,400
SerialNo,D0205I826810007
BTOFlag,1
BTO-ID,
IS-SUPPORTED,1
IS-EDITED,0
MachineName,
OP-TYPE,
OP-ID,65533
OP-YMOD,65535
OP-SOFT,65535
OP1-TYPE,
OP1-TYPEID,0
OP1-ID,65533
OP1-YMOD,65535
OP1-YMODTYPE,65535
OP1-SOFT,65535
OP2-TYPE,
OP2-TYPEID,0
OP2-ID,65533
OP2-YMOD,65535
OP2-YMODTYPE,65535
OP2-SOFT,65535
OP3-TYPE,
OP3-TYPEID,0
OP3-ID,65533
OP3-YMOD,65535
OP3-YMODTYPE,65535
OP3-SOFT,65535
ACCESS-LEVEL,1
SpecVersion,65535
AXIS-NUM,1
MOTOR-TYPE,SGM7J-04AFD21
MOTOR-ID,173
ENCODER-ID,24
ENCODER-SOFT,3
ServoControlType,512
CompatibleMapNum,6
CompatibleMap,0,3,3,6,6,10
CommentCnt,0
Comment,
ServoNameComment,Picker X
UserPrmCnt,198
UserPrm,000,17,2,1
UserPrm,001,0,2,0
UserPrm,002,0,2,0
UserPrm,006,2,2,0
UserPrm,007,0,2,0
UserPrm,008,0,2,0
UserPrm,009,16,2,0
UserPrm,00A,1,2,0
UserPrm,00B,256,2,1
UserPrm,00C,0,2,0
UserPrm,00D,0,2,0
UserPrm,00E,0,2,0
UserPrm,00F,0,2,0
UserPrm,010,1,2,0
UserPrm,021,0,2,0
UserPrm,040,0,2,0
UserPrm,080,0,2,0
UserPrm,081,0,2,0
UserPrm,100,400,2,0
UserPrm,101,2000,2,0
UserPrm,102,400,2,0
UserPrm,103,100,2,0
UserPrm,104,400,2,0
UserPrm,105,2000,2,0
UserPrm,106,400,2,0
UserPrm,109,0,2,0
UserPrm,10A,0,2,0
UserPrm,10B,0,2,0
UserPrm,10C,200,2,0
UserPrm,10D,0,2,0
UserPrm,10E,0,2,0
UserPrm,10F,0,2,0
UserPrm,11F,0,2,0
UserPrm,121,100,2,0
UserPrm,122,100,2,0
UserPrm,123,0,2,0
UserPrm,124,0,2,0
UserPrm,125,100,2,0
UserPrm,131,0,2,0
UserPrm,132,0,2,0
UserPrm,135,0,2,0
UserPrm,136,0,2,0
UserPrm,139,0,2,0
UserPrm,13D,2000,2,0
UserPrm,140,256,2,0
UserPrm,141,500,2,0
UserPrm,142,1000,2,0
UserPrm,143,1000,2,0
UserPrm,144,1000,2,0
UserPrm,145,500,2,0
UserPrm,146,700,2,0
UserPrm,147,1000,2,0
UserPrm,148,500,2,0
UserPrm,149,1000,2,0
UserPrm,14A,800,2,0
UserPrm,14B,100,2,0
UserPrm,14F,33,2,0
UserPrm,160,16,2,0
UserPrm,161,1000,2,0
UserPrm,162,100,2,0
UserPrm,163,0,2,0
UserPrm,164,0,2,0
UserPrm,165,0,2,0
UserPrm,166,0,2,0
UserPrm,170,5121,2,0
UserPrm,200,1,2,1
UserPrm,205,65535,2,0
UserPrm,207,0,2,0
UserPrm,20A,32768,4,0
UserPrm,20E,16777216,4,1
UserPrm,210,20000,4,1
UserPrm,212,5000,4,1
UserPrm,216,0,2,0
UserPrm,217,0,2,0
UserPrm,218,1,2,0
UserPrm,22A,0,2,0
UserPrm,240,0,2,0
UserPrm,281,20,2,0
UserPrm,300,600,2,0
UserPrm,301,100,2,0
UserPrm,302,200,2,0
UserPrm,303,300,2,0
UserPrm,304,50,2,1
UserPrm,305,0,2,0
UserPrm,306,0,2,0
UserPrm,307,40,2,0
UserPrm,308,0,2,0
UserPrm,30A,0,2,0
UserPrm,30C,0,2,0
UserPrm,310,0,2,0
UserPrm,311,100,2,0
UserPrm,312,50,2,0
UserPrm,316,10000,2,0
UserPrm,324,300,2,0
UserPrm,400,30,2,0
UserPrm,401,100,2,0
UserPrm,402,800,2,0
UserPrm,403,800,2,0
UserPrm,404,100,2,0
UserPrm,405,100,2,0
UserPrm,406,800,2,0
UserPrm,407,10000,2,0
UserPrm,408,0,2,0
UserPrm,409,5000,2,0
UserPrm,40A,70,2,0
UserPrm,40B,0,2,0
UserPrm,40C,5000,2,0
UserPrm,40D,70,2,0
UserPrm,40E,0,2,0
UserPrm,40F,5000,2,0
UserPrm,410,50,2,0
UserPrm,412,100,2,0
UserPrm,415,0,2,0
UserPrm,416,0,2,0
UserPrm,417,5000,2,0
UserPrm,418,70,2,0
UserPrm,419,0,2,0
UserPrm,41A,5000,2,0
UserPrm,41B,70,2,0
UserPrm,41C,0,2,0
UserPrm,41D,5000,2,0
UserPrm,41E,70,2,0
UserPrm,41F,0,2,0
UserPrm,423,0,2,0
UserPrm,424,50,2,0
UserPrm,425,100,2,0
UserPrm,426,0,2,0
UserPrm,427,0,2,0
UserPrm,456,15,2,0
UserPrm,460,257,2,0
UserPrm,475,0,2,0
UserPrm,476,0,2,0
UserPrm,481,400,2,0
UserPrm,482,3000,2,0
UserPrm,486,25,2,0
UserPrm,487,0,2,0
UserPrm,488,100,2,0
UserPrm,490,100,2,0
UserPrm,495,100,2,0
UserPrm,498,10,2,0
UserPrm,501,10,2,0
UserPrm,502,20,2,0
UserPrm,503,10,2,0
UserPrm,506,0,2,0
UserPrm,507,100,2,0
UserPrm,508,50,2,0
UserPrm,509,20,2,0
UserPrm,50A,8448,2,0
UserPrm,50B,25923,2,0
UserPrm,50C,34952,2,0
UserPrm,50D,34952,2,0
UserPrm,50E,12817,2,0
UserPrm,50F,0,2,0
UserPrm,510,0,2,0
UserPrm,512,0,2,0
UserPrm,513,0,2,0
UserPrm,514,0,2,0
UserPrm,515,34952,2,0
UserPrm,516,34952,2,0
UserPrm,517,1620,2,0
UserPrm,518,0,2,0
UserPrm,519,34952,2,0
UserPrm,51B,1000,4,0
UserPrm,51E,100,2,0
UserPrm,520,5242880,4,0
UserPrm,522,7,4,0
UserPrm,524,1073741824,4,0
UserPrm,526,5242880,4,0
UserPrm,528,100,2,0
UserPrm,529,10000,2,0
UserPrm,52A,20,2,0
UserPrm,52B,20,2,0
UserPrm,52C,100,2,0
UserPrm,52F,4095,2,0
UserPrm,530,0,2,0
UserPrm,531,32768,4,0
UserPrm,533,500,2,0
UserPrm,534,100,2,0
UserPrm,535,100,2,0
UserPrm,536,1,2,0
UserPrm,550,0,2,0
UserPrm,551,0,2,0
UserPrm,552,100,2,0
UserPrm,553,100,2,0
UserPrm,55A,1,2,0
UserPrm,560,400,2,0
UserPrm,561,100,2,0
UserPrm,600,0,2,0
UserPrm,601,0,2,0
UserPrm,603,0,2,0
UserPrm,604,0,2,0
UserPrm,621,0,2,0
UserPrm,622,10000,2,0
UserPrm,623,10000,2,0
UserPrm,624,10,2,0
UserPrm,625,100,2,0
UserPrm,626,100,4,0
UserPrm,628,10,2,0
Custom
CustomGroupNum,1
Gp1_Begin
GroupName,
Num,0
Gp1_End

Binary file not shown.

View File

@@ -0,0 +1,256 @@
File-Spec,2
FileType,User Parameters Data File
Made-by,YASKAWA SigmaWin+ Ver.7
DateTime,12/23/2020 11:46:21 AM
SERVO-TYPE,SGD7S-1R6A00A002
SERVO-ID,112
SERVO-YMOD,0
SERVO-SPEC,00
SERVO-SOFT,47
SERVO-CAPACITY,200
SerialNo,1A2036500620011
BTOFlag,1
BTO-ID,
IS-SUPPORTED,1
IS-EDITED,0
MachineName,
OP-TYPE,
OP-ID,65533
OP-YMOD,65535
OP-SOFT,65535
OP1-TYPE,
OP1-TYPEID,0
OP1-ID,65533
OP1-YMOD,65535
OP1-YMODTYPE,65535
OP1-SOFT,65535
OP2-TYPE,
OP2-TYPEID,0
OP2-ID,65533
OP2-YMOD,65535
OP2-YMODTYPE,65535
OP2-SOFT,65535
OP3-TYPE,
OP3-TYPEID,0
OP3-ID,65533
OP3-YMOD,65535
OP3-YMODTYPE,65535
OP3-SOFT,65535
ACCESS-LEVEL,1
SpecVersion,65535
AXIS-NUM,1
MOTOR-TYPE,SGM7J-02AFD2C
MOTOR-ID,173
ENCODER-ID,24
ENCODER-SOFT,3
ServoControlType,512
CompatibleMapNum,6
CompatibleMap,0,3,3,6,6,10
CommentCnt,0
Comment,
ServoNameComment,Picker Z
UserPrmCnt,198
UserPrm,000,17,2,1
UserPrm,001,0,2,0
UserPrm,002,0,2,0
UserPrm,006,2,2,0
UserPrm,007,0,2,0
UserPrm,008,0,2,0
UserPrm,009,16,2,0
UserPrm,00A,1,2,0
UserPrm,00B,256,2,1
UserPrm,00C,0,2,0
UserPrm,00D,0,2,0
UserPrm,00E,0,2,0
UserPrm,00F,0,2,0
UserPrm,010,1,2,0
UserPrm,021,0,2,0
UserPrm,040,0,2,0
UserPrm,080,0,2,0
UserPrm,081,0,2,0
UserPrm,100,400,2,0
UserPrm,101,2000,2,0
UserPrm,102,400,2,0
UserPrm,103,100,2,0
UserPrm,104,400,2,0
UserPrm,105,2000,2,0
UserPrm,106,400,2,0
UserPrm,109,0,2,0
UserPrm,10A,0,2,0
UserPrm,10B,0,2,0
UserPrm,10C,200,2,0
UserPrm,10D,0,2,0
UserPrm,10E,0,2,0
UserPrm,10F,0,2,0
UserPrm,11F,0,2,0
UserPrm,121,100,2,0
UserPrm,122,100,2,0
UserPrm,123,0,2,0
UserPrm,124,0,2,0
UserPrm,125,100,2,0
UserPrm,131,0,2,0
UserPrm,132,0,2,0
UserPrm,135,0,2,0
UserPrm,136,0,2,0
UserPrm,139,0,2,0
UserPrm,13D,2000,2,0
UserPrm,140,256,2,0
UserPrm,141,500,2,0
UserPrm,142,1000,2,0
UserPrm,143,1000,2,0
UserPrm,144,1000,2,0
UserPrm,145,500,2,0
UserPrm,146,700,2,0
UserPrm,147,1000,2,0
UserPrm,148,500,2,0
UserPrm,149,1000,2,0
UserPrm,14A,800,2,0
UserPrm,14B,100,2,0
UserPrm,14F,33,2,0
UserPrm,160,16,2,0
UserPrm,161,1000,2,0
UserPrm,162,100,2,0
UserPrm,163,0,2,0
UserPrm,164,0,2,0
UserPrm,165,0,2,0
UserPrm,166,0,2,0
UserPrm,170,5121,2,0
UserPrm,200,1,2,1
UserPrm,205,65535,2,0
UserPrm,207,0,2,0
UserPrm,20A,32768,4,0
UserPrm,20E,16777216,4,1
UserPrm,210,20000,4,1
UserPrm,212,5000,4,1
UserPrm,216,0,2,0
UserPrm,217,0,2,0
UserPrm,218,1,2,0
UserPrm,22A,0,2,0
UserPrm,240,0,2,0
UserPrm,281,20,2,0
UserPrm,300,600,2,0
UserPrm,301,100,2,0
UserPrm,302,200,2,0
UserPrm,303,300,2,0
UserPrm,304,50,2,1
UserPrm,305,0,2,0
UserPrm,306,0,2,0
UserPrm,307,40,2,0
UserPrm,308,0,2,0
UserPrm,30A,0,2,0
UserPrm,30C,0,2,0
UserPrm,310,0,2,0
UserPrm,311,100,2,0
UserPrm,312,50,2,0
UserPrm,316,10000,2,0
UserPrm,324,300,2,0
UserPrm,400,30,2,0
UserPrm,401,85,2,1
UserPrm,402,800,2,0
UserPrm,403,800,2,0
UserPrm,404,100,2,0
UserPrm,405,100,2,0
UserPrm,406,800,2,0
UserPrm,407,10000,2,0
UserPrm,408,256,2,1
UserPrm,409,5000,2,0
UserPrm,40A,70,2,0
UserPrm,40B,0,2,0
UserPrm,40C,1480,2,1
UserPrm,40D,150,2,1
UserPrm,40E,0,2,0
UserPrm,40F,5000,2,0
UserPrm,410,50,2,0
UserPrm,412,100,2,0
UserPrm,415,0,2,0
UserPrm,416,0,2,0
UserPrm,417,5000,2,0
UserPrm,418,70,2,0
UserPrm,419,0,2,0
UserPrm,41A,5000,2,0
UserPrm,41B,70,2,0
UserPrm,41C,0,2,0
UserPrm,41D,5000,2,0
UserPrm,41E,70,2,0
UserPrm,41F,0,2,0
UserPrm,423,0,2,0
UserPrm,424,50,2,0
UserPrm,425,100,2,0
UserPrm,426,0,2,0
UserPrm,427,0,2,0
UserPrm,456,15,2,0
UserPrm,460,257,2,0
UserPrm,475,0,2,0
UserPrm,476,0,2,0
UserPrm,481,400,2,0
UserPrm,482,3000,2,0
UserPrm,486,25,2,0
UserPrm,487,0,2,0
UserPrm,488,100,2,0
UserPrm,490,100,2,0
UserPrm,495,100,2,0
UserPrm,498,10,2,0
UserPrm,501,10,2,0
UserPrm,502,20,2,0
UserPrm,503,10,2,0
UserPrm,506,0,2,0
UserPrm,507,100,2,0
UserPrm,508,50,2,0
UserPrm,509,20,2,0
UserPrm,50A,8448,2,0
UserPrm,50B,25923,2,0
UserPrm,50C,34952,2,0
UserPrm,50D,34952,2,0
UserPrm,50E,12305,2,1
UserPrm,50F,512,2,1
UserPrm,510,0,2,0
UserPrm,512,0,2,0
UserPrm,513,0,2,0
UserPrm,514,0,2,0
UserPrm,515,34952,2,0
UserPrm,516,34952,2,0
UserPrm,517,1620,2,0
UserPrm,518,0,2,0
UserPrm,519,34952,2,0
UserPrm,51B,1000,4,0
UserPrm,51E,100,2,0
UserPrm,520,5242880,4,0
UserPrm,522,7,4,0
UserPrm,524,1073741824,4,0
UserPrm,526,5242880,4,0
UserPrm,528,100,2,0
UserPrm,529,10000,2,0
UserPrm,52A,20,2,0
UserPrm,52B,20,2,0
UserPrm,52C,100,2,0
UserPrm,52F,4095,2,0
UserPrm,530,0,2,0
UserPrm,531,32768,4,0
UserPrm,533,500,2,0
UserPrm,534,100,2,0
UserPrm,535,100,2,0
UserPrm,536,1,2,0
UserPrm,550,0,2,0
UserPrm,551,0,2,0
UserPrm,552,100,2,0
UserPrm,553,100,2,0
UserPrm,55A,1,2,0
UserPrm,560,400,2,0
UserPrm,561,100,2,0
UserPrm,600,0,2,0
UserPrm,601,0,2,0
UserPrm,603,0,2,0
UserPrm,604,0,2,0
UserPrm,621,0,2,0
UserPrm,622,10000,2,0
UserPrm,623,10000,2,0
UserPrm,624,10,2,0
UserPrm,625,100,2,0
UserPrm,626,100,4,0
UserPrm,628,10,2,0
Custom
CustomGroupNum,1
Gp1_Begin
GroupName,
Num,0
Gp1_End

Binary file not shown.

View File

@@ -0,0 +1,256 @@
File-Spec,2
FileType,User Parameters Data File
Made-by,YASKAWA SigmaWin+ Ver.7
DateTime,12/29/2020 4:34:27 PM
SERVO-TYPE,SGD7S-1R6A00A002
SERVO-ID,112
SERVO-YMOD,0
SERVO-SPEC,00
SERVO-SOFT,47
SERVO-CAPACITY,200
SerialNo,1A2036500620026
BTOFlag,1
BTO-ID,
IS-SUPPORTED,1
IS-EDITED,0
MachineName,
OP-TYPE,
OP-ID,65533
OP-YMOD,65535
OP-SOFT,65535
OP1-TYPE,
OP1-TYPEID,0
OP1-ID,65533
OP1-YMOD,65535
OP1-YMODTYPE,65535
OP1-SOFT,65535
OP2-TYPE,
OP2-TYPEID,0
OP2-ID,65533
OP2-YMOD,65535
OP2-YMODTYPE,65535
OP2-SOFT,65535
OP3-TYPE,
OP3-TYPEID,0
OP3-ID,65533
OP3-YMOD,65535
OP3-YMODTYPE,65535
OP3-SOFT,65535
ACCESS-LEVEL,1
SpecVersion,65535
AXIS-NUM,1
MOTOR-TYPE,SGM7J-02AFD21
MOTOR-ID,173
ENCODER-ID,24
ENCODER-SOFT,3
ServoControlType,512
CompatibleMapNum,6
CompatibleMap,0,3,3,6,6,10
CommentCnt,0
Comment,
ServoNameComment,PrintLeft Move
UserPrmCnt,198
UserPrm,000,16,2,1
UserPrm,001,0,2,0
UserPrm,002,0,2,0
UserPrm,006,2,2,0
UserPrm,007,0,2,0
UserPrm,008,0,2,0
UserPrm,009,16,2,0
UserPrm,00A,1,2,0
UserPrm,00B,256,2,1
UserPrm,00C,0,2,0
UserPrm,00D,0,2,0
UserPrm,00E,0,2,0
UserPrm,00F,0,2,0
UserPrm,010,1,2,0
UserPrm,021,0,2,0
UserPrm,040,0,2,0
UserPrm,080,0,2,0
UserPrm,081,0,2,0
UserPrm,100,600,2,1
UserPrm,101,2000,2,0
UserPrm,102,600,2,1
UserPrm,103,3000,2,1
UserPrm,104,400,2,0
UserPrm,105,2000,2,0
UserPrm,106,400,2,0
UserPrm,109,0,2,0
UserPrm,10A,0,2,0
UserPrm,10B,0,2,0
UserPrm,10C,200,2,0
UserPrm,10D,0,2,0
UserPrm,10E,0,2,0
UserPrm,10F,0,2,0
UserPrm,11F,0,2,0
UserPrm,121,100,2,0
UserPrm,122,100,2,0
UserPrm,123,0,2,0
UserPrm,124,0,2,0
UserPrm,125,100,2,0
UserPrm,131,0,2,0
UserPrm,132,0,2,0
UserPrm,135,0,2,0
UserPrm,136,0,2,0
UserPrm,139,0,2,0
UserPrm,13D,2000,2,0
UserPrm,140,256,2,0
UserPrm,141,500,2,0
UserPrm,142,1000,2,0
UserPrm,143,1000,2,0
UserPrm,144,1000,2,0
UserPrm,145,500,2,0
UserPrm,146,700,2,0
UserPrm,147,1000,2,0
UserPrm,148,500,2,0
UserPrm,149,1000,2,0
UserPrm,14A,800,2,0
UserPrm,14B,100,2,0
UserPrm,14F,33,2,0
UserPrm,160,16,2,0
UserPrm,161,1000,2,0
UserPrm,162,100,2,0
UserPrm,163,0,2,0
UserPrm,164,0,2,0
UserPrm,165,0,2,0
UserPrm,166,0,2,0
UserPrm,170,5120,2,1
UserPrm,200,1,2,1
UserPrm,205,65535,2,0
UserPrm,207,0,2,0
UserPrm,20A,32768,4,0
UserPrm,20E,16777216,4,1
UserPrm,210,46000,4,1
UserPrm,212,11500,4,1
UserPrm,216,0,2,0
UserPrm,217,0,2,0
UserPrm,218,1,2,0
UserPrm,22A,0,2,0
UserPrm,240,0,2,0
UserPrm,281,20,2,0
UserPrm,300,600,2,0
UserPrm,301,100,2,0
UserPrm,302,200,2,0
UserPrm,303,300,2,0
UserPrm,304,50,2,1
UserPrm,305,0,2,0
UserPrm,306,0,2,0
UserPrm,307,40,2,0
UserPrm,308,0,2,0
UserPrm,30A,0,2,0
UserPrm,30C,0,2,0
UserPrm,310,0,2,0
UserPrm,311,100,2,0
UserPrm,312,50,2,0
UserPrm,316,10000,2,0
UserPrm,324,300,2,0
UserPrm,400,90,2,1
UserPrm,401,400,2,1
UserPrm,402,800,2,0
UserPrm,403,800,2,0
UserPrm,404,800,2,1
UserPrm,405,800,2,1
UserPrm,406,800,2,0
UserPrm,407,10000,2,0
UserPrm,408,0,2,0
UserPrm,409,5000,2,0
UserPrm,40A,70,2,0
UserPrm,40B,0,2,0
UserPrm,40C,5000,2,0
UserPrm,40D,70,2,0
UserPrm,40E,0,2,0
UserPrm,40F,5000,2,0
UserPrm,410,50,2,0
UserPrm,412,100,2,0
UserPrm,415,0,2,0
UserPrm,416,0,2,0
UserPrm,417,5000,2,0
UserPrm,418,70,2,0
UserPrm,419,0,2,0
UserPrm,41A,5000,2,0
UserPrm,41B,70,2,0
UserPrm,41C,0,2,0
UserPrm,41D,5000,2,0
UserPrm,41E,70,2,0
UserPrm,41F,0,2,0
UserPrm,423,0,2,0
UserPrm,424,50,2,0
UserPrm,425,100,2,0
UserPrm,426,0,2,0
UserPrm,427,0,2,0
UserPrm,456,15,2,0
UserPrm,460,257,2,0
UserPrm,475,0,2,0
UserPrm,476,0,2,0
UserPrm,481,400,2,0
UserPrm,482,3000,2,0
UserPrm,486,25,2,0
UserPrm,487,0,2,0
UserPrm,488,100,2,0
UserPrm,490,100,2,0
UserPrm,495,100,2,0
UserPrm,498,10,2,0
UserPrm,501,10,2,0
UserPrm,502,20,2,0
UserPrm,503,10,2,0
UserPrm,506,0,2,0
UserPrm,507,100,2,0
UserPrm,508,50,2,0
UserPrm,509,20,2,0
UserPrm,50A,33025,2,1
UserPrm,50B,25928,2,1
UserPrm,50C,34952,2,0
UserPrm,50D,34952,2,0
UserPrm,50E,12817,2,0
UserPrm,50F,0,2,0
UserPrm,510,0,2,0
UserPrm,512,0,2,0
UserPrm,513,0,2,0
UserPrm,514,0,2,0
UserPrm,515,34952,2,0
UserPrm,516,34952,2,0
UserPrm,517,1620,2,0
UserPrm,518,0,2,0
UserPrm,519,34952,2,0
UserPrm,51B,1000,4,0
UserPrm,51E,100,2,0
UserPrm,520,5242880,4,0
UserPrm,522,7,4,0
UserPrm,524,1073741824,4,0
UserPrm,526,5242880,4,0
UserPrm,528,100,2,0
UserPrm,529,10000,2,0
UserPrm,52A,20,2,0
UserPrm,52B,20,2,0
UserPrm,52C,100,2,0
UserPrm,52F,4095,2,0
UserPrm,530,5,2,1
UserPrm,531,2000,4,1
UserPrm,533,100,2,1
UserPrm,534,100,2,0
UserPrm,535,3,2,1
UserPrm,536,0,2,1
UserPrm,550,0,2,0
UserPrm,551,0,2,0
UserPrm,552,100,2,0
UserPrm,553,100,2,0
UserPrm,55A,1,2,0
UserPrm,560,400,2,0
UserPrm,561,100,2,0
UserPrm,600,0,2,0
UserPrm,601,0,2,0
UserPrm,603,0,2,0
UserPrm,604,0,2,0
UserPrm,621,0,2,0
UserPrm,622,10000,2,0
UserPrm,623,10000,2,0
UserPrm,624,10,2,0
UserPrm,625,100,2,0
UserPrm,626,100,4,0
UserPrm,628,10,2,0
Custom
CustomGroupNum,1
Gp1_Begin
GroupName,
Num,0
Gp1_End

Binary file not shown.

View File

@@ -0,0 +1,256 @@
File-Spec,2
FileType,User Parameters Data File
Made-by,YASKAWA SigmaWin+ Ver.7
DateTime,12/29/2020 4:42:26 PM
SERVO-TYPE,SGD7S-1R6A00A002
SERVO-ID,112
SERVO-YMOD,0
SERVO-SPEC,00
SERVO-SOFT,47
SERVO-CAPACITY,200
SerialNo,1A2046912320009
BTOFlag,1
BTO-ID,
IS-SUPPORTED,1
IS-EDITED,0
MachineName,
OP-TYPE,
OP-ID,65533
OP-YMOD,65535
OP-SOFT,65535
OP1-TYPE,
OP1-TYPEID,0
OP1-ID,65533
OP1-YMOD,65535
OP1-YMODTYPE,65535
OP1-SOFT,65535
OP2-TYPE,
OP2-TYPEID,0
OP2-ID,65533
OP2-YMOD,65535
OP2-YMODTYPE,65535
OP2-SOFT,65535
OP3-TYPE,
OP3-TYPEID,0
OP3-ID,65533
OP3-YMOD,65535
OP3-YMODTYPE,65535
OP3-SOFT,65535
ACCESS-LEVEL,1
SpecVersion,65535
AXIS-NUM,1
MOTOR-TYPE,SGM7J-02AFD2C
MOTOR-ID,173
ENCODER-ID,24
ENCODER-SOFT,3
ServoControlType,512
CompatibleMapNum,6
CompatibleMap,0,3,3,6,6,10
CommentCnt,0
Comment,
ServoNameComment,Print Left Up/Dn
UserPrmCnt,198
UserPrm,000,17,2,1
UserPrm,001,0,2,0
UserPrm,002,0,2,0
UserPrm,006,2,2,0
UserPrm,007,0,2,0
UserPrm,008,0,2,0
UserPrm,009,16,2,0
UserPrm,00A,1,2,0
UserPrm,00B,256,2,1
UserPrm,00C,0,2,0
UserPrm,00D,0,2,0
UserPrm,00E,0,2,0
UserPrm,00F,0,2,0
UserPrm,010,1,2,0
UserPrm,021,0,2,0
UserPrm,040,0,2,0
UserPrm,080,0,2,0
UserPrm,081,0,2,0
UserPrm,100,400,2,0
UserPrm,101,2000,2,0
UserPrm,102,400,2,0
UserPrm,103,100,2,0
UserPrm,104,400,2,0
UserPrm,105,2000,2,0
UserPrm,106,400,2,0
UserPrm,109,0,2,0
UserPrm,10A,0,2,0
UserPrm,10B,0,2,0
UserPrm,10C,200,2,0
UserPrm,10D,0,2,0
UserPrm,10E,0,2,0
UserPrm,10F,0,2,0
UserPrm,11F,0,2,0
UserPrm,121,100,2,0
UserPrm,122,100,2,0
UserPrm,123,0,2,0
UserPrm,124,0,2,0
UserPrm,125,100,2,0
UserPrm,131,0,2,0
UserPrm,132,0,2,0
UserPrm,135,0,2,0
UserPrm,136,0,2,0
UserPrm,139,0,2,0
UserPrm,13D,2000,2,0
UserPrm,140,256,2,0
UserPrm,141,500,2,0
UserPrm,142,1000,2,0
UserPrm,143,1000,2,0
UserPrm,144,1000,2,0
UserPrm,145,500,2,0
UserPrm,146,700,2,0
UserPrm,147,1000,2,0
UserPrm,148,500,2,0
UserPrm,149,1000,2,0
UserPrm,14A,800,2,0
UserPrm,14B,100,2,0
UserPrm,14F,33,2,0
UserPrm,160,16,2,0
UserPrm,161,1000,2,0
UserPrm,162,100,2,0
UserPrm,163,0,2,0
UserPrm,164,0,2,0
UserPrm,165,0,2,0
UserPrm,166,0,2,0
UserPrm,170,5121,2,0
UserPrm,200,1,2,1
UserPrm,205,65535,2,0
UserPrm,207,0,2,0
UserPrm,20A,32768,4,0
UserPrm,20E,16777216,4,1
UserPrm,210,10000,4,1
UserPrm,212,2500,4,1
UserPrm,216,0,2,0
UserPrm,217,0,2,0
UserPrm,218,1,2,0
UserPrm,22A,0,2,0
UserPrm,240,0,2,0
UserPrm,281,20,2,0
UserPrm,300,600,2,0
UserPrm,301,100,2,0
UserPrm,302,200,2,0
UserPrm,303,300,2,0
UserPrm,304,50,2,1
UserPrm,305,0,2,0
UserPrm,306,0,2,0
UserPrm,307,40,2,0
UserPrm,308,0,2,0
UserPrm,30A,0,2,0
UserPrm,30C,0,2,0
UserPrm,310,0,2,0
UserPrm,311,100,2,0
UserPrm,312,50,2,0
UserPrm,316,10000,2,0
UserPrm,324,300,2,0
UserPrm,400,30,2,0
UserPrm,401,85,2,1
UserPrm,402,800,2,0
UserPrm,403,800,2,0
UserPrm,404,100,2,0
UserPrm,405,100,2,0
UserPrm,406,800,2,0
UserPrm,407,10000,2,0
UserPrm,408,256,2,1
UserPrm,409,5000,2,0
UserPrm,40A,70,2,0
UserPrm,40B,0,2,0
UserPrm,40C,1480,2,1
UserPrm,40D,150,2,1
UserPrm,40E,0,2,0
UserPrm,40F,5000,2,0
UserPrm,410,50,2,0
UserPrm,412,100,2,0
UserPrm,415,0,2,0
UserPrm,416,0,2,0
UserPrm,417,5000,2,0
UserPrm,418,70,2,0
UserPrm,419,0,2,0
UserPrm,41A,5000,2,0
UserPrm,41B,70,2,0
UserPrm,41C,0,2,0
UserPrm,41D,5000,2,0
UserPrm,41E,70,2,0
UserPrm,41F,0,2,0
UserPrm,423,0,2,0
UserPrm,424,50,2,0
UserPrm,425,100,2,0
UserPrm,426,0,2,0
UserPrm,427,0,2,0
UserPrm,456,15,2,0
UserPrm,460,257,2,0
UserPrm,475,0,2,0
UserPrm,476,0,2,0
UserPrm,481,400,2,0
UserPrm,482,3000,2,0
UserPrm,486,25,2,0
UserPrm,487,0,2,0
UserPrm,488,100,2,0
UserPrm,490,100,2,0
UserPrm,495,100,2,0
UserPrm,498,10,2,0
UserPrm,501,10,2,0
UserPrm,502,20,2,0
UserPrm,503,10,2,0
UserPrm,506,0,2,0
UserPrm,507,100,2,0
UserPrm,508,50,2,0
UserPrm,509,20,2,0
UserPrm,50A,8448,2,0
UserPrm,50B,25923,2,0
UserPrm,50C,34952,2,0
UserPrm,50D,34952,2,0
UserPrm,50E,12305,2,1
UserPrm,50F,512,2,1
UserPrm,510,0,2,0
UserPrm,512,0,2,0
UserPrm,513,0,2,0
UserPrm,514,0,2,0
UserPrm,515,34952,2,0
UserPrm,516,34952,2,0
UserPrm,517,1620,2,0
UserPrm,518,0,2,0
UserPrm,519,34952,2,0
UserPrm,51B,1000,4,0
UserPrm,51E,100,2,0
UserPrm,520,5242880,4,0
UserPrm,522,7,4,0
UserPrm,524,1073741824,4,0
UserPrm,526,5242880,4,0
UserPrm,528,100,2,0
UserPrm,529,10000,2,0
UserPrm,52A,20,2,0
UserPrm,52B,20,2,0
UserPrm,52C,100,2,0
UserPrm,52F,4095,2,0
UserPrm,530,0,2,0
UserPrm,531,32768,4,0
UserPrm,533,500,2,0
UserPrm,534,100,2,0
UserPrm,535,100,2,0
UserPrm,536,1,2,0
UserPrm,550,0,2,0
UserPrm,551,0,2,0
UserPrm,552,100,2,0
UserPrm,553,100,2,0
UserPrm,55A,1,2,0
UserPrm,560,400,2,0
UserPrm,561,100,2,0
UserPrm,600,0,2,0
UserPrm,601,0,2,0
UserPrm,603,0,2,0
UserPrm,604,0,2,0
UserPrm,621,0,2,0
UserPrm,622,10000,2,0
UserPrm,623,10000,2,0
UserPrm,624,10,2,0
UserPrm,625,100,2,0
UserPrm,626,100,4,0
UserPrm,628,10,2,0
Custom
CustomGroupNum,1
Gp1_Begin
GroupName,
Num,0
Gp1_End

Binary file not shown.

View File

@@ -0,0 +1,256 @@
File-Spec,2
FileType,User Parameters Data File
Made-by,YASKAWA SigmaWin+ Ver.7
DateTime,12/23/2020 11:42:01 AM
SERVO-TYPE,SGD7S-1R6A00A002
SERVO-ID,112
SERVO-YMOD,0
SERVO-SPEC,00
SERVO-SOFT,47
SERVO-CAPACITY,200
SerialNo,1A2036500620098
BTOFlag,1
BTO-ID,
IS-SUPPORTED,1
IS-EDITED,0
MachineName,
OP-TYPE,
OP-ID,65533
OP-YMOD,65535
OP-SOFT,65535
OP1-TYPE,
OP1-TYPEID,0
OP1-ID,65533
OP1-YMOD,65535
OP1-YMODTYPE,65535
OP1-SOFT,65535
OP2-TYPE,
OP2-TYPEID,0
OP2-ID,65533
OP2-YMOD,65535
OP2-YMODTYPE,65535
OP2-SOFT,65535
OP3-TYPE,
OP3-TYPEID,0
OP3-ID,65533
OP3-YMOD,65535
OP3-YMODTYPE,65535
OP3-SOFT,65535
ACCESS-LEVEL,1
SpecVersion,65535
AXIS-NUM,1
MOTOR-TYPE,SGM7J-02AFD21
MOTOR-ID,173
ENCODER-ID,24
ENCODER-SOFT,3
ServoControlType,512
CompatibleMapNum,6
CompatibleMap,0,3,3,6,6,10
CommentCnt,0
Comment,
ServoNameComment,Picker Theta
UserPrmCnt,198
UserPrm,000,17,2,1
UserPrm,001,0,2,0
UserPrm,002,0,2,0
UserPrm,006,2,2,0
UserPrm,007,0,2,0
UserPrm,008,0,2,0
UserPrm,009,16,2,0
UserPrm,00A,1,2,0
UserPrm,00B,256,2,1
UserPrm,00C,0,2,0
UserPrm,00D,0,2,0
UserPrm,00E,0,2,0
UserPrm,00F,0,2,0
UserPrm,010,1,2,0
UserPrm,021,0,2,0
UserPrm,040,0,2,0
UserPrm,080,0,2,0
UserPrm,081,0,2,0
UserPrm,100,400,2,0
UserPrm,101,2000,2,0
UserPrm,102,400,2,0
UserPrm,103,100,2,0
UserPrm,104,400,2,0
UserPrm,105,2000,2,0
UserPrm,106,400,2,0
UserPrm,109,0,2,0
UserPrm,10A,0,2,0
UserPrm,10B,0,2,0
UserPrm,10C,200,2,0
UserPrm,10D,0,2,0
UserPrm,10E,0,2,0
UserPrm,10F,0,2,0
UserPrm,11F,0,2,0
UserPrm,121,100,2,0
UserPrm,122,100,2,0
UserPrm,123,0,2,0
UserPrm,124,0,2,0
UserPrm,125,100,2,0
UserPrm,131,0,2,0
UserPrm,132,0,2,0
UserPrm,135,0,2,0
UserPrm,136,0,2,0
UserPrm,139,0,2,0
UserPrm,13D,2000,2,0
UserPrm,140,256,2,0
UserPrm,141,500,2,0
UserPrm,142,1000,2,0
UserPrm,143,1000,2,0
UserPrm,144,1000,2,0
UserPrm,145,500,2,0
UserPrm,146,700,2,0
UserPrm,147,1000,2,0
UserPrm,148,500,2,0
UserPrm,149,1000,2,0
UserPrm,14A,800,2,0
UserPrm,14B,100,2,0
UserPrm,14F,33,2,0
UserPrm,160,16,2,0
UserPrm,161,1000,2,0
UserPrm,162,100,2,0
UserPrm,163,0,2,0
UserPrm,164,0,2,0
UserPrm,165,0,2,0
UserPrm,166,0,2,0
UserPrm,170,5121,2,0
UserPrm,200,1,2,1
UserPrm,205,65535,2,0
UserPrm,207,0,2,0
UserPrm,20A,32768,4,0
UserPrm,20E,16777216,4,1
UserPrm,210,20000,4,1
UserPrm,212,5000,4,1
UserPrm,216,0,2,0
UserPrm,217,0,2,0
UserPrm,218,1,2,0
UserPrm,22A,0,2,0
UserPrm,240,0,2,0
UserPrm,281,20,2,0
UserPrm,300,600,2,0
UserPrm,301,100,2,0
UserPrm,302,200,2,0
UserPrm,303,300,2,0
UserPrm,304,200,2,1
UserPrm,305,0,2,0
UserPrm,306,0,2,0
UserPrm,307,40,2,0
UserPrm,308,0,2,0
UserPrm,30A,0,2,0
UserPrm,30C,0,2,0
UserPrm,310,0,2,0
UserPrm,311,100,2,0
UserPrm,312,50,2,0
UserPrm,316,10000,2,0
UserPrm,324,300,2,0
UserPrm,400,30,2,0
UserPrm,401,100,2,0
UserPrm,402,800,2,0
UserPrm,403,800,2,0
UserPrm,404,100,2,0
UserPrm,405,100,2,0
UserPrm,406,800,2,0
UserPrm,407,10000,2,0
UserPrm,408,0,2,0
UserPrm,409,5000,2,0
UserPrm,40A,70,2,0
UserPrm,40B,0,2,0
UserPrm,40C,5000,2,0
UserPrm,40D,70,2,0
UserPrm,40E,0,2,0
UserPrm,40F,5000,2,0
UserPrm,410,50,2,0
UserPrm,412,100,2,0
UserPrm,415,0,2,0
UserPrm,416,0,2,0
UserPrm,417,5000,2,0
UserPrm,418,70,2,0
UserPrm,419,0,2,0
UserPrm,41A,5000,2,0
UserPrm,41B,70,2,0
UserPrm,41C,0,2,0
UserPrm,41D,5000,2,0
UserPrm,41E,70,2,0
UserPrm,41F,0,2,0
UserPrm,423,0,2,0
UserPrm,424,50,2,0
UserPrm,425,100,2,0
UserPrm,426,0,2,0
UserPrm,427,0,2,0
UserPrm,456,15,2,0
UserPrm,460,257,2,0
UserPrm,475,0,2,0
UserPrm,476,0,2,0
UserPrm,481,400,2,0
UserPrm,482,3000,2,0
UserPrm,486,25,2,0
UserPrm,487,0,2,0
UserPrm,488,100,2,0
UserPrm,490,100,2,0
UserPrm,495,100,2,0
UserPrm,498,10,2,0
UserPrm,501,10,2,0
UserPrm,502,20,2,0
UserPrm,503,10,2,0
UserPrm,506,0,2,0
UserPrm,507,100,2,0
UserPrm,508,50,2,0
UserPrm,509,20,2,0
UserPrm,50A,8448,2,0
UserPrm,50B,25923,2,0
UserPrm,50C,34952,2,0
UserPrm,50D,34952,2,0
UserPrm,50E,12817,2,0
UserPrm,50F,0,2,0
UserPrm,510,0,2,0
UserPrm,512,0,2,0
UserPrm,513,0,2,0
UserPrm,514,0,2,0
UserPrm,515,34952,2,0
UserPrm,516,34952,2,0
UserPrm,517,1620,2,0
UserPrm,518,0,2,0
UserPrm,519,34952,2,0
UserPrm,51B,1000,4,0
UserPrm,51E,100,2,0
UserPrm,520,5242880,4,0
UserPrm,522,7,4,0
UserPrm,524,1073741824,4,0
UserPrm,526,5242880,4,0
UserPrm,528,100,2,0
UserPrm,529,10000,2,0
UserPrm,52A,20,2,0
UserPrm,52B,20,2,0
UserPrm,52C,100,2,0
UserPrm,52F,4095,2,0
UserPrm,530,0,2,0
UserPrm,531,32768,4,0
UserPrm,533,500,2,0
UserPrm,534,100,2,0
UserPrm,535,100,2,0
UserPrm,536,1,2,0
UserPrm,550,0,2,0
UserPrm,551,0,2,0
UserPrm,552,100,2,0
UserPrm,553,100,2,0
UserPrm,55A,1,2,0
UserPrm,560,400,2,0
UserPrm,561,100,2,0
UserPrm,600,0,2,0
UserPrm,601,0,2,0
UserPrm,603,0,2,0
UserPrm,604,0,2,0
UserPrm,621,0,2,0
UserPrm,622,10000,2,0
UserPrm,623,10000,2,0
UserPrm,624,10,2,0
UserPrm,625,100,2,0
UserPrm,626,100,4,0
UserPrm,628,10,2,0
Custom
CustomGroupNum,1
Gp1_Begin
GroupName,
Num,0
Gp1_End

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
namespace Project
{
public partial class FMain
{
}
}

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using UIControl;
using AR;
namespace Project
{
public partial class FMain
{
void _BUTTON_RESET()
{
//Common processing when RESET button is pressed
DIO.SetBuzzer(false); //buzzer off
if (PUB.popup.Visible)
PUB.popup.needClose = true;
if (
hmi1.Scean == HMI.eScean.xmove)
hmi1.Scean = UIControl.HMI.eScean.Nomal;
PUB.flag.set(eVarBool.FG_KEYENCE_OFFF, false, "USER");
PUB.flag.set(eVarBool.FG_KEYENCE_OFFR, false, "USER");
//Remove popup message if it's a removable message.
if (hmi1.HasPopupMenu && hmi1.PopupMenuRequireInput == false)
hmi1.DelMenu();
//Alarm clear work (only when motion has error)
if (PUB.mot.IsInit && PUB.mot.HasServoAlarm)
{
PUB.mot.SetAlarmClearOn();
System.Threading.Thread.Sleep(200);
PUB.mot.SetAlarmClearOff();
}
//If there's no material and sensor doesn't respond but vacuum is on, turn it off
if (DIO.isVacOKL() == 0 && PUB.flag.get(eVarBool.FG_PK_ITEMON) == false && DIO.GetIOOutput(eDOName.PICK_VAC1) == false)
DIO.SetPickerVac(false, true);
//This reset is meaningful in stop and error mode.
if (PUB.sm.Step == eSMStep.RUN)
{
PUB.log.Add("[RESET] button does not work during operation");
}
else if (PUB.sm.Step == eSMStep.PAUSE)
{
//Switch to start waiting state (execution starts when start key is pressed in waiting state)
PUB.sm.SetNewStep(eSMStep.WAITSTART);
PUB.log.AddAT("Reset Clear System Resume & Pause ON");
}
else if (PUB.sm.Step == eSMStep.EMERGENCY)
{
PUB.popup.setMessage("EMERGENCY RESET\n" +
"[Emergency Stop] state requires [System Initialization]\n" +
"Execute [Initialize] from the top menu");
PUB.log.Add("RESET button caused transition from EMG situation to IDLE");
PUB.sm.SetNewStep(eSMStep.IDLE);
}
else if (PUB.sm.Step == eSMStep.ERROR)
{
PUB.log.Add("RESET button caused transition from ERR situation to IDLE");
PUB.sm.SetNewStep(eSMStep.IDLE);
}
else if (PUB.sm.Step == eSMStep.WAITSTART)
{
//No processing even when waiting for start
//Pub.log.Add("[RESET] button does not work while waiting for start button");
}
else if (PUB.sm.Step == eSMStep.IDLE)
{
//Pub.log.Add("[RESET] button does not work during standby");
}
else
{
//Pub.log.AddE("REST key button input from undefined state - switching to standby state");
PUB.sm.SetNewStep(eSMStep.IDLE);
}
}
}
}

View File

@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using AR;
namespace Project
{
public partial class FMain
{
void _BUTTON_START()
{
if (PUB.sm.Step == eSMStep.RUN)
{
//아무것도 하지 않는다
PUB.log.Add("START button is not available during operation");
}
else if (PUB.sm.Step == eSMStep.IDLE) //일반대기상태
{
if (DIO.isVacOKL() > 0)
{
DIO.SetBuzzer(true);
PUB.popup.setMessage("PICKER ITEM DETECT\nItem detected in PICKER\nPress [Cancel Work] to DROP item and remove it.");
return;
}
else if (DIO.getCartSize(1) == eCartSize.None)
{
DIO.SetBuzzer(true);
PUB.popup.setMessage("Cart is not installed in loader");
return;
}
else if (DIO.GetIOInput(eDIName.PORTC_LIM_DN) == true && DIO.GetIOInput(eDIName.PORTC_DET_UP) == true)
{
//하단리밋과, 자재감지가 동시에 들어오면 overload 이다
DIO.SetBuzzer(true);
PUB.popup.setMessage("Too many reels are loaded in the loader\n" +
"Bottom limit sensor and top reel detection sensor are both active");
return;
}
//else if (Util_DO.getCartSize(0) == eCartSize.None && Util_DO.getCartSize(2) == eCartSize.None)
//{
// Util_DO.SetBuzzer(true);
// Pub.popup.setMessage("언로더에 카트가 장착되지 않았습니다");
// return;
//}
Func_start_job_select();
}
else if (PUB.sm.Step == eSMStep.WAITSTART) //시작대기상태
{
DIO.SetRoomLight(true);
//새로시작하면 포트 얼라인을 해제 해준다
PUB.flag.set(eVarBool.FG_RDY_PORT_PL, false, "SW_START");
PUB.flag.set(eVarBool.FG_RDY_PORT_PC, false, "SW_START");
PUB.flag.set(eVarBool.FG_RDY_PORT_PR, false, "SW_START");
VAR.BOOL[eVarBool.FG_WAIT_INFOSELECTCLOSE] = false;
//언로더 체크작업은 항상 다시 시작한다
if (PUB.Result.UnloaderSeq > 1) PUB.Result.UnloaderSeq = 1;
//팝업메세지가 사라지도록 한다
PUB.popup.needClose = true;
PUB.sm.SetNewStep(eSMStep.RUN);
PUB.log.Add("[User pause] released => Work continues");
}
else
{
//string msg = "SYSTEM {0}\n[RESET] 버튼을 누른 후 다시 시도하세요";
//msg = string.Format(msg, PUB.sm.Step);
//PUB.popup.setMessage(msg);
PUB.log.AddE($"Press [RESET] button and try again");
}
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using AR;
namespace Project
{
public partial class FMain
{
void _BUTTON_STOP()
{
//매거진 투입모터 멈춤
if (DIO.GetIOOutput(eDOName.PORTL_MOT_RUN)) DIO.SetPortMotor(0, eMotDir.CW, false, "Button Stop");
if (DIO.GetIOOutput(eDOName.PORTC_MOT_RUN)) DIO.SetPortMotor(1, eMotDir.CW, false, "Button Stop");
if (DIO.GetIOOutput(eDOName.PORTR_MOT_RUN)) DIO.SetPortMotor(2, eMotDir.CW, false, "Button Stop");
//자재가 없고, 센서도 반응안하는데. 진공이 되어잇으면 off한다
if (DIO.isVacOKL() == 0 && PUB.flag.get(eVarBool.FG_PK_ITEMON) == false && DIO.GetIOOutput(eDOName.PICK_VAC1) == true)
DIO.SetPickerVac(false, true);
//조명켜기
if (AR.SETTING.Data.Disable_RoomLight == false)
DIO.SetRoomLight(true);
//컨베이어 멈춘다 230502
DIO.SetOutput(eDOName.LEFT_CONV, false);
DIO.SetOutput(eDOName.RIGHT_CONV, false);
//모든 모터도 멈춘다
if (PUB.mot.HasMoving) PUB.mot.MoveStop("Stop Button");
if (PUB.sm.Step == eSMStep.RUN)
{
//일시중지상태로 전환한다
PUB.Result.SetResultMessage(eResult.OPERATION, eECode.USER_STOP, eNextStep.PAUSE);
PUB.log.Add("[User pause]");
}
else if (PUB.sm.Step == eSMStep.HOME_FULL) //홈진행중에는 대기상태로 전환
{
PUB.sm.SetNewStep(eSMStep.IDLE);
}
//로그 기록
PUB.LogFlush();
}
}
}

View File

@@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
namespace Project.Class
{
public class CHistoryJOB : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
List<JobData> _items;
public CHistoryJOB()
{
_items = new List<JobData>();
}
public void Clear()
{
lock (_items)
{
_items.Clear();
}
OnPropertyChanged("Clear");
}
public int Count
{
get
{
lock (_items)
{
return _items.Count;
}
}
}
public void SetItems(List<JobData> value)
{
lock (_items)
{
this._items = value;
}
OnPropertyChanged("REFRESH");
}
public List<JobData> Items { get { return _items; } }
public void Add(JobData data)
{
lock (_items)
{
data.No = this._items.Count + 1;
_items.Add(data);
}
OnPropertyChanged("Add:" + data.guid);
}
public void Remove(JobData data)
{
lock (_items)
{
_items.Remove(data);
}
OnPropertyChanged("Remove:" + data.guid);
}
public void Remove(string guid)
{
lock (_items)
{
var data = Get(guid);
_items.Remove(data);
}
OnPropertyChanged("Remove:" + guid);
}
public JobData Get(string guid)
{
lock (_items)
{
return _items.Where(t => t.guid == guid).FirstOrDefault();
}
}
public void Set(JobData data)
{
var item = Get(data.guid);
if (item == null) throw new Exception("No data guid:" + data.guid.ToString());
else
{
//item.No = data.No;
//item.JobStart = data.JobStart;
//item.JobEnd = data.JobEnd;
//item.VisionData = data.VisionData;
//item.error = data.error;
//item.Message = data.Message;
OnPropertyChanged("Set:" + data.guid);
}
}
public void RaiseSetEvent(string guid)
{
OnPropertyChanged("Set:" + guid);
}
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(name));
}
}
//[Serializable]
//public class JobData
//{
// //고유식별자
// public string guid { get; private set; }
// //비젼처리값
// public Class.VisionData VisionData { get; set; }
// //언로더포트(L/R)
// public string PortPos { get; set; }
// //프린트위치(U/LO)
// public string PrintPos { get; set; }
// //작업시작시간
// public DateTime JobStart { get; set; }
// //작업종료시간
// public DateTime JobEnd { get; set; }
// /// <summary>
// /// 이전 출고되는 시점과의 시간차 값
// /// </summary>
// public double TackTime { get { return (JobEnd - JobStart).TotalSeconds; } }
// //작업순서
// public int No { get; set; }
// //오류상태
// public eJobResult error { get; set; }
// //메세지
// public string message { get; set; }
// public TimeSpan JobRun
// {
// get
// {
// if (JobEnd.Year == 1982) return new TimeSpan(0);
// else return this.JobEnd - this.JobStart;
// }
// }
// public JobData()
// {
// this.No = 0;
// PortPos = string.Empty;
// PrintPos = string.Empty;
// guid = Guid.NewGuid().ToString();
// VisionData = new VisionData();
// this.JobStart = new DateTime(1982, 11, 23); // DateTime.Parse("1982-11-23");
// this.JobEnd = new DateTime(1982, 11, 23); // DateTime.Parse("1982-11-23");
// error = eJobResult.None;
// message = string.Empty;
// }
//}
}

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
namespace Project.Class
{
public class CHistorySIDRef : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Boolean JobSIDRecvError
{
get
{
//아이템이있어야 정상이다
if (_items == null || _items.Count < 1) return true;
else if (JobSIDRecvTime.Year == 1982) return true;
else return false;
}
}
public DateTime JobSIDRecvTime { get; set; }
public string JobSIDRecvMessage { get; set; }
List<SIDDataRef> _items;
public CHistorySIDRef()
{
Clear();
}
public void SetItems(List<SIDDataRef> value)
{
this._items = value;
OnPropertyChanged("REFRESH");
}
public List<SIDDataRef> Items { get { return _items; } }
public int Count
{
get
{
return _items.Count;
}
}
public SIDDataRef Get(string sid_)
{
return _items.Where(t => t.sid == sid_).FirstOrDefault();
}
public void Set(SIDDataRef data)
{
var item = Get(data.sid);
if (item == null) throw new Exception("No data sid:" + data.sid.ToString());
else
{
item.kpc = data.kpc;
item.unit = data.unit;
OnPropertyChanged("Set:" + data.sid);
}
}
public void Set(string sid, int kpc, string unit)
{
var item = Get(sid);
if (item == null)
{
Add(sid, kpc, unit); //없다면 추가해준다
}
else
{
item.kpc = kpc;
item.unit = unit;
OnPropertyChanged("Set:" + sid);
}
}
public void Add(SIDDataRef data)
{
_items.Add(data);
OnPropertyChanged("Add:" + data.sid);
}
public void Add(string sid, int kpc_, string unit)
{
if (string.IsNullOrEmpty(sid))
{
PUB.log.AddAT("SID addition failed - SID value not entered");
return;
}
//if (JobSidList.ContainsKey(sid) == false)
_items.Add(new SIDDataRef(sid, kpc_, unit));
OnPropertyChanged("Add:" + sid);
//else
//{
//이미 데이터가 있다. 중복이므로 누적한다
//JobSidList.TryGetValue()
//}
}
public void Clear()
{
//JobSIDRecvError = false;
JobSIDRecvMessage = string.Empty;
JobSIDRecvTime = DateTime.Parse("1982-11-23");
if (this._items == null) this._items = new List<SIDDataRef>();
else this._items.Clear();
OnPropertyChanged("Clear");
}
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(name));
}
}
[Serializable]
public class SIDDataRef
{
public string guid { get; set; }
public string sid { get; set; }
public string unit { get; set; }
public int kpc { get; set; }
public SIDDataRef(string sid_, int kpc_, string unit_)
{
guid = Guid.NewGuid().ToString();
sid = sid_;
unit = unit_;
kpc = kpc_;
}
public SIDDataRef() : this(string.Empty, 0, string.Empty) { }
}
}

View File

@@ -0,0 +1,546 @@
using AR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Project
{
public class CResult
{
public enum eInspectResult
{
NG = 0,
OK,
ERROR,
NOTSET = 9,
}
public UInt64 OptionValue = 0;
public UInt64 OptionValueData = 0;
public List<Class.RegexPattern> BCDPattern;
public List<Class.RegexPattern> BCDIgnorePattern;
public object BCDPatternLock = new object();
public DateTime ResetButtonDownTime = DateTime.Now;
public Boolean ClearAllSID = false;
public Class.CHistorySIDRef SIDReference; //SIDLIST받은 내역
public List<UIControl.CItem> OUTHistory; //출고포트 처리내역
public DataSet1.SIDHistoryDataTable SIDHistory; //sID별 rid 전체 목록 차수별로만 저장된다
public DataSet1.K4EE_Component_Reel_SID_ConvertDataTable DTSidConvert;
public List<string> DTSidConvertEmptyList;
public List<string> DTSidConvertMultiList;
public DSList dsList;
public ModelInfoM mModel; //모션 모델
public ModelInfoV vModel; //작업 모델
/// <summary>
/// 아이템의 정보가 담겨있다 (0:왼쪽,1:비젼,2:오른쪽)
/// </summary>
public Class.JobData ItemDataL = new Class.JobData(0);
public Class.JobData ItemDataC = new Class.JobData(1);
public Class.JobData ItemDataR = new Class.JobData(2);
public Guid guid = new Guid();
public string JobType2 = string.Empty;
public Boolean JobFirst
{
get
{
return VAR.I32[(int)eVarInt32.PickOnCount] == 0;
}
}
public Boolean DryRun
{
get
{
if (string.IsNullOrEmpty(JobType2)) return false;
else return JobType2.ToUpper() == "DRY";
}
}
public int OverLoadCountF { get; set; }
public int OverLoadCountR { get; set; }
public UIControl.CItem UnloaderItem = null;
public DateTime LastExtInputTime = DateTime.Parse("1982-11-23");
public DateTime LastOutTime = DateTime.Parse("1982-11-23");
public Single[] PortAlignWaitSec = new float[] { 0, 0, 0, 0 };
public long[] PortAlignTime = new long[] { 0, 0, 0, 0 };
public byte UnloaderSeq = 0;
public DateTime UnloaderSeqTime;
public DateTime UnloaderSendtime = DateTime.Parse("1982-11-23");
/// <summary>
/// 로딩에 사용하는 포트번호 (자동 판단됨)
/// </summary>
public int LoadPortIndex = -1;
/// <summary>
/// 로딩시에 사용한 포트의 번호(이 값으로 수량기록 위치를 결정)
/// </summary>
public int LoadPickIndex = -1;
/// <summary>
/// 최종 할당된 언로딩 포트번호(1~8)
/// </summary>
public int UnloadPortNo = -1;
public byte LiveViewseq = 0;
public string AcceptBcd = string.Empty;
public DateTime AcceptBcdTime = DateTime.Now;
public string AcceptSid = string.Empty;
//작업정보
public eInspectResult Result; //작업결과가 저장됨
public eResult ResultCode;
public eECode ResultErrorCode;
public string ResultMessage;
public string LastSIDFrom = string.Empty;//101 = string.Empty;
public string LastSIDTo = string.Empty; // 103 = string.Empty;
//public string LastSID103_2 = string.Empty;
public string LastVName = string.Empty;
public int LastSIDCnt = 0;
public Dictionary<string, string> PrintPostionList = null;
//작업정보(시간)
public DateTime JobStartTime = DateTime.Parse("1982-11-23");
public DateTime JobEndTime = DateTime.Parse("1982-11-23");
public TimeSpan JobRunTime()
{
if (JobStartTime.Year == 1982) return new TimeSpan(0);
if (JobEndTime.Year == 1982) return DateTime.Now - JobStartTime;
else return JobEndTime - JobStartTime;
}
/// <summary>
/// RUN -> Pause(Wait Start)모드 전환시 저장할 모터의 위치값
/// 조그모드등으로 좌표를 옴길때의 기준 좌표
/// 이 좌표값에서 현재 모션값에 변화가 있으면 프로그램에서는 오류로 처리하게 됨
/// </summary>
public double[] PreventMotionPosition = new double[8];
#region "SetResultMessage"
public void SetResultMessage(eResult code, eECode err, eNextStep systempause, params object[] args)
{
var rltMsg = PUB.GetResultCodeMessage(code);
var codeMSg = $"[E{(int)err}] ";// + Util.GetResultCodeMessage(code);
if (err == eECode.MESSAGE_ERROR)
{
codeMSg = $"[{rltMsg} ERROR MESSAGE]\n";
}
else if (err == eECode.MESSAGE_INFO)
{
codeMSg = $"[{rltMsg} INFORMATION]\n";
}
var erMsg = PUB.GetErrorMessage(err, args);
var msg = codeMSg + erMsg;
this.ResultCode = code;
this.ResultErrorCode = err;
this.ResultMessage = msg;
if (systempause == eNextStep.PAUSENOMESAGE) this.ResultMessage = string.Empty; //210129
PUB.log.AddE(msg);
if (systempause == eNextStep.PAUSE) PUB.sm.SetNewStep(eSMStep.PAUSE);
else if (systempause == eNextStep.PAUSENOMESAGE) PUB.sm.SetNewStep(eSMStep.PAUSE);
else if (systempause == eNextStep.ERROR) PUB.sm.SetNewStep(eSMStep.ERROR);
}
public void SetResultTimeOutMessage(eDOName pinName, Boolean checkState, eNextStep systemPause)
{
var pindef = DIO.Pin[pinName];
if (checkState) SetResultMessage(eResult.SENSOR, eECode.DOON, systemPause, pindef.terminalno, pindef.name);
else SetResultMessage(eResult.SENSOR, eECode.DOOFF, systemPause, pindef.terminalno, pindef.name);
}
public void SetResultTimeOutMessage(eDIName pinName, Boolean checkState, eNextStep systemPause)
{
var pindef = DIO.Pin[pinName];
if (checkState) SetResultMessage(eResult.SENSOR, eECode.DION, systemPause, pindef.terminalno, pindef.name);
else SetResultMessage(eResult.SENSOR, eECode.DIOFF, systemPause, pindef.terminalno, pindef.name);
}
public void SetResultTimeOutMessage(eAxis motAxis, eECode ecode, eNextStep systemPause, string source, double targetpos, string message)
{
SetResultMessage(eResult.TIMEOUT, ecode, systemPause, motAxis, source, targetpos, message);
}
public void SetResultTimeOutMessage(eECode ecode, eNextStep systemPause, params object[] args)
{
SetResultMessage(eResult.TIMEOUT, ecode, systemPause, args);
}
#endregion
public DateTime[] diCheckTime = new DateTime[256];
public DateTime[] doCheckTime = new DateTime[256];
public Boolean isError { get; set; }
public int retry = 0;
public DateTime retryTime;
public DateTime[] WaitForVar = new DateTime[255];
public int ABCount = 0;
public bool AutoReelOut = false;
public CResult()
{
mModel = new ModelInfoM();
vModel = new ModelInfoV();
SIDReference = new Class.CHistorySIDRef();
SIDHistory = new DataSet1.SIDHistoryDataTable();
BCDPattern = new List<Class.RegexPattern>();
OUTHistory = new List<UIControl.CItem>();
this.Clear("Result ctor");
dsList = new DSList();
LoadListDB();
//230509
if(DTSidConvert != null) DTSidConvert.Dispose();
DTSidConvert = new DataSet1.K4EE_Component_Reel_SID_ConvertDataTable();
DTSidConvertEmptyList = new List<string>();
DTSidConvertMultiList = new List<string>();
}
public void SaveListDB()
{
var finame = System.IO.Path.Combine(UTIL.CurrentPath, "Data", "SavaedList.xml");
var fi = new System.IO.FileInfo(finame);
if (fi.Directory.Exists == false) fi.Directory.Create();
this.dsList.WriteXml(fi.FullName);
PUB.log.Add("Pre-list DB saved " + fi.FullName);
}
public void LoadListDB()
{
var finame = System.IO.Path.Combine(UTIL.CurrentPath, "Data", "SavaedList.xml");
var fi = new System.IO.FileInfo(finame);
if (fi.Directory.Exists == false) fi.Directory.Create();
if (fi.Exists)
{
this.dsList.ReadXml(fi.FullName);
PUB.log.Add("Pre-list DB loaded " + fi.FullName);
}
}
///// <summary>
///// 입력한 sid 가 원본에 존재하지 않으면 -1을 존재하면 입력된 수량을 반환합니다
///// </summary>
///// <param name="sid"></param>
///// <returns></returns>
//public int ExistSIDReferenceCheck(string sid)
//{
// var dr = PUB.Result.SIDReference.Items.Where(t => t.sid.EndsWith(sid)).FirstOrDefault();
// if (dr == null) return -1;
// else return dr.kpc;
//}
//public void ClearHistory()
//{
// //this.JObHistory.Clear();
// this.SIDReference.Clear();
// PUB.log.AddI("Clear History");
//}
public void ClearOutPort()
{
OUTHistory.Clear();
}
public void Clear(string Reason)
{
this.guid = Guid.NewGuid();
//프린트위치를 별도로 저장하고 있는다(나중에 추가 활용한다) 231005
if (PrintPostionList == null)
PrintPostionList = new Dictionary<string, string>();
else
PrintPostionList.Clear();
PUB.log.Add("Print Positoin Clear");
ItemDataL.Clear(Reason);
ItemDataC.Clear(Reason);
ItemDataR.Clear(Reason);
OverLoadCountF = 0;
OverLoadCountR = 0;
ClearOutPort();
LoadPortIndex = -1;
if (PUB.sm != null)
PUB.sm.seq.ClearTime();
isError = false;
ABCount = 0;
///기다림용 변수모듬
for (int i = 0; i < WaitForVar.Length; i++)
WaitForVar[i] = DateTime.Parse("1982-11-23");
//조그모드시 모션이동 감지용 저장 변수
for (int i = 0; i < 6; i++)
PreventMotionPosition[i] = 0.0;
//JobStartTime = DateTime.Parse("1982-11-23");
//JobEndTime = DateTime.Parse("1982-11-23");
//LastOutTime = DateTime.Parse("1982-11-23");
Result = eInspectResult.NOTSET;
ResultCode = eResult.NOERROR;
ResultMessage = string.Empty;
//시간정보값을 초기화함
for (int i = 0; i < 2; i++)
ClearTime(i);
PUB.log.Add("Result data initialized");
}
public void ClearTime(int shutIdx)
{
//JobStartTime = DateTime.Parse("1982-11-23");
//JobEndTime = DateTime.Parse("1982-11-23");
Result = eInspectResult.NOTSET;
ResultCode = eResult.NOERROR;
ResultMessage = string.Empty;
PUB.log.Add("Result(Clear Time)");
}
public Boolean isSetmModel
{
get
{
if (PUB.Result.mModel == null || PUB.Result.mModel.idx == -1 || PUB.Result.mModel.Title.isEmpty())
return false;
else return true;
}
}
public Boolean isSetvModel
{
get
{
if (PUB.Result.vModel == null || PUB.Result.vModel.idx == -1 || PUB.Result.vModel.Title.isEmpty())
return false;
else return true;
}
}
//public string getErrorMessage(eResult rlt, eECode err, params object[] args)
//{
// switch (err)
// {
// case eECode.RIDDUPL:
// return string.Format(
// "좌측 언로더에 사용되었던 REEL ID 입니다\n" +
// "바코드 오류 가능성이 있습니다\n" +
// "좌측 릴의 바코드를 확인하시기 바랍니다\n" +
// "작업을 계속할 수 없습니다. 취소 후 다시 시도하세요\n{0}", args);
// case eECode.RIDDUPR:
// return string.Format(
// "우측 언로더에 사용되었던 REEL ID 입니다\n" +
// "바코드 오류 가능성이 있습니다\n" +
// "우측 릴의 바코드를 확인하시기 바랍니다\n" +
// "작업을 계속할 수 없습니다. 취소 후 다시 시도하세요\n{0}", args);
// case eECode.BARCODEVALIDERR:
// return string.Format("바코드 데이터 검증 실패\n" +
// "인쇄전 데이터와 인쇄후 데이터가 일치하지 않습니다\n" +
// "ID(O) : {1}\n" +
// "ID(N) : {2}\n" +
// "SID : {5}->{6}\n" +
// "QTY : {3}->{4}\n" +
// "DATE : {7}->{8}\n" +
// "Index : {0}", args);
// case eECode.MOTX_SAFETY:
// return string.Format("PICKER-X 축이 안전위치에 없습니다\n1. 조그를 이용하여 중앙으로 이동 합니다\n2.홈 작업을 다시 실행합니다", args);
// case eECode.NOERROR:
// return string.Format("오류가 없습니다", args);
// case eECode.PORTOVERLOAD:
// return string.Format("PORT OVERLOAD\n위치 : {0}\n" +
// "너무 많은 양이 적재 되었습니다\n" + "상단 LIMIT 센서에 걸리지 않게 적재하세요", args);
// case eECode.EMERGENCY:
// return string.Format("비상정지 버튼을 확인하세요\n" +
// "버튼 : F{0}\n" +
// "메인전원이 OFF 된 경우에도 이 메세지가 표시 됩니다\n" +
// "메인전원은 모니터 하단 AIR버튼 좌측에 있습니다"
// , DIO.GetIOInput(eDIName.BUT_EMGF));
// case eECode.NOMODELM:
// return "모션모델이 선택되지 않았습니다\n" +
// "상단 메뉴 [모션모델]에서 사용할 모델을 선택하세요";
// case eECode.NOMODELV:
// return "작업모델이 선택되지 않았습니다\n" +
// "상단 메뉴 [작업모델]에서 사용할 모델을 선택하세요";
// case eECode.CARTERROR:
// return string.Format("언로더 카트가 없거나 크기 정보가 일치하지 않습니다\n좌측:{0}, 로더:{1}, 우측:{2}", args);
// case eECode.CARTL:
// return string.Format("왼쪽(UNLOAD) 포트에 카트가 감지되지 않습니다\n카트를 장착하세요\n카트크기 : {0}, 릴크기:{1}", args);
// case eECode.CARTC:
// return string.Format("중앙(LOAD) 포트에 카트가 감지되지 않습니다\n카트를 장착하세요\n카트크기 : {0}, 릴크기:{1}", args);
// case eECode.CARTR:
// return string.Format("오른쪽(UNLOAD) 포트에 카트가 감지되지 않습니다\n카트를 장착하세요\n카트크기 : {0}, 릴크기:{1}", args);
// case eECode.CARTLMATCH:
// return string.Format("왼쪽(UNLOAD) 카트와 피커의 릴 크기가 일치하지 않습니다\n카트크기를 확인 하세요\n카트크기 : {0}, 릴크기:{1}", args);
// case eECode.CARTCMATCH:
// return string.Format("중앙(LOAD) 카트와 피커의 릴 크기가 일치하지 않습니다\n카트크기를 확인 하세요\n카트크기 : {0}, 릴크기:{1}", args);
// case eECode.CARTRMATCH:
// return string.Format("오른쪽(UNLOAD) 카트와 피커의 릴 크기가 일치하지 않습니다\n카트크기를 확인 하세요\n카트크기 : {0}, 릴크기:{1}", args);
// case eECode.NOREELSIZE:
// return string.Format("왼쪽포트에 놓을 릴의 크기정보가 없습니다\n프로그램 오류입니다\n개발자에게 해당 메세지를 전달하세요\n" +
// "장치 초기화를 진행 한 후 다시 시도하세요");
// case eECode.VISION_NOCONN:
// return string.Format("카메라({0}) 연결 안됨", args);
// case eECode.INCOMPLETE_LOADERDATA:
// return string.Format("로더 바코드 필수값을 읽지 못했습니다", args);
// case eECode.CAM_NOBARCODEU:
// return string.Format("언로더({0}) 바코드를 읽지 못했습니다", args);
// case eECode.HOME_TIMEOUT:
// return string.Format("홈 진행이 완료되지 않고 있습니다\n" +
// "오류가 발생했다면 '홈' 작업을 다시 진행하세요\n" +
// "대기시간 : {0}초", args);
// case eECode.DOORSAFTY:
// return string.Format("포트 안전센서가 감지 되었습니다\n" +
// "안전센서를 확인한 후 다시 시도하세요\n", args);
// case eECode.AIRNOOUT:
// return "AIR 공급이 차단 되어 있습니다.\n" +
// "전면의 AIR 버튼을 누르세요\n" +
// "공급이 되지 않으면 메인 전원 을 확인하세요\n" +
// "메인 전원은 AIR 버튼 좌측에 있습니다" +
// "메인 전원 공급 실패시 장비 후면의 차단기를 확인하세요";
// case eECode.DOOFF:
// var pinoOf = (eDOName)args[0];
// return string.Format("출력이 OFF 되지 않았습니다.\n" +
// "포트설명 : {0}\n" +
// "포트번호 : {1} ({2})", DIO.getPinDescription(pinoOf), (int)pinoOf, Enum.GetName(typeof(eDOPin), pinoOf));
// case eECode.DOON:
// var pinoOn = (eDOName)args[0];
// return string.Format("출력이 ON 되지 않았습니다.\n" +
// "포트설명 : {0}\n" +
// "포트번호 : {1} ({2})", DIO.getPinDescription(pinoOn), (int)pinoOn, Enum.GetName(typeof(eDOPin), pinoOn));
// case eECode.DIOFF:
// var piniOf = (eDIName)args[0];
// return string.Format("입력이 OFF 되지 않았습니다.\n" +
// "포트설명 : {0}\n" +
// "포트번호 : {1} ({2})", DIO.getPinDescription(piniOf), (int)piniOf, Enum.GetName(typeof(eDIPin), piniOf));
// case eECode.DION:
// var piniOn = (eDIName)args[0];
// return string.Format("입력이 ON 되지 않았습니다.\n" +
// "포트설명 : {0}\n" +
// "포트번호 : {1} ({2})", DIO.getPinDescription(piniOn), (int)piniOn, Enum.GetName(typeof(eDIPin), piniOn));
// case eECode.AZJINIT:
// return string.Format("DIO 혹은 모션카드가 초기화 되지 않았습니다.\n" +
// "DIO : {0}\n" +
// "MOTION : {1}\n" +
// "해당 카드는 본체 내부 PCI 슬롯에 장착 된 장비 입니다\n" +
// "EzConfig AXT 프로그램으로 카드 상태를 확인하세요",
// PUB.dio.IsInit, PUB.mot.IsInit);
// case eECode.MOT_HSET:
// var msg = "모션의 HOME 검색이 완료되지 않았습니다";
// for (int i = 0; i < 6; i++)
// {
// if (PUB.mot.IsUse(i) == false) continue;
// var axis = (eAxis)i;
// var stat = PUB.mot.IsHomeSet(i);
// if (stat == false) msg += string.Format("\n[{0}] {1} : {2}", i, axis, stat);
// }
// msg += "\n장치 초기화를 실행하세요";
// return msg;
// case eECode.MOT_SVOFF:
// var msgsv = "모션 중 SERVO-OFF 된 축이 있습니다";
// for (int i = 0; i < 6; i++)
// {
// if (PUB.mot.IsUse(i) == false) continue;
// var axis = (eAxis)i;
// var stat = PUB.mot.IsServOn(i);
// if (stat == false) msgsv += string.Format("\n[{0}] {1} : {2}", i, axis, stat);
// }
// msgsv += "\nRESET을 누른 후 '모션설정' 화면에서 확인합니다";
// return msgsv;
// case eECode.MOT_HSEARCH:
// return string.Format("모션의 홈 검색이 실패되었습니다\n" +
// "축 : {0}\n" +
// "메세지 : {1}", args);
// case eECode.MOT_CMD:
// var axisNo = (int)((eAxis)args[0]);
// var axisSrc = args[1].ToString();
// return string.Format("모션축 명령이 실패 되었습니다\n축 : {0}\n" +
// "현재위치 : {2}\n" +
// "명령위치 : {3}\n" +
// "소스 : {1}", axisNo, axisSrc, PUB.mot.GetActPos(axisNo), PUB.mot.GetActPos(axisNo));
// //case eECode.timeout_step:
// // return string.Format("스텝당 최대 실행 시간이 초과 되었습니다.\n" +
// // "스텝 : {0}\n" +
// // "최대동작시간 : " + COMM.SETTING.Data.Timeout_StepMaxTime.ToString(), args);
// case eECode.USER_STOP:
// return "'일시정지' 버튼 눌림\n" +
// "사용자에 의해 작동이 중지 되었습니다\n" +
// "'RESET' -> 'START'로 작업을 계속할 수 있습니다";
// case eECode.CAM_RIGHT:
// return "우측카메라가 사용가능한 상태가 아닙니다.\n" +
// "신규 실행시에는 초기화 완료까지 기다려 주세요";
// case eECode.CAM_LEFT:
// return "좌측카메라가 사용가능한 상태가 아닙니다.\n" +
// "신규 실행시에는 초기화 완료까지 기다려 주세요";
// default:
// return err.ToString();
// }
//}
//public string getResultCodeMessage(eResult rltCode)
//{
// //별도 메세지처리없이 그대로 노출한다
// return rltCode.ToString().ToUpper();
//}
}
}

View File

@@ -0,0 +1,459 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AR;
namespace Project.Commands
{
public class CommandBuffer
{
public int Idx { get; set; }
private int REGISTER_VALUE = 0;
private Boolean REGISTER_TRUE = false;
private Boolean REGISTER_FALSE = false;
private Boolean REGISTER_EQUAL = false;
private Boolean REGISTER_ABOVE = false;
private Boolean REGISTER_BELOW = false;
/// <summary>
/// 순차실행명령
/// </summary>
public List<Command> Commands;
/// <summary>
/// 상시실행명령
/// </summary>
public List<Command> SPS;
public CommandBuffer()
{
Commands = new List<Command>();
SPS = new List<Command>();
}
public void AddSeq(Command cmd)
{
cmd.Idx = this.Commands.Count;
this.Commands.Add(cmd);
}
public void AddSPS(Command cmd)
{
cmd.Idx = this.SPS.Count;
this.SPS.Add(cmd);
}
public void Clear()
{
Commands.Clear();
SPS.Clear();
Idx = 0;
}
public StepResult Run()
{
//sps는 모두 실행한다
StepResult rlt;
foreach (var sps in this.SPS)
{
rlt = RunCode(sps);
if (rlt == StepResult.Wait) return StepResult.Wait; //SPS에서 대기 코드가 있다
else if (rlt == StepResult.Error) return StepResult.Error;
}
//sequece 는 현재 것만 실행한다.
if (Idx < 0) Idx = 0;
var cmd = this.Commands[Idx];
rlt = RunCode(cmd);
if (rlt == StepResult.Complete) //이 명령이 완료되면 다음으로 진행한다
{
Idx += 1;
if (Idx >= this.Commands.Count) return StepResult.Complete;
else return StepResult.Wait;
}
return rlt;
}
private StepResult RunCode(Command cmd)
{
switch (cmd.type)
{
case CType.NOP: return StepResult.Complete;
case CType.Wait:
var data0 = cmd.Data as CDWait;
if (data0.Trigger == false)
{
//아직 시작을 안했으니 시작시키고 대기한다
data0.SetTrigger(true);
return StepResult.Wait;
}
else
{
//아직 시간을 다 쓰지 않았다면 넘어간다
if (data0.TimeOver == false) return StepResult.Wait;
}
break;
case CType.Output:
var data1 = cmd.Data as CDOutput;
if (data1.PinIndex < 0) return StepResult.Error;
if (DIO.SetOutput((eDOName)data1.Pin, data1.Value) == false) return StepResult.Error;
break;
case CType.Move:
var data2 = cmd.Data as CDMove;
MOT.Move((eAxis)data2.Axis, data2.Position, data2.Speed, data2.Acc, data2.Relative);
break;
case CType.MoveForece:
var data3 = cmd.Data as CDMove;
MOT.Move((eAxis)data3.Axis, data3.Position, data3.Speed, data3.Acc, data3.Relative, false, false);
break;
case CType.MoveWait:
var data4 = cmd.Data as CDMove;
var axis = (eAxis)data4.Axis;
var mrlt = MOT.CheckMotionPos(axis, new TimeSpan(1), data4.Position, data4.Speed, data4.Acc, data4.Dcc, cmd.description);
if (mrlt == false) return StepResult.Wait;
break;
case CType.GetFlag:
var data5 = cmd.Data as CDFlag;
data5.Value = PUB.flag.get(data5.Flag);
REGISTER_FALSE = data5.Value == false;
REGISTER_TRUE = data5.Value == true;
break;
case CType.SetFlag:
var data6 = cmd.Data as CDFlag;
PUB.flag.set(data6.Flag, data6.Value, cmd.description);
break;
case CType.True:
var data7 = cmd.Data as CDCommand;
if (REGISTER_TRUE) return RunCode(data7.Command);
break;
case CType.False:
var data8 = cmd.Data as CDCommand;
if (REGISTER_FALSE) return RunCode(data8.Command);
break;
case CType.GetVar: //공용변수의값
var data10 = cmd.Data as CDGetVar;
if (data10.Key == "STEPTIME")
{
data10.Confirm = true;
data10.Value = (int)PUB.sm.StepRunTime.TotalMilliseconds;
}
break;
case CType.GetSetVar: //공용변수(설정)의 값
var data11 = cmd.Data as CDGetVar;
if (data11.Key == "TIMEOUT_HOMEFULL")
{
data11.Confirm = true;
data11.Value = 60;// (int)Pub.sm.StepRunTime.TotalMilliseconds;
}
break;
case CType.Compare:
var data9 = cmd.Data as CDCompare<int>;
if (data9 != null)
{
RunCode(data9.Source); //비교값(좌)
RunCode(data9.Target); //비교값(우)
var valS = data9.Source.Data as ICommandValue;
var valT = data9.Target.Data as ICommandValue;
int ValueS = (int)valS.Value;
int ValueT = (int)valT.Value;
REGISTER_ABOVE = ValueS > ValueT;
REGISTER_BELOW = ValueS < ValueT;
REGISTER_EQUAL = ValueS == ValueT;
REGISTER_TRUE = ValueS == ValueT;
REGISTER_FALSE = ValueS != ValueT;
REGISTER_VALUE = ValueS - ValueT;
}
else return StepResult.Error;
break;
case CType.SetError:
var data12 = cmd.Data as CDError;
PUB.Result.SetResultMessage(data12.ResultCode, data12.ErrorCode, data12.NextStep);
break;
}
return StepResult.Complete;
}
}
public enum CType
{
NOP = 0,
/// <summary>
/// motion move
/// </summary>
Move,
MoveForece,
/// <summary>
/// move and wait
/// </summary>
MoveWait,
/// <summary>
/// set digital output
/// </summary>
Output,
Log,
StepChange,
/// <summary>
/// check digital input
/// </summary>
InputCheck,
/// <summary>
/// check digital output
/// </summary>
OutputCheck,
GetFlag,
SetFlag,
Equal,
NotEqual,
True,
False,
Zero,
NonZero,
SetError,
Compare,
SetVar,
GetVar,
GetSetVar,
Above,
Below,
Wait,
Run,
}
public class Command
{
public CType type { get; set; } = CType.NOP;
public int Idx { get; set; }
public string description { get; set; }
public ICommandData Data { get; set; }
public Command(CType type, string desc = "")
{
this.type = type;
this.description = desc;
}
}
public interface ICommandData
{
// string Description { get; set; }
}
public interface ICommandValue
{
object Value { get; set; }
}
public class CDGetVar : ICommandData, ICommandValue
{
public string Key { get; set; }
public object Value { get; set; }
public Boolean Confirm { get; set; }
public CDGetVar(string key)
{
this.Key = key;
}
}
public class CDGetSetVar : ICommandData, ICommandValue
{
public string Key { get; set; }
public object Value { get; set; }
public Boolean Confirm { get; set; }
public CDGetSetVar(string key)
{
this.Key = key;
}
}
public class CDSetVar : ICommandData
{
public string Key { get; set; }
public int Value { get; set; }
public CDSetVar(string key, int value)
{
this.Key = key;
this.Value = Value;
}
}
public class CDFlag : ICommandData
{
public eVarBool Flag { get; set; }
public Boolean Value { get; set; }
public CDFlag(eVarBool flag)
{
this.Flag = flag;
Value = false;
}
}
public class CDSetValI : ICommandData
{
public int Value { get; set; }
public CDSetValI(int idx, int value)
{
this.Value = value;
}
}
public class CDSetValB : ICommandData
{
public bool Value { get; set; }
public CDSetValB(int idx, bool value)
{
this.Value = value;
}
}
public class CDCommand : ICommandData
{
public Command Command { get; set; }
public CDCommand(Command command)
{
this.Command = command;
}
}
public class CDError : ICommandData
{
public eResult ResultCode { get; set; }
public eECode ErrorCode { get; set; }
public eNextStep NextStep { get; set; }
public CDError(eResult resultCode, eECode errorCode, eNextStep nextStep)
{
ResultCode = resultCode;
ErrorCode = errorCode;
NextStep = nextStep;
}
}
//public class CDCompare<T> : ICommandData
//{
// public T Value { get; set; }
// public CDCompare(T value)
// {
// Value = value;
// }
// public CDCompare(Command source, Command target)
// {
// Value = value;
// }
//}
public class CDCompare<T> : ICommandData
{
public Command Source { get; set; }
public Command Target { get; set; }
public CDCompare(Command source, Command target)
{
Source = source;
Target = target;
}
}
public class CDWait : ICommandData
{
public int WaitMS { get; set; }
public DateTime StartTime { get; set; }
public Boolean Trigger { get; set; }
private TimeSpan GetTime { get { return DateTime.Now - StartTime; } }
public Boolean TimeOver { get { return GetTime.TotalMilliseconds > WaitMS; } }
public void SetTrigger(Boolean value)
{
Trigger = value;
StartTime = DateTime.Now;
}
public CDWait() : this(100) { }
public CDWait(int ms)
{
this.WaitMS = ms;
}
}
public class CDMove : ICommandData
{
public int Axis { get; set; }
public double Position { get; set; }
public double Speed { get; set; }
public double Acc { get; set; }
public double Dcc { get; set; }
public Boolean Relative { get; set; }
// public string Description { get; set; }
public CDMove(eAxis axis, double pos, double speed) : this((int)axis, pos, speed, 0) { }
public CDMove(int axis, double pos, double speed, double acc, double dcc = 0, Boolean relatvie = false)
{
Axis = axis;
Position = pos;
Speed = speed;
Acc = acc;
Dcc = dcc == 0 ? acc : dcc;
Relative = relatvie;
}
}
public class CDOutput : ICommandData
{
public eDOName Pin { get; set; }
public int PinIndex { get; set; }
public Boolean Value { get; set; }
// public string Description { get; set; }
//public CDOutput(eDOName pin) : this(pin, false) { }
public CDOutput(eDOName pin, Boolean value)
{
Pin = pin;
PinIndex = (int)pin;
Value = value;
}
public CDOutput(int point, Boolean value)
{
Pin = (eDOName)point;
PinIndex = point;
Value = value;
}
}
public class CDRun : ICommandData
{
public Action Target { get; set; }
public CDRun(Action target)
{
Target = target;
}
}
public class CDRunRet<T> : ICommandData
{
public Func<T> Target { get; set; }
public CDRunRet(Func<T> target)
{
Target = target;
}
}
public class CDLog : ICommandData
{
public string Message { get; set; }
public Boolean IsError { get; set; }
public CDLog(string message, Boolean err = false)
{
Message = message;
IsError = err;
}
}
public class CDStep : ICommandData
{
public eSMStep Step { get; set; }
public Boolean Force { get; set; }
public CDStep(eSMStep step, Boolean force = false)
{
Step = step;
Force = force;
}
}
}

View File

@@ -0,0 +1,393 @@
//using Project;
//using Project.Device;
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Management;
//using System.Net;
//using System.Net.NetworkInformation;
//using System.Text;
//using System.Threading.Tasks;
//using AR;
///// <summary>
///// ============================================================================
///// 장비기술 상태 모니터링 관련 클래스
///// 이 클래스는 SQLfiletoDB 프로그램과 같이 사용하는 것을 권장합니다.
///// 현재 실행 중인 프로그램의 하위 폴더 Status 에 입력된 상태값을 SQL 파일로 기록합니다.
///// SQLfiletoDB는 SQL파일을 실제 DB에 기록하는 프로그램입니다.
///// ============================================================================
///// 작성자 : chi
///// 작성일 : 202-06-15
///// GIT : (none)
///// </summary>
//public static partial class EEMStatus
//{
// static System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(true);
// static string ip = string.Empty;
// static string mac = string.Empty;
// static DateTime StatusChecktime = DateTime.Now;
// static DateTime MonitorChecktime = DateTime.Now.AddYears(-1);
// static DateTime FileCheckTime = DateTime.Now;
// static string monitorfile = string.Empty;
// /// <summary>
// /// UpdateStatusSQL 명령이 동작하는 간격이며 기본 180초(=3분)로 되어 있습니다.
// /// </summary>
// public static int UpdateStatusInterval { get; set; } = 180;
// public static int UpdateFileInterval { get; set; } = 3;
// static bool queryok = false;
// static bool UpdateRun = false;
// public static string IP
// {
// get
// {
// if (queryok == false) GetNetworkInfo();
// return ip;
// }
// set { ip = value; }
// }
// public static string MAC
// {
// get
// {
// if (queryok == false) GetNetworkInfo();
// return mac;
// }
// set
// {
// mac = value;
// }
// }
// /// <summary>
// /// 현재 시스템의 IP/MAC정보를 취득합니다.
// /// </summary>
// static void GetNetworkInfo()
// {
// ip = "";
// mac = "";
// // string prgmName = Application.ProductName;
// var nif = NetworkInterface.GetAllNetworkInterfaces();
// var host = Dns.GetHostEntry(Dns.GetHostName());
// string fullname = System.Net.Dns.GetHostEntry("").HostName;
// foreach (IPAddress r in host.AddressList)
// {
// string str = r.ToString();
// if (str != "" && str.Substring(0, 3) == "10.")
// {
// ip = str;
// break;
// }
// }
// string rtn = string.Empty;
// ObjectQuery oq = new System.Management.ObjectQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled='TRUE'");
// ManagementObjectSearcher query1 = new ManagementObjectSearcher(oq);
// foreach (ManagementObject mo in query1.Get())
// {
// string[] address = (string[])mo["IPAddress"];
// if (address[0] == ip && mo["MACAddress"] != null)
// {
// mac = mo["MACAddress"].ToString();
// break;
// }
// }
// queryok = true;
// }
// public static void UpdateStatusSQL(eSMStep status, bool _extrun = false, string remark = "")
// {
// var tsrun = DateTime.Now - StatusChecktime;
// if (tsrun.TotalSeconds >= UpdateStatusInterval)
// {
// AddStatusSQL(status, "UPDATE", extrun: _extrun);
// StatusChecktime = DateTime.Now;
// }
// //내부실행모드일때에만 파일을 처리한다
// if (_extrun == false)
// {
// var tsfile = DateTime.Now - FileCheckTime;
// if (tsfile.TotalSeconds >= UpdateFileInterval)
// {
// if (UpdateRun == false)
// {
// UpdateRun = true;
// Task.Run(() =>
// {
// UpdateFileToDB();
// UpdateRun = false;
// });
// }
// FileCheckTime = DateTime.Now;
// }
// }
// }
// /// <summary>
// /// 상태모니터링 프로그램의 실행파일 명
// /// </summary>
// static string StatusMonitorFile
// {
// get
// {
// if (string.IsNullOrEmpty(monitorfile))
// monitorfile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status", "SQLFileToDB.exe");
// return monitorfile;
// }
// }
// static System.Diagnostics.Process CheckMonitor()
// {
// if (System.IO.File.Exists(StatusMonitorFile) == false) return null;
// var prcs = System.Diagnostics.Process.GetProcesses();
// return prcs.Where(t => t.ProcessName.ToLower().StartsWith("sqlfiletodb")).FirstOrDefault();
// }
// public static bool RunStatusMonitor()
// {
// //파일이 없으면 실행 불가
// if (System.IO.File.Exists(StatusMonitorFile) == false) return false;
// //실행프로세스 검사
// var prc = CheckMonitor();
// if (prc == null)
// {
// try
// {
// prc = new System.Diagnostics.Process();
// prc.StartInfo = new System.Diagnostics.ProcessStartInfo
// {
// Arguments = string.Empty,
// FileName = StatusMonitorFile,
// };
// prc.Start();
// }
// catch
// {
// return false;
// }
// }
// return true;
// }
// /// <summary>
// /// 작업수량을 입력합니다
// /// </summary>
// /// <param name="cnt"></param>
// /// <returns></returns>
// public static string AddStatusCount(int cnt, string remark = "")
// {
// if (remark.isEmpty()) remark = $"Count Set : {cnt}";
// return AddStatusSQL(PUB.sm.Step, remark, count: cnt);
// }
// /// <summary>
// /// 상태메세지를 status 폴더에 기록합니다.
// /// </summary>
// /// <param name="status">상태머신의 상태값</param>
// /// <param name="remark">비고</param>
// /// <param name="wdate">기록일시</param>
// /// <returns>오류발생시 오류메세지가 반환 됩니다</returns>
// public static string AddStatusSQL(eSMStep status, string remark = "", DateTime? wdate = null, bool extrun = false, int? count = null)
// {
// if (queryok == false || MAC.isEmpty()) GetNetworkInfo();
// if (status == eSMStep.CLOSEWAIT || status == eSMStep.CLOSED) return string.Empty;
// if (extrun)
// {
// //상태모니터링 프로그램을 실행합니다.
// var tsMon = DateTime.Now - MonitorChecktime;
// if (tsMon.TotalMinutes > 5) RunStatusMonitor();
// }
// try
// {
// var state = 0;
// string cntstr = "null";
// if (count != null) cntstr = count.ToString();
// var alarmid = string.Empty;
// var alarmmsg = string.Empty;
// if (string.IsNullOrEmpty(remark)) remark = $"STS:{status}";
// if (status == eSMStep.RUN) state = 1;
// else if (status == eSMStep.ERROR || status == eSMStep.EMERGENCY)
// {
// state = 2;
// alarmid = PUB.Result.ResultErrorCode.ToString();
// alarmmsg = PUB.Result.ResultMessage;
// }
// else if (status == eSMStep.PAUSE) //일시중지도 오류코드가 포함된다,
// {
// if (PUB.Result.ResultErrorCode == Project.eECode.USER_STEP ||
// PUB.Result.ResultErrorCode == Project.eECode.USER_STOP ||
// PUB.Result.ResultErrorCode.ToString().StartsWith("MESSAGE"))
// {
// //사용자에의해 멈추는 것은 오류코드를 넣지 않는다.
// }
// else
// {
// alarmid = PUB.Result.ResultErrorCode.ToString();
// alarmmsg = PUB.Result.ResultMessage;
// }
// }
// else if (status == eSMStep.INIT) state = 3; //시작
// else if (status == eSMStep.CLOSING) state = 4; //종료
// //length check
// if (alarmid.Length > 10) alarmid = alarmid.Substring(0, 10);
// if (remark.Length > 99) remark = remark.Substring(0, 99);
// if (alarmmsg.Length > 250) alarmmsg = alarmmsg.Substring(0, 50);
// var mcid = AR.SETTING.Data.MCID;// Project.PUB.setting.MCID;//.Data.MCID;
// //var mcid = Project.PUB.setting.MCID;//.Data.MCID;
// var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status");
// var file = System.IO.Path.Combine(path, $"{DateTime.Now.ToString("HHmmssfff")}_{status}.sql");
// var sql = "insert into MCMonitor_Rawdata(Model,status,remark,ip,mac,time,alarmid,alarmmsg,count,version) " +
// " values('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}',{8},'{9}')";
// var timestr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// if (wdate != null) timestr = ((DateTime)wdate).ToString("yyyy-MM-dd HH:mm:ss");
// var VersionNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
// sql = string.Format(sql, mcid, state, remark.Replace("'", "''"), IP, MAC, timestr, alarmid, alarmmsg, cntstr, VersionNumber);
// System.IO.File.WriteAllText(file, sql, System.Text.Encoding.Default);
// ////만들어진지 3분이 지난 파일은 삭제한다.
// //var di = new System.IO.DirectoryInfo(path);
// //var fi = di.GetFiles("*.sql", System.IO.SearchOption.TopDirectoryOnly).Where(t => t.LastWriteTime < DateTime.Now.AddMinutes(-3)).FirstOrDefault();
// //if (fi != null) fi.Delete();
// if (state == 4) UpdateFileToDB();
// return string.Empty;
// }
// catch (Exception ex)
// {
// return ex.Message;
// }
// }
// static void UpdateFileToDB()
// {
// if (mre.WaitOne(1000) == false) return;
// mre.Reset();
// var cs = "Data Source=10.131.15.18;Initial Catalog=EE;Persist Security Info=True;User ID=eeuser;Password=Amkor123!";
// var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status");
// var di = new System.IO.DirectoryInfo(path);
// if (di.Exists == false) return;
// var file = di.GetFiles("*.sql", System.IO.SearchOption.TopDirectoryOnly)
// .Where(t => t.LastWriteTime < DateTime.Now.AddSeconds(-3))
// .OrderByDescending(t => t.LastWriteTime).FirstOrDefault();
// if (file == null)
// {
// mre.Set();
// return;
// }
// //파일을 찾아야한다
// // PUB.log.Add($">> {file.FullName}");
// try
// {
// var sql = System.IO.File.ReadAllText(file.FullName, System.Text.Encoding.Default);
// if (string.IsNullOrEmpty(sql))
// {
// //비어잇다면
// var errpath = System.IO.Path.Combine(di.FullName, "Error");
// var errfile = System.IO.Path.Combine(errpath, file.Name);
// if (System.IO.Directory.Exists(errpath) == false) System.IO.Directory.CreateDirectory(errpath);
// System.IO.File.Move(file.FullName, errfile);// file.MoveTo(errfile);
// // ecnt += 1;
// }
// else
// {
// // var csstr = PUB.setting.ConnectionString;
// // if (string.IsNullOrEmpty(csstr)) csstr = "Data Source=10.131.15.18;Initial Catalog=EE;Persist Security Info=True;User ID=eeuser;Password=Amkor123!";
// var cn = new System.Data.SqlClient.SqlConnection(cs);
// var cmd = new System.Data.SqlClient.SqlCommand(sql, cn);
// cn.Open();
// var cnt = cmd.ExecuteNonQuery();
// //if (cnt == 0) PUB.log.Add($"Result Empty : {sql}");
// cn.Close();
// cnt += 1;
// var errpath = System.IO.Path.Combine(di.FullName, "Complete");
// var errfile = System.IO.Path.Combine(errpath, file.Name);
// if (System.IO.Directory.Exists(errpath) == false) System.IO.Directory.CreateDirectory(errpath);
// //file.MoveTo(errfile);
// System.IO.File.Move(file.FullName, errfile);
// }
// }
// catch (Exception ex)
// {
// if(ex.Message.Contains("deadlocked") == false)
// {
// var errpath = System.IO.Path.Combine(di.FullName, "Error");
// var errfile = System.IO.Path.Combine(errpath, file.Name);
// if (System.IO.Directory.Exists(errpath) == false) System.IO.Directory.CreateDirectory(errpath);
// try
// {
// //file.MoveTo(errfile);
// System.IO.File.Move(file.FullName, errfile);
// //오류내용도 저장한다..
// var errfilename = errfile + "_error.txt";
// System.IO.File.WriteAllText(errfilename, ex.Message, System.Text.Encoding.Default);
// }
// catch (Exception ex2)
// {
// }
// }
// else
// {
// Console.WriteLine("(UpdateFileToDB) Dead lock error ignored");
// }
// //ecnt += 1;
// }
// //try
// //{
// // //생성된지 10일이 넘은 자료는 삭제한다.
// // //시간소비를 피해서 1개의 파일만 작업한다
// // //var sqlfiles = di.GetFiles("*.sql", System.IO.SearchOption.AllDirectories);
// // //총3번의 데이터를 처리한다
// // //var files = sqlfiles.Where(t => t.LastWriteTime < DateTime.Now.AddDays(-10)).Select(t => t.FullName);
// // //int i = 0;
// // //var dellist = files.TakeWhile(t => i++ < 3);
// // //foreach (var delfile in dellist)
// // //System.IO.File.Delete(delfile);
// //}
// //catch
// //{
// //}
// mre.Set();
// }
//}
///*
//=================================================
//변경내역
//=================================================
//230619 chi UpdateFileToDB 에서 폴더가 없다면 return 하도록 함
//230615 chi UpdateFiletoDB의 ManualResetEvent적용
// Version 항목 추가
//230612 chi 프로그램 시작/종료 alarmid항목 추가
// 완료된 파일 10일간 보존하도록 함
//230522 chi extrun 모드 추가(agv용 - SQL파일을 외부 프로그램에서 처리하도록 함)
//230617 chi 파일쓰기함수를 Task 로 처리
// 3분지난데이터 삭제기능 제거
//230516 chi initial commit
//*/

View File

@@ -0,0 +1,689 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace Project
{
public enum StepResult
{
Wait = 0,
Complete,
Error,
}
public enum eWorkPort
{
Left = 0,
Right
}
public enum eNormalResult
{
True = 0,
False,
Error,
}
public enum eSMStep : byte
{
NOTSET = 0,
INIT = 1,
IDLE = 10,
RUN = 50,
RUN_ROOT_SEQUENCE_L,
RUN_ROOT_SEQUENCE_R,
RUN_KEYENCE_READ_L,
RUN_KEYENCE_READ_R,
RUN_PICKER_ON_L,
RUN_PICKER_ON_R,
RUN_PICKER_OFF_L,
RUN_PICKER_OFF_R,
RUN_PRINTER_F,
RUN_PRINTER_R,
RUN_PRINTER_ON_F,
RUN_PRINTER_ON_R,
RUN_PRINTER_OFF_F,
RUN_PRINTER_OFF_R,
RUN_QRVALID_F,
RUN_QRVALID_R,
RUN_COM_PT0,
RUN_COM_PT1,
RUN_COM_PT2,
RUN_PICK_RETRY,
//이후에 사용자 런 코드용 스텝을 추가한다.
EMERGENCY = 200,
HOME_FULL = 201,
HOME_DELAY,
HOME_CONFIRM,
HOME_QUICK,
CLOSING = 250,
CLOSEWAIT = 251,
CLOSED = 252,
//사용자영역
FINISH = 100,
PAUSE,
WAITSTART,
ERROR,
SAFTY,
CLEAR,
}
public enum eWaitMessage
{
PX = 0,
PZ,
LMOVE,
LUPDN,
RMOVE,
RUPDN,
LPRINT,
RPRINT,
VIS0,
VIS1,
VIS2,
}
//public enum eJobResult
//{
// None = 0,
// Error,
// ErrorOut,
// MaxCount,
// NotExistSID,
// DisableUnloader,
// MatchFail,
// NoBarcode
//}
public enum eCartSize
{
None = 0,
Inch7 = 7,
Inch13 = 13
}
public enum ePrintPutPos
{
None = 0,
Top,
Middle,
Bottom,
}
public enum ePrintVac
{
inhalation = 0,
exhaust,
off,
}
public enum eJobType : byte
{
Sorter = 0,
Dryrun,
}
public enum eHeaderHandler
{
Ping = 0,
RequestData,
RequstSeqNo,
RequstInputReel,
JobEnd,
JobDelete,
}
public struct sVisionDMResult
{
public Boolean iSystemErr { get; set; }
public Boolean isError { get; set; }
public string DM { get; set; }
public System.Drawing.Rectangle ROS { get; set; }
public System.Drawing.PointF DMCenter { get; set; }
public List<System.Drawing.PointF> DMCorner { get; set; }
public string DMMessage { get; set; }
}
public struct sObjectDetectResult
{
public string Message { get; set; }
public List<System.Drawing.Rectangle> Rect { get; set; }
public List<uint> Areas { get; set; }
public Boolean OK
{
get
{
if (Areas == null || Areas.Count < 1) return false;
else return true;
}
}
}
public enum eGridValue
{
/// <summary>
/// 아직 처리 전(기본 초기화된 상태)
/// </summary>
NotSet = 0,
/// <summary>
/// 원점검사에서 오류 발생
/// </summary>
OrientError,
/// <summary>
/// 아이템검출에서 실패됨
/// </summary>
NoItem,
/// <summary>
/// 아이템검출성공, 데이터매트릭스 검출 실패
/// </summary>
NewItem,
/// <summary>
/// 데이터매트릭스 읽기 실패
/// </summary>
DMReadError,
/// <summary>
/// 데이터매트릭스 관리 횟수가 기준횟수(10) 미만 (아직 정상)
/// </summary>
DMNotmalCount,
/// <summary>
/// 데이터매트릭스 관리 횟수가 기준횟수(10)를 초과한 경우
/// </summary>
DMOverCount,
}
public enum eRoiSeq
{
Area = 0,
DataMatrix,
Orient,
DetectUnit,
DetectDM
}
public enum eWaitType : byte
{
TryLock = 0,
TryUnLock,
AirBlowOn,
AirBlowOff,
AirBlowDustOn,
AirBlowDustOff,
PrintPickLOff,
PrintPickLOn,
PrintPickROff,
PrintPickROn,
PickOff,
PickOn,
AirBlowCoverDn,
AirBlowCoverUp,
UnloaderUp,
UnloaderDn,
LiftUp,
LiftDn,
}
public enum eSensorState : byte
{
Off = 0,
On = 1,
InComplete = 2,
}
public enum eIOCheckResult
{
Wait = 0,
Complete,
Timeout
}
public enum ePort
{
Left = 0,
Right,
}
enum eResultStringType
{
Nomal = 0,
Attention,
Error,
}
public enum eMotDir
{
Stop = 0,
CW = 1,
CCW = 2
}
/// <summary>
/// RUN중일 때 사용되는 세부 시퀀스
/// </summary>
public enum eRunStep : byte
{
NOTSET = 0,
/// <summary>
/// 프로그램 체크
/// </summary>
STARTCHKSW,
/// <summary>
/// 하드웨어 체크
/// </summary>
STARTCHKHW,
/// <summary>
/// 기계장치를 작업 시작 전 상태로 이동합니다
/// </summary>
INITIALHW,
/// <summary>
/// 안전지대(비활성화된경우 발생)
/// </summary>
SAFTYZONE_GO,
SAFTYZONE_RDY,
BEGINLOAD,
/// <summary>
/// 트레이를 로딩하기 위한 로더 이동 및 트레이 추출
/// </summary>
PORTLOAD,
/// <summary>
/// 비젼촬영을위한 위치로 이동
/// </summary>
BEGINPICK,
ENDPICK,
OVERLOAD,
SAVEDATA,
/// <summary>
/// 모션 원위치
/// </summary>
BARCODE,
/// <summary>
/// AIR/BLOW 위치 이동 및 작업
/// </summary>
AIRBLOW,
REELOUT,
TRAYOUT,
/// <summary>
/// 언로드위치로 셔틀을 이동
/// </summary>
BEGINUNLOADER,
/// <summary>
/// 트레이 언로드 작업
/// </summary>
TRAYUNLOAD,
/// <summary>
/// 언로딩하고 다시 로딩존으로 이동하는 시퀀스
/// </summary>
MOVE_TO_LOAD,
}
public enum ePLCIPin : byte
{
X00, X01, X02, X03, X04, X05, X06, X07, X08, X09, X0A,
X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X1A
}
public enum ePLCOPin : byte
{
Y00, Y01, Y02, Y03, Y04, Y05, Y06, Y07, Y08, Y09, Y0A,
Y10, Y11, Y12, Y13, Y14, Y15, Y16, Y17, Y18, Y19, Y1A
}
public enum ePLCITitle : byte
{
Run, Cart_Status_01, Cart_Status_02, Cart_Status_03, Cart_Status_04,
Machine_Confirm = 19
}
public enum ePLCOTitle : byte
{
Cart_No_Setting = 0,
Handler_Confirm = 19,
}
public enum eResult : byte
{
NOERROR,
EMERGENCY,
SAFTY,
DEVELOP,
SETUP,
HARDWARE,
SENSOR,
MOTION,
OPERATION,
COMMUNICATION,
TIMEOUT,
UNLOADER,
}
public enum eECode : byte
{
NOTSET = 0,
EMERGENCY = 1,
NOMODELV = 2,//작업모델
NOMODELM = 3,//모션모델
DOORSAFTY = 6,
AREASAFTY = 7,
VIS_LICENSE = 8,
HOME_TIMEOUT = 9,
AIRNOOUT = 10,
NOFUNCTION = 11,
AIRNOTDETECT = 12,
DOOFF = 27,//출력 off
DOON = 28,//출력 on
DIOFF = 29,//입력off
DION = 30,//입력 on
MESSAGE_INFO = 32,
MESSAGE_ERROR = 33,
VISION_NOTREADY = 34,
VISION_NOCONN = 35,
VISION_TRIGERROR = 36,
VISION_COMMERROR = 37,
VISION_NORECV = 38,
AZJINIT = 39, //DIO 혹은 모션카드 초기화 X
MOT_HSET = 41,
MOT_SVOFF = 42,
MOT_HSEARCH = 43,
MOT_CMD = 71,
USER_STOP = 72,
USER_STEP = 73,
POSITION_ERROR = 86,
MOTIONMODEL_MISSMATCH = 96,
//여기서부터는 전용코드로한다(소켓은 조금 섞여 있음)
VISCONF = 100,
NEED_AIROFF_L,
NEED_AIROFF_R,
PORTOVERLOAD,
NOPRINTLDATA,
NOPRINTRDATA,
PRINTL,
PRINTR,
CAM_LEFT,
CAM_RIGHT,
INCOMPLETE_LOADERDATA,
INCOMPLETE_INFOSELECT,
NOPUTPOSITION,
NOREELSIZE,
PRINTER,
QRDATAMISSMATCHL,
QRDATAMISSMATCHR,
MOTX_SAFETY,
NO_PAPER_DETECT_L,
NO_PAPER_DETECT_R,
CART_SIZE_ERROR_L,
CART_SIZE_ERROR_R,
PRE_USE_REELID_L,
PRE_USE_REELID_R,
NEED_JOBCANCEL,
LCONVER_REEL_DECTECT_ALL =150,
RCONVER_REEL_DECTECT_ALL,
LCONVER_REEL_DECTECT_IN,
RCONVER_REEL_DECTECT_IN,
LCONVER_MOVING,
RCONVER_MOVING,
NOREADY_KEYENCE,
PRINTER_LPICKER_NOBW,
PRINTER_RPICKER_NOBW,
NOBYPASSSID,
CONFIG_KEYENCE,
PRINTER_LPRINTER_NOUP,
PRINTER_RPRINTER_NOUP,
NOECSDATA,
PICKER_LCYL_NODOWN,
PICKER_RCYL_NODOWN,
PICKER_LCYL_NOUP,
PICKER_RCYL_NOUP,
NOSIDINFOFROMDB,
INBOUNDWEBAPIERROR,
SIDINFORDUP,
NOECSDATAACTIVE,
NOTSELECTMULTISID,
}
public enum eNextStep : byte
{
NOTHING = 0,
PAUSE,
PAUSENOMESAGE,
ERROR
}
public enum eILock
{
EMG = 0,
PAUSE,
HOMESET,
DOOR,
SAFTYAREA,
DISABLE,
XMOVE,
YMOVE,
ZMOVE,
X_POS,
Y_POS,
Z_POS,
PY_POS,
PZ_POS,
CYL_FORWARD,
MPrint,
}
//public enum eILockPKX
//{
// EMG = 0,
// PAUSE,
// HOMESET,
// DOOR,
// Disable,
// ZL_POS,
// ZR_POS,
// ZMOVE,
// PKZPOS,
//}
//public enum eILockPKZ
//{
// EMG = 0,
// PAUSE,
// HOMESET,
// DOOR,
// Disable,
// Y_POS,
// YMOVE,
// PORTRUN0,
// PORTRUN1,
// PORTRUN2
//}
//public enum eILockPKT
//{
// EMG = 0,
// PAUSE,
// HOMESET,
// DOOR,
// Disable,
// Y_POS,
// Y_MOVE,
// PortRun
//}
///// <summary>
///// PRINT MOVE AXIS (L+R)
///// </summary>
//public enum eILockPRM
//{
// Emergency = 0,
// Pause,
// HomeSet,
// Safty,
// Disable,
// ZMOVE,
// FORWARD,
// ITEMON,
// PKXPOS,
// PRNZPOS,
//}
//public enum eILockPRZ
//{
// EMG = 0,
// PAUSE,
// HOMESET,
// DOOR,
// Disable,
// YMOVE,
// ITEMON,
// PRNYPOS,
//}
public enum eILockPRL
{
EMG = 0,
PAUSE,
HOMESET,
DOOR,
SAFTYAREA,
DISABLE,
PRNYPOS,
PRNZPOS,
}
public enum eILockPRR
{
EMG = 0,
PAUSE,
HOMESET,
DOOR,
SAFTYAREA,
DISABLE,
PRNYPOS,
PRNZPOS,
}
public enum eILockVS0
{
EMG = 0,
PAUSE,
HOMESET,
DOOR,
SAFTYAREA,
DISABLE,
PORTRDY,
PKXPOS, //피커의 위치
PRNYPOS, //프린터Y축 위치
}
public enum eILockVS1
{
EMG = 0,
PAUSE,
HOMESET,
DOOR,
SAFTYAREA,
DISABLE,
PORTRDY,
PKXPOS,
}
public enum eILockVS2
{
EMG = 0,
PAUSE,
HOMESET,
DOOR,
SAFTYAREA,
DISABLE,
PORTRDY,
PKXPOS, //피커의 위치
PRNYPOS, //프린터Y축 위치
}
public enum eILockCV
{
EMG = 0,
PAUSE,
HOMESET,
DOOR,
SAFTYAREA,
/// <summary>
/// 포트를 사용하지 않는경우
/// </summary>
DISABLE,
/// <summary>
/// 카트모드
/// </summary>
CARTMODE,
/// <summary>
/// 업체컨이어의 ready 신호
/// </summary>
EXTBUSY,
/// <summary>
/// 나의 작업 신호
/// </summary>
BUSY,
VISION,
}
}

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace Project
{
public enum ePXLoc : byte
{
[Description("Reel Waiting(Left) Position")]
READYL = 0,
[Description("Reel Waiting(Right) Position")]
READYR,
[Description("Reel PickOn Position")]
PICKON,
[Description("Reel PickOff(Left) Position")]
PICKOFFL,
[Description("Reel PickOff(Right) Position")]
PICKOFFR,
}
public enum ePZLoc : byte
{
[Description("Ready Position")]
READY = 0,
[Description("Reel PickOn Position")]
PICKON,
[Description("Reel PickOff(Left) Position")]
PICKOFFL,
[Description("Reel PickOff(Right) Position")]
PICKOFFR,
}
public enum ePTLoc : byte
{
[Description("Ready Position")]
READY = 0,
}
public enum eLMLoc : byte
{
[Description("Ready Position")]
READY = 0,
[Description("7\" High Attach Position")]
PRINTH07,
[Description("7\" Low Attach Position")]
PRINTL07,
[Description("7\" Middle Attach Position")]
PRINTM07,
[Description("13\" High Attach Position")]
PRINTH13,
[Description("13\" Low Attach Position")]
PRINTL13,
[Description("13\" Middle Attach Position")]
PRINTM13,
}
public enum eLZLoc : byte
{
[Description("Ready Position")]
READY = 0,
[Description("Reel PickOn Position")]
PICKON,
[Description("Reel PickOff Position")]
PICKOFF,
}
public enum eRMLoc : byte
{
[Description("Ready Position")]
READY = 0,
[Description("7\" High Attach Position")]
PRINTH07,
[Description("7\" Low Attach Position")]
PRINTL07,
[Description("7\" Middle Attach Position")]
PRINTM07,
[Description("13\" High Attach Position")]
PRINTH13,
[Description("13\" Low Attach Position")]
PRINTL13,
[Description("13\" Middle Attach Position")]
PRINTM13,
}
public enum eRZLoc : byte
{
[Description("Ready Position")]
READY = 0,
[Description("Reel PickOn Position")]
PICKON,
[Description("Reel PickOff Position")]
PICKOFF,
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AR.FTPClient
{
public class MessageEventArgs : EventArgs
{
protected Boolean _isError = false;
public Boolean IsError { get { return _isError; } }
protected string _message = string.Empty;
public string Message { get { return _message; } }
public MessageEventArgs(Boolean isError, string Message)
{
_isError = isError;
_message = Message;
}
}
public class ListProgressEventArgs : EventArgs
{
//public long Max { get; set; }
//public long Value { get; set; }
public long TotalRecv { get; set; }
public ListProgressEventArgs(long TotalRecv_)
{
this.TotalRecv = TotalRecv_;
}
}
}

View File

@@ -0,0 +1,574 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace AR.FTPClient
{
public partial class FTPClient : IFTPClient
{
public string errorMessage { get; set; }
private int bufferSize = 2048;
private int timeout = 20000;
#region "Contstruct"
public FTPClient() : this("127.0.0.1", "Anonymous", "") { }
public FTPClient(string Host, string UserID, string UserPass) :
this(Host, UserID, UserPass, 21)
{ }
public FTPClient(string Host, string UserID, string UserPass, bool passive) :
this(Host, UserID, UserPass, 21, passive)
{ }
public FTPClient(string Host, string UserID, string UserPass, int port) :
this(Host, UserID, UserPass, port, false)
{ }
public FTPClient(string host, string userid, string userpass, int port, bool passive)
{
Host = host;
UserID = userid;
UserPassword = userpass;
Port = port;
PassiveMode = passive;
this.TextEncoding = System.Text.Encoding.UTF8;
}
#endregion
public event EventHandler<MessageEventArgs> Message;
public event EventHandler<ListProgressEventArgs> ListPrgress;
#region "Properties"
/// <summary>
/// 접속하려는 FTP서버의 IP혹은 도메인 주소를 입력하세요
/// 기본값 : 127.0.0.1
/// </summary>
public string Host { get; set; }
/// <summary>
/// FTP의 사용자 ID
/// 기본값 : Anonymous
/// </summary>
public string UserID { get; set; }
/// <summary>
/// FTP 사용자 ID의 암호
/// 기본값 : 없음
/// </summary>
public string UserPassword { get; set; }
/// <summary>
/// FTP 접속 포트
/// 기본값 : 21
/// </summary>
public int Port { get; set; }
/// <summary>
/// FTP 접속 방식 (능동형/수동형)
/// </summary>
public bool PassiveMode { get; set; }
/// <summary>
/// 문자수신시 사용할 인코딩 방식
/// </summary>
public System.Text.Encoding TextEncoding { get; set; }
#endregion
public void Dispose()
{
}
/// <summary>
/// 파일을 다운로드 합니다.
/// </summary>
/// <param name="remoteFile">원격위치의 전체 경로</param>
/// <param name="localFile">로컬위치의 전체 경로</param>
public Boolean Download(string remoteFile, string localFile, bool overwrite = false)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
//overwrite funcion - 190622 - chi
errorMessage = string.Empty;
if (overwrite == false && System.IO.File.Exists(localFile))
{
errorMessage = "Target file alreay exists";
return false;
}
else if (overwrite == true && System.IO.File.Exists(localFile))
{
try
{
System.IO.File.Delete(localFile);
}
catch (Exception ex)
{
errorMessage = ex.Message;
return false;
}
}
bool retval = true;
try
{
long Receive = 0;
var url = CombineUrl(remoteFile);
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(this.UserID, this.UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.DownloadFile;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
FileStream localFileStream = new FileStream(localFile, FileMode.Create);
byte[] byteBuffer = new byte[bufferSize];
int bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
Receive += bytesRead;
if (ListPrgress != null)
ListPrgress(this, new ListProgressEventArgs(Receive));
try
{
while (bytesRead > 0)
{
localFileStream.Write(byteBuffer, 0, bytesRead);
bytesRead = ftpStream.Read(byteBuffer, 0, bufferSize);
Receive += bytesRead;
if (ListPrgress != null)
ListPrgress(this, new ListProgressEventArgs(Receive));
}
}
catch (Exception ex) { retval = false; Console.WriteLine(ex.ToString()); }
localFileStream.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
}
catch (Exception ex) { retval = false; this.errorMessage = ex.Message; Console.WriteLine(ex.ToString()); }
return retval;
}
/// <summary>
/// 파일을 업로드 합니다.
/// </summary>
/// <param name="remoteFile">원격위치의 전체 경로</param>
/// <param name="localFile">로컬위치의 전체 경로</param>
/// <returns></returns>
public Boolean Upload(string remoteFile, string localFile)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(remoteFile);
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
ftpStream = ftpRequest.GetRequestStream();
FileStream localFileStream = new FileStream(localFile, FileMode.Open);
byte[] byteBuffer = new byte[bufferSize];
int bytesSent = localFileStream.Read(byteBuffer, 0, bufferSize);
Boolean bError = false;
try
{
System.Diagnostics.Stopwatch wat = new System.Diagnostics.Stopwatch();
wat.Restart();
while (bytesSent != 0)
{
ftpStream.Write(byteBuffer, 0, bytesSent);
bytesSent = localFileStream.Read(byteBuffer, 0, bufferSize);
}
}
catch (Exception ex)
{
bError = true;
}
localFileStream.Close();
ftpStream.Close();
ftpRequest = null;
if (bError) return false;
else return true;
}
catch (Exception ex)
{
this.errorMessage = ex.Message;
return false;
}
}
/// <summary>
/// 원격파일을 삭제 합니다.
/// </summary>
/// <param name="remotefile"></param>
public Boolean Delete(string remotefile)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(remotefile);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.DeleteFile;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
ftpRequest = null;
return true;
}
catch (Exception ex) { this.errorMessage = ex.Message; return false; }
}
/// <summary>
/// 원격파일의 이름을 변경 합니다.
/// </summary>
/// <param name="currentFileNameAndPath"></param>
/// <param name="newFileName"></param>
public Boolean rename(string currentFileNameAndPath, string newFileName)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(currentFileNameAndPath);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = true;
ftpRequest.Method = WebRequestMethods.Ftp.Rename;
ftpRequest.RenameTo = newFileName;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
ftpRequest = null;
return true;
}
catch (Exception ex) { this.errorMessage = ex.Message; return false; }
}
/// <summary>
/// 원격위치에 폴더를 생성 합니다.
/// 트리구조로 폴더를 생성하지 않습니다. 여러개의 폴더를 생성하려면 각각 호출 해야 합니다.
/// </summary>
/// <param name="newDirectory"></param>
/// <returns></returns>
public bool createDirectory(string newDirectory)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(newDirectory, false);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.MakeDirectory;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
ftpRequest = null;
return true;
}
catch (Exception ex) { this.errorMessage = ex.Message; return false; }
}
/// <summary>
/// 원격위치의 폴더를 삭제합니다. 폴더 삭제 전 대상 폴더는 비어있어야 합니다.
/// </summary>
/// <param name="Directory"></param>
/// <returns></returns>
public bool RemoveDirectory(string Directory)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(Directory, false);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.RemoveDirectory;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpResponse.Close();
ftpRequest = null;
return true;
}
catch (Exception ex) { this.errorMessage = ex.Message; return false; }
}
/// <summary>
/// 파일의 생성일자 반환
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string getFileCreatedDateTime(string fileName)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(fileName);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.GetDateTimestamp;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
StreamReader ftpReader = new StreamReader(ftpStream, this.TextEncoding);
string fileInfo = null;
try { fileInfo = ftpReader.ReadToEnd(); }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
return fileInfo;
}
catch (Exception ex) { this.errorMessage = ex.Message; Console.WriteLine(ex.ToString()); }
return "";
}
/// <summary>
/// 파일의 크기를 반환
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public string getFileSize(string fileName)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
try
{
var url = CombineUrl(fileName);
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = this.PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.Method = WebRequestMethods.Ftp.GetFileSize;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
StreamReader ftpReader = new StreamReader(ftpStream, this.TextEncoding);
string fileInfo = null;
try { while (ftpReader.Peek() != -1) { fileInfo = ftpReader.ReadToEnd(); } }
catch (Exception ex) { Console.WriteLine(ex.ToString()); }
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
return fileInfo;
}
catch (Exception ex) { errorMessage = ex.Message; Console.WriteLine(ex.ToString()); }
return "";
}
/// <summary>
/// 폴더와 파일의 이름만 반환 합니다.
/// </summary>
/// <param name="directory"></param>
/// <returns></returns>
public string[] directoryListSimple(string directory)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
errorMessage = string.Empty;
try
{
var url = CombineUrl(directory, false);
if (url.EndsWith("/") == false) url += "/";
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = PassiveMode;
ftpRequest.KeepAlive = true;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.ReadWriteTimeout = 30000;
ftpRequest.Timeout = 30000;
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
StreamReader ftpReader = new StreamReader(ftpStream, this.TextEncoding);
string directoryRaw = null;
try
{
while (ftpReader.Peek() != -1)
{
var dataLIne = ftpReader.ReadLine();
if (dataLIne.Trim() != "")
{
if (directoryRaw != null && directoryRaw != "") directoryRaw += "|";
directoryRaw += dataLIne;
}
}
}
catch (Exception ex) { errorMessage += "\n" + ex.Message; }
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
try { string[] directoryList = directoryRaw.Split("|".ToCharArray()); return directoryList; }
catch (Exception ex) { errorMessage += "\n" + ex.Message; }
}
catch (Exception ex) { errorMessage = ex.Message; Console.WriteLine(ex.ToString()); }
return new string[] { "" };
}
/// <summary>
/// 폴더 및 파일의 정보를 상세하게 표시합니다.
/// </summary>
/// <param name="directory"></param>
/// <returns></returns>
public FTPdirectory ListDirectoryDetail(string directory)
{
FtpWebRequest ftpRequest = null;
FtpWebResponse ftpResponse = null;
Stream ftpStream = null;
errorMessage = string.Empty;
try
{
var url = CombineUrl(directory, false);
if (url.EndsWith("/") == false) url += "/";
ftpRequest = (FtpWebRequest)WebRequest.Create(url);
ftpRequest.Credentials = new NetworkCredential(UserID, UserPassword);
ftpRequest.UsePassive = true;
ftpRequest.UseBinary = true;
ftpRequest.KeepAlive = false;
ftpRequest.ReadWriteTimeout = this.timeout;
ftpRequest.ReadWriteTimeout = 30000;
ftpRequest.Timeout = 30000;
ftpRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
ftpStream = ftpResponse.GetResponseStream();
StreamReader ftpReader = new StreamReader(ftpStream, this.TextEncoding);
string directoryRaw = null;
try { while (ftpReader.Peek() != -1) { directoryRaw += ftpReader.ReadLine() + "\r"; } }
catch (Exception ex) { errorMessage += "\n" + ex.Message; }
ftpReader.Close();
ftpStream.Close();
ftpResponse.Close();
ftpRequest = null;
directoryRaw = directoryRaw.Replace("\r\n", "\r").TrimEnd((char)0x0D);
return new FTPdirectory(directoryRaw, directory);
}
catch (Exception ex) { errorMessage += "\n" + ex.Message; }
return null;
}
#region "utillity"
/// <summary>
/// Url을 Host와 결합하여 생성
/// </summary>
/// <param name="file">경로명</param>
/// <param name="isfile">파일인지 여부</param>
/// <returns></returns>
string CombineUrl(string file, bool isfile = true)
{
file = file.Replace("\\", "/");
string url = this.Host;
if (this.Host.ToLower().StartsWith("ftp://") == false) url = "ftp://" + url;
if (url.Substring(5).LastIndexOf(':') == -1)
url += ":" + this.Port.ToString();
if (this.Host.EndsWith("/")) url = this.Host.Substring(0, Host.Length - 1);
if (file.StartsWith("/"))
url = url + System.Web.HttpUtility.UrlPathEncode(file);
else
url = url + "/" + System.Web.HttpUtility.UrlPathEncode(file);
url = url.Replace("#", "%23");
if (isfile)
return url;
else
return url + "/";
}
public string PathCombine(string path, string add)
{
var newpath = string.Empty;
if (path.EndsWith("/")) newpath = path + add;
else newpath = path + "/" + add;
if (!newpath.EndsWith("/")) newpath += '/';
return newpath;
}
public string PathFileCombine(string path, string add)
{
var newpath = string.Empty;
if (path.EndsWith("/")) newpath = path + add;
else newpath = path + "/" + add;
if (newpath.EndsWith("/")) newpath = newpath.Substring(0, newpath.Length - 1);
return newpath;
}
public string getParent(string path)
{
if (path == "/") return path;
else if (path == "") return "/";
else
{
//서브폴더를 찾아서 처리해준다.
if (path.IndexOf('/') == -1) return "/";
else
{
if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1);
var slashindex = path.LastIndexOf('/');
var parent = path.Substring(0, slashindex);
if (!parent.EndsWith("/")) parent += '/';
return parent;
}
}
}
public void RaiseMessage(Boolean isError, string message)
{
if (isError) errorMessage = message; //170920
if (Message != null) Message(this, new MessageEventArgs(isError, message));
}
#endregion
}
}

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AR.FTPClient
{
/// <summary>
/// ''' Stores a list of files and directories from an FTP result
/// ''' </summary>
/// ''' <remarks></remarks>
public class FTPdirectory : List<FTPfileInfo>
{
public FTPdirectory()
{
}
/// <summary>
/// ''' Constructor: create list from a (detailed) directory string
/// ''' </summary>
/// ''' <param name="dir">directory listing string</param>
/// ''' <param name="path"></param>
/// ''' <remarks></remarks>
public FTPdirectory(string dir, string path)
{
var lines = dir.Replace("\n","").Split('\r');
foreach (var line in lines)
{
if (line != "")
this.Add(new FTPfileInfo(line, path));
}
}
/// <summary>
/// ''' Filter out only files from directory listing
/// ''' </summary>
/// ''' <param name="ext">optional file extension filter</param>
/// ''' <returns>FTPdirectory listing</returns>
public FTPdirectory GetFiles(string ext = "")
{
return this.GetFileOrDir(FTPfileInfo.DirectoryEntryTypes.File, ext);
}
/// <summary>
/// ''' Returns a list of only subdirectories
/// ''' </summary>
/// ''' <returns>FTPDirectory list</returns>
/// ''' <remarks></remarks>
public FTPdirectory GetDirectories()
{
return this.GetFileOrDir(FTPfileInfo.DirectoryEntryTypes.Directory);
}
// internal: share use function for GetDirectories/Files
private FTPdirectory GetFileOrDir(FTPfileInfo.DirectoryEntryTypes type, string ext = "")
{
FTPdirectory result = new FTPdirectory();
foreach (FTPfileInfo fi in this)
{
if (fi.FileType == type)
{
if (ext == "")
result.Add(fi);
else if (ext == fi.Extension)
result.Add(fi);
}
}
return result;
}
public bool FileExists(string filename)
{
foreach (FTPfileInfo ftpfile in this)
{
if (ftpfile.Filename == filename)
return true;
}
return false;
}
private const char slash = '/';
public static string GetParentDirectory(string dir)
{
string tmp = dir.TrimEnd(slash);
int i = tmp.LastIndexOf(slash);
if (i > 0)
return tmp.Substring(0, i - 1);
else
throw new ApplicationException("No parent for root");
}
}
}

View File

@@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace AR.FTPClient
{
/// <summary>
/// ''' Represents a file or directory entry from an FTP listing
/// ''' </summary>
/// ''' <remarks>
/// ''' This class is used to parse the results from a detailed
/// ''' directory list from FTP. It supports most formats of
/// ''' </remarks>
public class FTPfileInfo
{
// Stores extended info about FTP file
public string FullName
{
get
{
var retval = Path + "/" + Filename;
return retval.Replace("//", "/");
}
}
public string Filename
{
get
{
return _filename;
}
}
public string Path
{
get
{
return _path;
}
}
public DirectoryEntryTypes FileType
{
get
{
return _fileType;
}
}
public long Size
{
get
{
return _size;
}
}
public DateTime FileDateTime
{
get
{
return _fileDateTime;
}
}
public string Permission
{
get
{
return _permission;
}
}
public string Extension
{
get
{
int i = this.Filename.LastIndexOf(".");
if (i >= 0 & i < (this.Filename.Length - 1))
return this.Filename.Substring(i + 1);
else
return "";
}
}
public string NameOnly
{
get
{
int i = this.Filename.LastIndexOf(".");
if (i > 0)
return this.Filename.Substring(0, i);
else
return this.Filename;
}
}
private string _filename;
private string _path;
private DirectoryEntryTypes _fileType;
private long _size;
private DateTime _fileDateTime;
private string _permission;
/// <summary>
/// ''' Identifies entry as either File or Directory
/// ''' </summary>
public enum DirectoryEntryTypes
{
File,
Directory,
Link
}
/// <summary>
/// ''' Constructor taking a directory listing line and path
/// ''' </summary>
/// ''' <param name="line">The line returned from the detailed directory list</param>
/// ''' <param name="path">Path of the directory</param>
/// ''' <remarks></remarks>
public FTPfileInfo(string line, string path)
{
// parse line
Match m = GetMatchingRegex(line);
if (m == null)
// failed
throw new ApplicationException("Unable to parse line: " + line);
else
{
_filename = m.Groups["name"].Value;
_path = path;
_permission = m.Groups["permission"].Value;
string _dir = m.Groups["dir"].Value;
if ((_dir != "" & (_dir == "d" || _dir == "D")))
{
_fileType = DirectoryEntryTypes.Directory;
_size = 0; // CLng(m.Groups("size").Value)
}
else if ((_dir != "" & (_dir == "l" || _dir == "L")))
{
_fileType = DirectoryEntryTypes.Link;
_size = 0; // CLng(m.Groups("size").Value)
}
else
{
_fileType = DirectoryEntryTypes.File;
_size = System.Convert.ToInt64(m.Groups["size"].Value);
}
try
{
var timestamp = m.Groups["timestamp"].Value;
if (timestamp.IndexOf(':') == -1)
{
_fileDateTime = DateTime.Parse(timestamp);
}
else
{
_fileDateTime = DateTime.Parse(DateTime.Now.Year + " " + timestamp);
}
}
catch
{
// MsgBox("datetime err=" & Now.Year & Space(1) & "value=" & m.Groups("timestamp").Value & vbCrLf & ex.Message.ToString)
_fileDateTime = DateTime.Parse("1982-11-23");
}
}
}
public FTPfileInfo(string filename, string permission, string dir, int size, DateTime filetime, Boolean isdir, string path)
{
_filename = filename;// m.Groups["name"].Value;
_path = path;
_permission = permission; // m.Groups["permission"].Value;
string _dir = dir;// m.Groups["dir"].Value;
if (isdir == true)
{
_fileType = DirectoryEntryTypes.Directory;
_size = 0; // CLng(m.Groups("size").Value)
}
else
{
_fileType = DirectoryEntryTypes.File;
_size = size;//
}
_fileDateTime = filetime;
}
private Match GetMatchingRegex(string line)
{
Regex rx;
Match m;
for (int i = 0; i <= _ParseFormats.Length - 1; i++)
{
rx = new Regex(_ParseFormats[i]);
m = rx.Match(line);
if (m.Success)
return m;
}
return null;
}
/// <summary>
/// ''' List of REGEX formats for different FTP server listing formats
/// ''' </summary>
/// ''' <remarks>
/// ''' The first three are various UNIX/LINUX formats, fourth is for MS FTP
/// ''' in detailed mode and the last for MS FTP in 'DOS' mode.
/// ''' I wish VB.NET had support for Const arrays like C# but there you go
/// ''' </remarks>
private static string[] _ParseFormats = new[] { @"(?<dir>[\-dl])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)", @"(?<dir>[\-dl])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)", @"(?<dir>[\-dl])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?<name>.+)", @"(?<dir>[\-dl])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?<name>.+)", @"(?<dir>[\-dl])(?<permission>([\-r][\-w][\-xs]){3})(\s+)(?<size>(\d+))(\s+)(?<ctbit>(\w+\s\w+))(\s+)(?<size2>(\d+))\s+(?<timestamp>\w+\s+\d+\s+\d{2}:\d{2})\s+(?<name>.+)", @"(?<timestamp>\d{2}\-\d{2}\-\d{2}\s+\d{2}:\d{2}[Aa|Pp][mM])\s+(?<dir>\<\w+\>){0,1}(?<size>\d+){0,1}\s+(?<name>.+)" };
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AR.FTPClient
{
public interface IFTPClient
{
void Dispose();
string errorMessage { get; set; }
//string Host { get; set; }
//string UserID { get; set; }
//string UserPassword { get; set; }
//int Port { get; set; }
System.Text.Encoding TextEncoding { get; set; }
Boolean Download(string remoteFile, string localFile,bool overwrite=false);
Boolean Upload(string remoteFile, string localFile);
Boolean Delete(string remotefile);
Boolean rename(string currentFileNameAndPath, string newFileName);
bool createDirectory(string newDirectory);
bool RemoveDirectory(string Directory);
string getFileCreatedDateTime(string fileName);
string getFileSize(string fileName);
string[] directoryListSimple(string directory);
FTPdirectory ListDirectoryDetail(string directory);
event EventHandler<MessageEventArgs> Message;
event EventHandler<ListProgressEventArgs> ListPrgress;
void RaiseMessage(Boolean isError, string message);
string PathCombine(string path, string add);
string PathFileCombine(string path, string add);
string getParent(string path);
}
}

View File

@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project.Class
{
public class JobData
{
public enum ErrorCode
{
None = 0,
BarcodeRead,
Print,
Camera,
}
public ErrorCode error = ErrorCode.None;
public int No { get; set; }
public VisionData VisionData;
public DateTime JobStart
{
get
{
if (this.VisionData == null) return new DateTime(1982, 11, 23);
else return VisionData.STime;
}
}
public DateTime JobEnd;
public TimeSpan JobRun
{
get
{
if (JobEnd.Year == 1982) return new TimeSpan(0);
else if (JobStart.Year == 1982) return new TimeSpan(0);
else return JobEnd - JobStart;
}
}
/// <summary>
/// 프린터에 명령을 전송한 시간
/// </summary>
public DateTime PrintTime { get; set; }
/// <summary>
/// 라벨을 추가한 시간
/// </summary>
public DateTime Attachtime { get; set; }
//작업데이터의 GUID(자료식별)
public string guid { get; private set; }
//언로더포트위치(L/R)
public string PortPos;
//동작관련 메세지
public string Message;
int idx;
public JobData(int idx_)
{
this.idx = idx_;
Clear("INIT");
}
public bool PrintAttach { get; set; }
public bool PrintQRValid { get; set; }
public string PrintQRValidResult { get; set; }
public void Clear(string source)
{
No = 0;
//JobStart = new DateTime(1982, 11, 23);
JobEnd = new DateTime(1982, 11, 23);
Attachtime = new DateTime(1982, 11, 23);
PortPos = string.Empty;
guid = Guid.NewGuid().ToString();
Message = string.Empty;
if (VisionData == null)
VisionData = new VisionData(source);
else
VisionData.Clear(source, false);
PrintAttach = false;
PrintQRValid = false;
PrintQRValidResult = string.Empty;
PrintTime = new DateTime(1982, 11, 23);
PUB.AddDebugLog($"item data {idx} clear by {source} guid={guid}");
}
public void CopyTo(ref JobData obj)
{
if (obj == null) return;
obj.No = this.No;
obj.error = this.error;
obj.JobEnd = this.JobEnd;
obj.guid = this.guid;
obj.PortPos = this.PortPos;
obj.Message = this.Message;
obj.PrintAttach = this.PrintAttach;
obj.PrintQRValid = this.PrintQRValid;
obj.PrintQRValidResult = this.PrintQRValidResult;
obj.Attachtime = this.Attachtime;
obj.PrintTime = this.PrintTime;
PUB.AddDebugLog("Before item copy rid:" + this.VisionData.RID);
this.VisionData.CopyTo(ref obj.VisionData);
PUB.AddDebugLog($"After item copy target rid : {obj.VisionData.RID}, guid={obj.guid}");
}
}
}

View File

@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace Project.Class
{
public class KeyenceBarcodeData
{
public double Angle { get; set; }
public StdLabelPrint.CAmkorSTDBarcode AmkorData { get; set; }
public Point[] vertex { get; set; }
public string Data { get; set; }
public Point CenterPX { get; set; }
public bool Ignore { get; set; }
/// <summary>
/// 1:QR, 11:Code 128(like 1D)
/// </summary>
public string barcodeSymbol { get; set; }
public string barcodeSource { get; set; } //230503
public Boolean UserActive { get; set; }
public Boolean isSTDBarcode
{
get
{
if (AmkorData != null && barcodeSymbol == "1" && AmkorData.isValid) return true;
return false;
}
}
public Boolean isNewLen15
{
get
{
if (AmkorData != null && barcodeSymbol == "1" && AmkorData.isValid && AmkorData.NewLen15Barcode) return true;
return false;
}
}
/// <summary>
/// 라벨의 위치를 표시한다. 8방향이며 키패드 유사하게 설정한다 789/4-6/123
/// </summary>
public byte LabelPosition { get; set; }
/// <summary>
/// 정규식 분석이 완료되었다면 True를 반환합니다
/// </summary>
public Boolean RegExConfirm { get; set; }
public int RefExApply { get; set; }
public KeyenceBarcodeData()
{
LabelPosition = 0;
Angle = 0.0;
Data = string.Empty;
CenterPX = Point.Empty;
AmkorData = null;
vertex = null;
barcodeSymbol = string.Empty;
UserActive = false;
RegExConfirm = false;
Ignore = false;
barcodeSource = string.Empty;
}
public override string ToString()
{
return string.Format("{0},Deg={1},Center={2}x{3}", Data, Angle, CenterPX.X, CenterPX.Y);
}
/// <summary>
/// 해당 중심점이 겹치는지 확인합니다.
/// </summary>
/// <param name="Center"></param>
/// <returns></returns>
public Boolean CheckIntersect(Point Center, string data)
{
if (data == null) return false;
if (data.Equals(this.Data) == false) return false; //자료가 다르면 다른 자료로 처리한다
return getInside(Center, vertex);
}
bool getInside(Point pt, Point[] ptArr)
{
int crosses = 0;
for (int i = 0; i < ptArr.Length; i++)
{
int j = (i + 1) % ptArr.Length;
if ((ptArr[i].Y > pt.Y) != (ptArr[j].Y > pt.Y))
{
//atX는 점 B를 지나는 수평선과 선분 (p[i], p[j])의 교점
double atX = (ptArr[j].X - ptArr[i].X) * (pt.Y - ptArr[i].Y) / (ptArr[j].Y - ptArr[i].Y) + ptArr[i].X;
//atX가 오른쪽 반직선과의 교점이 맞으면 교점의 개수를 증가시킨다.
if (pt.X < atX)
crosses++;
}
}
return crosses % 2 > 0;
}
}
}

View File

@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using AR;
namespace Project
{
public class ModelInfoM
{
//스피드 값과, 위치값을 저장하면 된다.
public int idx { get; set; }
public string Title { get; set; }
public Dictionary<int, PositionData[]> Position { get; set; }
public ModelInfoM()
{
idx = -1;
Title = string.Empty;
ClearDataPosition();
}
void ClearDataPosition()
{
Position = new Dictionary<int, PositionData[]>();
var motCount = Enum.GetNames(typeof(eAxis)).Length;
for (int i = 0; i < motCount; i++)
{
var datas = new PositionData[64];
for (int j = 0; j < datas.Length; j++)
datas[j] = new PositionData(-1, string.Empty, 0.0);
Position.Add(i, datas);
}
}
public Boolean isSet
{
get
{
if (idx == -1) return false;
else return !Title.isEmpty();
}
}
public void ReadValue(DataSet1.MCModelRow dr)
{
idx = dr.idx;
Title = dr.Title;
ReadValuePosition(idx);
}
public void ReadValue(int index)
{
var dr = PUB.mdm.dataSet.MCModel.Where(t => t.idx == index).FirstOrDefault();
if (dr == null)
{
idx = -1;
Title = string.Empty;
ClearDataPosition();
}
else
{
idx = dr.idx;
Title = dr.Title;
ReadValuePosition(idx);
}
}
public Boolean ReadValue(string title)
{
return ReadValue(title, PUB.mdm.dataSet.MCModel);
}
public Boolean ReadValue(string title, DataSet1.MCModelDataTable dt)
{
var dr = dt.Where(t => t.Title == title).FirstOrDefault();
if (dr == null)
{
idx = -1;
this.Title= string.Empty;
ClearDataPosition();
return false;
}
else
{
idx = dr.idx;
this.Title = dr.Title;
ReadValuePosition(idx);
return true;
}
}
public void ReadValuePosition(int modelidx)
{
ReadValuePosition(modelidx, PUB.mdm.dataSet.MCModel);
}
public void ReadValuePosition(int modelidx, DataSet1.MCModelDataTable dt)
{
ClearDataPosition();
//각 모터별로 데이터를 가져온다
int cnt = 0;
foreach (var data in Position)
{
//해당 모터의 속도값을 가져온다
var drows = dt.Where(t => t.pidx == modelidx && t.PosIndex >= 0 && t.MotIndex == data.Key);
foreach (DataSet1.MCModelRow dr in drows)
{
var item = data.Value[dr.PosIndex];
item.index = dr.PosIndex;
item.title = dr.PosTitle;
item.value = dr.Position;
item.speed = dr.Speed;
item.acc = dr.SpeedAcc;
item.dcc = dr.SpeedDcc;
data.Value[dr.PosIndex] = item;
cnt += 1;
}
}
PUB.log.Add(String.Format("Motion({0}) Data Load : {1}", modelidx, cnt));
}
}
}

View File

@@ -0,0 +1,204 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
namespace Project
{
public class ModelInfoV
{
[Browsable(false)]
public string SPN { get; set; }
//[Browsable(false)]
//public Boolean SplitSPN { get; set; }
[Browsable(false)]
public string Title { get; set; }
[Browsable(false)]
public string Code { get; set; }
[Browsable(false)]
public int idx { get; set; }
public string Motion { get; set; }
public Boolean BCD_1D { get; set; }
public Boolean BCD_QR { get; set; }
public Boolean BCD_DM { get; set; }
public UInt16 vOption { get; set; }
public UInt16 vWMSInfo { get; set; }
public UInt16 vSIDInfo { get; set; }
public UInt16 vJobInfo { get; set; }
public UInt16 vSIDConv1 { get; set; }
public string Def_Vname { get; set; }
public string Def_MFG { get; set; }
public Boolean IgnoreOtherBarcode { get; set; }
public bool DisableCamera { get; set; }
public bool DisablePrinter { get; set; }
public bool CheckSIDExsit { get; set; }
public bool bOwnZPL { get; set; }
public int BSave { get; set; }
public bool IgnorePartNo { get; set; }
public bool IgnoreBatch { get; set; }
public int AutoOutConveyor { get; set; }
public ModelInfoV()
{
vOption = vWMSInfo = vSIDInfo = vJobInfo = vSIDConv1 = 0;
bOwnZPL = false;
}
public void ReadValue(DataSet1.OPModelRow dr)
{
this.AutoOutConveyor= dr.AutoOutConveyor;
this.bOwnZPL = dr.bOwnZPL;
this.Title = dr.Title;
this.Code = dr.Code;
this.idx = dr.idx;
this.Motion = dr.Motion;
this.BCD_1D = dr.BCD_1D;
this.BCD_QR = dr.BCD_QR;
this.BCD_DM = dr.BCD_DM;
this.vOption = dr.vOption;
this.vJobInfo = dr.vJobInfo;
this.vWMSInfo = dr.vWMSInfo;
this.vSIDInfo = dr.vSIDInfo;
this.vSIDConv1 = dr.vSIDConv;
this.Def_MFG = dr.Def_MFG;
this.Def_Vname = dr.Def_VName;
this.IgnoreOtherBarcode = dr.IgnoreOtherBarcode;
this.DisableCamera = dr.DisableCamera;
this.DisablePrinter = dr.DisablePrinter;
this.CheckSIDExsit = dr.CheckSIDExsit;
this.BSave = dr.BSave;
this.IgnoreBatch = dr.IgnoreBatch;
this.IgnorePartNo = dr.IgnorePartNo;
}
}
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
public class RoiOffset
{
[DisplayName("Horizon"), Description("Vertical (Y-axis) change value (+ is downward, - is upward)")]
public double Y { get; set; }
[DisplayName("Vertical"), Description("Horizontal (X-axis) change value (+ is right, - is left)")]
public double X { get; set; }
[Browsable(false)]
public bool IsEmpty { get { if (Y == 0 && X == 0) return true; else return false; } }
public RoiOffset(double start = 0.0, double end = 0.0)
{
this.Y = start;
this.X = end;
}
public override string ToString()
{
return string.Format("{0},{1}", Y, X);
}
public string toPointStr()
{
return string.Format("{0};{1}", Y, X);
}
}
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
public class Range
{
[DisplayName("Start Value")]
public uint Start { get; set; }
[DisplayName("End Value")]
public uint End { get; set; }
[Browsable(false)]
public bool IsEmpty { get { if (Start == 0 && End == 0) return true; else return false; } }
public Range(UInt16 start, UInt16 end) : this((uint)start, (uint)end) { }
public Range(uint start = 0, uint end = 0)
{
this.Start = start;
this.End = end;
}
public static implicit operator RangeF(Range p)
{
return new RangeF((float)p.Start, (float)p.End);
}
public override string ToString()
{
return string.Format("{0}~{1}", Start, End);
}
}
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
public class RangeF
{
[DisplayName("Start Value")]
public float Start { get; set; }
[DisplayName("End Value")]
public float End { get; set; }
[Browsable(false)]
public bool IsEmpty { get { if (Start == 0f && End == 0f) return true; else return false; } }
public RangeF(float start = 0f, float end = 0f)
{
this.Start = start;
this.End = end;
}
public static implicit operator Range(RangeF p)
{
return new Range((uint)p.Start, (uint)p.End);
}
public override string ToString()
{
return string.Format("{0}~{1}", Start, End);
}
}
[TypeConverterAttribute(typeof(ExpandableObjectConverter))]
public class CVisionProcess
{
[Category("Special Settings (Developer)"), Description("Unused (was used for DOT recognition)")]
public UInt16 halfKernel { get; set; }
[Category("Special Settings (Developer)"), Description("Unused (was used for DOT recognition)")]
public UInt16 Constant { get; set; }
[Category("Special Settings (Developer)"), DisplayName("MP_Dilate"), Description("Unused (was used for DOT recognition)")]
public UInt16 dilate { get; set; }
[Category("Special Settings (Developer)"), DisplayName("MP_Erode"), Description("Unused (was used for DOT recognition)")]
public UInt16 erode { get; set; }
[Category("Special Settings (Developer)"), DisplayName("MP_Open"), Description("Unused (was used for DOT recognition)")]
public UInt16 open { get; set; }
[Category("Special Settings (Developer)"), DisplayName("MP_Open"), Description("Unused (was used for DOT recognition)")]
public UInt32 segment_threshold { get; set; }
[Category("Special Settings (Developer)"), DisplayName("MP_Open"), Description("Unused (was used for DOT recognition)")]
public Boolean isBlack { get; set; }
[Category("Special Settings (Developer)"), DisplayName("MP_Open"), Description("Unused (was used for DOT recognition)")]
public UInt32 judg_runcount { get; set; }
[Category("Unit Detection"), DisplayName("Brightness Threshold"), Description("Collects data above the entered value. The lower this value, the higher the detection value. Detection is determined by the value detected with this threshold. Since units are determined by looking at bright data, data above this threshold is detected")]
public byte detect_threhosld { get; set; }
[Category("Unit Detection"), DisplayName("Detection Threshold"), Description("This is the threshold value for detection. If the value detected due to the brightness threshold is 5000, and the value entered in this detection threshold is greater than 5000, it is determined that a unit exists. When it is lower, it is detected as an 'Empty' unit with no unit")]
public UInt16 detect_count { get; set; }
[Category("Unit Detection"), DisplayName("*Exception Area Detection Threshold"), Description("When an empty unit (=Empty), if light reflection from the shuttle frame is severe, the unit is detected by the reflection value. This value is used to remove such data, and in addition to the white area values used for unit detection, black blob detection is performed. If a black blob within the set value range is detected, it is detected as an 'Empty' unit")]
public Point detect_blobrange { get; set; }
[Category("2D Detection"), DisplayName("Brightness Threshold"), Description("Collects data below the entered value. The lower this value, the lower the detection value. Detection is determined by the value detected with this threshold. Since 2D codes are determined by looking at dark data, data below this threshold is detected")]
public byte detectDM_threhosld { get; set; }
[Category("2D Detection"), DisplayName("Detection Threshold"), Description("This is the threshold value for detection. If the value detected due to the brightness threshold is 5000, and the value entered in this detection threshold is greater than 5000, it is determined that an ID exists. When it is lower, it is detected as a 'New' unit with no ID")]
public UInt16 detectDM_count { get; set; }
public CVisionProcess()
{
}
public override string ToString()
{
return "Vision Settings";
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project
{
public class PositionData
{
public int index { get; set; }
public string title { get; set; }
public double value { get; set; }
public double speed { get; set; }
public double acc { get; set; }
public double dcc { get; set; }
public PositionData()
{
index = -1;
title = string.Empty;
value = 0.0;
this.speed = 0.0;
this.acc = 100.0;
this.dcc = 0.0;
}
public PositionData(int idx_, string title_, double value_)
{
this.index = idx_;
this.title = title_;
this.value = value_;
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project.Class
{
public class Reel
{
public string SID { get; set; }
public string venderLot { get; set; }
public string mfg { get; set; }
public int qty { get; set; }
public string id { get; set; }
//public string date { get; set; }
public string PartNo { get; set; }
public string venderName { get; set; }
public Reel()
{
Clear();
}
public void Clear()
{
SID = string.Empty;
venderLot = string.Empty;
mfg = string.Empty;
venderLot = string.Empty;
id = string.Empty;
//date = string.Empty;
PartNo = string.Empty;
venderName = string.Empty;
qty = 0;
}
public Reel(string _sid, string _lot, string _manu, int _qty, string _id, string _mfgdate, string _partnum)
{
int sidNum = 0;
if (int.TryParse(_sid, out sidNum) && sidNum.ToString().Length == 9)
SID = sidNum.ToString();
else
throw new Exception("SID is not a number or not a 9-digit number.");
venderLot = _lot;
mfg = _mfgdate;
qty = _qty;
id = _id;
PartNo = _partnum;
venderName = _manu;
}
public Reel(string qrbarcodestr)
{
var spData = qrbarcodestr.Split(';');
if (spData.Length < 6)
throw new Exception("Barcode length is insufficient.");
SID = spData[0];
venderLot = spData[1];
venderName = spData[2];
int _qty = 0;
if (int.TryParse(spData[3], out _qty))
qty = _qty;
else
throw new Exception("Quantity field does not contain numeric information.");
id = spData[4];
mfg = spData[5];
if (spData.Length > 6) PartNo = spData[6];
else PartNo = string.Empty;
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project.Class
{
public class RegexPattern
{
public string Customer { get; set; }
public string Pattern { get; set; }
public string Description { get; set; }
public bool IsTrust { get; set; }
public bool IsAmkStd { get; set; }
public Boolean IsEnable { get; set; }
public RegexGroupMatch[] Groups { get; set; }
public string Symbol { get; set; }
public int Seq { get; set; }
public RegexPattern()
{
Seq = 0;
Groups = null;
Pattern = string.Empty;
Description = string.Empty;
Customer = string.Empty;
IsTrust = false;
IsAmkStd = false;
Symbol = string.Empty;
}
}
public class RegexGroupMatch
{
/// <summary>
/// 1~
/// </summary>
public int GroupNo { get; set; }
/// <summary>
/// RID,SID,VLOT,MFG,PART,QTY,CUST,CUSTCODE,VNAME,
/// </summary>
public string TargetPos { get; set; }
public RegexGroupMatch()
{
GroupNo = 0;
TargetPos = string.Empty;
}
}
}

View File

@@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project.Class
{
public enum eStatusMesage : byte
{
Front = 0,
Rear,
TopJig,
Main,
}
public class StatusMessage
{
Dictionary<eStatusMesage, StatusMessageFormat> message;
public StatusMessage()
{
this.message = new Dictionary<eStatusMesage, StatusMessageFormat>();
}
public StatusMessageFormat get(eStatusMesage msg)
{
lock (this.message)
{
if (this.message.ContainsKey(msg) == false)
{
var nemsg = new StatusMessageFormat
{
Message = string.Empty
};
this.message.Add(msg, nemsg);
return nemsg;
}
else
return this.message[msg];
}
}
public void Clear()
{
}
public void set(eStatusMesage msg, StatusMessageFormat data)
{
lock (this.message)
{
if (this.message.ContainsKey(msg) == false)
this.message.Add(msg, data);
else
this.message[msg] = data;
}
}
public void set(eStatusMesage msg, string data, int progval = 0, int progmax = 0)
{
if (data.StartsWith("[") && data.Contains("]"))
{
var buf = data.Split(']');
var cate = buf[0].Substring(1);
var body = string.Join("]", buf, 1, buf.Length - 1);
set(msg, cate, body, Color.Black, progval, progmax);
}
else set(msg, string.Empty, data, Color.Black, progval, progmax);
}
//public void set(eStatusMesage msg, string cate, string data, int progval = 0, int progmax = 0)
//{
// set(msg, cate, data, Color.Black, progval, progmax);
//}
public void set(eStatusMesage msg, string cate, string data, Color fColor, int progval = 0, int progmax = 0)
{
lock (this.message)
{
if (this.message.ContainsKey(msg) == false)
{
var nemsg = new StatusMessageFormat
{
Category = cate,
Message = data,
fColor = fColor,
ProgressMax = progmax,
ProgressValue = progval
};
this.message.Add(msg, nemsg);
}
else
{
var m = this.message[msg];
m.Category = cate;
m.Message = data;
m.fColor = fColor;
if (progval != 0 || progmax != 0)
{
m.ProgressValue = progval;
m.ProgressMax = progmax;
}
}
}
}
public void set(eStatusMesage msg, string data, Color fColor, Color bColor1, Color bColor2)
{
lock (this.message)
{
if (this.message.ContainsKey(msg) == false)
{
var nemsg = new StatusMessageFormat
{
Message = data,
fColor = fColor,
bColor1 = bColor1,
bColor2 = bColor2
};
this.message.Add(msg, nemsg);
}
else
{
var m = this.message[msg];
m.Message = data;
m.fColor = fColor;
m.bColor2 = bColor2;
m.bColor1 = bColor1;
}
}
}
}
public class StatusMessageFormat
{
public string Category { get; set; }
public string Message { get; set; }
public Color fColor { get; set; }
public Color bColor1 { get; set; }
public Color bColor2 { get; set; }
public int ProgressValue { get; set; }
public int ProgressMax { get; set; }
public int ProgressPerc
{
get
{
if (ProgressMax == 0 || ProgressValue == 0) return 0;
return (int)(ProgressValue / (ProgressMax * 1.0));
}
}
public StatusMessageFormat()
{
Clear();
}
void setMessage(string t, string m, Color c)
{
this.Category = t;
this.Message = m;
this.fColor = c;
}
void setMessage(string m, Color c)
{
this.Category = string.Empty;
this.Message = m;
this.fColor = c;
}
public void Clear()
{
ProgressValue = 0;
ProgressMax = 0;
Category = string.Empty;
Message = string.Empty;
fColor = Color.Black;
bColor1 = Color.White;
bColor2 = Color.White;
}
}
}

View File

@@ -0,0 +1,877 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using AR;
namespace Project.Class
{
public class VisionData : INotifyPropertyChanged
{
public int RetryLoader { get; set; }
public Dictionary<int,string> bcdMessage { get; set; }
public Boolean LightOn { get; set; }
public DateTime STime; //비젼시작시간
public DateTime ETime; //비젼종료시간
public TimeSpan RunTime { get { return ETime - STime; } } //비젼동작시간
public DateTime GTime; //이미지수집시간
public string FileNameL; //로딩존 촬영
public string FileNameU; //언로딩존 촬영
public Boolean Complete;
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine($"SID:{SID}:{(SID_Trust ? "O" : "X")}");
sb.AppendLine($"RID:{RID}:{(RID_Trust ? "O" : "X")}");
sb.AppendLine($"LOT:{VLOT}:{(VLOT_Trust ? "O" : "X")}");
sb.AppendLine($"QTY:{QTY}:{(QTY_Trust ? "O" : "X")}");
sb.AppendLine($"BAT:{BATCH}");
sb.AppendLine($"MFG:{MFGDATE}:{(MFGDATE_Trust ? "O" : "X")}");
sb.AppendLine($"CPN:{PARTNO}:{(PARTNO_Trust ? "O" : "X")}");
sb.AppendLine($"RID2:{RID2}");
sb.AppendLine($"RIDNew:{RIDNew}");
sb.AppendLine($"SID0:{SID0}");
return sb.ToString();
}
//public Boolean AngleQR { get; set; }
//public Boolean AngleSTD { get; set; }
//public double Angle { get; set; }
//public Boolean IsAngleSet
//{
// get
// {
// if (AngleQR == false && AngleSTD == false && Angle == 0.0) return true;
// else return false;
// }
//}
/// <summary>
/// 부착위치에따른 추가회전
/// </summary>
public double PositionAngle { get; set; }
public double ApplyAngle { get; set; } //적용된 회전 각도
public Boolean NeedCylinderForward { get; set; } //부착시 실린더를 올려야하는가
public Boolean ApplyOffset { get; set; }
public Boolean BaseAngle(out string msg, out KeyenceBarcodeData bcd)
{
msg = string.Empty;
bcd = null;
//데이터없다면 회전하지 못한다.
if (this.barcodelist == null || this.barcodelist.Count < 1)
{
msg = "No barcode data";
return false;
}
//사용자가 확정한 코드를 우선으로 한다
KeyValuePair<string, Class.KeyenceBarcodeData> bcddata;
var bcdCanList = barcodelist.Where(t => t.Value.Ignore == false).ToList();
bcddata = bcdCanList.Where(t => t.Value.UserActive).FirstOrDefault();
if (bcddata.Value != null)
{
bcd = bcddata.Value;
msg = "User Active";
return true;
}
//표준바코드를 최우선 으로 사용
//15자리 기존 바코드는 angle 로 사용하지 않는다.
//이것은 각도가 일정치 않게 붙어지기 때문이다
bcddata = bcdCanList.Where(t => t.Value.isSTDBarcode && t.Value.isNewLen15 == false).FirstOrDefault();
if (bcddata.Value != null)
{
bcd = bcddata.Value;
msg = "STD Barcode";
return true;
}
//실제사용한 데이터 우선한다.
bcddata = bcdCanList.OrderByDescending(t=>t.Value.RefExApply).FirstOrDefault();
if (bcddata.Value != null && bcddata.Value.RefExApply > 0)
{
bcd = bcddata.Value;
msg = $"Used Data({bcddata.Value.RefExApply})";
return true;
}
//QR코드를 우선으로 사용 - return 릴은 적용하지 안게한다.
//RQ코드가 적용되지 않게한다 210824
bcddata = bcdCanList.Where(t => t.Value.barcodeSymbol == "1" && t.Value.isNewLen15 == false && t.Value.Data.EndsWith(";;;") == false && t.Value.Data.StartsWith("RQ") == false).FirstOrDefault();
if (bcddata.Value != null)
{
bcd = bcddata.Value;
msg = "QR Code";
return true;
}
//datamatrix, pdf417
bcddata = bcdCanList.Where(t => t.Value.barcodeSymbol != "11" && t.Value.barcodeSymbol != "6" && t.Value.Data.StartsWith("RQ") == false).FirstOrDefault();
if (bcddata.Value != null)
{
bcd = bcddata.Value;
return true;
}
//첫번쨰 아이템을 우선으로 사용
if (bcdCanList.Count == 1)
{
bcd = bcdCanList.First().Value;
msg = "Only One Barcode = " + bcd.Data;
return true;
}
else if (bcdCanList.Count > 1)
{
//여러개가 있음
bcddata = bcdCanList.Where(t => t.Value.barcodeSymbol == "0").FirstOrDefault();
if (bcd != null)
{
bcd = bcddata.Value;
msg = "1D Data";
return true;
}
else
{
bcd = bcdCanList.First().Value;//[0];
msg = $"first({bcd.barcodeSymbol}:{bcd.Data})";
return true;
}
}
else
{
bcd = null;
msg = "no data";
return false;
}
// angle = bcd.Angle;
//return true;
} //모션회전각도
public Boolean Ready { get; set; }
public Boolean ServerUpdate { get; set; }
public Boolean Confirm
{
get
{
return ConfirmAuto || ConfirmUser || ConfirmBypass;
}
}
public Boolean ConfirmUser { get; set; }
public Boolean ConfirmAuto { get; set; }
public bool ConfirmBypass { get; set; }
public Boolean ValidSkipbyUser { get; set; }
private string _rid = string.Empty;
private string _qty = string.Empty;
private string _qty0 = string.Empty;
private string _sid0 = string.Empty;
private string _sid = string.Empty;
private string _rid0 = string.Empty;
private string _vlot = string.Empty;
private string _vname = string.Empty;
private string _mfgdate = string.Empty;
private string _partno = string.Empty;
private string _custcode = string.Empty;
private string _custname = string.Empty;
private string _batch = string.Empty;
private string _qtymax = string.Empty;
private string _mcn = string.Empty;
public bool SID_Trust { get; set; }
public bool RID_Trust { get; set; }
public bool VLOT_Trust { get; set; }
public bool MFGDATE_Trust { get; set; }
public bool QTY_Trust { get; set; }
public bool PARTNO_Trust { get; set; }
public bool VNAME_Trust { get; set; }
public string Target { get; set; }
public string MCN
{
get { return _mcn; }
set { _mcn = value; OnPropertyChanged(); }
}
/// <summary>
/// Original QTY
/// </summary>
public string QTY0
{
get { return _qty0; }
set { _qty0 = value; OnPropertyChanged(); }
}
/// <summary>
/// Qty
/// </summary>
public string QTY
{
get { return _qty; }
set { _qty = value; OnPropertyChanged(); }
}
/// <summary>
/// QTY값이 RQ에서 입력된 데이터인가?
/// </summary>
public Boolean QTYRQ { get; set; }
public string RID0
{
get { return _rid0; }
set { _rid0 = value; OnPropertyChanged(); }
}
public string VLOT
{
get { return _vlot; }
set { _vlot = value; OnPropertyChanged(); }
}
public string VNAME
{
get { return _vname; }
set { _vname = value; OnPropertyChanged(); }
}
public string MFGDATE
{
get { return _mfgdate; }
set { _mfgdate = value; OnPropertyChanged(); }
}
public string PARTNO
{
get { return _partno; }
set { _partno = value; OnPropertyChanged(); }
}
/// <summary>
/// Original SID
/// </summary>
public string SID0
{
get { return _sid0; }
set { _sid0 = value; OnPropertyChanged(); }
}
public string BATCH
{
get
{
return _batch;
}
set
{
_batch = value; OnPropertyChanged();
}
}
public string QTYMAX
{
get
{
return _qtymax;
}
set
{
_qtymax = value; OnPropertyChanged();
}
}
public string SID
{
get { return _sid; }
set { _sid = value; OnPropertyChanged(); }
}
private void OnPropertyChanged([CallerMemberName] string caller = "")
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(caller));
}
/// <summary>
/// Reel ID
/// </summary>
public string RID
{
get { return _rid; }
private set { _rid = value; OnPropertyChanged(); }
}
/// <summary>
/// 릴 ID를 설정합니다.trust 상태를 자동으로 true 값으로 전환합니다
/// </summary>
/// <param name="value"></param>
/// <param name="reason"></param>
public void SetRID(string value, string reason)
{
//값이 변경될때 로그에 변경
if (_rid.Equals(value) == false)
{
PUB.AddDebugLog(string.Format("RID Changed {0} -> {1} by {2}", _rid, value, reason));
}
RID = value;
RID_Trust = true;
}
public Boolean RIDNew { get; set; }
public Boolean HASHEADER { get; set; }
public string CUSTCODE
{
get { return _custcode; }
set { _custcode = value; OnPropertyChanged(); }
}
public string CUSTNAME
{
get { return _custname; }
set { _custname = value; OnPropertyChanged(); }
}
/// <summary>
/// 데이터가 모두존재하는지 확인
/// </summary>
public Boolean DataValid
{
get
{
if (Confirm == false) return false;
return QTY.isEmpty() == false &&
SID.isEmpty() == false &&
RID.isEmpty() == false &&
VLOT.isEmpty() == false &&
VNAME.isEmpty() == false &&
MFGDATE.isEmpty() == false &&
PARTNO.isEmpty();
}
}
public Boolean PrintPositionCheck { get; set; }
public string PrintPositionData { get; set; }
//상단위치에 프린트를 할것인가?
//프린트위치에 따른다
public ePrintPutPos GetPrintPutPosition()
{
//하단에 찍는경우이다
if (PrintPositionData == "1" ||
PrintPositionData == "2" ||
PrintPositionData == "3")
{
return ePrintPutPos.Bottom;
}
else if (PrintPositionData == "7" ||
PrintPositionData == "8" ||
PrintPositionData == "9")
{
return ePrintPutPos.Top;
}
else if (PrintPositionData == "4") //왼쪽
{
if (ReelSize == eCartSize.Inch7)
return ePrintPutPos.Top;
else
return ePrintPutPos.Middle;
}
else if (PrintPositionData == "6") //오른쪽
{
if (ReelSize == eCartSize.Inch7)
return ePrintPutPos.Top;
else
return ePrintPutPos.Middle;
}
else return ePrintPutPos.None;
}
//public string LabelPos { get; set; }
//public Boolean PrintForce { get; set; }
public eCartSize ReelSize { get; set; }
public string QTY2 { get; set; } //바코드수량
public string SID2 { get; set; } //바코드
public string RID2 { get; set; } //바코드
public string VLOT2 { get; set; }
public string VNAME2 { get; set; }
public string MFGDATE2 { get; set; }
public string PARTNO2 { get; set; }
public System.Drawing.Color GetColorByBarcodeCount(int idx)
{
if (QRPositionData[idx] > 0) return Color.Gold; //QR데이터가있다면 금색으로 한다
var Cnt = LabelPositionData[idx];
if (Cnt == MaxBarcodePosData) return Color.Purple;
else if (Cnt == 0) return Color.FromArgb(32, 32, 32);
{
//나머진 숫자별로 데이터를 표시한다 (
var GValue = Cnt * 10;
if (GValue > 255) GValue = 255;
return Color.FromArgb(32, 32, GValue);
}
}
public Boolean isMaxBarcodePosition(int idx)
{
return LabelPositionData[idx] == MaxBarcodePosData;
}
public byte[] QRPositionData { get; private set; }
public byte[] LabelPositionData { get; private set; }
/// <summary>
/// keyence barcodeparse 같은데에서 분석한 자료를 이곳에 추가합니다.
/// 이 데이터는 SPS에서 처리완료됩니다.
/// </summary>
public ConcurrentDictionary<String, Class.KeyenceBarcodeData> barcodelist;
/// <summary>
/// keyence 로 부터 신규 바코드가 업데이트되었다
/// </summary>
public Boolean BarcodeTouched = false;
public event PropertyChangedEventHandler PropertyChanged;
//리더기로부터 읽은 자료 모두가 들어잇다
//public List<Class.KeyenceBarcodeData> barcodelist
//{
// get { return _barcodelist; }
// set
// {
// this._barcodelist = value;
// UpdateBarcodePositionData();
// }
//}
public byte MaxBarcodePosData { get; private set; }
/// <summary>
/// 바코드목록을 이용해서 라벨위치 분포값을 변경합낟.
/// 해당 위치값은 labelposdata로 접근가능함
/// </summary>
public void UpdateBarcodePositionData()
{
LabelPositionData[0] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 1).Count();
LabelPositionData[1] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 2).Count();
LabelPositionData[2] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 3).Count();
LabelPositionData[3] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 4).Count();
LabelPositionData[4] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 6).Count();
LabelPositionData[5] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 7).Count();
LabelPositionData[6] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 8).Count();
LabelPositionData[7] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 9).Count();
QRPositionData[0] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 1 && t.Value.AmkorData.isValid).Count();
QRPositionData[1] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 2 && t.Value.AmkorData.isValid).Count();
QRPositionData[2] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 3 && t.Value.AmkorData.isValid).Count();
QRPositionData[3] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 4 && t.Value.AmkorData.isValid).Count();
QRPositionData[4] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 6 && t.Value.AmkorData.isValid).Count();
QRPositionData[5] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 7 && t.Value.AmkorData.isValid).Count();
QRPositionData[6] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 8 && t.Value.AmkorData.isValid).Count();
QRPositionData[7] = (byte)barcodelist.Where(t => t.Value.LabelPosition == 9 && t.Value.AmkorData.isValid).Count();
MaxBarcodePosData = LabelPositionData.Max(t => t);
}
/// <summary>
/// Data1(인쇄전 인식데이터) 과 Data2(QR)가 동일한지 비교합니다.
/// </summary>
public Boolean MatchValidation
{
get
{
if (PARTNO == null) this.PARTNO = string.Empty;
if (PARTNO2 == null) this.PARTNO2 = string.Empty;
if (QTY == null) QTY = string.Empty;
if (QTY2 == null) QTY2 = string.Empty;
if (SID == null) SID = string.Empty;
if (SID2 == null) SID2 = string.Empty;
if (VLOT == null) VLOT = string.Empty;
if (VLOT2 == null) VLOT2 = string.Empty;
if (PARTNO == null) PARTNO = string.Empty;
if (PARTNO2 == null) PARTNO2 = string.Empty;
if (QTY.Equals(QTY2) == false)
{
PUB.log.AddE(string.Format("QR Validation Failed Quantity:{0} != {1}", QTY, QTY2));
return false;
}
if (RID.Equals(RID2) == false)
{
PUB.log.AddE(string.Format("QR Validation Failed RID:{0} != {1}", RID, RID2));
return false;
}
if (VLOT.Equals(VLOT2) == false)
{
PUB.log.AddE(string.Format("QR Validation Failed VLOT:{0} != {1}", VLOT, VLOT2));
return false;
}
if (PARTNO.Equals(PARTNO2) == false)
{
PUB.log.AddE(string.Format("QR Validation Failed PARTNO:{0} != {1}", PARTNO, PARTNO2));
return false;
}
if (SID.Equals(SID2) == false)
{
PUB.log.AddE(string.Format("QR Validation Failed SID:{0} != {1}", SID, SID2));
return false;
}
return true;
}
}
public string QRInputRaw { get; set; } //입력에 사용한 RAW
public string QROutRaw { get; set; } //부착된 QR코드의 값
public string ZPL { get; set; } //출력시 사용한 ZPL
public string PrintQRData { get; set; } //출력시 사용한 ZPL에 포함된 QR데이터
public string LastQueryStringSID = string.Empty;
public string LastQueryStringWMS = string.Empty;
public string LastQueryStringCNV = string.Empty;
public string LastQueryStringJOB = string.Empty;
public VisionData(string reason)
{
Clear(reason, false);
}
public Boolean isEmpty()
{
return RID.isEmpty();
}
public void Clear(string reason, Boolean timeBackup)
{
LastQueryStringSID = string.Empty;
LastQueryStringWMS = string.Empty;
LastQueryStringCNV = string.Empty;
LastQueryStringJOB = string.Empty;
RetryLoader = 0;
ApplyOffset = false;
var baktime = new DateTime(1982, 11, 23);
if (timeBackup) baktime = this.STime;
bcdMessage = new Dictionary<int, string>();
PositionAngle = 0;
HASHEADER = false;
CUSTCODE = string.Empty;
CUSTNAME = string.Empty;
RID0 = string.Empty;
RIDNew = false;
LightOn = false;
//SCODE = string.Empty;
ValidSkipbyUser = false;
NeedCylinderForward = false;
ApplyAngle = 0;
MaxBarcodePosData = 0;
PrintPositionCheck = false;
LabelPositionData = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
QRPositionData = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
ReelSize = eCartSize.None;
// PrintForce = false;
ConfirmAuto = false;
ConfirmUser = false;
ConfirmBypass = false;
ServerUpdate = false;
PrintPositionData = "";
//LabelPos = "";
if (barcodelist != null) barcodelist.Clear();
else barcodelist = new ConcurrentDictionary<string, KeyenceBarcodeData>();
QRInputRaw = string.Empty;
QROutRaw = string.Empty;
ZPL = string.Empty;
PrintQRData = string.Empty;
STime = baktime;// DateTime.Parse("1982-11-23");
ETime = DateTime.Parse("1982-11-23");
GTime = DateTime.Parse("1982-11-23");
Complete = false;
//Angle = 0.0;
//AngleQR = false;
//AngleSTD = false;
MCN = string.Empty;
Target = string.Empty;
Ready = false;
QTY0 = string.Empty;
QTY = string.Empty;// string.Empty;
QTYRQ = false;
//PUB.log.AddI($"비젼개체 CLEAR 로 RQ 상태 초기화(false)");
BATCH = string.Empty;
QTYMAX = string.Empty;
SID0 = string.Empty;
SID = string.Empty;
//RID = string.Empty;
SetRID(string.Empty, reason);
VLOT = string.Empty;
MFGDATE = string.Empty;
VNAME = string.Empty;
PARTNO = string.Empty;
QTY2 = "0";// string.Empty;
SID2 = string.Empty;
RID2 = string.Empty;
VLOT2 = string.Empty;
MFGDATE2 = string.Empty;
VNAME2 = string.Empty;
PARTNO2 = string.Empty;
FileNameL = string.Empty;
FileNameU = string.Empty;
MFGDATE_Trust = false;
PARTNO_Trust = false;
QTY_Trust = false;
SID_Trust = false;
RID_Trust = false;
VLOT_Trust = false;
VNAME_Trust = false;
BarcodeTouched = false;
MCN = string.Empty;
Target = string.Empty;
PUB.log.Add($"Vision Data Deleted ({reason})");
}
public void CopyTo(ref VisionData obj)
{
//바코드메세지 복사
obj.bcdMessage = new Dictionary<int, string>();
foreach (var item in this.bcdMessage)
obj.bcdMessage.Add(item.Key, item.Value);
obj.ApplyOffset = this.ApplyOffset;
obj.ConfirmAuto = this.ConfirmAuto;
obj.ConfirmUser = this.ConfirmUser;
obj.CUSTCODE = this.CUSTCODE;
obj.CUSTNAME = this.CUSTNAME;
obj.LightOn = this.LightOn;
//obj.SCODE = this.SCODE;
obj.ValidSkipbyUser = this.ValidSkipbyUser;
obj.NeedCylinderForward = this.NeedCylinderForward; //210207
obj.ApplyAngle = this.ApplyAngle; //210207
obj.STime = this.STime;
obj.ETime = this.ETime;
obj.GTime = this.GTime;
obj.FileNameL = this.FileNameL;
obj.FileNameU = this.FileNameU;
obj.Complete = this.Complete;
//obj.Angle = this.Angle;
//obj.AngleQR = this.AngleQR;
//obj.AngleSTD = this.AngleSTD;
obj.BATCH = this.BATCH;
obj.QTYMAX = this.QTYMAX;
obj.Ready = this.Ready;
obj.QTY = this.QTY;
obj.QTYRQ = this.QTYRQ;
obj.SID = this.SID;
obj.SID0 = this.SID0; //210331
obj.SetRID(this.RID, "copy");// obj.RID = this.RID;
obj.RID0 = this.RID0;
obj.RIDNew = this.RIDNew;
obj.VLOT = this.VLOT;
obj.VNAME = this.VNAME;
obj.MFGDATE = this.MFGDATE;
obj.PARTNO = this.PARTNO;
obj.MCN = this.MCN;
obj.Target = this.Target;
obj.QTY2 = this.QTY2;
obj.SID2 = this.SID2;
obj.RID2 = this.RID2;
obj.VLOT2 = this.VLOT2;
obj.VNAME2 = this.VNAME2;
obj.MFGDATE2 = this.MFGDATE;
obj.PARTNO2 = this.PARTNO2;
obj.QRInputRaw = this.QRInputRaw;
obj.QROutRaw = this.QROutRaw;
obj.ZPL = this.ZPL;
obj.PrintQRData = this.PrintQRData;
obj.PrintPositionData = this.PrintPositionData;
//obj.PrintForce = this.PrintForce;
obj.ReelSize = this.ReelSize;
obj.PrintPositionCheck = this.PrintPositionCheck;
obj.BarcodeTouched = this.BarcodeTouched;
//라벨위치값 복사
for (int i = 0; i < obj.LabelPositionData.Length; i++)
obj.LabelPositionData[i] = this.LabelPositionData[i];
for (int i = 0; i < obj.QRPositionData.Length; i++)
obj.QRPositionData[i] = this.QRPositionData[i];
//바코드 데이터를 복사해준다.
if (obj.barcodelist == null)
obj.barcodelist = new ConcurrentDictionary<string, KeyenceBarcodeData>();// List<KeyenceBarcodeData>();
else
obj.barcodelist.Clear();
foreach (var item in this.barcodelist)
{
var bcd = item.Value;
var newitema = new KeyenceBarcodeData
{
Angle = bcd.Angle,
CenterPX = new Point(bcd.CenterPX.X, bcd.CenterPX.Y),
Data = bcd.Data,
LabelPosition = bcd.LabelPosition,
UserActive = bcd.UserActive,
barcodeSymbol = bcd.barcodeSymbol,
};
newitema.vertex = new Point[bcd.vertex.Length];
bcd.vertex.CopyTo(newitema.vertex, 0);
if (bcd.AmkorData != null) //231006 null error fix
bcd.AmkorData.CopyTo(newitema.AmkorData);
obj.barcodelist.AddOrUpdate(item.Key, newitema,
(key, data) =>
{
data.Angle = newitema.Angle;
data.CenterPX = newitema.CenterPX;
data.Data = newitema.Data;
data.LabelPosition = newitema.LabelPosition;
data.UserActive = newitema.UserActive;
data.barcodeSymbol = newitema.barcodeSymbol;
data.RegExConfirm = newitema.RegExConfirm;
return data;
});
}
}
public void UpdateTo(ref VisionData obj)
{
//바코드메세지 복사
obj.bcdMessage = new Dictionary<int, string>();
foreach (var item in this.bcdMessage)
obj.bcdMessage.Add(item.Key, item.Value);
obj.ApplyOffset = this.ApplyOffset;
obj.ConfirmAuto = this.ConfirmAuto;
obj.ConfirmUser = this.ConfirmUser;
obj.CUSTCODE = this.CUSTCODE;
obj.CUSTNAME = this.CUSTNAME;
obj.LightOn = this.LightOn;
//obj.SCODE = this.SCODE;
obj.ValidSkipbyUser = this.ValidSkipbyUser;
obj.NeedCylinderForward = this.NeedCylinderForward; //210207
obj.ApplyAngle = this.ApplyAngle; //210207
obj.STime = this.STime;
obj.ETime = this.ETime;
obj.GTime = this.GTime;
obj.FileNameL = this.FileNameL;
obj.FileNameU = this.FileNameU;
obj.Complete = this.Complete;
//obj.Angle = this.Angle;
//obj.AngleQR = this.AngleQR;
//obj.AngleSTD = this.AngleSTD;
obj.Ready = this.Ready;
obj.QTY = this.QTY;
obj.QTYRQ = this.QTYRQ;
obj.SID = this.SID;
obj.SID0 = this.SID0; //210331
obj.SetRID(this.RID, "copy");// obj.RID = this.RID;
obj.RID0 = this.RID0;
obj.RIDNew = this.RIDNew;
obj.VLOT = this.VLOT;
obj.VNAME = this.VNAME;
obj.MFGDATE = this.MFGDATE;
obj.PARTNO = this.PARTNO;
obj.MCN = this.MCN;
obj.Target = this.Target;
obj.BATCH = this.BATCH;
obj.QTYMAX = this.QTYMAX;
obj.QTY2 = this.QTY2;
obj.SID2 = this.SID2;
obj.RID2 = this.RID2;
obj.VLOT2 = this.VLOT2;
obj.VNAME2 = this.VNAME2;
obj.MFGDATE2 = this.MFGDATE;
obj.PARTNO2 = this.PARTNO2;
obj.QRInputRaw = this.QRInputRaw;
obj.QROutRaw = this.QROutRaw;
obj.ZPL = this.ZPL;
obj.PrintQRData = this.PrintQRData;
obj.PrintPositionData = this.PrintPositionData;
//obj.PrintForce = this.PrintForce;
obj.ReelSize = this.ReelSize;
obj.PrintPositionCheck = this.PrintPositionCheck;
obj.BarcodeTouched = this.BarcodeTouched;
//라벨위치값 복사
for (int i = 0; i < obj.LabelPositionData.Length; i++)
obj.LabelPositionData[i] = this.LabelPositionData[i];
for (int i = 0; i < obj.QRPositionData.Length; i++)
obj.QRPositionData[i] = this.QRPositionData[i];
//바코드 데이터를 복사해준다.
if (obj.barcodelist == null)
obj.barcodelist = new ConcurrentDictionary<string, KeyenceBarcodeData>();// List<KeyenceBarcodeData>();
else
obj.barcodelist.Clear();
foreach (var item in this.barcodelist)
{
var bcd = item.Value;
var newitema = new KeyenceBarcodeData
{
Angle = bcd.Angle,
CenterPX = new Point(bcd.CenterPX.X, bcd.CenterPX.Y),
Data = bcd.Data,
LabelPosition = bcd.LabelPosition,
UserActive = bcd.UserActive,
barcodeSymbol = bcd.barcodeSymbol,
};
newitema.vertex = new Point[bcd.vertex.Length];
bcd.vertex.CopyTo(newitema.vertex, 0);
bcd.AmkorData.CopyTo(newitema.AmkorData);
obj.barcodelist.AddOrUpdate(item.Key, newitema,
(key, data) =>
{
data.Angle = newitema.Angle;
data.CenterPX = newitema.CenterPX;
data.Data = newitema.Data;
data.LabelPosition = newitema.LabelPosition;
data.UserActive = newitema.UserActive;
data.barcodeSymbol = newitema.barcodeSymbol;
data.RegExConfirm = newitema.RegExConfirm;
return data;
});
}
}
}
}

View File

@@ -0,0 +1,86 @@
using System;
namespace Project
{
[Serializable]
public class sPositionData
{
public float inpositionrange { get; set; }
public short Axis;
public double Position { get; set; }
public double Acc;
public double _dcc;
public double Dcc
{
get
{
if (_dcc == 0) return Acc;
else return _dcc;
}
set
{
_dcc = value;
}
}
public double Speed;
public Boolean isError { get { return Speed == 0; } }
public string Message;
public sPositionData(sPositionData baseData)
{
this.Clear();
this.Position = baseData.Position;
this.Acc = baseData.Acc;
this.Dcc = baseData.Dcc;
this._dcc = baseData._dcc;
this.Speed = baseData.Speed;
this.Axis = baseData.Axis;
this.Message = baseData.Message;
this.inpositionrange = baseData.inpositionrange;
}
public sPositionData Clone()
{
return new sPositionData
{
Position = this.Position,
Acc = this.Acc,
Dcc = this.Dcc,
//isError = this.isError,
Message = this.Message,
Speed = this.Speed,
_dcc = this.Dcc,
Axis = this.Axis,
inpositionrange = this.inpositionrange,
};
}
public sPositionData()
{
Clear();
}
public sPositionData(double pos)
{
Clear();
this.Position = pos;
}
//public void SetPosition(double pos) { this.Position = pos; }
public void Clear()
{
Axis = -1;
inpositionrange = 0f;
Position = 0;
Acc = 500;
_dcc = 0;
Speed = 0;
Message = "Not Set";
}
public override string ToString()
{
return $"Pos:{Position},Spd:{Speed}";
}
}
}

2556
Handler/Project/DSList.Designer.cs generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
namespace Project
{
partial class DSList
{
}
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!--<autogenerated>
This code was generated by a tool.
Changes to this file may cause incorrect behavior and will be lost if
the code is regenerated.
</autogenerated>-->
<DataSetUISetting Version="1.00" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
<TableUISettings />
</DataSetUISetting>

183
Handler/Project/DSList.xsd Normal file
View File

@@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="DSList" targetNamespace="http://tempuri.org/DSList.xsd" xmlns:mstns="http://tempuri.org/DSList.xsd" xmlns="http://tempuri.org/DSList.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:msprop="urn:schemas-microsoft-com:xml-msprop" attributeFormDefault="qualified" elementFormDefault="qualified">
<xs:annotation>
<xs:appinfo source="urn:schemas-microsoft-com:xml-msdatasource">
<DataSource DefaultConnectionIndex="0" FunctionsComponentName="QueriesTableAdapter" Modifier="AutoLayout, AnsiClass, Class, Public" SchemaSerializationMode="IncludeSchema" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
<Connections>
<Connection AppSettingsObjectName="Settings" AppSettingsPropertyName="CS" ConnectionStringObject="" IsAppSettingsProperty="true" Modifier="Assembly" Name="CS (Settings)" ParameterPrefix="@" PropertyReference="ApplicationSettings.Project.Properties.Settings.GlobalReference.Default.CS" Provider="System.Data.SqlClient" />
</Connections>
<Tables>
<TableAdapter BaseClass="System.ComponentModel.Component" DataAccessorModifier="AutoLayout, AnsiClass, Class, Public" DataAccessorName="K4EE_Component_Reel_CustRuleTableAdapter" GeneratorDataComponentClassName="K4EE_Component_Reel_CustRuleTableAdapter" Name="K4EE_Component_Reel_CustRule" UserDataComponentName="K4EE_Component_Reel_CustRuleTableAdapter">
<MainSource>
<DbSource ConnectionRef="CS (Settings)" DbObjectName="WMS.dbo.K4EE_Component_Reel_CustRule" DbObjectType="Table" FillMethodModifier="Public" FillMethodName="Fill" GenerateMethods="Both" GenerateShortCommands="true" GeneratorGetMethodName="GetData" GeneratorSourceName="Fill" GetMethodModifier="Public" GetMethodName="GetData" QueryType="Rowset" ScalarCallRetval="System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" UseOptimisticConcurrency="true" UserGetMethodName="GetData" UserSourceName="Fill">
<DeleteCommand>
<DbCommand CommandType="Text" ModifiedByUser="true">
<CommandText>DELETE FROM [K4EE_Component_Reel_CustRule] WHERE (([code] = @Original_code) AND ((@IsNull_pre = 1 AND [pre] IS NULL) OR ([pre] = @Original_pre)) AND ((@IsNull_pos = 1 AND [pos] IS NULL) OR ([pos] = @Original_pos)) AND ((@IsNull_len = 1 AND [len] IS NULL) OR ([len] = @Original_len)) AND ((@IsNull_exp = 1 AND [exp] IS NULL) OR ([exp] = @Original_exp)))</CommandText>
<Parameters>
<Parameter AllowDbNull="false" AutogeneratedName="Original_code" ColumnName="code" DataSourceName="WMS.dbo.K4EE_Component_Reel_CustRule" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@Original_code" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="code" SourceColumnNullMapping="false" SourceVersion="Original" />
<Parameter AllowDbNull="true" AutogeneratedName="IsNull_pre" ColumnName="" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@IsNull_pre" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="" SourceColumnNullMapping="true" SourceVersion="Original" />
<Parameter AllowDbNull="false" AutogeneratedName="Original_pre" ColumnName="" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@Original_pre" Precision="0" Scale="0" Size="1024" SourceColumn="" SourceColumnNullMapping="false" SourceVersion="Original" />
<Parameter AllowDbNull="true" AutogeneratedName="IsNull_pos" ColumnName="" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@IsNull_pos" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="" SourceColumnNullMapping="true" SourceVersion="Original" />
<Parameter AllowDbNull="false" AutogeneratedName="Original_pos" ColumnName="" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@Original_pos" Precision="0" Scale="0" Size="1024" SourceColumn="" SourceColumnNullMapping="false" SourceVersion="Original" />
<Parameter AllowDbNull="true" AutogeneratedName="IsNull_len" ColumnName="" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@IsNull_len" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="" SourceColumnNullMapping="true" SourceVersion="Original" />
<Parameter AllowDbNull="false" AutogeneratedName="Original_len" ColumnName="" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@Original_len" Precision="0" Scale="0" Size="1024" SourceColumn="" SourceColumnNullMapping="false" SourceVersion="Original" />
<Parameter AllowDbNull="true" AutogeneratedName="IsNull_exp" ColumnName="" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@IsNull_exp" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="" SourceColumnNullMapping="true" SourceVersion="Original" />
<Parameter AllowDbNull="false" AutogeneratedName="Original_exp" ColumnName="" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@Original_exp" Precision="0" Scale="0" Size="1024" SourceColumn="" SourceColumnNullMapping="false" SourceVersion="Original" />
</Parameters>
</DbCommand>
</DeleteCommand>
<InsertCommand>
<DbCommand CommandType="Text" ModifiedByUser="false">
<CommandText>INSERT INTO [K4EE_Component_Reel_CustRule] ([code], [MatchEx], [MatchIndex], [GroupIndex], [ReplaceEx], [ReplaceStr], [varName], [Remark]) VALUES (@code, @MatchEx, @MatchIndex, @GroupIndex, @ReplaceEx, @ReplaceStr, @varName, @Remark);
SELECT idx, code, MatchEx, MatchIndex, GroupIndex, ReplaceEx, ReplaceStr, varName, Remark FROM K4EE_Component_Reel_CustRule WHERE (idx = SCOPE_IDENTITY())</CommandText>
<Parameters>
<Parameter AllowDbNull="false" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@code" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="code" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="true" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@MatchEx" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="MatchEx" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="true" AutogeneratedName="" DataSourceName="" DbType="Int32" Direction="Input" ParameterName="@MatchIndex" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="MatchIndex" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="true" AutogeneratedName="" DataSourceName="" DbType="Int32" Direction="Input" ParameterName="@GroupIndex" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="GroupIndex" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="true" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@ReplaceEx" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ReplaceEx" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="true" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@ReplaceStr" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="ReplaceStr" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="true" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@varName" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="varName" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="true" AutogeneratedName="" DataSourceName="" DbType="AnsiString" Direction="Input" ParameterName="@Remark" Precision="0" ProviderType="VarChar" Scale="0" Size="0" SourceColumn="Remark" SourceColumnNullMapping="false" SourceVersion="Current" />
</Parameters>
</DbCommand>
</InsertCommand>
<SelectCommand>
<DbCommand CommandType="Text" ModifiedByUser="false">
<CommandText>SELECT idx, code, MatchEx, MatchIndex, GroupIndex, ReplaceEx, ReplaceStr, varName, Remark
FROM K4EE_Component_Reel_CustRule</CommandText>
<Parameters />
</DbCommand>
</SelectCommand>
<UpdateCommand>
<DbCommand CommandType="Text" ModifiedByUser="true">
<CommandText>UPDATE [K4EE_Component_Reel_CustRule] SET [code] = @code, [pre] = @pre, [pos] = @pos, [len] = @len, [exp] = @exp WHERE (([code] = @Original_code) AND ((@IsNull_pre = 1 AND [pre] IS NULL) OR ([pre] = @Original_pre)) AND ((@IsNull_pos = 1 AND [pos] IS NULL) OR ([pos] = @Original_pos)) AND ((@IsNull_len = 1 AND [len] IS NULL) OR ([len] = @Original_len)) AND ((@IsNull_exp = 1 AND [exp] IS NULL) OR ([exp] = @Original_exp)));
SELECT code, pre, pos, len, exp FROM K4EE_Component_Reel_CustRule WHERE (code = @code)</CommandText>
<Parameters>
<Parameter AllowDbNull="false" AutogeneratedName="code" ColumnName="code" DataSourceName="WMS.dbo.K4EE_Component_Reel_CustRule" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@code" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="code" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="false" AutogeneratedName="pre" ColumnName="pre" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@pre" Precision="0" Scale="0" Size="1024" SourceColumn="pre" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="false" AutogeneratedName="pos" ColumnName="pos" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@pos" Precision="0" Scale="0" Size="1024" SourceColumn="pos" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="false" AutogeneratedName="len" ColumnName="len" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@len" Precision="0" Scale="0" Size="1024" SourceColumn="len" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="false" AutogeneratedName="exp" ColumnName="exp" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@exp" Precision="0" Scale="0" Size="1024" SourceColumn="exp" SourceColumnNullMapping="false" SourceVersion="Current" />
<Parameter AllowDbNull="false" AutogeneratedName="Original_code" ColumnName="code" DataSourceName="WMS.dbo.K4EE_Component_Reel_CustRule" DataTypeServer="varchar(10)" DbType="AnsiString" Direction="Input" ParameterName="@Original_code" Precision="0" ProviderType="VarChar" Scale="0" Size="10" SourceColumn="code" SourceColumnNullMapping="false" SourceVersion="Original" />
<Parameter AllowDbNull="true" AutogeneratedName="IsNull_pre" ColumnName="" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@IsNull_pre" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="pre" SourceColumnNullMapping="true" SourceVersion="Original" />
<Parameter AllowDbNull="false" AutogeneratedName="Original_pre" ColumnName="pre" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@Original_pre" Precision="0" Scale="0" Size="1024" SourceColumn="pre" SourceColumnNullMapping="false" SourceVersion="Original" />
<Parameter AllowDbNull="true" AutogeneratedName="IsNull_pos" ColumnName="" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@IsNull_pos" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="pos" SourceColumnNullMapping="true" SourceVersion="Original" />
<Parameter AllowDbNull="false" AutogeneratedName="Original_pos" ColumnName="pos" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@Original_pos" Precision="0" Scale="0" Size="1024" SourceColumn="pos" SourceColumnNullMapping="false" SourceVersion="Original" />
<Parameter AllowDbNull="true" AutogeneratedName="IsNull_len" ColumnName="" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@IsNull_len" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="len" SourceColumnNullMapping="true" SourceVersion="Original" />
<Parameter AllowDbNull="false" AutogeneratedName="Original_len" ColumnName="len" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@Original_len" Precision="0" Scale="0" Size="1024" SourceColumn="len" SourceColumnNullMapping="false" SourceVersion="Original" />
<Parameter AllowDbNull="true" AutogeneratedName="IsNull_exp" ColumnName="" DataSourceName="" DataTypeServer="int" DbType="Int32" Direction="Input" ParameterName="@IsNull_exp" Precision="0" ProviderType="Int" Scale="0" Size="0" SourceColumn="exp" SourceColumnNullMapping="true" SourceVersion="Original" />
<Parameter AllowDbNull="false" AutogeneratedName="Original_exp" ColumnName="exp" DataSourceName="" DataTypeServer="unknown" DbType="Object" Direction="Input" ParameterName="@Original_exp" Precision="0" Scale="0" Size="1024" SourceColumn="exp" SourceColumnNullMapping="false" SourceVersion="Original" />
</Parameters>
</DbCommand>
</UpdateCommand>
</DbSource>
</MainSource>
<Mappings>
<Mapping SourceColumn="code" DataSetColumn="code" />
<Mapping SourceColumn="idx" DataSetColumn="idx" />
<Mapping SourceColumn="MatchEx" DataSetColumn="MatchEx" />
<Mapping SourceColumn="MatchIndex" DataSetColumn="MatchIndex" />
<Mapping SourceColumn="GroupIndex" DataSetColumn="GroupIndex" />
<Mapping SourceColumn="ReplaceEx" DataSetColumn="ReplaceEx" />
<Mapping SourceColumn="ReplaceStr" DataSetColumn="ReplaceStr" />
<Mapping SourceColumn="varName" DataSetColumn="varName" />
<Mapping SourceColumn="Remark" DataSetColumn="Remark" />
</Mappings>
<Sources />
</TableAdapter>
</Tables>
<Sources />
</DataSource>
</xs:appinfo>
</xs:annotation>
<xs:element name="DSList" msdata:IsDataSet="true" msdata:UseCurrentLocale="true" msprop:Generator_UserDSName="DSList" msprop:EnableTableAdapterManager="true" msprop:Generator_DataSetName="DSList">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Supply" msprop:Generator_RowEvHandlerName="SupplyRowChangeEventHandler" msprop:Generator_RowDeletedName="SupplyRowDeleted" msprop:Generator_RowDeletingName="SupplyRowDeleting" msprop:Generator_RowEvArgName="SupplyRowChangeEvent" msprop:Generator_TablePropName="Supply" msprop:Generator_RowChangedName="SupplyRowChanged" msprop:Generator_UserTableName="Supply" msprop:Generator_RowChangingName="SupplyRowChanging" msprop:Generator_RowClassName="SupplyRow" msprop:Generator_TableClassName="SupplyDataTable" msprop:Generator_TableVarName="tableSupply">
<xs:complexType>
<xs:sequence>
<xs:element name="TITLE" msprop:Generator_ColumnPropNameInTable="TITLEColumn" msprop:Generator_ColumnPropNameInRow="TITLE" msprop:Generator_UserColumnName="TITLE" msprop:Generator_ColumnVarNameInTable="columnTITLE" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SIDConvert" msprop:Generator_RowEvHandlerName="SIDConvertRowChangeEventHandler" msprop:Generator_RowDeletedName="SIDConvertRowDeleted" msprop:Generator_RowDeletingName="SIDConvertRowDeleting" msprop:Generator_RowEvArgName="SIDConvertRowChangeEvent" msprop:Generator_TablePropName="SIDConvert" msprop:Generator_RowChangedName="SIDConvertRowChanged" msprop:Generator_UserTableName="SIDConvert" msprop:Generator_RowChangingName="SIDConvertRowChanging" msprop:Generator_RowClassName="SIDConvertRow" msprop:Generator_TableClassName="SIDConvertDataTable" msprop:Generator_TableVarName="tableSIDConvert">
<xs:complexType>
<xs:sequence>
<xs:element name="SID101" msprop:Generator_ColumnPropNameInTable="SID101Column" msprop:Generator_ColumnPropNameInRow="SID101" msprop:Generator_UserColumnName="SID101" msprop:Generator_ColumnVarNameInTable="columnSID101" type="xs:string" />
<xs:element name="SID103" msprop:Generator_ColumnPropNameInTable="SID103Column" msprop:Generator_ColumnPropNameInRow="SID103" msprop:Generator_UserColumnName="SID103" msprop:Generator_ColumnVarNameInTable="columnSID103" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="K4EE_Component_Reel_CustRule" msprop:Generator_RowEvHandlerName="K4EE_Component_Reel_CustRuleRowChangeEventHandler" msprop:Generator_RowDeletedName="K4EE_Component_Reel_CustRuleRowDeleted" msprop:Generator_RowDeletingName="K4EE_Component_Reel_CustRuleRowDeleting" msprop:Generator_RowEvArgName="K4EE_Component_Reel_CustRuleRowChangeEvent" msprop:Generator_TablePropName="K4EE_Component_Reel_CustRule" msprop:Generator_RowChangedName="K4EE_Component_Reel_CustRuleRowChanged" msprop:Generator_UserTableName="K4EE_Component_Reel_CustRule" msprop:Generator_RowChangingName="K4EE_Component_Reel_CustRuleRowChanging" msprop:Generator_RowClassName="K4EE_Component_Reel_CustRuleRow" msprop:Generator_TableClassName="K4EE_Component_Reel_CustRuleDataTable" msprop:Generator_TableVarName="tableK4EE_Component_Reel_CustRule">
<xs:complexType>
<xs:sequence>
<xs:element name="code" msprop:Generator_ColumnPropNameInTable="codeColumn" msprop:Generator_ColumnPropNameInRow="code" msprop:Generator_UserColumnName="code" msprop:Generator_ColumnVarNameInTable="columncode">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="10" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="idx" msdata:ReadOnly="true" msdata:AutoIncrement="true" msdata:AutoIncrementSeed="-1" msdata:AutoIncrementStep="-1" msprop:Generator_ColumnPropNameInTable="idxColumn" msprop:Generator_ColumnPropNameInRow="idx" msprop:Generator_UserColumnName="idx" msprop:Generator_ColumnVarNameInTable="columnidx" type="xs:int" />
<xs:element name="MatchEx" msprop:Generator_ColumnPropNameInTable="MatchExColumn" msprop:Generator_ColumnPropNameInRow="MatchEx" msprop:Generator_UserColumnName="MatchEx" msprop:Generator_ColumnVarNameInTable="columnMatchEx" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="200" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="MatchIndex" msprop:Generator_ColumnPropNameInTable="MatchIndexColumn" msprop:Generator_ColumnPropNameInRow="MatchIndex" msprop:Generator_UserColumnName="MatchIndex" msprop:Generator_ColumnVarNameInTable="columnMatchIndex" type="xs:int" minOccurs="0" />
<xs:element name="GroupIndex" msprop:Generator_ColumnPropNameInTable="GroupIndexColumn" msprop:Generator_ColumnPropNameInRow="GroupIndex" msprop:Generator_UserColumnName="GroupIndex" msprop:Generator_ColumnVarNameInTable="columnGroupIndex" type="xs:int" minOccurs="0" />
<xs:element name="ReplaceEx" msprop:Generator_ColumnPropNameInTable="ReplaceExColumn" msprop:Generator_ColumnPropNameInRow="ReplaceEx" msprop:Generator_UserColumnName="ReplaceEx" msprop:Generator_ColumnVarNameInTable="columnReplaceEx" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="200" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="ReplaceStr" msprop:Generator_ColumnPropNameInTable="ReplaceStrColumn" msprop:Generator_ColumnPropNameInRow="ReplaceStr" msprop:Generator_UserColumnName="ReplaceStr" msprop:Generator_ColumnVarNameInTable="columnReplaceStr" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="200" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="varName" msprop:Generator_ColumnPropNameInTable="varNameColumn" msprop:Generator_ColumnPropNameInRow="varName" msprop:Generator_UserColumnName="varName" msprop:Generator_ColumnVarNameInTable="columnvarName" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="50" />
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="Remark" msprop:Generator_ColumnPropNameInTable="RemarkColumn" msprop:Generator_ColumnPropNameInRow="Remark" msprop:Generator_UserColumnName="Remark" msprop:Generator_ColumnVarNameInTable="columnRemark" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="255" />
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:unique name="Constraint1" msdata:PrimaryKey="true">
<xs:selector xpath=".//mstns:Supply" />
<xs:field xpath="mstns:TITLE" />
</xs:unique>
<xs:unique name="SIDConvert_Constraint1" msdata:ConstraintName="Constraint1" msdata:PrimaryKey="true">
<xs:selector xpath=".//mstns:SIDConvert" />
<xs:field xpath="mstns:SID101" />
<xs:field xpath="mstns:SID103" />
</xs:unique>
<xs:unique name="K4EE_Component_Reel_CustRule_Constraint1" msdata:ConstraintName="Constraint1" msdata:PrimaryKey="true">
<xs:selector xpath=".//mstns:K4EE_Component_Reel_CustRule" />
<xs:field xpath="mstns:code" />
</xs:unique>
<xs:unique name="Constraint2">
<xs:selector xpath=".//mstns:K4EE_Component_Reel_CustRule" />
<xs:field xpath="mstns:idx" />
</xs:unique>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--<autogenerated>
This code was generated by a tool to store the dataset designer's layout information.
Changes to this file may cause incorrect behavior and will be lost if
the code is regenerated.
</autogenerated>-->
<DiagramLayout xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ex:showrelationlabel="False" ViewPortX="0" ViewPortY="28" xmlns:ex="urn:schemas-microsoft-com:xml-msdatasource-layout-extended" xmlns="urn:schemas-microsoft-com:xml-msdatasource-layout">
<Shapes>
<Shape ID="DesignTable:K4EE_Component_Reel_CustRule" ZOrder="1" X="511" Y="141" Height="172" Width="300" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="121" />
<Shape ID="DesignTable:Supply" ZOrder="3" X="120" Y="87" Height="48" Width="150" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="44" />
<Shape ID="DesignTable:SIDConvert" ZOrder="2" X="316" Y="82" Height="67" Width="150" AdapterExpanded="true" DataTableExpanded="true" OldAdapterHeight="0" OldDataTableHeight="0" SplitterPosition="63" />
</Shapes>
<Connectors />
</DiagramLayout>

1099
Handler/Project/DSSetup.Designer.cs generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!--<autogenerated>
This code was generated by a tool.
Changes to this file may cause incorrect behavior and will be lost if
the code is regenerated.
</autogenerated>-->
<DataSetUISetting Version="1.00" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
<TableUISettings />
</DataSetUISetting>

Some files were not shown because too many files have changed in this diff Show More