Implement all Modbus function except 43 (Not tested)
This commit is contained in:
219
Modbus.Net/Modbus.Net.Modbus/Interfaces.cs
Normal file
219
Modbus.Net/Modbus.Net.Modbus/Interfaces.cs
Normal file
@@ -0,0 +1,219 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Modbus.Net.Modbus
|
||||
{
|
||||
/// <summary>
|
||||
/// 异常状态获取方法
|
||||
/// </summary>
|
||||
public interface IUtilityMethodExceptionStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取异常状态
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<byte>> GetExceptionStatusAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 诊断返回数据
|
||||
/// </summary>
|
||||
public class DiagnoticsData
|
||||
{
|
||||
/// <summary>
|
||||
/// 子方法编号
|
||||
/// </summary>
|
||||
public ushort SubFunction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 诊断数据
|
||||
/// </summary>
|
||||
public ushort[] Data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 诊断获取方法
|
||||
/// </summary>
|
||||
public interface IUtilityMethodDiagnotics
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取诊断信息
|
||||
/// </summary>
|
||||
/// <param name="subFunction">子方法编号</param>
|
||||
/// <param name="data">诊断数据</param>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<DiagnoticsData>> GetDiagnoticsAsync(ushort subFunction, ushort[] data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通讯事件计数器获取数据
|
||||
/// </summary>
|
||||
public class CommEventCounterData
|
||||
{
|
||||
/// <summary>
|
||||
/// 通讯状态
|
||||
/// </summary>
|
||||
public ushort Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件计数
|
||||
/// </summary>
|
||||
public ushort EventCount { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通讯事件计数器获取方法
|
||||
/// </summary>
|
||||
public interface IUtilityMethodCommEventCounter
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取通讯事件计数器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<CommEventCounterData>> GetCommEventCounterAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通讯事件获取数据
|
||||
/// </summary>
|
||||
public class CommEventLogData
|
||||
{
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public ushort Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件内容
|
||||
/// </summary>
|
||||
public byte[] Events { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通讯事件获取方法
|
||||
/// </summary>
|
||||
public interface IUtilityMethodCommEventLog
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取通讯事件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<CommEventLogData>> GetCommEventLogAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取从站号数据
|
||||
/// </summary>
|
||||
public class SlaveIdData
|
||||
{
|
||||
/// <summary>
|
||||
/// 从站号
|
||||
/// </summary>
|
||||
public byte SlaveId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 指示状态
|
||||
/// </summary>
|
||||
public byte IndicatorStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 附加信息
|
||||
/// </summary>
|
||||
public byte[] AdditionalData { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取从站号方法
|
||||
/// </summary>
|
||||
public interface IUtilityMethodSlaveId
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取从站号
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<SlaveIdData>> GetSlaveIdAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件记录读写方法
|
||||
/// </summary>
|
||||
public interface IUtilityMethodFileRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// 读文件记录
|
||||
/// </summary>
|
||||
/// <param name="recordDefs">读文件记录定义</param>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<ReadFileRecordOutputDef[]>> GetFileRecordAsync(ReadFileRecordInputDef[] recordDefs);
|
||||
/// <summary>
|
||||
/// 写文件记录
|
||||
/// </summary>
|
||||
/// <param name="recordDefs">写文件记录定义</param>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<WriteFileRecordOutputDef[]>> SetFileRecordAsync(WriteFileRecordInputDef[] recordDefs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 掩码写入数据
|
||||
/// </summary>
|
||||
public class MaskRegisterData
|
||||
{
|
||||
/// <summary>
|
||||
/// 地址索引
|
||||
/// </summary>
|
||||
public ushort ReferenceAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 与掩码
|
||||
/// </summary>
|
||||
public ushort AndMask { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 或掩码
|
||||
/// </summary>
|
||||
public ushort OrMask { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 掩码写入方法
|
||||
/// </summary>
|
||||
public interface IUtilityMethodMaskRegister
|
||||
{
|
||||
/// <summary>
|
||||
/// 写入掩码
|
||||
/// </summary>
|
||||
/// <param name="referenceAddress">地址索引</param>
|
||||
/// <param name="andMask">与掩码</param>
|
||||
/// <param name="orMask">或掩码</param>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<MaskRegisterData>> SetMaskRegister(ushort referenceAddress, ushort andMask, ushort orMask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 寄存器读写方法
|
||||
/// </summary>
|
||||
public interface IUtilityMethodMultipleRegister
|
||||
{
|
||||
/// <summary>
|
||||
/// 读写多寄存器
|
||||
/// </summary>
|
||||
/// <param name="readStartingAddress">读起始地址</param>
|
||||
/// <param name="quantityToRead">读数量</param>
|
||||
/// <param name="writeStartingAddress">写寄存器地址</param>
|
||||
/// <param name="writeValues">写数据</param>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<ushort[]>> GetMultipleRegister(ushort readStartingAddress, ushort quantityToRead, ushort writeStartingAddress, ushort[] writeValues);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FIFO队列读取方法
|
||||
/// </summary>
|
||||
public interface IUtilityMethodFIFOQueue
|
||||
{
|
||||
/// <summary>
|
||||
/// 读FIFO队列
|
||||
/// </summary>
|
||||
/// <param name="fifoPointerAddress">FIFO队列地址</param>
|
||||
/// <returns></returns>
|
||||
Task<ReturnStruct<ushort[]>> GetFIFOQueue(ushort fifoPointerAddress);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -53,7 +53,16 @@ namespace Modbus.Net.Modbus
|
||||
/// <summary>
|
||||
/// Modbus基础Api入口
|
||||
/// </summary>
|
||||
public class ModbusUtility : BaseUtility<byte[], byte[], ProtocolUnit<byte[], byte[]>, PipeUnit>
|
||||
public class ModbusUtility : BaseUtility<byte[], byte[], ProtocolUnit<byte[], byte[]>, PipeUnit>,
|
||||
IUtilityMethodExceptionStatus,
|
||||
IUtilityMethodDiagnotics,
|
||||
IUtilityMethodCommEventCounter,
|
||||
IUtilityMethodCommEventLog,
|
||||
IUtilityMethodSlaveId,
|
||||
IUtilityMethodFileRecord,
|
||||
IUtilityMethodMaskRegister,
|
||||
IUtilityMethodMultipleRegister,
|
||||
IUtilityMethodFIFOQueue
|
||||
{
|
||||
private static readonly ILogger<ModbusUtility> logger = LogProvider.CreateLogger<ModbusUtility>();
|
||||
|
||||
@@ -242,12 +251,7 @@ namespace Modbus.Net.Modbus
|
||||
ModbusType = (ModbusType)connectionType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读数据
|
||||
/// </summary>
|
||||
/// <param name="startAddress">起始地址</param>
|
||||
/// <param name="getByteCount">获取字节个数</param>
|
||||
/// <returns>获取的结果</returns>
|
||||
/// <inheritdoc />
|
||||
public override async Task<ReturnStruct<byte[]>> GetDatasAsync(string startAddress, int getByteCount)
|
||||
{
|
||||
try
|
||||
@@ -278,12 +282,7 @@ namespace Modbus.Net.Modbus
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写数据
|
||||
/// </summary>
|
||||
/// <param name="startAddress">起始地址</param>
|
||||
/// <param name="setContents">需要设置的数据</param>
|
||||
/// <returns>设置是否成功</returns>
|
||||
/// <inheritdoc />
|
||||
public override async Task<ReturnStruct<bool>> SetDatasAsync(string startAddress, object[] setContents)
|
||||
{
|
||||
try
|
||||
@@ -313,5 +312,305 @@ namespace Modbus.Net.Modbus
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<byte>> GetExceptionStatusAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new ReadExceptionStatusModbusInputStruct(SlaveAddress);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<ReadExceptionStatusModbusOutputStruct>(Wrapper[typeof(ReadExceptionStatusModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<byte>()
|
||||
{
|
||||
Datas = outputStruct.OutputData,
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<byte>
|
||||
{
|
||||
Datas = 0,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<DiagnoticsData>> GetDiagnoticsAsync(ushort subFunction, ushort[] data)
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new DiagnoticsModbusInputStruct(SlaveAddress, subFunction, data);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<DiagnoticsModbusOutputStruct>(Wrapper[typeof(DiagnoticsModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<DiagnoticsData>()
|
||||
{
|
||||
Datas = new DiagnoticsData() { SubFunction = outputStruct.SubFunction, Data = outputStruct.Data },
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<DiagnoticsData>
|
||||
{
|
||||
Datas = null,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<CommEventCounterData>> GetCommEventCounterAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new GetCommEventCounterModbusInputStruct(SlaveAddress);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<GetCommEventCounterModbusOutputStruct>(Wrapper[typeof(GetCommEventCounterModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<CommEventCounterData>()
|
||||
{
|
||||
Datas = new CommEventCounterData() { EventCount = outputStruct.EventCount, Status = outputStruct.Status },
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<CommEventCounterData>
|
||||
{
|
||||
Datas = null,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<CommEventLogData>> GetCommEventLogAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new GetCommEventLogModbusInputStruct(SlaveAddress);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<GetCommEventLogModbusOutputStruct>(Wrapper[typeof(GetCommEventLogModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<CommEventLogData>()
|
||||
{
|
||||
Datas = new CommEventLogData() { Status = outputStruct.Status, Events = outputStruct.Events},
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<CommEventLogData>
|
||||
{
|
||||
Datas = null,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<SlaveIdData>> GetSlaveIdAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new ReportSlaveIdModbusInputStruct(SlaveAddress);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<ReportSlaveIdModbusOutputStruct>(Wrapper[typeof(ReportSlaveIdModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<SlaveIdData>()
|
||||
{
|
||||
Datas = new SlaveIdData() { SlaveId = outputStruct.SlaveId, IndicatorStatus = outputStruct.RunIndicatorStatus, AdditionalData = outputStruct.AdditionalData},
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<SlaveIdData>
|
||||
{
|
||||
Datas = null,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<ReadFileRecordOutputDef[]>> GetFileRecordAsync(ReadFileRecordInputDef[] recordDefs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new ReadFileRecordModbusInputStruct(SlaveAddress, recordDefs);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<ReadFileRecordModbusOutputStruct>(Wrapper[typeof(ReadFileRecordModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<ReadFileRecordOutputDef[]>()
|
||||
{
|
||||
Datas = outputStruct.RecordDefs,
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<ReadFileRecordOutputDef[]>
|
||||
{
|
||||
Datas = null,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<WriteFileRecordOutputDef[]>> SetFileRecordAsync(WriteFileRecordInputDef[] recordDefs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new WriteFileRecordModbusInputStruct(SlaveAddress, recordDefs);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<WriteFileRecordModbusOutputStruct>(Wrapper[typeof(WriteFileRecordModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<WriteFileRecordOutputDef[]>()
|
||||
{
|
||||
Datas = outputStruct.WriteRecords,
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<WriteFileRecordOutputDef[]>
|
||||
{
|
||||
Datas = null,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<MaskRegisterData>> SetMaskRegister(ushort referenceAddress, ushort andMask, ushort orMask)
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new MaskWriteRegisterModbusInputStruct(SlaveAddress, referenceAddress, andMask, orMask);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<MaskWriteRegisterModbusOutputStruct>(Wrapper[typeof(MaskWriteRegisterModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<MaskRegisterData>()
|
||||
{
|
||||
Datas = new MaskRegisterData() { ReferenceAddress = outputStruct.ReferenceAddress, AndMask = outputStruct.AndMask, OrMask = outputStruct.OrMask},
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<MaskRegisterData>
|
||||
{
|
||||
Datas = null,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<ushort[]>> GetMultipleRegister(ushort readStartingAddress, ushort quantityToRead, ushort writeStartingAddress, ushort[] writeValues)
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new ReadWriteMultipleRegistersModbusInputStruct(SlaveAddress, readStartingAddress, quantityToRead, writeStartingAddress, writeValues);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<ReadWriteMultipleRegistersModbusOutputStruct>(Wrapper[typeof(ReadWriteMultipleRegistersModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<ushort[]>()
|
||||
{
|
||||
Datas = outputStruct.ReadRegisterValues,
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<ushort[]>
|
||||
{
|
||||
Datas = null,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ReturnStruct<ushort[]>> GetFIFOQueue(ushort fifoPointerAddress)
|
||||
{
|
||||
try
|
||||
{
|
||||
var inputStruct = new ReadFIFOQueueModbusInputStruct(SlaveAddress, fifoPointerAddress);
|
||||
var outputStruct = await
|
||||
Wrapper.SendReceiveAsync<ReadFIFOQueueModbusOutputStruct>(Wrapper[typeof(ReadFIFOQueueModbusProtocol)],
|
||||
inputStruct);
|
||||
return new ReturnStruct<ushort[]>()
|
||||
{
|
||||
Datas = outputStruct.FIFOValueRegister,
|
||||
IsSuccess = true,
|
||||
ErrorCode = 0,
|
||||
ErrorMsg = null
|
||||
};
|
||||
}
|
||||
catch (ModbusProtocolErrorException e)
|
||||
{
|
||||
logger.LogError(e, $"ModbusUtility -> SetDatas: {ConnectionString} error: {e.Message}");
|
||||
return new ReturnStruct<ushort[]>
|
||||
{
|
||||
Datas = null,
|
||||
IsSuccess = false,
|
||||
ErrorCode = e.ErrorMessageNumber,
|
||||
ErrorMsg = e.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user