diff --git a/.gitignore b/.gitignore index c8be16b4225c6bbee92ca0d14efb0aaae292fdf0..2406d259a56d492b3383791c547696589ad7347b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,9 @@ -test_data/test.csv \ No newline at end of file +# CMakeLists.txt +# main.cpp +test_data/test.csv +# sources/CMakeLists.txt +sources/py_BinFileParser.cpp +sources/py_BinFileParser.pyi +sources/py_BinFileParser.pyx +build/ +*.so \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..461face28aee72a98aa799455b9fa871241e3ff4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.16.3) + +project(BinParser CXX) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/sources) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) +endif () +message(STATUS "Build type: '${CMAKE_BUILD_TYPE}'") + +add_subdirectory(sources) + +add_executable(main main.cpp) +target_link_libraries(main PUBLIC binFileParser) \ No newline at end of file diff --git a/DT550WBinFileParser.py b/DT550WBinFileParser.py deleted file mode 100644 index 588b36d7109cb929d4125fa815a655555fac1009..0000000000000000000000000000000000000000 --- a/DT550WBinFileParser.py +++ /dev/null @@ -1,153 +0,0 @@ -''' -Description: DT5550W binary data parser -Author: Ming Fang -Date: 2022-09-02 15:55:20 -LastEditors: Ming Fang mingf2@illinois.edu -LastEditTime: 2022-09-02 21:09:40 -''' -from pathlib import Path -import numpy as np - - -class CITIROCEvent: - def __init__(self, buffer, FW_USE_VALIDATION: bool) -> None: - self._decodeBuffer(buffer, FW_USE_VALIDATION) - - def _decodeBuffer(self, buffer, FW_USE_VALIDATION: bool) -> None: - t = 0 - self._AsicID = (np.frombuffer(buffer[t] & 0xF, dtype=np.uint16))[0] - # self._EventTimeCode = (np.frombuffer(buffer[t+1], dtype=np.uint64))[0] - self._RunEventTimeCode = (np.frombuffer(buffer[t+2:t+4], dtype=np.uint64))[0] - self._EventCounter = (np.frombuffer(buffer[t+4], dtype=np.uint32))[0] - # self._EventTimeCode_ns = 8 * self._EventTimeCode - self._RunEventTimeCode_ns = self._RunEventTimeCode * 0.5 - t += 5 - - self._chargeLG = np.zeros(32, dtype=np.uint16) - self._chargeHG = np.zeros(32, dtype=np.uint16) - self._hit = np.zeros(32, dtype=np.bool8) - for i in range(32): - self._chargeHG[31-i] = (np.frombuffer(buffer[t] & 0x3FFF, dtype=np.uint16))[0] - self._chargeLG[31-i] = (np.frombuffer((buffer[t] >> 14) & 0x3FFF, dtype=np.uint16))[0] - self._hit[31-i] = (np.frombuffer((buffer[t] >> 28) & 0x1, dtype=np.bool8))[0] - t += 1 - if FW_USE_VALIDATION: - t += 3 - - assert (buffer[t] & 0xc0000000) == 0xc0000000, "Error in data parsing." - - @property - def ASICID(self): - return self._AsicID - - @property - def Hit(self): - return self._hit - - @property - def EventCounter(self): - return self._EventCounter - - @property - def chargeLG(self): - return self._chargeLG - - @property - def chargeHG(self): - return self._chargeHG - - @property - def TimeStamp(self): - return self._RunEventTimeCode_ns - - -class DT5550WBinFile: - """Paser for DT5550W binary file. - """ - def __init__(self, p, FW_USE_VALIDATION: bool=True) -> None: - """Initialize with input file path and firmware version. - - Args: - p (str | Path): Path to the binary data file saved by DT5550W. - FW_USE_VALIDATION (bool): True for Firmware and software > 2021.12.6, false otherwise. Default is true. - - Raises: - ValueError: If input file is not accessible. - """ - self._FW_USE_VALIDATION = FW_USE_VALIDATION - self._filePath = Path(p) # file path - if not self._filePath.is_file(): - raise ValueError(f"{str(p)} is not accessible.") - - self._fileObject = open(self._filePath, 'rb') # data file object - self._eventSize = 152 # event size in bytes - if self._FW_USE_VALIDATION: - self._eventSize += 12 - # discard garbage data at the beginning of the file - self._discardGarbageData() - - self._numberOfEvents = int((self._filePath.stat().st_size - self._fileObject.tell()) / self._eventSize) # total number of events in the file - - self._numberOfEventsUnread = self._numberOfEvents # number of events that have not been read - - def _discardGarbageData(self): - while True: - buffer = int.from_bytes(self._fileObject.read(4), 'little') - if ((buffer >> 4) & 0xc000000) == 0x8000000: - self._fileObject.seek(-4, 1) - break - - def skipNextEvent(self): - """Skip the next event. - """ - if self._numberOfEventsUnread > 0: - self._fileObject.seek(self._eventSize, 1) - self._numberOfEventsUnread -= 1 - - def readNextEvent(self): - if self._numberOfEventsUnread > 0: - self._discardGarbageData() - buffer = np.frombuffer(self._fileObject.read(self._eventSize), dtype=np.uint32) - self._numberOfEventsUnread -= 1 - return CITIROCEvent(buffer, self._FW_USE_VALIDATION) - else: - return None - - def readNextNEvents(self, num:int): - events = [] - for _ in range(num): - if self._numberOfEventsUnread > 0: - self._discardGarbageData() - buffer = np.frombuffer(self._fileObject.read(self._eventSize), dtype=np.uint32) - self._numberOfEventsUnread -= 1 - events.append(CITIROCEvent(buffer, self._FW_USE_VALIDATION)) - else: - break - return events - - def rewind(self): - """Go to the begnning of the file. - """ - self._fileObject.seek(0) - self._numberOfEventsUnread = self._numberOfEvents - - @property - def totalNumberOfEvents(self): - """The total number of events recorded on file. - - Returns: - int - """ - return self._numberOfEvents - - @property - def numberOfEventsUnread(self): - """The number of events that haven't been read. - - Returns: - int - """ - return self._numberOfEventsUnread - - def __del__(self): - self._fileObject.close() diff --git a/README.md b/README.md index 39fcc0e164b4e71b657c9e36f89165a338db6d70..a91d900a32cbdf4b8fee0ce119474bfdca6edf7e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,22 @@ -# Python Parser for DT5550W Binary File +## Install Cython and autowrap +```bash +pip install Cython +``` +```bash +pip install autowrap +``` -## Usage -- Include `DT550WBinFileParser.py` in your project and add the following lines to your python script to use the parser. - ```python - from DT550WBinFileParser import DT5550WBinFile, CITIROCEvent - # your code follows... - ``` \ No newline at end of file +## Compile the code +```bash +python setup.py build_ext --inplace +``` + +## Run tests +```bash +python binFileParserTest.py +``` + +## Run example +```bash +python example.py +``` \ No newline at end of file diff --git a/DT550WBinFileParserTest.py b/binFileParserTest.py similarity index 53% rename from DT550WBinFileParserTest.py rename to binFileParserTest.py index f736f87adb105f8c049317277b277e1786a522cd..22f936bd102bb25db97f021acd11a64e86e22429 100644 --- a/DT550WBinFileParserTest.py +++ b/binFileParserTest.py @@ -5,33 +5,36 @@ Date: 2022-08-22 19:26:55 LastEditors: Ming Fang mingf2@illinois.edu LastEditTime: 2022-09-02 20:38:55 ''' -import numpy as np import unittest -from DT550WBinFileParser import DT5550WBinFile, CITIROCEvent +from py_BinFileParser import CITIROCEvent, DT5550WBinFile -class TestBinParserV1(unittest.TestCase): +class TestBinParser(unittest.TestCase): def setUp(self): - self.binFile = DT5550WBinFile('test_data/test.data', True) + self.binFile = DT5550WBinFile(b'test_data/test.data', True) + + def testGetDummyEventsSuccess(self): + chunkSize = 100 + newChunk = self.binFile.createNDummyEvents(chunkSize) + assert len(newChunk) == chunkSize + for i in range(len(newChunk)): + self.assertEqual(newChunk[i].EventCounter, i) + self.assertEqual(newChunk[i].AsicID, i) + self.assertEqual(newChunk[i].RunEventTimecode, i) + # self.assertAlmostEqual(newChunk[i].RunEventTimecode_ns, 0.5 * i) + self.assertEqual(newChunk[i].hit, 0xFFFF) - def testConstructorSuccess(self): - self.assertEqual(self.binFile.totalNumberOfEvents, - 639374) - self.assertEqual(self.binFile.numberOfEventsUnread, - 639374) def testGetFirstEventSuccess(self): - newEvent = self.binFile.readNextEvent() - self.assertEqual(newEvent.ASICID, 1) - self.assertEqual(newEvent._RunEventTimeCode, 31439719) + newEvent = (self.binFile.readNextNEvents(1))[0] + self.assertEqual(self.binFile.getNumberOfEventRead(), + 1) + self.assertEqual(newEvent.AsicID, 1) + self.assertEqual(newEvent.RunEventTimecode, 31439719) + # self.assertAlmostEqual(newEvent.RunEventTimeCode_ns, 0.5 * 31439719) self.assertEqual(newEvent.EventCounter, 1) - hit = [0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0] - for i in range(len(hit)): - self.assertEqual(newEvent.Hit[i], hit[i]) + self.assertEqual(newEvent.hit, 0) chargeLG = [1486, 1526, 1470, 1508, 2733, 1550, 1429, 1546, 1481, 1500, 1489, 1433, 1541, 1547, 1462, 1558, @@ -47,22 +50,16 @@ class TestBinParserV1(unittest.TestCase): for i in range(len(chargeHG)): self.assertEqual(newEvent.chargeHG[i], chargeHG[i]) - self.assertEqual(self.binFile.numberOfEventsUnread, - self.binFile.totalNumberOfEvents - 1) def testGetSecondEventSuccess(self): - self.binFile.skipNextEvent() - newEvent = self.binFile.readNextEvent() - self.assertEqual(newEvent.ASICID, 2) - self.assertEqual(newEvent._RunEventTimeCode, 31439721) + self.binFile.readNextNEvents(1) + newEvent = (self.binFile.readNextNEvents(1))[0] + self.assertEqual(self.binFile.getNumberOfEventRead(), 2) + self.assertEqual(newEvent.AsicID, 2) + self.assertEqual(newEvent.RunEventTimecode, 31439721) self.assertEqual(newEvent.EventCounter, 2) - hit = [0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0] - for i in range(len(hit)): - self.assertEqual(newEvent.Hit[i], hit[i]) + self.assertEqual(newEvent.hit, 0) chargeLG = [1564, 1636, 1645, 1588, 1645, 1629, 3273, 1622, 1549, 1576, 1484, 1583, 1589, 1528, 1561, 1501, @@ -77,21 +74,18 @@ class TestBinParserV1(unittest.TestCase): 1541, 1551, 1512, 1471, 1462, 1501, 1568, 1563] for i in range(len(chargeHG)): self.assertEqual(newEvent.chargeHG[i], chargeHG[i]) - - self.assertEqual(self.binFile.numberOfEventsUnread, - self.binFile.totalNumberOfEvents - 2) def testRewindSuccess(self): - skipNumber = self.binFile.totalNumberOfEvents - for _ in range(10): - self.binFile.readNextEvent() + self.binFile.readNextNEvents(100) + self.assertEqual(self.binFile.getNumberOfEventRead(), 100) self.binFile.rewind() - self.assertEqual(self.binFile.numberOfEventsUnread, self.binFile.totalNumberOfEvents) + self.assertEqual(self.binFile.getNumberOfEventRead(), 0) - newEvent = self.binFile.readNextEvent() - self.assertEqual(newEvent.ASICID, 1) - self.assertEqual(newEvent._RunEventTimeCode, 31439719) - self.assertEqual(newEvent.EventCounter, 1) + firstEvent = (self.binFile.readNextNEvents(1))[0] + self.assertEqual(self.binFile.getNumberOfEventRead(), 1) + self.assertEqual(firstEvent.AsicID, 1) + self.assertEqual(firstEvent.RunEventTimecode, 31439719) + self.assertEqual(firstEvent.EventCounter, 1) if __name__ == '__main__': diff --git a/example.py b/example.py new file mode 100644 index 0000000000000000000000000000000000000000..e3877baf0d9234ee6613017124abf15884a0118e --- /dev/null +++ b/example.py @@ -0,0 +1,34 @@ +''' +Description: +Author: Ming Fang +Date: 2022-09-04 03:41:17 +LastEditors: Ming Fang +LastEditTime: 2022-09-04 03:41:17 +''' +from matplotlib import pyplot as plt +# import the parser to use it +from py_BinFileParser import CITIROCEvent, DT5550WBinFile + + +# Example 1 +fileHandle = DT5550WBinFile(b'test_data/test.data', True) +chunkSize = 1000000 +newChunk = fileHandle.readNextNEvents(chunkSize) +# assert len(newChunk) == chunkSize +print("Read {} events.".format(len(newChunk))) + +# Plot the spectra in ASIC 0, Channel 4 +ASIC = 0 +CHANNEL = 4 +LGcharges = [] +HGcharges = [] +for newEvent in newChunk: + if newEvent.AsicID == ASIC: + LGcharges.append(newEvent.chargeLG[CHANNEL]) + HGcharges.append(newEvent.chargeHG[CHANNEL]) +fig, ax = plt.subplots(1, 1, figsize=(6, 6)) +ax.hist(LGcharges, bins=1024, range=(0, 16384)) +ax.set_xlabel('LG charge') +ax.set_ylabel('Counts') +# ax.legend() +plt.show() diff --git a/exampleUsage.py b/exampleUsage.py deleted file mode 100644 index 7481030d1136d3eab97e5c86e7395fc9119ab71f..0000000000000000000000000000000000000000 --- a/exampleUsage.py +++ /dev/null @@ -1,41 +0,0 @@ -''' -Description: Example of using the paser -Author: Ming Fang -Date: 2022-08-22 20:55:13 -LastEditors: Ming Fang mingf2@illinois.edu -LastEditTime: 2022-09-02 21:13:27 -''' -from multiprocessing import Event -import numpy as np -from matplotlib import pyplot as plt -# import the parser to use it -from DT550WBinFileParser import DT5550WBinFile, CITIROCEvent - -# Example 1 -# Plot the spectra in ASIC 0, Channel 4 -binFile = DT5550WBinFile('test_data/test.data') -totalN = binFile.totalNumberOfEvents -print("There are {} pulses in total.".format(totalN)) - -ASIC = 0 -CHANNEL = 4 -LGcharges = [] -HGcharges = [] -# while binFile.numberOfEventsUnread > 0: -# newEvent = binFile.readNextEvent() -# if newEvent.ASICID == ASIC: # and newEvent.Hit[CHANNEL]: -# LGcharges.append(newEvent.chargeLG[CHANNEL]) -# HGcharges.append(newEvent.chargeHG[CHANNEL]) -# if newEvent.EventCounter >= 100: -# break -events = binFile.readNextNEvents(100000) -for newEvent in events: - if newEvent.ASICID == ASIC: - LGcharges.append(newEvent.chargeLG[CHANNEL]) - HGcharges.append(newEvent.chargeHG[CHANNEL]) -fig, ax = plt.subplots(1, 1, figsize=(6, 6)) -ax.hist(LGcharges, bins=1024, range=(0, 16384)) -ax.set_xlabel('LG charge') -ax.set_ylabel('Counts') -# ax.legend() -plt.show() diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cea18dd6677045cf0e3ea9bb89e1d71c4e156059 --- /dev/null +++ b/main.cpp @@ -0,0 +1,26 @@ +#include <string> +#include <iostream> +#include "BinFileParser.h" + + +int main(int argc, char** argv) +{ + std::string fpath("/home/mingf2/projects/DT5550W_python_parser/test_data/test.data"); + DT5550WBinFile binFileHandle(fpath, true); + auto events = binFileHandle.readNextNEvents(1); + CITIROCEvent firstEvent = events[0]; + std::cout << "Events read: " << binFileHandle.getNumberOfEventRead() << std::endl; + std::cout << "First event: ASICID = " << firstEvent.AsicID + << ", RunTimeCode = " << firstEvent.RunEventTimecode + << ", EventCounter = " << firstEvent.EventCounter + << ", Hit = " << firstEvent.hit << std::endl; + + events = binFileHandle.readNextNEvents(1); + CITIROCEvent secondEvent = events[0]; + std::cout << "Events read: " << binFileHandle.getNumberOfEventRead() << std::endl; + std::cout << "First event: ASICID = " << secondEvent.AsicID + << ", RunTimeCode = " << secondEvent.RunEventTimecode + << ", EventCounter = " << secondEvent.EventCounter + << ", Hit = " << secondEvent.hit << std::endl; + return 0; +} \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..4005f124a06025daa5e79e9e48c4cc994ee4cc18 --- /dev/null +++ b/setup.py @@ -0,0 +1,28 @@ +# from setuptools import setup +import os, platform, pkg_resources +from distutils.core import setup, Extension +from Cython.Distutils import build_ext +from autowrap.Main import run as autowrap_run + +data_dir = pkg_resources.resource_filename("autowrap", "data_files") +include_dir = os.path.join(data_dir, "autowrap") + +print('PRECOMPILE USING AUTOWRAP') +autowrap_run([os.path.abspath('./sources/BinFileParser.pxd')], [], [], + os.path.abspath('./sources/py_BinFileParser.pyx'), ) + +ext = Extension("py_BinFileParser", + sources = ['sources/py_BinFileParser.cpp'], + language="c++", + extra_compile_args=["-std=c++11"], #Release mode (no -g switch) + extra_link_args=["-std=c++11"], #Release mode (no -g switch) +# extra_compile_args=["-std=c++14", "-g"], #Debug mode (no -g switch) +# extra_link_args=["-std=c++14", "-g"], #Debug mode (no -g switch) + include_dirs = [include_dir, data_dir], + ) +setup( + cmdclass={"build_ext": build_ext}, + name="py_BinFileParser", + version="0.0.1", + ext_modules=[ext], +) diff --git a/sources/BinFileParser.cpp b/sources/BinFileParser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53b6ede2ef88550c982a358f93fe565610469dfd --- /dev/null +++ b/sources/BinFileParser.cpp @@ -0,0 +1,146 @@ +#include "BinFileParser.h" + +std::vector<CITIROCEvent> DT5550WBinFile::createNDummyEvents(int n) +{ + std::vector<CITIROCEvent> events; + for (int i = 0; i < n; i++) + { + // create dummpy event + CITIROCEvent newEvent; + newEvent.EventCounter = i; + newEvent.AsicID = i; + newEvent.RunEventTimecode = i; + // newEvent.RunEventTimecode_ns = 0.5 * i; + for (int j = 0; j < 32; j++) + { + newEvent.chargeLG[j]= (j+i); + newEvent.chargeHG[j] = (j+i); + } + newEvent.hit = 0xFFFF; + events.push_back(newEvent); + } + return events; +} + +std::vector<CITIROCEvent> DT5550WBinFile::readNextNEvents(int n) +{ + std::vector<CITIROCEvent> events; + if (n < 1) + { + return events; + } + + // parse data + char* buffer = new char[n*eventSize_]; + int numberOfEvents(0); + int64_t numberOfBytesLeft(0); + int64_t bufferSize(n*eventSize_); + while (numberOfEvents < n && fileObj_.peek() != EOF) + { + fileObj_.read(buffer, bufferSize); + bufferSize = fileObj_.gcount(); + numberOfBytesLeft = bufferSize; + if (bufferSize < eventSize_) + { + break; + } + // decode buffer + decode(buffer, bufferSize, events, numberOfEvents, numberOfBytesLeft); + // check if we have any bytes left in the buffer + if (numberOfBytesLeft != 0) + { + fileObj_.seekg(-numberOfBytesLeft, std::ios_base::cur); + } + if (numberOfEvents < n) + { + bufferSize = (n-numberOfEvents)*eventSize_; + numberOfBytesLeft = bufferSize; + } + } + numberOfEventsRead_ += numberOfEvents; + delete[] buffer; + return events; +} + +void DT5550WBinFile::decode(const char* buffer, const int64_t bufferSize, + std::vector<CITIROCEvent>& events, + int& numberOfEvents, + int64_t& numberOfBytesLeft) +{ + uint32_t p = 0; + uint32_t s = 0; + uint32_t bword = 0; + const uint32_t s_32 = bufferSize/4; + const uint32_t *p_ui32 = (uint32_t*)&(buffer[0]); + CITIROCEvent newEvent; + static uint32_t datarow[97]; + while (p < s_32) + { + switch (s) + { + case 0: + bword = p_ui32[p++]; + //Align to sync world + if (((bword >> 4) & 0xc000000) == 0x8000000) + { + if(numberOfBytesLeft < eventSize_) + { + p = s_32; + break; + } + s = 1; + newEvent.AsicID = bword & 0xF; + // newEvent.EventTimecode = (uint64_t) (p_ui32[p++]); + p++; + newEvent.RunEventTimecode = ((uint64_t)(p_ui32[p++])); + newEvent.RunEventTimecode += ((uint64_t)(p_ui32[p++])) << 32L; + newEvent.EventCounter = (uint64_t)(p_ui32[p++]); + } + else + numberOfBytesLeft = bufferSize - p*4; + + break; + + case 1: + for (int i = 0; i < 32; i++) + { + bword = p_ui32[p++]; + datarow[i * 3 + 0] = (bword >> 0) & 0x3FFF; + datarow[i * 3 + 1] = (bword >> 14) & 0x3FFF; + datarow[i * 3 + 2] = (bword >> 28) & 0x1; + } + int j; + for (int i = 0; i < 32; i++) + { + j = 31-i; + newEvent.hit += (datarow[j * 3 + 2] & 0x1) << i; + int dataHG = (int)datarow[(j * 3) + 0]; + int dataLG = (int)datarow[(j * 3) + 1]; + + newEvent.chargeHG[i] = (dataHG); + newEvent.chargeLG[i] = (dataLG); + } + + if (FW_USE_VALIDATION_ == 1) + p += 3; + s = 5; + break; + + case 5: + if ((p_ui32[p++] & 0xc0000000) == 0xc0000000) + { + events.push_back(newEvent); + numberOfEvents++; + } + numberOfBytesLeft = bufferSize - p*4; + s = 0; + break; + } + } +} + +void DT5550WBinFile::rewind() +{ + fileObj_.seekg(0, std::ios_base::beg); + numberOfEventsRead_ = 0; +} \ No newline at end of file diff --git a/sources/BinFileParser.h b/sources/BinFileParser.h new file mode 100644 index 0000000000000000000000000000000000000000..0533ecc5ddeba492af4b481eed106644abffe085 --- /dev/null +++ b/sources/BinFileParser.h @@ -0,0 +1,59 @@ +#pragma once +#include <fstream> +#include <vector> + +class CITIROCEvent +{ +public: + CITIROCEvent(): chargeLG(32, 0), chargeHG(32, 0) {} + // uint64_t EventTimecode; + uint64_t RunEventTimecode; + uint64_t EventCounter; + uint16_t AsicID; + + // double EventTimecode_ns; + double RunEventTimecode_ns; + + std::vector<uint16_t> chargeLG; + std::vector<uint16_t> chargeHG; + uint16_t hit{0}; + +}; + +class DT5550WBinFile +{ +private: + std::ifstream fileObj_; + int numberOfEventsRead_{0}; + bool FW_USE_VALIDATION_; + int eventSize_{152}; +public: + + DT5550WBinFile(std::string fpath, bool FW_USE_VALIDATION) : + fileObj_(fpath, std::ios::binary), + FW_USE_VALIDATION_(FW_USE_VALIDATION) + { + if(!fileObj_.good()) + { + throw std::ios_base::failure(fpath + " is not accessible."); + } + if (FW_USE_VALIDATION_) + { + eventSize_ += 12; + } + } + + ~DT5550WBinFile() + { + this->fileObj_.close(); + } + + std::vector<CITIROCEvent> readNextNEvents(int n); + std::vector<CITIROCEvent> createNDummyEvents(int n); + void decode(const char* buffer, const int64_t bufferSize, std::vector<CITIROCEvent>& events, int& numberOfEvents, int64_t& numberOfBytesLeft); + + int getNumberOfEventRead() {return numberOfEventsRead_;} + + void rewind(); + +}; \ No newline at end of file diff --git a/sources/BinFileParser.pxd b/sources/BinFileParser.pxd new file mode 100644 index 0000000000000000000000000000000000000000..564f2ba2f7903dafed58aabb9efd6eb0647db70d --- /dev/null +++ b/sources/BinFileParser.pxd @@ -0,0 +1,24 @@ +from libcpp.string cimport string as libcpp_string +from libcpp.vector cimport vector as libcpp_vector +from libcpp cimport bool +cdef extern from "BinFileParser.cpp": + pass + +cdef extern from "BinFileParser.h": + cdef cppclass CITIROCEvent: + CITIROCEvent() except + + CITIROCEvent(CITIROCEvent&) + unsigned long long RunEventTimecode # wrap-constant + unsigned long long EventCounter # wrap-constant + unsigned short AsicID # wrap-constant + + libcpp_vector[unsigned short] chargeLG # wrap-constant + libcpp_vector[unsigned short] chargeHG # wrap-constant + unsigned short hit # wrap-constant + + cdef cppclass DT5550WBinFile: + DT5550WBinFile(libcpp_string, bool) except + + libcpp_vector[CITIROCEvent] readNextNEvents(int) + libcpp_vector[CITIROCEvent] createNDummyEvents(int) + int getNumberOfEventRead() + void rewind() diff --git a/sources/CMakeLists.txt b/sources/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6dcb997734b2f9c22fe3384a11718f586ab87d33 --- /dev/null +++ b/sources/CMakeLists.txt @@ -0,0 +1 @@ +add_library(binFileParser SHARED BinFileParser.cpp) \ No newline at end of file