//Author:    Timothy Pearson <kb9vqf@pearsoncomputing.net>, (C) 2012
//Copyright: See COPYING file that comes with this distribution

#include "define.h"
#include "part.h"

#include <tdeaboutdata.h>   //::createAboutData()
#include <tdeaction.h>
#include <tdelocale.h>
#include <tdemessagebox.h>  //::start()
#include <tdeparts/genericfactory.h>
#include <kstatusbar.h>
#include <kstdaction.h>
#include <tqfile.h>        //encodeName()
#include <tqtimer.h>
#include <tqvbox.h>
#include <tqsocket.h>
#include <tqmutex.h>
#include <tqeventloop.h>
#include <tqapplication.h>
#include <unistd.h>       //access()
#include <stdint.h>
#include <cmath>

#include "tracewidget.h"
#include "floatspinbox.h"
#include "layout.h"

#define NETWORK_COMM_TIMEOUT_MS 15000

/* exception handling */
struct exit_exception {
	int c;
	exit_exception(int c):c(c) { }
};

namespace RemoteLab {

typedef KParts::GenericFactory<RemoteLab::CommAnalyzerPart> Factory;
#define CLIENT_LIBRARY "libremotelab_commanalyzer"
K_EXPORT_COMPONENT_FACTORY( libremotelab_commanalyzer, RemoteLab::Factory )


CommAnalyzerPart::CommAnalyzerPart( TQWidget *parentWidget, const char *widgetName, TQObject *parent, const char *name, const TQStringList& )
	: RemoteInstrumentPart( parent, name ), m_traceWidget(0), m_commHandlerState(-1), m_commHandlerMode(0), m_commHandlerCommandState(0), m_connectionActiveAndValid(false),
	m_base(0), stopTraceUpdate(false)
{
	// Initialize important base class variables
	m_clientLibraryName = CLIENT_LIBRARY;

	// Initialize mutex
	m_instrumentMutex = new TQMutex(false);

	// Initialize kpart
	setInstance(Factory::instance());
	setWidget(new TQVBox(parentWidget, widgetName));

	// Create timers
	m_forcedUpdateTimer = new TQTimer(this);
	connect(m_forcedUpdateTimer, SIGNAL(timeout()), this, SLOT(mainEventLoop()));
	m_updateTimeoutTimer = new TQTimer(this);
	connect(m_updateTimeoutTimer, SIGNAL(timeout()), this, SLOT(mainEventLoop()));

	// Create widgets
	m_base = new CommAnalyzerBase(widget());
	m_traceWidget = m_base->traceWidget;
	m_traceWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding));
	m_traceWidget->setTraceEnabled(0, true);
	m_traceWidget->setTraceName(0, "Trace 1");
	m_traceWidget->setTraceHorizontalUnits(0, "Hz");
	m_traceWidget->setTraceVerticalUnits(0, "dBm");
	m_traceWidget->setNumberOfCursors(4);
	m_traceWidget->setCursorOrientation(0, TQt::Horizontal);
	m_traceWidget->setCursorOrientation(1, TQt::Horizontal);
	m_traceWidget->setCursorOrientation(2, TQt::Vertical);
	m_traceWidget->setCursorOrientation(3, TQt::Vertical);
	m_traceWidget->setCursorEnabled(0, true);
	m_traceWidget->setCursorEnabled(1, true);
	m_traceWidget->setCursorEnabled(2, true);
	m_traceWidget->setCursorEnabled(3, true);
	m_traceWidget->setCursorName(0, "Cursor H1");
	m_traceWidget->setCursorName(1, "Cursor H2");
	m_traceWidget->setCursorName(2, "Cursor V1");
	m_traceWidget->setCursorName(3, "Cursor V2");
	m_traceWidget->setCursorPosition(0, 25);
	m_traceWidget->setCursorPosition(1, 75);
	m_traceWidget->setCursorPosition(2, 25);
	m_traceWidget->setCursorPosition(3, 75);
	m_traceWidget->setZoomBoxEnabled(true);

	m_base->traceZoomWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding));
	m_base->traceZoomWidget->setTraceEnabled(0, true, false);
	m_base->traceZoomWidget->setTraceName(0, "Trace 1");
	m_base->traceZoomWidget->setTraceHorizontalUnits(0, "Hz");
	m_base->traceZoomWidget->setTraceVerticalUnits(0, "dBm");
	connect(m_traceWidget, SIGNAL(zoomBoxChanged(const TQRectF&)), this, SLOT(updateZoomWidgetLimits(const TQRectF&)));
	connect(m_traceWidget, SIGNAL(offsetChanged(uint, double)), m_base->traceZoomWidget, SLOT(setTraceOffset(uint, double)));

	m_base->saRefLevel->setSizePolicy(TQSizePolicy(TQSizePolicy::Fixed, TQSizePolicy::Fixed));
	m_base->saRefLevel->setFloatMin(-128);
	m_base->saRefLevel->setFloatMax(128);
	m_base->saRefLevel->setLineStep(1);

	connect(m_base->saRefLevel, SIGNAL(floatValueChanged(double)), this, SLOT(saRefLevelChanged(double)));

	TQTimer::singleShot(0, this, TQT_SLOT(postInit()));
}

