changed the start and stop receiver error messages to be displayed to the client and not jsus recever

git-svn-id: file:///afs/psi.ch/project/sls_det_software/svn/slsDetectorSoftware@640 951219d9-93cf-4727-9268-0efd64621fa3
This commit is contained in:
l_maliakal_d 2013-07-30 14:49:53 +00:00
parent 500f83f0b4
commit 05f54e996c
8 changed files with 212 additions and 73 deletions

View File

@ -21,20 +21,24 @@ using namespace std;
#define NUM_ERROR_FLAGS 32 #define NUM_ERROR_FLAGS 32
#define CRITICAL_ERROR_MASK 0xFFFFFFFF #define CRITICAL_ERROR_MASK 0xFFFFFFFF
#define CANNOT_CONNECT_TO_DETECTOR 0x8000000000000000ULL #define CANNOT_CONNECT_TO_DETECTOR 0x8000000000000000ULL
#define CANNOT_CONNECT_TO_RECEIVER 0x4000000000000000ULL #define CANNOT_CONNECT_TO_RECEIVER 0x4000000000000000ULL
#define COULDNOT_SET_CONTROL_PORT 0x2000000000000000ULL #define COULDNOT_SET_CONTROL_PORT 0x2000000000000000ULL
#define COULDNOT_SET_STOP_PORT 0x1000000000000000ULL #define COULDNOT_SET_STOP_PORT 0x1000000000000000ULL
#define COULDNOT_SET_DATA_PORT 0x0800000000000000ULL #define COULDNOT_SET_DATA_PORT 0x0800000000000000ULL
#define FILE_PATH_DOES_NOT_EXIST 0x0400000000000000ULL
#define COULDNOT_CREATE_UDP_SOCKET 0x0200000000000000ULL
#define COULDNOT_CREATE_FILE 0x0100000000000000ULL
#define COULD_NOT_CONFIGURE_MAC 0x0000000000000001ULL #define COULD_NOT_CONFIGURE_MAC 0x0000000000000001ULL
#define COULDNOT_SET_NETWORK_PARAMETER 0x0000000000000002ULL #define COULDNOT_SET_NETWORK_PARAMETER 0x0000000000000002ULL
#define COULDNOT_SET_ROI 0x0000000000000004ULL #define COULDNOT_SET_ROI 0x0000000000000004ULL
#define FILE_PATH_DOES_NOT_EXIST 0x0000000000000008ULL #define RECEIVER_READ_FREQUENCY 0x0000000000000008ULL
#define RECEIVER_READ_FREQUENCY 0x0000000000000010ULL #define SETTINGS_NOT_SET 0x0000000000000010ULL
#define SETTINGS_NOT_SET 0x0000000000000020ULL #define COULDNOT_START_RECEIVER 0x0000000000000020ULL // default error like starting threads
#define COULDNOT_STOP_RECEIVER 0x0000000000000040ULL
/** @short class returning all error messages for error mask */ /** @short class returning all error messages for error mask */
class errorDefs { class errorDefs {
@ -68,6 +72,16 @@ public:
if(slsErrorMask&COULDNOT_SET_DATA_PORT) if(slsErrorMask&COULDNOT_SET_DATA_PORT)
retval.append("Could not set receiver port\n"); retval.append("Could not set receiver port\n");
if(slsErrorMask&FILE_PATH_DOES_NOT_EXIST)
retval.append("Path to Output Directory does not exist\n");
if(slsErrorMask&COULDNOT_CREATE_UDP_SOCKET)
retval.append("Could not create UDP socket to start receiver\n");
if(slsErrorMask&COULDNOT_CREATE_FILE)
retval.append("Could not create file to start receiver.\nCheck permissions of output directory\n");
if(slsErrorMask&COULD_NOT_CONFIGURE_MAC) if(slsErrorMask&COULD_NOT_CONFIGURE_MAC)
@ -79,15 +93,19 @@ public:
if(slsErrorMask&COULDNOT_SET_ROI) if(slsErrorMask&COULDNOT_SET_ROI)
retval.append("Could not set the exact region of interest. Verify ROI set by detector.\n"); retval.append("Could not set the exact region of interest. Verify ROI set by detector.\n");
if(slsErrorMask&FILE_PATH_DOES_NOT_EXIST)
retval.append("Path to Output Directory does not exist.\n");
if(slsErrorMask&RECEIVER_READ_FREQUENCY) if(slsErrorMask&RECEIVER_READ_FREQUENCY)
retval.append("Could not set receiver read frequency.\n"); retval.append("Could not set receiver read frequency.\n");
if(slsErrorMask&SETTINGS_NOT_SET) if(slsErrorMask&SETTINGS_NOT_SET)
retval.append("Could not set settings.\n"); retval.append("Could not set settings.\n");
if(slsErrorMask&COULDNOT_START_RECEIVER)
retval.append("Could not start receiver.\n");
if(slsErrorMask&COULDNOT_STOP_RECEIVER)
retval.append("Could not stop receiver.\n");
return retval; return retval;
} }

