• Création d'une image Windows CE - Part II

    Voila, ça y est j’ai (enfin ?) trouver un peu de temps pour faire booter un Windows CE sur ma carte VIA Eden. Bon, si je n’avais pas passé 3 heures à essayer de faire démarrer mon adaptateur CompactFlash<->IDE, cela se serait assez bien passé.

     Je viens de démarrer une image de Windows CE sur la configuration suivante :

    • Carte-mère VIA EDEN 5000 avec un processeur 533Mhz
    • Carte vidéo, LAN 10/100 et chipset audio intégré
    • 256Mo de Mémoire

     Bon, ce n’est pas spectaculaire, en fait, mais voici le résultat :

    CE-1

    Cela devient plus impressionnant quand je fais la liste des choses que ce système peut faire pour un tout petit peu plus de 12Mo :

    • support d’un touchscreen USB
    • support de .net Compact Framework 2.0
    • support de media amovible USB 2 (pour l’instant les disques de plus d’un giga ne sont pas accessible, mais cela ne devrait pas tarder)
    • réseau TCP/IP
    • serveur de fichier
    • Traiter des images bmp/jpg/png/gif

    Allez, maintenant, il ne me reste plus qu’à développer des choses à faire tourner sur ce bidule !

  • Création d'une image Windows CE

    Deux heures…

    Voila le temps qu’il m’a fallu entre la fin de téléchargement du kit d’évaluation Windows CE et la premiere exécution de l’émulateur pour un périphérique de test.

    WindowsCE-Logo.s[1]

    Cela faisait un moment que j’avais envie de tester Windows CE (pour les non-informaticiens et/ou les anti-microsoft, Windows CE est l’OS «générique» qui a été dérivé pour produire les PocketPC et autres Smartphone de la gamme Windows Mobile).

    Kezako ?

    CE est un système destiné à être embarqué, cela à pour principales conséquences de limiter :

    • l’espace de stockage utilisable, souvent limité à une mémoire flash de 16 à 64Mo,
    • la puissance de traitement de la machine, à quelques exceptions prêt, les processeurs embarqués sont encore très loin des performances de nos processeurs de PC/Mac

    Ce bridage, de fait, des ressources interdit l’utilisation d’un OS aussi gourmand que Windows XP, MacOS ou les version récentes de Linux, d’autres solutions ont donc dues être trouvées. La transformation Linux -> EmbeddedLinux (NSLU) qui s’est opéré dans le monde libre se manifeste de façon un peu plus complexe du coté Microsoft. Le géant de Seattle s’est en effet dispersé en deux OS adaptés :

    • WindowsCE (le sujet actuel), destiné aux vrais périphériques embarqués, ayant des limitations physiques importantes
    • Windows XP Embedded destiné à des systèmes disposant de beaucoup plus de ressources et qui n’est en fait qu’un dérivé de XP.

    Pour faire fonctionner un périphérique sous WinCE, le premier travail est donc de préparer une «image» de votre futur système en n’y ajoutant que ce dont vous aurez besoin : pas question de mettre la totalité des fonctionnalités d’un Windows complet et la collection de tous les drivers sur une mémoire flash de 8Mo…

    Et donc ?

    Revenons au sujet initial et au sujet de mon expérience : essayer de construire un périphérique embarqué simple et lui faire exécuter un logiciel en .net. C’était vraiment «pour faire joujou», mais l’expérience est plutôt intéressante.

    Première phase : la découverte de PlateformBuilder.

    Premier constat : l’interface de création d’images pour Windows CE est relativement claire, ressemble à s’y méprendre aux anciennes versions de Visual Studio et est assez intuitive. Par contre, on voit tout de suite que ce n’est pas pour les débutants : il y a plein de barbarismes un peu partout, difficile de s’y retrouver quand on a juste téléchargé ce soft «pour voir».

    PB-1
    L'interface de PlatformBuilder

    Deuxieme phase : mise à jours.

    1/4 plus tard, après avoir «tripatouillé» un peu partout pour essayer de comprendre (merci la doc pour les quelques explications qui ont permis de mettre en adéquation les termes utilisé et mes connaissances informatiques), c’est l’heure du deuxieme constat : «eh mais… c’est un vieux .net (compact framework 1.0) là dedans… comment on fait pour mettre le nouveau ?» Eh bien la solution est simple, on passe sur le site de Microsoft et on s’aperçoit qu’il y a deux tonnes et demies de mise à jour à installer. C’est l’occasion de rentabiliser l’accès ADSL…

    Troisieme phase : la création d’une image CE «de base»

    Bon, ce n’est pas de tout ça : c’est bon mon PB (Platform Builder) est prêt, je me lance !

    Après avoir sélectionné les BSP (en simplifiant un peu, une BSP est une architecture processeurs, il y en a quelques unes : x86, ARM, etc) cibles et un modèle de périphérique (j’ai pris «TinyKernel» qui permet d’avoir une configuration minimale), le projet est prêt à être complété.

    PB-2
    Mon projet

    La méthode n’est pas bien compliqué : il s’agit de sélectionner les fonctions que vous souhaitez ajouter à votre plateforme dans la liste de droite de les glisser vers votre projet. PlateformBuilder se chargeant de vérifier les dépendances. Par exemple, je souhaite que ma plateforme gère les périphériques USB de stockage (clés USB), il me reste donc à localiser le module correspondant, et à l’ajouter.

    PB-3
    Mon projet après l'ajout du controleur USB MassStorage

    Après avoir fait le tour pendant quelques minutes des différents modules disponibles, mon image est passé de 850Ko à 7800Ko : j’ai ajouté .net, la gestion des périphériques clavier/souris, un serveur web avec support ASP, le shell graphique, etc. J’ai peut-être ajouté des trucs qui ne me serviront pas, mais il sera toujours temps de regarder plus en détail dans un essai ultérieur.

    Quatrième phase : la compilation

    Bon, eh bien le moment est décisif : je lance la compilation. Comme je n’ai pas besoin de drivers particuliers, ni même de fonctions spécifiques, mon image de CE est «prête» à être testée. La compilation dure un certain temps (presque 1/2h pour compiler les deux configurations/BSP : Emulateur + CEPC en debug), mais c’est bientot le grand moment : celui de l’exécution.

    PB-4
    L'émulateur ayant chargé mon image

    Miracle, mon émulateur s’est lancé sans problèmes (et je crois effectivement que ça tiens du miracle, si je m’en réfère aux messages dans les newsgroup). Bon, les fonctionnalités sont très limités, vu que je n’ai rien installé comme logiciels (je crois que je vais quand même ajouter FreeCell ou le Solitaire, histoire de pouvoir m’amuser avec l’émulateur), mais le principe est là : je suis prêt à installer et faire tourner des applications WindowsCE.

    Il me reste maintenant deux choses à faire, lorsque j’aurais un peu de temps libre :

    • Ajouter un programme .net dans l’image, un «Hello Device !» me paraît être un bon candidat.
    • Essayer de comprendre le BiosLoader qui permet de booter une image sur un vrai périphérique embarqué (j’ai une carte Mini-ITX EPIA800 qui n’a pas encore eu le temps de servir, c’est l’occasion ou jamais avant qu’elle soit utilisée dans un HTPC)

  • Open source ?

    Cela fait quelques semaines que je consacre une bonne partie de mon temps libre à la réalisation d’un logiciel de gestion domotique. En ayant déjà parlé sur www.appartement-de-demain.net (enfin «parlé», j’ai déjà posté des images…) et comme cela n’est pas vraiment le sujet de ce blog je ne m’étendrai pas sur les fonctionnalités de ce soft, mais sur une décision qui marque, pour moi, la fin d’une époque.

    Quattrie (c’est le nom de développement du produit en question) sera plus que probablement publié sous une «licence libre» ! Incroyable, non ?

    Bon, ceux d’entre vous qui me connaissent bien m’ont déjà entendu râler sur ce mode de publication, mais dès que j’arrive à trouver une licence correcte dans la panoplie disponible (la GPL ne me semble pas tout à fait correspondre à mes besoins), je release Quattrie en open source. Comme (évidemment) j’ai un peu de mal à le faire, les sources ne seront pas disponibles immédiatement, mais c’est promis, je les mettrais à disposition pour que tout le monde puisse me dire que je code comme un porc ;).

    Ce n’est pas que je ne veuille pas reconnaître le monde du libre : je me sers de logiciels libres (bien qu’ils ne soient vraiment pas nombreux : XBMC et NDoc semblent être les seuls au moment où j’écris ces lignes, mais j’ai peut-être la mémoire sélective) et j’ai déjà participé (bien que là aussi dans une très petite mesure) à des projets de ce type, mais c’est la première fois que j’envisage sérieusement de publier mon travail sous ce type de licence.

    Voila, quand je vous disais que c’était la fin d’une époque !

  • Conversion chiffres vers lettres

    Voici une petite classe qui permet de convertir un nombre donnée en lettres.Le code est en C#, et devrait donc fonctionner sur toute la plateforme .net

    /// <summary>
    /// Conversion de chiffres vers lettres.
    /// </summary>
    public class Convertisseur
    {
      /// <summary>
      /// Converti une valeur en euros
      /// </summary>
      /// <param name="valeur">
      /// La valeur à convertir</param>
      /// <returns>Une chaine correspondant au nombre</returns>
      /// <remarks>format xxx euro et yyy cent(s)</remarks>
      public static string ConvertirEuro(decimal valeur)
      {
        return Convertir(valeur, 2, " euro", " cent(s)", " et ");
      }
    
      /// <summary>
      /// Conversion d'une valeur decimal en lettres
      /// </summary>
      /// <param name="valeur">Valeur à convertir</param>
      /// <param name="nbDecimales">
      /// Nombre de décimale à conserver&lt;/param>
      /// <returns>Une chaine correspondant au nombre</returns>
      /// <remarks>Pas d'unités, séparateur = ","</remarks>
      public static string Convertir(decimal valeur,
        int nbDecimales)
      {
        return Convertir(valeur, nbDecimales, "", "", ",");
      }
    
      /// <summary>
      /// Conversion d'une valeur decimal en lettres
      /// </summary>
      /// <param name="valeur">La valeur à convertir</param>
      /// <param name="nbDecimales">
      /// Le nombre de decimales à conserver</param>
      /// <param name="uniteEntiere">
      /// Le nom des unités de la partie entière</param>
      /// <param name="uniteDecimale">
      /// Le nom des unité de la partie décimale</param>
      /// <param name="separateur">le séparateur entre les parties</param>
      /// <returns>Une chaine correspondant au nombre</returns>
      public static string Convertir(decimal valeur, 
        int nbDecimales, 
        string uniteEntiere, 
        string uniteDecimale, 
        string separateur)
      {
        valeur = Math.Round(valeur,nbDecimales);
    
        int val = (int) Math.Floor((double) valeur);
        string ret = Convertir(val) + uniteEntiere;
    
        valeur = valeur - val;
        valeur = valeur * (int) (Math.Pow(10,nbDecimales));
        val = (int) Math.Floor((double) valeur);
        if(val>0)
          ret += separateur + Convertir(val) + uniteDecimale;
        
        return ret;
      }
    
      /// <summary>
      /// Conversion d'un entier en lettre
      /// </summary>
      /// <param name="nombre">
      /// L'entier à convertir</param>
      /// <returns>Une chaine correspondant au nombre</returns>
      public static string Convertir(int nombre)
      {
        StringBuilder lettre = new StringBuilder();
        int centaine, dizaine, unite, reste, y;
        reste = nombre;
        
        for(int i=1000000000; i>=1; i/=1000)
        {
          y = reste/i;
          if(y!=0)
          {
            centaine = y/100;
            dizaine  = (y - centaine*100)/10;
            unite = y-(centaine*100)-(dizaine*10);
            switch(centaine)
            {
              case 0:
                break;
              case 1:
                lettre.Append(Convert(centaine*100));
                lettre.Append(" ");
                break;
              default :
                lettre.Append(Convert(centaine));
                lettre.Append(" ");
                lettre.Append(Convert(100));
                if((dizaine == 0)&&(unite == 0)) lettre.Append("s ");
                else lettre.Append(" ");
                break;
            }
                
            switch(dizaine)
            {
              case 0:
                if(unite!=1 || (unite==1 && i!=1000) )
                {
                  lettre.Append(Convert(unite));
                  if(unite!=0) lettre.Append(" ");
                }
                break;
              case 1:
                lettre.Append(Convert(dizaine*10+unite));
                lettre.Append(" ");
                break;
              case 7:
                goto case 1;
              case 9:
                goto case 1;
              default :
    	    lettre.Append(Convert(dizaine*10));
                if(unite==1 && dizaine!=8) lettre.Append("-et-");
                else lettre.Append(" ");
                lettre.Append(Convert(unite));
                lettre.Append(" ");
                break;
    
            } 
            switch (i)
            {
              case 1000000000:
                if(y>1) lettre.Append("milliards ");
                else lettre.Append("milliard ");
                break;
              case 1000000:
                if(y>1) lettre.Append("millions ");
                else lettre.Append("million ");
                break;
              case 1000:
                lettre.Append("mille ");
                break;
            }
          } 
          reste -= y*i;
        } // end for
        if(lettre.Length ==0) return "zero"; 
        
        return lettre.ToString().Trim();  
      }
    
      private static string Convert(int nb)
      {
        switch(nb)
        {
          case 0: return "";
          case 1: return "un";
          case 2: return "deux";
          case 3: return "trois";
          case 4: return "quatre";
          case 5: return "cinq";
          case 6: return "six";
          case 7: return "sept";
          case 8: return "huit";
          case 9: return "neuf";
          case 10: return "dix";
          case 11: return "onze";
          case 12: return "douze";
          case 13: return "treize";
          case 14: return "quatorze";
          case 15: return "quinze";
          case 16: return "seize";
          case 17: return "dix-sept";
          case 18: return "dix-huit";
          case 19: return "dix-neuf";
          case 20: return "vingt";
          case 30: return "trente";
          case 40: return "quarante";
          case 50: return "cinquante";
          case 60: return "soixante";
          case 70: return "soixante-dix";
          case 71: return "soixante-onze";
          case 72: return "soixante-douze";
          case 73: return "soixante-treize";
          case 74: return "soixante-quatorze";
          case 75: return "soixante-quinze";
          case 76: return "soixante-seize";
          case 77: return "soixante-dix-sept";
          case 78: return "soixante-dix-huit";
          case 79: return "soixante-dix-neuf";
          case 80: return "quatre-vingt";
          case 90: return "quatre-vingt-dix";
          case 91: return "quatre-vingt-onze";
          case 92: return "quatre-vingt-douze";
          case 93: return "quatre-vingt-treize";
          case 94: return "quatre-vingt-quatorze";
          case 95: return "quatre-vingt-quinze";
          case 96: return "quatre-vingt-seize";
          case 97: return "quatre-vingt-dix-sept";
          case 98: return "quatre-vingt-dix-huit";
          case 99: return "quatre-vingt-dix-neuf";
          case 100: return "cent";
          case 1000: return "mille";
        }
        return "";
      }
    }