Protocoles de communication

Comment deux ordinateurs communiquent-ils ?

Code de base

Ce code permet uniquement d'échanger des messages par radio. Il comporte des problèmes majeurs :
  • l'ensemble est inintelligible
  • on ne sait pas qui est le destinataire ni l'émetteur
from microbit import *
import radio

radio.on()  # Active la radio
radio.config(channel=10)  # Définit un canal (10 ici)

while True:
    if button_a.was_pressed():
        msg_envoi = input("Message ?")
        radio.send(msg_envoi)  # Envoie un message
    message = radio.receive() # Permet de vérifier régulièrement la réception d'un message
    if message:
        print(message)  # Affiche le message reçu dans la console

Définition d'un protocole

Version 1
  • Le séparateur utilisé est le symbole monétaire générique ¤
  • La trame est définie ainsi : DESTINATAIRE¤ÉMETTEUR¤MESSAGE
  • Le destinataire, l'émetteur et le message ne peuvent pas être vides
  • ping est un nom réservé
  • On ignore les messages qui ne respectent pas ce protocole

Implémentation du protocole

On ajoute les éléments suivants :
  • constantes : SEP pour le séparateur, PSEUDO pour le nom de l'émetteur
  • utilisation de la fonction input() pour pouvoir saisir le pseudo du destinataire
  • concaténation des chaînes de caractères nécessaires à la création de la trame
  • on ignore les messages qui ne respectent pas le protocole :
    • utilisation de split() pour diviser le message reçu
    • si on obtient trois parties, on considère que la première est le destinataire, la deuxième est l'émetteur, la troisième est le message
    • chacune des trois parties ne doit pas être égale à une chaîne de caractères vide ''
from microbit import *
import radio

radio.on()  # Active la radio
radio.config(channel=10)  # Définit un canal (10 ici)
SEP = '¤'
PSEUDO = 'Mathieu'


while True:
    if button_a.was_pressed():
        msg_envoi = input("Message ?")
        destinataire = input("Destinataire ?")
        radio.send(destinataire+SEP+PSEUDO+SEP+msg_envoi)  # Envoie un message

    trame = radio.receive() # Permet de vérifier régulièrement la réception d'un message
    if trame:
        parts = trame.split(SEP)
        if len(parts) == 3 and parts[0] != '' and parts[1] != '' and parts[2] != '':
            print(parts[2])

Affichage des message qui nous concernent

On ne veut pas polluer notre affichage avec des messages qui ne nous sont pas adressés.
On définit donc notre nom d'utilisateur, et on affiche seulement les messages qui nous sont adressés.
from microbit import *
import radio

radio.on()  # Active la radio
radio.config(channel=10)  # Définit un canal (10 ici)
SEP = '¤'
PSEUDO = 'Mathieu'


while True:
    if button_a.was_pressed():
        msg_envoi = input("Message ?")
        destinataire = input("Destinataire ?")
        radio.send(destinataire+SEP+PSEUDO+SEP+msg_envoi)  # Envoie un message

    trame = radio.receive() # Permet de vérifier régulièrement la réception d'un message
    if trame:
        parts = trame.split(SEP)
        if len(parts) == 3 and parts[0] != '' and parts[1] != '' and parts[2] != '':
            if parts[0] == PSEUDO:
                print(parts[2])

Signaler sa présence sur le réseau (WIP)

Nous envoyons actuellement des messages aux personnes qui sont à portée de voix, qui sont capables de nous donner l'information de leur pseudonyme sur le réseau. Nous allons ajouter la fonctionnalité permettant de signaler sa présence sur le réseau, grâce à l'utilisation d'une commande, que nous appellerons ping.
"Envoyer un ping" revient à envoyer une trame au destinataire ping, avec le message correspondant à notre pseudo.
Cela signifie que ping devient un nom réservé : son utilisation comme pseudonyme doit être interdite.
from microbit import *
import radio

radio.on()  # Active la radio
radio.config(channel=10)  # Définit un canal (10 ici)
SEP = '¤'
PSEUDO = 'Mathieu'

while True:
    if button_a.was_pressed():
        msg_envoi = input("Message ?")
        dest = input("Destinataire ?")
        radio.send(dest+SEP+PSEUDO+SEP+msg_envoi)  # Envoie une trame

    if button_b.was_pressed():
        radio.send('ping'+SEP+PSEUDO)  # Envoie un ping pour signaler sa présence

    trame = radio.receive() # Permet de vérifier régulièrement la réception d'un message
    if trame:
        parts = trame.split(SEP)
        if len(parts) == 3 and parts[0] != '' and parts[1] != '' and parts[2] != '':
            if parts[0] == PSEUDO:
                print(parts[2])

Prise en compte du ping des autres

