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