diff --git a/src/components/panels/MorseTransmissionPanel.tsx b/src/components/panels/MorseTransmissionPanel.tsx index 535d46d..978336d 100644 --- a/src/components/panels/MorseTransmissionPanel.tsx +++ b/src/components/panels/MorseTransmissionPanel.tsx @@ -3,17 +3,25 @@ import React, { useEffect, useRef, useState } from 'react'; import ROSLIB from 'roslib'; import { useROS } from '@/ros/ROSContext'; +type DetectionType = 'NONE' | 'MORSE' | string; + const MorseTransmissionPanel: React.FC = () => { const { ros } = useROS(); const [message, setMessage] = useState(''); const [lastSent, setLastSent] = useState(null); + const [receivedText, setReceivedText] = useState(''); + const [detectionType, setDetectionType] = useState(null); + const [updating, setUpdating] = useState(false); + const [status, setStatus] = useState(null); const topicRef = useRef(null); useEffect(() => { if (!ros) { topicRef.current = null; + setDetectionType(null); + setReceivedText(''); return; } @@ -23,6 +31,19 @@ const MorseTransmissionPanel: React.FC = () => { messageType: 'std_msgs/msg/String', }); + const morseTextTopic = new ROSLIB.Topic({ + ros, + name: '/morse_text', + messageType: 'std_msgs/msg/String', + }); + + const handleMorseText = (msg: ROSLIB.Message) => { + const data = (msg as { data?: string }).data; + setReceivedText(typeof data === 'string' ? data : ''); + }; + + morseTextTopic.subscribe(handleMorseText); + return () => { try { topicRef.current?.unadvertise(); @@ -30,9 +51,92 @@ const MorseTransmissionPanel: React.FC = () => { // ignore } topicRef.current = null; + morseTextTopic.unsubscribe(handleMorseText); }; }, [ros]); + const refreshDetectionType = () => { + if (!ros) return; + + const service = new ROSLIB.Service({ + ros, + name: '/detect_node/get_parameters', + serviceType: 'rcl_interfaces/srv/GetParameters', + }); + + const request = new ROSLIB.ServiceRequest({ + names: ['detection_type'], + }); + + service.callService(request, (result: any) => { + const value = result.values?.[0]; + if (!value || value.type !== 4) { + setStatus('Failed to read detection_type'); + return; + } + setDetectionType(value.string_value ?? 'NONE'); + }); + }; + + useEffect(() => { + refreshDetectionType(); + }, [ros]); + + const setDetectParameter = ( + name: string, + value: { type: number; string_value?: string; bool_value?: boolean }, + onSuccess?: () => void, + ) => { + if (!ros) return; + + setUpdating(true); + setStatus(null); + + const service = new ROSLIB.Service({ + ros, + name: '/detect_node/set_parameters', + serviceType: 'rcl_interfaces/srv/SetParameters', + }); + + const request = new ROSLIB.ServiceRequest({ + parameters: [{ name, value }], + }); + + service.callService(request, (result: any) => { + const parameterResult = result.results?.[0]; + const success = parameterResult?.successful ?? false; + const reason = parameterResult?.reason ?? ''; + + setUpdating(false); + + if (!success) { + setStatus(reason || `Failed to set ${name}`); + if (name === 'detection_type') refreshDetectionType(); + return; + } + + onSuccess?.(); + setStatus(`Set ${name} successfully`); + }); + }; + + const handleMorseToggle = (enabled: boolean) => { + const mode = enabled ? 'MORSE' : 'NONE'; + setDetectParameter( + 'detection_type', + { type: 4, string_value: mode }, + () => setDetectionType(mode), + ); + }; + + const setCalibrate = () => { + setDetectParameter('calibrate', { type: 1, bool_value: true }); + }; + + const setStartDetection = () => { + setDetectParameter('start_detection', { type: 1, bool_value: true }); + }; + const send = () => { if (!topicRef.current || !message) return; topicRef.current.publish(new ROSLIB.Message({ data: message })); @@ -44,6 +148,9 @@ const MorseTransmissionPanel: React.FC = () => { }; const disabled = !ros; + const detectDisabled = disabled || updating || detectionType === null; + const morseEnabled = detectionType === 'MORSE'; + const morseActionsDisabled = detectDisabled || !morseEnabled; return (
@@ -62,7 +169,45 @@ const MorseTransmissionPanel: React.FC = () => {
+
+
Detection Options
+
+ + + +
+
+ + +
+
+ {lastSent &&
Last sent: {lastSent}
} + {status &&
{status}
}