using System;
using System.Collections.Generic;
using System.Text;
using WIDESEAWCS_S7Simulator.Core.Interfaces;
namespace WIDESEAWCS_S7Simulator.Core.Memory
{
///
/// DB区(数据块)- 支持多个DB块
///
public class DBRegion : IMemoryRegion
{
///
/// DB块字典,键为DB编号,值为字节数组
///
private readonly Dictionary _blocks;
///
/// 读写锁(支持并发访问)
///
private readonly ReaderWriterLockSlim _lock;
///
/// 释放状态标志
///
private bool _disposed = false;
///
/// 单个DB块的大小(字节)
///
private readonly int _blockSize;
///
/// 默认DB编号
///
private const ushort DEFAULT_DB_NUMBER = 1;
///
/// 区域类型
///
public string RegionType => "DB";
///
/// 区域大小(字节)- 返回默认DB块的大小
///
public int Size => _blockSize;
///
/// 构造函数
///
/// 默认DB编号
/// 单个DB块的大小
public DBRegion(ushort defaultDBNumber, int blockSize)
{
_blockSize = blockSize;
_blocks = new Dictionary();
_lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
// 创建默认DB块
CreateBlock(defaultDBNumber);
}
///
/// 创建DB块
///
/// DB编号
private void CreateBlock(ushort dbNumber)
{
if (!_blocks.ContainsKey(dbNumber))
{
_blocks[dbNumber] = new byte[_blockSize];
}
}
///
/// 获取DB块
///
/// DB编号
/// DB块字节数组
private byte[] GetBlock(ushort dbNumber)
{
if (!_blocks.ContainsKey(dbNumber))
{
throw new ArgumentException($"DB块不存在: DB{dbNumber}");
}
return _blocks[dbNumber];
}
///
/// 读取字节数据(使用默认DB1)
///
/// 偏移量
/// 长度
/// 字节数组
public byte[] Read(ushort offset, ushort length)
{
return Read(DEFAULT_DB_NUMBER, offset, length);
}
///
/// 读取字节数据(指定DB编号)
///
/// DB编号
/// 偏移量
/// 长度
/// 字节数组
public byte[] Read(ushort dbNumber, ushort offset, ushort length)
{
_lock.EnterReadLock();
try
{
var block = GetBlock(dbNumber);
if (offset + length > block.Length)
{
throw new ArgumentOutOfRangeException(
$"读取超出DB{dbNumber}区范围: offset={offset}, length={length}, size={block.Length}");
}
byte[] result = new byte[length];
Array.Copy(block, offset, result, 0, length);
return result;
}
finally
{
_lock.ExitReadLock();
}
}
///
/// 写入字节数据(使用默认DB1)
///
/// 偏移量
/// 字节数组
public void Write(ushort offset, byte[] data)
{
Write(DEFAULT_DB_NUMBER, offset, data);
}
///
/// 写入字节数据(指定DB编号)
///
/// DB编号
/// 偏移量
/// 字节数组
public void Write(ushort dbNumber, ushort offset, byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
_lock.EnterWriteLock();
try
{
// 如果DB块不存在,自动创建
if (!_blocks.ContainsKey(dbNumber))
{
CreateBlock(dbNumber);
}
var block = _blocks[dbNumber];
if (offset + data.Length > block.Length)
{
throw new ArgumentOutOfRangeException(
$"写入超出DB{dbNumber}区范围: offset={offset}, length={data.Length}, size={block.Length}");
}
Array.Copy(data, 0, block, offset, data.Length);
}
finally
{
_lock.ExitWriteLock();
}
}
///
/// 读取布尔值
///
/// DB编号
/// 字节偏移量
/// 位偏移量(0-7)
/// 布尔值
public bool ReadBool(ushort dbNumber, ushort byteOffset, byte bitOffset)
{
if (bitOffset > 7)
{
throw new ArgumentOutOfRangeException(nameof(bitOffset), "位偏移量必须在0-7之间");
}
_lock.EnterReadLock();
try
{
var block = GetBlock(dbNumber);
if (byteOffset >= block.Length)
{
throw new ArgumentOutOfRangeException(
$"读取超出DB{dbNumber}区范围: byteOffset={byteOffset}, size={block.Length}");
}
return (block[byteOffset] & (1 << bitOffset)) != 0;
}
finally
{
_lock.ExitReadLock();
}
}
///
/// 写入布尔值
///
/// DB编号
/// 字节偏移量
/// 位偏移量(0-7)
/// 布尔值
public void WriteBool(ushort dbNumber, ushort byteOffset, byte bitOffset, bool value)
{
if (bitOffset > 7)
{
throw new ArgumentOutOfRangeException(nameof(bitOffset), "位偏移量必须在0-7之间");
}
_lock.EnterWriteLock();
try
{
// 如果DB块不存在,自动创建
if (!_blocks.ContainsKey(dbNumber))
{
CreateBlock(dbNumber);
}
var block = _blocks[dbNumber];
if (byteOffset >= block.Length)
{
throw new ArgumentOutOfRangeException(
$"写入超出DB{dbNumber}区范围: byteOffset={byteOffset}, size={block.Length}");
}
if (value)
{
block[byteOffset] |= (byte)(1 << bitOffset);
}
else
{
block[byteOffset] &= (byte)~(1 << bitOffset);
}
}
finally
{
_lock.ExitWriteLock();
}
}
///
/// 读取16位整数(Int,大端序)
///
/// DB编号
/// 偏移量
/// 16位整数
public short ReadInt(ushort dbNumber, ushort offset)
{
var data = Read(dbNumber, offset, 2);
return (short)((data[0] << 8) | data[1]);
}
///
/// 写入16位整数(Int,大端序)
///
/// DB编号
/// 偏移量
/// 16位整数
public void WriteInt(ushort dbNumber, ushort offset, short value)
{
var data = new byte[2];
data[0] = (byte)((value >> 8) & 0xFF);
data[1] = (byte)(value & 0xFF);
Write(dbNumber, offset, data);
}
///
/// 读取32位整数(DInt,大端序)
///
/// DB编号
/// 偏移量
/// 32位整数
public int ReadDInt(ushort dbNumber, ushort offset)
{
var data = Read(dbNumber, offset, 4);
return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
}
///
/// 写入32位整数(DInt,大端序)
///
/// DB编号
/// 偏移量
/// 32位整数
public void WriteDInt(ushort dbNumber, ushort offset, int value)
{
var data = new byte[4];
data[0] = (byte)((value >> 24) & 0xFF);
data[1] = (byte)((value >> 16) & 0xFF);
data[2] = (byte)((value >> 8) & 0xFF);
data[3] = (byte)(value & 0xFF);
Write(dbNumber, offset, data);
}
///
/// 读取32位浮点数(Real,IEEE 754)
///
/// DB编号
/// 偏移量
/// 32位浮点数
public float ReadReal(ushort dbNumber, ushort offset)
{
var data = Read(dbNumber, offset, 4);
// 需要转换字节序(大端序转小端序)
if (BitConverter.IsLittleEndian)
{
Array.Reverse(data);
}
return BitConverter.ToSingle(data, 0);
}
///
/// 写入32位浮点数(Real,IEEE 754)
///
/// DB编号
/// 偏移量
/// 32位浮点数
public void WriteReal(ushort dbNumber, ushort offset, float value)
{
var data = BitConverter.GetBytes(value);
// 需要转换字节序(小端序转大端序)
if (BitConverter.IsLittleEndian)
{
Array.Reverse(data);
}
Write(dbNumber, offset, data);
}
///
/// 读取字符串(S7字符串格式)
/// S7字符串格式:[最大长度(1字节)][实际长度(1字节)][字符数据]
///
/// DB编号
/// 偏移量
/// 最大长度
/// 字符串
public string ReadString(ushort dbNumber, ushort offset, byte maxLength)
{
_lock.EnterReadLock();
try
{
var block = GetBlock(dbNumber);
if (offset + 2 + maxLength > block.Length)
{
throw new ArgumentOutOfRangeException(
$"读取字符串超出DB{dbNumber}区范围: offset={offset}, maxLength={maxLength}, size={block.Length}");
}
// 读取实际长度
byte actualLength = block[offset + 1];
// 读取字符数据
if (actualLength == 0)
{
return string.Empty;
}
var chars = new char[actualLength];
for (int i = 0; i < actualLength; i++)
{
chars[i] = (char)block[offset + 2 + i];
}
return new string(chars);
}
finally
{
_lock.ExitReadLock();
}
}
///
/// 写入字符串(S7字符串格式)
/// S7字符串格式:[最大长度(1字节)][实际长度(1字节)][字符数据]
///
/// DB编号
/// 偏移量
/// 字符串值
/// 最大长度
public void WriteString(ushort dbNumber, ushort offset, string value, byte maxLength)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (value.Length > maxLength)
{
throw new ArgumentException(
$"字符串长度{value.Length}超过最大长度{maxLength}");
}
_lock.EnterWriteLock();
try
{
// 如果DB块不存在,自动创建
if (!_blocks.ContainsKey(dbNumber))
{
CreateBlock(dbNumber);
}
var block = _blocks[dbNumber];
if (offset + 2 + maxLength > block.Length)
{
throw new ArgumentOutOfRangeException(
$"写入字符串超出DB{dbNumber}区范围: offset={offset}, maxLength={maxLength}, size={block.Length}");
}
// 写入最大长度
block[offset] = maxLength;
// 写入实际长度
block[offset + 1] = (byte)value.Length;
// 写入字符数据
for (int i = 0; i < value.Length; i++)
{
block[offset + 2 + i] = (byte)value[i];
}
// 填充剩余空间为0
for (int i = value.Length; i < maxLength; i++)
{
block[offset + 2 + i] = 0;
}
}
finally
{
_lock.ExitWriteLock();
}
}
///
/// 清空所有DB块
///
public void Clear()
{
_lock.EnterWriteLock();
try
{
foreach (var block in _blocks.Values)
{
Array.Clear(block, 0, block.Length);
}
}
finally
{
_lock.ExitWriteLock();
}
}
///
/// 释放资源
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// 释放资源
///
/// 是否正在释放托管资源
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_lock?.Dispose();
_blocks.Clear();
}
_disposed = true;
}
}
}
}