La console Enttec est une console professionnelle permettant de s’intégrer dans une installation destinée à contrôler des appareils DMX.
La console Enttec playback est équipée d’une carte réseau Ethernet et elle est capable de communiquer en UDP/IP.
Elle utilise un protocole propriétaire WING comme protocole de couche Application. Celui est décrit précisément dans le fichier wing_api_spec.pdf.
Il s’appuie sur deux types de messages :
Le transport des messages WODD/WIDD est assuré par le protocole UDP. Le modèle DoD est donc le suivant :
Couche | Protocole |
---|---|
Application | WING |
Transport | UDP |
Réseau | IP |
Interface | Ethernet_II |
On va réaliser une capture de trames sur le réseau avec wireshark.
On démarre wireshark avec les droits root avec gksudo
:
Puis on lance une capture sur l’interface relié au réseau (ici eth0
).
Aucune trame est reçue. La console Enttec n’envoie donc pas périodiquement l’état des ses boutons et glissières.
On appuie sur le bouton 1. On capture alors 2 trames :
La première trame correspond à l’appui sur le bouton
La deuxième trame correspond à son relachement
La console Enttec émet ses datagrammes en broadcast IP (adresse destination 255.255.255.255) vers le port UDP 3330. Son port d’écoute pour la réception de datagramme est aussi le 3330. Son adresse IP est 192.168.52.212.
Important : ici, le choix du broadcast IP permet à la console d’envoyer ses trames contenant les états à tous les postes du réseau sans connaître spécifiquement leur adresse. C’est la solution retenue par le fabricant Enttec qui leur a évité de mettre en place un protocole de type requête-réponse.
Les 28 octets de données du protocole WING sont « décodables » à partir de la documentation Enttec wing_api_spec.pdf. On peut remarquer que l’octet à l’adresse 0x32 passe de la valeur 0xFD (appui) à 0xFF (repos).
Les curseurs (fader ou slider) sont numérotés de 0 à 9, de gauche à droite. Ils renvoient une valeur sur 8 bits suivant la position du curseur. L’affectation des touches est ici.
On utilise QUdpSocket
pour dialoguer avec la console.
Apparu dans les systèmes UNIX, un socket est un élément logiciel qui est aujourd'hui répandu dans la plupart des systèmes d'exploitation. Il s'agit d'une interface de communication logicielle avec les services du système d'exploitation, grâce à laquelle un développeur exploitera facilement et de manière uniforme les services d'un protocole réseau. Il s'agit d'un modèle permettant la communication bidirectionnelle inter processus IPC (Inter Process Communication) afin de permettre à divers processus de communiquer aussi bien sur une même machine qu'à travers un réseau TCP/IP. Les sockets se situent entre la couche Transport et la couche Application. En résumé, une socket est un point de communication par lequel un processus peut émettre et recevoir des informations. Ce point de communication devra être relié à une adresse IP et un numéro de port et associé à un mode de communication, le plus souvent : le mode connecté (TCP) ou le mode non connecté (UDP).
Être capable de dialoguer avec la console Enttec.
On va créer une application simple qui permette de recevoir des datagrammes en provenance de la console.
$ ./dialogue-udp
<DialogueConsole.cpp:DialogueConsole:23> socket UDP sur le port 3330
<192.168.52.212:3330> datagramme de 28 octet(s) reçu(s)
WODD 0x10 0x01 0xFF 0xFF 0xFD 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00
<192.168.52.212:3330> datagramme de 28 octet(s) reçu(s)
WODD 0x10 0x01 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00
Pour cela, on va créer une classe DialogueConsole
:
#define PORT_ENTTEC 3330 //Enttec Port
class DialogueConsole : public QObject
{
Q_OBJECT
public:
DialogueConsole(QObject *pParent = 0);
~DialogueConsole();
void demarrer();
public slots:
void ReceptionnerDatagrammes();
signals :
void terminer();
private:
QUdpSocket *udpSocket;
bool statut;
int VerifierDatagramme(char *donneesBrutes, int nbOctets);
int TraiterDatagramme(char *donneesBrutes, int nbOctets);
};
Le constructeur de cette classe assure la création de la socket (udpSocket
) et son attachement sur le port 3330 des interfaces locales de la machine. Le destructeur fermera tout simplement la socket.
DialogueConsole::DialogueConsole(QObject *pParent):QObject(pParent)
{
udpSocket = new QUdpSocket(this);
// Attachement locale de la socket UDP :
statut = udpSocket->bind(QHostAddress((QString)"0.0.0.0"), PORT_ENTTEC);
if(!statut)
{
QMessageBox::critical(NULL, "Serveur UDP", "Erreur bind sur le port 3330");
}
}
DialogueConsole::~DialogueConsole()
{
udpSocket->close();
}
La méthode demarrer()
(appelée à partir de la fonction main()
) réalise la connexion du signal readyRead()
au slot ReceptionnerDatagrammes()
(si l’attachement bind()
a évidemment réussi).
void DialogueConsole::demarrer()
{
if(statut)
{
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(ReceptionnerDatagrammes()));
connect(this, SIGNAL(terminer()), qApp, SLOT(quit()));
}
}
La méthode ReceptionnerDatagrammes()
assure donc la réception des datagrammes UDP. Pour cela, elle réalise un boucle d’attente sur la présence de données dans la socket. Son pseudo code à compléter est le suivant :
void DialogueConsole::ReceptionnerDatagrammes()
{
int nbOctets = 0;
int etat;
// datagramme en attente d'être lu ?
while (udpSocket->hasPendingDatagrams())
{
QByteArray donneesDatagramme;
QHostAddress emetteurAdresse;
quint16 emetteurPort;
// Fixe la taille du tableau au nombre d'octets reçus en attente
donneesDatagramme.resize(udpSocket->pendingDatagramSize());
// Lit le datagramme en attente
//nbOctets = udpSocket->readDatagram(datagram.data(), datagram.size());
nbOctets = udpSocket->readDatagram(donneesDatagramme.data(), donneesDatagramme.size(),
&emetteurAdresse, &emetteurPort);
// Vérifie la validité du datagramme
etat = VerifierDatagramme(donneesDatagramme.data(), nbOctets);
if(etat == 1)
{
#ifdef DEBUG_DialogueConsole
QString qs_emetteurAdresse = emetteurAdresse.toString();
cout << "<" << qs_emetteurAdresse.toStdString() << ":" << emetteurPort
<< "> datagramme de " << nbOctets << " octet(s) reçu(s)" << endl;
#endif
TraiterDatagramme(donneesDatagramme.data(), donneesDatagramme.size());
}
else
{
#ifdef DEBUG_DialogueConsole
QString qs_emetteurAdresse = emetteurAdresse.toString();
cout << "<" << qs_emetteurAdresse.toStdString() << ":" << emetteurPort
<< "> datagramme de " << nbOctets << " octet(s) reçu(s) : INVALIDE !" << endl;
#endif
emit terminer(); /* sinon on quitte ! (à modifier par la suite) */
}
}
}
La méthode VerifierDatagramme()
s’assure de la validité du datagramme reçu. Pour cela, on vérifiera que le type du message est bien ‘WODD’ et que sa taille correspond à celle fournie par le protocole WING. Cette méthode retourne 1 si le datagramme est valide sinon 0.
La méthode TraiterDatagramme()
réalise pour l’instant seulement l’affichage simple des données reçues.
int DialogueConsole::TraiterDatagramme(char *donneesBrutes, int nbOctets)
{
bool commande = false;
bool enregistrement = false;
int etat;
int valeur;
#ifdef DEBUG_DialogueConsole
if(nbOctets == LG_MESSAGE_WOOD)
{
for(int i=0;i<INDEX_FIRMWARE;i++)
printf("%c", donneesBrutes[i]); //WODD
printf(" ");
for(int i=INDEX_FIRMWARE;i<nbOctets;i++)
printf("0x%02X ", (unsigned char)donneesBrutes[i]); // le reste des données
printf("\n\n");
}
#endif
return 0;
}
Code source fourni : activite-dialogue-console.zip
Tester l’application fournie.
Compléter la méthode TraiterDatagramme()
pour qu’elle assure la détection des touches PAGE_UP ou PAGE_DOWN, et l’affichage du slide n°0 (premier en partant de la gauche).
Écrire la méthode EnvoyerDatagramme()
qui permettra d’envoyer un message de type ‘WIDD’ vers la console.
Modifier l’application pour assurer l’incrémentation et la décrémentation de l’afficheur de la console lorsqu’on appuie sur une touche PAGE_UP ou PAGE_DOWN.
On vous fournit le code Qt d’un slider personnalisée.
Code source fourni : activite-myslider.zip
DialogueConsole
, créer un application qui dialogue avec la console Enttec pour synchroniser le widget myslider avec le slider n°0. Le numéro de canal DMX sera lui aussi synchronisé avec les afficheurs de la console.