Working C++ multiple API sit

This commit is contained in:
Anne de Jong 2020-10-10 18:28:43 +02:00
parent a43857070b
commit 29662c82e3
14 changed files with 784 additions and 735 deletions

View File

@ -5,6 +5,7 @@ add_library(cpp_daq lasp_cppdaq.cpp lasp_cppuldaq.cpp )
set_source_files_properties(lasp_daq.pyx PROPERTIES CYTHON_IS_CXX TRUE)
set_source_files_properties(lasp_deviceinfo.pyx PROPERTIES CYTHON_IS_CXX TRUE)
set_source_files_properties(lasp_daqconfig.pyx PROPERTIES CYTHON_IS_CXX TRUE)
set_source_files_properties(lasp_daq.cxx PROPERTIES COMPILE_FLAGS
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
@ -12,12 +13,19 @@ set_source_files_properties(lasp_daq.cxx PROPERTIES COMPILE_FLAGS
set_source_files_properties(lasp_deviceinfo.cxx PROPERTIES COMPILE_FLAGS
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
set_source_files_properties(lasp_daqconfig.cxx PROPERTIES COMPILE_FLAGS
"${CMAKE_CXX_FLAGS} ${CYTHON_EXTRA_CXX_FLAGS}")
cython_add_module(lasp_daq lasp_daq.pyx)
cython_add_module(lasp_deviceinfo lasp_deviceinfo.pyx)
cython_add_module(lasp_daqconfig lasp_daqconfig.pyx)
target_link_libraries(lasp_daq cpp_daq uldaq rtaudio pthread)
target_link_libraries(lasp_deviceinfo cpp_daq uldaq rtaudio pthread)
target_link_libraries(lasp_daqconfig cpp_daq uldaq rtaudio pthread)
if(win32)
target_link_libraries(lasp_daq python37)
target_link_libraries(lasp_deviceinfo python37)
target_link_libraries(lasp_daqconfig python37)
endif(win32)

View File

@ -1,6 +1,6 @@
#!/usr/bin/python3
from .lasp_daqconfig import *
from .lasp_avtype import *
from .lasp_device_common import *
from .lasp_daq import *
from .lasp_deviceinfo import *
from .lasp_daqconfig import *

View File

@ -39,16 +39,10 @@ cdef extern from "lasp_pyarray.h":
ctypedef unsigned us
ctypedef vector[bool] boolvec
ctypedef vector[double] dvec
ctypedef vector[us] usvec
cdef extern from "lasp_cppdaq.h" nogil:
cdef cppclass cppDaq "Daq":
void start(SafeQueue[void*] *inQueue,
SafeQueue[void*] *outQueue) except +
void stop()
double samplerate()
us neninchannels()
us nenoutchannels()
DataType getDataType()
cdef cppclass DaqApi:
string apiname
@ -63,21 +57,27 @@ cdef extern from "lasp_cppdaq.h" nogil:
cdef cppclass cppDeviceInfo "DeviceInfo":
DaqApi api
string name
string device_name
unsigned devindex
vector[DataType] availableDataTypes
vector[double] availableSampleRates
vector[us] availableFramesPerBlock
int prefSampleRateIndex
int prefInputRangeIndex
int prefFramesPerBlockIndex
unsigned ninchannels
unsigned noutchannels
bool hasInputIEPE
bool hasInputACCouplingSwitch
bool hasInputTrigger
vector[double] inputRanges
vector[double] availableInputRanges
cdef cppclass DaqConfiguration:
boolvec eninchannels
boolvec enoutchannels
vector[string] channel_names
vector[double] channel_sensitivities
unsigned sampleRateIndex
DataType datatype
bool monitorOutput
@ -85,12 +85,19 @@ cdef extern from "lasp_cppdaq.h" nogil:
boolvec inputIEPEEnabled;
boolvec inputACCouplingMode;
boolvec inputHighRange;
usvec inputRangeIndices;
cdef cppclass cppDaq "Daq":
void start(SafeQueue[void*] *inQueue,
SafeQueue[void*] *outQueue) except +
void stop()
double samplerate()
us neninchannels()
us nenoutchannels()
DataType getDataType()
cdef cppclass DaqDevices:
@staticmethod
cppDaq* createDaqDevice(cppDeviceInfo&, DaqConfiguration&)
@staticmethod
vector[cppDeviceInfo] getDeviceInfo()

View File

@ -1,6 +1,9 @@
#include "lasp_cppdaq.h"
#include "lasp_cppuldaq.h"
#include <algorithm>
#include <cassert>
#include <iostream>
#include <strstream>
using std::cout;
using std::endl;
@ -11,7 +14,6 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo> &devinfolist) {
UlError err;
unsigned int numdevs = MAX_DEV_COUNT_PER_API;
unsigned deviceno;
DaqDeviceDescriptor devdescriptors[MAX_DEV_COUNT_PER_API];
DaqDeviceDescriptor descriptor;
@ -43,13 +45,11 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo> &devinfolist) {
name += string(descriptor.productName) + " ";
name += string(descriptor.uniqueId);
devinfo.name = name;
devinfo.device_name = name;
devinfo.devindex = i;
devinfo.api_specific_devindex = i;
devinfo.availableDataTypes.push_back(dtype_fl64);
devinfo.ninchannels = 4;
devinfo.noutchannels = 1;
devinfo.prefDataTypeIndex = 0;
devinfo.availableSampleRates.push_back(10000);
devinfo.availableSampleRates.push_back(12000);
@ -60,18 +60,32 @@ void fillUlDaqDeviceInfo(vector<DeviceInfo> &devinfolist) {
devinfo.availableSampleRates.push_back(51000);
devinfo.prefSampleRateIndex = 5;
devinfo.availableFramesPerBlock.push_back(512);
devinfo.availableFramesPerBlock.push_back(1024);
devinfo.availableFramesPerBlock.push_back(2048);
devinfo.availableFramesPerBlock.push_back(4096);
devinfo.availableFramesPerBlock.push_back(8192);
devinfo.prefFramesPerBlockIndex = 1;
devinfo.availableInputRanges = {1.0, 10.0};
devinfo.prefInputRangeIndex = 0;
devinfo.ninchannels = 4;
devinfo.noutchannels = 1;
devinfo.hasInputIEPE = true;
devinfo.hasInputACCouplingSwitch = true;
devinfo.hasInputTrigger = true;
// Finally, this devinfo is pushed back in list
devinfolist.push_back(devinfo);
}
}
}
#endif
vector<DeviceInfo> DaqDevices::getDeviceInfo() {
vector<DeviceInfo> Daq::getDeviceInfo() {
vector<DeviceInfo> devs;
#ifdef HAS_ULDAQ_LINUX_API
fillUlDaqDeviceInfo(devs);
@ -89,8 +103,57 @@ vector<DeviceInfo> DaqDevices::getDeviceInfo() {
return devs;
}
Daq *DaqDevices::createDevice(const DeviceInfo &devinfo,
const DaqConfiguration &config) {
DaqConfiguration::DaqConfiguration(const DeviceInfo &device) {
api = device.api;
device_name = device.device_name;
eninchannels.resize(device.ninchannels, false);
enoutchannels.resize(device.noutchannels, false);
inchannel_sensitivities.resize(device.ninchannels, 1.0);
for (us i = 0; i < eninchannels.size(); i++) {
std::strstream chname;
chname << "Unnamed input channel " << i;
inchannel_names.push_back(chname.str());
}
for (us i = 0; i < enoutchannels.size(); i++) {
std::strstream chname;
chname << "Unnamed output channel " << i;
outchannel_names.push_back(chname.str());
}
sampleRateIndex = device.prefSampleRateIndex;
dataTypeIndex = device.prefDataTypeIndex;
framesPerBlockIndex = device.prefFramesPerBlockIndex;
monitorOutput = false;
inputIEPEEnabled.resize(device.ninchannels, false);
inputACCouplingMode.resize(device.ninchannels, false);
inputRangeIndices.resize(device.ninchannels, device.prefInputRangeIndex);
assert(match(device));
}
bool DaqConfiguration::match(const DeviceInfo& dev) const {
return (dev.device_name == device_name && dev.api == api);
}
Daq *Daq::createDevice(const DaqConfiguration &config,
const vector<DeviceInfo> &devinfos) {
bool match;
DeviceInfo devinfo;
for (auto cur_devinfo : devinfos) {
if ((match = config.match(cur_devinfo))) {
devinfo = cur_devinfo;
break;
}
}
if (!match) {
return NULL;
}
// Some basic sanity checks
if ((devinfo.ninchannels != config.eninchannels.size())) {
@ -107,3 +170,52 @@ Daq *DaqDevices::createDevice(const DeviceInfo &devinfo,
devinfo.api.apiname);
}
}
Daq::Daq(const DeviceInfo &devinfo, const DaqConfiguration &config)
: DaqConfiguration(config), DeviceInfo(devinfo) {
if (monitorOutput && !(nenoutchannels() > 0)) {
throw runtime_error(
"Output monitoring only possible when output is enabled");
}
// Some sanity checks
if (eninchannels.size() != 4) {
throw runtime_error("Invalid length of enabled inChannels vector");
}
if (enoutchannels.size() != 1) {
throw runtime_error("Invalid length of enabled outChannels vector");
}
}
double Daq::samplerate() const {
assert(sampleRateIndex < availableSampleRates.size());
return availableSampleRates[sampleRateIndex];
}
DataType Daq::dataType() const {
assert((us)dataTypeIndex < availableDataTypes.size());
return availableDataTypes[dataTypeIndex];
}
double Daq::inputRangeForChannel(us ch) const {
if (!(ch < ninchannels)) {
throw runtime_error("Invalid channel number");
}
assert(inputRangeIndices.size() == eninchannels.size());
return availableInputRanges[inputRangeIndices[ch]];
}
us Daq::neninchannels() const {
mutexlock lock(mutex);
us inch = std::count(eninchannels.begin(), eninchannels.end(), true);
if (monitorOutput)
inch++;
return inch;
}
us Daq::nenoutchannels() const {
mutexlock lock(mutex);
return std::count(enoutchannels.begin(), enoutchannels.end(), true);
}

View File

@ -1,6 +1,5 @@
#ifndef LASP_CPPDAQ_H
#define LASP_CPPDAQ_H
#include <strstream>
#ifdef HAS_RTAUDIO
#include <RtAudio.h>
@ -13,25 +12,29 @@
#include "lasp_cppqueue.h"
#include "string"
#include "vector"
#include <mutex>
using std::cerr;
using std::cout;
using std::endl;
using std::runtime_error;
using std::string;
using std::vector;
using std::runtime_error;
typedef unsigned int us;
typedef vector<bool> boolvec;
typedef vector<double> dvec;
typedef vector<us> usvec;
typedef std::lock_guard<std::mutex> mutexlock;
class DataType {
public:
string name;
unsigned sw;
bool is_floating;
public:
string name;
unsigned sw;
bool is_floating;
DataType(const char *name, unsigned sw, bool is_floating)
: name(name), sw(sw), is_floating(is_floating) {}
DataType():
name("invalid data type"),
sw(0),
is_floating(false) {}
DataType(const char *name, unsigned sw, bool is_floating)
: name(name), sw(sw), is_floating(is_floating) {}
DataType() : name("invalid data type"), sw(0), is_floating(false) {}
};
const DataType dtype_invalid;
@ -41,26 +44,26 @@ const DataType dtype_int16("16-bits integers", 2, false);
const DataType dtype_int32("32-bits integers", 4, false);
const std::vector<DataType> dataTypes = {
dtype_int8,
dtype_int16,
dtype_int32,
dtype_fl64,
dtype_int8,
dtype_int16,
dtype_int32,
dtype_fl64,
};
class DaqApi {
public:
string apiname = "";
unsigned apicode = 0;
unsigned api_specific_subcode = 0;
public:
string apiname = "";
unsigned apicode = 0;
unsigned api_specific_subcode = 0;
DaqApi(string apiname, unsigned apicode, unsigned api_specific_subcode = 0)
: apiname(apiname), apicode(apicode),
api_specific_subcode(api_specific_subcode) {}
DaqApi() {}
bool operator==(const DaqApi &other) const {
return (apiname == other.apiname && apicode == other.apicode &&
api_specific_subcode == other.api_specific_subcode);
}
DaqApi(string apiname, unsigned apicode, unsigned api_specific_subcode = 0)
: apiname(apiname), apicode(apicode),
api_specific_subcode(api_specific_subcode) {}
DaqApi() {}
bool operator==(const DaqApi &other) const {
return (apiname == other.apiname && apicode == other.apicode &&
api_specific_subcode == other.api_specific_subcode);
}
};
#ifdef HAS_ULDAQ_LINUX_API
@ -72,101 +75,134 @@ const DaqApi rtaudioalsaapi("RtAudio Linux ALSA", 1, RtAudio::Api::LINUX_ALSA);
const vector<DaqApi> compiledApis = {
#ifdef HAS_ULDAQ_LINUX_API
uldaqapi,
uldaqapi,
#endif
#ifdef HAS_RTAUDIO_ALSA_API
rtaudioalsaapi,
rtaudioalsaapi,
#endif
#ifdef HAS_RTAUDIO_PULSEAUDIO_API
DaqApi("RtAudio Linux Pulseaudio", 2, RtAudio::Api::LINUX_PULSE),
DaqApi("RtAudio Linux Pulseaudio", 2, RtAudio::Api::LINUX_PULSE),
#endif
#ifdef HAS_RTAUDIO_WIN_WASAPI_API
DaqApi("RtAudio Windows Wasapi", 3, RtAudio::Api::WINDOWS_WASAPI),
DaqApi("RtAudio Windows Wasapi", 3, RtAudio::Api::WINDOWS_WASAPI),
#endif
};
// Structure containing device info parameters
class DeviceInfo {
public:
DaqApi api;
string name = "";
unsigned devindex;
public:
DaqApi api;
string device_name = "";
vector<DataType> availableDataTypes;
vector<double> availableSampleRates;
vector<us> availableFramesPerBlock;
int api_specific_devindex = -1;
int prefSampleRateIndex = -1;
unsigned ninchannels = 0;
unsigned noutchannels = 0;
vector<DataType> availableDataTypes;
int prefDataTypeIndex = 0;
bool hasInputIEPE = false;
bool hasInputACCouplingSwitch = false;
bool hasInputTrigger = false;
vector<double> inputRanges;
vector<double> availableSampleRates;
int prefSampleRateIndex = -1;
/* DeviceInfo(): */
/* datatype(dtype_invalid) { } */
vector<us> availableFramesPerBlock;
unsigned prefFramesPerBlockIndex = 0;
double prefSampleRate() const {
if ((prefSampleRateIndex < availableSampleRates.size()) &&
(prefSampleRateIndex >= 0)) {
return availableSampleRates[prefSampleRateIndex];
} else {
throw std::runtime_error("No prefered sample rate available");
}
}
operator string() const {
std::stringstream str;
str << api.apiname + " " << devindex <<
" number of input channels: " << ninchannels <<
" number of output channels: " << noutchannels;
return str.str();
dvec availableInputRanges;
int prefInputRangeIndex = 0;
}
unsigned ninchannels = 0;
unsigned noutchannels = 0;
bool hasInputIEPE = false;
bool hasInputACCouplingSwitch = false;
bool hasInputTrigger = false;
/* DeviceInfo(): */
/* datatype(dtype_invalid) { } */
double prefSampleRate() const {
if (((us) prefSampleRateIndex < availableSampleRates.size()) &&
(prefSampleRateIndex >= 0)) {
return availableSampleRates[prefSampleRateIndex];
} else {
throw std::runtime_error("No prefered sample rate available");
}
}
operator string() const {
std::stringstream str;
str << api.apiname + " " << api_specific_devindex
<< " number of input channels: " << ninchannels
<< " number of output channels: " << noutchannels;
return str.str();
}
};
// Device configuration parameters
class DaqConfiguration {
public:
boolvec eninchannels; // Enabled input channels
boolvec enoutchannels; // Enabled output channels
public:
DaqApi api;
string device_name;
unsigned sampleRateIndex; // Index in list of sample rates
DataType
datatype = dtype_invalid; // Required datatype for output, should be present in the list
bool monitorOutput; // Whether the first output channel should be replicated
// to the input as the first channel
boolvec eninchannels; // Enabled input channels
boolvec enoutchannels; // Enabled output channels
unsigned nFramesPerBlock;
vector<double> inchannel_sensitivities;
vector<string> inchannel_names;
boolvec inputIEPEEnabled;
boolvec inputACCouplingMode;
boolvec inputHighRange;
// This is not necessary at the moment
/* vector<double> outchannel_sensitivities; */
vector<string> outchannel_names;
us sampleRateIndex = 0; // Index in list of sample rates
us dataTypeIndex = 0; // Required datatype for output, should be
// present in the list
us framesPerBlockIndex = 0;
bool monitorOutput = false; // Whether the first output channel should be replicated
// to the input as the first channel
boolvec inputIEPEEnabled;
boolvec inputACCouplingMode;
usvec inputRangeIndices;
// Create a default configuration, with all channels disabled on both
// input and output, and default channel names
DaqConfiguration(const DeviceInfo &device);
bool match(const DeviceInfo &devinfo) const;
};
class Daq;
class DaqDevices {
public:
static vector<DeviceInfo> getDeviceInfo();
static Daq *createDevice(const DeviceInfo &, const DaqConfiguration &config);
};
class Daq : public DaqConfiguration,public DeviceInfo {
class Daq {
mutable std::mutex mutex;
public:
virtual void start(SafeQueue<void *> *inqueue,
SafeQueue<void *> *outqueue) = 0;
public:
static vector<DeviceInfo> getDeviceInfo();
virtual void stop() = 0;
virtual double samplerate() const = 0;
virtual DataType getDataType() const = 0;
static Daq *createDevice(const DaqConfiguration &config,
const std::vector<DeviceInfo> &devinfos);
virtual ~Daq(){};
virtual us neninchannels() const = 0;
virtual us nenoutchannels() const = 0;
Daq(const DeviceInfo &devinfo, const DaqConfiguration &config);
virtual void start(SafeQueue<void *> *inqueue,
SafeQueue<void *> *outqueue) = 0;
virtual void stop() = 0;
virtual bool isRunning() const = 0;
virtual ~Daq(){};
us neninchannels() const;
us nenoutchannels() const;
double samplerate() const;
double inputRangeForChannel(us ch) const;
DataType dataType() const;
};
#endif // LASP_CPPDAQ_H

File diff suppressed because it is too large Load Diff

View File

@ -2,14 +2,6 @@
#define ULDAQ_H
#include "lasp_cppqueue.h"
#include "lasp_cppdaq.h"
#include <uldaq.h>
#include <algorithm>
#include <vector>
#include <mutex>
#include <atomic>
#include <thread>
using std::atomic;
Daq* createUlDaqDevice(const DeviceInfo& devinfo,
const DaqConfiguration& config);

View File

@ -1,8 +1,6 @@
cimport cython
from cpython.ref cimport PyObject,Py_INCREF, Py_DECREF
from .lasp_daqconfig import (Range as pyRange,
DAQChannel)
from .lasp_avtype import AvType
from .lasp_device_common import AvType
__all__ = ['Daq']

View File

View File

@ -8,10 +8,7 @@ cdef class DeviceInfo:
def api(self): return self.devinfo.api.apiname.decode('utf-8')
@property
def name(self): return self.devinfo.name.decode('utf-8')
@property
def devindex(self): return self.devinfo.devindex
def name(self): return self.devinfo.device_name.decode('utf-8')
@property
def ninchannels(self): return self.devinfo.ninchannels
@ -47,7 +44,7 @@ cdef class DeviceInfo:
@property
def inputRanges(self):
return self.devinfo.inputRanges
return self.devinfo.availableInputRanges
@staticmethod
def getDeviceInfo():
@ -60,7 +57,7 @@ cdef class DeviceInfo:
us numdevs, devno
cppDeviceInfo* devinfo
devinfos = DaqDevices.getDeviceInfo()
devinfos = cppDaq.getDeviceInfo()
numdevs = devinfos.size()
pydevinfos = []

View File

@ -8,8 +8,11 @@ from .lasp_atomic import Atomic
from threading import Thread, Condition, Lock
import numpy as np
class DAQConfiguration:
pass
import time
from .device import (Daq, DeviceInfo, DAQConfiguration,
from .device import (Daq, DeviceInfo,
# get_numpy_dtype_from_format_string,
# get_sampwidth_from_format_string,
AvType,

View File

@ -10,84 +10,80 @@ using std::endl;
int main() {
/* boolvec inChannels = {true, false, false, false}; */
boolvec inChannels = {true, true, false, false};
boolvec outChannels = {true};
double samplerate = 10000;
const us samplesPerBlock = 256;
DaqConfiguration config;
config.eninchannels = inChannels;
config.enoutchannels = outChannels;
config.inputIEPEEnabled = {false, false, false, false};
config.inputACCouplingMode = {false, false, false, false};
config.inputHighRange = {false, false, false, false};
config.sampleRateIndex = 0;
config.datatype = dtype_fl64;
config.monitorOutput = true;
config.inputIEPEEnabled = {false, false, false, false};
config.nFramesPerBlock = samplesPerBlock;
cout << "Inchannnels size: " <<config.eninchannels.size() << endl;
vector<DeviceInfo> devinfos = DaqDevices::getDeviceInfo();
DeviceInfo devinfo;
us i;
bool found = false;
for(i=0;i<devinfos.size();i++) {
if(devinfos[i].api == uldaqapi){
cout << string(devinfos[i]) << endl;
devinfo = devinfos[i];
found = true;
}
/* boolvec inChannels = {true, false, false, false}; */
auto devinfos = Daq::getDeviceInfo();
DeviceInfo devinfo;
us i;
bool found = false;
for(i=0;i<devinfos.size();i++) {
if(devinfos[i].api == uldaqapi){
cout << string(devinfos[i]) << endl;
devinfo = devinfos[i];
found = true;
}
if(!found) {
throw runtime_error("Could not find UlDaq device");
}
if(!found) {
throw runtime_error("Could not find UlDaq device");
}
DaqConfiguration config(devinfos[0]);
boolvec inChannels = {true, true, false, false};
boolvec outChannels = {true};
double samplerate = 10000;
const us samplesPerBlock = 256;
config.eninchannels = inChannels;
config.enoutchannels = outChannels;
config.sampleRateIndex = 0;
config.monitorOutput = true;
config.inputIEPEEnabled = {false, false, false, false};
cout << "Inchannnels size: " << config.eninchannels.size() << endl;
Daq* daq = Daq::createDevice(config, devinfos);
SafeQueue<void*> inqueue;
SafeQueue<void*> outqueue;
double totalTime = 5;
double t = 0;
double freq = 1000;
us nblocks = ((us) totalTime*samplerate/samplesPerBlock) + 10;
for(us i=0;i<nblocks;i++) {
double* data = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock));
for(us sample=0;sample<samplesPerBlock;sample++) {
data[sample] = sin(2*M_PI*freq*t);
t+= 1.0/samplerate;
}
outqueue.enqueue(data);
}
Daq* daq = DaqDevices::createDevice(devinfo, config);
daq->start(&inqueue, &outqueue);
SafeQueue<void*> inqueue;
SafeQueue<void*> outqueue;
std::this_thread::sleep_for(std::chrono::seconds((int) totalTime));
double totalTime = 5;
double t = 0;
double freq = 1000;
us nblocks = ((us) totalTime*samplerate/samplesPerBlock) + 10;
daq->stop();
for(us i=0;i<nblocks;i++) {
double* data = static_cast<double*>(malloc(sizeof(double)*samplesPerBlock));
for(us sample=0;sample<samplesPerBlock;sample++) {
data[sample] = sin(2*M_PI*freq*t);
t+= 1.0/samplerate;
}
outqueue.enqueue(data);
while(!inqueue.empty()) {
double* buf = (double*) inqueue.dequeue();
for(us i=0;i<samplesPerBlock;i++) {
for(us ch=0;ch<daq->neninchannels();ch++) {
cout << buf[ch*samplesPerBlock+i] << " ";
}
cout << endl;
}
free(buf);
}
while(!outqueue.empty()){
void* dat = outqueue.dequeue();
free(dat);
}
daq->start(&inqueue, &outqueue);
std::this_thread::sleep_for(std::chrono::seconds((int) totalTime));
daq->stop();
while(!inqueue.empty()) {
double* buf = (double*) inqueue.dequeue();
for(us i=0;i<samplesPerBlock;i++) {
for(us ch=0;ch<daq->neninchannels();ch++) {
cout << buf[ch*samplesPerBlock+i] << " ";
}
cout << endl;
}
free(buf);
}
while(!outqueue.empty()){
void* dat = outqueue.dequeue();
free(dat);
}
return 0;
return 0;
}