CommAnalyzerPart::~CommAnalyzerPart() {
	if (m_instrumentMutex->locked()) {
		printf("[WARNING] Exiting when data transfer still in progress!\n\r"); fflush(stdout);
	}

	disconnectFromServer();
	delete m_instrumentMutex;
}

void CommAnalyzerPart::postInit() {
	setUsingFixedSize(false);
}

bool CommAnalyzerPart::openURL(const KURL &url) {
	int ret;
	m_connectionActiveAndValid = false;
	ret = connectToServer(url.url());
	processLockouts();
	return (ret != 0);
}

bool CommAnalyzerPart::closeURL() {
	disconnectFromServer();
	m_url = KURL();
	return true;
}

void CommAnalyzerPart::processLockouts() {
	if (m_connectionActiveAndValid) {
		m_base->setEnabled(true);
	}
	else {
		m_base->setEnabled(false);
	}
}

void CommAnalyzerPart::disconnectFromServerCallback() {
	m_forcedUpdateTimer->stop();
	m_updateTimeoutTimer->stop();
	m_connectionActiveAndValid = false;
}

void CommAnalyzerPart::connectionFinishedCallback() {
	connect(m_socket, SIGNAL(readyRead()), m_socket, SLOT(processPendingData()));
	m_socket->processPendingData();
	connect(m_socket, SIGNAL(newDataReceived()), this, SLOT(mainEventLoop()));
	m_tickerState = 0;
	m_commHandlerState = 0;
	m_commHandlerMode = 0;
	m_socket->setDataTimeout(NETWORK_COMM_TIMEOUT_MS);
	m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
	processLockouts();
	mainEventLoop();
	return;
}

void CommAnalyzerPart::connectionStatusChangedCallback() {
	processLockouts();
}

void CommAnalyzerPart::setTickerMessage(TQString message) {
	m_connectionActiveAndValid = true;
	TQString tickerChar;
	switch (m_tickerState) {
		case 0:
			tickerChar = "-";
			break;
		case 1:
			tickerChar = "\\";
			break;
		case 2:
			tickerChar = "|";
			break;
		case 3:
			tickerChar = "/";
			break;
	}
	setStatusMessage(message + TQString("... %1").arg(tickerChar));
	m_tickerState++;
	if (m_tickerState > 3) {
		m_tickerState = 0;
	}
}

#define UPDATEDISPLAY_TIMEOUT		m_connectionActiveAndValid = false;														\
					m_tickerState = 0;																\
					m_commHandlerState = 2;																\
					m_commHandlerMode = 0;																\
					m_socket->clearIncomingData();															\
					setStatusMessage(i18n("Server ping timeout.  Please verify the status of your network connection."));						\
					m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);											\
					m_instrumentMutex->unlock();															\
					return;

