dimanche 8 février 2015

Arduino Ehternet Shield

Dans mes tests touchant la communication Ethernet et Arduino, j'ai commencé par le plus facile, soit le shield ethernet standard. Non seulement la librairie est incluse dans le IDE mais comme c'est un shield, ça se branche facilement. J'ai donc avancer mon code de serveur web au point de pouvoir recevoir des requêtes et y répondre. 

Le code est assez simple merci. Je me suis basé sur les exemples afin de faire un serveur Ethernet dont l'IP est obtenu via le DHCP et qui écoute sur le port 80. Ensuite, suffit de boucler sur l'attente d'une requête, ce qui retourne un objet EthernetClient implémentant un Stream.  Suffit de lire et d'écrire comme n'importe quel autre Stream ( tel que Serial ). Je n'ai pas fais de test avec plusieurs requêtes concurrentes ni des volume de données important, mais pour le moment tout marche numéro 1.

Par contre. la librairie Ethernet et SPI viennent prendre quelque peu de RAM. Comme mon but est d'avoir un serveur web assez complet sur un UNO n'ayant que 2K de RAM, ça reste un assez bon défi.

Alors voici quelque truc utiliser pour sauvegarder de la RAM:

  1. L'URL et les autre objet de type chaîne de caractère sont hashé sur 32 bits (FNV) et la comparaison se fait selon le hash. Plus rapide qu'une série de strcmp et prendre moins de RAM. 
  2. Aucune allocation de mémoire n'est dynamique et tout se fait dans un buffer configurable pour le moment de 256 octets ( décodage des caractères URL, hashing, etc ).
  3. Les valeur de hash sont gardé dans un tableau en PROGMEM et l'index 8bit du hash, si trouvé, est retourné.
  4. Seulement si  le client support gzip, les page HTML en PROGMEM pré-compressées sont retournées.
  5. Un objet HTTPResponse permet de spécifier le type et options de la réponse et la génération HTTP se fait via des string gardées en PROGMEM.
  6. L'analyse de la requête se fait ligne par ligne et un objet HttpRequest contenant les attributs selon des define et les hash de l'URL, host et connection est retourné.
L'idée est d'utiliser le plus possible l'espace FLASH et non la RAM. Reste qu'il n'y a que 32K de Flash sur un UNO.

N'empêche, présentement le serveur répond avec une erreur 404 sir l'URL n'est pas trouvé, deux page ( /index.html et /data.html ) retourne des page HTML en PROGMEM et un réponse en JSON a partir d'un senseur de température LM35 branché su A1 répond tel un service REST via /api/temperature. 

Ce n'est pas optimisé ni testé et pas très fonctionnel encore mais lorsque ce sera plus ready, je mettrai le tout sur github.  Reste a solidifer la gestion des paramètres de l'URL ( via un callback ) et implémenter le même genre de callback pour analyser l'envoie de formulaire et ce devrait être assez fonctionnel pour être distribué. Va reste a implémenter le Websocket et devrait permettre d'implémenter à peu près n'importe quel projet ( avec tout de même plusieurs limitations ).

Prochaine étape est d'ajouter une classe encapsulant le EthernetClient afin d'en compiler selon un define des version utilisant UIPEthernet afin de ne pas lié le serveur à une librairie précise. Je pourrai tester mon autre petit board Ethernet qui celui nécessite un voltage divider puisqu'il fonctionne sur 3.3 volt.

Évidemment, le but est de faire une page dont le Facicon, css et images proviennent du Arduino et dont la mise à jours des données et le contrôle du module s'effectue en javascript via des webservices. Donc plus évolué que simplement retourné une réponse harcodé lorsque l'on reçoit un GET et attendre une double fin de ligne. Cependant, dans une optique M2M ( Machine 2 Machine ) quelque chose que MQTT est plus approprié. Ici, c'est d'en faire un senseur intéractif via tablette et PC en plus d'être M2M friendly.

mardi 27 janvier 2015

Arduino et ethernet

Bien que je suis terriblement muet depuis plusieurs mois, ce n'est pas parce que je n'ai rien programmé. En fait, je crois que me qualifier d'expert sous Arduino n'est pas exagéré. Je ne suis pas un maître ninja des optimisation des appels bas niveau, mais disons qu'il n'y a plus beaucoup de projets qui me sont hors de porté.

Chose que j'ai peu expérimenté est la communication ethernet filaire. J'ai assez bien implémenté le sans-fils grâce au module XBEE S6B mais je n'ai jamais fait de branchement RJ45.

Il existe l'option officielle utilisant le shield Ethernet ou encore la version Ethernet du Arduino. La librairie est fournie de-facto avec le IDE et les deux options intègre une fente micro. Il est possible de fournir le courant via le RJ-45 avec les version PoE. Cette option utilise en fait la puce W5100 de Wiznet et est assez dispendieuse. Il existe aussi des modules beaucoup moins dispendieux basés sur la puce ENC28J60 de Microchip technologies. Alors qu'un module simple basé sur le W5100 coûte 13$ chez Robotshop, un module basé sur le ENC28J60 se détail aux alentour de 5$. Évidemment, les deux modules ne sont pas totalement équivalent. Le W5100 permet une communication en 100BaseT alors que le ENC28J60 est limité à 10BaseT. Mais avec un microcontrôleur à 16 MHz et 2 KBytes de RAM, être capable de communiquer à 20 MBytes secondes est plus un inconvénient qu'un atout. Il y a sûrement d'autre avantage au W5100 mais pour les besoins de bases, les deux sont quasi identique. La librairie UIPEthernet remplace la librairie Ethernet standard avec peu, sinon pas de changement au code.

Oui, le wifi est plus pratique, mais dans un optique de simplicité de configuration, pouvoir demander au DHCP une adresse et être up and running est un avantage. Enfin, je viens de recevoir les deux version, reste à terminer l'AI des turret de portail afin qu'elles puissent se parler!