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