Upload de firmware par XMODEM/YMODEM

Upload de firmware par XMODEM/YMODEM

XMODEM et YMODEM sont des protocoles permettant de transférer des fichiers de manière fiable à travers une communication série (UART). Ils ont été conçus pour améliorer la fiabilité des transferts de données sur les lignes téléphoniques analogiques il y a 50 ans, et on aurait pu imaginer qu'ils aient complètement disparu de nos jours. Il reste cependant quelques cas spécifiques où ils sont encore largement utilisés, raison pour laquelle nous venons d'ajouter le support natif pour ces protocoles dans nos modules de communication série.


Pourquoi XMODEM au XXIe siècle ?

Par rapport à tous les autres moyens de transférer des données de manière fiable aujourd'hui (USB, Ethernet, etc.), l'intérêt d'utiliser XMODEM/YMODEM sur une ligne série est que c'est une solution très légère à implémenter: elle ne nécessite que deux fils de données, utilise peu de ressources, et est assez simple à coder, en particulier pour le côté récepteur. Elle est donc encore couramment utilisée par le bootloader de produits basés sur un microcontrôleur pour la mise à jour du firmware. C'est le cas notamment pour les processeurs STM32, pour lequel on trouve des bootloader XMODEM et YMODEM en open-source.

C'est cette application que nous avons principalement ciblé avec notre support XMODEM/YMODEM: l'envoi de fichiers de firmware au bootloader de produits basés sur un microcontrôleur.

Implémentation

L'implémentation de référence de ces protocoles a été écrite en C pour UNIX, et en est assez fortement dépendante. On ne peut pas la transposer directement dans tous les langages de programmation d'aujourd'hui. Il existe d'autres implémentations open source plus récentes, mais avec des qualités très variables et qui ne respectent pas toujours le standard établi.

Nous avons choisi une solution plus optimale: implémenter les protocoles directement dans les modules Yoctopuce. Le code utilisateur n'a qu'à fournir le fichier tel quel au module série Yoctopuce (par exemple un Yocto-Serial-C ou un Yocto-RS232-C), et celui-ci se charge de gérer tout seul le calcul des checksums/CRC, les retransmissions et la gestion de la machine à états du protocole. Le code applicatif est ainsi complètement déchargé de la problématique XMODEM/YMODEM, et notamment des contraintes de timeouts.

Utilisation

La transmission d'un firmware sur une ligne série pouvant prendre plusieurs secondes (voire plusieurs dizaines de secondes selon les cas), nous avons choisi d'offrir une API permettant de surveiller l'avancement de la transmission. Le code de transmission ressemblera donc à ceci:

TIMEOUT = 30          # abort after 30 sec if receiver does not show up
USE_1K_BLOCKS = true  # use XMODEM-1K extension
progress = serial.xmodemUpload(firmwareImage, TIMEOUT, USE_1K_BLOCKS)
while progress < 100:
    # update your progress indicator here, if desired
    progress = serial.xmodemUploadMore()


Si une situation anormale se produit (timeout, ou annulation du transfert par le receveur), la méthode xmodemUploadMore déclenchera une exception avec un message d'erreur correspondant.

Lors d'un transfert XMODEM ou YMODEM, c'est le receveur qui a l'initiative de démarrer le transfert lorsqu'il est prêt. Dans le cas d'un bootloader, deux cas de figure peuvent se présenter selon la conception qui a été faite par le fabricant.

Dans le premier cas, il faut envoyer une commande particulière sur la ligne série pour demander le téléchargement du firmware. A la réception de cette commande, l'appareil commute en mode mise à jour et va réclamer le démarrage du transfert du firmware, jusqu'à le recevoir. Le code d'envoi du firmware a donc la structure suivante:

# request device to reboot to bootloader
serial.writeLine("update_firmware")
# send the firmware image
progress = serial.xmodemUpload(firmwareImage, TIMEOUT, USE_1K_BLOCKS)
while progress < 100:
    # update your progress indicator here, if desired
    progress = serial.xmodemUploadMore()



