IMA4 2018/2019 EC5

De Wiki d'activités IMA

Présentation du projet

Contexte

L'élève continue son semestre S8 à l'école.

Objectif

L'objectif de l'épreuve complémentaire est de programmer un dispositif de type système embarqué en micro-python pour utilisation dans des travaux pratiques en GIS3.

Description du projet

Vous devez utiliser une plateforme stm32f4-discovery. Les tâches à accomplir sur cette plateforme sont :

  • mettre à jour la plateforme pour vérifier que le dispositif ST-LINK intégré permet la programmation via système de fichiers, en cas contraire établir une liste des différentes versions de ST-LINK disponibles sur les différentes plateformes avec leurs fonctionnalités principales ;
  • installer micro-python sur la plateforme ;
  • écrire un programme python main.py pour :
    • implanter SLIP sur la plateforme ;
    • répondre aux paquets ICMP demande d'écho ;
    • gérer les 4 LEDs programmables sur réception de datagrammes UDP ;
    • gérer le bouton programmable et envoyer des datagrammes UDP sur changement d'état de ce bouton.

Comme adresse de destination des paquets de changement d'état des paquets vous utiliserez l'adresse source du dernier datagramme de gestion des LEDs. En cas d'absence de paquets UDP reçus vous pouvez utiliser 255.255.255.255 comme adresse destination.

Vous écrirez le programme Python dans le fichier main.py du périphérique clef USB implanté sur le processeur principal et accessible par le connecteur micro-USB. Trouvez le périphérique bloc correspondant par la commande lsblk. Le nom du périphérique est facile à trouver, c'est le seul d'une taille d'environ 100kB. Vous pouvez monter le périphérique par la commande mount /dev/sdb1 /mnt. Le fichier se trouve alors dans le répertoire /mnt. Avant de déconnecter la plateforme taper la commande umount /mnt. Pensez à sauver régulièrement votre main.py sur le disque du PC.

D'un point de vue pratique, vous pouvez lancer minicom -D /dev/ttyACM0 dans un terminal pour tester votre programme et nano /mnt/main.py (ou équivalent) dans un autre terminal pour modifier le programme. Tapez simplement CTRL-D dans l'interpréteur micro-python pour recharger le programme main.py. Vous pouvez aussi vous passer du câble mini-USB en connectant les broches PA9 et 5V sur le connecteur P2.

Il est a priori possible d'implanter SLIP sur la connexion série/USB en créant l'objet connexion série/USB avec ces quelques lignes :

import pyb
usb=pyb.USB_VCP()

Cette connexion est cependant difficile à utiliser pour SLIP : il faut détourner l'interruption du CTRL-C avec la méthode setinterrupt et même ainsi l'interpréteur Python a la fâcheuse habitude de reprendre la main sur la connexion série/USB. De plus utiliser cette connexion rend le développement du programme main.py compliqué car il n'est plus possible d'afficher des messages de déverminage.

Il est conseillé d'utiliser une autre connexion série pour implanter SLIP. Micro-python permet de créer des objets port série avec le constructeur pyb.UART. Le port série peut être connecté au PC en utilisant un convertisseur USB/Série connecté d'un coté sur les broches TX (fil jaune), RX (fil orange) et GND (fil noir) du port série et de l'autre sur un port USB du PC.

Pour tester votre connexion SLIP vous ouvrirez un troisième terminal pour lancer la commande slattach -Ldv -p slip -s 9600 /dev/ttyUSB0. Un quatrième terminal peut permettre de configurer la nouvelle interface réseau sl0, par exemple en lançant les commandes :

ip link set sl0 up
ip address add dev sl0 192.168.0.1 peer 192.168.0.10

Un ping 192.168.0.10 va provoquer l'envoi de paquets IPv4 sur l'objet série créé en micro-python. Des tests peuvent être effectués sur l'interpréteur micro-python disponible via l'utilitaire minicom dont il a été question plus haut.

Matériel nécessaire

Pour cette épreuve complémentaire sont fournis :

  • Un PC portable sur lequel les paquetages nécessaires sont déjà installés (voir le répertoire EC_Reseau et son fichier README).
  • Deux SMT32F4-discovery, une version MB997C et une version MB997D. Les deux versions doivent comporter deux ST-LINK différents pouvant amener des fonctionnalités différentes. Si les fonctionnalités sont effectivement différentes, essayez de trouver les différences entre les schématiques des deux versions des ST-LINK.
  • Un câble mini-USB et un câble micro-USB.
  • Un câble de connexion femelle/femelle.
  • Un convertisseur USB/série.

Planning prévisionnel

Travail effectué

Introduction

Avant de commencer, je dois déterminer la connexion.

1. J'utilise le cavalier pour connecter PA9 et 5V. Ça c'est pour alimenter.

