From 1303f452be6ce9231196c69e532e0d9ae686ead6 Mon Sep 17 00:00:00 2001
From: Christian <ckoernig@students.uni-mainz.de>
Date: Sat, 23 May 2020 17:48:30 +0200
Subject: [PATCH] Added COMMTEST packet types, added List Mode data record loop

- Added the commtest packet types for stream start and stopping (will be
needed for testing)
- Added public functions to the HardwareInterface to start and stop the
list mode streaming. This list datapacket is forwarded to a filestream.
The SYNC and CHECKSUM bytes are stripped from the packet, but PID and
LEN are still included. This can be used later to finde FIFO overflows
or add other type of data to the stream by adding custom PIDs
---
 include/AmptekHardwareInterface.h       | 10 +++++
 include/packet.h                        | 12 +++++-
 python/AmptekHardwareInterface.py       |  6 +++
 python/AmptekHardwareInterface_wrap.cpp | 57 +++++++++++++++++++++++++
 src/AmptekHardwareInterface.cpp         | 46 ++++++++++++++++++++
 src/packet.cpp                          | 18 ++++++++
 6 files changed, 147 insertions(+), 2 deletions(-)

diff --git a/include/AmptekHardwareInterface.h b/include/AmptekHardwareInterface.h
index eec1eee..2fdc0b0 100644
--- a/include/AmptekHardwareInterface.h
+++ b/include/AmptekHardwareInterface.h
@@ -2,6 +2,8 @@
 #define AmptekHardwareInterface_h
 #include "types.h"
 #include <chrono>
+#include <thread>
+#include <fstream>
 
 #include "AmptekConnectionHandler.h"
 
@@ -41,6 +43,9 @@ public:
     bool SetTextConfiguration(std::vector<std::string> commands);
     bool UpdateStatus() {return updateStatus(-1);};
 
+    bool EnableListMode(std::string targetfile);
+    bool DisableListMode();
+
     int FastCount(double max_age_ms = 100);
     int SlowCount(double max_age_ms = 100);
     double DeadTime(double max_age_ms = 100);
@@ -83,9 +88,14 @@ private:
     std::chrono::time_point<std::chrono::system_clock> last_status_update_time;
     std::chrono::time_point<std::chrono::system_clock> last_spectrum_update_time;
 
+    bool listmode_flag;
+
     AmptekState current_state = NOT_CONNECTED;
 
     AmptekConnectionHandler* connection_handler = nullptr;
+
+    std::thread* list_reader_thread = nullptr;
+    std::ofstream streamfile;
 };
 
 
diff --git a/include/packet.h b/include/packet.h
index cce243f..47a57d2 100644
--- a/include/packet.h
+++ b/include/packet.h
@@ -31,7 +31,7 @@ enum PID1_TYPE{
     DP5_P1_SCA_REQUEST          = 0x04,
     DP5_P1_TEXTCONFIG_REQUEST   = 0x20,
     DP5_P1_COMMAND_REQUEST      = 0xF0,
-    DP5_P1_COMTEST_REQUEST      = 0xF1,
+    DP5_P1_COMMTEST_REQUEST     = 0xF1,
 
     DP5_P1_STATUS_RESPONSE      = 0x80,
     DP5_P1_SPECTRUM_RESPONSE    = 0x81,
@@ -70,7 +70,11 @@ enum PID2_SUBTYPE_COMMAND_REQUEST{
     DP5_P2_COMMAND_REQUEST_CANCEL_BUFFER          = 0x1F,
     DP5_P2_COMMAND_REQUEST_KEEP_ALIVE_NO_SHARE    = 0x21,
 };
-
+enum PID2_SUBTYPE_COMMTEST_REQUEST{
+    DP5_P2_COMMTEST_REQUEST_ACK                   = 0xF1,
+    DP5_P2_COMMTEST_REQUEST_STREAM                = 0xF2,
+    DP5_P2_COMMTEST_REQUEST_ECHO                  = 0xF3,
+};
 enum PID2_SUBTYPE_STATUS_RESPONSE{
     DP5_P2_STATUS_RESPONSE_INFO = 0x01,
 };
@@ -173,6 +177,7 @@ public:
     static const Packet DP5_PKT_REQUEST_CANCEL_SEQ_BUFFERING;
     static const Packet DP5_PKT_REQUEST_LIST_DATA;
     static const Packet DP5_PKT_REQUEST_CLEAR_LIST_TIMER;
+    static const Packet DP5_PKT_REQUEST_STOP_STREAM_COMMTEST;
 
     static const Packet gernerateSetConfigurationRequest(std::string text_configuration);
     static const Packet gernerateGetConfigurationRequest(std::string text_configuration);
@@ -181,6 +186,9 @@ public:
     static const Packet generateBufferAndClearRequest(uint16_t buffer_index);
     static const Packet generateGetBufferRequest(uint16_t buffer_index);
 
+    static const Packet generateCommtestStreamingRequest(uint16_t min_channel,uint16_t max_channel, 
+                                                          uint16_t increment, uint16_t period);
+
 };
 
 #endif
