FlatBufferConnection.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // stl includes
  2. #include <stdexcept>
  3. // Qt includes
  4. #include <QRgb>
  5. // flatbuffer includes
  6. #include <flatbufserver/FlatBufferConnection.h>
  7. // flatbuffer FBS
  8. #include "hyperion_reply_generated.h"
  9. #include "hyperion_request_generated.h"
  10. FlatBufferConnection::FlatBufferConnection(const QString& origin, const QString& host, int priority, bool skipReply, quint16 port)
  11. : _socket()
  12. , _origin(origin)
  13. , _priority(priority)
  14. , _host(host)
  15. , _port(port)
  16. , _prevSocketState(QAbstractSocket::UnconnectedState)
  17. , _log(Logger::getInstance("FLATBUFCONN"))
  18. , _registered(false)
  19. {
  20. if(!skipReply)
  21. connect(&_socket, &QTcpSocket::readyRead, this, &FlatBufferConnection::readData, Qt::UniqueConnection);
  22. // init connect
  23. Info(_log, "Connecting to Hyperion: %s:%u", QSTRING_CSTR(_host), _port);
  24. connectToHost();
  25. // start the connection timer
  26. _timer.setInterval(5000);
  27. connect(&_timer, &QTimer::timeout, this, &FlatBufferConnection::connectToHost);
  28. _timer.start();
  29. }
  30. FlatBufferConnection::~FlatBufferConnection()
  31. {
  32. Debug(_log, "Closing connection to: %s:%u", QSTRING_CSTR(_host), _port);
  33. _timer.stop();
  34. _socket.close();
  35. }
  36. void FlatBufferConnection::readData()
  37. {
  38. _receiveBuffer += _socket.readAll();
  39. // check if we can read a header
  40. while(_receiveBuffer.size() >= 4)
  41. {
  42. uint32_t messageSize =
  43. ((_receiveBuffer[0]<<24) & 0xFF000000) |
  44. ((_receiveBuffer[1]<<16) & 0x00FF0000) |
  45. ((_receiveBuffer[2]<< 8) & 0x0000FF00) |
  46. ((_receiveBuffer[3] ) & 0x000000FF);
  47. // check if we can read a complete message
  48. if((uint32_t) _receiveBuffer.size() < messageSize + 4) return;
  49. // extract message only and remove header + msg from buffer :: QByteArray::remove() does not return the removed data
  50. const QByteArray msg = _receiveBuffer.mid(4, messageSize);
  51. _receiveBuffer.remove(0, messageSize + 4);
  52. const uint8_t* msgData = reinterpret_cast<const uint8_t*>(msg.constData());
  53. flatbuffers::Verifier verifier(msgData, messageSize);
  54. if (hyperionnet::VerifyReplyBuffer(verifier))
  55. {
  56. parseReply(hyperionnet::GetReply(msgData));
  57. continue;
  58. }
  59. Error(_log, "Unable to parse reply");
  60. }
  61. }
  62. void FlatBufferConnection::setSkipReply(bool skip)
  63. {
  64. if(skip)
  65. disconnect(&_socket, &QTcpSocket::readyRead, 0, 0);
  66. else
  67. connect(&_socket, &QTcpSocket::readyRead, this, &FlatBufferConnection::readData, Qt::UniqueConnection);
  68. }
  69. void FlatBufferConnection::setRegister(const QString& origin, int priority)
  70. {
  71. auto registerReq = hyperionnet::CreateRegister(_builder, _builder.CreateString(QSTRING_CSTR(origin)), priority);
  72. auto req = hyperionnet::CreateRequest(_builder, hyperionnet::Command_Register, registerReq.Union());
  73. _builder.Finish(req);
  74. uint32_t size = _builder.GetSize();
  75. const uint8_t header[] = {
  76. uint8_t((size >> 24) & 0xFF),
  77. uint8_t((size >> 16) & 0xFF),
  78. uint8_t((size >> 8) & 0xFF),
  79. uint8_t((size ) & 0xFF)};
  80. // write message
  81. int count = 0;
  82. count += _socket.write(reinterpret_cast<const char *>(header), 4);
  83. count += _socket.write(reinterpret_cast<const char *>(_builder.GetBufferPointer()), size);
  84. _socket.flush();
  85. _builder.Clear();
  86. }
  87. void FlatBufferConnection::setColor(const ColorRgb & color, int priority, int duration)
  88. {
  89. auto colorReq = hyperionnet::CreateColor(_builder, (color.red << 16) | (color.green << 8) | color.blue, duration);
  90. auto req = hyperionnet::CreateRequest(_builder, hyperionnet::Command_Color, colorReq.Union());
  91. _builder.Finish(req);
  92. sendMessage(_builder.GetBufferPointer(), _builder.GetSize());
  93. _builder.Clear();
  94. }
  95. void FlatBufferConnection::setImage(const Image<ColorRgb> &image)
  96. {
  97. auto imgData = _builder.CreateVector(reinterpret_cast<const uint8_t*>(image.memptr()), image.size());
  98. auto rawImg = hyperionnet::CreateRawImage(_builder, imgData, image.width(), image.height());
  99. auto imageReq = hyperionnet::CreateImage(_builder, hyperionnet::ImageType_RawImage, rawImg.Union(), -1);
  100. auto req = hyperionnet::CreateRequest(_builder,hyperionnet::Command_Image,imageReq.Union());
  101. _builder.Finish(req);
  102. sendMessage(_builder.GetBufferPointer(), _builder.GetSize());
  103. _builder.Clear();
  104. }
  105. void FlatBufferConnection::clear(int priority)
  106. {
  107. auto clearReq = hyperionnet::CreateClear(_builder, priority);
  108. auto req = hyperionnet::CreateRequest(_builder,hyperionnet::Command_Clear, clearReq.Union());
  109. _builder.Finish(req);
  110. sendMessage(_builder.GetBufferPointer(), _builder.GetSize());
  111. _builder.Clear();
  112. }
  113. void FlatBufferConnection::clearAll()
  114. {
  115. clear(-1);
  116. }
  117. void FlatBufferConnection::connectToHost()
  118. {
  119. // try connection only when
  120. if (_socket.state() == QAbstractSocket::UnconnectedState)
  121. _socket.connectToHost(_host, _port);
  122. }
  123. void FlatBufferConnection::sendMessage(const uint8_t* buffer, uint32_t size)
  124. {
  125. // print out connection message only when state is changed
  126. if (_socket.state() != _prevSocketState )
  127. {
  128. _registered = false;
  129. switch (_socket.state() )
  130. {
  131. case QAbstractSocket::UnconnectedState:
  132. Info(_log, "No connection to Hyperion: %s:%u", QSTRING_CSTR(_host), _port);
  133. break;
  134. case QAbstractSocket::ConnectedState:
  135. Info(_log, "Connected to Hyperion: %s:%u", QSTRING_CSTR(_host), _port);
  136. break;
  137. default:
  138. Debug(_log, "Connecting to Hyperion: %s:%u", QSTRING_CSTR(_host), _port);
  139. break;
  140. }
  141. _prevSocketState = _socket.state();
  142. }
  143. if (_socket.state() != QAbstractSocket::ConnectedState)
  144. return;
  145. if(!_registered)
  146. {
  147. setRegister(_origin, _priority);
  148. return;
  149. }
  150. const uint8_t header[] = {
  151. uint8_t((size >> 24) & 0xFF),
  152. uint8_t((size >> 16) & 0xFF),
  153. uint8_t((size >> 8) & 0xFF),
  154. uint8_t((size ) & 0xFF)};
  155. // write message
  156. int count = 0;
  157. count += _socket.write(reinterpret_cast<const char *>(header), 4);
  158. count += _socket.write(reinterpret_cast<const char *>(buffer), size);
  159. _socket.flush();
  160. }
  161. bool FlatBufferConnection::parseReply(const hyperionnet::Reply *reply)
  162. {
  163. if (!reply->error())
  164. {
  165. // no error set must be a success or registered or video
  166. const auto videoMode = reply->video();
  167. const auto registered = reply->registered();
  168. if (videoMode != -1) {
  169. // We got a video reply.
  170. emit setVideoMode(static_cast<VideoMode>(videoMode));
  171. return true;
  172. }
  173. // We got a registered reply.
  174. if (registered == -1 || registered != _priority)
  175. _registered = false;
  176. else
  177. _registered = true;
  178. return true;
  179. }
  180. else
  181. throw std::runtime_error(reply->error()->str());
  182. return false;
  183. }