2017-08-11 1 views
2

Je développe une application de mise à niveau de firmware en C# en utilisant VisualStudio 2015. L'application utilise un formulaire basé sur XAML et un code C#. La cible de la mise à niveau du micrologiciel est une carte personnalisée exécutant un processeur STM32F417 (ARM Cortex M4). Le code C# se connecte au 417, amène le 417 à accéder à son chargeur de démarrage (installé en usine) et utilise l'API bootloader pour charger le nouveau micrologiciel..NET SerialPort Write() ajout de caractères et déplacement d'octets

Après chaque transfert de 256 octets (transfert maximum autorisé), une somme de contrôle des données et le nombre d'octets est envoyé, et un octet ACK est reçu du 417 pour montrer que tout a été vérifié pour ce transfert. Le transfert échouerait après quelques blocs de 256 et pour tester le transfert, j'ai mis en place le code C# juste pour transférer le fichier .hex sans aucune des autres vérifications.

Je définis le code pour transférer le microprogramme mis à jour en tant que fichier .hex. ligne par ligne. Il écrit des données sur une ligne série et est capturé en tant que texte dans HyperTerminal. Je mis en œuvre comme une écriture de 256 octets:

 byte[] buffer256 = new byte[256]; 

     // Read the file and process one line at a time 
     System.IO.StreamReader file = new System.IO.StreamReader(path); 
     while ((line = file.ReadLine()) != null) 
     { 
      line = line.Substring(1, line.Length - 1); 

      // Create byte array from string 
      var bytes = GetBytesFromByteString(line).ToArray(); 

      // Assign values to variables from byte array 
      type = bytes[3]; 

      // BLOCK WRITE TO MEMORY 
      if (type == 0) // data type 
      { 
       length = bytes[0]; 

       if (byteCounter >= 255) 
       { 
        _serialPort.Write(buffer256, 0, 256); 

        Array.Clear(buffer256, 0, buffer256.Length); 
        byteCounter = 0; 
       } 

       for (int i = 0; i < length; i++) 
       { 
        buffer256[byteCounter++] = bytes[4 + i]; 
       } 
      } // end BLOCK WRITE TO MEMORY 

      counter++; 
     } // end WHILE loop for loading hex file 

     file.Close(); 

Et aussi comme écriture d'octets simples:

 byte[] buffer256 = new byte[256]; 

     // Read the file and process one line at a time 
     System.IO.StreamReader file = new System.IO.StreamReader(path); 
     while ((line = file.ReadLine()) != null) 
     { 
      line = line.Substring(1, line.Length - 1); 

      // Create byte array from string 
      var bytes = GetBytesFromByteString(line).ToArray(); 

      // Assign values to variables from byte array 
      type = bytes[3]; 

      if (type == 0) 
      { 
       length = bytes[0]; 

       for (int i = 0; i < length; i++) 
       { 
        _serialPort.Write(bytes, 4 + i, 1); 

       } // end FOR loop 

      }// end SINGLE BYTE WRITING 

      counter++; 
     } // end WHILE loop for loading hex file 

     file.Close(); 

Dans les deux cas, le fichier hexadécimal est modifié en écrivant à l'aide de la classe SerialPort . J'ai essayé plusieurs autres méthodes, même WriteAsync dans la classe BaseStream sur laquelle la classe SerialPort est construite (remplaçant les méthodes Stream).

Voici un échantillon (8 mots) du fichier .hex d'origine (données uniquement) par rapport aux données reçues:

Original: 
00F8012B 002AF9D1 18467047 70B50646 
2DF0FEFC 04680546 0A220021 304600F0 

Received: 
00F8012B 002AF9D1 18464670 4770B506 
462DF0FE FC046805 460A2200 21304600 

Ce sont des lignes 49 et 50 de 13391. Les checksums pour certains les blocs ont également été vérifiés et étaient faux. Je suis sûr que c'est la raison pour laquelle les mises à jour du firmware échouent - le chargeur de démarrage calcule une somme de contrôle en fonction de ce qu'il reçoit et échoue lorsqu'il compare la somme de contrôle que l'application C# calcule et envoie.

Ma question est: si le SerialPort (et Stream sous-jacent) n'est pas fiable, que dois-je remplacer avec et comment? Est-il possible de simplement remplacer la classe SerialPort, peut-être avec une classe C++? Ou serait-il préférable de réécrire l'ensemble de l'application en C++ ou autre chose?

+0

Pouvez-vous inclure le code source de 'GetBytesFromByteString'? – Biscuits

+0

Est-ce que 'GetBytesFromByteString' peut renvoyer une mauvaise valeur (la précédente) quand il rencontre un caractère CR/LF? – Biscuits

+0

Envoyez-vous le contenu hexadécimal imprimable du "fichier hexadécimal" ou avez-vous affaire à une traduction binaire à un moment donné? Dernièrement j'ai entendu dire que les bootloaders d'usine STM32 ne parlaient qu'un protocole binaire, mais peut-être qu'il y a une version plus récente. Si votre code de série corrompt le texte, vous avez un problème assez fondamental: que se passe-t-il si vous y envoyez du langage humain? –

Répondre

1

La classe SerialPort elle-même n'est pas fiable. Je l'ai utilisé avec succès sur le bureau et de nombreux appareils CE. Le problème pourrait être le matériel à chaque extrémité, l'un des systèmes d'exploitation, une valeur de configuration fiddly, ou une combinaison de ceux-ci.

Cela pourrait aussi être votre code. Je ne suis pas sûr que vous fassiez quelque chose de mal, mais lire des données binaires dans une chaîne en utilisant ReadLine me semble plutôt bizarre. Avez-vous vérifié octets [] est correct dans un débogueur? PS: si l'un des problèmes matériels est lié à la synchronisation, le passage au C++ peut être utile. Interop est assez indolore pour quelque chose comme ça, donc je ne prendrais pas la peine de réécrire toute l'application, mais je ne connais pas votre situation, donc je ne peux pas en être certain.

+0

Je cherchais simplement à utiliser une fonction d'écriture C++ en utilisant Interop hier. La classe en série que je prévois d'utiliser a quatre fichiers .cpp que je peux mettre dans une DLL? Je ne suis pas sûr de cette partie. Du côté C#, j'ai mis une référence à la fonction write. Maintenant, je dois juste changer mon tableau d'octets en quelque chose qui est compatible avec const void *. Toute contribution sur cette configuration sera utile, car c'est un territoire inexploré pour moi. – Gordon

+0

https://msdn.microsoft.com/en-us/library/55d3thsc.aspx vérifier cela. Je recommande le chemin pinvoke sur COM interop. Donc, standard C DLL et assurez-vous que vos fonctions sont ...__ stdcall, je veux dire? Quoi qu'il en soit, assurez-vous qu'ils correspondent. C'est facile, mais difficile à déboguer :) – zzxyz

+0

En tant que modification, si vous êtes vraiment familier avec la création d'objets COM en C++, ce chemin rend le côté C# complètement non-compliqué. Je suis assez rouillé avec ATL/MFC/COM que je n'aime pas cette approche, cependant. YMMV – zzxyz