initial commit
This commit is contained in:
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal 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
24
FrontEnd/.gitignore
vendored
Normal 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
224
FrontEnd/App.tsx
Normal 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
20
FrontEnd/README.md
Normal 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
10
FrontEnd/build.bat
Normal 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
289
FrontEnd/communication.ts
Normal 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();
|
||||||
39
FrontEnd/components/CameraPanel.tsx
Normal file
39
FrontEnd/components/CameraPanel.tsx
Normal 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>
|
||||||
|
);
|
||||||
50
FrontEnd/components/IOPanel.tsx
Normal file
50
FrontEnd/components/IOPanel.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
181
FrontEnd/components/InitializeModal.tsx
Normal file
181
FrontEnd/components/InitializeModal.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
633
FrontEnd/components/Machine3D.tsx
Normal file
633
FrontEnd/components/Machine3D.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
58
FrontEnd/components/ModelInfoPanel.tsx
Normal file
58
FrontEnd/components/ModelInfoPanel.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
67
FrontEnd/components/MotionPanel.tsx
Normal file
67
FrontEnd/components/MotionPanel.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
119
FrontEnd/components/RecipePanel.tsx
Normal file
119
FrontEnd/components/RecipePanel.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
166
FrontEnd/components/SettingsModal.tsx
Normal file
166
FrontEnd/components/SettingsModal.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
29
FrontEnd/components/common/CyberPanel.tsx
Normal file
29
FrontEnd/components/common/CyberPanel.tsx
Normal 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>
|
||||||
|
);
|
||||||
19
FrontEnd/components/common/PanelHeader.tsx
Normal file
19
FrontEnd/components/common/PanelHeader.tsx
Normal 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>
|
||||||
|
);
|
||||||
54
FrontEnd/components/common/TechButton.tsx
Normal file
54
FrontEnd/components/common/TechButton.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
31
FrontEnd/components/layout/Footer.tsx
Normal file
31
FrontEnd/components/layout/Footer.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
101
FrontEnd/components/layout/Header.tsx
Normal file
101
FrontEnd/components/layout/Header.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
61
FrontEnd/components/layout/Layout.tsx
Normal file
61
FrontEnd/components/layout/Layout.tsx
Normal 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
108
FrontEnd/index.css
Normal 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
197
FrontEnd/index.html
Normal 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
22
FrontEnd/index.tsx
Normal 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
7
FrontEnd/metadata.json
Normal 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
3556
FrontEnd/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
35
FrontEnd/package.json
Normal file
35
FrontEnd/package.json
Normal 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
163
FrontEnd/pages/HomePage.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
125
FrontEnd/pages/IOMonitorPage.tsx
Normal file
125
FrontEnd/pages/IOMonitorPage.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
245
FrontEnd/pages/RecipePage.tsx
Normal file
245
FrontEnd/pages/RecipePage.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
||||||
6
FrontEnd/postcss.config.js
Normal file
6
FrontEnd/postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
3
FrontEnd/run.bat
Normal file
3
FrontEnd/run.bat
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@echo off
|
||||||
|
echo Starting Frontend Dev Server...
|
||||||
|
call npm run dev
|
||||||
59
FrontEnd/tailwind.config.js
Normal file
59
FrontEnd/tailwind.config.js
Normal 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
22
FrontEnd/tsconfig.json
Normal 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" }]
|
||||||
|
}
|
||||||
10
FrontEnd/tsconfig.node.json
Normal file
10
FrontEnd/tsconfig.node.json
Normal 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
77
FrontEnd/types.ts
Normal 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
20
FrontEnd/vite.config.ts
Normal 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,
|
||||||
|
}
|
||||||
|
});
|
||||||
14
Handler/.claude/settings.local.json
Normal file
14
Handler/.claude/settings.local.json
Normal 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
9
Handler/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.pdb
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
desktop.ini
|
||||||
|
.vs
|
||||||
|
packages
|
||||||
|
*.zip
|
||||||
99
Handler/CLAUDE.md
Normal file
99
Handler/CLAUDE.md
Normal 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
BIN
Handler/DLL/ArLog.Net4.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/CarlosAg.ExcelXmlWriter.dll
Normal file
BIN
Handler/DLL/CarlosAg.ExcelXmlWriter.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/ChilkatDotNet4.dll
Normal file
BIN
Handler/DLL/ChilkatDotNet4.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/Communication.dll
Normal file
BIN
Handler/DLL/Communication.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/Keyence.AutoID.SDK.dll
Normal file
BIN
Handler/DLL/Keyence.AutoID.SDK.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/Newtonsoft.Json.dll
Normal file
BIN
Handler/DLL/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/Sato/x64/SATOPrinterAPI.dll
Normal file
BIN
Handler/DLL/Sato/x64/SATOPrinterAPI.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/Sato/x86/SATOPrinterAPI.dll
Normal file
BIN
Handler/DLL/Sato/x86/SATOPrinterAPI.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/VncClientControlCommon.dll
Normal file
BIN
Handler/DLL/VncClientControlCommon.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/VncClientControlCommonLib.dll
Normal file
BIN
Handler/DLL/VncClientControlCommonLib.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/WatsonWebsocket.dll
Normal file
BIN
Handler/DLL/WatsonWebsocket.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/Winsock Orcas.dll
Normal file
BIN
Handler/DLL/Winsock Orcas.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/arControl.Net4.dll
Normal file
BIN
Handler/DLL/arControl.Net4.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/arRS232.Net4.dll
Normal file
BIN
Handler/DLL/arRS232.Net4.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/libxl.dll
Normal file
BIN
Handler/DLL/libxl.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/libxl.net.dll
Normal file
BIN
Handler/DLL/libxl.net.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/libxl/bin64/libxl.dll
Normal file
BIN
Handler/DLL/libxl/bin64/libxl.dll
Normal file
Binary file not shown.
BIN
Handler/DLL/libxl/libxl.net.dll
Normal file
BIN
Handler/DLL/libxl/libxl.net.dll
Normal file
Binary file not shown.
BIN
Handler/MotParam/Mot_Picker_X.swpp
Normal file
BIN
Handler/MotParam/Mot_Picker_X.swpp
Normal file
Binary file not shown.
256
Handler/MotParam/Mot_Picker_X.usrs
Normal file
256
Handler/MotParam/Mot_Picker_X.usrs
Normal 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
|
||||||
BIN
Handler/MotParam/Mot_Picker_Z.swpp
Normal file
BIN
Handler/MotParam/Mot_Picker_Z.swpp
Normal file
Binary file not shown.
256
Handler/MotParam/Mot_Picker_Z.usrs
Normal file
256
Handler/MotParam/Mot_Picker_Z.usrs
Normal 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
|
||||||
BIN
Handler/MotParam/Mot_Printer_Y.swpp
Normal file
BIN
Handler/MotParam/Mot_Printer_Y.swpp
Normal file
Binary file not shown.
256
Handler/MotParam/Mot_Printer_Y.usrs
Normal file
256
Handler/MotParam/Mot_Printer_Y.usrs
Normal 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
|
||||||
BIN
Handler/MotParam/Mot_Printer_Z.swpp
Normal file
BIN
Handler/MotParam/Mot_Printer_Z.swpp
Normal file
Binary file not shown.
256
Handler/MotParam/Mot_Printer_Z.usrs
Normal file
256
Handler/MotParam/Mot_Printer_Z.usrs
Normal 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
|
||||||
BIN
Handler/MotParam/Mot_Theta.swpp
Normal file
BIN
Handler/MotParam/Mot_Theta.swpp
Normal file
Binary file not shown.
256
Handler/MotParam/Mot_Theta.usrs
Normal file
256
Handler/MotParam/Mot_Theta.usrs
Normal 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
|
||||||
12
Handler/Project/Button/AIR.cs
Normal file
12
Handler/Project/Button/AIR.cs
Normal 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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
86
Handler/Project/Button/RESET.cs
Normal file
86
Handler/Project/Button/RESET.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
81
Handler/Project/Button/START.cs
Normal file
81
Handler/Project/Button/START.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
Handler/Project/Button/STOP.cs
Normal file
49
Handler/Project/Button/STOP.cs
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
168
Handler/Project/Class/CHistoryJOB.cs
Normal file
168
Handler/Project/Class/CHistoryJOB.cs
Normal 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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
//}
|
||||||
|
}
|
||||||
134
Handler/Project/Class/CHistorySIDRef.cs
Normal file
134
Handler/Project/Class/CHistorySIDRef.cs
Normal 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) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
546
Handler/Project/Class/CResult.cs
Normal file
546
Handler/Project/Class/CResult.cs
Normal 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();
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
459
Handler/Project/Class/Command.cs
Normal file
459
Handler/Project/Class/Command.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
393
Handler/Project/Class/EEMStatus.cs
Normal file
393
Handler/Project/Class/EEMStatus.cs
Normal 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
|
||||||
|
//*/
|
||||||
689
Handler/Project/Class/EnumData.cs
Normal file
689
Handler/Project/Class/EnumData.cs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
95
Handler/Project/Class/Enum_MotPosition.cs
Normal file
95
Handler/Project/Class/Enum_MotPosition.cs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
31
Handler/Project/Class/FTP/EventArgs.cs
Normal file
31
Handler/Project/Class/FTP/EventArgs.cs
Normal 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_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
574
Handler/Project/Class/FTP/FTPClient.cs
Normal file
574
Handler/Project/Class/FTP/FTPClient.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
95
Handler/Project/Class/FTP/FTPdirectory.cs
Normal file
95
Handler/Project/Class/FTP/FTPdirectory.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
216
Handler/Project/Class/FTP/FTPfileInfo.cs
Normal file
216
Handler/Project/Class/FTP/FTPfileInfo.cs
Normal 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>.+)" };
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Handler/Project/Class/FTP/IFTPClient.cs
Normal file
34
Handler/Project/Class/FTP/IFTPClient.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
118
Handler/Project/Class/ItemData.cs
Normal file
118
Handler/Project/Class/ItemData.cs
Normal 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}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
105
Handler/Project/Class/KeyenceBarcodeData.cs
Normal file
105
Handler/Project/Class/KeyenceBarcodeData.cs
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
131
Handler/Project/Class/ModelInfoM.cs
Normal file
131
Handler/Project/Class/ModelInfoM.cs
Normal 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
204
Handler/Project/Class/ModelInfoV.cs
Normal file
204
Handler/Project/Class/ModelInfoV.cs
Normal 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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
34
Handler/Project/Class/PositionData.cs
Normal file
34
Handler/Project/Class/PositionData.cs
Normal 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_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
74
Handler/Project/Class/Reel.cs
Normal file
74
Handler/Project/Class/Reel.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
Handler/Project/Class/RegexPattern.cs
Normal file
52
Handler/Project/Class/RegexPattern.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
184
Handler/Project/Class/StatusMessage.cs
Normal file
184
Handler/Project/Class/StatusMessage.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
877
Handler/Project/Class/VisionData.cs
Normal file
877
Handler/Project/Class/VisionData.cs
Normal 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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
Handler/Project/Class/sPositionData.cs
Normal file
86
Handler/Project/Class/sPositionData.cs
Normal 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
2556
Handler/Project/DSList.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
8
Handler/Project/DSList.cs
Normal file
8
Handler/Project/DSList.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Project
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
partial class DSList
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
9
Handler/Project/DSList.xsc
Normal file
9
Handler/Project/DSList.xsc
Normal 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
183
Handler/Project/DSList.xsd
Normal 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>
|
||||||
14
Handler/Project/DSList.xss
Normal file
14
Handler/Project/DSList.xss
Normal 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
1099
Handler/Project/DSSetup.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
Handler/Project/DSSetup.xsc
Normal file
9
Handler/Project/DSSetup.xsc
Normal 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
Reference in New Issue
Block a user