2. J'utilise un convertisseur USB / série pour connecter le port série à mon PC.

UART(2) is on: (TX, RX) = (X1, X2) = (PA2, PA3)

La ligne jaune de ce convertisseur est connectée à PA2, la ligne orange à PA3, la ligne noire à GND et l'autre côté est connecté au port USB du PC.

3. J'utilise le câble USB pour connecter la plateforme et PC.

Lololo.jpegLplp.jpeg

Semaine 1

1. Mettre à jour du firmware

Tout d'abord, j'ai décompresser l'archive et il est dans le répertoire Allplateforms. Ensuite, j'ai connecté le STM32F4-discovery sur le PC avec les deux connecteurs USB. En finale, j'ai lancé l'utilitaire java par la commande 'java -jar STLinkUpgrqde.jar'.

2. Essai de téléchargement d'un programme sur le STM32F4-discovery

Dans le répertoire stlink, j'ai compilé par la commande 'make rebuild_cache release'. Ensuite, aller dans le chemin build/Release et utiliser la commande 'make install' pour installer l'utilitaire. Dans le sous-répertoire blinky, j'ai compilé la file 'main.c' par 'make' et téléchargé par 'make burn' pour essayer l'exemple.Après, j'ai modifié le programme pour clignoter toutes les LEDs (PD12 à PD15).

Dans l'exemple, il est pour clignoter LED orange(PIN13):

  GPIOD ->MODER = (1 << 26)       GPIOD ->ODR ^= (1 << 13)

Modification pour clignoter tous les LEDs:

  GPIOD ->MODER = (1 << 26)|(1 << 24)|(1 << 28)|(1 << 30)       
  GPIOD ->ODR ^= (1 << 13)|(1 << 12)|(1 << 14)|(1 << 15)

Yxl.jpeg

3. Essai de téléchargement en mode DFU

D'abord, j'ai utilisé le cavalier de JP2 pour connecter BOOT0 et VDD sur le connecteur P2. Et ensuite j'ai réinitialisé la plateforme. Dans le terminal, j'ai trouve les binaires du programme de démonstration. Pour télécharger le démonstration:

  dfu-util -a 0 -d 0483:0000,0483:df11 -D STM32F4-Discovery_Demonstration_V1.0.0.dfu

Finalement, j'ai enlevé le cavalier et réinitialisé la plateforme.

Semaine 2

Cette semaine, j'ai flashé le STM32F4-Discovery à partir de Linux.

Installer dfu-utils:

 sudo apt-get install dfu-util

J‘ai utilisé la commande pour créer un fichier de règles udev:

 sudo vi /etc/udev/rules.d/49-stmdiscovery.rules

Ensuite, j'ai mis le contenu suivant:

 # f055:9800 - STM32F4 Discovery running MicroPython in USB Serial Mode (CN5)
 ATTRS{idVendor}=="f055", ENV{ID_MM_DEVICE_IGNORE}="1"
 ATTRS{idVendor}=="f055", ENV{MTP_NO_PROBE}="1"
 SUBSYSTEMS=="usb", ATTRS{idVendor}=="f055", MODE:="0666"
 KERNEL=="ttyACM*", ATTRS{idVendor}=="f055", MODE:="0666"
 # 0483:df11 - STM32F4 Discovery in DFU mode (CN5)
 SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE:="0666"

La commande suivante est pour recharger les règles:

 sudo udevadm control --reload-rules

Pour utiliser DFU, j'ai connecté CN5 sur le PC. Et j'ai utilisé un cavalier entre PA9 et 5V pour alimenter. Avant programmer le plateforme, j'ai installé un cavalier de JP2 pour connecter BOOT0 et VDD. En même temps, j'ai appuyé le bouton Reset pout réinitialiser la plateforme. Dans le chemin '/home/pifou/EC Réseau/micropython/ports/stm32', j'ai entré la commande suivant pour:

 make BOARD=STM32F4DISC deploy

Après cette commande, j'ai retiré le cavalier BOOT0 et appuyez sur reset. Dans le nouveau terminal, je peux tester le programme avec:

 minicom -D /dev/ttyACM0

Semaine 3 & 4

1. Recevoir et Envoyer un paquet

Lll.jpeg

Si l'octet END apparaît dans les données à envoyer, la séquence à deux octets ESC, ESC_END est envoyée à la place,

Si l'octet ESC apparaît dans les données, la séquence à deux octets ESC, ESC_ESC est envoyée.

2. Analyser le paquet

Selon le format de différents datagrammes, j'ai analysé le paquet reçu.

IP

Ip.jpeg

ICMP

Icmp.jpeg

UDP

Udp.jpeg

a) Si la somme de contrôle n'est pas égale 0, c'est un paquet mauvais et le jetter.