diff --git a/python/AmptekHardwareInterface.py b/python/AmptekHardwareInterface.py
index 8ee86f1..6813727 100644
--- a/python/AmptekHardwareInterface.py
+++ b/python/AmptekHardwareInterface.py
@@ -658,6 +658,12 @@ class AmptekHardwareInterface(object):
     def UpdateStatus(self):
         return _AmptekHardwareInterface.AmptekHardwareInterface_UpdateStatus(self)
 
+    def EnableListMode(self, targetfile):
+        return _AmptekHardwareInterface.AmptekHardwareInterface_EnableListMode(self, targetfile)
+
+    def DisableListMode(self):
+        return _AmptekHardwareInterface.AmptekHardwareInterface_DisableListMode(self)
+
     def FastCount(self, max_age_ms=100):
         return _AmptekHardwareInterface.AmptekHardwareInterface_FastCount(self, max_age_ms)
 
diff --git a/python/AmptekHardwareInterface_wrap.cpp b/python/AmptekHardwareInterface_wrap.cpp
index c6dcbfd..ae30ab8 100644
--- a/python/AmptekHardwareInterface_wrap.cpp
+++ b/python/AmptekHardwareInterface_wrap.cpp
@@ -14734,6 +14734,61 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_AmptekHardwareInterface_EnableListMode(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  AmptekHardwareInterface *arg1 = (AmptekHardwareInterface *) 0 ;
+  std::string arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  bool result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:AmptekHardwareInterface_EnableListMode",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_AmptekHardwareInterface, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AmptekHardwareInterface_EnableListMode" "', argument " "1"" of type '" "AmptekHardwareInterface *""'"); 
+  }
+  arg1 = reinterpret_cast< AmptekHardwareInterface * >(argp1);
+  {
+    std::string *ptr = (std::string *)0;
+    int res = SWIG_AsPtr_std_string(obj1, &ptr);
+    if (!SWIG_IsOK(res) || !ptr) {
+      SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in method '" "AmptekHardwareInterface_EnableListMode" "', argument " "2"" of type '" "std::string""'"); 
+    }
+    arg2 = *ptr;
+    if (SWIG_IsNewObj(res)) delete ptr;
+  }
+  result = (bool)(arg1)->EnableListMode(arg2);
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_AmptekHardwareInterface_DisableListMode(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  AmptekHardwareInterface *arg1 = (AmptekHardwareInterface *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  bool result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:AmptekHardwareInterface_DisableListMode",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_AmptekHardwareInterface, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AmptekHardwareInterface_DisableListMode" "', argument " "1"" of type '" "AmptekHardwareInterface *""'"); 
+  }
+  arg1 = reinterpret_cast< AmptekHardwareInterface * >(argp1);
+  result = (bool)(arg1)->DisableListMode();
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_AmptekHardwareInterface_FastCount__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   AmptekHardwareInterface *arg1 = (AmptekHardwareInterface *) 0 ;
@@ -17253,6 +17308,8 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"AmptekHardwareInterface_SetPresetCounts", _wrap_AmptekHardwareInterface_SetPresetCounts, METH_VARARGS, NULL},
 	 { (char *)"AmptekHardwareInterface_SetTextConfiguration", _wrap_AmptekHardwareInterface_SetTextConfiguration, METH_VARARGS, NULL},
 	 { (char *)"AmptekHardwareInterface_UpdateStatus", _wrap_AmptekHardwareInterface_UpdateStatus, METH_VARARGS, NULL},
+	 { (char *)"AmptekHardwareInterface_EnableListMode", _wrap_AmptekHardwareInterface_EnableListMode, METH_VARARGS, NULL},
+	 { (char *)"AmptekHardwareInterface_DisableListMode", _wrap_AmptekHardwareInterface_DisableListMode, METH_VARARGS, NULL},
 	 { (char *)"AmptekHardwareInterface_FastCount", _wrap_AmptekHardwareInterface_FastCount, METH_VARARGS, NULL},
 	 { (char *)"AmptekHardwareInterface_SlowCount", _wrap_AmptekHardwareInterface_SlowCount, METH_VARARGS, NULL},
 	 { (char *)"AmptekHardwareInterface_DeadTime", _wrap_AmptekHardwareInterface_DeadTime, METH_VARARGS, NULL},
