namespace RobotNet.Script;
///
/// Client CC‑Link IE Basic (SLMP over TCP/UDP) dùng để kết nối PC ↔ PLC Mitsubishi qua Ethernet thường,
/// hỗ trợ đọc/ghi device, polling chu kỳ và gửi lệnh SLMP thô.
///
public interface ICcLinkIeBasicClient : IAsyncDisposable, IDisposable
{
///
/// Trạng thái đã kết nối phiên transport (TCP/UDP) tới PLC hay chưa.
///
bool IsConnected { get; }
///
/// Số lần thử gửi lại khi lỗi tạm thời/timeout.
///
int RetryCount { get; set; }
///
/// Ngắt kết nối transport và giải phóng tài nguyên liên quan.
///
/// Token hủy bất đồng bộ.
Task DisconnectAsync(CancellationToken ct = default);
///
/// Đọc mảng bit (X/Y/M/L/S/B...) từ PLC.
///
/// Loại device code.
/// Địa chỉ bắt đầu.
/// Số bit cần đọc.
/// Token hủy.
/// Mảng giá trị bit.
Task ReadBitsAsync(DeviceCode device, int startAddress, int count, CancellationToken ct = default);
///
/// Ghi mảng bit (X/Y/M/L/S/B...) vào PLC.
///
/// Loại device code.
/// Địa chỉ bắt đầu.
/// Dãy giá trị bit cần ghi.
/// Token hủy.
Task WriteBitsAsync(DeviceCode device, int startAddress, ReadOnlyMemory values, CancellationToken ct = default);
///
/// Đọc mảng word (D/W/R/ZR/B...) từ PLC.
///
/// Loại device code.
/// Địa chỉ bắt đầu (đơn vị word).
/// Số word cần đọc.
/// Token hủy.
/// Mảng word (UInt16).
Task ReadWordsAsync(DeviceCode device, int startAddress, int wordCount, CancellationToken ct = default);
///
/// Ghi mảng word (D/W/R/ZR/B...) vào PLC.
///
/// Loại device code.
/// Địa chỉ bắt đầu (đơn vị word).
/// Dãy word cần ghi.
/// Token hủy.
Task WriteWordsAsync(DeviceCode device, int startAddress, ReadOnlyMemory words, CancellationToken ct = default);
///
/// Đọc mảng double‑word (UInt32) từ PLC (áp dụng cho vùng hỗ trợ dword).
///
/// Loại device code.
/// Địa chỉ bắt đầu (đơn vị dword).
/// Số dword cần đọc.
/// Token hủy.
/// Mảng dword (UInt32).
Task ReadDWordsAsync(DeviceCode device, int startAddress, int dwordCount, CancellationToken ct = default);
///
/// Ghi mảng double‑word (UInt32) vào PLC (áp dụng cho vùng hỗ trợ dword).
///
/// Loại device code.
/// Địa chỉ bắt đầu (đơn vị dword).
/// Dãy dword cần ghi.
/// Token hủy.
Task WriteDWordsAsync(DeviceCode device, int startAddress, ReadOnlyMemory dwords, CancellationToken ct = default);
///
/// Đọc ngẫu nhiên nhiều điểm word rời rạc (mixed areas) trong một lần.
///
/// Danh sách (device, address) cần đọc.
/// Token hủy.
/// Mảng word theo thứ tự điểm yêu cầu.
Task ReadRandomWordsAsync((DeviceCode Device, int Address)[] points, CancellationToken ct = default);
///
/// Ghi ngẫu nhiên nhiều điểm word rời rạc (mixed areas) trong một lần.
///
/// Danh sách (device, address) cần ghi.
/// Giá trị word theo thứ tự điểm.
/// Token hủy.
Task WriteRandomWordsAsync((DeviceCode Device, int Address)[] points, ReadOnlyMemory values, CancellationToken ct = default);
///
/// Sự kiện bắn ra sau mỗi chu kỳ polling hoàn tất.
///
event EventHandler? Polled;
///
/// Bắt đầu polling chu kỳ một hoặc nhiều vùng device.
///
/// Tùy chọn polling (chu kỳ, vùng, giới hạn kích thước).
/// Token hủy.
void StartPolling(PollOptions options, CancellationToken ct = default);
///
/// Dừng polling chu kỳ.
///
/// Token hủy.
Task StopPollingAsync(CancellationToken ct = default);
///
/// Lấy trạng thái liên kết/SLMP gần nhất (end code, thống kê thời gian phản hồi...).
///
/// Token hủy.
/// Thông tin trạng thái IE Basic.
Task GetStatusAsync(CancellationToken ct = default);
///
/// Kiểm tra liên lạc PLC (ví dụ node monitor) ở mức nhanh/gọn.
///
/// Token hủy.
/// true nếu phản hồi hợp lệ, ngược lại false.
Task PingAsync(CancellationToken ct = default);
///
/// Truy vấn thông tin nhận dạng module/CPU (nếu PLC cho phép).
///
/// Token hủy.
/// Thông tin định danh CPU/module.
Task IdentifyAsync(CancellationToken ct = default);
///
/// Gửi lệnh SLMP thô (mở rộng/đặc thù) và nhận phản hồi.
///
/// Mã lệnh SLMP.
/// Payload SLMP theo định dạng frame chọn (3E/4E).
/// Token hủy.
/// Phản hồi SLMP gồm end code và payload.
Task SendSlmpAsync(SlmpCommand command, ReadOnlyMemory payload, CancellationToken ct = default);
}
///
/// Loại transport cho CC‑Link IE Basic (UDP hoặc TCP).
///
public enum IeBasicTransport
{
/// Giao tiếp qua UDP (thường dùng cho IE Basic).
Udp,
/// Giao tiếp qua TCP.
Tcp
}
///
/// Định dạng frame SLMP.
///
public enum SlmpFrameFormat
{
/// Khung 3E (Format 3E).
Format3E,
/// Khung 4E (Format 4E).
Format4E
}
///
/// Device code (vùng thiết bị) cấp ứng dụng.
///
public enum DeviceCode
{
/// Input (bit).
X,
/// Output (bit).
Y,
/// Internal relay (bit).
M,
/// Latch relay (bit).
L,
/// Link relay (bit/word tùy CPU).
B,
/// Step relay (bit).
S,
/// Data register (word).
D,
/// Link register (word).
W,
/// File register (word).
R,
/// Extended file register (word).
ZR
}
///
/// Tham số logic phía local (PC/sender) khi gửi SLMP.
///
/// Số mạng logic.
/// Địa chỉ I/O module logic (thường 0x03FF).
/// Số đa điểm (nếu dùng).
/// Số trạm logic.
public readonly record struct IeBasicLocal(
byte NetworkNo,
ushort ModuleIoNo,
byte MultidropNo,
byte StationNo
);
///
/// Cấu hình đầu xa: địa chỉ IP/Port và tham số logic đích cho SLMP.
///
/// Địa chỉ IP hoặc hostname PLC/module.
/// Cổng SLMP (ví dụ 5007).
/// Số mạng logic đích.
/// Địa chỉ I/O module logic đích.
/// Số đa điểm (nếu dùng).
/// Số trạm logic đích.
public readonly record struct IeBasicRemote(
string Host,
int Port,
byte NetworkNo,
ushort ModuleIoNo,
byte MultidropNo,
byte StationNo
);
///
/// Tùy chọn khởi tạo/kết nối IE Basic client.
///
public sealed record IeBasicClientOptions(
string Host,
int Port,
byte NetworkNo,
ushort ModuleIoNo,
byte MultidropNo,
byte StationNo
)
{
/// Transport: UDP hoặc TCP.
public IeBasicTransport Transport { get; init; } = IeBasicTransport.Udp;
/// Định dạng frame SLMP (3E/4E).
public SlmpFrameFormat FrameFormat { get; init; } = SlmpFrameFormat.Format3E;
/// Tham số logic phía local.
public IeBasicLocal Local { get; init; } =
new IeBasicLocal(0, 0x03FF, 0, 0);
/// Timeout cho mỗi yêu cầu.
public TimeSpan Timeout { get; init; } = TimeSpan.FromMilliseconds(1000);
/// Số lần retry khi lỗi tạm thời.
public int RetryCount { get; init; } = 2;
/// Tự động reconnect nếu mất liên kết.
public bool AutoReconnect { get; init; } = true;
///
/// Quy ước ghép cặp word trong DWord/Float (true: little‑endian word order).
///
public bool LittleEndianWordOrder { get; init; } = true;
}
///
/// Tùy chọn cho polling chu kỳ các vùng device.
///
public sealed record PollOptions
{
/// Khoảng thời gian giữa hai lần poll.
public TimeSpan Interval { get; init; } = TimeSpan.FromMilliseconds(20);
/// Danh sách vùng cần poll (device, địa chỉ bắt đầu, số lượng).
public (DeviceCode Device, int Start, int Count)[] Areas { get; init; } = [];
/// Giới hạn số word tối đa mỗi chu kỳ (để tránh gói quá lớn).
public int MaxWordsPerCycle { get; init; } = 256;
/// Gom vùng theo từng loại device để tối ưu số gói.
public bool AlignAreasByDevice { get; init; } = true;
}
///
/// Dữ liệu trả về sau mỗi chu kỳ polling.
///
public sealed class PollUpdatedEventArgs : EventArgs
{
/// Thời điểm khung dữ liệu được cập nhật.
public DateTimeOffset Timestamp { get; init; }
/// Mảng bit (nếu có vùng bit được cấu hình).
public ReadOnlyMemory? Bits { get; init; }
/// Mảng word (nếu có vùng word được cấu hình).
public ReadOnlyMemory? Words { get; init; }
/// Mảng dword (nếu có vùng dword được cấu hình).
public ReadOnlyMemory? DWords { get; init; }
}
///
/// Trạng thái liên kết/SLMP để chẩn đoán và theo dõi.
///
public sealed record IeBasicStatus
{
/// Liên kết hiện “đang lên” (có phản hồi) hay không.
public bool LinkUp { get; init; }
/// Số lỗi liên tiếp gần nhất.
public int ConsecutiveErrors { get; init; }
/// End code SLMP của lỗi gần nhất (nếu có).
public SlmpEndCode? LastEndCode { get; init; }
/// Mô tả lỗi gần nhất (nếu có).
public string? LastErrorText { get; init; }
/// Thời gian phản hồi trung bình ước tính.
public TimeSpan? AvgRtt { get; init; }
/// Thời gian phản hồi lớn nhất quan sát.
public TimeSpan? MaxRtt { get; init; }
}
///
/// Thông tin nhận dạng CPU/module (nếu PLC cho phép truy vấn).
///
public sealed record ModuleIdentity
{
/// Dòng CPU (ví dụ iQ‑R, iQ‑F).
public string? CpuSeries { get; init; }
/// Model cụ thể (ví dụ R04ENCPU).
public string? CpuModel { get; init; }
/// Phiên bản firmware.
public string? Firmware { get; init; }
/// Nhà sản xuất (thường là Mitsubishi Electric).
public string? Vendor { get; init; }
/// Thông tin bổ sung khác (nếu có).
public string? AdditionalInfo { get; init; }
}
///
/// Mã lệnh SLMP rút gọn (có thể mở rộng khi hiện thực adapter).
///
public enum SlmpCommand : ushort
{
/// Đọc device theo dải liên tục (bit/word).
ReadDevice = 0x0401,
/// Ghi device theo dải liên tục (bit/word).
WriteDevice = 0x1401,
/// Đọc ngẫu nhiên nhiều điểm.
ReadRandom = 0x0403,
/// Ghi ngẫu nhiên nhiều điểm.
WriteRandom = 0x1402,
/// Node monitor / kiểm tra liên lạc.
NodeMonitor = 0x0619,
/// Truy vấn thông tin thiết bị/PLC.
DeviceInfo = 0x0601
}
///
/// Mã end code SLMP (hoàn thành/thất bại), gồm cả mã nội bộ ánh xạ lỗi transport/timeout.
///
public enum SlmpEndCode : ushort
{
/// Hoàn thành thành công.
Completed = 0x0000,
/// Lệnh không hợp lệ.
InvalidCommand = 0xC059,
/// Truy cập bị từ chối.
AccessDenied = 0xC056,
/// Lỗi phạm vi device.
DeviceRangeError = 0xC051,
/// Thiết bị bận.
Busy = 0xCEE0,
/// Quá thời gian chờ (gán nội bộ).
Timeout = 0xFFFF,
/// Lỗi transport/socket (gán nội bộ).
TransportError = 0xFFFE,
/// Lỗi không xác định (gán nội bộ).
Unknown = 0xFFFD
}
///
/// Phản hồi SLMP thô trả về từ .
///
public sealed record SlmpResponse
{
/// End code của phản hồi.
public SlmpEndCode EndCode { get; init; }
/// Payload nhị phân trả về (theo frame 3E/4E).
public ReadOnlyMemory Payload { get; init; }
/// Thời điểm nhận gói.
public DateTimeOffset Timestamp { get; init; }
}