/*
* Title: PupeDiagnosticsWin.cpp
* Author: M.Thomas BEAM Ltd
* Date: 2007-02-13
*
* Contents: Status Display
*
* Mod Rec:
*
*/
#include <PupeDiagnosticsWin.h>
#include <qlayout.h>
#include <qvbox.h>
#include <qlabel.h>
#include <qtable.h>
#include <BError.h>
#include <TmsD.h>
#include <qvalidator.h>
#include <qmessagebox.h>
#include <qgroupbox.h>
#include <qvgroupbox.h>
#include <BQComboBox.h>
#include <math.h>
#include <Globals.h>
#include <qfiledialog.h>
#include <fftw3.h>
const int BUTTON_WIDTH = 200;
const int LINE_EDIT_MAX_WIDTH = 200;
const int GRAPHS_TOTAL_HEIGHT = 620;
const int GRAPHS_X_LEDGEND_HEIGHT = 50;
using namespace std;
using namespace Tms;
#define BIT(v,b) ((v >> b) & 1)
PupeDiagBitDefinition defSource0[] = {
// name startBit nBits isSigned gain
{ "fref", 63, 1, 0, 1 },
{ "PllMsb", 62, 1, 0, -1 },
{ "PhaseTableMsb", 61, 1, 0, -1 },
{ "lo1", 60, 1, 0, 1 },
{ "sigma", 32, 12, 1, 4 },
{ "lo2", 56, 1, 0, 1 },
{ "gate", 49, 1, 0, 1 },
{ "blr", 48, 1, 0, 1 },
{ "mean1", 50, 1, 0, 1 },
{ "mean2", 51, 1, 0, 1 },
{ "rfSelect1", 52, 1, 0, 1 },
{ "rfSelect2", 53, 1, 0, 1 },
{ "selFilter", 54, 1, 0, 1 },
{ "SwitchState", 44, 4, 0, 1 },
{ "dds_freq", 0, 26, 1, 64 },
{ 0,0,0,0,0 }
};
PupeDiagBitDefinition defSource1[] = {
{ "FREF", 63, 1, 0, 1 },
{ "PllMsb", 62, 1, 0, -1 },
{ "PhaseTableMsb", 61, 1, 0, -1 },
{ "LO_pulse1", 60, 1, 0, 1 },
{ "sigma", 57, 3, 1, 2048 },
{ "LO_pulse2", 56, 1, 0, 1 },
{ "mult_out1", 38, 14, 1, 1 },
{ "mult_out2", 24, 14, 1, 1 },
{ "f_error", 0, 24, 1, 1 },
{ 0,0,0,0,0 }
};
// Source = 2
PupeDiagBitDefinition defSource2[] = {
{ "FREF", 63, 1, 0, 1 },
{ "PllMsb", 62, 1, 0, -1 },
{ "PhaseTableMsb", 61, 1, 0, -1 },
{ "LO1", 60, 1, 0, 1 },
{ "sigma", 57, 3, 1, 2048 },
{ "LO2", 56, 1, 0, 1 },
{ "Gate", 55, 1, 0, 1 },
{ "B0", 32, 23, 1, 1 },
{ "Result0", 0, 32, 1, 1 },
{ 0,0,0,0,0 }
};
PupeDiagBitDefinition defSource3[] = {
{ "fref", 63, 1, 0, 1 },
{ "PllMsb", 62, 1, 0, -1 },
{ "PhaseTableMsb", 61, 1, 0, -1 },
{ "lo1", 60, 1, 0, 1 },
#ifdef ZAP
{ "hchange_temp", 59, 1, 0, 1 },
{ "hchange_switch", 58, 1, 0, 1 },
{ "ms_pulse_reg", 57, 1, 0, 1 },
#else
{ "SigmaDelayed", 57, 3, 1, 2048 },
#endif
{ "lo2", 56, 1, 0, 1 },
{ "BLR", 55, 1, 0, 1 },
{ "Gate", 54, 1, 0, 1 },
{ "Sigma", 40, 14, 1, 1 },
{ "DeltaX", 26, 14, 1, 1 },
{ "DeltaY", 12, 14, 1, 1 },
{ 0,0,0,0,0 }
};
PupeDiagBitDefinition defSigma[] = {
{ "Sigma", 40, 14, 1, 1 },
{ 0,0,0,0,0 }
};
PupeDiagBitDefinition defDeltaX[] = {
{ "DeltaX", 26, 14, 1, 1 },
{ 0,0,0,0,0 }
};
PupeDiagBitDefinition defDeltaY[] = {
{ "DeltaY", 12, 14, 1, 1 },
{ 0,0,0,0,0 }
};
PupeDiagBitDefinition defSource0trigger[] = {
{ "FREF", 7, 1, 0, 1 },
{ "HCHANGE", 6, 1, 0, 1 },
{ "INJECTION", 5, 1, 0, 1 },
{ "CAL_STOP", 4, 1, 0, 1 },
{ "CAL_START", 3, 1, 0, 1 },
{ "CYCLE_STOP", 2, 1, 0, 1 },
{ "CYCLE_START", 1, 1, 0, 1 },
{ "10MHz", 0, 1, 0, 1 },
};
typedef BArray<float> BFArray;
static ComboDefinition sourceDef[] = {
{ 0, "Source 0", 0, 1 },
{ 1, "Source 1", 1, 0 },
{ 2, "Source 2", 2, 0 },
{ 3, "Source 3", 3, 0 },
{ 4, "Sigma", 4, 0 },
{ 5, "DeltaX", 5, 0 },
{ 6, "DeltaY", 6, 0 },
{ 0,0,0,0 }
};
static ComboDefinition clockDef[] = {
{ 0, "ADC Clock", ClkAdcDiv_1, 1 },
{ 1, "ADC Clock/2", ClkAdcDiv_2, 0 },
{ 2, "ADC Clock/5", ClkAdcDiv_5, 0 },
{ 3, "ADC Clock/10", ClkAdcDiv_10, 0 },
{ 4, "ADC Clock/20", ClkAdcDiv_20, 0 },
{ 5, "ADC Clock/50", ClkAdcDiv_50, 0 },
{ 6, "ADC Clock/100", ClkAdcDiv_100, 0 },
{ 7, "ADC Clock/200", ClkAdcDiv_200, 0 },
{ 8, "ADC Clock/500", ClkAdcDiv_500, 0 },
{ 9, "ADC Clock/1000", ClkAdcDiv_1000, 0 },
{ 10, "ADC Clock/2000", ClkAdcDiv_2000, 0 },
{ 11, "ADC Clock/5000", ClkAdcDiv_5000, 0 },
{ 12, "ADC Clock/10000", ClkAdcDiv_10000, 0 },
{ 13, "ADC Clock/20000", ClkAdcDiv_20000, 0 },
{ 14, "ADC Clock/50000", ClkAdcDiv_50000, 0 },
{ 15, "ADC Clock/100000", ClkAdcDiv_100000, 0 },
{ 16, "Ms", ClkMs, 0 },
{ 17, "FREF", ClkFref, 0 },
{ 0,0,0,0 }
};
Int32 getBitValue(UInt64 value, int startBit, int nBits, int s){
Int64 v;
UInt64 bm = (1ULL << nBits) - 1;
UInt64 sm = (1ULL << (nBits - 1));
v = (value >> startBit) & bm;
if(s){
v = -(v & sm) | v;
}
return v;
}
PupeDiagnosticsWin::PupeDiagnosticsWin(QWidget* w,Control& c) : ocontrol(c) {
QVBox* mv = new QVBox(this);
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
oplots.append(new BGraph(mv));
ographControls = new BGraphControlBasic(mv);
QValidator* validator = new QIntValidator(0, (int)pow(2.0,31.0), this );
QRegExpValidator* validatorHex = new QRegExpValidator(this);
QRegExp rx;
QWidget* t = new QWidget(mv,"dataEntry");
QVGroupBox* masksG = new QVGroupBox(t);
QWidget* masks = new QWidget(masksG);
QGridLayout* v1 = new QGridLayout(masks);
QHBox* h = new QHBox(mv,"controls");
QGridLayout* v = new QGridLayout(t);
int row = 0;
int col = 0;
rx.setPattern("0x[0-9,a-f][0-9,a-f]");
validatorHex->setRegExp(rx);
orefreshButton = new QPushButton("Refresh Data",h,"refreshButton");
osaveButton = new QPushButton("Save To File",h,"saveButton");
okst = new QCheckBox(t,"");
ochannel = new QSpinBox(1,60,1,t,"");
osource = new BQComboBox(sourceDef,t,"");
oclock = new BQComboBox(clockDef,t,"");
ostartTime = new QLineEdit(t,"");ostartTime->setValidator(validator);
opostTriggerDelay = new QLineEdit(t,"");opostTriggerDelay->setValidator(validator);
v1->addWidget(oClock = new QCheckBox("Clock",masks,""),1,3);
v1->addWidget(oCycleStart = new QCheckBox("Cycle Start",masks,""),1,2);
v1->addWidget(oCycleStop = new QCheckBox("Cycle Stop",masks,""),1,1);
v1->addWidget(oCalStart = new QCheckBox("Cal Start",masks,""),1,0);
v1->addWidget(oCalStop = new QCheckBox("Cal Stop",masks,""),0,3);
v1->addWidget(oInjection = new QCheckBox("Injection",masks,""),0,2);
v1->addWidget(oHChange = new QCheckBox("H Change",masks,""),0,1);
v1->addWidget(oFref = new QCheckBox("Fref",masks,""),0,0);
v1->addWidget(oState = new QCheckBox("In State:",masks,""),2,0); // JMB
v1->addWidget(oStateV = new QSpinBox(0,15,1,masks,""),2,1); // JMB
oInjection->setChecked(true);
oStateV->setEnabled(FALSE);
otriggerSourceData = new QCheckBox(t,"");
otriggerAnd = new QCheckBox(t,"");
otriggerStore = new QCheckBox(t,"");
ostartTime->setText("0");
opostTriggerDelay->setText("0");
masksG->setTitle("Trigger Mask");
h->setMargin(4);
ochannel->setWrapping(true);
orefreshButton->setMaximumWidth(BUTTON_WIDTH);
osaveButton->setMaximumWidth(BUTTON_WIDTH);
ochannel->setMaximumWidth(LINE_EDIT_MAX_WIDTH);
osource->setMaximumWidth(LINE_EDIT_MAX_WIDTH);
oclock->setMaximumWidth(LINE_EDIT_MAX_WIDTH);
ostartTime->setMaximumWidth(LINE_EDIT_MAX_WIDTH);
opostTriggerDelay->setMaximumWidth(LINE_EDIT_MAX_WIDTH);
otriggerAnd->setMaximumWidth(LINE_EDIT_MAX_WIDTH);
otriggerStore->setMaximumWidth(LINE_EDIT_MAX_WIDTH);
otriggerSourceData->setMaximumWidth(LINE_EDIT_MAX_WIDTH);
oStateV->setMaximumWidth(LINE_EDIT_MAX_WIDTH);
col = 0;row = 0;
v->setSpacing(4); // JMB
v->addMultiCellWidget(masksG ,row,3,col+4,col+4); // JMB
v->addWidget(new QLabel("Channel",t,""),row,col); v->addWidget(ochannel,row,col+1); row++;
v->addWidget(new QLabel("Source",t,""),row,col); v->addWidget(osource,row,col+1); row++;
v->addWidget(new QLabel("Clock",t,""),row,col); v->addWidget(oclock,row,col+1); row++;
v->addWidget(new QLabel("StartTime (ms)",t,""),row,col); v->addWidget(ostartTime,row,col+1); row++;
v->addWidget(new QLabel("Post Trigger Delay (Clk)",t,""),row,col); v->addWidget(opostTriggerDelay,row,col+1); row++;
col = 2;row = 0;
v->addWidget(new QLabel("Trigger Src Data",t,""),row,col); v->addWidget(otriggerSourceData,row,col+1); row++;
v->addWidget(new QLabel("Trigger And",t,""),row,col); v->addWidget(otriggerAnd,row,col+1); row++;
v->addWidget(new QLabel("Trigger Store",t,""),row,col); v->addWidget(otriggerStore,row,col+1); row++;
v->addWidget(new QLabel("Save Format Kst",t,""),row,col); v->addWidget(okst ,row,col+1); row++;
BIter i;
for (oplots.start(i);! oplots.isEnd(i);oplots.next(i)) {
ographControls->addGraph(oplots[i]);
oplots[i]->setGrid(16,0);
oplots[i]->installEventFilter(this);
}
connect(orefreshButton,SIGNAL(clicked()),this,SLOT(refresh()));
connect(osaveButton,SIGNAL(clicked()),this,SLOT(saveFile()));
connect(oState,SIGNAL(clicked()),this,SLOT(statebuttonupdate()));
}
PupeDiagnosticsWin::~PupeDiagnosticsWin() {}
void PupeDiagnosticsWin::show() {
QWidget::show();
}
/*
* Dim or brighten the oStateV spin button according to the state of the oState
* check button.
* JMB
*/
void PupeDiagnosticsWin::statebuttonupdate() {
if (oState->isChecked())
oStateV->setEnabled(TRUE);
else
oStateV->setEnabled(FALSE);
}
void PupeDiagnosticsWin::refresh() {
BError err;
int source;
Tms::TestCaptureInfo captureInfo;
Tms::PuChannel puPhysChannel;
// Build request
source = (int)osource->getValue();
if((source == 4) || (source == 5) || (source == 6))
source = 3;
captureInfo.source = source;;
captureInfo.clock = (int)oclock->getValue();
captureInfo.startTime = ostartTime->text().toUInt();
captureInfo.postTriggerDelay = opostTriggerDelay->text().toUInt();
captureInfo.triggerSourceData = otriggerSourceData->isChecked();
// Slip in the state-qualified trigger enable. - JMB
captureInfo.triggerAnd = otriggerAnd->isChecked() | oState->isChecked() << 1; // JMB
captureInfo.triggerStore = otriggerStore->isChecked();
captureInfo.triggerMask =
oClock->isChecked() << 0 |
oCycleStart->isChecked() << 1 |
oCycleStop->isChecked() << 2 |
oCalStart->isChecked() << 3 |
oCalStop->isChecked() << 4 |
oInjection->isChecked() << 5 |
oHChange->isChecked() << 6 |
oFref->isChecked() << 7 |
oStateV->value() << 8; // JMB
if (err = ocontrol.getPuChannel (ochannel->value(),puPhysChannel)) {
warningDialog("Reading Test Data",err);
return;
}
if (err = ocontrol.getTestData(puPhysChannel,captureInfo,odata)) {
warningDialog("Reading Test Data",err);
return;
}
setPlotData();
}
void PupeDiagnosticsWin::doFft(){
BArray<float> dataIn;
BArray<float> dataOut;
int n;
fftw_complex* in;
fftw_complex* out;
fftw_plan p;
int i;
oplots[0]->getData(dataIn);
n = dataIn.size();
in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * n);
out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * n);
p = fftw_plan_dft_1d(n, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
for(i = 0; i < n; i++){
in[i][0] = dataIn[i] / 8192.0;
// in[i][0] = 1.0 * sin(100 * 3.14 * i / n) + 0.5 * sin(n / 4 * 2 * 3.14 * i / n);
in[i][1] = 0;
}
fftw_execute(p);
dataOut.resize(n);
for(i = 0; i < n; i++){
out[i][0] /= (n / 2.0);
out[i][1] /= (n / 2.0);
dataOut[i] = 10 * log10(out[i][0] * out[i][0] + out[i][1] * out[i][1]);
}
dataOut[0] = dataOut[1];
setGraphHeights(2);
oplots[1]->setData(dataOut);
oplots[0]->setXLabel("Sample");
oplots[1]->setYLabel("Power dB");
oplots[1]->setXLabel("Frequency");
fftw_destroy_plan(p);
fftw_free(in);
fftw_free(out);
}
void PupeDiagnosticsWin::setPlotData() {
BIter i;
// Bit Pattern Source 0
int source = (int)osource->getValue();
switch (source) {
case 0:
if (! otriggerStore->isChecked())
updateGraphs(defSource0);
else
updateGraphs(defSource0trigger);
break;
case 1: updateGraphs(defSource1);
break;
case 2: updateGraphs(defSource2);
break;
case 3: updateGraphs(defSource3);
break;
case 4: updateGraphs(defSigma);
doFft();
break;
case 5: updateGraphs(defDeltaX);
doFft();
break;
case 6: updateGraphs(defDeltaY);
doFft();
break;
default:
BError err;
err.set(1,"Unsupported source type");
warningDialog("Viewing Pupe Diagnostics",err);
break;
}
ographControls->setMax(odata.size());
}
void PupeDiagnosticsWin::saveFile() {
BError err;
BString fname;
BString msg;
int source = (int)osource->getValue();
int n;
fname.printf("pupeSource%d.txt",(int)osource->getValue());
QFileDialog saveDialog(
".",
"Pupe Diagnostics Dump File (*.txt)",
this,
"save file dialog",
"Choose a file" );
saveDialog.setMode(QFileDialog::QFileDialog::AnyFile);
saveDialog.setSelection(fname.retStr());
switch (n = saveDialog.exec()) {
case 0: return; //Cancel Button
break;
case 1: break; //Save Button
default: printf("Unknown Button (%d)\n",n);
}
if ((fname = saveDialog.selectedFile().ascii()) == "")
return;
if (ofile.open(fname,"w+")) {
warningDialog("PupeDiagnostics",BString("Cannot open save file (") + fname + ")");
return;
}
switch (source) {
case 0:
if (! otriggerStore->isChecked())
writeFile(defSource0);
else
writeFile(defSource0trigger);
break;
case 1: writeFile(defSource1);
break;
case 2: writeFile(defSource2);
break;
case 3: writeFile(defSource3);
break;
case 4: writeFile(defSigma);
break;
case 5: writeFile(defDeltaX);
break;
case 6: writeFile(defDeltaY);
break;
default:
BError err;
err.set(1,"Unsupported source type");
warningDialog("Viewing Pupe Diagnostics",err);
break;
}
ofile.close();
msg = BString("File Saved (") + fname + ")";
gstatusbar->message(msg.retStr(),2000);
}
// Utility routines
void PupeDiagnosticsWin::updateGraphs(PupeDiagBitDefinition sourceDefs[]) {
PupeDiagBitDefinition def;
int i = 0;
while (sourceDefs[i].name) {
def = sourceDefs[i];
oplots[i]->setData(extractBitLinear(def));
oplots[i]->setYLabel(def.name);
i++;
}
setGraphHeights(i);
setXAxisLabel();
}
BArray<float> PupeDiagnosticsWin::extractBitLinear(PupeDiagBitDefinition def) {
unsigned int n;
float f;
BArray<float> data;
data.resize(odata.size());
for(n = 0; n < odata.size(); n++){
f = getBitValue(odata[n], def.startBit, def.nBits,def.isSigned);
data[n] = def.gain * f;
}
return data;
}
void PupeDiagnosticsWin::writeFile(PupeDiagBitDefinition defs[]) {
unsigned int n;
float f;
PupeDiagBitDefinition def;
if (okst->isChecked()) {
int i = 0;
while (defs[i].name)
ofile.printf("%s ",defs[i++].name);
ofile.printf("\n");
}
for(n = 0; n < odata.size(); n++){
int i = 0;
while (defs[i].name) {
def = defs[i];
f = getBitValue(odata[n], def.startBit, def.nBits,def.isSigned);
f *= def.gain;
ofile.printf("%f ",f);
i++;
}
ofile.printf("\n");
}
}
void PupeDiagnosticsWin::setGraphHeights(int num) {
BIter i;
int height = (GRAPHS_TOTAL_HEIGHT - GRAPHS_X_LEDGEND_HEIGHT)/num;
int n = 1;
for (oplots.start(i);! oplots.isEnd(i);oplots.next(i)) {
oplots[i]->show();
if (n < num) {
oplots[i]->setMaximumHeight(height);
oplots[i]->setMinimumHeight(height);
}
else if ( n == num) {
oplots[i]->setMinimumHeight(height + GRAPHS_X_LEDGEND_HEIGHT);
}
else {
oplots[i]->hide();
oplots[i]->setMinimumHeight(height);
}
n++;
}
}
void PupeDiagnosticsWin::setXAxisLabel() {
BIter i,o;
for (oplots.start(i);! oplots.isEnd(i);oplots.next(i)) {
oplots[i]->setXLabel("");
}
for (oplots.start(i);! oplots.isEnd(i);oplots.next(i)) {
if (oplots[i]->isHidden())
break;
o = i;
}
oplots[o]->setXLabel("Sample");
}
bool PupeDiagnosticsWin::eventFilter( QObject *o, QEvent *e )
{
if ( e->type() == QEvent::Wheel ) {
QWheelEvent* we = (QWheelEvent*)e;
int delta = (we->delta() > 0) ? -1 : 1;
ographControls->scroll(delta);
return TRUE;
} else {
// standard event processing
return FALSE;
}
}
void PupeDiagnosticsWin::warningDialog(BString title, BError err){
BString m;
QMessageBox b;
m = BString("<h5>") + title + "</h5><p>" + err.getString() + "</p>";
b.setMinimumWidth(300);
b.setCaption("tmsControlGui - Warning");
b.setIcon(QMessageBox::Warning);
b.setText(m.retStr());
b.exec();
}