#define COMMUNICATIONS_FAILED		m_connectionActiveAndValid = false;														\
					m_tickerState = 0;																\
					m_commHandlerState = 2;																\
					m_commHandlerMode = 0;																\
					m_socket->clearIncomingData();															\
					setStatusMessage(i18n("Instrument communication failure.  Please verify the status of your network connection."));				\
					m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);											\
					m_instrumentMutex->unlock();															\
					return;

#define SET_WATCHDOG_TIMER		if (!m_updateTimeoutTimer->isActive()) m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);
#define PAT_WATCHDOG_TIMER		m_updateTimeoutTimer->stop(); m_updateTimeoutTimer->start(NETWORK_COMM_TIMEOUT_MS, TRUE);							\
					setTickerMessage(i18n("Connected"));

#define SET_NEXT_STATE(x)		if (m_commHandlerMode == 0) {															\
						m_commHandlerState = x;															\
					}																		\
					else {																		\
						m_commHandlerState = 255;														\
					}

#define EXEC_NEXT_STATE_IMMEDIATELY	m_forcedUpdateTimer->start(0, TRUE);

void CommAnalyzerPart::mainEventLoop() {
	TQDataStream ds(m_socket);
	ds.setPrintableData(true);

	if (!m_instrumentMutex->tryLock()) {
		EXEC_NEXT_STATE_IMMEDIATELY
		return;
	}

	if (m_socket) {
		if ((m_commHandlerMode == 0) || (m_commHandlerMode == 1)) {
			if (m_commHandlerState == 0) {
				// Request communications analyzer access
				ds << TQString("COMMUNICATIONS ANALYZER");
				m_socket->writeEndOfFrame();

				m_commHandlerState = 1;
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 1) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER
	
					// Get command status
					TQString result;
					ds >> result;
					m_socket->clearFrameTail();
	
					if (result == "ACK") {
						SET_NEXT_STATE(2)
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 2) {
				// Set spectrum analyzer mode
				ds << TQString("SETMODESPECTRUMANALYZER");
				m_socket->writeEndOfFrame();

				SET_NEXT_STATE(3)
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 3) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER
	
					// Get command status
					TQString result;
					ds >> result;
					m_socket->clearFrameTail();
	
					if (result == "ACK") {
						SET_NEXT_STATE(4)
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 4) {
				// Get number of samples in trace, step 1
				ds << TQString("GETTRACESAMPLECOUNT");
				m_socket->writeEndOfFrame();

				SET_NEXT_STATE(5)
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 5) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER
	
					// Get number of samples in trace, step 2
					TQString result;
					ds >> result;
					if (result == "ACK") {
						ds >> m_samplesInTrace;
					}
					m_socket->clearFrameTail();
	
					if (result == "ACK") {	
						SET_NEXT_STATE(6)
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 6) {
				// Get number of horizontal divisions, step 1
				ds << TQString("GETHORIZONTALDIVCOUNT");
				m_socket->writeEndOfFrame();

				SET_NEXT_STATE(7)
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 7) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER

					// Get number of horizontal divisions, step 2
					TQString result;
					ds >> result;
					if (result == "ACK") {
						ds >> m_hdivs;
					}
					m_socket->clearFrameTail();

					if (result == "ACK") {
						SET_NEXT_STATE(8)
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 8) {
				// Get number of vertical divisions, step 1
				ds << TQString("GETVERTICALDIVCOUNT");
				m_socket->writeEndOfFrame();

				SET_NEXT_STATE(9)
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 9) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER

					// Get number of vertical divisions, step 2
					TQString result;
					ds >> result;
					if (result == "ACK") {
						ds >> m_vdivs;
					}
					m_socket->clearFrameTail();
	
					if (result == "ACK") {
						SET_NEXT_STATE(10)
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 10) {
				// Get reference power level, step 1
				ds << TQString("GETREFERENCEPOWERLEVEL");
				m_socket->writeEndOfFrame();

				SET_NEXT_STATE(11)
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 11) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER
	
					// Get reference power level, step 2
					TQString result;
					ds >> result;
					if (result == "ACK") {
						ds >> m_rpower;
					}
					m_socket->clearFrameTail();
	
					if (result == "ACK") {
						SET_NEXT_STATE(12)
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 12) {
				// Get vertical division scale, step 1
				ds << TQString("GETVERTDIVSCALE");
				m_socket->writeEndOfFrame();

				SET_NEXT_STATE(13)
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 13) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER

					// Get vertical division scale, step 2
					TQString result;
					ds >> result;
					if (result == "ACK") {
						ds >> m_vscale;
					}
					m_socket->clearFrameTail();
	
					if (result == "ACK") {
						SET_NEXT_STATE(14)
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 14) {
				// Get center frequency, step 1
				ds << TQString("GETCENTERFREQUENCY");
				m_socket->writeEndOfFrame();

				SET_NEXT_STATE(15)
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 15) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER
	
					// Get center frequency, step 2
					TQString result;
					ds >> result;
					if (result == "ACK") {
						ds >> m_centerfreq;
					}
					m_socket->clearFrameTail();
	
					if (result == "ACK") {
						SET_NEXT_STATE(16)
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 16) {
				// Get frequency span, step 1
				ds << TQString("GETFREQUENCYSPAN");
				m_socket->writeEndOfFrame();

				SET_NEXT_STATE(17)
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 17) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER

					// Get frequency span, step 2
					TQString result;
					ds >> result;
					if (result == "ACK") {
						ds >> m_spanfreq;
					}
					m_socket->clearFrameTail();
	
					if (result == "ACK") {
						// Update display widget(s)
						updateGraticule();
					}

					if (result == "ACK") {
						SET_NEXT_STATE(18)
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 18) {
				// Get trace, step 1
				ds << TQString("GETSPECTRUMTRACE");
				m_socket->writeEndOfFrame();

				SET_NEXT_STATE(19)
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerState == 19) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER

					// Get trace, step 2
					TQDoubleArray trace;
					TQString result;
					ds >> result;
					if (result == "ACK") {
						ds >> trace;
					}
					m_socket->clearFrameTail();

					if (result == "ACK") {
#if 1
						// Trace grab is slow on most instruments
						// Put in the next trace request before processing the trace we just got so as to increase the overall update rate
						if (m_commHandlerMode == 0) {
							// Get trace, step 1
							ds << TQString("GETSPECTRUMTRACE");
							m_socket->writeEndOfFrame();
						}
						
#endif
						// Update display widget(s)
						m_traceWidget->setSamples(0, trace);
						m_base->traceZoomWidget->setSamples(0, trace);
						postProcessTrace();
						m_traceWidget->repaint(false);
						m_base->traceZoomWidget->repaint(false);
					}


					if (result == "ACK") {
#if 0
						//SET_NEXT_STATE(2)
						SET_NEXT_STATE(18)
						EXEC_NEXT_STATE_IMMEDIATELY
#else
						SET_NEXT_STATE(19)
						EXEC_NEXT_STATE_IMMEDIATELY
#endif
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerState == 255) {
				// Execute pending command
				m_commHandlerMode = 2;
				m_socket->clearIncomingData();
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			SET_WATCHDOG_TIMER
		}
		else if (m_commHandlerMode == 2) {
			if (m_commHandlerCommandState == 0) {
				m_commHandlerMode = 0;
				m_commHandlerState = 10;
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerCommandState == 1) {
				// Set reference power level
				ds << TQString("SETREFERENCEPOWERLEVEL");
				ds << m_rpower;
				m_socket->writeEndOfFrame();

				m_commHandlerCommandState = 2;
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerCommandState == 2) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER

					// Set reference power level, step 2
					TQString result;
					ds >> result;
					m_socket->clearFrameTail();
	
					if (result == "ACK") {
						m_commHandlerCommandState = 3;
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
			else if (m_commHandlerCommandState == 3) {
				// Get reference power level, step 1
				ds << TQString("GETREFERENCEPOWERLEVEL");
				m_socket->writeEndOfFrame();

				m_commHandlerCommandState = 4;
				EXEC_NEXT_STATE_IMMEDIATELY
			}
			else if (m_commHandlerCommandState == 4) {
				// Get response data
				if (m_socket->canReadFrame()) {
					PAT_WATCHDOG_TIMER

					// Get reference power level, step 2
					TQString result;
					ds >> result;
					if (result == "ACK") {
						ds >> m_rpower;
					}
					m_socket->clearFrameTail();

					// Update display as needed
					updateGraticule();

					if (result == "ACK") {
						m_commHandlerCommandState = 0;
						EXEC_NEXT_STATE_IMMEDIATELY
					}
					else {
						COMMUNICATIONS_FAILED
					}
				}
				else {
					if (!m_updateTimeoutTimer->isActive()) {
						UPDATEDISPLAY_TIMEOUT
					}
				}
			}
		}
	}
	else {
		m_commHandlerState = 0;
		m_commHandlerCommandState = 0;
	}

	processLockouts();

	m_instrumentMutex->unlock();
}

void CommAnalyzerPart::postProcessTrace() {
	return;
}

void CommAnalyzerPart::updateZoomWidgetLimits(const TQRectF& zoomRect) {
	TQRectF fullZoomRect = m_traceWidget->displayLimits(0);
	double widthSpan = fullZoomRect.width()-fullZoomRect.x();
	double heightSpan = fullZoomRect.height()-fullZoomRect.y();

	TQRectF zoomLimitsRect((fullZoomRect.x()+(widthSpan*(zoomRect.x()/100.0))), (fullZoomRect.y()+(heightSpan*(zoomRect.y()/100.0))), (fullZoomRect.x()+(widthSpan*((zoomRect.x()/100.0)+(zoomRect.width()/100.0)))), (fullZoomRect.y()+(heightSpan*((zoomRect.y()/100.0)+(zoomRect.height()/100.0)))));

	m_base->traceZoomWidget->setDisplayLimits(0, zoomLimitsRect);
}

void CommAnalyzerPart::updateGraticule() {
	m_traceWidget->setNumberOfSamples(0, m_samplesInTrace);
	m_traceWidget->setNumberOfHorizontalDivisions(m_hdivs);
	m_traceWidget->setNumberOfVerticalDivisions(m_vdivs);
	m_base->traceZoomWidget->setNumberOfSamples(0, m_samplesInTrace);
	m_base->traceZoomWidget->setNumberOfHorizontalDivisions(m_hdivs);
	m_base->traceZoomWidget->setNumberOfVerticalDivisions(m_vdivs);

	m_leftFrequency = m_centerfreq - (m_spanfreq/2.0);
	m_rightFrequency = m_centerfreq + (m_spanfreq/2.0);

	double freqincr = (m_rightFrequency-m_leftFrequency)/m_samplesInTrace;
	double freqpos = m_leftFrequency;
	TQDoubleArray tracepositions;
	tracepositions.resize(m_samplesInTrace);
	for (int i=0; i<m_samplesInTrace; i++) {
		tracepositions[i] = freqpos;
		freqpos = freqpos + freqincr;
	}
	m_traceWidget->setPositions(0, tracepositions);
	m_traceWidget->setDisplayLimits(0, TQRectF(m_leftFrequency, m_rpower, m_rightFrequency, m_rpower-(m_vscale*m_vdivs)));
	m_base->traceZoomWidget->setPositions(0, tracepositions);
	updateZoomWidgetLimits(m_traceWidget->zoomBox());

	// Also update controls
	m_base->saRefLevel->blockSignals(true);
	m_base->saRefLevel->setFloatValue(m_rpower);
	m_base->saRefLevel->blockSignals(false);
}

void CommAnalyzerPart::saRefLevelChanged(double newval) {
	if (m_commHandlerMode < 2) {
		m_rpower = newval;
		m_commHandlerMode = 1;
		m_commHandlerCommandState = 1;
		mainEventLoop();
	}
}

TDEAboutData* CommAnalyzerPart::createAboutData() {
	return new TDEAboutData( APP_NAME, I18N_NOOP( APP_PRETTYNAME ), APP_VERSION );
}

} //namespace RemoteLab

#include "part.moc"