View File

@ -5938,15 +5938,24 @@ int slsDetector::setFileIndex(int i) {
int slsDetector::startReceiver(){ int slsDetector::startReceiver(){
int fnum=F_START_RECEIVER; int fnum=F_START_RECEIVER;
int ret = FAIL; int ret = FAIL;
char mess[MAX_STR_LENGTH] = "";
if (setReceiverOnline(ONLINE_FLAG)==ONLINE_FLAG) { if (setReceiverOnline(ONLINE_FLAG)==ONLINE_FLAG) {
#ifdef VERBOSE #ifdef VERBOSE
std::cout << "Starting Receiver " << std::endl; std::cout << "Starting Receiver " << std::endl;
#endif #endif
if (connectData() == OK) if (connectData() == OK)
ret=thisReceiver->executeFunction(fnum); ret=thisReceiver->executeFunction(fnum,mess);
if(ret==FORCE_UPDATE) if(ret==FORCE_UPDATE)
ret=updateReceiver(); ret=updateReceiver();
else if (ret == FAIL){
if(strstr(mess,"UDP")!=NULL)
setErrorMask((getErrorMask())|(COULDNOT_CREATE_UDP_SOCKET));
else if(strstr(mess,"file")!=NULL)
setErrorMask((getErrorMask())|(COULDNOT_CREATE_FILE));
else
setErrorMask((getErrorMask())|(COULDNOT_START_RECEIVER));
}
} }
if(ret==OK) if(ret==OK)
ret=detectorSendToReceiver(true); ret=detectorSendToReceiver(true);
@ -5960,6 +5969,7 @@ int slsDetector::startReceiver(){
int slsDetector::stopReceiver(){ int slsDetector::stopReceiver(){
int fnum=F_STOP_RECEIVER; int fnum=F_STOP_RECEIVER;
int ret = FAIL; int ret = FAIL;
char mess[] = "";
detectorSendToReceiver(false); detectorSendToReceiver(false);
@ -5968,9 +5978,11 @@ int slsDetector::stopReceiver(){
std::cout << "Stopping Receiver " << std::endl; std::cout << "Stopping Receiver " << std::endl;
#endif #endif
if (connectData() == OK) if (connectData() == OK)
ret=thisReceiver->executeFunction(fnum); ret=thisReceiver->executeFunction(fnum,mess);
if(ret==FORCE_UPDATE) if(ret==FORCE_UPDATE)
ret=updateReceiver(); ret=updateReceiver();
else if (ret == FAIL)
setErrorMask((getErrorMask())|(COULDNOT_STOP_RECEIVER));
} }
return ret; return ret;
@ -6080,13 +6092,14 @@ int slsDetector::getReceiverCurrentFrameIndex(){
int slsDetector::resetFramesCaught(){ int slsDetector::resetFramesCaught(){
int fnum=F_RESET_FRAMES_CAUGHT; int fnum=F_RESET_FRAMES_CAUGHT;
int ret = FAIL; int ret = FAIL;
char mess[] = "";
if (setReceiverOnline(ONLINE_FLAG)==ONLINE_FLAG) { if (setReceiverOnline(ONLINE_FLAG)==ONLINE_FLAG) {
#ifdef VERBOSE #ifdef VERBOSE
std::cout << "Reset Frames Caught by Receiver" << std::endl; std::cout << "Reset Frames Caught by Receiver" << std::endl;
#endif #endif
if (connectData() == OK) if (connectData() == OK)
ret=thisReceiver->executeFunction(fnum); ret=thisReceiver->executeFunction(fnum,mess);
if(ret==FORCE_UPDATE) if(ret==FORCE_UPDATE)
ret=updateReceiver(); ret=updateReceiver();
} }

View File

@ -266,8 +266,7 @@ void slsDetectorUtils::acquire(int delflag){
break; break;
} }
//start receiver //start receiver
startReceiver(); if((startReceiver() == FAIL) || (setReceiverOnline()==OFFLINE_FLAG)){
if(setReceiverOnline()==OFFLINE_FLAG){
stopReceiver(); stopReceiver();
pthread_mutex_unlock(&mg); pthread_mutex_unlock(&mg);
break; break;

View File

@ -21,7 +21,7 @@
using namespace std; using namespace std;
FILE* slsReceiverFunctionList::sfilefd(NULL); FILE* slsReceiverFunctionList::sfilefd(NULL);
int slsReceiverFunctionList::listening_thread_running(0); int slsReceiverFunctionList::receiver_threads_running(0);
slsReceiverFunctionList::slsReceiverFunctionList(detectorType det,bool moenchwithGotthardTest): slsReceiverFunctionList::slsReceiverFunctionList(detectorType det,bool moenchwithGotthardTest):
myDetectorType(det), myDetectorType(det),
@ -39,6 +39,8 @@ slsReceiverFunctionList::slsReceiverFunctionList(detectorType det,bool moenchwit
acquisitionIndex(0), acquisitionIndex(0),
framesInFile(0), framesInFile(0),
prevframenum(0), prevframenum(0),
listening_thread_running(0),
writing_thread_running(0),
status(IDLE), status(IDLE),
latestData(NULL), latestData(NULL),
udpSocket(NULL), udpSocket(NULL),
@ -106,6 +108,8 @@ slsReceiverFunctionList::slsReceiverFunctionList(detectorType det,bool moenchwit
if(withGotthard) if(withGotthard)
cout << "Testing MOENCH Receiver with GOTTHARD Detector" << endl; cout << "Testing MOENCH Receiver with GOTTHARD Detector" << endl;
pthread_mutex_init(&status_mutex,NULL);
} }
@ -200,52 +204,100 @@ void slsReceiverFunctionList::resetTotalFramesCaught(){
int slsReceiverFunctionList::startReceiver(){ int slsReceiverFunctionList::startReceiver(char message[]){
#ifdef VERBOSE #ifdef VERBOSE
cout << "Starting Receiver" << endl; cout << "Starting Receiver" << endl;
#endif #endif
cout << endl; cout << endl;
int err = 0; int err = 0;
if(!listening_thread_running){ if(!receiver_threads_running){
#ifdef VERBOSE #ifdef VERBOSE
cout << "Starting new acquisition threadddd ...." << endl; cout << "Starting new acquisition threadddd ...." << endl;
#endif #endif
listening_thread_running=1; //change status
while(1){
if(!pthread_mutex_trylock(&(status_mutex))){
status = IDLE;
listening_thread_running = 0;
writing_thread_running = 0;
receiver_threads_running = 1;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
// creating listening thread----------
err = pthread_create(&listening_thread, NULL,startListeningThread, (void*) this);
if(err){
//change status
while(1){
if(!pthread_mutex_trylock(&(status_mutex))){
status = IDLE;
listening_thread_running = 0;
receiver_threads_running = 0;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
sprintf(message,"Cant create listening thread. Status:%d\n",status);
cout << endl << message << endl;
return FAIL;
}
//wait till udp socket created
while(!listening_thread_running);
if(listening_thread_running!=1){
strcpy(message,"Could not create UDP Socket.\n");
return FAIL;
}
#ifdef VERBOSE
cout << "Listening thread created successfully." << endl;
#endif
// creating writing thread // creating writing thread----------
err = 0;
err = pthread_create(&writing_thread, NULL,startWritingThread, (void*) this); err = pthread_create(&writing_thread, NULL,startWritingThread, (void*) this);
if(err){ if(err){
listening_thread_running=0; //change status
status = IDLE; while(1){
cout << "Cant create writing thread. Status:" << status << endl << endl; if(!pthread_mutex_trylock(&(status_mutex))){
status = IDLE;
writing_thread_running = 0;
receiver_threads_running = 0;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
//stop listening thread
pthread_join(listening_thread,NULL);
sprintf(message,"Cant create writing thread. Status:%d\n",status);
cout << endl << message << endl;
return FAIL;
}
//wait till file is created
while(!writing_thread_running);
if(writing_thread_running!=1){
sprintf(message,"Could not create file %s.\n",savefilename);
return FAIL; return FAIL;
} }
#ifdef VERBOSE #ifdef VERBOSE
cout << "Writing thread created successfully." << endl; cout << "Writing thread created successfully." << endl;
#endif #endif
// creating listenign thread
err = 0; //change status----------
err = pthread_create(&listening_thread, NULL,startListeningThread, (void*) this); while(1){
if(err){ if(!pthread_mutex_trylock(&(status_mutex))){
listening_thread_running=0; status = RUNNING;
status = IDLE; pthread_mutex_unlock(&(status_mutex));
//stop writing thread break;
pthread_join(writing_thread,NULL); }
cout << endl << "Cant create listening thread. Status:" << status << endl << endl;
return FAIL;
} }
while(status!=RUNNING);
#ifdef VERBOSE
cout << "Listening thread created successfully." << endl;
#endif
cout << "Threads created successfully." << endl; cout << "Threads created successfully." << endl;
struct sched_param tcp_param, listen_param, write_param; struct sched_param tcp_param, listen_param, write_param;
int policy= SCHED_RR; int policy= SCHED_RR;
@ -280,22 +332,31 @@ int slsReceiverFunctionList::stopReceiver(){
cout << "Stopping Receiver" << endl; cout << "Stopping Receiver" << endl;
#endif #endif
if(listening_thread_running){ if(receiver_threads_running){
#ifdef VERBOSE #ifdef VERBOSE
cout << "Stopping new acquisition threadddd ...." << endl; cout << "Stopping new acquisition threadddd ...." << endl;
#endif #endif
//stop listening thread //stop listening thread
listening_thread_running=0; while(1){
if(!pthread_mutex_trylock(&(status_mutex))){
receiver_threads_running=0;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
if(udpSocket) udpSocket->ShutDownSocket(); if(udpSocket) udpSocket->ShutDownSocket();
pthread_join(listening_thread,NULL); pthread_join(listening_thread,NULL);
status = IDLE;
//stop writing thread
pthread_join(writing_thread,NULL); pthread_join(writing_thread,NULL);
} }
cout << "Receiver Stoppped.\nStatus:" << status << endl; //change status
while(1){
if(!pthread_mutex_trylock(&(status_mutex))){
status = IDLE;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
cout << "Receiver Stopped.\nStatus:" << status << endl;
return OK; return OK;
} }
@ -320,7 +381,6 @@ int slsReceiverFunctionList::startListening(){
#ifdef VERYVERBOSE #ifdef VERYVERBOSE
cout << "In startListening()\n"); cout << "In startListening()\n");
#endif #endif
int rc; int rc;
measurementStarted = false; measurementStarted = false;
@ -349,13 +409,26 @@ int slsReceiverFunctionList::startListening(){
#ifdef VERBOSE #ifdef VERBOSE
std::cout<< "Could not create UDP socket "<< server_port << std::endl; std::cout<< "Could not create UDP socket "<< server_port << std::endl;
#endif #endif
while(1){
if(!pthread_mutex_trylock(&(status_mutex))){
listening_thread_running = -1;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
break; break;
} }
while (listening_thread_running) { while (receiver_threads_running) {
status = RUNNING; while(1){
if(!pthread_mutex_trylock(&(status_mutex))){
listening_thread_running = 1;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
if (!fifofree->isEmpty()) { if (!fifofree->isEmpty()) {
fifofree->pop(buffer); fifofree->pop(buffer);
@ -388,7 +461,7 @@ int slsReceiverFunctionList::startListening(){
//so that it doesnt write the last frame twice //so that it doesnt write the last frame twice
if(listening_thread_running){ if(receiver_threads_running){
//s.assign(buffer); //s.assign(buffer);
if(fifo->isFull()) if(fifo->isFull())
;//cout<<"**********************FIFO FULLLLLLLL************************"<<endl; ;//cout<<"**********************FIFO FULLLLLLLL************************"<<endl;
@ -402,15 +475,21 @@ int slsReceiverFunctionList::startListening(){
} }
} }
} }
} while (listening_thread_running); } while (receiver_threads_running);
listening_thread_running=0; while(1){
status = IDLE; if(!pthread_mutex_trylock(&(status_mutex))){
receiver_threads_running=0;
status = IDLE;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
//Close down any open socket descriptors //Close down any open socket descriptors
udpSocket->Disconnect(); udpSocket->Disconnect();
#ifdef VERBOSE #ifdef VERBOSE
cout << "listening_thread_running:" << listening_thread_running << endl; cout << "receiver_threads_running:" << receiver_threads_running << endl;
#endif #endif
return 0; return 0;
@ -470,7 +549,7 @@ int slsReceiverFunctionList::startWriting(){
cout << "Ready!" << endl; cout << "Ready!" << endl;
while(listening_thread_running || (!fifo->isEmpty())){ while(receiver_threads_running || (!fifo->isEmpty())){
//start a new file //start a new file
if ((framesInFile == maxFramesPerFile) || (strlen(savefilename) == 0)){ if ((framesInFile == maxFramesPerFile) || (strlen(savefilename) == 0)){
@ -488,6 +567,13 @@ int slsReceiverFunctionList::startWriting(){
if (NULL == (sfilefd = fopen((const char *) (savefilename), "w"))){ if (NULL == (sfilefd = fopen((const char *) (savefilename), "w"))){
cout << "Error: Could not create file " << savefilename << endl; cout << "Error: Could not create file " << savefilename << endl;
while(1){
if(!pthread_mutex_trylock(&(status_mutex))){
writing_thread_running = -1;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
break; break;
} }
@ -512,6 +598,14 @@ int slsReceiverFunctionList::startWriting(){
} }
} }
while(1){
if(!pthread_mutex_trylock(&(status_mutex))){
writing_thread_running = 1;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
//if(prevframenum != 0){ //if(prevframenum != 0){
if(framesCaught){ if(framesCaught){
prevframenum = currframenum; prevframenum = currframenum;
@ -567,7 +661,7 @@ int slsReceiverFunctionList::startWriting(){
frameFactor = nFrameToGui-1; frameFactor = nFrameToGui-1;
//catch nth frame: gui ready to copy data //catch nth frame: gui ready to copy data
while(guiData==NULL){ while(guiData==NULL){
if(!listening_thread_running) if(!receiver_threads_running)
break; break;
usleep(10000); usleep(10000);
guiDataReady=0; guiDataReady=0;
@ -580,7 +674,7 @@ int slsReceiverFunctionList::startWriting(){
//catch nth frame: wait for gui to take data //catch nth frame: wait for gui to take data
while(guiData==latestData){ while(guiData==latestData){
if(!listening_thread_running) if(!receiver_threads_running)
break; break;
usleep(100000); usleep(100000);
} }
@ -598,7 +692,14 @@ int slsReceiverFunctionList::startWriting(){
usleep(50000); usleep(50000);
} }
} }
listening_thread_running = 0;
while(1){
if(!pthread_mutex_trylock(&(status_mutex))){
receiver_threads_running=0;
pthread_mutex_unlock(&(status_mutex));
break;
}
}
cout << "Total Frames Caught:"<< totalFramesCaught << endl; cout << "Total Frames Caught:"<< totalFramesCaught << endl;

View File

@ -144,9 +144,10 @@ public:
/** /**
* Starts Receiver - starts to listen for packets * Starts Receiver - starts to listen for packets
* @param message is the error message if there is an error
* Returns success * Returns success
*/ */
int startReceiver(); int startReceiver(char message[]);
/** /**
* Stops Receiver - stops listening for packets * Stops Receiver - stops listening for packets
@ -263,6 +264,15 @@ private:
/** thread writing packets */ /** thread writing packets */
pthread_t writing_thread; pthread_t writing_thread;
/** mutex for locking variable used by different threads */
pthread_mutex_t status_mutex;
/** listening thread running */
int listening_thread_running;
/** writing thread running */
int writing_thread_running;
/** status of receiver */ /** status of receiver */
runStatus status; runStatus status;
@ -383,8 +393,8 @@ public:
/** File Descriptor */ /** File Descriptor */
static FILE *sfilefd; static FILE *sfilefd;
/** if the listening thread is running*/ /** if the receiver threads are running*/
static int listening_thread_running; static int receiver_threads_running;
/** /**

View File

@ -30,12 +30,12 @@ slsReceiverFuncs::~slsReceiverFuncs() {
slsReceiverFuncs::slsReceiverFuncs(int argc, char *argv[], int &success): slsReceiverFuncs::slsReceiverFuncs(int argc, char *argv[], int &success):
myDetectorType(GOTTHARD), myDetectorType(GOTTHARD),
socket(NULL),
ret(OK), ret(OK),
lockStatus(0), lockStatus(0),
shortFrame(-1), shortFrame(-1),
packetsPerFrame(GOTTHARD_PACKETS_PER_FRAME), packetsPerFrame(GOTTHARD_PACKETS_PER_FRAME),
withGotthard(0){ withGotthard(0),
socket(NULL){
int port_no = DEFAULT_PORTNO+2; int port_no = DEFAULT_PORTNO+2;
ifstream infile; ifstream infile;
@ -348,7 +348,7 @@ int slsReceiverFuncs::M_nofunc(){
void slsReceiverFuncs::closeFile(int p){ void slsReceiverFuncs::closeFile(int p){
if(slsReceiverFunctionList::listening_thread_running) if(slsReceiverFunctionList::receiver_threads_running)
fclose(slsReceiverFunctionList::sfilefd); fclose(slsReceiverFunctionList::sfilefd);
@ -670,7 +670,6 @@ int slsReceiverFuncs::setup_udp(){
int slsReceiverFuncs::start_receiver(){ int slsReceiverFuncs::start_receiver(){
ret=OK; ret=OK;
strcpy(mess,"Could not start receiver\n"); strcpy(mess,"Could not start receiver\n");
// execute action if the arguments correctly arrived // execute action if the arguments correctly arrived
@ -686,7 +685,7 @@ int slsReceiverFuncs::start_receiver(){
} }
*/ */
else if(slsReceiverList->getStatus()!=RUNNING) else if(slsReceiverList->getStatus()!=RUNNING)
ret=slsReceiverList->startReceiver(); ret=slsReceiverList->startReceiver(mess);
#endif #endif
if(ret==OK && socket->differentClients){ if(ret==OK && socket->differentClients){

View File

@ -117,15 +117,13 @@ int receiverInterface::getLastClientIP(int fnum, char retval[]){
int receiverInterface::executeFunction(int fnum){ int receiverInterface::executeFunction(int fnum,char mess[]){
int ret = slsDetectorDefs::FAIL; int ret = slsDetectorDefs::FAIL;
char mess[100] = "";
dataSocket->SendDataOnly(&fnum,sizeof(fnum)); dataSocket->SendDataOnly(&fnum,sizeof(fnum));
dataSocket->ReceiveDataOnly(&ret,sizeof(ret)); dataSocket->ReceiveDataOnly(&ret,sizeof(ret));
if (ret==slsDetectorDefs::FAIL){ if (ret==slsDetectorDefs::FAIL){
dataSocket->ReceiveDataOnly(mess,sizeof(mess)); dataSocket->ReceiveDataOnly(mess,MAX_STR_LENGTH);
std::cout<< "Receiver returned error: " << mess << std::endl; std::cout<< "Receiver returned error: " << mess << std::endl;
} }
dataSocket->Disconnect(); dataSocket->Disconnect();

View File

@ -97,9 +97,10 @@ public:
/** /**
* Send a function number to execute function * Send a function number to execute function
* @param fnum function enum to determine which function to execute * @param fnum function enum to determine which function to execute
* @param mess return error message
* \returns success of operation * \returns success of operation
*/ */
int executeFunction(int fnum); int executeFunction(int fnum,char mess[]);
//here one should implement the funcs listed in //here one should implement the funcs listed in