Dans le deuxième cas, il n'existe pas de commande spécifique de mise à jour, mais l'appareil vérifie rapidement au démarrage si une mise à jour lui est proposée: il essaie systématiquement de lancer un transfert et abandonne si il ne reçoit pays de réponse immédiate. Parfois, cette vérification est conditionnée à la présence d'un signal haut ou bas sur une pin particulière. Pour être sûr que le transfert soit lancé dans le délai imparti, la meilleure solution consiste donc à initier le transfert avant de faire redémarrer l'appareil, de sorte à ce que le Yocto-Serial-C soit immédiatement prêt à envoyer le début du fichier dès qu'il est demandé:

# initiate transfer early
progress = serial.xmodemUpload(firmwareImage, TIMEOUT, USE_1K_BLOCKS)
# pull RTS line, assuming it is connected to the pin triggering the bootloader
serial.set_RTS(1)
# reboot the device to trigger the firmware update
RebootCustomDevice()
# wait until update is completed
while progress < 100:
    # update your progress indicator here, if desired
    progress = serial.xmodemUploadMore()
# update complete, release RTS line
serial.set_RTS(0)



XMODEM ou YMODEM ?

Entre la première implémentation de XMODEM par Ward Christensen en 1977 et la standardisation de YMODEM dix ans plus tard, une foultitude de variantes ont vu le jour, parfois incompatibles entre elles. En 1987, Chuck Forsberg a clarifié ce qu'on devait entendre par les dénominations XMODEM et YMODEM:

  • XMODEM ne gère que le transfert du contenu d'un seul fichier
  • YMODEM permet de transmettre plusieurs fichiers, et de transmettre des métadonnées (nom du fichier, taille, attributs)

La variante XMODEM/CRC qui vérifie l'intégrité des données par un CRC plutôt que par un checksum ne pose aucun problème de compatibilité puisque c'est le receveur qui indique quel type de validation il désire. Les modules série Yoctopuce supportent le mode CRC et le mode checksum de manière transparente.

La variante XMODEM-1k, qui utilise des blocs de 1KB à la place de 128 bytes, exige que les deux parties prenantes l'activent simultanément. C'est pourquoi vous devez spécifier explicitement si vous voulez utiliser des blocs de 1KB, lors de l'appel à xmodemUpload(). XMODEM-1k travaille toujours en mode CRC.

YMODEM transfère le contenu des fichiers selon XMODEM-1k, mais ajoute des paquet de métadonnées autour du contenu pour que le récepteur connaisse d'avance le nom et la taille du fichier, et pour permettre de chaîner plusieurs transferts. Voici comment envoyer plusieurs fichiers en YMODEM avec les modules série Yoctopuce:

nFiles = len(files)
for i in range(nFiles):
    isLast = (i + 1 >= nFiles)
    progress = serial.ymodemUpload(files[i], TIMEOUT, names[i], "", isLast)
    while progress < 100:
        # update your file progress indicator here, if desired
        progress = serial.ymodemUploadMore()



Attention, il arrive que certains vendeurs utilisent abusivement le nom YMODEM pour se référer à XMODEM-1k. Si vous ne devez transférer qu'un seul fichier et que le vendeur spécifie YMODEM, il se peut qu'il s'agisse en fait de XMODEM-1k.

Si votre transfert de firmware ne démarre pas comme prévu, n'oubliez pas que vous pouvez toujours ouvrir l'interface Web de VirtualHub pour observer en temps réel les échanges de données entre le Yocto-Serial-C et votre appareil. Cela peut vous aider à comprendre ce qu'il se passe...

Conclusion

Si vous utilisez des microcontrôleurs avec un bootloader par ligne série, ces nouvelles méthodes devraient vous faciliter la vie pour mettre en place vos procédures de mise à jour et de tests automatiques.

Notez qu'il existe d'autres protocoles encore plus évolués qui ont suivi YMODEM: YMODEM-g, ZMODEM, etc. Mais comme ils n'ont pas été retenus pour les technologies de bootloader, en raison de leur complexité accrue et de l'absence de bénéfice réel, nous ne les avons pas implémentés pour l'instant dans les modules de communication série Yoctopuce.

Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.