message type updates
This commit is contained in:
9
aerpaw/MESSAGE_TYPE.m
Normal file
9
aerpaw/MESSAGE_TYPE.m
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
classdef MESSAGE_TYPE < uint8
|
||||||
|
enumeration
|
||||||
|
TARGET (1) % Server->Client: target coordinates follow (3 doubles)
|
||||||
|
ACK (2) % Client->Server: command received
|
||||||
|
READY (3) % Both: ready for next command / mission complete
|
||||||
|
RTL (4) % Server->Client: return to launch
|
||||||
|
LAND (5) % Server->Client: land now
|
||||||
|
end
|
||||||
|
end
|
||||||
Binary file not shown.
@@ -1,282 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
UAV Client for AERPAW Target Location Protocol
|
|
||||||
|
|
||||||
Protocol:
|
|
||||||
Server sends: TARGET:x,y,z (ENU coordinates in meters)
|
|
||||||
Client sends: ACK:TARGET
|
|
||||||
Client (after moving): READY
|
|
||||||
Server sends: FINISHED
|
|
||||||
|
|
||||||
Coordinates:
|
|
||||||
- Server sends local ENU (East, North, Up) coordinates in meters
|
|
||||||
- Client converts to lat/lon using shared origin from config/origin.txt
|
|
||||||
- Origin must match between controller and UAV
|
|
||||||
|
|
||||||
Auto-detection:
|
|
||||||
- If flight controller is available, uses aerpawlib to move drone
|
|
||||||
- If no flight controller, runs in test mode with placeholder movement
|
|
||||||
"""
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Optional, Tuple
|
|
||||||
|
|
||||||
# Get the aerpaw directory (parent of client/)
|
|
||||||
AERPAW_DIR = Path(__file__).parent.parent
|
|
||||||
CONFIG_DIR = AERPAW_DIR / "config"
|
|
||||||
|
|
||||||
|
|
||||||
def load_origin(path: Path) -> Tuple[float, float, float]:
|
|
||||||
"""
|
|
||||||
Load ENU origin from config file.
|
|
||||||
Returns (lat, lon, alt) tuple.
|
|
||||||
"""
|
|
||||||
with open(path, 'r') as f:
|
|
||||||
for line in f:
|
|
||||||
line = line.strip()
|
|
||||||
if not line or line.startswith('#'):
|
|
||||||
continue
|
|
||||||
parts = line.split(',')
|
|
||||||
if len(parts) == 3:
|
|
||||||
return float(parts[0]), float(parts[1]), float(parts[2])
|
|
||||||
raise ValueError(f"No valid origin found in {path}")
|
|
||||||
|
|
||||||
|
|
||||||
def load_connection(path: Path) -> str:
|
|
||||||
"""
|
|
||||||
Load drone connection string from config file.
|
|
||||||
Returns connection string (e.g., 'udp:127.0.0.1:14550').
|
|
||||||
"""
|
|
||||||
with open(path, 'r') as f:
|
|
||||||
for line in f:
|
|
||||||
line = line.strip()
|
|
||||||
if not line or line.startswith('#'):
|
|
||||||
continue
|
|
||||||
return line
|
|
||||||
raise ValueError(f"No valid connection string found in {path}")
|
|
||||||
|
|
||||||
|
|
||||||
def load_server(path: Path) -> Tuple[str, int]:
|
|
||||||
"""
|
|
||||||
Load controller server address from config file.
|
|
||||||
Returns (ip, port) tuple.
|
|
||||||
"""
|
|
||||||
with open(path, 'r') as f:
|
|
||||||
for line in f:
|
|
||||||
line = line.strip()
|
|
||||||
if not line or line.startswith('#'):
|
|
||||||
continue
|
|
||||||
parts = line.split(',')
|
|
||||||
if len(parts) == 2:
|
|
||||||
return parts[0].strip(), int(parts[1].strip())
|
|
||||||
raise ValueError(f"No valid server address found in {path}")
|
|
||||||
|
|
||||||
|
|
||||||
def parse_target(message: str) -> Tuple[float, float, float]:
|
|
||||||
"""Parse TARGET:x,y,z message and return (x, y, z) ENU coordinates."""
|
|
||||||
if not message.startswith("TARGET:"):
|
|
||||||
raise ValueError(f"Invalid message format: {message}")
|
|
||||||
|
|
||||||
coords_str = message[7:] # Remove "TARGET:" prefix
|
|
||||||
parts = coords_str.split(",")
|
|
||||||
if len(parts) != 3:
|
|
||||||
raise ValueError(f"Expected 3 coordinates, got {len(parts)}")
|
|
||||||
|
|
||||||
x, y, z = float(parts[0]), float(parts[1]), float(parts[2])
|
|
||||||
return (x, y, z)
|
|
||||||
|
|
||||||
|
|
||||||
def enu_to_coordinate(origin_lat: float, origin_lon: float, origin_alt: float,
|
|
||||||
enu_x: float, enu_y: float, enu_z: float):
|
|
||||||
"""
|
|
||||||
Convert ENU (East, North, Up) coordinates to lat/lon/alt.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
origin_lat, origin_lon, origin_alt: Origin in degrees/meters
|
|
||||||
enu_x: East offset in meters
|
|
||||||
enu_y: North offset in meters
|
|
||||||
enu_z: Up offset in meters (altitude above origin)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
aerpawlib Coordinate object
|
|
||||||
"""
|
|
||||||
from aerpawlib.util import Coordinate, VectorNED
|
|
||||||
|
|
||||||
origin = Coordinate(origin_lat, origin_lon, origin_alt)
|
|
||||||
# ENU to NED: north=enu_y, east=enu_x, down=-enu_z
|
|
||||||
offset = VectorNED(north=enu_y, east=enu_x, down=-enu_z)
|
|
||||||
return origin + offset
|
|
||||||
|
|
||||||
|
|
||||||
def try_connect_drone(conn_str: str, timeout: float = 10.0):
|
|
||||||
"""
|
|
||||||
Try to connect to drone flight controller.
|
|
||||||
Returns Drone object if successful, None if not available.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
from aerpawlib.vehicle import Drone
|
|
||||||
print(f" Attempting to connect to flight controller: {conn_str}")
|
|
||||||
drone = Drone(conn_str)
|
|
||||||
print(f" Connected to flight controller")
|
|
||||||
return drone
|
|
||||||
except Exception as e:
|
|
||||||
print(f" Could not connect to flight controller: {e}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def try_connect_server(ip: str, port: int, timeout: float = 2.0) -> Optional[socket.socket]:
|
|
||||||
"""
|
|
||||||
Try to connect to controller server with timeout.
|
|
||||||
Returns socket if successful, None if connection fails.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
s.settimeout(timeout)
|
|
||||||
s.connect((ip, port))
|
|
||||||
s.settimeout(None) # Reset to blocking mode after connect
|
|
||||||
return s
|
|
||||||
except (socket.timeout, ConnectionRefusedError, OSError):
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def move_to_target_test(enu_x: float, enu_y: float, enu_z: float,
|
|
||||||
lat: float, lon: float, alt: float):
|
|
||||||
"""
|
|
||||||
Placeholder movement for test mode.
|
|
||||||
"""
|
|
||||||
print(f" [TEST MODE] Target ENU: ({enu_x}, {enu_y}, {enu_z}) meters")
|
|
||||||
print(f" [TEST MODE] Target lat/lon: ({lat:.6f}, {lon:.6f}, {alt:.1f})")
|
|
||||||
print(f" [TEST MODE] Simulating movement...")
|
|
||||||
time.sleep(1.0)
|
|
||||||
print(f" [TEST MODE] Arrived at target")
|
|
||||||
|
|
||||||
|
|
||||||
async def move_to_target_real(drone, target_coord, tolerance: float = 2.0):
|
|
||||||
"""
|
|
||||||
Move drone to target using aerpawlib.
|
|
||||||
"""
|
|
||||||
print(f" [REAL MODE] Moving to: ({target_coord.lat:.6f}, {target_coord.lon:.6f}, {target_coord.alt:.1f})")
|
|
||||||
await drone.goto_coordinates(target_coord, tolerance=tolerance)
|
|
||||||
print(f" [REAL MODE] Arrived at target")
|
|
||||||
|
|
||||||
|
|
||||||
async def run_uav_client(client_id: int):
|
|
||||||
"""Run a single UAV client."""
|
|
||||||
print(f"UAV {client_id}: Starting...")
|
|
||||||
|
|
||||||
# Load configuration
|
|
||||||
origin_path = CONFIG_DIR / "origin.txt"
|
|
||||||
connection_testbed_path = CONFIG_DIR / "connection_testbed.txt"
|
|
||||||
connection_local_path = CONFIG_DIR / "connection.txt"
|
|
||||||
server_testbed_path = CONFIG_DIR / "server_testbed.txt"
|
|
||||||
server_local_path = CONFIG_DIR / "server.txt"
|
|
||||||
|
|
||||||
print(f"UAV {client_id}: Loading origin from {origin_path}")
|
|
||||||
origin_lat, origin_lon, origin_alt = load_origin(origin_path)
|
|
||||||
print(f"UAV {client_id}: Origin: lat={origin_lat}, lon={origin_lon}, alt={origin_alt}")
|
|
||||||
|
|
||||||
# Load both connection configs
|
|
||||||
testbed_conn = load_connection(connection_testbed_path)
|
|
||||||
local_conn = load_connection(connection_local_path)
|
|
||||||
|
|
||||||
# Try testbed flight controller first (AERPAW MAVLink filter)
|
|
||||||
print(f"UAV {client_id}: Trying testbed flight controller: {testbed_conn}...")
|
|
||||||
drone = try_connect_drone(testbed_conn)
|
|
||||||
|
|
||||||
if not drone:
|
|
||||||
print(f"UAV {client_id}: Testbed not available, trying local: {local_conn}...")
|
|
||||||
drone = try_connect_drone(local_conn)
|
|
||||||
|
|
||||||
real_mode = drone is not None
|
|
||||||
|
|
||||||
if real_mode:
|
|
||||||
print(f"UAV {client_id}: Running in REAL mode")
|
|
||||||
else:
|
|
||||||
print(f"UAV {client_id}: Running in TEST mode (no flight controller)")
|
|
||||||
|
|
||||||
# Try testbed server first, fall back to local
|
|
||||||
testbed_ip, testbed_port = load_server(server_testbed_path)
|
|
||||||
local_ip, local_port = load_server(server_local_path)
|
|
||||||
|
|
||||||
print(f"UAV {client_id}: Trying testbed server at {testbed_ip}:{testbed_port}...")
|
|
||||||
s = try_connect_server(testbed_ip, testbed_port)
|
|
||||||
|
|
||||||
if s:
|
|
||||||
print(f"UAV {client_id}: Connected to testbed server")
|
|
||||||
else:
|
|
||||||
print(f"UAV {client_id}: Testbed server not available, trying local server at {local_ip}:{local_port}...")
|
|
||||||
s = try_connect_server(local_ip, local_port)
|
|
||||||
if s:
|
|
||||||
print(f"UAV {client_id}: Connected to local server")
|
|
||||||
else:
|
|
||||||
print(f"UAV {client_id}: ERROR - Could not connect to any server")
|
|
||||||
if drone:
|
|
||||||
drone.close()
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Receive TARGET command
|
|
||||||
data = s.recv(1024).decode().strip()
|
|
||||||
print(f"UAV {client_id}: Received: {data}")
|
|
||||||
|
|
||||||
# Parse target coordinates (ENU)
|
|
||||||
enu_x, enu_y, enu_z = parse_target(data)
|
|
||||||
print(f"UAV {client_id}: Parsed ENU target: x={enu_x}, y={enu_y}, z={enu_z}")
|
|
||||||
|
|
||||||
# Convert ENU to lat/lon
|
|
||||||
target_coord = enu_to_coordinate(origin_lat, origin_lon, origin_alt,
|
|
||||||
enu_x, enu_y, enu_z)
|
|
||||||
print(f"UAV {client_id}: Target coordinate: lat={target_coord.lat:.6f}, lon={target_coord.lon:.6f}, alt={target_coord.alt:.1f}")
|
|
||||||
|
|
||||||
# Send acknowledgment
|
|
||||||
s.sendall(b"ACK:TARGET")
|
|
||||||
print(f"UAV {client_id}: Sent ACK:TARGET")
|
|
||||||
|
|
||||||
# Move to target
|
|
||||||
if real_mode:
|
|
||||||
await move_to_target_real(drone, target_coord)
|
|
||||||
else:
|
|
||||||
move_to_target_test(enu_x, enu_y, enu_z,
|
|
||||||
target_coord.lat, target_coord.lon, target_coord.alt)
|
|
||||||
|
|
||||||
# Signal ready
|
|
||||||
s.sendall(b"READY")
|
|
||||||
print(f"UAV {client_id}: Sent READY")
|
|
||||||
|
|
||||||
# Wait for FINISHED signal from server
|
|
||||||
data = s.recv(1024).decode().strip()
|
|
||||||
if data == "FINISHED":
|
|
||||||
print(f"UAV {client_id}: Received FINISHED - session ended normally")
|
|
||||||
else:
|
|
||||||
print(f"UAV {client_id}: Unexpected message: {data}")
|
|
||||||
|
|
||||||
except ValueError as e:
|
|
||||||
error_msg = f"ERROR:{str(e)}"
|
|
||||||
s.sendall(error_msg.encode())
|
|
||||||
print(f"UAV {client_id}: Error - {e}")
|
|
||||||
|
|
||||||
finally:
|
|
||||||
s.close()
|
|
||||||
if drone:
|
|
||||||
drone.close()
|
|
||||||
print(f"UAV {client_id}: Connection closed")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if len(sys.argv) != 2:
|
|
||||||
print(f"Usage: {sys.argv[0]} <client_id>")
|
|
||||||
print(" Run one instance per UAV, e.g.:")
|
|
||||||
print(" Terminal 1: ./uav.py 1")
|
|
||||||
print(" Terminal 2: ./uav.py 2")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
client_id = int(sys.argv[1])
|
|
||||||
asyncio.run(run_uav_client(client_id))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -8,29 +8,40 @@ Run via:
|
|||||||
Or use the auto-detecting wrapper:
|
Or use the auto-detecting wrapper:
|
||||||
./run_uav.sh
|
./run_uav.sh
|
||||||
|
|
||||||
Protocol:
|
Binary Protocol:
|
||||||
Server sends: TARGET:x,y,z (ENU coordinates in meters)
|
Server sends: TARGET (1 byte) + x,y,z (24 bytes as 3 doubles)
|
||||||
Client sends: ACK:TARGET
|
Client sends: ACK (1 byte)
|
||||||
Client (after moving): READY
|
Client (after moving): READY (1 byte)
|
||||||
Server sends: RTL
|
Server sends: RTL (1 byte)
|
||||||
Client sends: ACK:RTL
|
Client sends: ACK (1 byte)
|
||||||
Client (after returning home): RTL_COMPLETE
|
Client (after returning home): READY (1 byte)
|
||||||
Server sends: LAND
|
Server sends: LAND (1 byte)
|
||||||
Client sends: ACK:LAND
|
Client sends: ACK (1 byte)
|
||||||
Client (after landing): LAND_COMPLETE
|
Client (after landing): READY (1 byte)
|
||||||
Server sends: FINISHED
|
Server sends: READY (1 byte) - mission complete, disconnect
|
||||||
"""
|
"""
|
||||||
|
from enum import IntEnum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
import struct
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from aerpawlib.runner import BasicRunner, entrypoint
|
from aerpawlib.runner import BasicRunner, entrypoint
|
||||||
from aerpawlib.util import Coordinate, VectorNED
|
from aerpawlib.util import Coordinate, VectorNED
|
||||||
from aerpawlib.vehicle import Drone
|
from aerpawlib.vehicle import Drone
|
||||||
|
|
||||||
|
|
||||||
|
# Message types - must match MESSAGE_TYPE.m enum
|
||||||
|
class MessageType(IntEnum):
|
||||||
|
TARGET = 1
|
||||||
|
ACK = 2
|
||||||
|
READY = 3
|
||||||
|
RTL = 4
|
||||||
|
LAND = 5
|
||||||
|
|
||||||
|
|
||||||
AERPAW_DIR = Path(__file__).parent.parent
|
AERPAW_DIR = Path(__file__).parent.parent
|
||||||
CONFIG_FILE = AERPAW_DIR / "config" / "config.yaml"
|
CONFIG_FILE = AERPAW_DIR / "config" / "config.yaml"
|
||||||
|
|
||||||
@@ -56,15 +67,42 @@ def get_environment():
|
|||||||
return env
|
return env
|
||||||
|
|
||||||
|
|
||||||
def parse_target(message: str):
|
def recv_exactly(sock: socket.socket, n: int) -> bytes:
|
||||||
"""Parse TARGET:x,y,z message. Returns (x, y, z) ENU coordinates."""
|
"""Receive exactly n bytes from socket."""
|
||||||
if not message.startswith("TARGET:"):
|
data = b''
|
||||||
raise ValueError(f"Invalid message format: {message}")
|
while len(data) < n:
|
||||||
coords_str = message[7:]
|
chunk = sock.recv(n - len(data))
|
||||||
parts = coords_str.split(",")
|
if not chunk:
|
||||||
if len(parts) != 3:
|
raise ConnectionError("Connection closed while receiving data")
|
||||||
raise ValueError(f"Expected 3 coordinates, got {len(parts)}")
|
data += chunk
|
||||||
return float(parts[0]), float(parts[1]), float(parts[2])
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def recv_message_type(sock: socket.socket) -> MessageType:
|
||||||
|
"""Receive a single-byte message type."""
|
||||||
|
data = recv_exactly(sock, 1)
|
||||||
|
return MessageType(data[0])
|
||||||
|
|
||||||
|
|
||||||
|
def send_message_type(sock: socket.socket, msg_type: MessageType):
|
||||||
|
"""Send a single-byte message type."""
|
||||||
|
sock.sendall(bytes([msg_type]))
|
||||||
|
|
||||||
|
|
||||||
|
def recv_target(sock: socket.socket) -> tuple[float, float, float]:
|
||||||
|
"""Receive TARGET message (1 byte type + 3 doubles).
|
||||||
|
|
||||||
|
Returns (x, y, z) ENU coordinates.
|
||||||
|
"""
|
||||||
|
# First byte is message type (already consumed or check it)
|
||||||
|
msg_type = recv_message_type(sock)
|
||||||
|
if msg_type != MessageType.TARGET:
|
||||||
|
raise ValueError(f"Expected TARGET, got {msg_type.name}")
|
||||||
|
|
||||||
|
# Next 24 bytes are 3 doubles (little-endian)
|
||||||
|
data = recv_exactly(sock, 24)
|
||||||
|
x, y, z = struct.unpack('<ddd', data)
|
||||||
|
return x, y, z
|
||||||
|
|
||||||
|
|
||||||
class UAVRunner(BasicRunner):
|
class UAVRunner(BasicRunner):
|
||||||
@@ -117,12 +155,9 @@ class UAVRunner(BasicRunner):
|
|||||||
await drone.takeoff(25)
|
await drone.takeoff(25)
|
||||||
print("[UAV] Takeoff complete, waiting for target...")
|
print("[UAV] Takeoff complete, waiting for target...")
|
||||||
|
|
||||||
# Receive TARGET command
|
# Receive TARGET command (1 byte type + 24 bytes coords)
|
||||||
data = sock.recv(1024).decode().strip()
|
enu_x, enu_y, enu_z = recv_target(sock)
|
||||||
print(f"[UAV] Received: {data}")
|
print(f"[UAV] Received TARGET: x={enu_x}, y={enu_y}, z={enu_z}")
|
||||||
|
|
||||||
enu_x, enu_y, enu_z = parse_target(data)
|
|
||||||
print(f"[UAV] Target ENU: x={enu_x}, y={enu_y}, z={enu_z}")
|
|
||||||
|
|
||||||
# Convert ENU to lat/lon
|
# Convert ENU to lat/lon
|
||||||
# ENU: x=East, y=North, z=Up
|
# ENU: x=East, y=North, z=Up
|
||||||
@@ -131,8 +166,8 @@ class UAVRunner(BasicRunner):
|
|||||||
print(f"[UAV] Target coord: {target.lat:.6f}, {target.lon:.6f}, {target.alt:.1f}")
|
print(f"[UAV] Target coord: {target.lat:.6f}, {target.lon:.6f}, {target.alt:.1f}")
|
||||||
|
|
||||||
# Acknowledge
|
# Acknowledge
|
||||||
sock.sendall(b"ACK:TARGET")
|
send_message_type(sock, MessageType.ACK)
|
||||||
print("[UAV] Sent ACK:TARGET")
|
print(f"[UAV] Sent {MessageType.ACK.name}")
|
||||||
|
|
||||||
# Move to target
|
# Move to target
|
||||||
print("[UAV] Moving to target...")
|
print("[UAV] Moving to target...")
|
||||||
@@ -140,50 +175,45 @@ class UAVRunner(BasicRunner):
|
|||||||
print("[UAV] Arrived at target")
|
print("[UAV] Arrived at target")
|
||||||
|
|
||||||
# Signal ready
|
# Signal ready
|
||||||
sock.sendall(b"READY")
|
send_message_type(sock, MessageType.READY)
|
||||||
print("[UAV] Sent READY, waiting for commands...")
|
print(f"[UAV] Sent {MessageType.READY.name}, waiting for commands...")
|
||||||
|
|
||||||
# Command loop - handle RTL, LAND, FINISHED from controller
|
# Command loop - handle RTL, LAND, READY (mission complete) from controller
|
||||||
while True:
|
while True:
|
||||||
data = sock.recv(1024).decode().strip()
|
msg_type = recv_message_type(sock)
|
||||||
print(f"[UAV] Received: {data}")
|
print(f"[UAV] Received: {msg_type.name}")
|
||||||
|
|
||||||
if data == "RTL":
|
if msg_type == MessageType.RTL:
|
||||||
sock.sendall(b"ACK:RTL")
|
send_message_type(sock, MessageType.ACK)
|
||||||
|
print(f"[UAV] Sent {MessageType.ACK.name}")
|
||||||
print("[UAV] Returning to home...")
|
print("[UAV] Returning to home...")
|
||||||
# Navigate to home lat/lon but stay at current altitude
|
# Navigate to home lat/lon at safe altitude
|
||||||
# (AERPAW blocks goto_coordinates below 20m, but land() mode is allowed)
|
|
||||||
home = drone.home_coords
|
home = drone.home_coords
|
||||||
current_alt = drone.position.alt
|
|
||||||
safe_alt = 25 # Set to 25m alt for RTL motion
|
safe_alt = 25 # Set to 25m alt for RTL motion
|
||||||
rtl_target = Coordinate(home.lat, home.lon, safe_alt)
|
rtl_target = Coordinate(home.lat, home.lon, safe_alt)
|
||||||
print(f"[UAV] RTL to {home.lat:.6f}, {home.lon:.6f} at {safe_alt:.1f}m")
|
print(f"[UAV] RTL to {home.lat:.6f}, {home.lon:.6f} at {safe_alt:.1f}m")
|
||||||
await drone.goto_coordinates(rtl_target)
|
await drone.goto_coordinates(rtl_target)
|
||||||
print("[UAV] Arrived at home position")
|
print("[UAV] Arrived at home position")
|
||||||
sock.sendall(b"RTL_COMPLETE")
|
send_message_type(sock, MessageType.READY)
|
||||||
print("[UAV] Sent RTL_COMPLETE")
|
print(f"[UAV] Sent {MessageType.READY.name}")
|
||||||
|
|
||||||
elif data == "LAND":
|
elif msg_type == MessageType.LAND:
|
||||||
sock.sendall(b"ACK:LAND")
|
send_message_type(sock, MessageType.ACK)
|
||||||
|
print(f"[UAV] Sent {MessageType.ACK.name}")
|
||||||
print("[UAV] Landing...")
|
print("[UAV] Landing...")
|
||||||
await drone.land()
|
await drone.land()
|
||||||
print("[UAV] Landed and disarmed")
|
print("[UAV] Landed and disarmed")
|
||||||
sock.sendall(b"LAND_COMPLETE")
|
send_message_type(sock, MessageType.READY)
|
||||||
print("[UAV] Sent LAND_COMPLETE")
|
print(f"[UAV] Sent {MessageType.READY.name}")
|
||||||
|
|
||||||
elif data == "FINISHED":
|
elif msg_type == MessageType.READY:
|
||||||
print("[UAV] Received FINISHED - mission complete")
|
print("[UAV] Received READY from server - mission complete")
|
||||||
break
|
break
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print(f"[UAV] Unknown command: {data}")
|
print(f"[UAV] Unknown command: {msg_type}")
|
||||||
|
|
||||||
except ValueError as e:
|
except (ValueError, ConnectionError) as e:
|
||||||
error_msg = f"ERROR:{str(e)}"
|
|
||||||
try:
|
|
||||||
sock.sendall(error_msg.encode())
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
print(f"[UAV] Error: {e}")
|
print(f"[UAV] Error: {e}")
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
@@ -8,14 +8,13 @@ BUILD="$AERPAW_DIR/build"
|
|||||||
|
|
||||||
mkdir -p "$BUILD"
|
mkdir -p "$BUILD"
|
||||||
|
|
||||||
|
# Compile all codegen sources (handles any new generated files)
|
||||||
g++ -I/home/kdee/matlab/R2025a/extern/include \
|
g++ -I/home/kdee/matlab/R2025a/extern/include \
|
||||||
-I"$CODEGEN" \
|
-I"$CODEGEN" \
|
||||||
-I"$IMPL" \
|
-I"$IMPL" \
|
||||||
"$IMPL/controller_main.cpp" \
|
"$IMPL/controller_main.cpp" \
|
||||||
"$CODEGEN/controller.cpp" \
|
|
||||||
"$IMPL/controller_impl.cpp" \
|
"$IMPL/controller_impl.cpp" \
|
||||||
"$CODEGEN/controller_initialize.cpp" \
|
"$CODEGEN"/*.cpp \
|
||||||
"$CODEGEN/controller_terminate.cpp" \
|
|
||||||
-o "$BUILD/controller_app" \
|
-o "$BUILD/controller_app" \
|
||||||
-lpthread
|
-lpthread
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,11 @@
|
|||||||
<Size type="coderapp.internal.codertype.Dimension"/>
|
<Size type="coderapp.internal.codertype.Dimension"/>
|
||||||
<Size type="coderapp.internal.codertype.Dimension"/>
|
<Size type="coderapp.internal.codertype.Dimension"/>
|
||||||
</Types>
|
</Types>
|
||||||
|
<Types id="10" type="coderapp.internal.codertype.PrimitiveType">
|
||||||
|
<ClassName>int32</ClassName>
|
||||||
|
<Size type="coderapp.internal.codertype.Dimension"/>
|
||||||
|
<Size type="coderapp.internal.codertype.Dimension"/>
|
||||||
|
</Types>
|
||||||
</Types>
|
</Types>
|
||||||
</coderapp.internal.interface.project.Interface>
|
</coderapp.internal.interface.project.Interface>
|
||||||
</MF0>
|
</MF0>
|
||||||
@@ -145,7 +150,7 @@
|
|||||||
</Artifacts>
|
</Artifacts>
|
||||||
<BuildFolder type="coderapp.internal.util.mfz.FileSpec"/>
|
<BuildFolder type="coderapp.internal.util.mfz.FileSpec"/>
|
||||||
<Success>true</Success>
|
<Success>true</Success>
|
||||||
<Timestamp>2026-01-30T18:21:40</Timestamp>
|
<Timestamp>2026-02-01T15:39:22</Timestamp>
|
||||||
</MainBuildResult>
|
</MainBuildResult>
|
||||||
</coderapp.internal.mlc.mfz.MatlabCoderProjectState>
|
</coderapp.internal.mlc.mfz.MatlabCoderProjectState>
|
||||||
</MF0>
|
</MF0>
|
||||||
|
|||||||
@@ -49,27 +49,29 @@ for i = 1:numClients
|
|||||||
target = targets(i, :);
|
target = targets(i, :);
|
||||||
|
|
||||||
if coder.target('MATLAB')
|
if coder.target('MATLAB')
|
||||||
disp(['Sending TARGET to client ', num2str(i), ': ', ...
|
disp(['Sending ', char(MESSAGE_TYPE.TARGET), ' to client ', num2str(i), ': ', ...
|
||||||
num2str(target(1)), ',', num2str(target(2)), ',', num2str(target(3))]);
|
num2str(target(1)), ',', num2str(target(2)), ',', num2str(target(3))]);
|
||||||
else
|
else
|
||||||
coder.ceval('sendTarget', int32(i), coder.ref(target));
|
coder.ceval('sendTarget', int32(i), coder.ref(target));
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
% Wait for TARGET acknowledgments from all clients (simultaneously using select())
|
% Wait for ACK from all clients
|
||||||
if coder.target('MATLAB')
|
if coder.target('MATLAB')
|
||||||
disp('Waiting for ACK:TARGET from all clients...');
|
disp(['Waiting for ', char(MESSAGE_TYPE.ACK), ' from all clients...']);
|
||||||
disp('All TARGET acknowledgments received.');
|
disp('All acknowledgments received.');
|
||||||
else
|
else
|
||||||
coder.ceval('waitForAllTargetAck', int32(numClients));
|
coder.ceval('waitForAllMessageType', int32(numClients), ...
|
||||||
|
int32(MESSAGE_TYPE.ACK));
|
||||||
end
|
end
|
||||||
|
|
||||||
% Wait for READY signals from all clients (simultaneously using select())
|
% Wait for READY signals from all clients
|
||||||
if coder.target('MATLAB')
|
if coder.target('MATLAB')
|
||||||
disp('Waiting for READY from all clients...');
|
disp(['Waiting for ', char(MESSAGE_TYPE.READY), ' from all clients...']);
|
||||||
disp('All UAVs at target positions.');
|
disp('All UAVs at target positions.');
|
||||||
else
|
else
|
||||||
coder.ceval('waitForAllReady', int32(numClients));
|
coder.ceval('waitForAllMessageType', int32(numClients), ...
|
||||||
|
int32(MESSAGE_TYPE.READY));
|
||||||
end
|
end
|
||||||
|
|
||||||
% Wait for user input before closing experiment
|
% Wait for user input before closing experiment
|
||||||
@@ -82,43 +84,61 @@ end
|
|||||||
% Send RTL command to all clients
|
% Send RTL command to all clients
|
||||||
for i = 1:numClients
|
for i = 1:numClients
|
||||||
if coder.target('MATLAB')
|
if coder.target('MATLAB')
|
||||||
disp(['Sending RTL to client ', num2str(i)]);
|
disp(['Sending ', char(MESSAGE_TYPE.RTL), ' to client ', num2str(i)]);
|
||||||
else
|
else
|
||||||
coder.ceval('sendRTL', int32(i));
|
coder.ceval('sendMessageType', int32(i), int32(MESSAGE_TYPE.RTL));
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
% Wait for RTL_COMPLETE from all clients (simultaneously using select())
|
% Wait for ACK from all clients
|
||||||
if coder.target('MATLAB')
|
if coder.target('MATLAB')
|
||||||
disp('Waiting for RTL_COMPLETE from all clients...');
|
disp(['Waiting for ', char(MESSAGE_TYPE.ACK), ' from all clients...']);
|
||||||
|
else
|
||||||
|
coder.ceval('waitForAllMessageType', int32(numClients), ...
|
||||||
|
int32(MESSAGE_TYPE.ACK));
|
||||||
|
end
|
||||||
|
|
||||||
|
% Wait for READY from all clients (returned to home)
|
||||||
|
if coder.target('MATLAB')
|
||||||
|
disp(['Waiting for ', char(MESSAGE_TYPE.READY), ' from all clients...']);
|
||||||
disp('All UAVs returned to home.');
|
disp('All UAVs returned to home.');
|
||||||
else
|
else
|
||||||
coder.ceval('waitForAllRTLComplete', int32(numClients));
|
coder.ceval('waitForAllMessageType', int32(numClients), ...
|
||||||
|
int32(MESSAGE_TYPE.READY));
|
||||||
end
|
end
|
||||||
|
|
||||||
% Send LAND command to all clients
|
% Send LAND command to all clients
|
||||||
for i = 1:numClients
|
for i = 1:numClients
|
||||||
if coder.target('MATLAB')
|
if coder.target('MATLAB')
|
||||||
disp(['Sending LAND to client ', num2str(i)]);
|
disp(['Sending ', char(MESSAGE_TYPE.LAND), ' to client ', num2str(i)]);
|
||||||
else
|
else
|
||||||
coder.ceval('sendLAND', int32(i));
|
coder.ceval('sendMessageType', int32(i), int32(MESSAGE_TYPE.LAND));
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
% Wait for LAND_COMPLETE from all clients (simultaneously using select())
|
% Wait for ACK from all clients
|
||||||
if coder.target('MATLAB')
|
if coder.target('MATLAB')
|
||||||
disp('Waiting for LAND_COMPLETE from all clients...');
|
disp(['Waiting for ', char(MESSAGE_TYPE.ACK), ' from all clients...']);
|
||||||
disp('All UAVs landed and disarmed.');
|
|
||||||
else
|
else
|
||||||
coder.ceval('waitForAllLANDComplete', int32(numClients));
|
coder.ceval('waitForAllMessageType', int32(numClients), ...
|
||||||
|
int32(MESSAGE_TYPE.ACK));
|
||||||
end
|
end
|
||||||
|
|
||||||
% Send FINISHED to all clients before closing
|
% Wait for READY from all clients (landed and disarmed)
|
||||||
|
if coder.target('MATLAB')
|
||||||
|
disp(['Waiting for ', char(MESSAGE_TYPE.READY), ' from all clients...']);
|
||||||
|
disp('All UAVs landed and disarmed.');
|
||||||
|
else
|
||||||
|
coder.ceval('waitForAllMessageType', int32(numClients), ...
|
||||||
|
int32(MESSAGE_TYPE.READY));
|
||||||
|
end
|
||||||
|
|
||||||
|
% Send READY to all clients to signal mission complete
|
||||||
for i = 1:numClients
|
for i = 1:numClients
|
||||||
if coder.target('MATLAB')
|
if coder.target('MATLAB')
|
||||||
disp(['Sending FINISHED to client ', num2str(i)]);
|
disp(['Sending ', char(MESSAGE_TYPE.READY), ' to client ', num2str(i)]);
|
||||||
else
|
else
|
||||||
coder.ceval('sendFinished', int32(i));
|
coder.ceval('sendMessageType', int32(i), int32(MESSAGE_TYPE.READY));
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -51,23 +51,6 @@ void acceptClient(int clientId) {
|
|||||||
std::cout << "Client " << clientId << " connected\n";
|
std::cout << "Client " << clientId << " connected\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendMessage(int clientId) {
|
|
||||||
if(clientId <= 0 || clientId > clientSockets.size()) return;
|
|
||||||
const char* msg = "Hello from server";
|
|
||||||
send(clientSockets[clientId-1], msg, strlen(msg), 0);
|
|
||||||
std::cout << "Sent message to client " << clientId << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
int receiveAck(int clientId) {
|
|
||||||
if(clientId <= 0 || clientId > clientSockets.size()) return 0;
|
|
||||||
char buffer[1024];
|
|
||||||
int len = recv(clientSockets[clientId-1], buffer, sizeof(buffer)-1, 0);
|
|
||||||
if(len <= 0) return 0;
|
|
||||||
buffer[len] = '\0';
|
|
||||||
std::cout << "Received ACK from client " << clientId << ": " << buffer << "\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeServer() {
|
void closeServer() {
|
||||||
for(auto sock : clientSockets) {
|
for(auto sock : clientSockets) {
|
||||||
close(sock);
|
close(sock);
|
||||||
@@ -129,91 +112,61 @@ int loadTargets(const char* filename, double* targets, int maxClients) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send target coordinates to a client
|
// Message type names for logging
|
||||||
// target points to 3 doubles: [x, y, z]
|
static const char* messageTypeName(uint8_t msgType) {
|
||||||
void sendTarget(int clientId, const double* target) {
|
switch (msgType) {
|
||||||
if (clientId <= 0 || clientId > (int)clientSockets.size()) return;
|
case 1: return "TARGET";
|
||||||
|
case 2: return "ACK";
|
||||||
char buffer[256];
|
case 3: return "READY";
|
||||||
snprintf(buffer, sizeof(buffer), "TARGET:%.6f,%.6f,%.6f",
|
case 4: return "RTL";
|
||||||
target[0], target[1], target[2]);
|
case 5: return "LAND";
|
||||||
|
default: return "UNKNOWN";
|
||||||
send(clientSockets[clientId - 1], buffer, strlen(buffer), 0);
|
}
|
||||||
std::cout << "Sent target to client " << clientId << ": " << buffer << "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive and validate ACK:TARGET response
|
// Send a single-byte message type to a client
|
||||||
// Returns 1 if ACK:TARGET received, 0 otherwise
|
int sendMessageType(int clientId, int msgType) {
|
||||||
int receiveTargetAck(int clientId) {
|
|
||||||
if (clientId <= 0 || clientId > (int)clientSockets.size()) return 0;
|
if (clientId <= 0 || clientId > (int)clientSockets.size()) return 0;
|
||||||
|
|
||||||
char buffer[256];
|
uint8_t msg = (uint8_t)msgType;
|
||||||
int len = recv(clientSockets[clientId - 1], buffer, sizeof(buffer) - 1, 0);
|
ssize_t sent = send(clientSockets[clientId - 1], &msg, 1, 0);
|
||||||
if (len <= 0) return 0;
|
if (sent != 1) {
|
||||||
buffer[len] = '\0';
|
std::cerr << "Send failed for client " << clientId << "\n";
|
||||||
|
|
||||||
std::cout << "Received from client " << clientId << ": " << buffer << "\n";
|
|
||||||
|
|
||||||
if (strncmp(buffer, "ACK:TARGET", 10) == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Sent to client " << clientId << ": " << messageTypeName(msg) << " (" << (int)msg << ")\n";
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for READY signal from client
|
// Send TARGET message with coordinates (1 byte type + 24 bytes coords)
|
||||||
// Returns 1 if READY received, 0 otherwise
|
int sendTarget(int clientId, const double* coords) {
|
||||||
int waitForReady(int clientId) {
|
|
||||||
if (clientId <= 0 || clientId > (int)clientSockets.size()) return 0;
|
if (clientId <= 0 || clientId > (int)clientSockets.size()) return 0;
|
||||||
|
|
||||||
char buffer[256];
|
// Build message: 1 byte type + 3 doubles (little-endian)
|
||||||
int len = recv(clientSockets[clientId - 1], buffer, sizeof(buffer) - 1, 0);
|
uint8_t buffer[1 + 3 * sizeof(double)];
|
||||||
if (len <= 0) return 0;
|
buffer[0] = 1; // TARGET = 1
|
||||||
buffer[len] = '\0';
|
memcpy(buffer + 1, coords, 3 * sizeof(double));
|
||||||
|
|
||||||
std::cout << "Received from client " << clientId << ": " << buffer << "\n";
|
ssize_t sent = send(clientSockets[clientId - 1], buffer, sizeof(buffer), 0);
|
||||||
|
if (sent != sizeof(buffer)) {
|
||||||
if (strncmp(buffer, "READY", 5) == 0) {
|
std::cerr << "Send target failed for client " << clientId << "\n";
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Sent TARGET to client " << clientId << ": "
|
||||||
|
<< coords[0] << "," << coords[1] << "," << coords[2] << "\n";
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send COMPLETE message to signal graceful shutdown
|
// Wait for a specific message type from ALL clients simultaneously using select()
|
||||||
void sendFinished(int clientId) {
|
// Returns 1 if all clients responded with expected message type, 0 on failure
|
||||||
if (clientId <= 0 || clientId > (int)clientSockets.size()) return;
|
int waitForAllMessageType(int numClients, int expectedType) {
|
||||||
|
|
||||||
const char* msg = "FINISHED";
|
|
||||||
send(clientSockets[clientId - 1], msg, strlen(msg), 0);
|
|
||||||
std::cout << "Sent FINISHED to client " << clientId << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send RTL (Return-To-Launch) command to a client
|
|
||||||
void sendRTL(int clientId) {
|
|
||||||
if (clientId <= 0 || clientId > (int)clientSockets.size()) return;
|
|
||||||
|
|
||||||
const char* msg = "RTL";
|
|
||||||
send(clientSockets[clientId - 1], msg, strlen(msg), 0);
|
|
||||||
std::cout << "Sent RTL to client " << clientId << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send LAND command to a client
|
|
||||||
void sendLAND(int clientId) {
|
|
||||||
if (clientId <= 0 || clientId > (int)clientSockets.size()) return;
|
|
||||||
|
|
||||||
const char* msg = "LAND";
|
|
||||||
send(clientSockets[clientId - 1], msg, strlen(msg), 0);
|
|
||||||
std::cout << "Sent LAND to client " << clientId << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for a specific message from ALL clients simultaneously using select()
|
|
||||||
// Returns 1 if all clients sent the expected message, 0 otherwise
|
|
||||||
static int waitForAllMessage(int numClients, const char* expectedMessage) {
|
|
||||||
if (numClients <= 0 || numClients > (int)clientSockets.size()) return 0;
|
if (numClients <= 0 || numClients > (int)clientSockets.size()) return 0;
|
||||||
|
|
||||||
std::vector<std::string> accumulated(numClients);
|
uint8_t expected = (uint8_t)expectedType;
|
||||||
std::vector<bool> completed(numClients, false);
|
std::vector<bool> completed(numClients, false);
|
||||||
int completedCount = 0;
|
int completedCount = 0;
|
||||||
char buffer[512];
|
|
||||||
|
|
||||||
while (completedCount < numClients) {
|
while (completedCount < numClients) {
|
||||||
// Build fd_set for select()
|
// Build fd_set for select()
|
||||||
@@ -235,17 +188,17 @@ static int waitForAllMessage(int numClients, const char* expectedMessage) {
|
|||||||
// Check each socket
|
// Check each socket
|
||||||
for (int i = 0; i < numClients; i++) {
|
for (int i = 0; i < numClients; i++) {
|
||||||
if (!completed[i] && FD_ISSET(clientSockets[i], &readfds)) {
|
if (!completed[i] && FD_ISSET(clientSockets[i], &readfds)) {
|
||||||
int len = recv(clientSockets[i], buffer, sizeof(buffer) - 1, 0);
|
uint8_t msgType;
|
||||||
if (len <= 0) return 0;
|
int len = recv(clientSockets[i], &msgType, 1, 0);
|
||||||
buffer[len] = '\0';
|
if (len != 1) return 0;
|
||||||
std::cout << "Received from client " << (i + 1) << ": " << buffer << "\n";
|
|
||||||
accumulated[i] += buffer;
|
|
||||||
|
|
||||||
// Check if expected message received
|
std::cout << "Received from client " << (i + 1) << ": "
|
||||||
if (accumulated[i].find(expectedMessage) != std::string::npos) {
|
<< messageTypeName(msgType) << " (" << (int)msgType << ")\n";
|
||||||
|
|
||||||
|
if (msgType == expected) {
|
||||||
completed[i] = true;
|
completed[i] = true;
|
||||||
completedCount++;
|
completedCount++;
|
||||||
std::cout << "Client " << (i + 1) << " completed " << expectedMessage << "\n";
|
std::cout << "Client " << (i + 1) << " completed: " << messageTypeName(expected) << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,30 +207,6 @@ static int waitForAllMessage(int numClients, const char* expectedMessage) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for ACK:TARGET from ALL clients simultaneously
|
|
||||||
// Returns 1 if all clients acknowledged, 0 otherwise
|
|
||||||
int waitForAllTargetAck(int numClients) {
|
|
||||||
return waitForAllMessage(numClients, "ACK:TARGET");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for READY from ALL clients simultaneously
|
|
||||||
// Returns 1 if all clients are ready, 0 otherwise
|
|
||||||
int waitForAllReady(int numClients) {
|
|
||||||
return waitForAllMessage(numClients, "READY");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for RTL_COMPLETE from ALL clients simultaneously
|
|
||||||
// Returns 1 if all clients completed RTL, 0 otherwise
|
|
||||||
int waitForAllRTLComplete(int numClients) {
|
|
||||||
return waitForAllMessage(numClients, "RTL_COMPLETE");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for LAND_COMPLETE from ALL clients simultaneously
|
|
||||||
// Returns 1 if all clients completed LAND, 0 otherwise
|
|
||||||
int waitForAllLANDComplete(int numClients) {
|
|
||||||
return waitForAllMessage(numClients, "LAND_COMPLETE");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for user to press Enter
|
// Wait for user to press Enter
|
||||||
void waitForUserInput() {
|
void waitForUserInput() {
|
||||||
std::cout << "Press Enter to close experiment (RTL + LAND)...\n";
|
std::cout << "Press Enter to close experiment (RTL + LAND)...\n";
|
||||||
|
|||||||
@@ -1,34 +1,28 @@
|
|||||||
#ifndef CONTROLLER_IMPL_H
|
#ifndef CONTROLLER_IMPL_H
|
||||||
#define CONTROLLER_IMPL_H
|
#define CONTROLLER_IMPL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Server lifecycle
|
||||||
void initServer();
|
void initServer();
|
||||||
void acceptClient(int clientId);
|
void acceptClient(int clientId);
|
||||||
void sendMessage(int clientId);
|
|
||||||
int receiveAck(int clientId);
|
|
||||||
void closeServer();
|
void closeServer();
|
||||||
|
|
||||||
// Target location protocol functions
|
// Configuration
|
||||||
int loadTargets(const char* filename, double* targets, int maxClients);
|
int loadTargets(const char* filename, double* targets, int maxClients);
|
||||||
void sendTarget(int clientId, const double* target);
|
|
||||||
int receiveTargetAck(int clientId);
|
|
||||||
int waitForReady(int clientId);
|
|
||||||
void sendFinished(int clientId);
|
|
||||||
|
|
||||||
// Parallel wait functions (using select() for simultaneous processing)
|
// User interaction
|
||||||
int waitForAllTargetAck(int numClients);
|
|
||||||
int waitForAllReady(int numClients);
|
|
||||||
int waitForAllRTLComplete(int numClients);
|
|
||||||
int waitForAllLANDComplete(int numClients);
|
|
||||||
|
|
||||||
// RTL and LAND protocol functions
|
|
||||||
void sendRTL(int clientId);
|
|
||||||
void sendLAND(int clientId);
|
|
||||||
void waitForUserInput();
|
void waitForUserInput();
|
||||||
|
|
||||||
|
// Binary protocol operations
|
||||||
|
int sendMessageType(int clientId, int msgType);
|
||||||
|
int sendTarget(int clientId, const double* coords);
|
||||||
|
int waitForAllMessageType(int numClients, int expectedType);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
classdef REGION_TYPE
|
classdef REGION_TYPE < uint8
|
||||||
properties
|
properties
|
||||||
id
|
id
|
||||||
color
|
color
|
||||||
|
|||||||
Reference in New Issue
Block a user