+++ /dev/null
-#include <cstdio>
-#include <cstring>
-#include <csignal>
-#include <unistd.h>
-#include <stdio.h>
-#include <math.h>
-#include <iostream>
-#include <fstream>
-#include <vector>
-#include <chrono>
-#include <array>
-#include <sys/stat.h>
-
-//Necessary for readout handler
-#include "hadaq/api.h"
-
-//Necessary to control mimosis and trbnet
-#include "trbnet.h"
-
-//Necessary for mimosis specific functions
-#include "mimosis.hpp"
-
-#define FPGA 0xa000
-
-#define VPHFINE 0x0046
-
-#define SUPERINDEX(x,y,s) ((y*1024+x)*256+s)
-
-using namespace std::chrono;
-
-//Enum to make access to the information vector more clear
-enum params {
- STATE,
- YSTA,
- YEND,
- YTRA,
- XLOW,
- XHIG,
- VPHSTA,
- VPHEND,
- VPHSTEP,
- COUNTS,
- MOD,
- REGION,
- VCASN,
- SINGLEACCESS
-};
-
-
-//Collection of data related variables used throughout the programm.
-namespace Data
-{
- std::string source;
- //Main data array holds counts of pulses for every pixel and VPH_FINE
- std::array<unsigned,1024*504*256> dataArray;
-
- //Current state of the programm.
- std::string state;
-
- //Boundaries within pulses were done
- int yLowMax = 503, yHigMax = 0, xLowMax = 1023, xHigMax = 0;
-
- //Directory where data and METADATA will be put.
- std::string dataDir;
-
- //Keep track of VCASN to put in METADATA later.
- std::vector<std::string> vcasnVec;
-
- bool singleAccess = true;
- //Measure time of execution of the programm and put
- //information in METADATA
- decltype(high_resolution_clock::now()) start;
-};
-
-
-
-namespace Stats
-{
- int totalFrames = 0;
- int totalFramesSkipped = 0;
-};
-
-
-//Name of PID file.
-const std::string pidName = "/tmp/hldprint-pid";
-
-
-
-void mimosis_sec_write(uint16_t fpga, uint16_t reg, uint16_t data, bool sa)
-{
- uint16_t readVal = mimosis::register_read( fpga, reg, sa);
-
- int cnt = 0;
-
- while (readVal!= data)
- {
- mimosis::register_write( fpga, reg, data, sa );
- readVal = mimosis::register_read( fpga, reg, sa );
-
- cnt++;
-
- if(cnt >= 1000)
- {
- std::printf("Cannot write 0x%04x to 0x%04x.\nExiting.\n",data, reg);
- std::exit(-1);
- break;
- }
- }
-}
-
-
-
-//Write PID to PID-file
-void write_pid(void)
-{
- int pid = (int)getpid();
-
- FILE *pidFile = fopen(pidName.c_str(), "w");
-
- if(pidFile == nullptr) {
- std::printf("ERROR: Couldn't open file.\n");
- std::exit(-1);
- }
-
- fprintf(pidFile, "%d",pid);
-
- fclose(pidFile);
-}
-
-
-
-//Open a pipe and wait for commands and informations
-//from controller script
-std::vector<std::string> await_params()
-{
- //Receiving pipe for informations from controller
- std::string pipeName = "/tmp/scurveipipe";
-
- FILE *iPipe = fopen(pipeName.c_str(), "r");
-
- if(iPipe == nullptr) {
- std::printf("ERROR: Couldn't open file.\n");
- std::exit(-1);
- }
-
-
- //Read from pipe char by char until full frame is reached.
- //Frames start with START and end with END.
- //Information is delimited by '-' characters.
- int buf;
- bool foundFrame = false, foundSta = false, foundEnd = false;
- std::string word;
-
- //Staore all informations, without START and END, in values vector.
- std::vector<std::string> values;
-
- buf = fgetc(iPipe);
-
- while(!foundFrame && buf != EOF)
- {
- char c = static_cast<char>(buf);
-
- if(c == '-') {
- values.push_back(word);
- word = "";
- } else {
- word += c;
- }
-
- if(word == "START") { foundSta = true; }
- if(word == "END") { foundEnd = true; }
-
- buf = fgetc(iPipe);
-
- if(foundSta && foundEnd) {
- foundFrame = true;
- break;
- }
- }
-
- //Delete "START" from first position
- values.erase(values.begin());
-
- // for (const auto& i: values)
- // std::cout << i << '\n';
-
- fclose(iPipe);
-
- //Return the whole array.
- return values;
-}
-
-
-
-//Open a pipe to transmit an acknowledgement to the
-//controller script
-int send_ack()
-{
- //Transmitting pipe to acknowledge receiving and processing of informations
- //A simple 'ACK' indicates the controller successful operation
- std::string pipeName = "/tmp/scurveapipe";
-
- FILE *iPipe = fopen(pipeName.c_str(), "w");
-
- if(iPipe == nullptr) {
- std::printf("ERROR: Couldn't open file.\n");
- std::exit(-1);
- }
-
- std::string msg("ACK");
- fputs(msg.c_str(),iPipe);
- fclose(iPipe);
- return 0;
-}
-
-
-
-//Writing contents of Data::dataArr to file.
-void write_data(std::string reg, std::string vcasn)
-{
- //For each VCASN a new sub dir is created and a csv file with
- //the same name holds the data.
- std::string subDir = Data::dataDir + "/" + reg + "-" + vcasn;
-
- mkdir(subDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
-
- std::string fileName = subDir + "/" + reg + "-" + vcasn + ".csv";
-
- //Buffered ofstream increases performance.
- //One could also dump the whole array as binary file, but this complicates
- //Post processing a bit.
- //Another option would be to include root and use TTree's.
- std::ofstream file(fileName);
- char buffer[1000000];
- file.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
-
- // std::printf("%d %d %d %d\n", Data::yLowMax, Data::yHigMax, Data::xLowMax, Data::xHigMax);
-
- //Only write relevant data between boundaries of scan.
- for(int y = Data::yLowMax; y <= Data::yHigMax; y++) {
-
- for(int x = Data::xLowMax; x <= Data::xHigMax; x++) {
-
- for(int s = 0; s <= 255; s++) {
-
- auto v = Data::dataArray[SUPERINDEX(x,y,s)];
-
- file << v << '\t';
- // file << s << '\t';
-
- //Reset data to 0
- Data::dataArray[SUPERINDEX(x,y,s)] = 0;
- }
- file << '\n';
- }
- }
- file.close();
-}
-
-
-
-//Decodeing of mimosis words into pixels
-void decode_pixel(const uint32_t& word, unsigned int& column, unsigned int& row, unsigned int& region)
-{
- unsigned int pixelcode = (word >> 6) & 0x3ff;
-
- unsigned int side = 0, topdown = 0;
-
- if((pixelcode&3) == 0x1 || (pixelcode&3) == 0x2) side = 1;
- if((pixelcode&3) == 0x3 || (pixelcode&3) == 0x2) topdown = 1;
-
- row = (pixelcode>>2)*2 + topdown;
- column = (((word>>3)&0x7) + region*8)*2 + side;
-}
-
-
-
-//Main data taking procedure.
-void loop_vph(
- int yLow, int yHig,
- int xLow, int xHig,
- int vphSta, int vphEnd, int vphTra,
- int maxCounts, int mod, int exp)
-{
-#ifdef DEBUG
- std::printf("loop_vph(): yLow(%4d) yHig(%4d) xLow(%4d) xHig(%4d) vphSta(%4d) vphEnd(%4d) vphTra(%4d) maxCounts(%4d) mod(%8d)\n",
- yLow,yHig,xLow,xHig,vphSta,vphEnd,vphTra,maxCounts,mod);
-#endif
-
- int pulse = static_cast<int>(std::pow(2.0,static_cast<double>(exp)));
-
- hadaq::ReadoutHandle ref = hadaq::ReadoutHandle::Connect(Data::source.c_str());
- if (ref.null()) return;
- hadaq::RawEvent *evnt = nullptr;
-
- for(int vphfine = vphSta;
- vphfine <= vphEnd;
- vphfine += vphTra)
- // for(int vphfine = vphSta;
- // vphfine <= vphEnd;
- // vphfine++)
- {
- std::printf("Scan: %3d\r",vphfine);
- fflush(stdout);
-
- //Set VPH_FINE
- mimosis_sec_write( FPGA, VPHFINE, vphfine, Data::singleAccess );
-
- auto start = high_resolution_clock::now();
- auto stop = high_resolution_clock::now();
- auto duration = duration_cast<microseconds>(stop-start);
-
- for(int mimTra = 0;
- mimTra<maxCounts;
- mimTra++)
- {
- evnt = ref.NextEvent(1.,-1);
- if (!evnt) continue;
-
- hadaq::RawSubevent* sub = nullptr;
-
- while ((sub = evnt->NextSubevent(sub)) != nullptr)
- {
- unsigned size = sub->GetNrOfDataWords();
-
- int headerNow = 0;
-
- uint32_t mimFraCnt;
-
- unsigned region = 0, column = 0, row = 0;
-
- for( unsigned i = 0; i<size; i++)
- {
- uint32_t data = static_cast<uint32_t>(sub->Data(i));
-
- if((data & 0xFF000000) == 0xFE000000) {
-
- ++headerNow;
-
- if(headerNow == 1) {
-
- mimFraCnt = (data & 0xFF0000) >> 16;
- mimFraCnt += (data & 0xFF) << 8;
-
- } else if(headerNow == 2) {
-
- mimFraCnt += data & 0xFF0000;
- mimFraCnt += (data & 0xFF) << 24;
-
- } else if(headerNow == 3) {
- } else if(headerNow == 4) {
- }
-
- } else if((data & 0xFF000000) == 0xFF000000) {
-
- headerNow = 0;
- mimTra++;
-
- } else {
-
- if( (data & 0xFF000000) == 0xFD000000 ) {
-
- int tmp = (data>>16) & 0xFF;
- if(tmp > 63) continue;
- region = tmp;
-
- } else {
-
- decode_pixel(data>>16,column,row,region);
-
- if(column >= xLow &&
- column <= xHig &&
- row >= yLow &&
- row < yHig &&
- mimFraCnt%pulse == mod) {
-
- // if (vphfine%vphTra == 0)
- Data::dataArray[SUPERINDEX(column,row,vphfine)] += 1;
- }
- }
-
- if((data & 0x0000FF00) != 0x0000FC00) {
-
- decode_pixel(data&0xFFFF,column,row,region);
-
- if(column >= xLow &&
- column <= xHig &&
- row >= yLow &&
- row < yHig &&
- mimFraCnt%pulse == mod) {
-
- // if (vphfine%vphTra == 0)
- Data::dataArray[SUPERINDEX(column,row,vphfine)] += 1;
- }
- }
- }
-
- if(mimTra >= maxCounts) {
- goto MAXCOUNTS;
- }
-
- } // End loop over data in sub event
- } // End loop over sub-events in event
- } //End while duration
- MAXCOUNTS:
- ;
- }
- std::printf("\n");
- ref.Disconnect();
-}
-
-
-
-int find_mod(
- int yLow, int yHig,
- int xLow, int xHig,
- int modPulse)
-{
- int pulse = static_cast<int>(std::pow(2.0,static_cast<double>(modPulse)));
-
- int modFound = -1;
-
- const int modN = 2;
- std::vector<int> modVec(modN);
- for(auto& i: modVec) { i = -1; }
- int modInd = 0;
- int modX = -1,modY = -1;
-
- //Set VPH_FINE to smth high, so pulses get visible
- mimosis_sec_write( FPGA, VPHFINE, 0xff, Data::singleAccess );
-
- hadaq::ReadoutHandle ref = hadaq::ReadoutHandle::Connect(Data::source.c_str());
- if (ref.null()) return -2;
- hadaq::RawEvent *evnt = nullptr;
-
- uint32_t lastMimFraCnt;
-
- while(modFound == -1)
- {
- while(true)
- {
- evnt = ref.NextEvent(1.,-1);
- if (!evnt) continue;
-
- hadaq::RawSubevent* sub = nullptr;
-
- while ((sub = evnt->NextSubevent(sub)) != nullptr)
- {
- unsigned size = sub->GetNrOfDataWords();
- int headerNow = 0;
- uint32_t mimFraCnt;
- unsigned region = 0, column = 0, row = 0;
-
- for( unsigned i = 0; i<size; i++)
- {
- uint32_t data = static_cast<uint32_t>(sub->Data(i));
-
- if((data & 0xFF000000) == 0xFE000000) {
-
- ++headerNow;
-
- if(headerNow == 1) {
-
- mimFraCnt = (data & 0xFF0000) >> 16;
- mimFraCnt += (data & 0xFF) << 8;
-
- } else if(headerNow == 2) {
-
- mimFraCnt += data & 0xFF0000;
- mimFraCnt += (data & 0xFF) << 24;
-
- } else if(headerNow == 3) {
- } else if(headerNow == 4) {
- }
-
- } else if((data & 0xFF000000) == 0xFF000000) {
-
- headerNow = 0;
-
- } else {
-
- if( (data & 0xFF000000) == 0xFD000000 ) {
-
- int tmp = (data>>16) & 0xFF;
- if(tmp > 63) continue;
- region = tmp;
-
- } else {
-
- decode_pixel(data>>16,column,row,region);
-
- if(column >= xLow &&
- column <= xHig &&
- row >= yLow &&
- row < yHig &&
- lastMimFraCnt != mimFraCnt &&
- modInd < modN &&
- (row == modY || modY == -1) &&
- (column == modX || modX == -1)) {
-
- modY = row;
- modX = column;
-
- modVec[modInd] = mimFraCnt%pulse;
-
- modInd++;
-
- lastMimFraCnt = mimFraCnt;
-
- if(modInd == modN) { goto EVALMODS; }
- }
- }
-
- if((data & 0x0000FF00) != 0x0000FC00) {
-
- decode_pixel(data&0xFFFF,column,row,region);
-
- if(column >= xLow &&
- column <= xHig &&
- row >= yLow &&
- row < yHig &&
- lastMimFraCnt != mimFraCnt &&
- modInd < modN &&
- (row == modY || modY == -1) &&
- (column == modX || modX == -1)) {
-
- modY = row;
- modX = column;
-
- modVec[modInd] = mimFraCnt%pulse;
-
- modInd++;
-
- lastMimFraCnt = mimFraCnt;
-
- if(modInd == modN) { goto EVALMODS; }
- }
- }
- }
- } // End loop over data in sub event
- } // End loop over sub-events in event
- }
-
- EVALMODS:
-
- int firstMod = modVec[0];
- int wrongMods = 0;
-
- for(int i = 1; i < modN; i++) {
- if(modVec[i] != firstMod) {
- wrongMods++;
- }
- }
-
- if(wrongMods > 0) {
- modInd = 0;
- continue;
- } else if(wrongMods == 0) {
- modFound = firstMod;
- break;
- }
- } //End while mod not found
-
- ref.Disconnect();
- return modFound;
-}
-
-
-
-void loop_rows(
- int ySta, int yEnd, int yTra,
- int xSta, int xEnd,
- int vphSta, int vphEnd, int vphTra,
- int maxCounts, int exp)
-{
-#ifdef DEBUG
- std::printf("loop_rows(): ySta(%4d) yEnd(%4d) yTra(%4d) xSta(%4d) xEnd(%4d) vphSta(%4d) vphEnd(%4d) vphTra(%4d) maxCounts(%8d) exp(%4d)\n",
- ySta,yEnd,yTra,xSta,xEnd,vphSta,vphEnd,vphTra,maxCounts,exp);
-#endif
-
- for(int yOff = ySta;
- yOff <= yEnd;
- yOff += yTra)
- {
- std::printf("Mark pixels: %d - %d, %d - %d\n", yOff, yOff+yTra-1, xSta, xEnd);
-
- int y = yOff;
-
- //Mark pixels for pulsing
- for(; y < yOff + yTra && y <= yEnd; y++)
- {
- Data::yLowMax = y < Data::yLowMax ? y : Data::yLowMax;
- Data::yHigMax = y > Data::yHigMax ? y : Data::yHigMax;
-
- int regAddY = y/8;
- int regBitY = (1<<(y%8));
- int regWordY = (regAddY<<8)+0x84;
-
- mimosis_sec_write(FPGA, regWordY, regBitY, Data::singleAccess );
-
- int regAddX;
- int regBitX;
-
- int currRegX = xSta/16;
-
- int word82 = 0;
- int word81 = 0;
-
- for (int x = xSta; x <= xEnd; x++)
- {
- Data::xLowMax = x < Data::xLowMax ? x : Data::xLowMax;
- Data::xHigMax = x > Data::xHigMax ? x : Data::xHigMax;
-
- if((x/16) == currRegX &&
- x != xEnd) {
-
- if (x%2 == 1) { word82 |= (1<<((x/2)%8)); }
- else if (x%2 == 0) { word81 |= (1<<((x/2)%8)); }
-
- } else {
-
- if(word82 == word81) {
-
- int addr = (currRegX<<8) + 0x83;
- mimosis_sec_write( FPGA, addr, word81, Data::singleAccess );
- mimosis::instr_write( FPGA, 0x05 );
- mimosis_sec_write( FPGA, addr, 0, Data::singleAccess );
-
- } else {
- int addr81 = (currRegX<<8) + 0x81;
- int addr82 = (currRegX<<8) + 0x82;
- mimosis_sec_write( FPGA, addr81, word81, Data::singleAccess );
- mimosis_sec_write( FPGA, addr82, word82, Data::singleAccess );
- mimosis::instr_write( FPGA, 0x05 );
- mimosis_sec_write( FPGA, addr81, 0, Data::singleAccess );
- mimosis_sec_write( FPGA, addr82, 0, Data::singleAccess );
- }
- currRegX = x/16;
-
- word81 = 0;
- word82 = 0;
-
- if (x%2 == 1) { word82 = (1<<((x/2)%8)); }
- else if (x%2 == 0) { word81 = (1<<((x/2)%8)); }
- }
- }
- mimosis_sec_write(FPGA, regWordY, 0x0, Data::singleAccess );
- }
-
- int mod = find_mod(yOff, y, xSta, xEnd, exp);
-
- mimosis_sec_write( FPGA, VPHFINE, 0, Data::singleAccess );
- sleep(1);
-
- loop_vph(yOff, y, xSta, xEnd, vphSta, vphEnd, vphTra, maxCounts, mod, exp);
-
- mimosis::instr_write( FPGA, 0x3f );
- mimosis::instr_write( FPGA, 0x04 );
- mimosis::instr_write( FPGA, 0x3e );
-
- //Set VPH_FINE back to zero, to get rid of peak at begining of scan
- //Do it double, to be sure
- mimosis_sec_write( FPGA, VPHFINE, 0, Data::singleAccess );
- }
-}
-
-
-
-//Write the METADATA file and put into dataDir.
-void write_meta()
-{
- std::string fileName = Data::dataDir + "/METADATA";
-
- std::ofstream file(fileName);
-
- file << "START:" << '\t' << Data::dataDir << '\n';
-
- file << "VCASN:";
- for(const auto& i: Data::vcasnVec) {
- file << '\t' << i;
- }
- file << '\n';
-
- file << "YMIN:" << '\t' << Data::yLowMax << '\n';
- file << "YMAX:" << '\t' << Data::yHigMax << '\n';
- file << "XMIN:" << '\t' << Data::xLowMax << '\n';
- file << "XMAX:" << '\t' << Data::xHigMax << '\n';
-
- file << "EXITSTATE:" << '\t' << Data::state << '\n';
-
- auto stop = high_resolution_clock::now();
- auto duration = duration_cast<seconds>(stop - Data::start);
- file << "TIME(s):" << '\t' << duration.count() << '\n';
-
- file << "COMMENT:\t<insert comment here>\n";
-
- file.close();
-}
-
-
-
-//Signal handler for clean exit at CTRL-C.
-//Data will be dumped and marked with 'INTERRUPTED',
-//if current state was a data taking state.
-void signal_handler( int signum )
-{
- std::cout << "Interrupt signal (" << signum << ") received Cleaning up...\n";
-
- if(Data::state == "TAKEDATA" ||
- Data::state == "WAITDAQ" ||
- Data::state == "FIT") {
-
- std::string lastReg = "INTERRUPTED";
- std::string lastVca = "INTERRUPTED";
- write_data(lastReg, lastVca);
- std::cout << "Remining data indicated by INTERRUPTED flags.\n";
-
- } else {
- }
-
- //Set VPH_FINE back to zero, to get rid of peak at begining of scan
- //Do it double, to be sure
- mimosis_sec_write( FPGA, VPHFINE, 0, Data::singleAccess );
-
- //Remove pid file
- remove(pidName.c_str());
-
- write_meta();
-
- std::exit(signum);
-}
-
-
-
-//main. Make initialization and then enter main loop.
-int main(int argc, char* argv[])
-{
- //Read stream url
- Data::source = argv[1];
-
-
- //Initialize trbnet for this run
- int trbnetState = init_ports();
-
-
- //Start clock to report execution time METADATA
- Data::start = high_resolution_clock::now();
-
-
- //Generate the PID file
- write_pid();
-
-
- //Register signal SIGINT and signal handler
- signal(SIGINT, signal_handler);
-
-
- //Declare stateVec, that will hold the
- //informations passed from control script
- std::vector<std::string> stateVec;
-
-
- //Create main data dir by time stamp
- std::time_t time = std::time(0);
- std::tm* now = std::localtime(&time);
-
- Data::dataDir = std::to_string(now->tm_year + 1900) + '-'
- + std::to_string(now->tm_mon + 1) + '-'
- + std::to_string(now->tm_mday) + '-'
- + std::to_string(now->tm_hour) + '-'
- + std::to_string(now->tm_min);
-
- mkdir(Data::dataDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
-
-
- //Initialize data array with 0's
- for(int y = 0; y < 504; y++)
- for(int x = 0; x < 1024; x++)
- for(int s = 0; s < 256; s++)
- Data::dataArray[SUPERINDEX(x,y,s)] = 0;
-
-
- //Main control loop. After init phase,
- //wait for commands from control script
- AWAIT:
- stateVec = await_params();
- Data::state = stateVec[STATE];
- Data::singleAccess = stateVec[SINGLEACCESS] == "1";
-
- if(Data::state == "TAKEDATA") {
-
- loop_rows(
- std::stoi(stateVec[YSTA], nullptr, 10),
- std::stoi(stateVec[YEND], nullptr, 10),
- std::stoi(stateVec[YTRA], nullptr, 10),
- std::stoi(stateVec[XLOW], nullptr, 10),
- std::stoi(stateVec[XHIG], nullptr, 10),
- std::stoi(stateVec[VPHSTA], nullptr, 10),
- std::stoi(stateVec[VPHEND], nullptr, 10),
- std::stoi(stateVec[VPHSTEP], nullptr, 10),
- std::stoi(stateVec[COUNTS], nullptr, 10),
- std::stoi(stateVec[MOD], nullptr, 10)
- );
-
- send_ack();
-
- goto AWAIT;
-
- } else if(Data::state == "FIT") {
-
- std::string regStr = stateVec[REGION];
- std::string vcaStr = stateVec[VCASN];
-
- Data::vcasnVec.push_back(vcaStr);
- std::printf("Write data: %s %s\n",regStr.c_str(),vcaStr.c_str());
-
- write_data(regStr,vcaStr);
- send_ack();
-
- goto AWAIT;
-
- } else if(Data::state == "DONE") {
-
- std::printf("Done.\n");
- send_ack();
-
- remove(pidName.c_str());
-
- write_meta();
-
- return 0;
-
- } else {
-
- //Never happend so far, but just in case,
- //exit cleanly and remove pid file
- std::printf("Received garbage. Exiting.\n");
-
- remove(pidName.c_str());
-
- return 1;
- }
-}