Modules Yoctopuce: inventaire et arborescence

Modules Yoctopuce: inventaire et arborescence

L'API Yoctopuce a été conçue pour contrôler très facilement n'importe quel module Yoctopuce avec un minimum de code: Il est ainsi très facile d'inventorier tous les modules directement connectés par USB à une machine. En revanche, jusqu'à aujourd'hui, il était assez difficile, voire impossible, de reconstituer l'arborescence exacte d'un système basé sur des modules Yoctopuce, en particulier pour les modules accessibles par réseau. Il se trouve que la dernière version de l'API permet de faire ça grâce à trois nouvelles fonctions.

Question: peut-on détecter la structure de ce banc de test Yoctopuce?
Question: peut-on détecter la structure de ce banc de test Yoctopuce?


Inventaire USB local

Les fonctions pour réaliser un inventaire de tous les modules Yoctopuce sont apparues dès les premiers jours. Il s'agit des fonctions FirstModule et nextModule qui permettent d'obtenir en 5 lignes la liste de tous les modules connectés par USB, voici un exemple en C#:

 YAPI.RegisterHub("usb", ref errmsg)
 m = YModule.FirstModule();
 while (m!=null)
    { Console.WriteLine(m.get_serialNumber());
      m = m.nextModule();
    }


Le cas des hubs

Il est tout aussi facile d'énumérer tous les modules accessibles par USB ou par Ethernet: il suffit de rajouter un registerhub avec le paramètre "net" et d'attendre un peu que les hubs réseau aient eu le temps de se manifester avant de commencer l'énumération.

 YAPI.RegisterHub("net", ref errmsg)
 YAPI.RegisterHub("usb", ref errmsg)
 YAPI.Sleep(2000, ref errmsg);
 m = YModule.FirstModule();
 while (m!=null)
    { Console.WriteLine(m.get_serialNumber());
      m = m.nextModule();
    }


Ce code très simple donne la liste des tous les modules accessibles tant sur USB que sur le réseau local. Mais il y a un hic, il donne une liste plate: on ne sait pas quel module est branché sur quel hub.

Liste des modules connectés à un hub

Jusqu'à présent le seul moyen d'énumérer les modules connectés à un hub Yoctopuce était d'énumérer ses ports: le nom logique d'un port de hub prend automatiquement pour valeur le numéro de série du module qui lui est connecté. Voici un petit bout de code qui énumère toutes fonctionnalités d'un hub, trouve les ports et utilise leur nom logique pour retrouver les modules connectés.

static void hubSubDevices(YModule hub)
  { for (int i = 0; i < hub.functionCount(); i++)
      { string fctname = hub.functionId(i);
        if (fctname.Length > 7 && fctname.Substring(0, 7) == "hubPort")
          { string logicalName = hub.functionName(i);
            if (logicalName != "")
              { YModule m = YModule.FindModule(logicalName);
                Console.WriteLine(m.get_serialNumber()+' '+m.get_productName());
              }
          }
      }
  }


Ce code n'est pas parfait: il ne donne que la liste de modules directement connecté au hub, il ne permet pas d'obtenir la liste des YoctoHub-Shield qui lui sont connectés, et encore moins la liste de modules qui sont connectés à ces shields. Il ne permet pas non plus d'énumérer les modules contrôlés par un VirtualHub, car un VirtualHub n'a pas de fonction hubPort.

La méthode get_subDevices

La classe YModule met à disposition une nouvelle méthode, get_subDevices, qui permet d'obtenir directement les numéros de série de tous les modules connectés à un hub, y compris les shields et les modules qui leur sont raccordés. Cerise sur le gâteau, elle marche aussi avec les VirtualHub. Voici un court exemple d'utilisation.

static void hubSubDevices(YModule hub)
  { List<String> subDevices = hub.get_subDevices();
    for (int i = 0; i < subDevices.Count; i++)
      {  Console.WriteLine(subDevices[i]);
      }
  }


Notez que la liste des sous-modules est retournée en vrac, pour savoir quel module est branché sur quel port, vous allez devoir utiliser l'astuce des noms logiques des fonctions hubport, qui marche aussi sur les shields.

Construire une arborescence dynamique

On a vu comment construire une arborescence statique, autrement dit, comment réaliser une photographie de l'arborescence des modules accessibles à un moment donné. Mais dans la vraie vie, cette arborescence est susceptible de changer en permanence. On a affaire à des modules plug and play qui peuvent être branchés ou débranchés à tout moment. On pourrait bien sûr reconstruire notre arborescence à intervalle régulier, mais ce n'est pas la méthode la plus pratique, ni la plus efficace.