b) Si l'adresse de destination n'est pas correct, c'est un paquet mauvais et le jetter.

c) Si le protocol est égal 0x11, analyser le paquet UDP.

d) Si le protocol est égal 0x01, analyser le paquet ICMP et envoyer un paquet 'réponse à une demande d'écho'.

Semaine 5

Dans cette semaine, j'écris les fonctions pour construire le paquet. La partie la plus importante est de calculer la somme de contrôle.

1. construireIPv4

La somme de contrôle du paquet IP vérifie uniquement l'en-tête du paquet IP.

 entetesIP=[ version<<4|ihl, 0x00 ] + bin2list(total_length) + [ 0x00, 0x00, 0x00, 0x00, ttl, protocol, 0x00, 0x00 ] + source + cible
 checksum=bin2list(somme(entetesIP))
 entetesIP[10]=checksum[0]
 entetesIP[11]=checksum[1]

2. construireUDP

La somme de contrôle de UDP consiste à vérifier à la fois l'en-tête et la partie données. Et besoin d'encapsuler un pseudo en-tête avant de calculer la somme de contrôle UDP.

La forme de pseudo en-tête:

l'adresse de source (4 octets) | l'adresse de destination (4 octets) | 0 (1 octet) | protocole (1 octet) | la taille de UDP (2 octets)

 pseudo=source+cible+[0x00, 0x11]+bin2list(taille)
 UDPheader=bin2list(sport)+bin2list(dport)+bin2list(taille)+[0x00, 0x00]
 tout=pseudo+UDPheader+donnees
 sum=bin2list(somme(tout))
 UDP=UDPheader+donnees
 UDP[6]=sum[0]
 UDP[7]=sum[1]

Ajouter l'en-tête du paquet IP :

 paquetUDP=construireIPv4(0x40,0x11,source,cible,UDP)

3. construireICMPv4

La somme de contrôle ICMP est calculé de la même manière, à la différence près qu'il ne contrôle que l'intégralité du paquet ICMP, sans en-tête factice ni en-tête de paquet IP.

 icmp=[type, code, 0x00, 0x00]+donnees
 check=bin2list(somme(icmp))
 icmp[2]=check[0]
 icmp[3]=check[1]

Ajouter l'en-tête du paquet IP :

 paquetICMP=construireIPv4(0xff,0x01,source,cible,icmp)

Après avoir construit le paquet, nous devons émettre différents paquets de réponse en fonction des différents résultats obtenus en analysant le paquet.

 if protocol==0x11:
   udp=construireUDP(d_addr,s_addr,d1,s1,data)
   ecrire(serie,udp)
 if protocol==0x01:
   icmp_reply=construireICMPv4(d_addr,s_addr,data)
   ecrire(serie,icmp_reply)

Semaine 6

Dans cette semaine, je réalise :

1) Gérer les 4 LEDs programmables sur réception de datagrammes UDP;

 pyb.LED()
 led1=pyb.LED(1)
 led2=pyb.LED(2)
 led3=pyb.LED(3)
 led4=pyb.LED(4)

Selon la différence de chaque bit dans l'octet du paquet reçu, on peut gérer les LEDs.

 byte=paquet[iph_length+8
 if byte&0x01==0x01:led1.on()
 if byte&0x10==0x10:led1.off()
 if byte&0x02==0x02:led2.on()
 if byte&0x20==0x20:led2.off()
 if byte&0x04==0x04:led3.on()
 if byte&0x40==0x40:led3.off()
 if byte&0x08==0x08:led4.on()
 if byte&0x80==0x80:led4.off()
 echo -ne '\x01' | nc -q0 -u 192.168.0.10 4000
 echo -ne '\x02' | nc -q0 -u 192.168.0.10 4000
 echo -ne '\x04' | nc -q0 -u 192.168.0.10 4000
 echo -ne '\x08' | nc -q0 -u 192.168.0.10 4000

Après, j'ai observé les LEDs :

Kokoko.jpeg

2) Gérer le bouton programmable et envoyer des datagrammes UDP sur changement d'état de ce bouton.

 bouton=pyb.Switch()

La fonction de sa fonction de rappel est d’envoyer un datagramme UDP lorsque le bouton est appuyé.

 def usr_callback_func():
     global bouton_presse
     bouton_presse += 1
 bouton.callback(usr_callback_func)
 if byte==0xff:
       global bouton_presse
       newdata=[bouton_presse]
       bouton_presse=0
       udp=construireUDP(d_addr,s_addr,d1,bin2list(hisport),newdata)
       ecrire(serie,udp)

Après, j'ai testé la fonction quelques fois avec :

 echo -ne '\xff' | nc -q0 -u 192.168.0.10 4000 

Et obtenu :

Kpkp.jpeg

Documents

Média:EC5-réseau.zip