Communication série, 2014/2015, TD2
Sommaire
Présentation du projet:
Le projet communication série consiste à concevoir une liaison série fonctionnelle. C'est à dire que si on envoie une certaine information par le biais de cette liaison, elle devra être capable de renvoyer exactement le même message sur l'interface d'envoi. Il y a donc une grande partie d'électronique qui consiste à concevoir cette liaison, et une partie un peu moins consistante en informatique dans le but de concevoir l'interface d'envoi. Celle-ci sera constitué d'une page web, dans laquelle on entrera un mot ou un phrase, et ce même mot sera ensuite envoyé à la liaison série par le biais d'un serveur websockets.
Séance du mercredi 11 Mars :
Partie informatique:
Durant cette séance nous avons tout d'abord observé ce que notre système devra faire, une fois sa conception terminée, au moyen d'une carte ARDUINO programmée spécialement pour cette application. Après avoir ouvert la liaison et configuré la carte dans le terminal, on a testé le programme. Lorsqu'on écrit une chaîne de caractères dans le terminal, on l’envoi à travers la liaison et la même chaîne de caractère réapparaît sur le terminal, écrite avec des '*'. Après cette observation, nous avons codé la page web d'où l'information sera envoyé dans la liaison série, et où on affichera l'information reçue après parcours de la liaison (les deux informations devront être les mêmes si la liaison a bien été réalisée). Puis nous avons codé le programme qui gérera les envois et réceptions de l'information. Jusqu'à la fin de la séance, nous avons commencé à étudier le code du serveur websockets, un peu compliqué à comprendre, dans le but de savoir comment implanter notre code C à l'intérieur du serveur, ce qui permettra d'envoyer une information directement depuis notre page web. A suivre..
Partie électronique
Au cours de cette séance nous nous sommes intéressés à savoir comment on allait transmettre et recevoir une trame ( pour le moment 8 bits) par un unique fil. Pour cela nous avons à notre disposition la Nanoboard programmable grâce au logiciel Altium Designer. Après avoir défini les éléments nécessaires pour pouvoir transmettre une information en série, nous mettons en place ce schéma:
L'élément principal de ce projet est le registre à décalage qui nous permet en fonction d'une horloge de transmettre en série un mot chargé en parallèle. Nous avons décidé de tester la transmission par affichage des bits transmis en série. Cependant nous avons du réduire la fréquence de l'horloge à 2Hz afin de pouvoir lire notre mot qui défilait sur une LED. En effet, nous avons laisser la transmission en continue du registre en décalage. Dans une seconde partie, nous avons ajouté à notre schéma la partie réception en ajoutant simplement un autre registre à décalage mais en laissant la transmission en continue de l'autre côté. On a alors pu observer, sur 8 LEDs, défiler notre mot.
Afin de pouvoir contrôler l'envoi et la réception d'une trame avec un bit de start et un bit de stop nous allons devoir utiliser des registres à décalage de 16 bits. De plus, nous avons réfléchit comment on pouvait automatiser le processus d'envoi et de réception. Pour cela, nous avons quelques pistes qui nous amènerait à utiliser un compteur qui s'incrémenterait à chaque bit transmis et comparateur qui arrêterait la transmission.
Séance du mercredi 18 Mars:
Partie Informatique
Durant cette séance, nous avons effectué quelques finitions sur la page web de notre application, elle est maintenant connectée au serveur de Polytech Lille. On peut voir à quoi elle ressemble sur l'image suivante:
Puis nous avons ensuite modifié l'exemple de serveur websockets,notamment dans les parties envoie d'un message au serveur, et sa réception par ce dernier, pour qu'il puisse être utilisable par notre application.Sur les deux images suivantes, on discernera deux étapes. On rentrera dans un premier temps le message souhaité dans le bloc de saisie prévu à cet effet. Puis nous verrons ce message s'afficher sur la page web , formé avec des '#'.
Vous pourrez consulter nos codes dans les annexes disponibles en bas de page. Nous avons également commencé à étudier l'implantation de nos programmes sur la foxboard, mais il nous reste encore quelques éléments à étudier pour notre prochaine séance.
Partie Electronique
Durant cette séance, nous avons principalement testé la partie envoie de notre liaison série. Elle était tout à fait fonctionnel, en effet, le cable RS232 étant relié à l'ordinateur et en utilisant le logiciel hyperterminal, nous avons constaté que lorsqu'on envoyait un caractère depuis notre clavier, le même caractère s'affichait sur le terminal de l'ordinateur relié à la liaison. De plus, nous avons remarqué qu'il ne servait à rien d'utiliser un compteur pour décaler les bits dans les registres à décalage, car ils se décalent en continu.
Séance du Mercredi 25 Mars
Partie Informatique
Durant cette séance, notre serveur et son application étant opérationnels sur le réseau local, nous avons configuré notre foxboard. Pour cela, nous avons du nous connecter sur la foxboard en série grâce au logiciel minicom dans le but de la configurer. Une fois entrés dans la foxboard, nous avons commencé par modifier le fichier /etc/network/interfaces. Nous avons donc remplacé les lignes correspondantes par :
auto eth0 iface eth0 inet static address 172.26.79.15 //15, le numéro de notre ordinateur netmask 255.255.240.0 gateway 172.26.79.254 dns-nameservers 193.48.57.34
Une fois ceci fait, nous avons pu nous connecter sur notre foxboard en ssh, en entrant la commande suivante dans le terminal:
ssh root@172.26.79.15
La première chose à faire, une fois connectés, était de transférer nos fichiers locaux dans les répertoires appropriés sur la foxboard. Nous avons donc créé un nouveau dossier nommé "serie" sur la foxboard, où nous avons transféré depuis notre machine locale nos fichiers de code( websockets.c, serial.h, serial.c). La commande utilisée a été:
scp <fichier> root@172.26.79.15:<destination>
Après avoir installé sur la foxboard le dernier paquet "libwebsockets-dev", nous avons pu compiler notre programme. Voici la commande de cette compilation:
gcc serial.c serial.h websockets.c -o websocket -lwebsockets
L'installation du paquet "libwebsockets-dev" était indispensable pour pouvoir utiliser les bibliothèques liées aux websockets. D'où l'inclusion du morceau "-lwebsockets" qui précise qu'on utilisera cette bibliothèque pour compiler.
Nous avons ensuite copié nos fichiers dédiés à l'application web en elle même(websockets.html, style.css) avec la même commande scp, dans le répertoire /var/www/.
Pour finir, nous devions configurer la foxboard pour qu'elle lance le serveur et donc l'application à chaque démarrage. Pour cela, nous avons modifié le fichier /etc/rc.local pour lui dire d'aller chercher dans le dossier "serie" l'executable "websocket". Nous avons donc modifié le fichier et inséré la ligne:
serie/websocket&
Après redémarrage de la foxboard, nous avons pu tester notre application sur le serveur en rentrant l'adresse de la foxboard dans la barre d'URL de notre navigateur. Tout fonctionnait comme lors des tests en local.
Partie Electronique
Durant cette séance nous nous sommes penchés sur la partie du renvoi et de la réception, et nous nous sommes rendus compte qu'il y avait un problème, car lorsqu'on envoyait un 'A' par exemple, on recevait en retour un 'ù'. Nous avons ensuite découvert que le fait de renvoyer l'information au bout de 8 fronts d'horloge ne laissait pas le temps à l'information complète de se charger dans le registre d'envoi. Nous avons donc remplacé le compteur modulo 8 par un compteur modulo 9, et notre liaison série marchait parfaitement.
On peut voir ici le schéma finalisé et fonctionnel de notre liaison :
Mise en commun des deux parties
Une fois chaque partie finie, nous avons pu les mettre en commun. Après avoir emmené un ordinateur et la foxboard en salle d'électronique, nous avons tout d'abord relié la foxboard à la nanoboard par le biais d'un adaptateur USB vers série, branché en usb sur la foxboard. Nous avons ensuite alimenté la foxboard. Une fois allumée nous avons du modifier le code du fichier websockets.c en remplacant une ligne:
#define SERIAL_DEVICE "/dev/ACM0" par #define SERIAL_DEVICE "/dev/USB0" //car la liaison série est branché sur port USB0 de la foxboard.
On recompile et on relance la foxboard. Une fois sur la page de notre application on constate que l'entête est bien verte, ce qui signifie que nous sommes bien connectés. On commence donc la phase de test:
Sur cette photo, on voit qu'une chaîne de caractère est prête à être en envoyé à travers la liaison.
Et ici, on voit qu'elle a bien été envoyée et reçu de nouveau par la page de l'application. On remarquera que le résultat reçu n'est pas écrit avec des '#', car c'était la plaquette Arduino qui était configuré comme cela pour la liaison série.
Pour une démonstration, vous pouvez regarder une video qui présente tous les éléments de ce projet:
Veuillez noter que la page de l'onglet "notre équipe" de notre application n'a pas pu être finalisée.
Annexes
-fichier websockets.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <libwebsockets.h> #include <unistd.h> #include <termios.h> #include "serial.h"
#define MAX_FRAME_SIZE 1024 #define WAIT_DELAY 50 #define SERIAL_DEVICE "/dev/ACM0" //ou USB0 #define TAILLE 50
int sd; //port serie
static int callback_http( struct libwebsocket_context *this, struct libwebsocket *wsi,enum libwebsocket_callback_reasons reason, void *user,void *in,size_t len) { return 0; }
static int callback_my( struct libwebsocket_context * this, struct libwebsocket *wsi,enum libwebsocket_callback_reasons reason, void *user,void *in,size_t len) { switch(reason){ case LWS_CALLBACK_ESTABLISHED: printf("connection established\n"); // Declenchement d'un prochain envoi au navigateur libwebsocket_callback_on_writable(this,wsi); break; case LWS_CALLBACK_RECEIVE: // Ici sont traites les messages envoyes par le navigateur printf("received data: %s\n",(char *)in); write(sd,(char*)in,strlen((char*)in)); break; case LWS_CALLBACK_SERVER_WRITEABLE: { // Ici sont envoyes les messages au navigateur char message[1+LWS_SEND_BUFFER_PRE_PADDING+LWS_SEND_BUFFER_POST_PADDING]; char c; int nb=read(sd,&c,sizeof(char)); if(nb==sizeof(char)){ char *out=message+LWS_SEND_BUFFER_PRE_PADDING; out[0]=c; libwebsocket_write(wsi,(unsigned char *)out,1,LWS_WRITE_TEXT); } libwebsocket_callback_on_writable(this,wsi); } break; default: break; } return 0; }
static struct libwebsocket_protocols protocols[] = { { "http-only", // name callback_http, // callback 0, // data size 0 // maximum frame size }, {"myprotocol",callback_my,0,MAX_FRAME_SIZE}, {NULL,NULL,0,0} };
int main(void) { sd=serialOpen(SERIAL_DEVICE,SERIAL_BOTH); serialConfig(sd,B9600); int port=9000; struct lws_context_creation_info info; memset(&info,0,sizeof info); info.port=port; info.protocols=protocols; info.gid=-1; info.uid=-1; struct libwebsocket_context *context=libwebsocket_create_context(&info); if(context==NULL){ fprintf(stderr, "libwebsocket init failed\n"); return -1; } printf("starting server...\n"); while(1){ libwebsocket_service(context,WAIT_DELAY); } libwebsocket_context_destroy(context); serialClose(sd); return 0; }
-fichier serial.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <strings.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/file.h> #include <linux/serial.h>
#include "serial.h" // // Open serial port device // int serialOpen(char *device,int mode){ int flags=(mode==SERIAL_READ?O_RDONLY:(mode==SERIAL_WRITE?O_WRONLY:O_RDWR)); int fd=open(device,flags|O_NOCTTY|O_NONBLOCK); if(fd<0){ perror(device); exit(-1); } return fd; }
// // Serial port configuration // void serialConfig(int fd,int speed){ struct termios new; bzero(&new,sizeof(new)); new.c_cflag=CLOCAL|CREAD|speed|CS8; new.c_iflag=0; new.c_oflag=0; new.c_lflag=0; /* set input mode (non-canonical, no echo,...) */ new.c_cc[VTIME]=0; /* inter-character timer unused */ new.c_cc[VMIN]=1; /* blocking read until 1 char received */ if(tcsetattr(fd,TCSANOW,&new)<0){ perror("serialInit.tcsetattr"); exit(-1); } }
// // Serial port termination // void serialClose(int fd){ close(fd); }
fichier serial.h
#define SERIAL_READ 0 #define SERIAL_WRITE 1 #define SERIAL_BOTH 2
//// // Public prototypes //// int serialOpen(char *device,int mode); void serialConfig(int fd,int speed); void serialClose(int fd);