using System;
using WIDESEAWCS_S7Simulator.Core.Interfaces;
namespace WIDESEAWCS_S7Simulator.Core.Memory
{
///
/// C区(计数器区/Counter)实现
/// 用于模拟西门子S7 PLC的计数器区域
/// 每个计数器占用2字节,存储计数器的当前值
///
public class CRegion : MemoryRegion, IMemoryRegion
{
///
/// 区域类型
///
public override string RegionType => "C";
///
/// 每个计数器占用的字节数(S7计数器为2字节)
///
private const int CounterSize = 2;
///
/// 计数器数量
///
public int CounterCount => Size / CounterSize;
///
/// 构造函数
///
/// 计数器数量
/// 当counterCount小于或等于0时抛出
/// 当counterCount * CounterSize超出int范围时抛出
public CRegion(int counterCount) : base(counterCount * CounterSize)
{
if (counterCount <= 0)
throw new ArgumentOutOfRangeException(nameof(counterCount), "计数器数量必须大于0");
// 验证没有溢出
if (counterCount > Size / CounterSize)
throw new OverflowException($"计数器数量{counterCount}过大,超出内存限制");
}
///
/// 读取计数器值
///
/// 计数器号(从1开始)
/// 计数器值
/// 当counterNumber为0或超出计数器数量时抛出
public ushort ReadCounter(ushort counterNumber)
{
if (counterNumber == 0)
throw new ArgumentOutOfRangeException(nameof(counterNumber), "计数器号必须大于0(从1开始)");
if (counterNumber > CounterCount)
throw new ArgumentOutOfRangeException(nameof(counterNumber),
$"计数器号{counterNumber}超出范围,当前计数器总数为{CounterCount}");
ushort offset = (ushort)((counterNumber - 1) * CounterSize);
var data = Read(offset, CounterSize);
return (ushort)((data[0] << 8) | data[1]);
}
///
/// 写入计数器值
///
/// 计数器号(从1开始)
/// 计数器值
/// 当counterNumber为0或超出计数器数量时抛出
public void WriteCounter(ushort counterNumber, ushort value)
{
if (counterNumber == 0)
throw new ArgumentOutOfRangeException(nameof(counterNumber), "计数器号必须大于0(从1开始)");
if (counterNumber > CounterCount)
throw new ArgumentOutOfRangeException(nameof(counterNumber),
$"计数器号{counterNumber}超出范围,当前计数器总数为{CounterCount}");
ushort offset = (ushort)((counterNumber - 1) * CounterSize);
var data = new byte[] { (byte)(value >> 8), (byte)(value & 0xFF) };
Write(offset, data);
}
}
}