mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-12 21:07:13 +02:00
wip
This commit is contained in:
@ -6,22 +6,24 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define TEMP_PROG_FILE_NAME "/var/tmp/tmp.rawbin"
|
#define TEMP_PROG_FOLDER_NAME "/var/tmp/"
|
||||||
|
#define TEMP_PROG_FILE_NAME TEMP_PROG_FOLDER_NAME "tmp.rawbin"
|
||||||
|
|
||||||
void defineGPIOpins();
|
void defineGPIOpins();
|
||||||
void FPGAdontTouchFlash();
|
int FPGAdontTouchFlash();
|
||||||
void FPGATouchFlash();
|
int FPGATouchFlash();
|
||||||
void resetFPGA();
|
int resetFPGA();
|
||||||
|
|
||||||
int deleteOldFile(char *mess);
|
int emptyTempFolder(char *mess);
|
||||||
/**
|
/**
|
||||||
* deletes old file
|
* deletes old file
|
||||||
* verify memory available to copy
|
* verify memory available to copy
|
||||||
* open file to copy
|
* open file to copy
|
||||||
*/
|
*/
|
||||||
int preparetoCopyFPGAProgram(FILE **fd, uint64_t fsize, char *mess);
|
int preparetoCopyProgram(FILE **fd, uint64_t fsize, char *mess);
|
||||||
int copyToFlash(ssize_t fsize, char *clientChecksum, char *mess);
|
int copyToFlash(enum PROGRAMINDEX index, char *mType, ssize_t fsize,
|
||||||
int getDrive(char *mess);
|
char *clientChecksum, char *mess);
|
||||||
|
int getDrive(enum PROGRAMINDEX index, char *mess);
|
||||||
/** Notify fpga not to touch flash, open src and flash drive to write */
|
/** Notify fpga not to touch flash, open src and flash drive to write */
|
||||||
int openFileForFlash(FILE **flashfd, FILE **srcfd, char *mess);
|
int openFileForFlash(FILE **flashfd, FILE **srcfd, char *mess);
|
||||||
int eraseFlash(char *mess);
|
int eraseFlash(char *mess);
|
@ -12,9 +12,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(MYTHEN3D) || defined(GOTTHARD2D)
|
#if defined(MYTHEN3D) || defined(GOTTHARD2D)
|
||||||
#include "programFpgaNios.h"
|
#include "programViaNios.h"
|
||||||
#elif defined(CHIPTESTBOARDD) || defined(JUNGFRAUD) || defined(MOENCHD)
|
#elif defined(CHIPTESTBOARDD) || defined(JUNGFRAUD) || defined(MOENCHD)
|
||||||
#include "programFpgaBlackfin.h"
|
#include "programViaBlackfin.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(MYTHEN3D) || defined(GOTTHARD2D)
|
#if defined(MYTHEN3D) || defined(GOTTHARD2D)
|
||||||
@ -60,7 +60,7 @@ typedef struct udpStruct_s {
|
|||||||
int isInitCheckDone();
|
int isInitCheckDone();
|
||||||
int getInitResult(char **mess);
|
int getInitResult(char **mess);
|
||||||
void basictests();
|
void basictests();
|
||||||
int getKernelVersion(char* retvals);
|
int getKernelVersion(char *retvals);
|
||||||
#if defined(GOTTHARDD) || defined(JUNGFRAUD) || defined(CHIPTESTBOARDD) || \
|
#if defined(GOTTHARDD) || defined(JUNGFRAUD) || defined(CHIPTESTBOARDD) || \
|
||||||
defined(MOENCHD) || defined(MYTHEN3D) || defined(GOTTHARD2D)
|
defined(MOENCHD) || defined(MYTHEN3D) || defined(GOTTHARD2D)
|
||||||
int checkType();
|
int checkType();
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#define GOODBYE (-200)
|
#define GOODBYE (-200)
|
||||||
#define REBOOT (-400)
|
#define REBOOT (-400)
|
||||||
|
|
||||||
|
enum PROGRAMINDEX {FPGA_PROGRAM, KERNEL_PROGRAM, SERVER_PROGRAM}
|
||||||
|
|
||||||
// initialization functions
|
// initialization functions
|
||||||
int printSocketReadError();
|
int printSocketReadError();
|
||||||
void init_detector();
|
void init_detector();
|
||||||
@ -119,6 +121,10 @@ int get_transmission_delay_left(int);
|
|||||||
int set_transmission_delay_right(int);
|
int set_transmission_delay_right(int);
|
||||||
int get_transmission_delay_right(int);
|
int get_transmission_delay_right(int);
|
||||||
int program_fpga(int);
|
int program_fpga(int);
|
||||||
|
void program_fpga_via_blackfin(int file_des, enum PROGRAMINDEX index,
|
||||||
|
uint64_t filesize, char *checksum);
|
||||||
|
void program_fpga_via_nios(int file_des, enum PROGRAMINDEX index,
|
||||||
|
uint64_t filesize, char *checksum);
|
||||||
int reset_fpga(int);
|
int reset_fpga(int);
|
||||||
int power_chip(int);
|
int power_chip(int);
|
||||||
int set_activate(int);
|
int set_activate(int);
|
||||||
@ -278,4 +284,4 @@ int set_udp_first_dest(int);
|
|||||||
int get_readout_speed(int);
|
int get_readout_speed(int);
|
||||||
int set_readout_speed(int);
|
int set_readout_speed(int);
|
||||||
int get_kernel_version(int);
|
int get_kernel_version(int);
|
||||||
int copy_kernel(int);
|
int program_kernel(int);
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||||
#include "programFpgaBlackfin.h"
|
#include "programViaBlackfin.h"
|
||||||
#include "clogger.h"
|
#include "clogger.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "sls/ansi.h"
|
#include "sls/ansi.h"
|
||||||
@ -13,13 +13,26 @@
|
|||||||
/* global variables */
|
/* global variables */
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#define MAX_TIME_FPGA_TOUCH_FLASH_US (10 * 1000 * 1000) // 10s
|
#define MAX_TIME_FPGA_TOUCH_FLASH_US (10 * 1000 * 1000) // 10s
|
||||||
#define CMD_GET_FLASH "awk \'$4== \"\\\"bitfile(spi)\\\"\" {print $1}\' /proc/mtd"
|
|
||||||
|
#define CMD_GPIO9_DEFINE_OUT "echo out > /sys/class/gpio/gpio9/direction"
|
||||||
|
#define CMD_GPIO3_DEFINE_OUT "echo out > /sys/class/gpio/gpio3/direction"
|
||||||
|
#define CMD_GPIO9_DEFINE_IN "echo in > /sys/class/gpio/gpio9/direction"
|
||||||
|
#define CMD_GPIO3_DEFINE_IN "echo in > /sys/class/gpio/gpio3/direction"
|
||||||
|
|
||||||
|
#define CMD_GPIO9_DONT_TOUCH_FLASH "echo 0 > /sys/class/gpio/gpio9/value"
|
||||||
|
#define CMD_GPIO3_DONT_TOUCH_FLASH "echo 0 > /sys/class/gpio/gpio3/value"
|
||||||
|
|
||||||
|
#define CMD_GET_FPGA_FLASH_DRIVE "awk \'$4== \"\\\"bitfile(spi)\\\"\" {print $1}\' /proc/mtd"
|
||||||
|
#define CMD_GET_KERNEL_FLASH_DRIVE "awk \'$4== \"\\\"linux kernel(nor)\\\"\" {print $1}\' /proc/mtd"
|
||||||
|
|
||||||
#define CMD_FPGA_PICKED_STATUS "cat /sys/class/gpio/gpio7/value"
|
#define CMD_FPGA_PICKED_STATUS "cat /sys/class/gpio/gpio7/value"
|
||||||
|
|
||||||
#define FLASH_BUFFER_MEMORY_SIZE (128 * 1024) // 500 KB
|
#define FLASH_BUFFER_MEMORY_SIZE (128 * 1024) // 500 KB
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
#define FLASH_DRIVE_NAME_SIZE 16
|
#define FLASH_DRIVE_NAME_SIZE 16
|
||||||
char flashDriveName[FLASH_DRIVE_NAME_SIZE] = {0};
|
char flashDriveName[FLASH_DRIVE_NAME_SIZE] = {0};
|
||||||
|
char messageType[SHORT_STR_LENGTH] = {0};
|
||||||
int gpioDefined = 0;
|
int gpioDefined = 0;
|
||||||
|
|
||||||
extern int executeCommand(char *command, char *result, enum TLogLevel level);
|
extern int executeCommand(char *command, char *result, enum TLogLevel level);
|
||||||
@ -60,80 +73,122 @@ void defineGPIOpins() {
|
|||||||
LOG(logDEBUG1, ("gpio pins already defined earlier\n"));
|
LOG(logDEBUG1, ("gpio pins already defined earlier\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FPGAdontTouchFlash() {
|
int FPGAdontTouchFlash(char *mess) {
|
||||||
#ifdef VIRTUAL
|
#ifdef VIRTUAL
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
// define as output pins
|
// define as output pins
|
||||||
system("echo out > /sys/class/gpio/gpio9/direction");
|
if (executeCommand(CMD_GPIO9_DEFINE_OUT, retvals, logDEBUG1) == FAIL) {
|
||||||
|
snprintf(mess, MAX_STR_LENGTH,
|
||||||
|
"Could not program fpga. (could not set gpio9 as output)\n");
|
||||||
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
LOG(logINFO, ("\tgpio9: setting output\n"));
|
LOG(logINFO, ("\tgpio9: setting output\n"));
|
||||||
|
|
||||||
if (latestKernelVerified == 1) {
|
if (latestKernelVerified == 1) {
|
||||||
// gpio 3 = not chip enable
|
// gpio 3 = not chip enable
|
||||||
system("echo out > /sys/class/gpio/gpio3/direction");
|
if (executeCommand(CMD_GPIO3_DEFINE_OUT, retvals, logDEBUG1) == FAIL) {
|
||||||
|
snprintf(
|
||||||
|
mess, MAX_STR_LENGTH,
|
||||||
|
"Could not program fpga. (could not set gpio3 as output)\n");
|
||||||
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
LOG(logINFO, ("\tgpio3: setting output\n"));
|
LOG(logINFO, ("\tgpio3: setting output\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell FPGA to not touch flash
|
// tell FPGA to not touch
|
||||||
system("echo 0 > /sys/class/gpio/gpio9/value");
|
if (executeCommand(CMD_GPIO9_DONT_TOUCH_FLASH, retvals, logDEBUG1) ==
|
||||||
LOG(logINFO, ("\tgpio9: fpga dont touch flash\n"));
|
FAIL) {
|
||||||
|
snprintf(mess, MAX_STR_LENGTH,
|
||||||
|
"Could not program fpga. (could not set gpio9 to not touch "
|
||||||
|
"flash)\n");
|
||||||
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
LOG(logINFO, ("\tgpio9: fpga dont touch flash\n"));
|
||||||
|
|
||||||
if (latestKernelVerified == 1) {
|
if (latestKernelVerified == 1) {
|
||||||
system("echo 1 > /sys/class/gpio/gpio3/value");
|
if (executeCommand(CMD_GPIO3_DONT_TOUCH_FLASH, retvals, logDEBUG1) ==
|
||||||
|
FAIL) {
|
||||||
|
snprintf(mess, MAX_STR_LENGTH,
|
||||||
|
"Could not program fpga. (could not set gpio3 to not "
|
||||||
|
"touch flash)\n");
|
||||||
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
LOG(logINFO, ("\tgpio3: fpga dont touch flash\n"));
|
LOG(logINFO, ("\tgpio3: fpga dont touch flash\n"));
|
||||||
}
|
}
|
||||||
// usleep(100*1000);
|
// usleep(100*1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FPGATouchFlash() {
|
int FPGATouchFlash(char *mess) {
|
||||||
#ifdef VIRTUAL
|
#ifdef VIRTUAL
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
// tell FPGA to touch flash to program itself
|
// tell FPGA to touch flash to program itself
|
||||||
system("echo in > /sys/class/gpio/gpio9/direction");
|
if (executeCommand(CMD_GPIO9_DEFINE_IN, retvals, logDEBUG1) == FAIL) {
|
||||||
|
snprintf(mess, MAX_STR_LENGTH,
|
||||||
|
"Could not program fpga. (could not set gpio9 as input)\n");
|
||||||
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
LOG(logINFO, ("\tgpio9: setting input\n"));
|
LOG(logINFO, ("\tgpio9: setting input\n"));
|
||||||
|
|
||||||
if (latestKernelVerified == 1) {
|
if (latestKernelVerified == 1) {
|
||||||
system("echo in > /sys/class/gpio/gpio3/direction");
|
if (executeCommand(CMD_GPIO3_DEFINE_IN, retvals, logDEBUG1) == FAIL) {
|
||||||
|
snprintf(
|
||||||
|
mess, MAX_STR_LENGTH,
|
||||||
|
"Could not program fpga. (could not set gpio3 as input)\n");
|
||||||
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
LOG(logINFO, ("\tgpio3: setting input\n"));
|
LOG(logINFO, ("\tgpio3: setting input\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetFPGA() {
|
int resetFPGA(char *mess) {
|
||||||
LOG(logINFOBLUE, ("Reseting FPGA\n"));
|
LOG(logINFOBLUE, ("Reseting FPGA\n"));
|
||||||
#ifdef VIRTUAL
|
#ifdef VIRTUAL
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
FPGAdontTouchFlash();
|
if (FPGAdontTouchFlash(mess) == FAIL) {
|
||||||
FPGATouchFlash();
|
return FAIL;
|
||||||
|
}
|
||||||
|
if (FPGATouchFlash(mess) == FAIL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
usleep(CTRL_SRVR_INIT_TIME_US);
|
usleep(CTRL_SRVR_INIT_TIME_US);
|
||||||
}
|
}
|
||||||
|
|
||||||
int deleteOldFile(char *mess) {
|
int emptyTempFolder(char *mess) {
|
||||||
char cmd[MAX_STR_LENGTH] = {0};
|
char cmd[MAX_STR_LENGTH] = {0};
|
||||||
char retvals[MAX_STR_LENGTH] = {0};
|
char retvals[MAX_STR_LENGTH] = {0};
|
||||||
|
|
||||||
char *format = "rm -fr %s";
|
char *format = "rm -fr %s*";
|
||||||
if (snprintf(cmd, MAX_STR_LENGTH, format, TEMP_PROG_FILE_NAME) >=
|
if (snprintf(cmd, MAX_STR_LENGTH, format, TEMP_PROG_FOLDER_NAME) >=
|
||||||
MAX_STR_LENGTH) {
|
MAX_STR_LENGTH) {
|
||||||
strcpy(
|
sprintf(mess,
|
||||||
mess,
|
"Could not update %s. Command to empty %s folder is too long\n",
|
||||||
"Could not program fpga. Command to delete old file is too long\n");
|
messageType, TEMP_PROG_FOLDER_NAME);
|
||||||
LOG(logERROR, (mess));
|
LOG(logERROR, (mess));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
||||||
snprintf(mess, MAX_STR_LENGTH,
|
snprintf(mess, MAX_STR_LENGTH,
|
||||||
"Could not program fpga. (could not delete old file: %s)\n",
|
"Could not update %s. (could not empty %s folder: %s)\n",
|
||||||
retvals);
|
messageType, TEMP_PROG_FOLDER_NAME, retvals);
|
||||||
// LOG(logERROR, (mess)); already printed in executecommand
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
LOG(logINFO,
|
LOG(logINFO, ("\tDeleted temp folder(%s)\n", TEMP_PROG_FOLDER_NAME));
|
||||||
("\tDeleted old programming file (%s)\n", TEMP_PROG_FILE_NAME));
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int preparetoCopyFPGAProgram(FILE **fd, uint64_t fsize, char *mess) {
|
int preparetoCopyProgram(FILE **fd, uint64_t fsize, char *mess) {
|
||||||
|
|
||||||
if (deleteOldFile(mess) == FAIL) {
|
if (emptyTempFolder(mess) == FAIL) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +198,7 @@ int preparetoCopyFPGAProgram(FILE **fd, uint64_t fsize, char *mess) {
|
|||||||
sysinfo(&info);
|
sysinfo(&info);
|
||||||
if (fsize >= info.freeram) {
|
if (fsize >= info.freeram) {
|
||||||
sprintf(mess,
|
sprintf(mess,
|
||||||
"Could not program fpga. Not enough memory to copy "
|
"Could not update program. Not enough memory to copy "
|
||||||
"program. [File size:%ldMB, free RAM: %ldMB]\n",
|
"program. [File size:%ldMB, free RAM: %ldMB]\n",
|
||||||
(long int)(fsize / (1024 * 1024)),
|
(long int)(fsize / (1024 * 1024)),
|
||||||
(long int)(info.freeram / (1024 * 1024)));
|
(long int)(info.freeram / (1024 * 1024)));
|
||||||
@ -163,9 +218,13 @@ int preparetoCopyFPGAProgram(FILE **fd, uint64_t fsize, char *mess) {
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int copyToFlash(ssize_t fsize, char *clientChecksum, char *mess) {
|
int copyToFlash(enum PROGRAMINDEX index, char *mType, ssize_t fsize,
|
||||||
|
char *clientChecksum, char *mess) {
|
||||||
|
|
||||||
if (getDrive(mess) == FAIL) {
|
memset(messageType, 0, sizeof(messageType));
|
||||||
|
strcpy(messageType, mType);
|
||||||
|
|
||||||
|
if (getDrive(index, messageType, mess) == FAIL) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,6 +234,12 @@ int copyToFlash(ssize_t fsize, char *clientChecksum, char *mess) {
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index == FPGA_PROGRAM) {
|
||||||
|
if (FPGAdontTouchFlash(char *mess) == FAIL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (eraseFlash(mess) == FAIL) {
|
if (eraseFlash(mess) == FAIL) {
|
||||||
fclose(flashfd);
|
fclose(flashfd);
|
||||||
fclose(srcfd);
|
fclose(srcfd);
|
||||||
@ -185,24 +250,40 @@ int copyToFlash(ssize_t fsize, char *clientChecksum, char *mess) {
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deleteOldFile(mess) == FAIL) {
|
if (emptyTempFolder(mess) == FAIL) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ignoring this until flash fixed
|
/* remove condition when flash fpga fixed */
|
||||||
if (verifyChecksumFromFlash(mess, clientChecksum, flashDriveName, fsize) == FAIL) { return FAIL;
|
if (index == KERNEL_PROGRAM) {
|
||||||
|
if (verifyChecksumFromFlash(mess, clientChecksum, flashDriveName,
|
||||||
|
fsize) == FAIL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
if (waitForFPGAtoTouchFlash(mess) == FAIL) {
|
if (index == FPGA_PROGRAM) {
|
||||||
return FAIL;
|
if (waitForFPGAtoTouchFlash(mess) == FAIL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kernel
|
||||||
|
else {
|
||||||
|
if (executeCommand("sync", retvals, logDEBUG1) == FAIL) {
|
||||||
|
snprintf(mess, MAX_STR_LENGTH,
|
||||||
|
"Could not update %s. (could not sync)\n", messageType);
|
||||||
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getDrive(char *mess) {
|
int getDrive(enum PROGRAMINDEX index, char *mess) {
|
||||||
#ifdef VIRTUAL
|
#ifdef VIRTUAL
|
||||||
strcpy(flashDriveName, "/tmp/SLS_mtd3");
|
strcpy(flashDriveName, "/tmp/SLS_tmpDrive");
|
||||||
return OK;
|
return OK;
|
||||||
#endif
|
#endif
|
||||||
LOG(logDEBUG1, ("Finding flash drive...\n"));
|
LOG(logDEBUG1, ("Finding flash drive...\n"));
|
||||||
@ -217,18 +298,25 @@ int getDrive(char *mess) {
|
|||||||
char cmd[MAX_STR_LENGTH] = {0};
|
char cmd[MAX_STR_LENGTH] = {0};
|
||||||
char retvals[MAX_STR_LENGTH] = {0};
|
char retvals[MAX_STR_LENGTH] = {0};
|
||||||
|
|
||||||
strcpy(cmd, CMD_GET_FLASH);
|
if (index == FPGA_PROGRAM) {
|
||||||
|
strcpy(cmd, CMD_GET_FPGA_FLASH_DRIVE);
|
||||||
|
} else {
|
||||||
|
strcpy(cmd, CMD_GET_KERNEL_FLASH_DRIVE);
|
||||||
|
}
|
||||||
if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
||||||
snprintf(mess, MAX_STR_LENGTH,
|
snprintf(mess, MAX_STR_LENGTH,
|
||||||
"Could not program fpga. (could not get flash drive: %s)\n",
|
"Could not update %s. (could not get flash drive: %s)\n",
|
||||||
retvals);
|
messageType, retvals);
|
||||||
// LOG(logERROR, (mess)); already printed in executecommand
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pch = strtok(retvals, ":");
|
char *pch = strtok(retvals, ":");
|
||||||
if (pch == NULL) {
|
if (pch == NULL) {
|
||||||
strcpy(mess, "Could not get mtd drive to flash (strtok fail).\n");
|
strcpy(mess,
|
||||||
|
"Could not update %s. Could not get mtd drive to flash (strtok "
|
||||||
|
"fail).\n",
|
||||||
|
messageType);
|
||||||
LOG(logERROR, (mess));
|
LOG(logERROR, (mess));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -241,15 +329,14 @@ int getDrive(char *mess) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int openFileForFlash(FILE **flashfd, FILE **srcfd, char *mess) {
|
int openFileForFlash(FILE **flashfd, FILE **srcfd, char *mess) {
|
||||||
FPGAdontTouchFlash();
|
|
||||||
|
|
||||||
// open src file
|
// open src file
|
||||||
*srcfd = fopen(TEMP_PROG_FILE_NAME, "r");
|
*srcfd = fopen(TEMP_PROG_FILE_NAME, "r");
|
||||||
if (*srcfd == NULL) {
|
if (*srcfd == NULL) {
|
||||||
sprintf(mess,
|
sprintf(
|
||||||
"Could not flash. Unable to open temp program file %s in read "
|
mess,
|
||||||
"mode\n",
|
"Could not update %s. Unable to open temp program file %s in read "
|
||||||
TEMP_PROG_FILE_NAME);
|
"mode\n",
|
||||||
|
messageType, TEMP_PROG_FILE_NAME);
|
||||||
LOG(logERROR, (mess));
|
LOG(logERROR, (mess));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -259,8 +346,10 @@ int openFileForFlash(FILE **flashfd, FILE **srcfd, char *mess) {
|
|||||||
*flashfd = fopen(flashDriveName, "w");
|
*flashfd = fopen(flashDriveName, "w");
|
||||||
if (*flashfd == NULL) {
|
if (*flashfd == NULL) {
|
||||||
fclose(*srcfd);
|
fclose(*srcfd);
|
||||||
sprintf(mess, "Unable to open flash drive %s in write mode\n",
|
sprintf(mess,
|
||||||
flashDriveName);
|
"Could not update %s. Unable to open flash drive %s in write "
|
||||||
|
"mode\n",
|
||||||
|
messageType, flashDriveName);
|
||||||
LOG(logERROR, (mess));
|
LOG(logERROR, (mess));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -279,15 +368,16 @@ int eraseFlash(char *mess) {
|
|||||||
char *format = "flash_eraseall %s";
|
char *format = "flash_eraseall %s";
|
||||||
if (snprintf(cmd, MAX_STR_LENGTH, format, flashDriveName) >=
|
if (snprintf(cmd, MAX_STR_LENGTH, format, flashDriveName) >=
|
||||||
MAX_STR_LENGTH) {
|
MAX_STR_LENGTH) {
|
||||||
strcpy(mess,
|
sprintf(mess,
|
||||||
"Could not program fpga. Command to erase flash is too long\n");
|
"Could not update %s. Command to erase flash is too long\n",
|
||||||
|
messageType);
|
||||||
LOG(logERROR, (mess));
|
LOG(logERROR, (mess));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
||||||
snprintf(mess, MAX_STR_LENGTH,
|
snprintf(mess, MAX_STR_LENGTH,
|
||||||
"Could not program fpga. (could not erase flash: %s)\n",
|
"Could not update %s. (could not erase flash: %s)\n",
|
||||||
retvals);
|
messageType, retvals);
|
||||||
// LOG(logERROR, (mess)); already printed in executecommand
|
// LOG(logERROR, (mess)); already printed in executecommand
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -302,8 +392,10 @@ int writeToFlash(ssize_t fsize, FILE *flashfd, FILE *srcfd, char *mess) {
|
|||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
fclose(flashfd);
|
fclose(flashfd);
|
||||||
fclose(srcfd);
|
fclose(srcfd);
|
||||||
strcpy(mess, "Could not program fpga. Memory allocation to write to "
|
sprintf(mess,
|
||||||
"flash failed.\n");
|
"Could not update %s. Memory allocation to write to "
|
||||||
|
"flash failed.\n",
|
||||||
|
messageType);
|
||||||
LOG(logERROR, (mess));
|
LOG(logERROR, (mess));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -325,9 +417,10 @@ int writeToFlash(ssize_t fsize, FILE *flashfd, FILE *srcfd, char *mess) {
|
|||||||
fclose(flashfd);
|
fclose(flashfd);
|
||||||
fclose(srcfd);
|
fclose(srcfd);
|
||||||
sprintf(mess,
|
sprintf(mess,
|
||||||
"Could not write to flash (bytes written:%ld, expected: "
|
"Could not update %s. Could not write to flash (bytes "
|
||||||
|
"written:%ld, expected: "
|
||||||
"%ld, total written:%ld)\n",
|
"%ld, total written:%ld)\n",
|
||||||
(long int)bytesWritten, (long int)bytes,
|
messageType, (long int)bytesWritten, (long int)bytes,
|
||||||
(long int)totalBytes);
|
(long int)totalBytes);
|
||||||
LOG(logERROR, (mess));
|
LOG(logERROR, (mess));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -357,9 +450,9 @@ int writeToFlash(ssize_t fsize, FILE *flashfd, FILE *srcfd, char *mess) {
|
|||||||
|
|
||||||
if (totalBytes != fsize) {
|
if (totalBytes != fsize) {
|
||||||
sprintf(mess,
|
sprintf(mess,
|
||||||
"Could not program fpga. Incorrect bytes written to flash %lu "
|
"Could not update %s. Incorrect bytes written to flash %lu "
|
||||||
"[expected: %lu]\n",
|
"[expected: %lu]\n",
|
||||||
totalBytes, fsize);
|
messageType, totalBytes, fsize);
|
||||||
LOG(logERROR, (mess));
|
LOG(logERROR, (mess));
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@ -368,7 +461,9 @@ int writeToFlash(ssize_t fsize, FILE *flashfd, FILE *srcfd, char *mess) {
|
|||||||
|
|
||||||
int waitForFPGAtoTouchFlash(char *mess) {
|
int waitForFPGAtoTouchFlash(char *mess) {
|
||||||
// touch and program
|
// touch and program
|
||||||
FPGATouchFlash();
|
if (FPGATouchFlash(mess) == FAIL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VIRTUAL
|
#ifdef VIRTUAL
|
||||||
return OK;
|
return OK;
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||||
#include "programFpgaNios.h"
|
#include "programViaNios.h"
|
||||||
#include "clogger.h"
|
#include "clogger.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "sls/ansi.h"
|
#include "sls/ansi.h"
|
@ -415,8 +415,7 @@ void function_table() {
|
|||||||
flist[F_GET_READOUT_SPEED] = &get_readout_speed;
|
flist[F_GET_READOUT_SPEED] = &get_readout_speed;
|
||||||
flist[F_SET_READOUT_SPEED] = &set_readout_speed;
|
flist[F_SET_READOUT_SPEED] = &set_readout_speed;
|
||||||
flist[F_GET_KERNEL_VERSION] = &get_kernel_version;
|
flist[F_GET_KERNEL_VERSION] = &get_kernel_version;
|
||||||
flist[F_COPY_KERNEL] = ©_kernel;
|
flist[F_PROGRAM_KERNEL] = &program_kernel;
|
||||||
|
|
||||||
|
|
||||||
// check
|
// check
|
||||||
if (NUM_DET_FUNCTIONS >= RECEIVER_ENUM_START) {
|
if (NUM_DET_FUNCTIONS >= RECEIVER_ENUM_START) {
|
||||||
@ -3667,129 +3666,152 @@ int program_fpga(int file_des) {
|
|||||||
return printSocketReadError();
|
return printSocketReadError();
|
||||||
LOG(logDEBUG1, ("checksum is: %s\n\n", checksum));
|
LOG(logDEBUG1, ("checksum is: %s\n\n", checksum));
|
||||||
|
|
||||||
#if defined(MYTHEN3D) || defined(GOTTHARD2D)
|
switch (myDetectorType) {
|
||||||
if (filesize > NIOS_MAX_APP_IMAGE_SIZE) {
|
case MYTHEN3:
|
||||||
ret = FAIL;
|
case GOTTHARD2:
|
||||||
sprintf(mess,
|
program_fpga_via_nios(file_des, FPGA_PROGRAM, filesize, checksum);
|
||||||
"Could not start programming FPGA. File size 0x%llx "
|
break;
|
||||||
"exceeds max size 0x%llx. Forgot Compression?\n",
|
default:
|
||||||
(long long unsigned int)filesize,
|
program_fpga_via_blackfin(file_des, FPGA_PROGRAM, filesize,
|
||||||
(long long unsigned int)NIOS_MAX_APP_IMAGE_SIZE);
|
checksum);
|
||||||
LOG(logERROR, (mess));
|
break;
|
||||||
}
|
}
|
||||||
Server_SendResult(file_des, INT32, NULL, 0);
|
|
||||||
|
|
||||||
// receive program
|
|
||||||
if (ret == OK) {
|
if (ret == OK) {
|
||||||
char *fpgasrc = malloc(filesize);
|
LOG(logINFOGREEN, ("Programming FPGA completed successfully\n"));
|
||||||
if (receiveData(file_des, fpgasrc, filesize, OTHER) < 0) {
|
} else {
|
||||||
free(fpgasrc);
|
|
||||||
return printSocketReadError();
|
|
||||||
}
|
|
||||||
ret = eraseAndWriteToFlash(mess, checksum, fpgasrc, filesize);
|
|
||||||
Server_SendResult(file_des, INT32, NULL, 0);
|
|
||||||
free(fpgasrc);
|
|
||||||
}
|
|
||||||
if (ret == FAIL) {
|
|
||||||
LOG(logERROR, ("Program FPGA FAIL!\n"));
|
LOG(logERROR, ("Program FPGA FAIL!\n"));
|
||||||
return FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // jungfrau, ctb, moench
|
|
||||||
|
|
||||||
// open file and allocate memory for part program
|
|
||||||
FILE *fd = NULL;
|
|
||||||
ret = preparetoCopyFPGAProgram(&fd, filesize, mess);
|
|
||||||
char *src = NULL;
|
|
||||||
if (ret == OK) {
|
|
||||||
src = malloc(MAX_FPGAPROGRAMSIZE);
|
|
||||||
if (src == NULL) {
|
|
||||||
fclose(fd);
|
|
||||||
struct sysinfo info;
|
|
||||||
sysinfo(&info);
|
|
||||||
sprintf(mess,
|
|
||||||
"Could not allocate memory to get fpga program. Free "
|
|
||||||
"space: %d MB\n",
|
|
||||||
(int)(info.freeram / (1024 * 1024)));
|
|
||||||
LOG(logERROR, (mess));
|
|
||||||
ret = FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Server_SendResult(file_des, INT32, NULL, 0);
|
|
||||||
if (ret == FAIL) {
|
|
||||||
LOG(logERROR, ("Program FPGA FAIL1!\n"));
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copying program part by part
|
|
||||||
uint64_t totalsize = filesize;
|
|
||||||
while (ret == OK && filesize) {
|
|
||||||
uint64_t unitprogramsize = MAX_FPGAPROGRAMSIZE; // 2mb
|
|
||||||
if (unitprogramsize > filesize) // less than 2mb
|
|
||||||
unitprogramsize = filesize;
|
|
||||||
LOG(logDEBUG1, ("unit size to receive is:%lld [filesize:%lld]\n",
|
|
||||||
(long long unsigned int)unitprogramsize,
|
|
||||||
(long long unsigned int)filesize));
|
|
||||||
|
|
||||||
// receive part of program
|
|
||||||
if (receiveData(file_des, src, unitprogramsize, OTHER) < 0) {
|
|
||||||
printSocketReadError();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unitprogramsize - filesize == 0) {
|
|
||||||
// src[unitprogramsize] = '\0';
|
|
||||||
filesize -= unitprogramsize;
|
|
||||||
// unitprogramsize++;
|
|
||||||
} else
|
|
||||||
filesize -= unitprogramsize;
|
|
||||||
|
|
||||||
// copy program
|
|
||||||
if (fwrite((void *)src, sizeof(char), unitprogramsize, fd) !=
|
|
||||||
unitprogramsize) {
|
|
||||||
ret = FAIL;
|
|
||||||
sprintf(mess, "Could not copy program to /var/tmp (size:%ld)\n",
|
|
||||||
(long int)unitprogramsize);
|
|
||||||
LOG(logERROR, (mess));
|
|
||||||
}
|
|
||||||
Server_SendResult(file_des, INT32, NULL, 0);
|
|
||||||
if (ret == FAIL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// print progress
|
|
||||||
LOG(logINFO,
|
|
||||||
("\t%d%%\r",
|
|
||||||
(int)(((double)(totalsize - filesize) / totalsize) * 100)));
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
free(src);
|
|
||||||
fclose(fd);
|
|
||||||
|
|
||||||
// checksum of copied program
|
|
||||||
if (ret == OK) {
|
|
||||||
ret = verifyChecksumFromFile(mess, checksum, TEMP_PROG_FILE_NAME);
|
|
||||||
}
|
|
||||||
Server_SendResult(file_des, INT32, NULL, 0);
|
|
||||||
if (ret == FAIL) {
|
|
||||||
LOG(logERROR, ("Program FPGA FAIL!\n"));
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy to flash
|
|
||||||
ret = copyToFlash(totalsize, checksum, mess);
|
|
||||||
Server_SendResult(file_des, INT32, NULL, 0);
|
|
||||||
if (ret == FAIL) {
|
|
||||||
LOG(logERROR, ("Program FPGA FAIL!\n"));
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // end of Blackfin programming
|
|
||||||
LOG(logINFOGREEN, ("Programming FPGA completed successfully\n"));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void program_fpga_via_blackfin(int file_des, enum PROGRAMINDEX index,
|
||||||
|
uint64_t filesize, char *checksum) {
|
||||||
|
char messageType[SHORT_STR_LENGTH] = {0};
|
||||||
|
switch (index) {
|
||||||
|
case FPGA_PROGRAM:
|
||||||
|
strcpy(messageType, "fpga program");
|
||||||
|
break;
|
||||||
|
case KERNEL_PROGRAM:
|
||||||
|
strcpy(messageType, "kernel program");
|
||||||
|
break;
|
||||||
|
case SERVER_PROGRAM:
|
||||||
|
strcpy(messageType, "server program");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = FAIL;
|
||||||
|
sprintf(mess, "Unknown program index %d\n", index);
|
||||||
|
LOG(logERROR, (mess));
|
||||||
|
Server_SendResult(file_des, INT32, NULL, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open file and allocate memory for part program
|
||||||
|
FILE *fd = NULL;
|
||||||
|
ret = preparetoCopyProgram(&fd, filesize, mess);
|
||||||
|
char *src = NULL;
|
||||||
|
if (ret == OK) {
|
||||||
|
src = malloc(MAX_BLACKFIN_PROGRAM_SIZE);
|
||||||
|
if (src == NULL) {
|
||||||
|
fclose(fd);
|
||||||
|
struct sysinfo info;
|
||||||
|
sysinfo(&info);
|
||||||
|
sprintf(mess,
|
||||||
|
"Could not allocate memory to get %s. Free "
|
||||||
|
"space: %d MB\n",
|
||||||
|
messageType, (int)(info.freeram / (1024 * 1024)));
|
||||||
|
LOG(logERROR, (mess));
|
||||||
|
ret = FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Server_SendResult(file_des, INT32, NULL, 0);
|
||||||
|
if (ret == FAIL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copying program part by part
|
||||||
|
uint64_t totalsize = filesize;
|
||||||
|
while (ret == OK && filesize) {
|
||||||
|
uint64_t unitprogramsize = MAX_BLACKFIN_PROGRAM_SIZE;
|
||||||
|
if (unitprogramsize > filesize)
|
||||||
|
unitprogramsize = filesize;
|
||||||
|
LOG(logDEBUG1, ("unit size to receive is:%lld [filesize:%lld]\n",
|
||||||
|
(long long unsigned int)unitprogramsize,
|
||||||
|
(long long unsigned int)filesize));
|
||||||
|
|
||||||
|
// receive part of program
|
||||||
|
if (receiveData(file_des, src, unitprogramsize, OTHER) < 0) {
|
||||||
|
printSocketReadError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
filesize -= unitprogramsize;
|
||||||
|
|
||||||
|
// copy program
|
||||||
|
if (fwrite((void *)src, sizeof(char), unitprogramsize, fd) !=
|
||||||
|
unitprogramsize) {
|
||||||
|
ret = FAIL;
|
||||||
|
sprintf(mess, "Could not copy program to /var/tmp (size:%ld)\n",
|
||||||
|
(long int)unitprogramsize);
|
||||||
|
LOG(logERROR, (mess));
|
||||||
|
}
|
||||||
|
Server_SendResult(file_des, INT32, NULL, 0);
|
||||||
|
if (ret == FAIL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// print progress
|
||||||
|
LOG(logINFO,
|
||||||
|
("\t%d%%\r",
|
||||||
|
(int)(((double)(totalsize - filesize) / totalsize) * 100)));
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
free(src);
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
// checksum of copied program
|
||||||
|
if (ret == OK) {
|
||||||
|
ret = verifyChecksumFromFile(mess, checksum, TEMP_PROG_FILE_NAME);
|
||||||
|
}
|
||||||
|
Server_SendResult(file_des, INT32, NULL, 0);
|
||||||
|
if (ret == FAIL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy to flash
|
||||||
|
ret = copyToFlash(index, messageType, totalsize, checksum, mess);
|
||||||
|
Server_SendResult(file_des, INT32, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int program_fpga_via_nios(int file_des, uint64_t filesize, char *checksum) {
|
||||||
|
// validate file size
|
||||||
|
if (filesize > NIOS_MAX_APP_IMAGE_SIZE) {
|
||||||
|
ret = FAIL;
|
||||||
|
sprintf(mess,
|
||||||
|
"Could not start programming FPGA. File size 0x%llx "
|
||||||
|
"exceeds max size 0x%llx. Forgot Compression?\n",
|
||||||
|
(long long unsigned int)filesize,
|
||||||
|
(long long unsigned int)NIOS_MAX_APP_IMAGE_SIZE);
|
||||||
|
LOG(logERROR, (mess));
|
||||||
|
}
|
||||||
|
Server_SendResult(file_des, INT32, NULL, 0);
|
||||||
|
if (ret == FAIL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// receive program
|
||||||
|
char *src = malloc(filesize);
|
||||||
|
if (receiveData(file_des, src, filesize, OTHER) < 0) {
|
||||||
|
free(src);
|
||||||
|
ret = printSocketReadError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// erase and program
|
||||||
|
ret = eraseAndWriteToFlash(mess, checksum, src, filesize);
|
||||||
|
Server_SendResult(file_des, INT32, NULL, 0);
|
||||||
|
free(src);
|
||||||
|
}
|
||||||
|
|
||||||
int reset_fpga(int file_des) {
|
int reset_fpga(int file_des) {
|
||||||
ret = OK;
|
ret = OK;
|
||||||
memset(mess, 0, sizeof(mess));
|
memset(mess, 0, sizeof(mess));
|
||||||
@ -9428,8 +9450,8 @@ int get_kernel_version(int file_des) {
|
|||||||
// get only
|
// get only
|
||||||
ret = getKernelVersion(retvals);
|
ret = getKernelVersion(retvals);
|
||||||
if (ret == FAIL) {
|
if (ret == FAIL) {
|
||||||
snprintf(mess, MAX_STR_LENGTH,
|
snprintf(mess, MAX_STR_LENGTH, "Could not get kernel version. %s\n",
|
||||||
"Could not get kernel version. %s\n", retvals);
|
retvals);
|
||||||
LOG(logERROR, (mess));
|
LOG(logERROR, (mess));
|
||||||
} else {
|
} else {
|
||||||
LOG(logDEBUG1, ("kernel version: [%s]\n", retvals));
|
LOG(logDEBUG1, ("kernel version: [%s]\n", retvals));
|
||||||
@ -9437,138 +9459,9 @@ int get_kernel_version(int file_des) {
|
|||||||
return Server_SendResult(file_des, OTHER, retvals, sizeof(retvals));
|
return Server_SendResult(file_des, OTHER, retvals, sizeof(retvals));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int program_kernel(int file_des) {
|
||||||
int copy_kernel(int file_des) {
|
|
||||||
ret = OK;
|
ret = OK;
|
||||||
memset(mess, 0, sizeof(mess));
|
memset(mess, 0, sizeof(mess));
|
||||||
char args[2][MAX_STR_LENGTH];
|
|
||||||
char retvals[MAX_STR_LENGTH] = {0};
|
|
||||||
|
|
||||||
memset(args, 0, sizeof(args));
|
return ret;
|
||||||
memset(retvals, 0, sizeof(retvals));
|
}
|
||||||
|
|
||||||
if (receiveData(file_des, args, sizeof(args), OTHER) < 0)
|
|
||||||
return printSocketReadError();
|
|
||||||
|
|
||||||
#ifdef VIRTUAL
|
|
||||||
functionNotImplemented();
|
|
||||||
#else
|
|
||||||
|
|
||||||
// only set
|
|
||||||
if (Server_VerifyLock() == OK) {
|
|
||||||
char *sname = args[0];
|
|
||||||
char *hostname = args[1];
|
|
||||||
LOG(logINFOBLUE, ("Copying kernel image %s from host %s\n", sname, hostname));
|
|
||||||
char cmd[MAX_STR_LENGTH] = {0};
|
|
||||||
|
|
||||||
// tftp server
|
|
||||||
char *format = "tftp %s -r %s -g";
|
|
||||||
if (snprintf(cmd, MAX_STR_LENGTH, format, hostname, sname) >=
|
|
||||||
MAX_STR_LENGTH) {
|
|
||||||
ret = FAIL;
|
|
||||||
strcpy(mess, "Could not copy detector server. Command to copy "
|
|
||||||
"server too long\n");
|
|
||||||
LOG(logERROR, (mess));
|
|
||||||
} else if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
|
||||||
ret = FAIL;
|
|
||||||
snprintf(mess, MAX_STR_LENGTH,
|
|
||||||
"Could not copy detector server (tftp). %s\n", retvals);
|
|
||||||
// LOG(logERROR, (mess)); already printed in executecommand
|
|
||||||
} else {
|
|
||||||
LOG(logINFO, ("\tServer copied\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// give permissions
|
|
||||||
if (ret == OK) {
|
|
||||||
if (snprintf(cmd, MAX_STR_LENGTH, "chmod 777 %s", sname) >=
|
|
||||||
MAX_STR_LENGTH) {
|
|
||||||
ret = FAIL;
|
|
||||||
strcpy(mess, "Could not copy detector server. Command to give "
|
|
||||||
"permissions to server is too long\n");
|
|
||||||
LOG(logERROR, (mess));
|
|
||||||
} else if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
|
||||||
ret = FAIL;
|
|
||||||
snprintf(mess, MAX_STR_LENGTH,
|
|
||||||
"Could not copy detector server (permissions). %s\n",
|
|
||||||
retvals);
|
|
||||||
// LOG(logERROR, (mess)); already printed in executecommand
|
|
||||||
} else {
|
|
||||||
LOG(logINFO, ("\tPermissions modified\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// symbolic link
|
|
||||||
if (ret == OK) {
|
|
||||||
if (snprintf(cmd, MAX_STR_LENGTH, "ln -sf %s %s", sname,
|
|
||||||
LINKED_SERVER_NAME) >= MAX_STR_LENGTH) {
|
|
||||||
ret = FAIL;
|
|
||||||
strcpy(mess, "Could not copy detector server. Command to "
|
|
||||||
"create symbolic link too long\n");
|
|
||||||
LOG(logERROR, (mess));
|
|
||||||
} else if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
|
||||||
ret = FAIL;
|
|
||||||
snprintf(mess, MAX_STR_LENGTH,
|
|
||||||
"Could not copy detector server (symbolic link). %s\n",
|
|
||||||
retvals);
|
|
||||||
// LOG(logERROR, (mess)); already printed in executecommand
|
|
||||||
} else {
|
|
||||||
LOG(logINFO, ("\tSymbolic link created\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// blackfin boards (respawn) (only kept for backwards compatibility)
|
|
||||||
#if defined(JUNGFRAUD) || defined(CHIPTESTBOARDD) || defined(MOENCHD) || \
|
|
||||||
defined(GOTTHARDD)
|
|
||||||
// delete every line with DetectorServer in /etc/inittab
|
|
||||||
if (ret == OK) {
|
|
||||||
strcpy(cmd, "sed -i '/DetectorServer/d' /etc/inittab");
|
|
||||||
if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
|
||||||
ret = FAIL;
|
|
||||||
snprintf(
|
|
||||||
mess, MAX_STR_LENGTH,
|
|
||||||
"Could not copy detector server (del respawning). %s\n",
|
|
||||||
retvals);
|
|
||||||
// LOG(logERROR, (mess)); already printed in executecommand
|
|
||||||
} else {
|
|
||||||
LOG(logINFO, ("\tinittab: DetectoServer line deleted\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add new link name to /etc/inittab
|
|
||||||
if (ret == OK) {
|
|
||||||
format = "echo 'ttyS0::respawn:/./%s' >> /etc/inittab";
|
|
||||||
if (snprintf(cmd, MAX_STR_LENGTH, format, LINKED_SERVER_NAME) >=
|
|
||||||
MAX_STR_LENGTH) {
|
|
||||||
ret = FAIL;
|
|
||||||
strcpy(mess, "Could not copy detector server. Command "
|
|
||||||
"to add new server for spawning is too long\n");
|
|
||||||
LOG(logERROR, (mess));
|
|
||||||
} else if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
|
||||||
ret = FAIL;
|
|
||||||
snprintf(mess, MAX_STR_LENGTH,
|
|
||||||
"Could not copy detector server (respawning). %s\n",
|
|
||||||
retvals);
|
|
||||||
// LOG(logERROR, (mess)); already printed in executecommand
|
|
||||||
} else {
|
|
||||||
LOG(logINFO, ("\tinittab: updated for respawning\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// sync
|
|
||||||
if (ret == OK) {
|
|
||||||
strcpy(cmd, "sync");
|
|
||||||
if (executeCommand(cmd, retvals, logDEBUG1) == FAIL) {
|
|
||||||
ret = FAIL;
|
|
||||||
snprintf(mess, MAX_STR_LENGTH,
|
|
||||||
"Could not copy detector server (sync). %s\n",
|
|
||||||
retvals);
|
|
||||||
// LOG(logERROR, (mess)); already printed in executecommand
|
|
||||||
} else {
|
|
||||||
LOG(logINFO, ("\tsync\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return Server_SendResult(file_des, OTHER, retvals, sizeof(retvals));
|
|
||||||
}
|
|
||||||
|
@ -1393,7 +1393,6 @@ std::vector<char> DetectorImpl::readProgrammingFile(const std::string &fname) {
|
|||||||
|
|
||||||
std::vector<char> DetectorImpl::readKernelFile(const std::string &fname) {
|
std::vector<char> DetectorImpl::readKernelFile(const std::string &fname) {
|
||||||
// validate type of file
|
// validate type of file
|
||||||
bool isPof = false;
|
|
||||||
switch (shm()->detType) {
|
switch (shm()->detType) {
|
||||||
case JUNGFRAU:
|
case JUNGFRAU:
|
||||||
case CHIPTESTBOARD:
|
case CHIPTESTBOARD:
|
||||||
@ -1401,7 +1400,6 @@ std::vector<char> DetectorImpl::readKernelFile(const std::string &fname) {
|
|||||||
if (fname.find(".lzma") == std::string::npos) {
|
if (fname.find(".lzma") == std::string::npos) {
|
||||||
throw RuntimeError("Kernel image file must be a lzma file.");
|
throw RuntimeError("Kernel image file must be a lzma file.");
|
||||||
}
|
}
|
||||||
isPof = true;
|
|
||||||
break;
|
break;
|
||||||
case MYTHEN3:
|
case MYTHEN3:
|
||||||
case GOTTHARD2:
|
case GOTTHARD2:
|
||||||
@ -1410,11 +1408,11 @@ std::vector<char> DetectorImpl::readKernelFile(const std::string &fname) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw RuntimeError("Programming kernel image via the package is not implemented for this detector");
|
throw RuntimeError("Programming kernel image via the package is not "
|
||||||
|
"implemented for this detector");
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(logINFO)
|
LOG(logINFO) << "Updating Kernel...";
|
||||||
<< "Updating Kernel...";
|
|
||||||
LOG(logDEBUG1) << "Programming kernel image with file name:" << fname;
|
LOG(logDEBUG1) << "Programming kernel image with file name:" << fname;
|
||||||
|
|
||||||
// check if it exists
|
// check if it exists
|
||||||
@ -1425,9 +1423,7 @@ std::vector<char> DetectorImpl::readKernelFile(const std::string &fname) {
|
|||||||
|
|
||||||
FILE *fp = fopen(fname.c_str(), "rb");
|
FILE *fp = fopen(fname.c_str(), "rb");
|
||||||
if (fp == nullptr) {
|
if (fp == nullptr) {
|
||||||
throw RuntimeError(
|
throw RuntimeError("Program kernel: Could not open file: " + fname);
|
||||||
"Program kernel: Could not open file: " +
|
|
||||||
fname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get file size to print progress
|
// get file size to print progress
|
||||||
@ -1446,8 +1442,7 @@ std::vector<char> DetectorImpl::readKernelFile(const std::string &fname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fclose(fp) != 0) {
|
if (fclose(fp) != 0) {
|
||||||
throw RuntimeError(
|
throw RuntimeError("Program kernel: Could not close file");
|
||||||
"Program kernel: Could not close file");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(logDEBUG1) << "Read file into memory";
|
LOG(logDEBUG1) << "Read file into memory";
|
||||||
|
@ -836,8 +836,9 @@ std::vector<uint64_t> Module::getNumMissingPackets() const {
|
|||||||
auto client = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort);
|
auto client = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort);
|
||||||
client.Send(F_GET_NUM_MISSING_PACKETS);
|
client.Send(F_GET_NUM_MISSING_PACKETS);
|
||||||
if (client.Receive<int>() == FAIL) {
|
if (client.Receive<int>() == FAIL) {
|
||||||
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
|
throw ReceiverError(
|
||||||
" returned error: " + client.readErrorMessage());
|
"Receiver " + std::to_string(moduleIndex) +
|
||||||
|
" returned error: " + client.readErrorMessage());
|
||||||
} else {
|
} else {
|
||||||
auto nports = client.Receive<int>();
|
auto nports = client.Receive<int>();
|
||||||
std::vector<uint64_t> retval(nports);
|
std::vector<uint64_t> retval(nports);
|
||||||
@ -1172,7 +1173,8 @@ void Module::setReceiverHostname(const std::string &receiverIP) {
|
|||||||
LOG(logDEBUG1) << "Setting up Receiver hostname with " << receiverIP;
|
LOG(logDEBUG1) << "Setting up Receiver hostname with " << receiverIP;
|
||||||
|
|
||||||
if (getRunStatus() == RUNNING) {
|
if (getRunStatus() == RUNNING) {
|
||||||
throw RuntimeError("Cannot set receiver hostname. Acquisition already running. Stop it first.");
|
throw RuntimeError("Cannot set receiver hostname. Acquisition already "
|
||||||
|
"running. Stop it first.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receiverIP == "none") {
|
if (receiverIP == "none") {
|
||||||
@ -1529,7 +1531,7 @@ void Module::sendReceiverRateCorrections(const std::vector<int64_t> &t) {
|
|||||||
receiver.Send(t);
|
receiver.Send(t);
|
||||||
if (receiver.Receive<int>() == FAIL) {
|
if (receiver.Receive<int>() == FAIL) {
|
||||||
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
|
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
|
||||||
" returned error: " + receiver.readErrorMessage());
|
" returned error: " + receiver.readErrorMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1785,7 +1787,7 @@ void Module::sendVetoPhoton(const int chipIndex,
|
|||||||
client.Send(values);
|
client.Send(values);
|
||||||
if (client.Receive<int>() == FAIL) {
|
if (client.Receive<int>() == FAIL) {
|
||||||
throw DetectorError("Detector " + std::to_string(moduleIndex) +
|
throw DetectorError("Detector " + std::to_string(moduleIndex) +
|
||||||
" returned error: " + client.readErrorMessage());
|
" returned error: " + client.readErrorMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1797,14 +1799,14 @@ void Module::getVetoPhoton(const int chipIndex,
|
|||||||
client.Send(chipIndex);
|
client.Send(chipIndex);
|
||||||
if (client.Receive<int>() == FAIL) {
|
if (client.Receive<int>() == FAIL) {
|
||||||
throw DetectorError("Detector " + std::to_string(moduleIndex) +
|
throw DetectorError("Detector " + std::to_string(moduleIndex) +
|
||||||
" returned error: " + client.readErrorMessage());
|
" returned error: " + client.readErrorMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nch = client.Receive<int>();
|
auto nch = client.Receive<int>();
|
||||||
if (nch != shm()->nChan.x) {
|
if (nch != shm()->nChan.x) {
|
||||||
throw DetectorError("Could not get veto photon. Expected " +
|
throw DetectorError("Could not get veto photon. Expected " +
|
||||||
std::to_string(shm()->nChan.x) + " channels, got " +
|
std::to_string(shm()->nChan.x) + " channels, got " +
|
||||||
std::to_string(nch));
|
std::to_string(nch));
|
||||||
}
|
}
|
||||||
std::vector<int> gainIndices(nch);
|
std::vector<int> gainIndices(nch);
|
||||||
std::vector<int> values(nch);
|
std::vector<int> values(nch);
|
||||||
@ -2032,7 +2034,7 @@ void Module::getBadChannels(const std::string &fname) const {
|
|||||||
client.Send(F_GET_BAD_CHANNELS);
|
client.Send(F_GET_BAD_CHANNELS);
|
||||||
if (client.Receive<int>() == FAIL) {
|
if (client.Receive<int>() == FAIL) {
|
||||||
throw DetectorError("Detector " + std::to_string(moduleIndex) +
|
throw DetectorError("Detector " + std::to_string(moduleIndex) +
|
||||||
" returned error: " + client.readErrorMessage());
|
" returned error: " + client.readErrorMessage());
|
||||||
}
|
}
|
||||||
// receive badchannels
|
// receive badchannels
|
||||||
auto nch = client.Receive<int>();
|
auto nch = client.Receive<int>();
|
||||||
@ -2089,7 +2091,7 @@ void Module::setBadChannels(const std::string &fname) {
|
|||||||
}
|
}
|
||||||
if (client.Receive<int>() == FAIL) {
|
if (client.Receive<int>() == FAIL) {
|
||||||
throw DetectorError("Detector " + std::to_string(moduleIndex) +
|
throw DetectorError("Detector " + std::to_string(moduleIndex) +
|
||||||
" returned error: " + client.readErrorMessage());
|
" returned error: " + client.readErrorMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2403,7 +2405,7 @@ std::map<std::string, std::string> Module::getAdditionalJsonHeader() const {
|
|||||||
client.Send(F_GET_ADDITIONAL_JSON_HEADER);
|
client.Send(F_GET_ADDITIONAL_JSON_HEADER);
|
||||||
if (client.Receive<int>() == FAIL) {
|
if (client.Receive<int>() == FAIL) {
|
||||||
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
|
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
|
||||||
" returned error: " + client.readErrorMessage());
|
" returned error: " + client.readErrorMessage());
|
||||||
} else {
|
} else {
|
||||||
auto size = client.Receive<int>();
|
auto size = client.Receive<int>();
|
||||||
std::string buff(size, '\0');
|
std::string buff(size, '\0');
|
||||||
@ -2452,7 +2454,7 @@ void Module::setAdditionalJsonHeader(
|
|||||||
|
|
||||||
if (client.Receive<int>() == FAIL) {
|
if (client.Receive<int>() == FAIL) {
|
||||||
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
|
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
|
||||||
" returned error: " + client.readErrorMessage());
|
" returned error: " + client.readErrorMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2492,7 +2494,8 @@ void Module::programFPGA(std::vector<char> buffer) {
|
|||||||
programFPGAviaNios(buffer);
|
programFPGAviaNios(buffer);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw RuntimeError("Programming FPGA via the package is not implemented for this detector");
|
throw RuntimeError("Programming FPGA via the package is not "
|
||||||
|
"implemented for this detector");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2532,7 +2535,8 @@ void Module::updateKernel(std::vector<char> buffer) {
|
|||||||
updateKernelviaNios(buffer);
|
updateKernelviaNios(buffer);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw RuntimeError("Updating Kernel via the package is not implemented for this detector");
|
throw RuntimeError("Updating Kernel via the package is not implemented "
|
||||||
|
"for this detector");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3193,7 +3197,7 @@ void Module::setModule(sls_detector_module &module, bool trimbits) {
|
|||||||
sendModule(&module, client);
|
sendModule(&module, client);
|
||||||
if (client.Receive<int>() == FAIL) {
|
if (client.Receive<int>() == FAIL) {
|
||||||
throw DetectorError("Module " + std::to_string(moduleIndex) +
|
throw DetectorError("Module " + std::to_string(moduleIndex) +
|
||||||
" returned error: " + client.readErrorMessage());
|
" returned error: " + client.readErrorMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3465,12 +3469,12 @@ void Module::programFPGAviaBlackfin(std::vector<char> buffer) {
|
|||||||
throw DetectorError(os.str());
|
throw DetectorError(os.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// sending program in parts of 2mb each
|
// sending program in parts
|
||||||
uint64_t unitprogramsize = 0;
|
uint64_t unitprogramsize = 0;
|
||||||
int currentPointer = 0;
|
int currentPointer = 0;
|
||||||
while (filesize > 0) {
|
while (filesize > 0) {
|
||||||
unitprogramsize = MAX_FPGAPROGRAMSIZE; // 2mb
|
unitprogramsize = MAX_BLACKFIN_PROGRAM_SIZE;
|
||||||
if (unitprogramsize > filesize) { // less than 2mb
|
if (unitprogramsize > filesize) {
|
||||||
unitprogramsize = filesize;
|
unitprogramsize = filesize;
|
||||||
}
|
}
|
||||||
LOG(logDEBUG) << "unitprogramsize:" << unitprogramsize
|
LOG(logDEBUG) << "unitprogramsize:" << unitprogramsize
|
||||||
@ -3657,12 +3661,12 @@ void Module::updateKernelviaBlackfin(std::vector<char> buffer) {
|
|||||||
throw DetectorError(os.str());
|
throw DetectorError(os.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// sending program in parts of 2mb each
|
// sending program in parts
|
||||||
uint64_t unitprogramsize = 0;
|
uint64_t unitprogramsize = 0;
|
||||||
int currentPointer = 0;
|
int currentPointer = 0;
|
||||||
while (filesize > 0) {
|
while (filesize > 0) {
|
||||||
unitprogramsize = MAX_FPGAPROGRAMSIZE; // 2mb
|
unitprogramsize = MAX_BLACKFIN_PROGRAM_SIZE;
|
||||||
if (unitprogramsize > filesize) { // less than 2mb
|
if (unitprogramsize > filesize) {
|
||||||
unitprogramsize = filesize;
|
unitprogramsize = filesize;
|
||||||
}
|
}
|
||||||
LOG(logDEBUG) << "unitprogramsize:" << unitprogramsize
|
LOG(logDEBUG) << "unitprogramsize:" << unitprogramsize
|
||||||
|
@ -55,9 +55,8 @@
|
|||||||
/** maximum trim en */
|
/** maximum trim en */
|
||||||
#define MAX_TRIMEN 100
|
#define MAX_TRIMEN 100
|
||||||
|
|
||||||
/** maximum unit size of program sent to detector */
|
/** maximum unit size of program sent to blackfin */
|
||||||
//#define MAX_FPGAPROGRAMSIZE (2 * 1024 * 1024)
|
#define MAX_BLACKFIN_PROGRAM_SIZE (128 * 1024)
|
||||||
#define MAX_FPGAPROGRAMSIZE (128 * 1024)
|
|
||||||
|
|
||||||
#define GET_FLAG -1
|
#define GET_FLAG -1
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ enum detFuncs {
|
|||||||
F_GET_READOUT_SPEED,
|
F_GET_READOUT_SPEED,
|
||||||
F_SET_READOUT_SPEED,
|
F_SET_READOUT_SPEED,
|
||||||
F_GET_KERNEL_VERSION,
|
F_GET_KERNEL_VERSION,
|
||||||
F_COPY_KERNEL,
|
F_PROGRAM_KERNEL,
|
||||||
|
|
||||||
NUM_DET_FUNCTIONS,
|
NUM_DET_FUNCTIONS,
|
||||||
RECEIVER_ENUM_START = 256, /**< detector function should not exceed this
|
RECEIVER_ENUM_START = 256, /**< detector function should not exceed this
|
||||||
@ -611,7 +611,7 @@ const char* getFunctionNameFromEnum(enum detFuncs func) {
|
|||||||
case F_GET_READOUT_SPEED: return "F_GET_READOUT_SPEED";
|
case F_GET_READOUT_SPEED: return "F_GET_READOUT_SPEED";
|
||||||
case F_SET_READOUT_SPEED: return "F_SET_READOUT_SPEED";
|
case F_SET_READOUT_SPEED: return "F_SET_READOUT_SPEED";
|
||||||
case F_GET_KERNEL_VERSION: return "F_GET_KERNEL_VERSION";
|
case F_GET_KERNEL_VERSION: return "F_GET_KERNEL_VERSION";
|
||||||
case F_COPY_KERNEL: return "F_COPY_KERNEL";
|
case F_PROGRAM_KERNEL: return "F_PROGRAM_KERNEL";
|
||||||
|
|
||||||
case NUM_DET_FUNCTIONS: return "NUM_DET_FUNCTIONS";
|
case NUM_DET_FUNCTIONS: return "NUM_DET_FUNCTIONS";
|
||||||
case RECEIVER_ENUM_START: return "RECEIVER_ENUM_START";
|
case RECEIVER_ENUM_START: return "RECEIVER_ENUM_START";
|
||||||
|
Reference in New Issue
Block a user