Implemented Interleaved streams transmit mode. Changed port rate averaging algo.

Fixes issue 12
This commit is contained in:
Srivats P. 2011-08-31 18:16:42 +05:30
parent ca4a6cb103
commit ca7a264b36
22 changed files with 745 additions and 88 deletions

View File

@ -33,6 +33,7 @@ HEADERS += \
mainwindow.h \
packetmodel.h \
port.h \
portconfigdialog.h \
portgroup.h \
portgrouplist.h \
portmodel.h \
@ -49,6 +50,7 @@ HEADERS += \
FORMS += \
about.ui \
mainwindow.ui \
portconfigdialog.ui \
portstatsfilter.ui \
portstatswindow.ui \
portswindow.ui \
@ -63,6 +65,7 @@ SOURCES += \
mainwindow.cpp \
packetmodel.cpp \
port.cpp \
portconfigdialog.cpp \
portgroup.cpp \
portgrouplist.cpp \
portmodel.cpp \

View File

@ -32,6 +32,8 @@ extern QMainWindow *mainWindow;
uint Port::mAllocStreamId = 0;
static const int kEthOverhead = 20;
uint Port::newStreamId()
{
return mAllocStreamId++;
@ -82,23 +84,36 @@ void Port::recalculateAverageRates()
double r = s->averagePacketRate();
pps += r;
bps += r * s->frameLenAvg() * 8;
bps += r * (s->frameLenAvg() + kEthOverhead) * 8;
n++;
if (s->nextWhat() == Stream::e_nw_stop)
if ((transmitMode() == OstProto::kSequentialTransmit)
&& (s->nextWhat() == Stream::e_nw_stop))
break;
}
if (n)
{
switch (transmitMode())
{
case OstProto::kSequentialTransmit:
avgPacketsPerSec_ = pps/n;
avgBitsPerSec_ = bps/n;
break;
case OstProto::kInterleavedTransmit:
avgPacketsPerSec_ = pps;
avgBitsPerSec_ = bps;
break;
default:
Q_ASSERT(false); // Unreachable!!
}
numActiveStreams_ = n;
}
else
avgPacketsPerSec_ = avgBitsPerSec_ = 0;
avgPacketsPerSec_ = avgBitsPerSec_ = numActiveStreams_ = 0;
qDebug("%s: avgPps = %g avgBps = %g", __FUNCTION__,
avgPacketsPerSec_, avgBitsPerSec_);
qDebug("%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
emit portRateChanged(mPortGroupId, mPortId);
@ -106,76 +121,145 @@ void Port::recalculateAverageRates()
void Port::setAveragePacketRate(double packetsPerSec)
{
double rate;
double pps = 0;
double bps = 0;
int n = 0;
qDebug("@%s: packetsPerSec = %g", __FUNCTION__, packetsPerSec);
qDebug("@%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
foreach (Stream* s, mStreams)
{
if (!s->isEnabled())
continue;
s->setAveragePacketRate(packetsPerSec);
switch (transmitMode())
{
case OstProto::kSequentialTransmit:
rate = s->averagePacketRate() * (packetsPerSec/avgPacketsPerSec_);
break;
case OstProto::kInterleavedTransmit:
rate = s->averagePacketRate() +
((s->averagePacketRate()/avgPacketsPerSec_) *
(packetsPerSec - avgPacketsPerSec_));
break;
default:
Q_ASSERT(false); // Unreachable!!
}
qDebug("cur stream pps = %g", s->averagePacketRate());
s->setAveragePacketRate(rate);
qDebug("new stream pps = %g", s->averagePacketRate());
double r = s->averagePacketRate();
pps += r;
bps += r * s->frameLenAvg() * 8;
bps += r * (s->frameLenAvg() + kEthOverhead) * 8;
n++;
if (s->nextWhat() == Stream::e_nw_stop)
if ((transmitMode() == OstProto::kSequentialTransmit)
&& (s->nextWhat() == Stream::e_nw_stop))
break;
}
if (n)
{
switch (transmitMode())
{
case OstProto::kSequentialTransmit:
avgPacketsPerSec_ = pps/n;
avgBitsPerSec_ = bps/n;
break;
case OstProto::kInterleavedTransmit:
avgPacketsPerSec_ = pps;
avgBitsPerSec_ = bps;
break;
default:
Q_ASSERT(false); // Unreachable!!
}
numActiveStreams_ = n;
}
else
avgPacketsPerSec_ = avgBitsPerSec_ = 0;
avgPacketsPerSec_ = avgBitsPerSec_ = numActiveStreams_ = 0;
qDebug("%s: avgPps = %g avgBps = %g", __FUNCTION__,
avgPacketsPerSec_, avgBitsPerSec_);
qDebug("%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
emit portRateChanged(mPortGroupId, mPortId);
}
void Port::setAverageBitRate(double bitsPerSec)
{
double rate;
double pps = 0;
double bps = 0;
int n = 0;
qDebug("@%s: bitsPerSec = %g", __FUNCTION__, bitsPerSec);
qDebug("@%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
foreach (Stream* s, mStreams)
{
if (!s->isEnabled())
continue;
s->setAveragePacketRate(bitsPerSec/s->frameLenAvg());
switch (transmitMode())
{
case OstProto::kSequentialTransmit:
rate = s->averagePacketRate() * (bitsPerSec/avgBitsPerSec_);
qDebug("rate = %g", rate);
break;
case OstProto::kInterleavedTransmit:
rate = s->averagePacketRate()
+ ((s->averagePacketRate()/avgPacketsPerSec_)
* ((bitsPerSec - avgBitsPerSec_)
/ ((s->frameLenAvg()+kEthOverhead)*8)));
break;
default:
Q_ASSERT(false); // Unreachable!!
}
qDebug("cur stream pps = %g", s->averagePacketRate());
s->setAveragePacketRate(rate);
qDebug("new stream pps = %g", s->averagePacketRate());
double r = s->averagePacketRate();
pps += r;
bps += r * s->frameLenAvg() * 8;
bps += r * (s->frameLenAvg() + kEthOverhead) * 8;
n++;
if (s->nextWhat() == Stream::e_nw_stop)
if ((transmitMode() == OstProto::kSequentialTransmit)
&& (s->nextWhat() == Stream::e_nw_stop))
break;
}
if (n)
{
switch (transmitMode())
{
case OstProto::kSequentialTransmit:
avgPacketsPerSec_ = pps/n;
avgBitsPerSec_ = bps/n;
break;
case OstProto::kInterleavedTransmit:
avgPacketsPerSec_ = pps;
avgBitsPerSec_ = bps;
break;
default:
Q_ASSERT(false); // Unreachable!!
}
numActiveStreams_ = n;
}
else
avgPacketsPerSec_ = avgBitsPerSec_ = 0;
qDebug("%s: avgPps = %g avgBps = %g", __FUNCTION__,
avgPacketsPerSec_, avgBitsPerSec_);
avgPacketsPerSec_ = avgBitsPerSec_ = numActiveStreams_ = 0;
qDebug("%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
emit portRateChanged(mPortGroupId, mPortId);
}
bool Port::newStreamAt(int index, OstProto::Stream const *stream)

View File

@ -45,6 +45,7 @@ class Port : public QObject {
double avgPacketsPerSec_;
double avgBitsPerSec_;
int numActiveStreams_;
QList<quint32> mLastSyncStreamList;
QList<Stream*> mStreams; // sorted by stream's ordinal value
@ -76,6 +77,8 @@ public:
{ return (d.is_enabled()?AdminEnable:AdminDisable); }
bool hasExclusiveControl()
{ return d.is_exclusive_control(); }
OstProto::TransmitMode transmitMode()
{ return d.transmit_mode(); }
double averagePacketRate()
{ return avgPacketsPerSec_; }
double averageBitRate()

View File

@ -0,0 +1,57 @@
/*
Copyright (C) 2011 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#include "portconfigdialog.h"
PortConfigDialog::PortConfigDialog(OstProto::Port &portConfig, QWidget *parent)
: QDialog(parent), portConfig_(portConfig)
{
qDebug("In %s", __FUNCTION__);
setupUi(this);
switch(portConfig_.transmit_mode())
{
case OstProto::kSequentialTransmit:
sequentialStreamsButton->setChecked(true);
break;
case OstProto::kInterleavedTransmit:
interleavedStreamsButton->setChecked(true);
break;
default:
Q_ASSERT(false); // Unreachable!!!
break;
}
exclusiveControlButton->setChecked(portConfig_.is_exclusive_control());
}
void PortConfigDialog::accept()
{
if (sequentialStreamsButton->isChecked())
portConfig_.set_transmit_mode(OstProto::kSequentialTransmit);
else if (interleavedStreamsButton->isChecked())
portConfig_.set_transmit_mode(OstProto::kInterleavedTransmit);
else
Q_ASSERT(false); // Unreachable!!!
portConfig_.set_is_exclusive_control(exclusiveControlButton->isChecked());
QDialog::accept();
}

39
client/portconfigdialog.h Normal file
View File

@ -0,0 +1,39 @@
/*
Copyright (C) 2011 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef _PORT_CONFIG_DIALOG_H
#define _PORT_CONFIG_DIALOG_H
#include "ui_portconfigdialog.h"
#include "protocol.pb.h"
#include <QDialog>
class PortConfigDialog : public QDialog, public Ui::PortConfigDialog
{
public:
PortConfigDialog(OstProto::Port &portConfig, QWidget *parent);
private:
virtual void accept();
OstProto::Port &portConfig_;
};
#endif

109
client/portconfigdialog.ui Normal file
View File

@ -0,0 +1,109 @@
<ui version="4.0" >
<class>PortConfigDialog</class>
<widget class="QDialog" name="PortConfigDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>244</width>
<height>160</height>
</rect>
</property>
<property name="windowTitle" >
<string>Port Config</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QGroupBox" name="transmitModeBox" >
<property name="title" >
<string>Transmit Mode</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QRadioButton" name="sequentialStreamsButton" >
<property name="text" >
<string>Sequential Streams</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="interleavedStreamsButton" >
<property name="text" >
<string>Interleaved Streams</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="exclusiveControlButton" >
<property name="text" >
<string>Exclusive Control</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PortConfigDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PortConfigDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -340,7 +340,7 @@ void PortGroup::processModifyStreamAck(int portIndex,
delete controller;
}
void PortGroup::modifyPort(int portIndex, bool isExclusive)
void PortGroup::modifyPort(int portIndex, OstProto::Port portConfig)
{
OstProto::PortConfigList *portConfigList = new OstProto::PortConfigList;
OstProto::Ack *ack = new OstProto::Ack;
@ -353,8 +353,8 @@ void PortGroup::modifyPort(int portIndex, bool isExclusive)
mainWindow->setDisabled(true);
OstProto::Port *port = portConfigList->add_port();
port->CopyFrom(portConfig);
port->mutable_port_id()->set_id(mPorts[portIndex]->id());
port->set_is_exclusive_control(isExclusive);
PbRpcController *controller = new PbRpcController(portConfigList, ack);
serviceStub->modifyPort(controller, portConfigList, ack,
@ -412,9 +412,10 @@ void PortGroup::processUpdatedPortConfig(PbRpcController *controller)
id = portConfigList->port(i).port_id().id();
// FIXME: don't mix port id & index into mPorts[]
mPorts[id]->updatePortConfig(portConfigList->mutable_port(i));
emit portGroupDataChanged(mPortGroupId, id);
}
emit portGroupDataChanged(mPortGroupId);
_exit:
mainWindow->setEnabled(true);

View File

@ -94,7 +94,7 @@ public:
void processDeleteStreamAck(PbRpcController *controller);
void processModifyStreamAck(int portIndex, PbRpcController *controller);
void modifyPort(int portId, bool isExclusive);
void modifyPort(int portId, OstProto::Port portConfig);
void processModifyPortAck(PbRpcController *controller);
void processUpdatedPortConfig(PbRpcController *controller);

View File

@ -296,6 +296,7 @@ void PortModel::when_portGroupDataChanged(int portGroupId, int portId)
QModelIndex index;
int row;
qDebug("portGroupId = %d, portId = %d", portGroupId, portId);
if (portId == 0xFFFF)
row = pgl->indexOfPortGroup(portGroupId);
else

View File

@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "portswindow.h"
#include "abstractfileformat.h"
#include "portconfigdialog.h"
#include "streamconfigdialog.h"
#include "streamlistdelegate.h"
@ -54,6 +55,7 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
tvPortList->addAction(actionDisconnect_Port_Group);
tvPortList->addAction(actionExclusive_Control);
tvPortList->addAction(actionPort_Configuration);
// Populate StramList Context Menu Actions
tvStreamList->addAction(actionNew_Stream);
@ -156,6 +158,8 @@ void PortsWindow::when_portView_currentChanged(const QModelIndex& current,
updatePortViewActions(current);
updateStreamViewActions();
qDebug("In %s", __FUNCTION__);
if (previous.isValid() && plm->isPort(previous))
{
disconnect(&(plm->port(previous)), SIGNAL(portRateChanged(int, int)),
@ -186,6 +190,7 @@ void PortsWindow::when_portView_currentChanged(const QModelIndex& current,
void PortsWindow::when_portModel_dataChanged(const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
qDebug("In %s", __FUNCTION__);
#if 0 // not sure why the >= <= operators are not overloaded in QModelIndex
if ((tvPortList->currentIndex() >= topLeft) &&
(tvPortList->currentIndex() <= bottomRight))
@ -195,7 +200,10 @@ void PortsWindow::when_portModel_dataChanged(const QModelIndex& topLeft,
(((tvPortList->currentIndex() < bottomRight)) ||
(tvPortList->currentIndex() == bottomRight)))
{
updatePortViewActions(tvPortList->currentIndex());
// Update UI to reflect potential change in exclusive mode,
// transmit mode et al
when_portView_currentChanged(tvPortList->currentIndex(),
tvPortList->currentIndex());
}
}
@ -223,7 +231,7 @@ void PortsWindow::on_averageBitsPerSec_editingFinished()
Q_ASSERT(plm->isPort(current));
bool isOk;
double bps = QLocale().toDouble(averageBitsPerSec->text(), &isOk)/8;
double bps = QLocale().toDouble(averageBitsPerSec->text(), &isOk);
plm->port(current).setAverageBitRate(bps);
}
@ -300,6 +308,7 @@ void PortsWindow::updatePortViewActions(const QModelIndex& current)
actionDisconnect_Port_Group->setDisabled(true);
actionExclusive_Control->setDisabled(true);
actionPort_Configuration->setDisabled(true);
goto _EXIT;
}
@ -311,6 +320,7 @@ void PortsWindow::updatePortViewActions(const QModelIndex& current)
actionDelete_Port_Group->setEnabled(true);
actionExclusive_Control->setDisabled(true);
actionPort_Configuration->setDisabled(true);
switch(plm->portGroup(current).state())
{
@ -349,6 +359,7 @@ void PortsWindow::updatePortViewActions(const QModelIndex& current)
actionExclusive_Control->setChecked(true);
else
actionExclusive_Control->setChecked(false);
actionPort_Configuration->setEnabled(true);
}
_EXIT:
@ -458,7 +469,29 @@ void PortsWindow::on_actionExclusive_Control_triggered(bool checked)
QModelIndex current = tvPortList->selectionModel()->currentIndex();
if (plm->isPort(current))
plm->portGroup(current.parent()).modifyPort(current.row(), checked);
{
OstProto::Port config;
config.set_is_exclusive_control(checked);
plm->portGroup(current.parent()).modifyPort(current.row(), config);
}
}
void PortsWindow::on_actionPort_Configuration_triggered()
{
QModelIndex current = tvPortList->selectionModel()->currentIndex();
if (!plm->isPort(current))
return;
OstProto::Port config;
config.set_transmit_mode(plm->port(current).transmitMode());
config.set_is_exclusive_control(plm->port(current).hasExclusiveControl());
PortConfigDialog dialog(config, this);
if (dialog.exec() == QDialog::Accepted)
plm->portGroup(current.parent()).modifyPort(current.row(), config);
}
void PortsWindow::on_actionNew_Stream_triggered()

View File

@ -70,6 +70,7 @@ private slots:
void on_actionDisconnect_Port_Group_triggered();
void on_actionExclusive_Control_triggered(bool checked);
void on_actionPort_Configuration_triggered();
void on_actionNew_Stream_triggered();
void on_actionEdit_Stream_triggered();

View File

@ -253,6 +253,11 @@
<string>Save Streams ...</string>
</property>
</action>
<action name="actionPort_Configuration" >
<property name="text" >
<string>Port Configuration ...</string>
</property>
</action>
</widget>
<resources>
<include location="ostinato.qrc" />

View File

@ -165,8 +165,22 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex,
//! \todo Support Goto Stream Id
leStreamId->setHidden(true);
disconnect(rbActionGotoStream, SIGNAL(toggled(bool)), leStreamId, SLOT(setEnabled(bool)));
//! \todo Support Continuous Mode
switch(mPort.transmitMode())
{
case OstProto::kSequentialTransmit:
rbModeFixed->setChecked(true);
rbModeContinuous->setDisabled(true);
break;
case OstProto::kInterleavedTransmit:
rbModeContinuous->setChecked(true);
rbModeFixed->setDisabled(true);
nextWhat->setHidden(true);
break;
default:
Q_ASSERT(false); // Unreachable
}
// Finally, restore the saved last geometry and selected tab for the
// various tab widgets
@ -1098,7 +1112,16 @@ void StreamConfigDialog::on_pbOk_clicked()
// Store dialog contents into stream
StoreCurrentStream();
if (!mpStream->preflightCheck(log))
if ((mPort.transmitMode() == OstProto::kInterleavedTransmit)
&& (mpStream->isFrameVariable()))
{
log += "In 'Interleaved Streams' transmit mode, the count for "
"varying fields at transmit time may not be same as configured\n";
}
mpStream->preflightCheck(log);
if (log.length())
{
if (QMessageBox::warning(this, "Preflight Check", log + "\nContinue?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::No)

View File

@ -42,7 +42,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<string/>
</property>
<property name="currentIndex" >
<number>2</number>
<number>0</number>
</property>
<widget class="QWidget" name="packetConfigTab" >
<attribute name="title" >
@ -146,8 +146,8 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<rect>
<x>0</x>
<y>0</y>
<width>586</width>
<height>248</height>
<width>592</width>
<height>269</height>
</rect>
</property>
<attribute name="label" >
@ -940,7 +940,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
</widget>
</item>
<item rowspan="2" row="0" column="3" >
<widget class="QGroupBox" name="groupBox_11" >
<widget class="QGroupBox" name="nextWhat" >
<property name="title" >
<string>After this stream</string>
</property>
@ -982,6 +982,19 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
</layout>
</widget>
</item>
<item rowspan="2" row="0" column="4" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>41</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" >
<widget class="QGroupBox" name="groupBox_5" >
<property name="title" >
@ -1008,14 +1021,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
</layout>
</widget>
</item>
<item row="2" column="0" colspan="4" >
<widget class="Line" name="line_4" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0" colspan="4" >
<item row="3" column="0" colspan="5" >
<widget class="QGroupBox" name="groupBox_12" >
<property name="enabled" >
<bool>true</bool>
@ -1283,12 +1289,12 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>293</x>
<y>137</y>
<x>463</x>
<y>143</y>
</hint>
<hint type="destinationlabel" >
<x>293</x>
<y>169</y>
<x>463</x>
<y>177</y>
</hint>
</hints>
</connection>
@ -1300,11 +1306,11 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<hints>
<hint type="sourcelabel" >
<x>30</x>
<y>66</y>
<y>68</y>
</hint>
<hint type="destinationlabel" >
<x>71</x>
<y>250</y>
<x>299</x>
<y>82</y>
</hint>
</hints>
</connection>
@ -1316,11 +1322,11 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<hints>
<hint type="sourcelabel" >
<x>30</x>
<y>91</y>
<y>95</y>
</hint>
<hint type="destinationlabel" >
<x>71</x>
<y>310</y>
<x>299</x>
<y>132</y>
</hint>
</hints>
</connection>
@ -1332,11 +1338,11 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<hints>
<hint type="sourcelabel" >
<x>30</x>
<y>91</y>
<y>95</y>
</hint>
<hint type="destinationlabel" >
<x>134</x>
<y>177</y>
<y>189</y>
</hint>
</hints>
</connection>
@ -1347,12 +1353,12 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>48</x>
<y>252</y>
<x>299</x>
<y>82</y>
</hint>
<hint type="destinationlabel" >
<x>39</x>
<y>278</y>
<x>299</x>
<y>108</y>
</hint>
</hints>
</connection>
@ -1363,12 +1369,12 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>51</x>
<y>303</y>
<x>299</x>
<y>132</y>
</hint>
<hint type="destinationlabel" >
<x>54</x>
<y>339</y>
<x>299</x>
<y>158</y>
</hint>
</hints>
</connection>
@ -1379,12 +1385,12 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>82</x>
<y>356</y>
<x>299</x>
<y>182</y>
</hint>
<hint type="destinationlabel" >
<x>103</x>
<y>372</y>
<x>299</x>
<y>208</y>
</hint>
</hints>
</connection>
@ -1399,8 +1405,8 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<y>70</y>
</hint>
<hint type="destinationlabel" >
<x>154</x>
<y>255</y>
<x>299</x>
<y>82</y>
</hint>
</hints>
</connection>
@ -1415,8 +1421,40 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
<y>98</y>
</hint>
<hint type="destinationlabel" >
<x>173</x>
<y>299</y>
<x>299</x>
<y>132</y>
</hint>
</hints>
</connection>
<connection>
<sender>rbModeContinuous</sender>
<signal>toggled(bool)</signal>
<receiver>leNumPackets</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>73</x>
<y>196</y>
</hint>
<hint type="destinationlabel" >
<x>164</x>
<y>108</y>
</hint>
</hints>
</connection>
<connection>
<sender>rbModeContinuous</sender>
<signal>toggled(bool)</signal>
<receiver>leNumBursts</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>96</x>
<y>199</y>
</hint>
<hint type="destinationlabel" >
<x>226</x>
<y>155</y>
</hint>
</hints>
</connection>

View File

@ -42,7 +42,12 @@ int StreamModel::rowCount(const QModelIndex &parent) const
int StreamModel::columnCount(const QModelIndex &/*parent*/) const
{
return (int) StreamMaxFields;
int count = StreamMaxFields;
if (mCurrentPort &&
(mCurrentPort->transmitMode() == OstProto::kInterleavedTransmit))
count--;
return count;
}
Qt::ItemFlags StreamModel::flags(const QModelIndex &index) const

View File

@ -58,8 +58,8 @@ class StreamModel : public QAbstractTableModel
public:
enum StreamFields {
StreamIcon = 0,
StreamName,
StreamStatus,
StreamName,
StreamNextWhat,
StreamMaxFields

View File

@ -151,6 +151,11 @@ message StreamIdList {
repeated StreamId stream_id = 2;
}
enum TransmitMode {
kSequentialTransmit = 0;
kInterleavedTransmit = 1;
}
message Port {
required PortId port_id = 1;
optional string name = 2;
@ -158,6 +163,7 @@ message Port {
optional string notes = 4;
optional bool is_enabled = 5;
optional bool is_exclusive_control = 6;
optional TransmitMode transmit_mode = 7 [default = kSequentialTransmit];
}
message PortConfigList {

View File

@ -17,12 +17,16 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#define __STDC_FORMAT_MACROS
#include "abstractport.h"
#include <QString>
#include <QIODevice>
#include "../common/streambase.h"
#include <inttypes.h>
#include <limits.h>
#include <math.h>
AbstractPort::AbstractPort(int id, const char *device)
@ -65,6 +69,9 @@ bool AbstractPort::modify(const OstProto::Port &port)
data_.set_is_exclusive_control(val);
}
if (port.has_transmit_mode())
data_.set_transmit_mode(port.transmit_mode());
return ret;
}
@ -112,6 +119,22 @@ bool AbstractPort::deleteStream(int streamId)
}
void AbstractPort::updatePacketList()
{
switch(data_.transmit_mode())
{
case OstProto::kSequentialTransmit:
updatePacketListSequential();
break;
case OstProto::kInterleavedTransmit:
updatePacketListInterleaved();
break;
default:
Q_ASSERT(false); // Unreachable!!!
break;
}
}
void AbstractPort::updatePacketListSequential()
{
int len;
bool isVariable;
@ -237,7 +260,8 @@ void AbstractPort::updatePacketList()
returnToQIdx = 0;
*/
setPacketListLoopMode(true, streamList_[i]->sendUnit() ==
setPacketListLoopMode(true, 0,
streamList_[i]->sendUnit() ==
StreamBase::e_su_bursts ? ibg1 : ipg1);
goto _stop_no_more_pkts;
@ -257,6 +281,225 @@ _stop_no_more_pkts:
isSendQueueDirty_ = false;
}
void AbstractPort::updatePacketListInterleaved()
{
int numStreams = 0;
quint64 minGap = ULONG_LONG_MAX;
quint64 duration = quint64(1e9);
QList<quint64> ibg1, ibg2;
QList<quint64> nb1, nb2;
QList<quint64> ipg1, ipg2;
QList<quint64> np1, np2;
QList<ulong> schedSec, schedNsec;
QList<ulong> pktCount, burstCount;
QList<ulong> burstSize;
QList<bool> isVariable;
QList<QByteArray> pktBuf;
QList<ulong> pktLen;
qDebug("In %s", __FUNCTION__);
// First sort the streams by ordinalValue
qSort(streamList_.begin(), streamList_.end(), StreamBase::StreamLessThan);
clearPacketList();
for (int i = 0; i < streamList_.size(); i++)
{
if (!streamList_[i]->isEnabled())
continue;
double numBursts = 0;
double numPackets = 0;
quint64 _burstSize;
double ibg = 0;
quint64 _ibg1 = 0, _ibg2 = 0;
quint64 _nb1 = 0, _nb2 = 0;
double ipg = 0;
quint64 _ipg1 = 0, _ipg2 = 0;
quint64 _np1 = 0, _np2 = 0;
switch (streamList_[i]->sendUnit())
{
case OstProto::StreamControl::e_su_bursts:
numBursts = streamList_[i]->burstRate();
if (streamList_[i]->burstRate() > 0)
{
ibg = 1e9/double(streamList_[i]->burstRate());
_ibg1 = quint64(ceil(ibg));
_ibg2 = quint64(floor(ibg));
_nb1 = quint64((ibg - double(_ibg2)) * double(numBursts));
_nb2 = quint64(numBursts) - _nb1;
_burstSize = streamList_[i]->burstSize();
}
break;
case OstProto::StreamControl::e_su_packets:
numPackets = streamList_[i]->packetRate();
if (streamList_[i]->packetRate() > 0)
{
ipg = 1e9/double(streamList_[i]->packetRate());
_ipg1 = llrint(ceil(ipg));
_ipg2 = quint64(floor(ipg));
_np1 = quint64((ipg - double(_ipg2)) * double(numPackets));
_np2 = quint64(numPackets) - _np1;
_burstSize = 1;
}
break;
default:
qWarning("Unhandled stream control unit %d",
streamList_[i]->sendUnit());
continue;
}
qDebug("numBursts = %g, numPackets = %g\n", numBursts, numPackets);
qDebug("ibg = %g", ibg);
qDebug("ibg1 = %" PRIu64, _ibg1);
qDebug("nb1 = %" PRIu64, _nb1);
qDebug("ibg2 = %" PRIu64, _ibg2);
qDebug("nb2 = %" PRIu64 "\n", _nb2);
qDebug("ipg = %g", ipg);
qDebug("ipg1 = %" PRIu64, _ipg1);
qDebug("np1 = %" PRIu64, _np1);
qDebug("ipg2 = %" PRIu64, _ipg2);
qDebug("np2 = %" PRIu64 "\n", _np2);
if (_ibg2 && (_ibg2 < minGap))
minGap = _ibg2;
if (_ibg1 && (_ibg1 > duration))
duration = _ibg1;
ibg1.append(_ibg1);
ibg2.append(_ibg2);
nb1.append(_nb1);
nb2.append(_nb1);
burstSize.append(_burstSize);
if (_ipg2 && (_ipg2 < minGap))
minGap = _ipg2;
if (_np1)
{
if (_ipg1 && (_ipg1 > duration))
duration = _ipg1;
}
else
{
if (_ipg2 && (_ipg2 > duration))
duration = _ipg2;
}
ipg1.append(_ipg1);
ipg2.append(_ipg2);
np1.append(_np1);
np2.append(_np1);
schedSec.append(0);
schedNsec.append(0);
pktCount.append(0);
burstCount.append(0);
if (streamList_[i]->isFrameVariable())
{
isVariable.append(true);
pktBuf.append(QByteArray());
pktLen.append(0);
}
else
{
isVariable.append(false);
pktBuf.append(QByteArray());
pktBuf.last().resize(kMaxPktSize);
pktLen.append(streamList_[i]->frameValue(
(uchar*)pktBuf.last().data(), pktBuf.last().size(), 0));
}
numStreams++;
} // for i
qDebug("minGap = %" PRIu64, minGap);
qDebug("duration = %" PRIu64, duration);
uchar* buf;
int len;
quint64 durSec = duration/ulong(1e9);
quint64 durNsec = duration % ulong(1e9);
quint64 sec = 0;
quint64 nsec = 0;
quint64 lastPktTxSec = 0;
quint64 lastPktTxNsec = 0;
do
{
for (int i = 0; i < numStreams; i++)
{
// If a packet is not scheduled yet, look at the next stream
if ((schedSec.at(i) > sec) || (schedNsec.at(i) > nsec))
continue;
for (uint j = 0; j < burstSize[i]; j++)
{
if (isVariable.at(i))
{
buf = pktBuf_;
len = streamList_[i]->frameValue(pktBuf_, sizeof(pktBuf_),
pktCount[i]);
}
else
{
buf = (uchar*) pktBuf.at(i).data();
len = pktLen.at(i);
}
if (len <= 0)
continue;
qDebug("q(%d) sec = %" PRIu64 " nsec = %" PRIu64, i, sec, nsec);
appendToPacketList(sec, nsec, buf, len);
lastPktTxSec = sec;
lastPktTxNsec = nsec;
pktCount[i]++;
schedNsec[i] += (pktCount.at(i) < np1.at(i)) ?
ipg1.at(i) : ipg2.at(i);
while (schedNsec.at(i) >= 1e9)
{
schedSec[i]++;
schedNsec[i] -= long(1e9);
}
}
burstCount[i]++;
schedNsec[i] += (burstCount.at(i) < nb1.at(i)) ?
ibg1.at(i) : ibg2.at(i);
while (schedNsec.at(i) >= 1e9)
{
schedSec[i]++;
schedNsec[i] -= long(1e9);
}
}
nsec += minGap;
while (nsec >= 1e9)
{
sec++;
nsec -= long(1e9);
}
} while ((sec < durSec) || (nsec < durNsec));
quint64 delaySec = durSec - lastPktTxSec;
quint64 delayNsec = durNsec - lastPktTxNsec;
qDebug("loop Delay = %" PRIu64 "/%" PRIu64, delaySec, delayNsec);
setPacketListLoopMode(true, durSec - lastPktTxSec, durNsec - lastPktTxNsec);
isSendQueueDirty_ = false;
}
void AbstractPort::stats(PortStats *stats)
{
stats->rxPkts = stats_.rxPkts - epochStats_.rxPkts;

View File

@ -73,7 +73,8 @@ public:
virtual void clearPacketList() = 0;
virtual bool appendToPacketList(long sec, long nsec, const uchar *packet,
int length) = 0;
virtual void setPacketListLoopMode(bool loop, long nsecDelay) = 0;
virtual void setPacketListLoopMode(bool loop,
long secDelay, long nsecDelay) = 0;
void updatePacketList();
virtual void startTransmit() = 0;
@ -89,6 +90,9 @@ public:
void resetStats() { epochStats_ = stats_; }
protected:
void updatePacketListSequential();
void updatePacketListInterleaved();
bool isUsable_;
OstProto::Port data_;
OstProto::LinkState linkState_;

View File

@ -24,6 +24,7 @@ win32 {
LIBS += -L"../rpc" -lpbrpc
POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a"
}
LIBS += -lm
LIBS += -lprotobuf
LIBS += -L"../extra/qhexedit2/$(OBJECTS_DIR)/" -lqhexedit2
RESOURCES += drone.qrc

View File

@ -295,7 +295,7 @@ void PcapPort::PortTransmitter::clearPacketList()
pcap_send_queue *sq = sendQueueList_.takeFirst();
pcap_sendqueue_destroy(sq);
}
setPacketListLoopMode(false, 0);
setPacketListLoopMode(false, 0, 0);
}
bool PcapPort::PortTransmitter::appendToPacketList(long sec, long nsec,

View File

@ -40,14 +40,15 @@ public:
virtual void clearPacketList() {
transmitter_->clearPacketList();
setPacketListLoopMode(false, 0);
setPacketListLoopMode(false, 0, 0);
}
virtual bool appendToPacketList(long sec, long nsec, const uchar *packet,
int length) {
return transmitter_->appendToPacketList(sec, nsec, packet, length);
}
virtual void setPacketListLoopMode(bool loop, long nsecDelay) {
transmitter_->setPacketListLoopMode(loop, nsecDelay);
virtual void setPacketListLoopMode(bool loop, long secDelay, long nsecDelay)
{
transmitter_->setPacketListLoopMode(loop, secDelay, nsecDelay);
}
virtual void startTransmit() {
@ -97,9 +98,9 @@ protected:
void clearPacketList();
bool appendToPacketList(long sec, long usec, const uchar *packet,
int length);
void setPacketListLoopMode(bool loop, long nsecDelay) {
void setPacketListLoopMode(bool loop, long secDelay, long nsecDelay) {
returnToQIdx_ = loop ? 0 : -1;
loopDelay_ = nsecDelay/1000;
loopDelay_ = secDelay*long(1e6) + nsecDelay/1000;
}
void setHandle(pcap_t *handle);
void useExternalStats(AbstractPort::PortStats *stats);