mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-20 16:13:34 +08:00
Transfer buffering system detemplatized; compiles but tests are failing
This commit is contained in:
@@ -86,14 +86,14 @@ class UAVCAN_EXPORT Dispatcher : Noncopyable
|
||||
|
||||
class ListenerRegistry
|
||||
{
|
||||
LinkedListRoot<TransferListenerBase> list_;
|
||||
LinkedListRoot<TransferListener> list_;
|
||||
|
||||
class DataTypeIDInsertionComparator
|
||||
{
|
||||
const DataTypeID id_;
|
||||
public:
|
||||
explicit DataTypeIDInsertionComparator(DataTypeID id) : id_(id) { }
|
||||
bool operator()(const TransferListenerBase* listener) const
|
||||
bool operator()(const TransferListener* listener) const
|
||||
{
|
||||
UAVCAN_ASSERT(listener);
|
||||
return id_ > listener->getDataTypeDescriptor().getID();
|
||||
@@ -103,15 +103,15 @@ class UAVCAN_EXPORT Dispatcher : Noncopyable
|
||||
public:
|
||||
enum Mode { UniqueListener, ManyListeners };
|
||||
|
||||
bool add(TransferListenerBase* listener, Mode mode);
|
||||
void remove(TransferListenerBase* listener);
|
||||
bool add(TransferListener* listener, Mode mode);
|
||||
void remove(TransferListener* listener);
|
||||
bool exists(DataTypeID dtid) const;
|
||||
void cleanup(MonotonicTime ts);
|
||||
void handleFrame(const RxFrame& frame);
|
||||
|
||||
unsigned getNumEntries() const { return list_.getLength(); }
|
||||
|
||||
const LinkedListRoot<TransferListenerBase>& getList() const { return list_; }
|
||||
const LinkedListRoot<TransferListener>& getList() const { return list_; }
|
||||
};
|
||||
|
||||
ListenerRegistry lmsg_;
|
||||
@@ -162,13 +162,13 @@ public:
|
||||
|
||||
void cleanup(MonotonicTime ts);
|
||||
|
||||
bool registerMessageListener(TransferListenerBase* listener);
|
||||
bool registerServiceRequestListener(TransferListenerBase* listener);
|
||||
bool registerServiceResponseListener(TransferListenerBase* listener);
|
||||
bool registerMessageListener(TransferListener* listener);
|
||||
bool registerServiceRequestListener(TransferListener* listener);
|
||||
bool registerServiceResponseListener(TransferListener* listener);
|
||||
|
||||
void unregisterMessageListener(TransferListenerBase* listener);
|
||||
void unregisterServiceRequestListener(TransferListenerBase* listener);
|
||||
void unregisterServiceResponseListener(TransferListenerBase* listener);
|
||||
void unregisterMessageListener(TransferListener* listener);
|
||||
void unregisterServiceRequestListener(TransferListener* listener);
|
||||
void unregisterServiceResponseListener(TransferListener* listener);
|
||||
|
||||
bool hasSubscriber(DataTypeID dtid) const;
|
||||
bool hasPublisher(DataTypeID dtid) const;
|
||||
@@ -185,15 +185,15 @@ public:
|
||||
* removed from this list as soon as the corresponding service call is complete.
|
||||
* @{
|
||||
*/
|
||||
const LinkedListRoot<TransferListenerBase>& getListOfMessageListeners() const
|
||||
const LinkedListRoot<TransferListener>& getListOfMessageListeners() const
|
||||
{
|
||||
return lmsg_.getList();
|
||||
}
|
||||
const LinkedListRoot<TransferListenerBase>& getListOfServiceRequestListeners() const
|
||||
const LinkedListRoot<TransferListener>& getListOfServiceRequestListeners() const
|
||||
{
|
||||
return lsrv_req_.getList();
|
||||
}
|
||||
const LinkedListRoot<TransferListenerBase>& getListOfServiceResponseListeners() const
|
||||
const LinkedListRoot<TransferListener>& getListOfServiceResponseListeners() const
|
||||
{
|
||||
return lsrv_resp_.getList();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,47 @@
|
||||
|
||||
namespace uavcan
|
||||
{
|
||||
/**
|
||||
* Standalone static buffer
|
||||
*/
|
||||
class StaticTransferBufferImpl : public ITransferBuffer
|
||||
{
|
||||
uint8_t* const data_;
|
||||
const uint16_t size_;
|
||||
uint16_t max_write_pos_;
|
||||
|
||||
public:
|
||||
StaticTransferBufferImpl(uint8_t* buf, uint16_t buf_size) :
|
||||
data_(buf),
|
||||
size_(buf_size),
|
||||
max_write_pos_(0)
|
||||
{ }
|
||||
|
||||
virtual int read(unsigned offset, uint8_t* data, unsigned len) const;
|
||||
virtual int write(unsigned offset, const uint8_t* data, unsigned len);
|
||||
|
||||
void reset();
|
||||
|
||||
uint16_t getSize() const { return size_; }
|
||||
|
||||
uint8_t* getRawPtr() { return data_; }
|
||||
const uint8_t* getRawPtr() const { return data_; }
|
||||
|
||||
uint16_t getMaxWritePos() const { return max_write_pos_; }
|
||||
void setMaxWritePos(uint16_t value) { max_write_pos_ = value; }
|
||||
};
|
||||
|
||||
template <uint16_t Size>
|
||||
class UAVCAN_EXPORT StaticTransferBuffer : public StaticTransferBufferImpl
|
||||
{
|
||||
uint8_t buffer_[Size];
|
||||
public:
|
||||
StaticTransferBuffer() : StaticTransferBufferImpl(buffer_, Size)
|
||||
{
|
||||
StaticAssert<(Size > 0)>::check();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal for TransferBufferManager
|
||||
*/
|
||||
@@ -53,41 +94,13 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal for TransferBufferManager
|
||||
*/
|
||||
class UAVCAN_EXPORT TransferBufferManagerEntry : public ITransferBuffer, Noncopyable
|
||||
{
|
||||
TransferBufferManagerKey key_;
|
||||
|
||||
protected:
|
||||
virtual void resetImpl() = 0;
|
||||
|
||||
public:
|
||||
TransferBufferManagerEntry() { }
|
||||
|
||||
explicit TransferBufferManagerEntry(const TransferBufferManagerKey& key)
|
||||
: key_(key)
|
||||
{ }
|
||||
|
||||
const TransferBufferManagerKey& getKey() const { return key_; }
|
||||
bool isEmpty() const { return key_.isEmpty(); }
|
||||
|
||||
void reset(const TransferBufferManagerKey& key = TransferBufferManagerKey())
|
||||
{
|
||||
key_ = key;
|
||||
resetImpl();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Resizable gather/scatter storage.
|
||||
* reset() call releases all memory blocks.
|
||||
* Supports unordered write operations - from higher to lower offsets
|
||||
*/
|
||||
class UAVCAN_EXPORT DynamicTransferBufferManagerEntry
|
||||
: public TransferBufferManagerEntry
|
||||
, public LinkedListNode<DynamicTransferBufferManagerEntry>
|
||||
class UAVCAN_EXPORT TransferBufferManagerEntry : public ITransferBuffer
|
||||
, public LinkedListNode<TransferBufferManagerEntry>
|
||||
{
|
||||
struct Block : LinkedListNode<Block>
|
||||
{
|
||||
@@ -107,116 +120,58 @@ class UAVCAN_EXPORT DynamicTransferBufferManagerEntry
|
||||
LinkedListRoot<Block> blocks_; // Blocks are ordered from lower to higher buffer offset
|
||||
uint16_t max_write_pos_;
|
||||
const uint16_t max_size_;
|
||||
|
||||
/// Reset functionality must be implemented in a non-virtual method to call it safely from the destructor.
|
||||
void doReset();
|
||||
|
||||
virtual void resetImpl();
|
||||
TransferBufferManagerKey key_;
|
||||
|
||||
public:
|
||||
DynamicTransferBufferManagerEntry(IPoolAllocator& allocator, uint16_t max_size)
|
||||
: allocator_(allocator)
|
||||
, max_write_pos_(0)
|
||||
, max_size_(max_size)
|
||||
TransferBufferManagerEntry(IPoolAllocator& allocator, uint16_t max_size) :
|
||||
allocator_(allocator),
|
||||
max_write_pos_(0),
|
||||
max_size_(max_size)
|
||||
{
|
||||
StaticAssert<(Block::Size > 8)>::check();
|
||||
IsDynamicallyAllocatable<Block>::check();
|
||||
IsDynamicallyAllocatable<DynamicTransferBufferManagerEntry>::check();
|
||||
IsDynamicallyAllocatable<TransferBufferManagerEntry>::check();
|
||||
}
|
||||
|
||||
virtual ~DynamicTransferBufferManagerEntry()
|
||||
{
|
||||
doReset();
|
||||
}
|
||||
virtual ~TransferBufferManagerEntry() { reset(); }
|
||||
|
||||
static DynamicTransferBufferManagerEntry* instantiate(IPoolAllocator& allocator, uint16_t max_size);
|
||||
static void destroy(DynamicTransferBufferManagerEntry*& obj, IPoolAllocator& allocator);
|
||||
|
||||
virtual int read(unsigned offset, uint8_t* data, unsigned len) const;
|
||||
virtual int write(unsigned offset, const uint8_t* data, unsigned len);
|
||||
};
|
||||
|
||||
/**
|
||||
* Standalone static buffer
|
||||
*/
|
||||
class StaticTransferBufferImpl : public ITransferBuffer
|
||||
{
|
||||
uint8_t* const data_;
|
||||
const uint16_t size_;
|
||||
uint16_t max_write_pos_;
|
||||
|
||||
public:
|
||||
StaticTransferBufferImpl(uint8_t* buf, uint16_t buf_size)
|
||||
: data_(buf)
|
||||
, size_(buf_size)
|
||||
, max_write_pos_(0)
|
||||
{ }
|
||||
static TransferBufferManagerEntry* instantiate(IPoolAllocator& allocator, uint16_t max_size);
|
||||
static void destroy(TransferBufferManagerEntry*& obj, IPoolAllocator& allocator);
|
||||
|
||||
virtual int read(unsigned offset, uint8_t* data, unsigned len) const;
|
||||
virtual int write(unsigned offset, const uint8_t* data, unsigned len);
|
||||
|
||||
void reset();
|
||||
void reset(const TransferBufferManagerKey& key = TransferBufferManagerKey());
|
||||
|
||||
uint16_t getSize() const { return size_; }
|
||||
|
||||
uint8_t* getRawPtr() { return data_; }
|
||||
const uint8_t* getRawPtr() const { return data_; }
|
||||
|
||||
uint16_t getMaxWritePos() const { return max_write_pos_; }
|
||||
void setMaxWritePos(uint16_t value) { max_write_pos_ = value; }
|
||||
};
|
||||
|
||||
template <uint16_t Size>
|
||||
class UAVCAN_EXPORT StaticTransferBuffer : public StaticTransferBufferImpl
|
||||
{
|
||||
uint8_t buffer_[Size];
|
||||
public:
|
||||
StaticTransferBuffer()
|
||||
: StaticTransferBufferImpl(buffer_, Size)
|
||||
{
|
||||
StaticAssert<(Size > 0)>::check();
|
||||
}
|
||||
const TransferBufferManagerKey& getKey() const { return key_; }
|
||||
bool isEmpty() const { return key_.isEmpty(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Statically allocated storage for the buffer manager
|
||||
* Buffer manager implementation.
|
||||
*/
|
||||
class StaticTransferBufferManagerEntryImpl : public TransferBufferManagerEntry
|
||||
class TransferBufferManager : public Noncopyable
|
||||
{
|
||||
StaticTransferBufferImpl buf_;
|
||||
LinkedListRoot<TransferBufferManagerEntry> buffers_;
|
||||
IPoolAllocator& allocator_;
|
||||
const uint16_t max_buf_size_;
|
||||
|
||||
virtual void resetImpl();
|
||||
TransferBufferManagerEntry* findFirst(const TransferBufferManagerKey& key);
|
||||
|
||||
public:
|
||||
StaticTransferBufferManagerEntryImpl(uint8_t* buf, uint16_t buf_size)
|
||||
: buf_(buf, buf_size)
|
||||
TransferBufferManager(uint16_t max_buf_size, IPoolAllocator& allocator) :
|
||||
allocator_(allocator),
|
||||
max_buf_size_(max_buf_size)
|
||||
{ }
|
||||
|
||||
virtual int read(unsigned offset, uint8_t* data, unsigned len) const;
|
||||
virtual int write(unsigned offset, const uint8_t* data, unsigned len);
|
||||
};
|
||||
~TransferBufferManager();
|
||||
|
||||
template <uint16_t Size>
|
||||
class UAVCAN_EXPORT StaticTransferBufferManagerEntry : public StaticTransferBufferManagerEntryImpl
|
||||
{
|
||||
uint8_t buffer_[Size];
|
||||
public:
|
||||
StaticTransferBufferManagerEntry()
|
||||
: StaticTransferBufferManagerEntryImpl(buffer_, Size)
|
||||
{ }
|
||||
};
|
||||
ITransferBuffer* access(const TransferBufferManagerKey& key);
|
||||
ITransferBuffer* create(const TransferBufferManagerKey& key);
|
||||
void remove(const TransferBufferManagerKey& key);
|
||||
bool isEmpty() const;
|
||||
|
||||
/**
|
||||
* Manages different storage types (static/dynamic) for transfer reception logic.
|
||||
*/
|
||||
class UAVCAN_EXPORT ITransferBufferManager
|
||||
{
|
||||
public:
|
||||
virtual ~ITransferBufferManager() { }
|
||||
virtual ITransferBuffer* access(const TransferBufferManagerKey& key) = 0;
|
||||
virtual ITransferBuffer* create(const TransferBufferManagerKey& key) = 0;
|
||||
virtual void remove(const TransferBufferManagerKey& key) = 0;
|
||||
virtual bool isEmpty() const = 0;
|
||||
unsigned getNumBuffers() const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -224,13 +179,13 @@ public:
|
||||
*/
|
||||
class UAVCAN_EXPORT TransferBufferAccessor
|
||||
{
|
||||
ITransferBufferManager& bufmgr_;
|
||||
TransferBufferManager& bufmgr_;
|
||||
const TransferBufferManagerKey key_;
|
||||
|
||||
public:
|
||||
TransferBufferAccessor(ITransferBufferManager& bufmgr, TransferBufferManagerKey key)
|
||||
: bufmgr_(bufmgr)
|
||||
, key_(key)
|
||||
TransferBufferAccessor(TransferBufferManager& bufmgr, TransferBufferManagerKey key) :
|
||||
bufmgr_(bufmgr),
|
||||
key_(key)
|
||||
{
|
||||
UAVCAN_ASSERT(!key.isEmpty());
|
||||
}
|
||||
@@ -239,54 +194,6 @@ public:
|
||||
void remove() { bufmgr_.remove(key_); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer manager implementation.
|
||||
*/
|
||||
class TransferBufferManagerImpl : public ITransferBufferManager, Noncopyable
|
||||
{
|
||||
LinkedListRoot<DynamicTransferBufferManagerEntry> dynamic_buffers_;
|
||||
IPoolAllocator& allocator_;
|
||||
const uint16_t max_buf_size_;
|
||||
|
||||
DynamicTransferBufferManagerEntry* findFirstDynamic(const TransferBufferManagerKey& key);
|
||||
|
||||
public:
|
||||
TransferBufferManagerImpl(uint16_t max_buf_size, IPoolAllocator& allocator)
|
||||
: allocator_(allocator)
|
||||
, max_buf_size_(max_buf_size)
|
||||
{ }
|
||||
|
||||
virtual ~TransferBufferManagerImpl();
|
||||
|
||||
virtual ITransferBuffer* access(const TransferBufferManagerKey& key);
|
||||
virtual ITransferBuffer* create(const TransferBufferManagerKey& key);
|
||||
virtual void remove(const TransferBufferManagerKey& key);
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
unsigned getNumBuffers() const;
|
||||
};
|
||||
|
||||
template <uint16_t MaxBufSize>
|
||||
class UAVCAN_EXPORT TransferBufferManager : public TransferBufferManagerImpl
|
||||
{
|
||||
public:
|
||||
explicit TransferBufferManager(IPoolAllocator& allocator) :
|
||||
TransferBufferManagerImpl(MaxBufSize, allocator)
|
||||
{ }
|
||||
};
|
||||
|
||||
template <>
|
||||
class UAVCAN_EXPORT TransferBufferManager<0> : public ITransferBufferManager
|
||||
{
|
||||
public:
|
||||
TransferBufferManager() { }
|
||||
TransferBufferManager(IPoolAllocator&) { }
|
||||
virtual ITransferBuffer* access(const TransferBufferManagerKey&) { return NULL; }
|
||||
virtual ITransferBuffer* create(const TransferBufferManagerKey&) { return NULL; }
|
||||
virtual void remove(const TransferBufferManagerKey&) { }
|
||||
virtual bool isEmpty() const { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // UAVCAN_TRANSPORT_TRANSFER_BUFFER_HPP_INCLUDED
|
||||
|
||||
@@ -96,11 +96,11 @@ public:
|
||||
/**
|
||||
* Internal, refer to the transport dispatcher class.
|
||||
*/
|
||||
class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListenerBase>, Noncopyable
|
||||
class UAVCAN_EXPORT TransferListener : public LinkedListNode<TransferListener>, Noncopyable
|
||||
{
|
||||
const DataTypeDescriptor& data_type_;
|
||||
Map<TransferBufferManagerKey, TransferReceiver>& receivers_;
|
||||
ITransferBufferManager& bufmgr_;
|
||||
TransferBufferManager bufmgr_;
|
||||
Map<TransferBufferManagerKey, TransferReceiver> receivers_;
|
||||
TransferPerfCounter& perf_;
|
||||
const TransferCRC crc_base_; ///< Pre-initialized with data type hash, thus constant
|
||||
bool allow_anonymous_transfers_;
|
||||
@@ -108,10 +108,10 @@ class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListene
|
||||
class TimedOutReceiverPredicate
|
||||
{
|
||||
const MonotonicTime ts_;
|
||||
ITransferBufferManager& parent_bufmgr_;
|
||||
TransferBufferManager& parent_bufmgr_;
|
||||
|
||||
public:
|
||||
TimedOutReceiverPredicate(MonotonicTime arg_ts, ITransferBufferManager& arg_bufmgr)
|
||||
TimedOutReceiverPredicate(MonotonicTime arg_ts, TransferBufferManager& arg_bufmgr)
|
||||
: ts_(arg_ts)
|
||||
, parent_bufmgr_(arg_bufmgr)
|
||||
{ }
|
||||
@@ -122,25 +122,28 @@ class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListene
|
||||
bool checkPayloadCrc(const uint16_t compare_with, const ITransferBuffer& tbb) const;
|
||||
|
||||
protected:
|
||||
TransferListenerBase(TransferPerfCounter& perf, const DataTypeDescriptor& data_type,
|
||||
Map<TransferBufferManagerKey, TransferReceiver>& receivers,
|
||||
ITransferBufferManager& bufmgr)
|
||||
: data_type_(data_type)
|
||||
, receivers_(receivers)
|
||||
, bufmgr_(bufmgr)
|
||||
, perf_(perf)
|
||||
, crc_base_(data_type.getSignature().toTransferCRC())
|
||||
, allow_anonymous_transfers_(false)
|
||||
{ }
|
||||
|
||||
virtual ~TransferListenerBase() { }
|
||||
|
||||
void handleReception(TransferReceiver& receiver, const RxFrame& frame, TransferBufferAccessor& tba);
|
||||
void handleAnonymousTransferReception(const RxFrame& frame);
|
||||
|
||||
virtual void handleIncomingTransfer(IncomingTransfer& transfer) = 0;
|
||||
|
||||
public:
|
||||
TransferListener(TransferPerfCounter& perf, const DataTypeDescriptor& data_type,
|
||||
uint16_t max_buffer_size, IPoolAllocator& allocator)
|
||||
: data_type_(data_type)
|
||||
, bufmgr_(max_buffer_size, allocator)
|
||||
, receivers_(allocator)
|
||||
, perf_(perf)
|
||||
, crc_base_(data_type.getSignature().toTransferCRC())
|
||||
, allow_anonymous_transfers_(false)
|
||||
{ }
|
||||
|
||||
virtual ~TransferListener()
|
||||
{
|
||||
// Map must be cleared before bufmgr is destroyed
|
||||
receivers_.clear();
|
||||
}
|
||||
|
||||
const DataTypeDescriptor& getDataTypeDescriptor() const { return data_type_; }
|
||||
|
||||
/**
|
||||
@@ -154,29 +157,6 @@ public:
|
||||
virtual void handleFrame(const RxFrame& frame);
|
||||
};
|
||||
|
||||
/**
|
||||
* This class should be derived by transfer receivers (subscribers, servers).
|
||||
*/
|
||||
template <unsigned MaxBufSize>
|
||||
class UAVCAN_EXPORT TransferListener : public TransferListenerBase
|
||||
{
|
||||
TransferBufferManager<MaxBufSize> bufmgr_;
|
||||
Map<TransferBufferManagerKey, TransferReceiver> receivers_;
|
||||
|
||||
public:
|
||||
TransferListener(TransferPerfCounter& perf, const DataTypeDescriptor& data_type, IPoolAllocator& allocator)
|
||||
: TransferListenerBase(perf, data_type, receivers_, bufmgr_)
|
||||
, bufmgr_(allocator)
|
||||
, receivers_(allocator)
|
||||
{ }
|
||||
|
||||
virtual ~TransferListener()
|
||||
{
|
||||
// Map must be cleared before bufmgr is destroyed
|
||||
receivers_.clear();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This class is used by transfer listener to decide if the frame should be accepted or ignored.
|
||||
*/
|
||||
@@ -194,19 +174,16 @@ public:
|
||||
/**
|
||||
* This class should be derived by callers.
|
||||
*/
|
||||
template <unsigned MaxBufSize>
|
||||
class UAVCAN_EXPORT TransferListenerWithFilter : public TransferListener<MaxBufSize>
|
||||
class UAVCAN_EXPORT TransferListenerWithFilter : public TransferListener
|
||||
{
|
||||
const ITransferAcceptanceFilter* filter_;
|
||||
|
||||
virtual void handleFrame(const RxFrame& frame);
|
||||
|
||||
public:
|
||||
typedef TransferListener<MaxBufSize> BaseType;
|
||||
|
||||
TransferListenerWithFilter(TransferPerfCounter& perf, const DataTypeDescriptor& data_type,
|
||||
IPoolAllocator& allocator)
|
||||
: BaseType(perf, data_type, allocator)
|
||||
uint16_t max_buffer_size, IPoolAllocator& allocator)
|
||||
: TransferListener(perf, data_type, max_buffer_size, allocator)
|
||||
, filter_(NULL)
|
||||
{ }
|
||||
|
||||
@@ -216,27 +193,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* TransferListenerWithFilter<>
|
||||
*/
|
||||
template <unsigned MaxBufSize>
|
||||
void TransferListenerWithFilter<MaxBufSize>::handleFrame(const RxFrame& frame)
|
||||
{
|
||||
if (filter_ != NULL)
|
||||
{
|
||||
if (filter_->shouldAcceptFrame(frame))
|
||||
{
|
||||
BaseType::handleFrame(frame);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UAVCAN_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // UAVCAN_TRANSPORT_TRANSFER_LISTENER_HPP_INCLUDED
|
||||
|
||||
Reference in New Issue
Block a user