...
This commit is contained in:
6
App.tsx
6
App.tsx
@@ -180,9 +180,9 @@ const App: React.FC = () => {
|
||||
}, [addLog]);
|
||||
|
||||
// Tag Transmission Logic
|
||||
const sendTag = useCallback((tagId: string) => {
|
||||
const sendTag = useCallback((tagId: string | number) => {
|
||||
if (agvSerialRef.current) {
|
||||
const paddedId = tagId.padStart(6, '0').slice(-6);
|
||||
const paddedId = String(tagId).padStart(6, '0').slice(-6);
|
||||
const encoder = new TextEncoder();
|
||||
const cmdBytes = encoder.encode("TAG");
|
||||
const valBytes = encoder.encode(paddedId);
|
||||
@@ -704,7 +704,7 @@ const App: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = 1; // Default AGV ID
|
||||
const id = 0; // Default ACS ID = 0
|
||||
const len = 1 + 1 + payload.length; // ID + CMD + DATA
|
||||
const buffer = [0x02, len, id, cmd, ...payload];
|
||||
|
||||
|
||||
1800
NewMap.json
1800
NewMap.json
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@ interface AcsControlsProps {
|
||||
const AcsControls: React.FC<AcsControlsProps> = ({ onSend, isConnected, mapData }) => {
|
||||
const [tagId, setTagId] = useState('0001');
|
||||
const [alias, setAlias] = useState('charger1');
|
||||
const [targetId, setTargetId] = useState<number>(11); // Default Target ID
|
||||
|
||||
const PRESET_ALIASES = [
|
||||
'charger1', 'charger2',
|
||||
@@ -21,15 +22,16 @@ const AcsControls: React.FC<AcsControlsProps> = ({ onSend, isConnected, mapData
|
||||
const availableTags = useMemo(() => {
|
||||
// Extract unique, non-empty RFID tags from map nodes
|
||||
const tags = mapData.nodes
|
||||
.filter(n => n.rfidId && n.rfidId.trim() !== '')
|
||||
.map(n => n.rfidId);
|
||||
.filter(n => n.rfidId && String(n.rfidId).trim() !== '')
|
||||
.map(n => String(n.rfidId));
|
||||
return Array.from(new Set(tags)).sort();
|
||||
}, [mapData]);
|
||||
|
||||
const handleSend = (cmd: number, dataStr?: string, dataByte?: number) => {
|
||||
if (!isConnected) return;
|
||||
|
||||
let payload: number[] = [];
|
||||
// Payload always starts with Target ID
|
||||
let payload: number[] = [targetId];
|
||||
|
||||
if (dataStr !== undefined) {
|
||||
// Convert string to ASCII bytes
|
||||
@@ -50,6 +52,31 @@ const AcsControls: React.FC<AcsControlsProps> = ({ onSend, isConnected, mapData
|
||||
<span className="text-[10px] bg-gray-900 px-1.5 py-0.5 rounded text-gray-500 border border-gray-700">EXT CMD</span>
|
||||
</h3>
|
||||
|
||||
{/* Target ID Selection */}
|
||||
<div className="flex items-center gap-2 mb-3 bg-gray-900 p-2 rounded border border-gray-700">
|
||||
<span className="text-xs text-gray-400">Target AGV:</span>
|
||||
<label className="flex items-center gap-1 cursor-pointer">
|
||||
<input
|
||||
type="radio"
|
||||
name="targetId"
|
||||
checked={targetId === 11}
|
||||
onChange={() => setTargetId(11)}
|
||||
className="text-green-500 focus:ring-0"
|
||||
/>
|
||||
<span className={`text-xs ${targetId === 11 ? 'text-green-400 font-bold' : 'text-gray-500'}`}>ID 11</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-1 cursor-pointer">
|
||||
<input
|
||||
type="radio"
|
||||
name="targetId"
|
||||
checked={targetId === 12}
|
||||
onChange={() => setTargetId(12)}
|
||||
className="text-green-500 focus:ring-0"
|
||||
/>
|
||||
<span className={`text-xs ${targetId === 12 ? 'text-green-400 font-bold' : 'text-gray-500'}`}>ID 12</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Navigation Commands */}
|
||||
<div className="space-y-2 mb-4">
|
||||
{/* Goto Tag */}
|
||||
@@ -71,7 +98,7 @@ const AcsControls: React.FC<AcsControlsProps> = ({ onSend, isConnected, mapData
|
||||
</datalist>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleSend(0x81, tagId)}
|
||||
onClick={() => handleSend(100, tagId)}
|
||||
className="bg-gray-700 hover:bg-green-700 text-white text-xs px-3 py-1.5 rounded flex items-center gap-1 transition-colors border border-gray-600"
|
||||
>
|
||||
GO <ChevronRight size={10} />
|
||||
@@ -97,7 +124,7 @@ const AcsControls: React.FC<AcsControlsProps> = ({ onSend, isConnected, mapData
|
||||
</datalist>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleSend(0x82, alias)}
|
||||
onClick={() => handleSend(107, alias)}
|
||||
className="bg-gray-700 hover:bg-green-700 text-white text-xs px-3 py-1.5 rounded flex items-center gap-1 transition-colors border border-gray-600"
|
||||
>
|
||||
GO <ChevronRight size={10} />
|
||||
@@ -111,26 +138,26 @@ const AcsControls: React.FC<AcsControlsProps> = ({ onSend, isConnected, mapData
|
||||
{/* Action Buttons Grid */}
|
||||
<div className="grid grid-cols-2 gap-2 mb-3">
|
||||
<button
|
||||
onClick={() => handleSend(0x83, undefined, 1)}
|
||||
onClick={() => handleSend(110, undefined, 1)}
|
||||
className="flex items-center justify-center gap-2 bg-blue-900/40 hover:bg-blue-800 border border-blue-800 text-blue-200 py-2 rounded text-xs transition-colors"
|
||||
>
|
||||
<Package size={14} /> Pick ON
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleSend(0x83, undefined, 0)}
|
||||
onClick={() => handleSend(111, undefined, 0)}
|
||||
className="flex items-center justify-center gap-2 bg-gray-700 hover:bg-gray-600 border border-gray-600 text-gray-300 py-2 rounded text-xs transition-colors"
|
||||
>
|
||||
<Package size={14} /> Pick OFF
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => handleSend(0x84, undefined, 1)}
|
||||
onClick={() => handleSend(109, undefined, 1)}
|
||||
className="flex items-center justify-center gap-2 bg-yellow-900/40 hover:bg-yellow-800 border border-yellow-800 text-yellow-200 py-2 rounded text-xs transition-colors"
|
||||
>
|
||||
<Zap size={14} /> Charge ON
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleSend(0x84, undefined, 0)}
|
||||
onClick={() => handleSend(109, undefined, 0)}
|
||||
className="flex items-center justify-center gap-2 bg-gray-700 hover:bg-gray-600 border border-gray-600 text-gray-300 py-2 rounded text-xs transition-colors"
|
||||
>
|
||||
<Zap size={14} /> Charge OFF
|
||||
@@ -141,25 +168,19 @@ const AcsControls: React.FC<AcsControlsProps> = ({ onSend, isConnected, mapData
|
||||
<div className="mb-3">
|
||||
<h4 className="text-[10px] text-gray-500 uppercase font-bold mb-1">Lift Control</h4>
|
||||
<div className="flex gap-1">
|
||||
<button onClick={() => handleSend(0x85, undefined, 1)} className="flex-1 bg-gray-700 hover:bg-green-700 text-white text-xs py-1.5 rounded border border-gray-600">UP</button>
|
||||
<button onClick={() => handleSend(0x85, undefined, 0)} className="flex-1 bg-gray-700 hover:bg-red-700 text-white text-xs py-1.5 rounded border border-gray-600">STOP</button>
|
||||
<button onClick={() => handleSend(0x85, undefined, 2)} className="flex-1 bg-gray-700 hover:bg-green-700 text-white text-xs py-1.5 rounded border border-gray-600">DOWN</button>
|
||||
<button onClick={() => handleSend(106, undefined, 1)} className="flex-1 bg-gray-700 hover:bg-green-700 text-white text-xs py-1.5 rounded border border-gray-600">UP</button>
|
||||
<button onClick={() => handleSend(106, undefined, 0)} className="flex-1 bg-gray-700 hover:bg-red-700 text-white text-xs py-1.5 rounded border border-gray-600">STOP</button>
|
||||
<button onClick={() => handleSend(106, undefined, 2)} className="flex-1 bg-gray-700 hover:bg-green-700 text-white text-xs py-1.5 rounded border border-gray-600">DOWN</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* System Controls (New) */}
|
||||
<div>
|
||||
<h4 className="text-[10px] text-gray-500 uppercase font-bold mb-1">System Control</h4>
|
||||
<div className="grid grid-cols-2 gap-2 mb-2">
|
||||
<button onClick={() => handleSend(0x86)} className="bg-red-900/40 hover:bg-red-800 text-red-200 border border-red-800 text-xs py-1.5 rounded font-bold">EMG STOP</button>
|
||||
<button onClick={() => handleSend(0x87)} className="bg-gray-700 hover:bg-gray-600 text-gray-200 border border-gray-600 text-xs py-1.5 rounded">RESET</button>
|
||||
</div>
|
||||
<div className="flex items-center justify-between bg-gray-900 p-2 rounded border border-gray-700">
|
||||
<span className="text-xs text-gray-400">Mark Stop</span>
|
||||
<div className="flex gap-1">
|
||||
<button onClick={() => handleSend(0x88, undefined, 1)} className="px-2 py-0.5 text-[10px] bg-green-900 text-green-300 rounded border border-green-800 hover:bg-green-800">ON</button>
|
||||
<button onClick={() => handleSend(0x88, undefined, 0)} className="px-2 py-0.5 text-[10px] bg-gray-700 text-gray-300 rounded border border-gray-600 hover:bg-gray-600">OFF</button>
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-2 mb-2">
|
||||
<button onClick={() => handleSend(101)} className="bg-red-900/40 hover:bg-red-800 text-red-200 border border-red-800 text-xs py-1.5 rounded font-bold">STOP</button>
|
||||
<button onClick={() => handleSend(102)} className="bg-gray-700 hover:bg-gray-600 text-gray-200 border border-gray-600 text-xs py-1.5 rounded">RESET</button>
|
||||
<button onClick={() => handleSend(105, undefined, 1)} className="px-2 py-0.5 text-[10px] bg-green-900 text-green-300 rounded border border-green-800 hover:bg-green-800">MARK STOP</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1211,7 +1211,7 @@ const SimulationCanvas: React.FC<SimulationCanvasProps> = ({ activeTool, mapData
|
||||
return { x: rawX, y: rawY };
|
||||
};
|
||||
|
||||
const handleWheel = (e: React.WheelEvent) => {
|
||||
const handleWheel = useCallback((e: WheelEvent) => {
|
||||
e.preventDefault();
|
||||
const rect = canvasRef.current?.getBoundingClientRect();
|
||||
if (!rect) return;
|
||||
@@ -1234,7 +1234,20 @@ const SimulationCanvas: React.FC<SimulationCanvasProps> = ({ activeTool, mapData
|
||||
const newY = screenY - worldY * newScale;
|
||||
|
||||
viewRef.current = { x: newX, y: newY, scale: newScale };
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Attach non-passive wheel listener
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (canvas) {
|
||||
canvas.addEventListener('wheel', handleWheel, { passive: false });
|
||||
}
|
||||
return () => {
|
||||
if (canvas) {
|
||||
canvas.removeEventListener('wheel', handleWheel);
|
||||
}
|
||||
};
|
||||
}, [handleWheel]);
|
||||
|
||||
const handleMouseMove = (e: React.MouseEvent) => {
|
||||
const rect = canvasRef.current?.getBoundingClientRect();
|
||||
@@ -1547,7 +1560,7 @@ const SimulationCanvas: React.FC<SimulationCanvasProps> = ({ activeTool, mapData
|
||||
setSelectedItemIds(newSelection);
|
||||
|
||||
// Prepare Multi-Drag
|
||||
const initialStates: Record<string, any> = {};
|
||||
const initialStates: any = {};
|
||||
newSelection.forEach(id => {
|
||||
const n = mapData.nodes.find(o => o.id === id);
|
||||
if (n) initialStates[id] = { x: n.x, y: n.y };
|
||||
@@ -1648,7 +1661,6 @@ const SimulationCanvas: React.FC<SimulationCanvasProps> = ({ activeTool, mapData
|
||||
ref={canvasRef}
|
||||
width={dimensions.width}
|
||||
height={dimensions.height}
|
||||
onWheel={handleWheel}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseUp={handleMouseUp}
|
||||
|
||||
Reference in New Issue
Block a user