diff --git a/src/AmptekHardwareInterface.cpp b/src/AmptekHardwareInterface.cpp
index 0af63f3..34e67ad 100644
--- a/src/AmptekHardwareInterface.cpp
+++ b/src/AmptekHardwareInterface.cpp
@@ -335,6 +335,52 @@ if (connection_handler != nullptr){
 
 
 
+bool AmptekHardwareInterface::EnableListMode(std::string targetfile){
+
+    streamfile.open( targetfile, ios::binary );
+    //f.write( static_cast <char*> ( &(pts.count) ), sizeof( unsigned ) );
+    listmode_flag = true;
+    list_reader_thread = new std::thread([&](){
+        while(listmode_flag){
+            try{
+                 Packet listResponse = connection_handler->sendAndReceive( Packet::DP5_PKT_REQUEST_LIST_DATA );
+                //std::cout << spectrumResponse.size() << std::endl;
+                if (listResponse.at(PID1) != DP5_P1_DATA_RESPONSE )
+                {
+                    throw AmptekException("Response Packet is not of type DATA_RESPONSE: " + listResponse.toString());
+                }
+                if( listResponse.at(PID2) != DP5_P2_DATA_RESPONSE_LISTDATA && listResponse.at(PID2) != DP5_P2_DATA_RESPONSE_LISTDATA_FULL ){
+                    throw AmptekException("Response Packet is not of subtype LISTDATA: " + listResponse.toString());
+                }
+                //write the packet without the sync and checksum to file : [PID1,PID2,LEN_MSB;LEN_LSB,DATA_0,....,DATA_N]
+                streamfile.write( reinterpret_cast<char*>( &listResponse[PID1] ), listResponse.dataLength + 4 );
+
+            }
+            catch(AmptekException& e){
+                std::cerr << e.what() << std::endl;
+            }
+            std::this_thread::sleep_for(std::chrono::microseconds(100));
+        }
+    });
+    return true;
+}
+
+bool AmptekHardwareInterface::DisableListMode(){
+    listmode_flag = false;
+    list_reader_thread->join();
+    streamfile.close();
+    delete list_reader_thread;
+}
+
+
+
+
+
+
+
+
+
+
 
 
 
diff --git a/src/packet.cpp b/src/packet.cpp
index b2ea60f..4a0964d 100644
--- a/src/packet.cpp
+++ b/src/packet.cpp
@@ -20,6 +20,9 @@ const Packet Packet::DP5_PKT_REQUEST_RESTART_SEQ_BUFFERING = Packet( DP5_P1_COMM
 const Packet Packet::DP5_PKT_REQUEST_CANCEL_SEQ_BUFFERING  = Packet( DP5_P1_COMMAND_REQUEST     , DP5_P2_COMMAND_REQUEST_CANCEL_BUFFER      , nullptr, 0);
 const Packet Packet::DP5_PKT_REQUEST_CLEAR_LIST_TIMER      = Packet( DP5_P1_COMMAND_REQUEST     , DP5_P2_COMMAND_REQUEST_CLEAR_TIMER        , nullptr, 0);
 
+
+const Packet Packet::DP5_PKT_REQUEST_STOP_STREAM_COMMTEST  = Packet( DP5_P1_COMMTEST_REQUEST    , DP5_P2_COMMTEST_REQUEST_STREAM            , nullptr, 0 );
+
 const Packet Packet::gernerateSetConfigurationRequest(std::string text_configuration){
     word16 len = text_configuration.size();
     byte data[len];
@@ -51,6 +54,21 @@ const Packet Packet::generateGetBufferRequest(uint16_t buffer_index){
     data[1] = buffer_index;
     return Packet( DP5_P1_SPECTRUM_REQUEST, DP5_P2_SPECTRUM_REQUEST_GET_BUFFER, data, 2 );
 }
+const Packet Packet::generateCommtestStreamingRequest(uint16_t min_channel,uint16_t max_channel, 
+                                                          uint16_t increment, uint16_t period)
+{
+    byte data[8];
+    data[0] = min_channel >> 8;
+    data[1] = min_channel;
+    data[2] = max_channel >> 8;
+    data[3] = max_channel;
+    data[4] = increment >> 8;
+    data[5] = increment;
+    data[6] = period >> 8;
+    data[7] = period;
+    return Packet( DP5_P1_COMMTEST_REQUEST    , DP5_P2_COMMTEST_REQUEST_STREAM , data, 8 );
+
+}
 
 
 Packet::Packet():vector<byte>(), dataLength(0)
-- 
GitLab