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; } } } }