using Microsoft.AspNetCore.Mvc;
using Server.Models;
using Server.Services;
namespace Server.Controllers
{
///
/// Controller for CAT (Computer Aided Transceiver) operations
///
[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class CatController : ControllerBase
{
private readonly ISerialCommunicationService _serialService;
private readonly ILogger _logger;
public CatController(ISerialCommunicationService serialService, ILogger logger)
{
_serialService = serialService ?? throw new ArgumentNullException(nameof(serialService));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
///
/// Gets all available serial ports on the system
///
/// List of available serial ports
/// Returns the list of available serial ports
[HttpGet("ports")]
[ProducesResponseType(typeof(PortListResponse), StatusCodes.Status200OK)]
public ActionResult GetPorts()
{
try
{
_logger.LogInformation("Getting available serial ports");
var ports = _serialService.GetAvailablePorts();
var response = new PortListResponse
{
Ports = ports
};
_logger.LogInformation("Found {PortCount} available ports", response.Count);
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting available ports");
return StatusCode(500, new ErrorResponse
{
Error = "Internal server error while getting ports",
Details = ex.Message
});
}
}
///
/// Opens and configures a serial port for communication
///
/// Port configuration parameters
/// Result of the port open operation
/// Port opened successfully
/// Invalid request parameters
/// Internal server error
[HttpPost("open")]
[ProducesResponseType(typeof(PortOperationResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status500InternalServerError)]
public async Task> OpenPort([FromBody] OpenPortRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new ErrorResponse
{
Error = "Invalid request parameters",
Details = string.Join("; ", ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage))
});
}
_logger.LogInformation("Attempting to open port {PortName} with baud rate {BaudRate}",
request.PortName, request.BaudRate);
var success = await _serialService.OpenPortAsync(
request.PortName,
request.BaudRate,
request.Parity,
request.StopBits,
request.Handshake);
var response = new PortOperationResponse
{
Success = success,
PortName = request.PortName,
IsOpen = _serialService.IsPortOpen(),
Message = success
? $"Port {request.PortName} opened successfully"
: $"Failed to open port {request.PortName}"
};
if (success)
{
_logger.LogInformation("Successfully opened port {PortName}", request.PortName);
return Ok(response);
}
else
{
_logger.LogWarning("Failed to open port {PortName}", request.PortName);
return StatusCode(500, new ErrorResponse
{
Error = response.Message
});
}
}
catch (ArgumentException ex)
{
_logger.LogWarning(ex, "Invalid argument for opening port: {PortName}", request.PortName);
return BadRequest(new ErrorResponse
{
Error = "Invalid port parameters",
Details = ex.Message
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error opening port: {PortName}", request.PortName);
return StatusCode(500, new ErrorResponse
{
Error = "Internal server error while opening port",
Details = ex.Message
});
}
}
///
/// Closes the currently opened serial port
///
/// Result of the port close operation
/// Port closed successfully
/// Internal server error
[HttpPost("close")]
[ProducesResponseType(typeof(PortOperationResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status500InternalServerError)]
public async Task> ClosePort()
{
try
{
var currentPortName = _serialService.GetCurrentPortName();
_logger.LogInformation("Attempting to close port {PortName}", currentPortName ?? "unknown");
await _serialService.ClosePortAsync();
var response = new PortOperationResponse
{
Success = true,
PortName = currentPortName,
IsOpen = _serialService.IsPortOpen(),
Message = "Port closed successfully"
};
_logger.LogInformation("Successfully closed port");
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error closing port");
return StatusCode(500, new ErrorResponse
{
Error = "Internal server error while closing port",
Details = ex.Message
});
}
}
///
/// Sends a CAT command to the connected radio
///
/// CAT command to send
/// Result of the command operation including any response from the radio
/// Command sent successfully
/// Invalid request parameters or no port open
/// Internal server error
[HttpPost("command")]
[ProducesResponseType(typeof(CommandResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status500InternalServerError)]
public async Task> SendCommand([FromBody] SendCommandRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(new ErrorResponse
{
Error = "Invalid request parameters",
Details = string.Join("; ", ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage))
});
}
if (!_serialService.IsPortOpen())
{
return BadRequest(new ErrorResponse
{
Error = "No serial port is currently open",
Details = "You must open a serial port before sending commands"
});
}
_logger.LogInformation("Sending CAT command: {Command}", request.Command);
var radioResponse = await _serialService.SendCommandAsync(request.Command);
var response = new CommandResponse
{
Success = true,
Command = request.Command,
Response = radioResponse,
Message = "Command sent successfully",
Timestamp = DateTime.UtcNow
};
_logger.LogInformation("CAT command sent successfully. Response: {Response}", radioResponse);
return Ok(response);
}
catch (ArgumentException ex)
{
_logger.LogWarning(ex, "Invalid command: {Command}", request.Command);
return BadRequest(new ErrorResponse
{
Error = "Invalid command",
Details = ex.Message
});
}
catch (InvalidOperationException ex)
{
_logger.LogWarning(ex, "Cannot send command - port not open");
return BadRequest(new ErrorResponse
{
Error = "Cannot send command",
Details = ex.Message
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error sending CAT command: {Command}", request.Command);
return StatusCode(500, new ErrorResponse
{
Error = "Internal server error while sending command",
Details = ex.Message
});
}
}
///
/// Gets the current status of the serial port connection
///
/// Current port status
/// Returns current port status
[HttpGet("status")]
[ProducesResponseType(typeof(PortOperationResponse), StatusCodes.Status200OK)]
public ActionResult GetStatus()
{
try
{
var isOpen = _serialService.IsPortOpen();
var currentPort = _serialService.GetCurrentPortName();
var response = new PortOperationResponse
{
Success = true,
PortName = currentPort,
IsOpen = isOpen,
Message = isOpen
? $"Port {currentPort} is open"
: "No port is currently open"
};
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting port status");
return StatusCode(500, new ErrorResponse
{
Error = "Internal server error while getting status",
Details = ex.Message
});
}
}
}
}