DeviceArrivalCallback et DeviceRemovalCallback

L'API vous permet de définir deux fonctions qui seront automatiquement appelées à chaque fois que votre application voit apparaître ou disparaître un nouveau module, voici un petit exemple, toujours en C#:

  static void arrivalCallback(YModule dev)
   {  Console.WriteLine("arrival: " + dev.get_serialNumber());
   }

  static void removalCallback(YModule dev)
   {  Console.WriteLine("removal: " + dev.get_serialNumber());
   }

  static void Main(string[] args)
   { string errmsg="";
     YAPI.RegisterHub("usb", ref errmsg);
     YAPI.RegisterHub("net", ref errmsg);
     YAPI.RegisterDeviceArrivalCallback(arrivalCallback);
     YAPI.RegisterDeviceRemovalCallback(removalCallback);
     while (true)
      { YAPI.UpdateDeviceList(ref errmsg);
        YAPI.Sleep(1000, ref errmsg);
      }
    }


Cette méthode donne elle aussi une liste à plat des modules au fur et à mesure qu'ils apparaissent. Mais la dernière version de la librairie Yoctopuce contient deux nouvelles méthodes dans la classe YModule, qui vont permettre de reconstruire l'arborescence.

  • YModule.get_url() donne le chemin d'accès interne à un module Yoctopuce. C'est une information un peu ésotérique qui n'est généralement pas passionnante pour l'utilisateur moyen, mais elle permet de détecter quand un module est directement branché par USB: dans ce cas, cette méthode renvoie simplement la chaîne de caractères "usb".
  • YModule.get_parentHub() renvoie le numéro de série du hub parent d'un module, ou une chaîne vide s'il n'y a pas de parent. Attention, dans le cas d'un module connecté à un shield, lui-même connecté à un hub, ce sera le numéro de série du hub et pas celui du shield qui sera renvoyé.


En utilisant ces deux méthodes, on peut facilement reconstruire l'architecture de tout un système en créant une structure de données en forme d'arbre, et en la mettant à jour à chaque fois qu'un nouveau module apparaît ou disparaît. Par exemple si on suppose que KnownHubs est une liste d'objets de type KnownHub, dont le premier élément correspond artificiellement à la liste des modules connectés par USB, le code de l'arrivalCallback pourrait ressembler plus ou moins ça:

static void arrivalCallback(YModule dev)
  { string serial = dev.get_serialNumber();

    if (dev.get_url() == "usb") // usb device case
     { KnownHubs[0].addSubdevice(dev);
     }
    else if (serial.Substring(0, 7) == "YHUBSHL") // shield
     { findHub(dev.get_parentHub()).addShield(dev);
     }
    else if (dev.get_parentHub() == "")  // network hub or virtualhub
     { KnownHubs.Add(new KnownHub(dev));
     } // regular device connected to a hub
    else findHub(dev.get_parentHub()).addSubdevice(dev);
  }
 



Et il suffit d'utiliser le removalCallback pour supprimer de l'arborescence les modules qui disparaissent. Attention cependant, removalCallback fournit bien un objet YModule en paramètre, mais il correspond à un module qui vient de disparaître, probablement à cause d'une déconnexion. Par conséquent, faute de pouvoir communiquer avec le module, les seules informations que cet objet pourra vous fournir sont les informations persistantes comme le numéro de série ou le modèle du module. Ainsi, pas question de lui demander qui était le hub parent. Vous devez retrouver l'élément à supprimer de l'arborescence par vos propres moyens, par exemple:

static void removalCallback(YModule dev)
  { string serial = dev.get_serialNumber();
    for (int i = KnownHubs.Count - 1; i >= 0; i--)
     { if (KnownHubs[i].get_serial() == serial)
        { KnownHubs.RemoveAt(i);
          return;
        }
       if (KnownHubs[i].removeSubDevice(dev))
        { return;
        }
     }
  }
 


Réponse: oui, on peut
Réponse: oui, on peut


Conclusion

Ça n'a l'air de rien mais, grâce à l'ajout de trois méthodes à la classe YModule, il est maintenant possible de reconstruire en temps réel l'arborescence de tous les modules Yoctopuce connectés au réseau local ou encore par USB. Si vous souhaitez approfondir le sujet, vous trouverez dans toutes les librairies Yoctopuce un répertoire nommé Prog-DevicesTree qui contient un exemple complet qui construit et maintient cette arborescence à jour.


Commenter aucun commentaire Retour au blog












Yoctopuce, get your stuff connected.