Phase 16 (v0.6 milestone) — supporto Fagor CNC via FTP, riuso pattern Siemens/Mitsubishi (FtpWebRequest + ASCII). Modelli supportati: 8060/8065/8070 (FTP nativo), 8055 (con opzione Ethernet). Modelli 8025-8050 esclusi (solo RS232). Code: - Cnc/Fagor/* — FagorConnectionConfig, IFagorFtpClient, FagorFtpClient, FagorMachine. ProgramExtension configurabile (default .nc), ProgramDirectory /Users/Prg/. - Cnc/Models/CncManufacturer.cs — enum + Fagor. - Cnc/CncMachineFactory.cs — case Fagor, porta default 21. - Cnc/NcProgramValidator.cs — refactor IsRestrictiveDialect(): block-80/no-tab/no-lowercase/nested-parens/comment-32 ora applicati solo a Fanuc+Mitsubishi (Heidenhain/Siemens/Fagor esenti). Fagor name rules: max 24 char, no ñ (escape ñ per safety codepage), stem alphanumerico + spazi (estensione separata). - ArgParser.cs — case "fagor". - Program.cs — help text manufacturer/username/password. Tests: - FagorMachineTests — 12 unit (10 mock + 2 validator reale). - FagorMachineIntegrationTests — 5 stub-based (riusa FtpServerStub) + 1 hardware skip via FAGOR_TEST_IP env var. - NcProgramValidatorTests — 12 nuovi Fagor (8 + 4 extension coverage), 6 lock Siemens/Heidenhain exemption, 3 esistenti Siemens→Fanuc. - CncMachineFactoryTests — Create_Fagor_ReturnsFagorMachine. Docs: - README.md — sezione "Controller Fagor" italiano: modelli supportati/ non supportati, regole nome, env var test. Build: - *.csproj — 4 Compile Include main + 2 test. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
71 lines
2.7 KiB
C#
71 lines
2.7 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Text;
|
|
|
|
namespace NcProgramManager.Cnc.Fagor
|
|
{
|
|
/// <summary>Client FTP per trasferimento programmi Fagor CNC.</summary>
|
|
internal sealed class FagorFtpClient : IFagorFtpClient
|
|
{
|
|
private readonly FagorConnectionConfig _config;
|
|
|
|
public FagorFtpClient(FagorConnectionConfig config)
|
|
{
|
|
_config = config ?? throw new ArgumentNullException("config");
|
|
}
|
|
|
|
/// <summary>Verifica raggiungibilità server FTP listando la directory programmi.</summary>
|
|
public bool Ping()
|
|
{
|
|
try
|
|
{
|
|
var req = CreateRequest(_config.ProgramDirectory, WebRequestMethods.Ftp.ListDirectory);
|
|
using (var resp = (FtpWebResponse)req.GetResponse())
|
|
return resp.StatusCode == FtpStatusCode.DataAlreadyOpen
|
|
|| resp.StatusCode == FtpStatusCode.OpeningData
|
|
|| (int)resp.StatusCode / 100 == 2;
|
|
}
|
|
catch { return false; }
|
|
}
|
|
|
|
/// <summary>Scarica file dal Fagor in stringa.</summary>
|
|
public string DownloadFile(string ncPath)
|
|
{
|
|
var req = CreateRequest(ncPath, WebRequestMethods.Ftp.DownloadFile);
|
|
using (var resp = (FtpWebResponse)req.GetResponse())
|
|
using (var reader = new StreamReader(resp.GetResponseStream(), Encoding.ASCII))
|
|
return reader.ReadToEnd();
|
|
}
|
|
|
|
/// <summary>Carica contenuto stringa su Fagor.</summary>
|
|
public void UploadFile(string ncPath, string content)
|
|
{
|
|
var req = CreateRequest(ncPath, WebRequestMethods.Ftp.UploadFile);
|
|
byte[] data = Encoding.ASCII.GetBytes(content);
|
|
req.ContentLength = data.Length;
|
|
using (var stream = req.GetRequestStream())
|
|
stream.Write(data, 0, data.Length);
|
|
using ((FtpWebResponse)req.GetResponse()) { }
|
|
}
|
|
|
|
public void DeleteFile(string ncPath)
|
|
{
|
|
var req = CreateRequest(ncPath, WebRequestMethods.Ftp.DeleteFile);
|
|
using ((FtpWebResponse)req.GetResponse()) { }
|
|
}
|
|
|
|
private FtpWebRequest CreateRequest(string path, string method)
|
|
{
|
|
string uri = string.Format("ftp://{0}:{1}{2}", _config.IpAddress, _config.Port, path);
|
|
var req = (FtpWebRequest)WebRequest.Create(uri);
|
|
req.Method = method;
|
|
req.Credentials = new NetworkCredential(_config.Username, _config.Password);
|
|
req.Timeout = (int)_config.RequestTimeout.TotalMilliseconds;
|
|
req.KeepAlive = false;
|
|
req.UseBinary = false;
|
|
req.UsePassive = true;
|
|
return req;
|
|
}
|
|
}
|
|
}
|