mirror of
https://github.com/preble/libpinproc
synced 2026-02-24 18:25:23 +01:00
pinprocfw: code cleanup
This commit is contained in:
committed by
Gerry Stellenberg
parent
954084d348
commit
83f8f116f9
@@ -32,12 +32,18 @@
|
||||
#endif /* DEBUG_MODE */
|
||||
|
||||
#include "pinprocfw.h"
|
||||
#include "../../src/PRHardware.h"
|
||||
#include "lenval.h"
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__WIN32__) || defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#define PRSleep(milliseconds) Sleep(milliseconds)
|
||||
#else
|
||||
#define PRSleep(milliseconds) usleep(milliseconds*1000)
|
||||
#endif
|
||||
|
||||
#include "pinproc.h" // Include libpinproc's header.
|
||||
PRMachineType machineType = kPRMachineCustom; // Should work with all machines.
|
||||
|
||||
@@ -514,7 +520,7 @@ void setPort(short p,short val)
|
||||
|
||||
|
||||
// Toggle TCK.
|
||||
void pulseClock()
|
||||
void pulseClock(void)
|
||||
{
|
||||
setPort(TCK,0); /* set the TCK port to low */
|
||||
setPort(TCK,1); /* set the TCK port to high */
|
||||
@@ -540,7 +546,7 @@ void readByte(unsigned char *data)
|
||||
long int bytesPer200th = numBytesTotal / 200;
|
||||
numBytesCurrent++;
|
||||
if (numBytesCurrent % bytesPerTenth == 0) {
|
||||
printf("\n%ld0%% ",numBytesCurrent/bytesPerTenth);
|
||||
printf("\n%d0%% ",(int) (numBytesCurrent/bytesPerTenth));
|
||||
fflush(stdout);
|
||||
}
|
||||
else if (numBytesCurrent % bytesPer200th == 0) {
|
||||
@@ -549,7 +555,7 @@ void readByte(unsigned char *data)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char readTDOBit()
|
||||
unsigned char readTDOBit(void)
|
||||
{
|
||||
PRJTAGStatus jtagStatus;
|
||||
|
||||
@@ -1853,7 +1859,7 @@ void xsvfCleanup( SXsvfInfo* pXsvfInfo )
|
||||
* Parameters: none.
|
||||
* Returns: int - Legacy result values: 1 == success; 0 == failed.
|
||||
*****************************************************************************/
|
||||
int xsvfExecute()
|
||||
int xsvfExecute(void)
|
||||
{
|
||||
SXsvfInfo xsvfInfo;
|
||||
|
||||
@@ -1874,7 +1880,7 @@ int xsvfExecute()
|
||||
}
|
||||
else
|
||||
{
|
||||
XSVFDBG_PRINTF( 0, "SUCCESS - Operation completed successfully. Cycle P-ROC power to activate any changes.\n" );
|
||||
XSVFDBG_PRINTF( 0, "SUCCESS - Operation completed successfully.\nCycle P-ROC power to activate any changes.\n" );
|
||||
}
|
||||
|
||||
xsvfCleanup( &xsvfInfo );
|
||||
@@ -1882,7 +1888,7 @@ int xsvfExecute()
|
||||
return( XSVF_ERRORCODE(xsvfInfo.iErrorCode) );
|
||||
}
|
||||
|
||||
int openPROC()
|
||||
int openPROC(void)
|
||||
{
|
||||
// Instantiate the P-ROC device:
|
||||
XSVFDBG_PRINTF( 1, "Opening P-ROC.\n");
|
||||
@@ -1898,35 +1904,27 @@ int openPROC()
|
||||
|
||||
void printUsage(char * name)
|
||||
{
|
||||
fprintf(stderr, "\n%s: Version 1.1", name );
|
||||
fprintf(stderr, "\nUSAGE: %s <filename>\n", name );
|
||||
fprintf(stderr, "%s: Version 1.1\n", name );
|
||||
fprintf(stderr, "USAGE: %s <filename>\n", name );
|
||||
fprintf(stderr, " filename = the .xsvf or .p-roc file to execute.\n" );
|
||||
}
|
||||
|
||||
int getNumFileBytes() {
|
||||
unsigned char data;
|
||||
int i=0;
|
||||
while (!feof(in))
|
||||
{
|
||||
data = (unsigned char)fgetc( in );
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
// Move file pointer to beginning of XSVF data.
|
||||
void preparePROCFile() {
|
||||
void preparePROCFile(void) {
|
||||
int temp, num_header_words;
|
||||
int i;
|
||||
|
||||
rewind(in);
|
||||
fscanf(in, "%x\n", &temp);
|
||||
num_header_words = (int)(0x012345678 - temp);
|
||||
|
||||
for (i=0; i<num_header_words; i++) fscanf(in, "%x\n", &temp);
|
||||
for (i = 0; i < num_header_words; i++) {
|
||||
fscanf(in, "%x\n", &temp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t P3ROC_SPIWaitForReady()
|
||||
uint32_t P3ROC_SPIWaitForReady(void)
|
||||
{
|
||||
uint32_t dataBuffer[1];
|
||||
uint32_t addr = 0;
|
||||
@@ -1952,7 +1950,7 @@ uint32_t P3ROC_SPIWaitForReady()
|
||||
return 1;
|
||||
}
|
||||
|
||||
void P3ROC_SPISendWEL()
|
||||
void P3ROC_SPISendWEL(void)
|
||||
{
|
||||
uint32_t dataBuffer[512];
|
||||
uint32_t addr = 0;
|
||||
@@ -1961,7 +1959,7 @@ void P3ROC_SPISendWEL()
|
||||
PRWriteData (proc, P3_ROC_BUS_SPI_SELECT, addr, 1, dataBuffer);
|
||||
}
|
||||
|
||||
void P3ROC_SPIBulkErase()
|
||||
void P3ROC_SPIBulkErase(void)
|
||||
{
|
||||
uint32_t dataBuffer[512];
|
||||
uint32_t addr = 0;
|
||||
@@ -2001,10 +1999,10 @@ void P3ROC_SPIWritePage(uint32_t page_addr, uint32_t * writeDataBuffer)
|
||||
P3ROC_SPIWaitForReady();
|
||||
}
|
||||
|
||||
int verifyP3ROCImage()
|
||||
int verifyP3ROCImage(void)
|
||||
{
|
||||
unsigned char inChars [4];
|
||||
uint32_t dataBuffer[512];
|
||||
uint32_t dataBuffer[64];
|
||||
uint32_t readBuffer[64];
|
||||
|
||||
int pageAddr = 0;
|
||||
@@ -2025,7 +2023,7 @@ int verifyP3ROCImage()
|
||||
inChars[j] = fgetc(in);
|
||||
numBytesCurrent++;
|
||||
if (numBytesCurrent % bytesPerTenth == 0) {
|
||||
printf("\n%ld0%% ",numBytesCurrent/bytesPerTenth);
|
||||
printf("\n%d0%% ", (int)(numBytesCurrent / bytesPerTenth));
|
||||
fflush(stdout);
|
||||
}
|
||||
else if (numBytesCurrent % bytesPer200th == 0) {
|
||||
@@ -2042,20 +2040,19 @@ int verifyP3ROCImage()
|
||||
//fprintf(stderr, "\nWriting Page: %x", pageAddr);
|
||||
P3ROC_SPIReadPage(pageAddr, &readBuffer[0]);
|
||||
|
||||
for (int i=0; i<64; i++)
|
||||
{
|
||||
if (readBuffer[i] != dataBuffer[i]) return 0;
|
||||
if (memcmp(readBuffer, dataBuffer, sizeof readBuffer) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pageAddr++;
|
||||
}
|
||||
|
||||
XSVFDBG_PRINTF( 0, "\n\nSUCCESS - Operation completed successfully. Cycle P3-ROC power to activate any changes.\n" );
|
||||
XSVFDBG_PRINTF( 0, "\n\nSUCCESS - Operation completed successfully.\nCycle P3-ROC power to activate any changes.\n" );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void writeP3ROCImage()
|
||||
void writeP3ROCImage(void)
|
||||
{
|
||||
unsigned char inChars [4];
|
||||
uint32_t dataBuffer[512];
|
||||
@@ -2069,16 +2066,13 @@ void writeP3ROCImage()
|
||||
printf("\nProgramming new image:\n0%% ");
|
||||
fflush(stdout);
|
||||
while (!feof(in)) {
|
||||
for (int i=0; i<64; i++)
|
||||
{
|
||||
if (!feof(in))
|
||||
{
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
for (int i=0; i<64; i++) {
|
||||
if (!feof(in)) {
|
||||
for (int j=0; j<4; j++) {
|
||||
inChars[j] = fgetc(in);
|
||||
numBytesCurrent++;
|
||||
if (numBytesCurrent % bytesPerTenth == 0) {
|
||||
printf("\n%ld0%% ",numBytesCurrent/bytesPerTenth);
|
||||
printf("\n%d0%% ", (int)(numBytesCurrent / bytesPerTenth));
|
||||
fflush(stdout);
|
||||
}
|
||||
else if (numBytesCurrent % bytesPer200th == 0) {
|
||||
@@ -2105,7 +2099,7 @@ void writeP3ROCImage()
|
||||
|
||||
}
|
||||
|
||||
void processP3ROCFile()
|
||||
void processP3ROCFile(void)
|
||||
{
|
||||
fprintf(stderr, "\n\nUpdating P3-ROC. This may take a couple of minutes.\n");
|
||||
fprintf(stderr, "WARNING: DO NOT POWER CYCLE UNTIL COMPLETE!\n");
|
||||
@@ -2113,22 +2107,18 @@ void processP3ROCFile()
|
||||
P3ROC_SPIBulkErase();
|
||||
fprintf(stderr, "\nFlash erased.\n");
|
||||
writeP3ROCImage();
|
||||
rewind(in);
|
||||
preparePROCFile();
|
||||
if (verifyP3ROCImage() == 0)
|
||||
fprintf(stderr, "\nERROR: Verification failed. Please retry. DO NOT CYCLE POWER.\n\n");
|
||||
}
|
||||
|
||||
int processFile()
|
||||
int processFile(void)
|
||||
{
|
||||
clock_t startClock;
|
||||
clock_t endClock;
|
||||
int iErrorCode;
|
||||
//fseek(in, 0L, SEEK_END);
|
||||
//numBytesTotal = ftell(in);
|
||||
//fseek(in, 0L, SEEK_SET);
|
||||
numBytesCurrent = 0;
|
||||
|
||||
numBytesCurrent = 0;
|
||||
|
||||
/* Execute the XSVF in the file */
|
||||
startClock = clock();
|
||||
@@ -2139,91 +2129,92 @@ int processFile()
|
||||
return iErrorCode;
|
||||
}
|
||||
|
||||
uint32_t checkPROCFile() {
|
||||
uint32_t checkPROCFile(void) {
|
||||
uint32_t checksum=0, file_checksum, file_board_id, header_checksum;
|
||||
unsigned char data;
|
||||
int i=0,file_i=0;
|
||||
int min_board_rev, max_board_rev;
|
||||
int temp, num_header_words, proc_file_version;
|
||||
int temp[8], num_header_words, proc_file_version;
|
||||
|
||||
if (!fscanf(in, "%x\n", &temp)) return 0;
|
||||
num_header_words = (int)(0x012345678 - temp);
|
||||
//fprintf(stderr, "\nproc_file_version: %x, %x", num_header_words, temp);
|
||||
if (!fscanf(in, "%x\n", &temp)) return 0;
|
||||
proc_file_version = (int)(-1 - temp);
|
||||
//fprintf(stderr, "\nproc_file_version: %x, %x", proc_file_version, temp);
|
||||
if (!fscanf(in, "%x\n", &temp)) return 0;
|
||||
file_i = (int)(-1 - temp);
|
||||
//fprintf(stderr, "\nbyte count: %d, %x", file_i, temp);
|
||||
if (!fscanf(in, "%x\n", &temp)) return 0;
|
||||
file_board_id = (uint32_t)(-1 - temp);
|
||||
//fprintf(stderr, "\nid: %x, %x", file_board_id, temp);
|
||||
if (!fscanf(in, "%x\n", &temp)) return 0;
|
||||
min_board_rev = (int)(-1 - temp);
|
||||
//fprintf(stderr, "\nmin_board: %d, %x", min_board_rev, temp);
|
||||
if (!fscanf(in, "%x\n", &temp)) return 0;
|
||||
max_board_rev = (int)(-1 - temp);
|
||||
//fprintf(stderr, "\nmax_board: %d, %x", max_board_rev, temp);
|
||||
if (!fscanf(in, "%x\n", &temp)) return 0;
|
||||
file_checksum = (uint32_t)(-1 - temp);
|
||||
//fprintf(stderr, "\nchecksum: %d, %x", file_checksum, temp);
|
||||
if (!fscanf(in, "%x\n", &temp)) return 0;
|
||||
header_checksum = (uint32_t)(-1 - temp);
|
||||
//fprintf(stderr, "\nheader_checksum: %d, %x", header_checksum, temp);
|
||||
// Read 8 hex values from start of file.
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (!fscanf(in, "%x\n", &temp[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
num_header_words = (int)(0x012345678 - temp[0]);
|
||||
proc_file_version = (int)(-1 - temp[1]);
|
||||
file_i = (int)(-1 - temp[2]);
|
||||
file_board_id = (uint32_t)(-1 - temp[3]);
|
||||
min_board_rev = (int)(-1 - temp[4]);
|
||||
max_board_rev = (int)(-1 - temp[5]);
|
||||
file_checksum = (uint32_t)(-1 - temp[6]);
|
||||
header_checksum = (uint32_t)(-1 - temp[7]);
|
||||
|
||||
uint32_t readdata[4], board_rev, board_id;
|
||||
PRReadData(proc, 0, 0, 4, readdata);
|
||||
fprintf(stderr, "File version %d, for board_id 0x%08X (board revs %d to %d)\n",
|
||||
proc_file_version, file_board_id, min_board_rev, max_board_rev);
|
||||
fprintf(stderr, "%d-byte data checksum 0x%08X, header checksum 0x%08X\n",
|
||||
file_i, file_checksum, header_checksum);
|
||||
|
||||
uint32_t readdata[4], board_id;
|
||||
PRReadData(proc, P_ROC_MANAGER_SELECT, P_ROC_REG_CHIP_ID_ADDR, 4, readdata);
|
||||
board_id = readdata[0];
|
||||
board_rev = readdata[3];
|
||||
int board_rev = 0;
|
||||
if (board_id == P3_ROC_CHIP_ID) {
|
||||
board_rev = (board_rev & 0x800) >> 11 |
|
||||
(board_rev & 0x400) >> 10 |
|
||||
(board_rev & 0x200) >> 9 |
|
||||
(board_rev & 0x100) >> 8;
|
||||
fprintf(stderr, "\nReading P3-ROC board_rev: %d", board_rev);
|
||||
board_rev = (readdata[3] & 0x800) >> 11 |
|
||||
(readdata[3] & 0x400) >> 10 |
|
||||
(readdata[3] & 0x200) >> 9 |
|
||||
(readdata[3] & 0x100) >> 8;
|
||||
fprintf(stderr, "Connected to P3-ROC (board rev %d).\n", board_rev);
|
||||
}
|
||||
else if (board_id == P_ROC_CHIP_ID) {
|
||||
board_rev = (readdata[3] & 0x80) >> 7 |
|
||||
(readdata[3] & 0x40) >> 6 |
|
||||
(readdata[3] & 0x20) >> 5 |
|
||||
(readdata[3] & 0x10) >> 4;
|
||||
fprintf(stderr, "Connected to P-ROC (board rev %d).\n", board_rev);
|
||||
}
|
||||
else {
|
||||
board_rev = (board_rev & 0x80) >> 7 |
|
||||
(board_rev & 0x40) >> 6 |
|
||||
(board_rev & 0x20) >> 5 |
|
||||
(board_rev & 0x10) >> 4;
|
||||
fprintf(stderr, "\nReading P-ROC board_rev: %d", board_rev);
|
||||
fprintf(stderr, "Connected to unrecognized hardware (0x%08X).\n",
|
||||
board_id);
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "Current FPGA version: %u.%u\n",
|
||||
readdata[1] >> 16, readdata[1] & 0xffff);
|
||||
|
||||
if (proc_file_version != 0) {
|
||||
fprintf(stderr, "\nERROR: Unsupported .p-roc file version: %x. Check for an updated version of this tool.\n\n", proc_file_version);
|
||||
fprintf(stderr, "ERROR: Unsupported .p-roc file version: 0x%x. Check for an updated version of this tool.\n\n",
|
||||
proc_file_version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check for valid board ID and rev
|
||||
if (board_id != file_board_id) {
|
||||
fprintf(stderr, "\nERROR: board type mismatch.");
|
||||
if (board_id == P_ROC_CHIP_ID && file_board_id == P3_ROC_CHIP_ID)
|
||||
fprintf(stderr, "\nCannot program a P3-ROC image onto a P-ROC\n\n");
|
||||
else if (board_id == P3_ROC_CHIP_ID && file_board_id == P_ROC_CHIP_ID)
|
||||
fprintf(stderr, "\nCannot program a P-ROC image onto a P3-ROC\n\n");
|
||||
else fprintf(stderr, "\nImage (0x%08X) and board (0x%08X) are incompatible\n\n", file_board_id, board_id);
|
||||
if (board_id == file_board_id) {
|
||||
fprintf(stderr, "Board ID verified\n");
|
||||
}
|
||||
else {
|
||||
if (board_id == P_ROC_CHIP_ID && file_board_id == P3_ROC_CHIP_ID) {
|
||||
fprintf(stderr, "ERROR: Cannot program a P3-ROC image onto a P-ROC\n\n");
|
||||
}
|
||||
else if (board_id == P3_ROC_CHIP_ID && file_board_id == P_ROC_CHIP_ID) {
|
||||
fprintf(stderr, "ERROR: Cannot program a P-ROC image onto a P3-ROC\n\n");
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "ERROR: Image (0x%08X) and board (0x%08X) are incompatible\n\n",
|
||||
file_board_id, board_id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else fprintf(stderr, "\nBoard ID verified");
|
||||
|
||||
if (board_rev > max_board_rev) {
|
||||
fprintf(stderr, "\nERROR: board_rev %d > max_board_rev %d", board_rev, max_board_rev);
|
||||
}
|
||||
if (board_rev < min_board_rev) {
|
||||
fprintf(stderr, "\nERROR: board_rev < min_board_rev");
|
||||
}
|
||||
|
||||
if (board_rev > max_board_rev || board_rev < min_board_rev) {
|
||||
fprintf(stderr, "\nERROR: This image is not compatible with the P-ROC board (rev: %x)", board_id);
|
||||
fprintf(stderr, "ERROR: Board rev %d not between %d and %d\n",
|
||||
board_rev, min_board_rev, max_board_rev);
|
||||
return 0;
|
||||
}
|
||||
else fprintf(stderr, "\nBoard rev verified");
|
||||
|
||||
checksum = 0;
|
||||
i = 0;
|
||||
while (!feof(in))
|
||||
{
|
||||
while (!feof(in)) {
|
||||
data = (unsigned char)fgetc( in );
|
||||
checksum += data;
|
||||
i++;
|
||||
@@ -2235,7 +2226,7 @@ uint32_t checkPROCFile() {
|
||||
if ((i != file_i) ||
|
||||
(checksum != file_checksum) ||
|
||||
(header_checksum != new_header_checksum)) {
|
||||
fprintf(stderr, "\nFPGA data verification failure!\n\n");
|
||||
fprintf(stderr, "FPGA data verification failure!\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2264,11 +2255,8 @@ int main( int argc, char** argv )
|
||||
int i;
|
||||
int iErrorCode;
|
||||
|
||||
// Set a signal handler so that we can exit gracefully on Ctrl-C:
|
||||
//signal(SIGINT, sigint);
|
||||
|
||||
iErrorCode = XSVF_ERRORCODE( XSVF_ERROR_NONE );
|
||||
pzXsvfFileName = 0;
|
||||
pzXsvfFileName = NULL;
|
||||
|
||||
//printf( "XSVF Player v%s, Xilinx, Inc.\n", XSVF_VERSION );
|
||||
|
||||
@@ -2296,26 +2284,22 @@ int main( int argc, char** argv )
|
||||
// Check for .p-roc file
|
||||
if (strstr(pzXsvfFileName, ".p-roc")) {
|
||||
|
||||
fprintf(stderr, "\nP-ROC file format detected\n.");
|
||||
fprintf(stderr, "P-ROC file format detected.\n");
|
||||
|
||||
in = fopen( pzXsvfFileName, "rb" );
|
||||
if ( !in ) {
|
||||
fprintf(stderr, "ERROR: Cannot open file %s\n.", pzXsvfFileName );
|
||||
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", pzXsvfFileName );
|
||||
iErrorCode = XSVF_ERRORCODE( XSVF_ERROR_UNKNOWN );
|
||||
}
|
||||
else {
|
||||
|
||||
if (openPROC()) {
|
||||
fprintf(stderr, "\nVerifying file contents and board compatibility...");
|
||||
switch (checkPROCFile())
|
||||
{
|
||||
fprintf(stderr, "Verifying file contents and board compatibility...\n");
|
||||
switch (checkPROCFile()) {
|
||||
case P_ROC_CHIP_ID:
|
||||
rewind(in);
|
||||
preparePROCFile();
|
||||
processFile();
|
||||
break;
|
||||
case P3_ROC_CHIP_ID:
|
||||
rewind(in);
|
||||
preparePROCFile();
|
||||
processP3ROCFile();
|
||||
break;
|
||||
@@ -2323,35 +2307,38 @@ int main( int argc, char** argv )
|
||||
fprintf(stderr, "Failed to parse file.\n");
|
||||
break;
|
||||
}
|
||||
// Destroy the P-ROC device handle created by openPROC()
|
||||
PRDelete(proc);
|
||||
proc = kPRHandleInvalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check for .p-roc file
|
||||
// Check for .xsvf file
|
||||
else if (strstr(pzXsvfFileName, ".xsvf")) {
|
||||
fprintf(stderr, "\nXSVF file format detected.\n");
|
||||
fprintf(stderr, "XSVF file format detected.\n");
|
||||
in = fopen( pzXsvfFileName, "rb" );
|
||||
if ( !in ) {
|
||||
fprintf(stderr, "ERROR: Cannot open file %s\n.", pzXsvfFileName );
|
||||
fprintf(stderr, "ERROR: Cannot open file '%s'.\n", pzXsvfFileName );
|
||||
iErrorCode = XSVF_ERRORCODE( XSVF_ERROR_UNKNOWN );
|
||||
}
|
||||
else {
|
||||
numBytesTotal = getNumFileBytes();
|
||||
rewind(in);
|
||||
|
||||
if (openPROC()) {
|
||||
fseek(in, 0, SEEK_END);
|
||||
numBytesTotal = ftell(in);
|
||||
rewind(in);
|
||||
processFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "\nERROR: Unsupported file format.\n");
|
||||
fprintf(stderr, "ERROR: Unsupported file format.\n");
|
||||
printUsage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (proc != kPRHandleInvalid) {
|
||||
// Destroy the P-ROC device handle created by openPROC()
|
||||
PRDelete(proc);
|
||||
proc = kPRHandleInvalid;
|
||||
}
|
||||
|
||||
return( iErrorCode );
|
||||
}
|
||||
#endif /* XSVF_MAIN */
|
||||
|
||||
Reference in New Issue
Block a user