2015-01-14 00:50:55 +00:00
/*************************************************************************
* Copyright ( C ) 2015 by Andrius Š tikonas < andrius @ stikonas . eu > *
* *
* This program 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 "socket.h"
2015-01-14 13:55:28 +00:00
# include <algorithm>
2015-01-25 19:39:15 +00:00
# include <iostream>
2015-02-03 01:24:47 +00:00
# include <QThread>
# include <QUdpSocket>
2015-01-14 13:55:28 +00:00
2015-01-31 15:28:34 +00:00
Socket : : Socket ( QHostAddress IPaddress , QByteArray reply )
2015-01-14 00:50:55 +00:00
{
ip = IPaddress ;
2015-01-31 15:28:34 +00:00
mac = reply . mid ( 7 , 6 ) ;
2015-01-14 13:55:28 +00:00
rmac = mac ;
2015-01-31 15:28:34 +00:00
std : : reverse ( rmac . begin ( ) , rmac . end ( ) ) ;
2015-01-14 13:55:28 +00:00
2015-01-31 15:28:34 +00:00
powered = reply . right ( 1 ) = = one ;
// 68:64:00:06:71:61 initial detection ??
2015-01-25 19:39:15 +00:00
2015-01-31 15:28:34 +00:00
commandID [ Subscribe ] = QByteArray : : fromHex ( " 63 6c " ) ;
commandID [ PowerOn ] = QByteArray : : fromHex ( " 73 66 " ) ;
2015-01-25 19:39:15 +00:00
commandID [ PowerOff ] = commandID [ PowerOn ] ;
2015-01-31 15:28:34 +00:00
commandID [ TableData ] = QByteArray : : fromHex ( " 72 74 " ) ;
2015-01-26 00:55:20 +00:00
commandID [ SocketData ] = commandID [ TableData ] ;
commandID [ TimingData ] = commandID [ TableData ] ;
2015-01-31 15:28:34 +00:00
commandID [ WriteSocketData ] = QByteArray : : fromHex ( " 74 6d " ) ;
2015-02-21 21:14:22 +00:00
QByteArray commandIDPower = QByteArray : : fromHex ( " 64 63 " ) ;
2015-01-25 19:39:15 +00:00
// 2 hex bytes are the total length of the message
2015-02-15 15:11:39 +00:00
datagram [ Subscribe ] = commandID [ Subscribe ] + mac + twenties + rmac + twenties ;
2015-02-21 21:14:22 +00:00
datagram [ PowerOn ] = commandIDPower + mac + twenties + zeros + one ;
datagram [ PowerOff ] = commandIDPower + mac + twenties + zeros + zero ;
2015-02-15 15:11:39 +00:00
datagram [ TableData ] = commandID [ TableData ] + mac + twenties + zeros + QByteArray : : fromHex ( " 01 00 00 " ) + zeros ;
2015-01-31 15:28:34 +00:00
2015-02-03 01:24:47 +00:00
udpSocket = new QUdpSocket ( ) ;
udpSocket - > connectToHost ( ip , 10000 ) ;
2015-02-01 01:42:45 +00:00
2015-02-07 17:29:12 +00:00
connect ( this , & Socket : : datagramQueued , this , & Socket : : listen ) ;
2015-02-01 01:42:45 +00:00
subscribeTimer = new QTimer ( this ) ;
2015-02-09 21:09:50 +00:00
subscribeTimer - > setInterval ( 2 * 60 * 1000 ) ; // 2 min
2015-02-03 01:24:47 +00:00
subscribeTimer - > setSingleShot ( false ) ;
2015-02-01 01:42:45 +00:00
connect ( subscribeTimer , & QTimer : : timeout , this , & Socket : : subscribe ) ;
subscribeTimer - > start ( ) ;
2015-02-07 17:29:12 +00:00
subscribe ( ) ;
tableData ( ) ;
2015-02-01 01:42:45 +00:00
}
Socket : : ~ Socket ( )
{
delete subscribeTimer ;
2015-02-03 01:24:47 +00:00
delete udpSocket ;
2015-02-01 01:42:45 +00:00
}
2015-02-07 17:29:12 +00:00
void Socket : : sendDatagram ( Datagram d )
{
commands . enqueue ( d ) ;
Q_EMIT datagramQueued ( ) ;
}
void Socket : : run ( )
{
while ( commands . size ( ) > 0 )
{
2015-02-15 15:11:39 +00:00
QByteArray currentDatagram = datagram [ commands . head ( ) ] ;
QByteArray recordLength ;
QDataStream stream ( & recordLength , QIODevice : : WriteOnly ) ;
stream . setByteOrder ( QDataStream : : BigEndian ) ;
uint16_t length = currentDatagram . length ( ) + 4 ; // +4 for magicKey and total message length
stream < < length ;
currentDatagram = magicKey + recordLength + currentDatagram ;
udpSocket - > write ( currentDatagram ) ;
2015-02-07 17:29:12 +00:00
QThread : : msleep ( 100 ) ;
}
}
2015-02-01 01:42:45 +00:00
void Socket : : subscribe ( )
{
sendDatagram ( Subscribe ) ;
2015-01-14 13:55:28 +00:00
}
2015-01-26 00:55:20 +00:00
void Socket : : toggle ( )
2015-01-14 13:55:28 +00:00
{
2015-02-03 01:24:47 +00:00
sendDatagram ( powered ? PowerOff : PowerOn ) ;
2015-01-14 13:55:28 +00:00
}
2015-02-03 01:24:47 +00:00
void Socket : : changeSocketName ( QString newName )
2015-01-31 15:28:34 +00:00
{
2015-02-03 01:24:47 +00:00
QByteArray name = newName . toLatin1 ( ) . leftJustified ( 16 , ' ' , true ) ;
2015-02-15 12:31:21 +00:00
writeSocketData ( name , remotePassword , timeZone ) ;
}
void Socket : : changeSocketPassword ( QString newPassword )
{
QByteArray password = newPassword . toLatin1 ( ) . leftJustified ( 12 , ' ' , true ) ;
writeSocketData ( socketName , password , timeZone ) ;
}
2015-02-03 01:24:47 +00:00
2015-02-15 12:31:21 +00:00
void Socket : : changeTimezone ( int8_t newTimezone )
{
QByteArray timezone ;
QDataStream stream ( & timezone , QIODevice : : WriteOnly ) ;
stream . setByteOrder ( QDataStream : : BigEndian ) ;
stream < < newTimezone ;
writeSocketData ( socketName , remotePassword , timezone ) ;
}
void Socket : : writeSocketData ( QByteArray name , QByteArray password , QByteArray timezone )
{
2015-02-15 15:26:37 +00:00
QByteArray record = QByteArray : : fromHex ( " 01:00 " ) /* record number = 1*/ + versionID + mac + twenties + rmac + twenties + password + name + icon + hardwareVersion + firmwareVersion + wifiFirmwareVersion + port + staticServerIP + port + domainServerName + localIP + localGatewayIP + localNetMask + dhcpNode + discoverable + timeZoneSet + timezone + QByteArray : : fromHex ( " 00:ff " ) + countdown ;
2015-02-15 15:11:39 +00:00
2015-02-12 23:26:31 +00:00
QByteArray recordLength ;
QDataStream stream ( & recordLength , QIODevice : : WriteOnly ) ;
stream . setByteOrder ( QDataStream : : LittleEndian ) ;
2015-02-15 12:31:21 +00:00
uint16_t length = record . length ( ) ;
2015-02-12 23:26:31 +00:00
stream < < length ;
2015-02-15 15:11:39 +00:00
datagram [ WriteSocketData ] = commandID [ WriteSocketData ] + mac + twenties + zeros + QByteArray : : fromHex ( " 04:00:01 " ) /*table number and unknown*/ + recordLength + record ;
2015-01-31 15:28:34 +00:00
sendDatagram ( WriteSocketData ) ;
}
2015-01-26 00:55:20 +00:00
void Socket : : tableData ( )
{
2015-01-31 15:28:34 +00:00
sendDatagram ( TableData ) ;
2015-02-15 15:11:39 +00:00
datagram [ SocketData ] = commandID [ SocketData ] + mac + twenties + zeros + QByteArray : : fromHex ( " 04 00 00 " ) + zeros ;
datagram [ TimingData ] = commandID [ TimingData ] + mac + twenties + zeros + QByteArray : : fromHex ( " 03 00 00 " ) + zeros ;
2015-01-31 15:28:34 +00:00
// table number + 00 + version number
sendDatagram ( SocketData ) ;
sendDatagram ( TimingData ) ;
2015-01-26 00:55:20 +00:00
}
2015-01-31 15:28:34 +00:00
bool Socket : : parseReply ( QByteArray reply )
{
if ( reply . left ( 2 ) ! = magicKey )
2015-02-01 01:42:45 +00:00
{
2015-01-31 15:28:34 +00:00
return false ;
2015-02-01 01:42:45 +00:00
}
2015-01-31 15:28:34 +00:00
QByteArray id = reply . mid ( 4 , 2 ) ;
unsigned int datagram = std : : distance ( commandID , std : : find ( commandID , commandID + MaxCommands , id ) ) ; // match commandID with enum
2015-02-12 23:26:31 +00:00
if ( datagram = = TableData ) // determine the table number
2015-01-31 15:28:34 +00:00
{
unsigned int table = reply [ reply . indexOf ( zeros ) + 4 ] ; // Table number immediately follows zeros
switch ( table )
{
case 1 :
break ;
case 3 :
datagram = TimingData ;
break ;
case 4 :
datagram = SocketData ;
break ;
default :
return false ;
2015-01-25 19:39:15 +00:00
}
}
2015-01-31 15:28:34 +00:00
switch ( datagram )
{
case Subscribe :
case PowerOff :
case PowerOn :
2015-02-01 01:42:45 +00:00
{
bool poweredOld = powered ;
2015-01-31 15:28:34 +00:00
powered = reply . right ( 1 ) = = one ;
2015-02-01 01:42:45 +00:00
if ( powered ! = poweredOld )
Q_EMIT stateChanged ( ) ;
2015-02-15 14:41:09 +00:00
if ( datagram = = PowerOff & & powered = = true ) // Required to deque
2015-02-07 17:29:12 +00:00
{
datagram = PowerOn ;
}
2015-01-31 15:28:34 +00:00
break ;
2015-02-01 01:42:45 +00:00
}
2015-01-31 15:28:34 +00:00
case TableData :
// FIXME: order might be swapped;
socketTableVersion = reply . mid ( reply . indexOf ( QByteArray : : fromHex ( " 000100000600 " ) ) + 6 , 2 ) ;
// 000100000600
break ;
case SocketData :
2015-02-09 21:09:50 +00:00
{
2015-02-13 11:01:48 +00:00
std : : cout < < reply . toHex ( ) . toStdString ( ) < < " " < < datagram < < std : : endl ; // for debugging purposes only
2015-02-09 21:09:50 +00:00
unsigned short int index = reply . indexOf ( rmac + twenties ) ;
versionID = reply . mid ( index - 14 , 2 ) ;
index + = 12 ; // length of rmac + padding
remotePassword = reply . mid ( index , 12 ) ; // max 12 symbols
index + = 12 ;
2015-02-15 12:31:21 +00:00
socketName = reply . mid ( index , 16 ) ; // max 16 symbols
2015-02-09 21:09:50 +00:00
index + = 16 ;
icon = reply . mid ( index , 2 ) ;
index + = 2 ;
hardwareVersion = reply . mid ( index , 4 ) ;
index + = 4 ;
firmwareVersion = reply . mid ( index , 4 ) ;
index + = 4 ;
2015-02-11 00:33:04 +00:00
wifiFirmwareVersion = reply . mid ( index , 4 ) ;
index + = 6 ;
staticServerIP = reply . mid ( index , 4 ) ; // 42.121.111.208 is used
2015-02-15 15:26:37 +00:00
index + = 6 ;
domainServerName = reply . mid ( index , 40 ) ;
index + = 40 ;
2015-02-11 00:33:04 +00:00
localIP = reply . mid ( index , 4 ) ;
index + = 4 ;
localGatewayIP = reply . mid ( index , 4 ) ;
2015-02-11 14:31:20 +00:00
index + = 4 ;
localNetMask = reply . mid ( index , 4 ) ;
index + = 4 ;
dhcpNode = reply . mid ( index , 1 ) ;
+ + index ;
discoverable = reply . mid ( index , 1 ) ;
+ + index ;
timeZoneSet = reply . mid ( index , 1 ) ;
+ + index ;
timeZone = reply . mid ( index , 1 ) ;
+ + index ;
countdown = reply . mid ( index , 2 ) ;
2015-02-01 01:42:45 +00:00
Q_EMIT stateChanged ( ) ;
2015-01-31 15:28:34 +00:00
break ;
2015-02-09 21:09:50 +00:00
}
2015-01-31 15:28:34 +00:00
case TimingData :
break ;
2015-02-01 01:42:45 +00:00
case WriteSocketData :
2015-02-03 01:24:47 +00:00
sendDatagram ( SocketData ) ;
2015-02-01 01:42:45 +00:00
break ;
2015-01-31 15:28:34 +00:00
default :
return false ;
}
2015-02-07 17:29:12 +00:00
if ( commands . size ( ) > 0 )
{
if ( datagram = = commands . head ( ) )
{
commands . dequeue ( ) ;
}
}
2015-01-31 15:28:34 +00:00
return true ;
2015-01-14 13:55:28 +00:00
}