mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-12 16:57:23 -05:00
Enable DMR Direct Mode Voice; No Data;
This commit is contained in:
77
src/dmr_ms.c
77
src/dmr_ms.c
@@ -10,6 +10,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
char ambe_fr[4][24] = {0};
|
||||
char ambe_fr2[4][24] = {0};
|
||||
char ambe_fr3[4][24] = {0};
|
||||
char ambe_fr4[4][24] = {0};
|
||||
char t_ambe_fr[4][24] = {9};
|
||||
char t_ambe_fr2[4][24] = {9};
|
||||
char t_ambe_fr3[4][24] = {9};
|
||||
@@ -71,7 +72,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
short int m = 0;
|
||||
|
||||
state->dmrburstL = 16; //Use 16 for Voice?
|
||||
// No CACH in MS Mode?
|
||||
// No CACH in MS/DM Mode?
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
@@ -296,7 +297,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->slot1light, "[slot1]");
|
||||
sprintf(state->slot2light, " slot2 ");
|
||||
//fprintf (stderr,"Sync: +DMR [slot1] slot2 | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
fprintf (stderr,"Sync: +DMR MS MODE | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
//test with vc1 reset disabled, if all is well, leave disabled
|
||||
//vc1 = 1;
|
||||
}
|
||||
@@ -305,7 +306,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->slot2light, "[slot2]");
|
||||
sprintf(state->slot1light, " slot1 ");
|
||||
//fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
fprintf (stderr,"Sync: +DMR MS MODE | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | RC ", state->color_code);
|
||||
//test with vc1 reset disabled, if all is well, leave disabled
|
||||
//vc2 = 1;
|
||||
}
|
||||
@@ -342,9 +343,9 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
//fprintf (stderr,"Sync: +DMR slot1 [slot2] | Color Code=%02d | DMRSTEREO | Data ", state->color_code);
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS MODE ");
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR MS MODE ");
|
||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE ");
|
||||
//test with vc1 reset disabled, if all is well, leave disabled
|
||||
//vc2 = 1;
|
||||
}
|
||||
@@ -367,7 +368,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
if (internalslot == 0 && opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc1);
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc1);
|
||||
if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
@@ -398,7 +399,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (internalslot == 0 && opts->inverted_dmr == 1)
|
||||
{
|
||||
fprintf (stderr,"Sync: -DMR MS MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc1);
|
||||
fprintf (stderr,"Sync: -DMR MS/DM MODE | Color Code=%02d | DMRSTEREO | VC%d ", state->color_code, vc1);
|
||||
if (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10)
|
||||
{
|
||||
fprintf (stderr, "%s", KYEL);
|
||||
@@ -436,9 +437,22 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
state->dmr_ms_mode == 1;
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2));
|
||||
|
||||
//state->directmode = 0; //flag off for testing
|
||||
|
||||
if (state->directmode == 0)
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
|
||||
if (vc1 == 6 && state->payload_algid >= 21)
|
||||
{
|
||||
@@ -468,7 +482,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
} // end while loop
|
||||
//reset these variables when exiting MS mode.
|
||||
//reset these variables when exiting MS/DM mode.
|
||||
END:
|
||||
//get first half payload dibits and store them in the payload for the next repitition
|
||||
skipDibit (opts, state, 144);
|
||||
@@ -487,6 +501,7 @@ void dmrMS (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_stereo = 0;
|
||||
state->dmr_ms_mode = 0;
|
||||
state->dmr_ms_rc = 0;
|
||||
state->directmode = 0; //flag off
|
||||
state->DMRvcL = 0;
|
||||
|
||||
}
|
||||
@@ -499,6 +514,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
char ambe_fr[4][24] = {0};
|
||||
char ambe_fr2[4][24] = {0};
|
||||
char ambe_fr3[4][24] = {0};
|
||||
char ambe_fr4[4][24] = {0}; //shim for playing back direct mode samples where ambe1 is bad, duplicate 2 to 4 and play both to smooth audio
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
@@ -643,7 +659,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
//work around to set erroneous PI header values to 0 if K is active
|
||||
if (state->K > 0)
|
||||
if (state->K > 0 || state->K1 > 0)
|
||||
{
|
||||
state->payload_keyid = 0; //just for testing
|
||||
state->payload_keyidR = 0; //just for testing
|
||||
@@ -653,7 +669,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS MODE | Frame Sync | DMRSTEREO | VC1 ");
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE | Frame Sync | DMRSTEREO | VC1 ");
|
||||
if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
|
||||
(state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x10) )
|
||||
{
|
||||
@@ -685,7 +701,7 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr,"Sync: -DMR MS MODE | Frame Sync | DMRSTEREO | VC1 ");
|
||||
fprintf (stderr,"Sync: -DMR MS/DM MODE | Frame Sync | DMRSTEREO | VC1 ");
|
||||
if ( (state->K > 0 && state->dmr_so & 0x40 && state->payload_keyid == 0 && state->dmr_fid == 0x10) ||
|
||||
(state->K > 0 && state->dmr_soR & 0x40 && state->payload_keyidR == 0 && state->dmr_fid == 0x10) )
|
||||
{
|
||||
@@ -719,9 +735,23 @@ void dmrMSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_ms_mode = 1;
|
||||
state->DMRvcL = 0;
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
memcpy (ambe_fr4, ambe_fr2, sizeof(ambe_fr2));
|
||||
|
||||
//state->directmode = 0; //flag off for testing samples
|
||||
|
||||
if (state->directmode == 0)
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr4, NULL); //play duplicate of 2 here to smooth audio
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
|
||||
|
||||
skipDibit (opts, state, 144); //skip to next TDMA slot
|
||||
dmrMS (opts, state); //bootstrap into full TDMA frame
|
||||
@@ -807,15 +837,17 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
//hide behind payload due to errs in data in MS mode
|
||||
if (opts->payload == 1)
|
||||
//state->directmode = 0; //flag off for testing
|
||||
|
||||
//hide behind payload due to errs in data in MS/DM mode
|
||||
if (opts->payload == 1 && state->directmode == 0)
|
||||
{
|
||||
fprintf (stderr, "%s ", getTime());
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR MS MODE ");
|
||||
fprintf (stderr,"Sync: +DMR MS/DM MODE ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR MS MODE ");
|
||||
else fprintf (stderr,"Sync: -DMR MS/DM MODE ");
|
||||
}
|
||||
|
||||
|
||||
@@ -827,13 +859,14 @@ void dmrMSData (dsd_opts * opts, dsd_state * state)
|
||||
state->dmr_ms_mode = 1;
|
||||
|
||||
//only run if payload is set to 1 due to errors with MS data
|
||||
if (opts->payload == 1)
|
||||
if (opts->payload == 1 && state->directmode == 0) //don't run on Direct Mode just yet
|
||||
{
|
||||
processDMRdata (opts, state);
|
||||
}
|
||||
|
||||
state->dmr_stereo = 0;
|
||||
state->dmr_ms_mode = 0;
|
||||
state->directmode = 0; //flag off
|
||||
|
||||
//get potential first half payload dibits and store them in the payload for the next repitition, MS voice or data.
|
||||
skipDibit (opts, state, 144);
|
||||
|
||||
@@ -209,10 +209,10 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->dmr_stereo == 0 && state->synctype == 32)
|
||||
{
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "Please use XDMA decoding class to decode MS/Simplex \n");
|
||||
fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (opts->dmr_stereo == 1)
|
||||
if (opts->dmr_stereo == 1) //opts->dmr_stereo == 1
|
||||
{
|
||||
state->dmr_stereo = 1; //set the state to 1 when handling pure voice frames
|
||||
if (state->synctype > 31 )
|
||||
@@ -229,7 +229,7 @@ processFrame (dsd_opts * opts, dsd_state * state)
|
||||
closeMbeOutFile (opts, state);
|
||||
state->err_str[0] = 0;
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "Please use XDMA decoding class to decode MS/Simplex \n");
|
||||
fprintf (stderr, "Please use XDMA or DMR Stereo to decode MS/Simplex \n");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
}
|
||||
if (opts->dmr_stereo == 1)
|
||||
|
||||
@@ -940,7 +940,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + (lmax)) / 2;
|
||||
state->min = ((state->min) + (lmin)) / 2;
|
||||
state->currentslot = 0;
|
||||
//state->currentslot = 0;
|
||||
state->directmode = 1; //Direct mode
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
@@ -948,14 +948,14 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 10;
|
||||
//state->lastsynctype = 10;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (10);
|
||||
//return (33);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -963,18 +963,18 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 11)
|
||||
{
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 11;
|
||||
//state->lastsynctype = 11;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (11);
|
||||
return (32);
|
||||
}
|
||||
} /* End if(strcmp (synctest, DMR_DIRECT_MODE_TS1_DATA_SYNC) == 0) */
|
||||
if(strcmp (synctest, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0)
|
||||
@@ -983,7 +983,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + (lmax)) / 2;
|
||||
state->min = ((state->min) + (lmin)) / 2;
|
||||
state->currentslot = 1;
|
||||
//state->currentslot = 1;
|
||||
state->directmode = 1; //Direct mode
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
@@ -991,14 +991,14 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 10;
|
||||
//state->lastsynctype = 10;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (10);
|
||||
//return (33);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1006,18 +1006,18 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1 && opts->dmr_stereo == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 11)
|
||||
{
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 11;
|
||||
//state->lastsynctype = 11;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (11);
|
||||
return (32);
|
||||
}
|
||||
} /* End if(strcmp (synctest, DMR_DIRECT_MODE_TS2_DATA_SYNC) == 0) */
|
||||
//if((strcmp (synctest, DMR_MS_VOICE_SYNC) == 0) || (strcmp (synctest, DMR_BS_VOICE_SYNC) == 0))
|
||||
@@ -1070,15 +1070,15 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->currentslot = 0;
|
||||
//state->currentslot = 0;
|
||||
state->directmode = 1; //Direct mode
|
||||
if (opts->inverted_dmr == 0 && opts->dmr_stereo == 0)
|
||||
if (opts->inverted_dmr == 0) //&& opts->dmr_stereo == 1
|
||||
{
|
||||
// voice frame
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1)
|
||||
if (opts->errorbars == 1 && opts->dmr_stereo == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 12)
|
||||
{
|
||||
@@ -1089,7 +1089,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (12);
|
||||
return (32); //treat Direct Mode same as MS mode for now
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1097,10 +1097,10 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1 && opts->dmr_stereo == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 13;
|
||||
return (13);
|
||||
//return (33);
|
||||
}
|
||||
} /* End if(strcmp (synctest, DMR_DIRECT_MODE_TS1_VOICE_SYNC) == 0) */
|
||||
if(strcmp (synctest, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0)
|
||||
@@ -1109,26 +1109,26 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
state->currentslot = 1;
|
||||
//state->currentslot = 1;
|
||||
state->directmode = 1; //Direct mode
|
||||
if (opts->inverted_dmr == 0)
|
||||
if (opts->inverted_dmr == 0) //&& opts->dmr_stereo == 1
|
||||
{
|
||||
// voice frame
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1 && opts->dmr_stereo == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "+DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 12)
|
||||
{
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 12;
|
||||
//state->lastsynctype = 12;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (12);
|
||||
return (32);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1136,15 +1136,14 @@ getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
sprintf(state->ftype, "DMR ");
|
||||
if (opts->errorbars == 1 && opts->dmr_stereo == 0)
|
||||
{
|
||||
printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
//printFrameSync (opts, state, "-DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 13;
|
||||
//state->lastsynctype = 13;
|
||||
if ( opts->monitor_input_audio == 1)
|
||||
{
|
||||
|
||||
pa_simple_flush(opts->pulse_raw_dev_out, NULL);
|
||||
}
|
||||
return (13);
|
||||
//return (33);
|
||||
}
|
||||
} //End if(strcmp (synctest, DMR_DIRECT_MODE_TS2_VOICE_SYNC) == 0)
|
||||
} //End if (opts->frame_dmr == 1)
|
||||
|
||||
@@ -92,7 +92,7 @@ noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
state->carrier = 0;
|
||||
state->max = 15000;
|
||||
state->min = -15000;
|
||||
state->center = 0; //quick disable for dmr testing with buffer
|
||||
state->center = 0;
|
||||
state->err_str[0] = 0;
|
||||
state->err_strR[0] = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
|
||||
Reference in New Issue
Block a user