#include "AVReceiverDevice.h" #include "GlobalDefine.h" #include "ProtocolDefs.h" #include /** Command syntax @ SUBUNIT : FUNCNAME = Parameter [CR/LF] [1] [2] [3] [4] [5] [6] [7] [1] Start Delimiter (@) : The beginning of a command [2] Sub Unit Name : Indicating whether the command is for System, any zones or any internal input sources as iPod, Tuner, Sirius, and Rhapsody etc [3] Command Delimiter (:) : Sub Unit Name and Function name are separated by this delimiter [4] Function Name : Specifying actual operations, some of them are abbreviated [5] Parameter Delimiter (=) : Separating the Function Name and its Parameter (Value) [6] Parameter : Showing a parameter value of the command [7] End Delimiter : The end of a command, Carriage */ CAVReceiverDevice::CAVReceiverDevice() { mReceiverSocket = new QTcpSocket; mDisconnectTimer = new QTimer; mStateRequestTimer = new QTimer; // mSyncDelayTimer = new QTimer; mDisconnectTimer->setSingleShot(true); mDisconnectTimer->stop(); mStateRequestTimer->setSingleShot(true); mStateRequestTimer->setInterval(RECEIVER_STATE_UPDATE_TIMEOUT); // mSyncDelayTimer->setSingleShot(true); // mSyncDelayTimer->setInterval(500); connect(mDisconnectTimer,SIGNAL(timeout()),this,SLOT(DisconnectTimerExpired())); connect(mReceiverSocket,SIGNAL(connected()),this,SLOT(SocketConnected())); connect(mReceiverSocket,SIGNAL(disconnected()),this,SLOT(SocketDisconnected())); connect(mReceiverSocket,SIGNAL(readyRead()),this,SLOT(SocketRX())); connect(mStateRequestTimer,SIGNAL(timeout()),this,SLOT(StateRequestTimerExpired())); // connect(mSyncDelayTimer,&QTimer::timeout,this,&CAVReceiverDevice::SyncTimerExpired); } CAVReceiverDevice::~CAVReceiverDevice() { mReceiverSocket->disconnectFromHost(); mReceiverSocket->waitForDisconnected(100); delete mReceiverSocket; delete mDisconnectTimer; delete mStateRequestTimer; delete mSyncDelayTimer; } int CAVReceiverDevice::Start() { mStateRequestTimer->start(); return RET_OK; } int CAVReceiverDevice::ConnectToReceiver() { if(mReceiverSocket->state() != QAbstractSocket::ConnectedState) { mReceiverSocket->connectToHost("192.168.50.101",50000); } return RET_OK; } int CAVReceiverDevice::DisconnectReceiver() { if(mReceiverSocket->state() != QAbstractSocket::ConnectedState) return RET_ERROR; mReceiverSocket->disconnectFromHost(); return RET_OK; } int CAVReceiverDevice::AnalyseRxData(QByteArray data) { QString Data(data); if(data == "\r\n") { // qDebug("AV Receiver: Heartbeat received"); return RET_OK; } QStringList Commands = Data.split("\r\n",QString::SkipEmptyParts); for(int i = 0; imMainPwrStatus = true; } else UnitStatus->mMainPwrStatus = false; } if(Fcn == "SLEEP") { if(Param == "On") { UnitStatus->mMainSleepStatus = true; } else { UnitStatus->mMainSleepStatus = false; } } else if(Fcn == "VOL") { bool OK; float Vol = Param.toFloat(&OK); if(OK) { UnitStatus->mMainVolume = Vol; } else { UnitStatus->mMainPwrStatus = 0xDEADBEEF; } } else if(Fcn == "MUTE") { if(Param == "On") { UnitStatus->mIsMute = true; } else { UnitStatus->mIsMute = false; } } else if (Fcn == "INP") { UnitStatus->mInput = Param; } else if (Fcn == "SOUNDPRG") { UnitStatus->mProgram = Param; } } return RET_OK; } int CAVReceiverDevice::SendReceiverCommand(QString Command) { //Make sure the escape sequence is correct. // Command.remove("\r"); // Command.remove("\n"); // Command.append("\r\n"); if(mReceiverSocket->state() == QAbstractSocket::ConnectedState) { mReceiverSocket->write(Command.toUtf8()); // qDebug("Sent command to receiver : %s",qPrintable(mPendingCommand)); } else { mPendingCommand = Command; ConnectToReceiver(); } return RET_OK; } void CAVReceiverDevice::SocketConnected() { if(mPendingCommand.isEmpty() == false) { QByteArray data =mPendingCommand.toLatin1(); int ret = mReceiverSocket->write(data); // qDebug("Sent command to receiver : %s",qPrintable(mPendingCommand)); mPendingCommand.clear(); return; } qDebug("Receiver Connected"); } void CAVReceiverDevice::SocketDisconnected() { // qDebug("Receiver Disconnected"); } void CAVReceiverDevice::SocketRX() { // qDebug("Receiver response:"); QByteArray Data = mReceiverSocket->readAll(); // qDebug("%s",qPrintable(Data)); AnalyseRxData(Data); } void CAVReceiverDevice::DisconnectTimerExpired() { DisconnectReceiver(); mDisconnectTimer->stop(); } int CAVReceiverDevice::DisconnectReceiverDelayed(int Delay) { if(Delay > 5000) { Delay = 5000; } mDisconnectTimer->start(Delay); return RET_OK; } void CAVReceiverDevice::StateRequestTimerExpired() { if(mReceiverSocket->state() != QAbstractSocket::ConnectedState) { SendReceiverCommand("@MAIN:BASIC=?\r\n@ZONE2:BASIC=?\r\n"); mStateRequestTimer->start(RECEIVER_STATE_UPDATE_TIMEOUT); DisconnectReceiverDelayed(1000); } else { //A transaction is going on... wait and retry later mStateRequestTimer->start(500); } } ////// Network Interface Implementation int CAVReceiverDevice::SetZone2(bool OnOff) { QString Cmd = "@ZONE2:PWR="; if(OnOff) { Cmd += "On\r\n"; } else Cmd += "Standby\r\n"; SendReceiverCommand(Cmd); DisconnectReceiverDelayed(); return RET_OK; } int CAVReceiverDevice::SetMainZone(bool OnOff) { QString Cmd = "@MAIN:PWR="; if(OnOff) { Cmd += "On\r\n"; } else Cmd += "Standby\r\n"; SendReceiverCommand(Cmd); DisconnectReceiverDelayed(); return RET_OK; } int CAVReceiverDevice::SetSpeakers(int SpeakerA, int SpeakerB) { //First, speaker A. if(SpeakerA != RECEIVER_DONT_CHANGE_SPK) { QString Cmd = "@MAIN:SPEAKERA="; if(SpeakerA == RECEIVER_SET_SPK_ON) { Cmd += "On\r\n"; } else if(SpeakerA == RECEIVER_SET_SPK_OFF) { Cmd += "Off\r\n"; } else if(SpeakerA == RECEVIVER_TOGGLE_SPK) { // if(mReceiverStatus.mSpeakerAState == true) // { // Cmd += "Off"; // } // else // { // Cmd += "On"; // } } else { qDebug("Got a SetSpeakers() command with invalid parameter for Speaker A. Weirds stuff!!"); } SendReceiverCommand(Cmd); } //Then, speaker B. if(SpeakerB != RECEIVER_DONT_CHANGE_SPK) { QString Cmd = "@MAIN:SPEAKERB="; if(SpeakerB == RECEIVER_SET_SPK_ON) { Cmd += "On"; } else if(SpeakerB == RECEIVER_SET_SPK_OFF) { Cmd += "Off"; } else if(SpeakerB == RECEVIVER_TOGGLE_SPK) { // if(mReceiverStatus.mSpeakerAState == true) // { // Cmd += "Off"; // } // else // { // Cmd += "On"; // } } else { qDebug("Got a SetSpeakers() command with invalid parameter for Speaker B. Weirds stuff!!"); } SendReceiverCommand(Cmd); } DisconnectReceiverDelayed(); return RET_OK; } int CAVReceiverDevice::SendRawCommand(QString Cmd) { return SendReceiverCommand(Cmd); DisconnectReceiverDelayed(2000); } QByteArray CAVReceiverDevice::GetReceiverStatus() { QByteArray StatusArray; QDataStream Strm(&StatusArray,QIODevice::WriteOnly | QIODevice::Unbuffered); Strm.device()->seek(0); Strm << mReceiverStatus << mZone2Status ; if(mReceiverStatus.mSyncZonesVolumes == true && ( (mReceiverStatus.mMainVolume != mLastMainZoneVolume) || (mReceiverStatus.mMainVolume != mZone2Status.mMainVolume))) { SetZone2Volume(mReceiverStatus.mMainVolume); } mLastMainZoneVolume = mReceiverStatus.mMainVolume; return StatusArray; } int CAVReceiverDevice::SelectScene(char Zone, char Scene) { QString Cmd; if(Zone == AV_RECEIVER_MAIN_ZONE) { Cmd = QString("@MAIN:SCENE=Scene %1\r\n").arg((int)Scene,1); } else if(Zone == AV_RECEIVER_ZONE_2) { Cmd = QString("@ZONE2:SCENE=Scene %1\r\n").arg((int)Scene,1); } else { return RET_ERROR; } SendReceiverCommand(Cmd); DisconnectReceiverDelayed(2000); return RET_OK; } int CAVReceiverDevice::SetMainVolume(float Volume) { QString Cmd; Cmd = QString("@MAIN:VOL=%1\r\n").arg(Volume,1,'f',1); // qDebug("%s",qPrintable(Cmd)); SendReceiverCommand(Cmd); // DisconnectReceiverDelayed(); if(mReceiverStatus.mSyncZonesVolumes == true) { SetZone2Volume(Volume); } return RET_OK; } int CAVReceiverDevice::SetZone2Volume(float Volume) { QString Cmd; Cmd = QString("@ZONE2:VOL=%1\r\n").arg(Volume,1,'f',1); SendReceiverCommand(Cmd); // DisconnectReceiverDelayed(); return RET_OK; } int CAVReceiverDevice::SetZone2Input(QString InputString) { QString Cmd; Cmd = QString("@ZONE2:INP=%1\r\n").arg(InputString); SendReceiverCommand(Cmd); return RET_OK; } int CAVReceiverDevice::SetSyncZ2withZ1(bool Sync) { mReceiverStatus.mSyncZonesVolumes = Sync; if(Sync == true) { SetZone2Volume(mReceiverStatus.mMainVolume); } // qDebug("Sync Z2 with Z1: %d",Sync); }