can somewhat count on time with soft proton
This commit is contained in:
+190
-131
@@ -25,23 +25,9 @@
|
||||
# SHUTTER2_PV: PV of a second shutter state will be taken as a gate signal for the protoon current
|
||||
# SHUTTER2_CLOSED_VAL: Value of the shutter PV when the shutter is closed
|
||||
|
||||
record(mbbi, "$(INSTR)$(NAME):STATUS")
|
||||
{
|
||||
field(DESC, "DAQ Status")
|
||||
field(ZRVL, "0")
|
||||
field(ZRST, "Idle")
|
||||
field(ONVL, "1")
|
||||
field(ONST, "Counting")
|
||||
field(TWVL, "2")
|
||||
field(TWST, "Low rate")
|
||||
field(THVL, "3")
|
||||
field(THST, "Paused")
|
||||
# 4 should never happen, if it does it means the DAQ reports undocumented statusbits
|
||||
field(FRVL, "4")
|
||||
field(FRST, "INVALID")
|
||||
# We start in idle
|
||||
field(VAL, 0)
|
||||
}
|
||||
################################################################################
|
||||
# Count Config
|
||||
################################################################################
|
||||
|
||||
record(longin, "$(INSTR)$(NAME):CHANNELS")
|
||||
{
|
||||
@@ -63,43 +49,44 @@ record(bi, "$(INSTR)$(NAME):IS_LOWRATE")
|
||||
field(ONAM, "GOOD RATE")
|
||||
}
|
||||
|
||||
record(longout,"$(INSTR)$(NAME):THRESHOLD-MONITOR")
|
||||
{
|
||||
# Alias to RBV to be compatible with higher level interface
|
||||
alias("$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV")
|
||||
field(DESC, "Channel monitored for minimum rate")
|
||||
field(VAL, "1") # Monitor
|
||||
field(DRVL, "0") # Smallest Threshold Channel (0 is off)
|
||||
field(DRVH, "1") # Largest Threshold Channel
|
||||
}
|
||||
|
||||
record(ao,"$(INSTR)$(NAME):THRESHOLD")
|
||||
{
|
||||
# Alias to RBV to be compatible with higher level interface
|
||||
alias("$(INSTR)$(NAME):THRESHOLD_RBV")
|
||||
field(DESC, "Minimum rate for counting to proceed")
|
||||
field(VAL, "1") # Default Rate
|
||||
field(DRVL, "1") # Minimum Rate
|
||||
field(DRVH, "100000") # Maximum Rate
|
||||
field(OMSL, "supervisory")
|
||||
}
|
||||
|
||||
record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL")
|
||||
{
|
||||
alias("$(INSTR)$(NAME):MONITOR-CHANNEL_RBV")
|
||||
field(DESC, "Count preset channel")
|
||||
field(VAL, 1)
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Commands
|
||||
################################################################################
|
||||
|
||||
record(ao, "$(INSTR)$(NAME):PRESET_COUNT")
|
||||
record(seq, "$(INSTR)$(NAME):START")
|
||||
{
|
||||
field(DESC, "Count until preset reached")
|
||||
field(VAL, 0)
|
||||
field(PREC, 2)
|
||||
field(FLNK, "$(INSTR)$(NAME):PRESET_COUNT-TRIG")
|
||||
}
|
||||
|
||||
record(longout, "$(INSTR)$(NAME):PRESET_COUNT-TRIG")
|
||||
{
|
||||
field(DESC, "Count until preset reached")
|
||||
# Signal count preset as command
|
||||
field(VAL, 1)
|
||||
field(OUT, "$(INSTR)$(NAME):COMMAND-TRIG PP")
|
||||
field(FLNK, "$(INSTR)$(NAME):COUNT-TYPE")
|
||||
}
|
||||
|
||||
record(ao, "$(INSTR)$(NAME):PRESET_TIME")
|
||||
{
|
||||
field(DESC, "Count for specified time")
|
||||
field(VAL, 0)
|
||||
field(PREC, 2)
|
||||
field(EGU, "seconds")
|
||||
field(FLNK, "$(INSTR)$(NAME):PRESET_TIME-TRIG")
|
||||
}
|
||||
|
||||
record(longout, "$(INSTR)$(NAME):PRESET_TIME-TRIG")
|
||||
{
|
||||
field(DESC, "Count until preset time reached")
|
||||
# Signal count preset as command
|
||||
field(VAL, 2)
|
||||
field(OUT, "$(INSTR)$(NAME):COMMAND-TRIG PP")
|
||||
field(FLNK, "$(INSTR)$(NAME):COUNT-TYPE")
|
||||
field(DESC, "Start a count")
|
||||
field(SELM, "All")
|
||||
field(DO0, 1)
|
||||
field(LNK0, "$(INSTR)$(NAME):COMMAND-TRIG PP")
|
||||
}
|
||||
|
||||
record(seq, "$(INSTR)$(NAME):PAUSE")
|
||||
@@ -131,22 +118,7 @@ record(seq, "$(INSTR)$(NAME):FULL-RESET")
|
||||
field(DESC, "Perform full reset")
|
||||
field(SELM, "All")
|
||||
field(DO0, 6)
|
||||
field(LNK0, "$(INSTR)$(NAME):COMMAND-TRIG PP")
|
||||
}
|
||||
|
||||
# Emulate Reset elapsed time
|
||||
# 0. set status to busy
|
||||
# 1. set elapsed time to 0
|
||||
# 2. set status to OK
|
||||
record(seq, "$(INSTR)$(NAME):T_CLEAR")
|
||||
{
|
||||
field(SELM, "All")
|
||||
field(LNK0, "$(INSTR)$(NAME):T_STS PP")
|
||||
field(DO0, 1)
|
||||
field(LNK1, "$(INSTR)$(NAME):T PP")
|
||||
field(DO1, 0)
|
||||
field(LNK2, "$(INSTR)$(NAME):T_STS PP")
|
||||
field(DO2, 0)
|
||||
field(LNK0, "$(INSTR)$(NAME):COMMAND-TRIG PP")
|
||||
}
|
||||
|
||||
# Record is to signal command given by the client to the emulated counter.
|
||||
@@ -159,8 +131,8 @@ record(mbbi, "$(INSTR)$(NAME):COMMAND-TRIG")
|
||||
field(ZRVL, 0)
|
||||
field(ONST, "Count preset command")
|
||||
field(ONVL, 1)
|
||||
field(TWST, "Time preset command")
|
||||
field(TWVL, 2)
|
||||
# field(TWST, "Time preset command")
|
||||
# field(TWVL, 2)
|
||||
field(THST, "Pause command")
|
||||
field(THVL, 3)
|
||||
field(FRST, "Continue command")
|
||||
@@ -171,53 +143,31 @@ record(mbbi, "$(INSTR)$(NAME):COMMAND-TRIG")
|
||||
field(SXVL, 6)
|
||||
}
|
||||
|
||||
# Copy COMMAND-TRIG to memorize what type of count is on-going
|
||||
record(longin, "$(INSTR)$(NAME):COUNT-TYPE") {
|
||||
field(INP, "$(INSTR)$(NAME):COMMAND-TRIG.VAL NPP")
|
||||
field(VAL, 0)
|
||||
# Identical to FULL-RESET
|
||||
record(seq, "$(INSTR)$(NAME):RESET")
|
||||
{
|
||||
field(SELM, "All")
|
||||
field(DO0, 1)
|
||||
field(LNK0, "$(INSTR)$(NAME):FULL-RESET.PROC PP")
|
||||
}
|
||||
|
||||
record(longout,"$(INSTR)$(NAME):THRESHOLD-MONITOR")
|
||||
{
|
||||
# Alias to RBV to be compatible with higher level interface
|
||||
alias("$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV")
|
||||
field(DESC, "Channel monitored for minimum rate")
|
||||
field(VAL, "1") # Monitor
|
||||
field(DRVL, "0") # Smallest Threshold Channel (0 is off)
|
||||
field(DRVH, "1") # Largest Threshold Channel
|
||||
}
|
||||
################################################################################
|
||||
# Poll Loop
|
||||
################################################################################
|
||||
|
||||
record(ao,"$(INSTR)$(NAME):THRESHOLD")
|
||||
{
|
||||
# Alias to RBV to be compatible with higher level interface
|
||||
alias("$(INSTR)$(NAME):THRESHOLD_RBV")
|
||||
field(DESC, "Minimum rate for counting to proceed")
|
||||
field(VAL, "1") # Default Rate
|
||||
field(DRVL, "1") # Minimum Rate
|
||||
field(DRVH, "100000") # Maximum Rate
|
||||
field(OMSL, "supervisory")
|
||||
}
|
||||
# TODO need to reset the presets to 0 after the count
|
||||
|
||||
record(ai,"$(INSTR)$(NAME):T")
|
||||
record(dfanout, "$(INSTR)$(NAME):DB_POLL")
|
||||
{
|
||||
field(DESC, "DAQ Measured Time")
|
||||
field(EGU, "sec")
|
||||
}
|
||||
|
||||
# Current Status of elapsed time
|
||||
record(bi, "$(INSTR)$(NAME):T_STS")
|
||||
{
|
||||
field(DESC, "Channel Status")
|
||||
field(VAL, 0)
|
||||
field(ZNAM, "Idle")
|
||||
field(ONAM, "Busy")
|
||||
}
|
||||
|
||||
record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL")
|
||||
{
|
||||
alias("$(INSTR)$(NAME):MONITOR-CHANNEL_RBV")
|
||||
field(DESC, "PRESET_COUNT Monitors this channel")
|
||||
field(VAL, 1)
|
||||
field(SELM, "All")
|
||||
field(OMSL, "closed_loop")
|
||||
field(DOL, 1)
|
||||
# This order is important, to ensure that the status
|
||||
# can't change whichout having first updated the time
|
||||
# and count records to their final values
|
||||
field(OUTA, "$(INSTR)$(NAME):T_STS_RAW.PROC")
|
||||
field(OUTB, "$(INSTR)$(NAME):CH1_STS_RAW.PROC")
|
||||
field(OUTB, "$(INSTR)$(NAME):STATUS.PROC")
|
||||
}
|
||||
|
||||
# Array Subroutine record which emulates the counterbox functionality
|
||||
@@ -244,11 +194,11 @@ record(aSub, "$(INSTR)$(NAME):EMULATION")
|
||||
field(FTE, "LONG")
|
||||
field(INPF, "$(INSTR)$(NAME):THRESHOLD")
|
||||
field(FTF, "DOUBLE")
|
||||
field(INPG, "$(INSTR)$(NAME):COUNT-TYPE")
|
||||
field(FTG, "ULONG")
|
||||
field(INPH, "$(INSTR)$(NAME):PRESET_COUNT")
|
||||
field(FTH, "DOUBLE")
|
||||
field(INPI, "$(INSTR)$(NAME):PRESET_TIME")
|
||||
# field(INPG, "$(INSTR)$(NAME):COUNT-TYPE")
|
||||
# field(FTG, "ULONG")
|
||||
field(INPH, "$(INSTR)$(NAME):CH1_PRESET")
|
||||
field(FTH, "INT64")
|
||||
field(INPI, "$(INSTR)$(NAME):T_PRESET")
|
||||
field(FTI, "DOUBLE")
|
||||
# L is last input before EPICS 7.0.10
|
||||
field(INPJ, "$(INSTR)$(NAME):CH1_RATE-PREV")
|
||||
@@ -257,7 +207,7 @@ record(aSub, "$(INSTR)$(NAME):EMULATION")
|
||||
field(FTL, "DOUBLE")
|
||||
|
||||
# The first 4 outputs are also mapped as the first 4 inputs
|
||||
field(OUTA, "$(INSTR)$(NAME):STATUS PP")
|
||||
field(OUTA, "$(INSTR)$(NAME):RAW_STATUS PP")
|
||||
field(FTVA, "ULONG")
|
||||
field(OUTB, "$(INSTR)$(NAME):CH1 PP")
|
||||
field(FTVB, "INT64")
|
||||
@@ -272,11 +222,96 @@ record(aSub, "$(INSTR)$(NAME):EMULATION")
|
||||
field(OUTG, "$(INSTR)$(NAME):MsgTxt PP")
|
||||
field(FTVG, "CHAR")
|
||||
field(NOVG, 40)
|
||||
|
||||
field(FLNK, "$(INSTR)$(NAME):DB_POLL")
|
||||
}
|
||||
|
||||
#######################
|
||||
record(mbbi, "$(INSTR)$(NAME):RAW_STATUS")
|
||||
{
|
||||
field(DESC, "Raw returned status value")
|
||||
}
|
||||
|
||||
record(mbbi, "$(INSTR)$(NAME):STATUS")
|
||||
{
|
||||
field(DESC, "DAQ Status")
|
||||
field(INP, "$(INSTR)$(NAME):RAW_STATUS NPP MS")
|
||||
field(ZRVL, "0")
|
||||
field(ZRST, "Idle")
|
||||
field(ONVL, "1")
|
||||
field(ONST, "Counting")
|
||||
field(TWVL, "2")
|
||||
field(TWST, "Low rate")
|
||||
field(THVL, "3")
|
||||
field(THST, "Paused")
|
||||
# 4 should never happen, if it does it means the DAQ reports undocumented statusbits
|
||||
field(FRVL, "4")
|
||||
field(FRST, "INVALID")
|
||||
# We start in idle
|
||||
field(VAL, 0)
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Time Channel interface
|
||||
################################################################################
|
||||
|
||||
record(ai,"$(INSTR)$(NAME):T")
|
||||
{
|
||||
field(DESC, "DAQ Measured Time")
|
||||
field(EGU, "sec")
|
||||
}
|
||||
|
||||
record(ai, "$(INSTR)$(NAME):T_PRESET")
|
||||
{
|
||||
field(DESC, "Time Preset")
|
||||
field(VAL, 0)
|
||||
}
|
||||
|
||||
record(calc, "$(INSTR)$(NAME):T_STS_RAW")
|
||||
{
|
||||
field(DESC, "Raw time channel status")
|
||||
field(INPA, "$(INSTR)$(NAME):STATUS NPP MS")
|
||||
field(INPB, "$(INSTR)$(NAME):T_CLEARED NPP")
|
||||
field(CALC, "(0 < A && A < 4) || B")
|
||||
field(FLNK, "$(INSTR)$(NAME):T_STS")
|
||||
}
|
||||
|
||||
# Current Status of elapsed time
|
||||
record(bi, "$(INSTR)$(NAME):T_STS")
|
||||
{
|
||||
field(DESC, "Channel Status")
|
||||
field(INP, "$(INSTR)$(NAME):T_STS_RAW NPP MS")
|
||||
field(ZNAM, "Idle")
|
||||
field(ONAM, "Busy")
|
||||
}
|
||||
|
||||
record(bi, "$(INSTR)$(NAME):T_CLEARED")
|
||||
{
|
||||
field(DESC, "is being cleared")
|
||||
field(VAL, 0)
|
||||
field(ZNAM, "Cleared")
|
||||
field(ONAM, "Clearing")
|
||||
field(FLNK, "$(INSTR)$(NAME):T_STS_RAW")
|
||||
}
|
||||
|
||||
# Emulate Reset elapsed time
|
||||
# 0. set status to busy
|
||||
# 1. set elapsed time to 0
|
||||
# 2. set status to OK
|
||||
record(seq, "$(INSTR)$(NAME):T_CLEAR")
|
||||
{
|
||||
field(SELM, "All")
|
||||
field(LNK0, "$(INSTR)$(NAME):T_CLEARED PP")
|
||||
field(DO0, 1)
|
||||
field(LNK1, "$(INSTR)$(NAME):T PP")
|
||||
field(DO1, 0)
|
||||
field(LNK2, "$(INSTR)$(NAME):T_CLEARED PP")
|
||||
field(DO2, 0)
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Channel interface
|
||||
#######################
|
||||
################################################################################
|
||||
|
||||
record(int64in, "$(INSTR)$(NAME):CH1")
|
||||
{
|
||||
field(DESC, "DAQ CH0, proton current")
|
||||
@@ -307,19 +342,19 @@ record(ai, "$(INSTR)$(NAME):CH1_RATE-PREV") {
|
||||
field(DESC, "Previous rate of DAQ CH0 proton current")
|
||||
}
|
||||
|
||||
# Emulate clearing channel
|
||||
# 0. set status to busy
|
||||
# 1. set elapsed time to 0
|
||||
# 2. set status to OK
|
||||
record(seq, "$(INSTR)$(NAME):CH1_CLEAR")
|
||||
record(int64in, "$(INSTR)$(NAME):CH1_PRESET")
|
||||
{
|
||||
field(SELM, "All")
|
||||
field(LNK0, "$(INSTR)$(NAME):CH1_STS PP")
|
||||
field(DO0, 1)
|
||||
field(LNK1, "$(INSTR)$(NAME):CH1 PP")
|
||||
field(DO1, 0)
|
||||
field(LNK2, "$(INSTR)$(NAME):CH1_STS PP")
|
||||
field(DO2, 0)
|
||||
field(DESC, "Monitor Count Preset")
|
||||
field(VAL, 0)
|
||||
}
|
||||
|
||||
record(calc, "$(INSTR)$(NAME):CH1_STS_RAW")
|
||||
{
|
||||
field(DESC, "Raw Channel Status")
|
||||
field(INPA, "$(INSTR)$(NAME):STATUS NPP MS")
|
||||
field(INPB, "$(INSTR)$(NAME):CH1_CLEARED NPP")
|
||||
field(CALC, "(0 < A && A < 4) || B")
|
||||
field(FLNK, "$(INSTR)$(NAME):CH1_STS")
|
||||
}
|
||||
|
||||
# Current Status of Channel
|
||||
@@ -327,7 +362,31 @@ record(seq, "$(INSTR)$(NAME):CH1_CLEAR")
|
||||
record(bi, "$(INSTR)$(NAME):CH1_STS")
|
||||
{
|
||||
field(DESC, "Channel Status")
|
||||
field(INP, "$(INSTR)$(NAME):CH1_STS_RAW NPP MS")
|
||||
field(ZNAM, "Idle")
|
||||
field(ONAM, "Busy")
|
||||
}
|
||||
|
||||
record(bi, "$(INSTR)$(NAME):CH1_CLEARED")
|
||||
{
|
||||
field(DESC, "are hw counts being cleared")
|
||||
field(VAL, 0)
|
||||
field(ZNAM, "OK")
|
||||
field(ONAM, "CLEARING")
|
||||
field(ZNAM, "Cleared")
|
||||
field(ONAM, "Clearing")
|
||||
field(FLNK, "$(INSTR)$(NAME):CH1_STS_RAW")
|
||||
}
|
||||
|
||||
# Emulate clearing channel
|
||||
# 0. set status to busy
|
||||
# 1. set elapsed time to 0
|
||||
# 2. set status to OK
|
||||
record(seq, "$(INSTR)$(NAME):CH1_CLEAR")
|
||||
{
|
||||
field(SELM, "All")
|
||||
field(LNK0, "$(INSTR)$(NAME):CH1_CLEARED PP")
|
||||
field(DO0, 1)
|
||||
field(LNK1, "$(INSTR)$(NAME):CH1 PP")
|
||||
field(DO1, 0)
|
||||
field(LNK2, "$(INSTR)$(NAME):CH1_CLEARED PP")
|
||||
field(DO2, 0)
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ record(mbbi, "$(INSTR)$(NAME):T_STS")
|
||||
# Time Channel Preset
|
||||
|
||||
# If set, stop count once preset reached
|
||||
# TODO type
|
||||
record(int64in, "$(INSTR)$(NAME):T_PRESET")
|
||||
{
|
||||
field(DESC, "Time Preset")
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#var softProtonDebug 1
|
||||
var softProtonDebug 1
|
||||
|
||||
$(SET_SIM_MODE=#)dbLoadRecords("$(sinqDAQ_DB)sim_proton_current.db", "INSTR=$(INSTR), NAME=$(NAME)")
|
||||
$(SET_SIM_MODE=#)epicsEnvSet("REMOTE_RATE_PV", "$(INSTR)$(NAME):SIM-PROTON-CURR")
|
||||
|
||||
dbLoadRecords("$(sinqDAQ_DB)daq_soft_proton.db", "INSTR=$(INSTR), NAME=$(NAME), REMOTE_RATE_PV=$(REMOTE_RATE_PV=MHC6:IST:2), RATE_EGU=$(RATE_EGU=cts/sec), COUNTER_EGU=$(COUNTER_EGU=cts), SCALE_FACTOR=$(SCALE_FACTOR=100)")
|
||||
|
||||
iocInit
|
||||
|
||||
+21
-18
@@ -31,9 +31,9 @@ struct spc_internal {
|
||||
epicsFloat64 threshold;
|
||||
epicsFloat64 proton_rate;
|
||||
epicsFloat64 prev_proton_rate;
|
||||
epicsUInt32 count_type;
|
||||
epicsFloat64 preset_count;
|
||||
epicsFloat64 preset_time;
|
||||
//epicsUInt32 count_type;
|
||||
epicsInt64 ch1_preset;
|
||||
epicsFloat64 t_preset;
|
||||
epicsFloat64 average_rate;
|
||||
};
|
||||
|
||||
@@ -134,9 +134,9 @@ static long processEmulatedCounter(struct aSubRecord *psub) {
|
||||
spc->command_trig = *(epicsUInt32 *)psub->d;
|
||||
spc->threshold_ch = *(epicsInt32 *)psub->e;
|
||||
spc->threshold = *(epicsFloat64 *)psub->f;
|
||||
spc->count_type = *(epicsUInt32 *)psub->g;
|
||||
spc->preset_count = *(epicsFloat64 *)psub->h;
|
||||
spc->preset_time = *(epicsFloat64 *)psub->i;
|
||||
// spc->count_type = *(epicsUInt32 *)psub->g;
|
||||
spc->ch1_preset = *(epicsInt64 *)psub->h;
|
||||
spc->t_preset = *(epicsFloat64 *)psub->i;
|
||||
spc->prev_proton_rate = *(epicsFloat64 *)psub->j;
|
||||
spc->proton_rate = *(epicsFloat64 *)psub->l;
|
||||
|
||||
@@ -218,13 +218,14 @@ static long processEmulatedCounter(struct aSubRecord *psub) {
|
||||
spc->command_trig == TIME_PRESET)) {
|
||||
/* Determine if we are idle but received a count command */
|
||||
if (softProtonDebug)
|
||||
printf("%s: Starting Count!\n", funcstr);
|
||||
printf("%s: Starting Count! (time <= %f, count <= %d)\n",
|
||||
funcstr, spc->t_preset, spc->ch1_preset);
|
||||
/* Sanity check that count type is properly stored */
|
||||
if (spc->command_trig != spc->count_type) {
|
||||
if (softProtonDebug)
|
||||
printf("%s: Count type not stored!\n", funcstr);
|
||||
return -1;
|
||||
}
|
||||
// if (spc->command_trig != spc->count_type) {
|
||||
// if (softProtonDebug)
|
||||
// printf("%s: Count type not stored!\n", funcstr);
|
||||
// return -1;
|
||||
// }
|
||||
/* Starting a new count
|
||||
* Reset counter and time */
|
||||
*monitor_count_out = 0;
|
||||
@@ -281,12 +282,14 @@ static long processEmulatedCounter(struct aSubRecord *psub) {
|
||||
|
||||
/* Check if count is finished normally.
|
||||
* Higher priority than low rate */
|
||||
if (/* Time based count finished */
|
||||
(*elapsed_time_out >= spc->preset_time &&
|
||||
spc->count_type == TIME_PRESET) ||
|
||||
/* Monitor based count finished */
|
||||
(*monitor_count_out >= spc->preset_count &&
|
||||
spc->count_type == COUNT_PRESET)) {
|
||||
if (
|
||||
(spc->t_preset > 0 && *elapsed_time_out >= spc->t_preset) ||
|
||||
(spc->ch1_preset > 0 && *monitor_count_out >= spc->ch1_preset)
|
||||
) {
|
||||
if (softProtonDebug)
|
||||
printf("%s: Case COUNT preset reached (time: %f >= %f, count: %lld >= %lld)\n",
|
||||
funcstr, *elapsed_time_out, spc->t_preset,
|
||||
*monitor_count_out, spc->ch1_preset);
|
||||
*status_out = IDLE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user