Nous devons prendre en compte les ping et ajouter l'identifiant qui s'est signalé à nous à une liste, pour faciliter son utilisation.
On utilise un dictionnaire pour stocker les pseudos, car un dictionnaire, par construction, ne peut pas avoir deux clés identiques. Cela nous permet donc :
  • d'éviter les doublons
  • de stocker une valeur associée à chaque pseudo (utile pour la suite)
from microbit import *
import radio

radio.on()  # Active la radio
radio.config(channel=10)  # Définit un canal (10 ici)
SEP = '¤'
PSEUDO = 'Mathieu'

annuaire = {}

while True:
    if button_a.was_pressed():
        msg_envoi = input("Message ?")
        dest = input("Destinataire ?")
        radio.send(dest+SEP+PSEUDO+SEP+msg_envoi)  # Envoie une trame

    if button_b.was_pressed():
        radio.send('ping'+SEP+PSEUDO)  # Envoie un ping pour signaler sa présence
        print(annuaire)

    trame = radio.receive() # Permet de vérifier régulièrement la réception d'un message
    if trame:
        parts = trame.split(SEP)
        if len(parts) == 2 and parts[0] == 'ping' and parts[1] != '':
            annuaire[parts[1]] = 'toto'

        if len(parts) == 3 and parts[0] != '' and parts[1] != '' and parts[2] != '':
            if parts[0] == PSEUDO:
                print(parts[2])

Automatisation du ping

On utilisera la fonction running_time() disponible sur les cartes micro:bit, ainsi que l'opérateur modulo %.
Explication de la ligne if running_time() % 5000 < 10 :
  • running_time() nous donne le nombre de millisecondes écoulées depuis le démarrage de la carte micro:bit
  • running_time() % 5000 nous permet d'obtenir le reste de la division par 5000
  • si ce reste est inférieur à 10ms, alors nous venons de dépasser 5 secondes depuis moins de 10 millisecondes
Cette ligne nous permet donc d'activer l'envoi du ping toutes les 5 secondes
from microbit import *
import radio

radio.on()  # Active la radio
radio.config(channel=10)  # Définit un canal (10 ici)
SEP = '¤'
PSEUDO = 'Mathieu'

annuaire = {}

while True:
    if running_time() % 5000 < 10:
        radio.send('ping'+SEP+PSEUDO)
        sleep(10) # mise en pause pendant 10ms pour éviter d'envoyer le ping plusieurs fois d'un coup

    if button_a.was_pressed():
        msg_envoi = input("Message ?")
        dest = input("Destinataire ?")
        radio.send(dest+SEP+PSEUDO+SEP+msg_envoi)  # Envoie une trame

    if button_b.was_pressed():
        print(annuaire)

    trame = radio.receive() # Permet de vérifier régulièrement la réception d'un message
    if trame:
        parts = trame.split(SEP)
        if len(parts) == 2 and parts[0] == 'ping' and parts[1] != '':
            annuaire[parts[1]] = 'toto'

        if len(parts) == 3 and parts[0] != '' and parts[1] != '' and parts[2] != '':
            if parts[0] == PSEUDO:
                print(parts[2])

Sélection du destinataire

Le dictionnaire créé à l'étape 6 contient les pseudos des différents utilisateurs du réseau de communication. On peut utiliser ce dictionnaire pour permettre de choisir le destinataire dans une liste, plutôt que d'avoir à recopier son pseudo à chaque fois.
Attention, en fonction des ping reçus, la liste des utilisateurs va forcément évoluer au fil du temps. Il faut donc la créer à partir du dictionnaire à chaque fois qu'on a besoin de choisir un utilisateur.
from microbit import *
import radio

radio.on()  # Active la radio
radio.config(channel=10)  # Définit un canal (10 ici)
SEP = '¤'
PSEUDO = 'Mathieu'

annuaire = {}

def choix_destinataire():
    utilisateurs = { str(index): pseudo for index,pseudo in enumerate(annuaire)}
    print(utilisateurs)
    choix = input("Utilisateur ?"")
    return utilisateurs[choix]

while True:
    if running_time() % 5000 < 10:
        radio.send('ping'+SEP+PSEUDO)
        sleep(10) # mise en pause pendant 10ms pour éviter d'envoyer le ping plusieurs fois d'un coup

    if button_a.was_pressed():
        msg_envoi = input("Message ?")
        dest = choix_destinataire()
        radio.send(dest+SEP+PSEUDO+SEP+msg_envoi)  # Envoie une trame

    if button_b.was_pressed():
        print(annuaire)

    trame = radio.receive() # Permet de vérifier régulièrement la réception d'un message
    if trame:
        parts = trame.split(SEP)
        if len(parts) == 2 and parts[0] == 'ping' and parts[1] != '':
            annuaire[parts[1]] = 'toto'

        if len(parts) == 3 and parts[0] != '' and parts[1] != '' and parts[2] != '':
            if parts[0] == PSEUDO:
                print(parts[2])