Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
QHyodaTcp.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2022 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7#include <QHyodaTcp.h>
8#include <QHyodaMachine.h>
9#include <QHyodaToolMesh.h>
10#include <QHyodaToolMatrix.h>
11#include <QHyodaPapi.h>
12
13// ****************************************************************************
14// * QHyodaTcp class
15// ****************************************************************************
16QHyodaTcp::
17QHyodaTcp(QHyodaJob *jb)
18: job(jb)
19, tcpServerConnection(nullptr)
20, iceWdth((job->iceWidthHeight>>16)&0xFFFFul)
21, iceHght((job->iceWidthHeight)&0xFFFFul)
22, tcpImageBytes(iceWdth*iceHght*sizeof(uint32_t))
23, image(nullptr)
24, matrix(nullptr)
25, byteArray(nullptr)
26, matrixArray(nullptr)
27, state(QHyodaTcp::Sleeping)
28, tcpPacketLength(0)
29{
30 connect(&tcpServer, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
31 while (!tcpServer.isListening() &&
32 !tcpServer.listen(QHostAddress::Any,job->tcpPort));//usleep(100);
33 qDebug() << "\33[37m[QHyodaTcp::QHyodaTcp] Listening @ port" << tcpServer.serverPort()<<"\33[m";
34}
35
36// ****************************************************************************
37// * ~QHyodaTcp
38// ****************************************************************************
39QHyodaTcp::~QHyodaTcp(){
40 qDebug() << "\33[37m[QHyodaTcp::~QHyodaTcp]\33[m";
41 if (tcpServerConnection){
42 tcpServerConnection->close();
43 delete tcpServerConnection;
44 }
45 tcpServer.close();
46 delete image;
47 //free(data);
48}
49
50// ****************************************************************************
51// * acceptConnection
52// ****************************************************************************
53void QHyodaTcp::acceptConnection(){
54 // On arrive là lorsque HyodaArc créé son HyodaTcp
55 qDebug() << "\33[37m[QHyodaTcp::acceptConnection] NEW Connection detected!\33[m";
56 tcpServerConnection = tcpServer.nextPendingConnection();
57 //Seeks to the start of input for random-access devices
58 //tcpServerConnection->reset();
59 connect(tcpServerConnection, SIGNAL(readyRead()),this,SLOT(tcpReadyRead()));
60 connect(tcpServerConnection, SIGNAL(error(QAbstractSocket::SocketError)),
61 this, SLOT(displayError(QAbstractSocket::SocketError)));
62 tcpServer.close();
63}
64
65// ****************************************************************************
66// * tcpSleeping
67// ****************************************************************************
68void QHyodaTcp::tcpSleeping(){
69 char pktHeader[8];
70 // On attend au moins le QHyodaTcpSwitch de 4+4 octets
71 if (tcpServerConnection->bytesAvailable() < 8) return;
72 //qDebug()<<"\33[37m[QHyodaTcp::tcpSleeping] Sleeping\33[m";
73 // On lit alors le header
74 if (tcpServerConnection->read(pktHeader,8)!=8)
75 qFatal("\33[37m[QHyodaTcp::tcpReadyRead] Could not fetch packet header!\33[m");
76 // On récupère la taille tout de suite
77 tcpPacketLength=*(unsigned int*)&pktHeader[4];
78 //qDebug()<<"[QHyodaTcp] tcpPacketLength="<<tcpPacketLength;
79 //qDebug()<<"[QHyodaTcp] Header code="<<*(unsigned int*)&pktHeader[0]<<", tcpPacketLength="<<tcpPacketLength;
80 if (*(unsigned int*)&pktHeader[0]==0xe73b2e9cul) state=QHyodaTcp::HandShake;
81 if (*(unsigned int*)&pktHeader[0]==0xca6cd6f0ul) state=QHyodaTcp::VariableName;
82 if (*(unsigned int*)&pktHeader[0]==0xcbce69bcul) state=QHyodaTcp::MeshIceTHeader;
83 if (*(unsigned int*)&pktHeader[0]==0x73491278ul) state=QHyodaTcp::MeshIceTImage;
84 if (*(unsigned int*)&pktHeader[0]==0xb80dd1a3ul) state=QHyodaTcp::Papi;
85 if (*(unsigned int*)&pktHeader[0]==0x78f78f67ul) state=QHyodaTcp::MatrixIceTHeader;
86 if (*(unsigned int*)&pktHeader[0]==0x2cd5e780ul) state=QHyodaTcp::MatrixIceTImage;
87 // et on reprovoque pour aller traiter ce qu'on a éventuellement switché
88 tcpReadyRead();
89}
90
91// ****************************************************************************
92// * tcpHandShake
93// ****************************************************************************
94void QHyodaTcp::tcpHandShake(){
95 char data[1024];
96 quint32 pid;
97 const int tcpPacketLengthLeft=tcpPacketLength-8;
98 if (tcpServerConnection->bytesAvailable() < tcpPacketLengthLeft) return;
99 qDebug()<<"\33[37m[QHyodaTcp::tcpHandShake] QHyodaTcp::HandShake\33[m";
100 // On récupère le pid
101 qDebug()<<"\33[37m[QHyodaTcp::tcpHandShake] @ HandShake: On recupere le pid\33[m";
102 if (tcpServerConnection->read(data,4)!=4)
103 qFatal("\33[37m[QHyodaTcp::tcpHandShake] Could not fetch pid!\33[m");
104 pid=*(unsigned int*)&data[0];
105 qDebug()<<"\33[37m[QHyodaTcp::tcpHandShake] \33[7m@ HandShake: pid="<<pid<<"\33[m";
106 job->pid=QString("%1").arg(pid);
107 // On récupère le nom de la machine
108 if (tcpServerConnection->read(data,4)!=4)
109 qFatal("\33[37m[QHyodaTcp::tcpHandShake] Could not fetch hostname len!\33[m");
110 unsigned int len=*(unsigned int*)&data[0];
111 qDebug()<<"\33[37m[QHyodaTcp::tcpHandShake] @ HandShake: hostname's len="<<len<<"\33[m";
112 if (tcpServerConnection->read(data,len)!=len)
113 qFatal("\33[37m[QHyodaTcp] Could not fetch hostname!\33[m");
114 qDebug()<<"\33[37m[QHyodaTcp::tcpHandShake] \33[7m@ HandShake: rankZero is"<<data<<"\33[m";
115 job->host=QString(data);
116 // On récupère le nom de la ligne de commande
117 if (tcpServerConnection->read(data,4)!=4)
118 qFatal("\33[37m[QHyodaTcp::tcpHandShake] Could not fetch command line len!\33[m");
119 len=*(unsigned int*)&data[0];
120 qDebug()<<"\33[37m[QHyodaTcp::tcpHandShake] @ HandShake: COMMAND LINE's len="<<len<<"\33[m";
121 if (tcpServerConnection->read(data,len)!=len)
122 qFatal("\33[37m[QHyodaTcp] Could not fetch COMMAND LINE!\33[m");
123 qDebug()<<"\33[37m[QHyodaTcp::tcpHandShake] \33[7m@ HandShake: COMMAND LINE is"<<data<<"\33[m";
124 job->broadcasted_cmdline=QString(data);
125 job->has_been_broadcasted=true;
126 // On récupère le SLURM_JOB_ID
127 if (tcpServerConnection->read(data,4)!=4)
128 qFatal("\33[37m[QHyodaTcp::tcpHandShake] Could not fetch SLURM_JOB_ID!\33[m");
129 job->id=*(unsigned int*)&data[0];
130 qDebug()<<"\33[37m[QHyodaTcp::tcpHandShake] \33[7m@ HandShake: SLURM_JOB_ID is"<<job->id<<"\33[m";
131 // On acknowlege le handshake
132 sendAcknowledgePacket();
133 // Si on s'est hand-shaké, on se met en doze
134 state=QHyodaTcp::Sleeping;
135}
136
137// ****************************************************************************
138// * tcpVariableName
139// ****************************************************************************
140void QHyodaTcp::tcpVariableName(){
141 char varName[4*1024];
142 const int tcpPacketLengthLeft=tcpPacketLength-8;
143 qDebug()<<"\33[37m[QHyodaTcp::tcpVariableName] state @ QHyodaTcp::\33[7mVariableName\33[m";
144 // Tant qu'on a pas tout le nom de la variable qui est arrivé, on à rien à faire
145 if (tcpServerConnection->bytesAvailable() < tcpPacketLengthLeft) return;
146 qDebug()<<"\33[37m[QHyodaTcp::tcpVariableName] QHyodaTcp::VariableName\33[m";
147 // On récupère les noms des variables
148 if (tcpServerConnection->read(varName,tcpPacketLengthLeft)!=tcpPacketLengthLeft)
149 qFatal("\33[37m[QHyodaTcp::tcpVariableName] Could not fetch variable name!\33[m");
150 for(int offset=0;offset<tcpPacketLengthLeft;){
151 //int var_name_len=varName[offset];
152 unsigned int var_name_len=*(unsigned int*)&varName[offset]; // 4o
153 // On saute les 4o de len
154 offset+=4;
155 //qDebug()<<"\t[QHyodaTcp::tcpReadyRead]"<<var_name_len<<" bytes for this name";
156 qDebug()<<"\33[37m\t[QHyodaTcp::tcpVariableName] Variable \33[7m"<<&varName[offset]<<"\33[m";
157 // On rajoute cette variable arcane à la liste des noms
158 *job->arcane_variables_names<<&varName[offset];
159 //job->topRightTools->mesh->variablesComboBox->addItem(&varName[offset]);
160 //qDebug()<<"[QHyodaTcp::tcpReadyRead] arcane_variables_names are now:"<<*job->arcane_variables_names;
161 offset+=var_name_len;
162 }
163 // Et on retourne en mode doze
164 state=QHyodaTcp::Sleeping;
165 // Maintenant qu'on a tout récupéré, on accroche gdb
166 qDebug()<<"\33[37m[QHyodaTcp::tcpVariableName] Maintenant qu'on a tout recupere, on accroche GDB\33[m";
167 //job->machine->tabJobs->setTabText(job->machine->tabJobs->currentIndex(),job->host);
168 job->gdbserver_hook();
169 // On acknowledge le getVariableCollectionAndSendItToHost
170 //qDebug()<<"\33[7m[QHyodaTcp::tcpReadyRead] On acknowledge le getVariableCollectionAndSendItToHost\33[m";
171 sendAcknowledgePacket();
172}
173
174// ****************************************************************************
175// * tcpMeshIceTHeader
176// ****************************************************************************
177void QHyodaTcp::tcpMeshIceTHeader(){
178 //qDebug()<<"\33[7m[QHyodaTcp::tcpMeshIceTHeader]\33[m";
179 sendAcknowledgePacket();
180 state=QHyodaTcp::MeshIceTImage;
181}
182
183// ****************************************************************************
184// * tcpMeshIceTImage
185// ****************************************************************************
186void QHyodaTcp::tcpMeshIceTImage(){
187 // Tant qu'on a pas tout reçu, on revient plus tard
188 if (tcpServerConnection->bytesAvailable() < tcpImageBytes) return;
189 //qDebug()<<"\33[7m[QHyodaTcp::tcpMeshIceTImage]\33[m";
190 // On fait le ménage avant de récupérer la nouvelle image
191 if (byteArray) delete byteArray;
192 byteArray=new QByteArray(tcpServerConnection->read(tcpImageBytes));
193 sendAcknowledgePacket();
194 // On a tout reçu, on peut envoyer une réponse
195 // On va envoyer le POV et l'index de la variable
196 double pov[6]={0.,0.,0.,0.,0.,0.};
197 if (job->topRightTools->mesh!=NULL){
198 job->topRightTools->mesh->ice->sxyz(&pov[0]);
199 pov[4]=job->topRightTools->mesh->variablesComboBox->currentIndex();
200 pov[5]=job->topRightTools->mesh->hPluginComboBox->currentIndex();
201 }
202 sendPacket((char*)&pov[0],8*(4+1+1));
203 recvAcknowledgePacket();
204 // On retourne par défaut en mode doze dès qu'on a reçu une image
205 state=QHyodaTcp::Sleeping;
206 // Tant qu'on a pas demandé le tab QHyodaToolMesh, on ne fait rien
207 if (job->topRightTools->mesh==NULL) return;
208 // Tant qu'on a pas cliqué sur le bouton
209 if (job->meshButton->isEnabled()) return;
210 // On recréé l'image à chaque fois
211 if (image!=NULL) delete image;
212 image=new QImage((uchar*)byteArray->data(), iceWdth, iceHght, QImage::Format_ARGB32);// ARGB32 vs RGBA8888
213 job->topRightTools->mesh->ice->setImage(image);
214 // Et on update le GL
215 //job->topRightTools->mesh->ice->update();
216}
217
218// ****************************************************************************
219// * tcpPapi
220// ****************************************************************************
221void QHyodaTcp::tcpPapi(){
222 const int bytesAvailable=tcpServerConnection->bytesAvailable();
223 if (bytesAvailable < 8) return;
224 //qDebug()<<"\33[37m[QHyodaTcp::tcpPapi] Papi #"<<bytesAvailable<<"\33[m";
225 //qDebug()<<"\33[37m[QHyodaTcp::tcpPapi] Read PAPI input!\33[m";
226 // Et on update le profiling s'il a été initialisé
227 if (job->bottomRightTools->papi)
228 job->bottomRightTools->papi->update(new QByteArray(tcpServerConnection->read(bytesAvailable)));
229 sendAcknowledgePacket();
230 state=QHyodaTcp::Sleeping;
231}
232
233// ****************************************************************************
234// * tcpMatrixIceTHeader
235// ****************************************************************************
236void QHyodaTcp::tcpMatrixIceTHeader(){
237 //qDebug()<<"\33[37m[QHyodaTcp::tcpMatrixIceTHeader]\33[m";
238 sendAcknowledgePacket();
239 state=QHyodaTcp::MatrixIceTImage;
240}
241
242// ****************************************************************************
243// * tcpMatrixIceTImage
244// ****************************************************************************
245void QHyodaTcp::tcpMatrixIceTImage(){
246 // Tant qu'on a pas tout reçu, on revient plus tard
247 if (tcpServerConnection->bytesAvailable() < tcpImageBytes) return;
248 //qDebug()<<"\33[37m[QHyodaTcp::tcpMatrixIceTImage]\33[m";
249 // On fait le ménage avant de récupérer la nouvelle image
250 if (matrixArray) delete matrixArray;
251 matrixArray=new QByteArray(tcpServerConnection->read(tcpImageBytes));
252 //qDebug()<<"\33[37m[QHyodaTcp::tcpReadyRead] sending AcknowledgePacket\33[0m";
253 sendAcknowledgePacket();
254 // On a tout reçu, on peut envoyer une réponse, on va envoyer le POV
255 double pov[6]={0.,0.,0.,0.,0.,0.};
256 if (job->topLeftTools){
257 if (job->topLeftTools->matrix!=NULL){
258 job->topLeftTools->matrix->ice->sxyz(&pov[0]);
259 }
260 }
261 //qDebug()<<"\33[37m[QHyodaTcp::tcpReadyRead] sending POV Packet\33[0m";
262 sendPacket((char*)&pov[0],8*(4+1+1));
263 //qDebug()<<"\33[37m[QHyodaTcp::tcpReadyRead] waiting for recvAcknowledgePacket\33[0m";
264 recvAcknowledgePacket();
265 // On retourne par défaut en mode doze dès qu'on a reçu une image
266 state=QHyodaTcp::Sleeping;
267 // On indique que l'on a une matrice à visualiser
268 job->matrixButton->setEnabled(true);
269 // Tant qu'on a pas demandé le tab QHyodaToolMesh, on ne fait rien
270 if (job->topLeftTools->matrix==NULL) return;
271 // Pour l'instant, on recréé l'image à chaque fois: cela permet d'éviter le 'shift' visuel
272 if (matrix!=NULL) delete matrix;
273 matrix=new QImage((uchar*)matrixArray->data(), iceWdth, iceHght, QImage::Format_ARGB32);
274 job->topLeftTools->matrix->ice->setImage(matrix);
275 // Et on update le GL
276 //job->topLeftTools->matrix->ice->updateGL();
277}
278
279// ****************************************************************************
280// * tcpReadyRead
281// ****************************************************************************
282void QHyodaTcp::tcpReadyRead(){
283 //qDebug()<<"\33[37m[QHyodaTcp::tcpReadyRead] switch\33[m";
284 switch (state){
285 case (QHyodaTcp::Sleeping):{tcpSleeping();break;}
286 case (QHyodaTcp::HandShake):{tcpHandShake();break;}
287 case (QHyodaTcp::VariableName):{tcpVariableName();break;}
288 case (QHyodaTcp::MeshIceTHeader):{tcpMeshIceTHeader();break;}
289 case (QHyodaTcp::MeshIceTImage):{tcpMeshIceTImage();break;}
290 case (QHyodaTcp::Papi):{tcpPapi();break;}
291 case (QHyodaTcp::MatrixIceTHeader):{tcpMatrixIceTHeader();break;}
292 case (QHyodaTcp::MatrixIceTImage):{tcpMatrixIceTImage();break;}
293 default: qFatal("\33[37m[QHyodaTcp::tcpReadyRead] Unknown state!\33[m");
294 }
295}
296
297// ****************************************************************************
298// * displayError
299// ****************************************************************************
300void QHyodaTcp::displayError(QAbstractSocket::SocketError socketError){
301 if (socketError == QTcpSocket::RemoteHostClosedError) return;
302 qDebug() << "\33[37m[QHyodaTcp::displayError] \33[7mSocket error"<<socketError<<"\33[m";
303 tcpServer.close();
304}
305
306// ****************************************************************************
307// * sendPacket
308// ****************************************************************************
309qint64 QHyodaTcp::sendPacket(const char *data, qint64 maxSize){
310 //qDebug() << "\33[7m[QHyodaTcp::sndPacket]\33[m";
311 if (tcpServerConnection->write(data,maxSize)!=maxSize)
312 qFatal("\33[37m[QHyodaTcp::sendPacket] has not sent maxSize bytes!\33[m");
313 return 0;
314}
315
316
317// ****************************************************************************
318// * sndAcknowledgePacket
319// * BaseForm [Hash[ "Acknowledge", "CRC32"], 16] = 0x3e9ff203
320// ****************************************************************************
321void QHyodaTcp::sendAcknowledgePacket(void){
322 char pkt[4];
323 *(unsigned int*)&pkt[0]=0x3e9ff203ul;
324 //qDebug() << "\33[37m[QHyodaTcp::sendAcknowledgePacket] \33[m";
325 sendPacket((char*)&pkt[0],4);
326}
327
328
329// ****************************************************************************
330// * recvAcknowledgePacket
331// ****************************************************************************
332void QHyodaTcp::recvAcknowledgePacket(void){
333 char pktHeader[4];
334 if (tcpServerConnection->bytesAvailable() < 4) return;
335 //qDebug()<<"\33[37m[QHyodaTcp::recvAcknowledgePacket]\33[m";
336 if (tcpServerConnection->read(pktHeader,4)!=4)
337 qFatal("\33[37m[QHyodaTcp::recvAcknowledgePacket] Could not fetch packet header!\33[m");
338 //qDebug()<<"[QHyodaTcp] Header code="<<*(unsigned int*)&pktHeader[0];
339 if (*(unsigned int*)&pktHeader[0]==0x3e9ff203ul) return;
340 //qFatal("\33[37m[QHyodaTcp::recvAcknowledgePacket] Not an ACK packet!");
341}
Integer len(const char *s)
Retourne la longueur de la chaîne s.