Skip to content

Commit

Permalink
Merge pull request #183 from slaclab/ESCRYODET-479
Browse files Browse the repository at this point in the history
Validate the SmurfProcessor's filter
  • Loading branch information
jesusvasquez333 authored Nov 16, 2019
2 parents 60aed5f + 0f14a33 commit d55a912
Show file tree
Hide file tree
Showing 6 changed files with 465 additions and 1 deletion.
136 changes: 136 additions & 0 deletions python/pysmurf/core/emulators/_DataFromFile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# Title : PySMuRF DataFromFile
#-----------------------------------------------------------------------------
# File : _StreamDataEmulator.py
# Created : 2019-11-15
#-----------------------------------------------------------------------------
# Description:
# Stream data from a file
#-----------------------------------------------------------------------------
# This file is part of the smurf software platform. It is subject to
# the license terms in the LICENSE.txt file found in the top-level directory
# of this distribution and at:
# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
# No part of the smurf software platform, including this file, may be
# copied, modified, propagated, or distributed except according to the terms
# contained in the LICENSE.txt file.
#-----------------------------------------------------------------------------

import sys
import time
import rogue.interfaces.stream
import pyrogue

class DataFromFile(pyrogue.Device):
"""
Class to stream data from a test file.
"""
def __init__(self, name="DataFromFile", description="Data from file source", **kwargs):
pyrogue.Device.__init__(self, name=name, description=description, **kwargs)
self._data_master = DataMaster()

self.add(pyrogue.LocalVariable(
name='FileName',
description='Path to the data file',
mode='RW',
value='/tmp/fw/x.dat'))

self.add(pyrogue.LocalVariable(
name='FrameCnt',
description='Number of sent frames',
mode='RO',
value=0,
localGet = self._data_master.get_frame_cnt))

self.add(pyrogue.LocalCommand(
name='SendData',
description='Send data',
function=self._send_data))

def _send_data(self):
"""
Method to send data from the specified text file.
"""
file_name = self.FileName.get()
self._data_master.send_data(file_name=file_name)

def _getStreamMaster(self):
"""
Method called by streamConnect, streamTap and streamConnectBiDir to access master.
"""
return self._data_master



class DataMaster(rogue.interfaces.stream.Master):
"""
A Rogue master device, used to stream the data.
"""
def __init__(self):
super().__init__()
self._frame_cnt=0

def get_frame_cnt(self):
"""
Get the number of sent frames
"""
return self._frame_cnt

def send_data(self, file_name):
"""
Send all the data from a text file. The input data file,
must be a text file with data point on each line. The data
must be of type int16.
Each data point is read from the file, and then send on a
frame with the SMuRF header, with only the first channel
containing the data point.
Args:
-----
- file_name (str) : path to the input data file
"""
if not file_name:
print("ERROR: Must define a data file first!")
return

try:
with open(file_name, 'r') as f:
for data in f:
self.sendData(data=data)
time.sleep(0.01)

except IOError:
print("Error trying to open {file_name}")


# Method for generating a frame
def sendData(self, data):
"""
Send a Rogue Frame. The frame contains the SMuRF header and the
input data point in the first channel. The frame will contain only
one channel. The SMuRF header will be only partially filled, containing
only the number of channels, and a the frame counter words.
Args:
-----
- data (int) : input data (must be of type int16)
"""

# Request a frame to hold 1 data point
frame = self._reqFrame(128+2, True)

# Write the number of channels
frame.write( bytearray((1).to_bytes(4, sys.byteorder)), 4)

# Write the frame counter into the header
frame.write( bytearray(self._frame_cnt.to_bytes(4, sys.byteorder)), 84)

# Write the data into the first channel
frame.write( bytearray(int(data).to_bytes(2, sys.byteorder, signed=True)), 128)

# Send the frame
self._sendFrame(frame)

# Update the frame counter
self._frame_cnt = self._frame_cnt + 1
1 change: 1 addition & 0 deletions python/pysmurf/core/emulators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@

from pysmurf.core.emulators._StreamDataEmulator import StreamDataEmulator
from pysmurf.core.emulators._StreamDataSource import StreamDataSource
from pysmurf.core.emulators._DataFromFile import DataFromFile
133 changes: 133 additions & 0 deletions python/pysmurf/core/transmitters/_DataToFile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# Title : PySMuRF DataToFile
#-----------------------------------------------------------------------------
# File : _StreamDataEmulator.py
# Created : 2019-11-15
#-----------------------------------------------------------------------------
# Description:
# Receive a stream and write the data to disk
#-----------------------------------------------------------------------------
# This file is part of the smurf software platform. It is subject to
# the license terms in the LICENSE.txt file found in the top-level directory
# of this distribution and at:
# https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
# No part of the smurf software platform, including this file, may be
# copied, modified, propagated, or distributed except according to the terms
# contained in the LICENSE.txt file.
#-----------------------------------------------------------------------------

import sys
import rogue.interfaces.stream
import pyrogue

class DataToFile(pyrogue.Device):
"""
Class to write data to a file
"""
def __init__(self, name="DataToFile", description="Data to file writer", **kwargs):
pyrogue.Device.__init__(self, name=name, description=description, **kwargs)
self._data_slave = DataSlave()
self._meta_slave = MetaSlave()

self.add(pyrogue.LocalVariable(
name='FileName',
description='Path to the data file',
mode='RW',
value='/tmp/fw/y.dat'))

self.add(pyrogue.LocalCommand(
name='WriteData',
description='Write data to disk',
function=self._write_data))

def _write_data(self):
"""
Method to write the data to the specified text file.
"""
file_name = self.FileName.get()
self._data_slave.write_data(file_name=file_name)

def getDataChannel(self):
"""
Method called by streamConnect, streamTap and streamConnectBiDir to access slave.
This is method is called to request the data channel.
"""
return self._data_slave

def getMetaChannel(self):
"""
Method called by streamConnect, streamTap and streamConnectBiDir to access slave.
This is method is called to request the metadata channel.
"""
return self._meta_slave

class DataSlave(rogue.interfaces.stream.Slave):
"""
A Rogue slave device, used receive a stream of data and write it to disk.
"""
def __init__(self):
super().__init__()
self._data = []

def write_data(self, file_name):
"""
Method to write the data buffer to a text file. Writes the
content of the data buffer (self._data) to the output file,
one data point on each line as text.
Args:
-----
- file_name (str) : path to the output data file.
"""
if not file_name:
print("ERROR: Must define a data file first!")
return

try:
with open(file_name, 'w') as f:
for datum in self._data:
f.write(f'{str(datum)}\n')


except IOError:
print("Error trying to open {file_name}")

def _acceptFrame(self, frame):
"""
Args:
Receive a frame with SMuRF data. The first channel is appended
to the data buffer.
-----
frame (rogue.interfaces.stream.Frame) : a frame with SMuRF data.
"""
with frame.lock():
data = bytearray(4)

frame.read(data, 128)
self._data.append(int.from_bytes(bytes(data), byteorder=sys.byteorder, signed=True))

#try:
# with open(self._file_name, 'a+') as f:
# f.write(f'{str(data_int)}\n')
#except IOError:
# pass


class MetaSlave(rogue.interfaces.stream.Slave):
"""
A Rogue slave device, used to connect to the metadata channel.
"""
def __init__(self):
super().__init__()

def _acceptFrame(self, frame):
"""
Receive a frame with metadata. The frame is discarded.
Args:
-----
frame (rogue.interfaces.stream.Frame) : a frame with metadata
"""
pass
1 change: 1 addition & 0 deletions python/pysmurf/core/transmitters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
#-----------------------------------------------------------------------------

from pysmurf.core.transmitters._BaseTransmitter import *
from pysmurf.core.transmitters._DataToFile import DataToFile
3 changes: 2 additions & 1 deletion src/smurf/core/processors/SmurfProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,8 @@ void scp::SmurfProcessor::acceptFrame(ris::FramePtr frame)
break;

// Get the mapped value from the framweBuffer and cast it
currentData.at(i) = static_cast<unwrap_t>(*(inIt + m * sizeof(fw_t)));
// Reinterpret the bytes from the frameBuffer to 'fw_t' values. And the cast that value to 'unwrap_t' values
currentData.at(i) = static_cast<unwrap_t>(*(reinterpret_cast<fw_t*>(&(*( inIt + m * sizeof(fw_t) )))));

// Unwrap the value is the unwrapper is not disabled.
// If it is disabled, don't do anything to the data
Expand Down
Loading

0 comments on commit d55a912

Please sign in to comment.