2017-09-26 9 views
3

J'essaye de programmer un générateur d'adresses d'automate. Cependant là je dois faire l'addition peu sage pour trouver la prochaine adresse disponible. Cela signifie que si je commence par l'adresse 0.0 et que j'ajoute 2 bits, alors l'adresse libre suivante sera 0,3. Il monte jusqu'à 0,7 puis la prochaine adresse est de 1,0 jusqu'à 1,7 puis 2,0 et ainsi de suite.Comment faire pour ajouter bit à bit dans C#?

En fonction du type de données que j'ajoute à l'addition, l'adresse libre suivante doit être calculée.

Par exemple, un bool est un bit. 0.1 -> 0.2 -> 0.3 et ainsi de suite Un octet a 8 bits si j'ajoute un octet et la dernière adresse libre est 0.4 la prochaine adresse libre devrait être 2.0. Un mot a 16 bits alors 0.0 -> 2.0 -> 4.0 et ainsi de suite. Un double mot a 32 bits alors 0.0 -> 4.0 -> 8.0 et ainsi de suite.

Je suis à la recherche d'une implémentation en C# où je peux ajouter les différents types en entrée et il l'ajoute et me donne l'adresse correspondante et stocke ensuite la prochaine adresse libre interne pour la prochaine opération.

Par exemple:

Type   Startaddress 
1 Bool   0.0   (->0.1) 
2 Bool   0.1   (->0.2) 
3 Byte   1.0   (->1.7) as 8 bits are required 
4 Bool   2.0   (->2.1) 
5 Word   3.0   (->4.7) as 16 bits are required 
6 Double Word 5.0   (->8.7) as 32 bits are required 

Toute idée comment je pourrais mettre en œuvre que, à part un grand nombre de cas et d'autre boucle? Je suis à la recherche d'une approche élégante de l'opérateur surchargé.

+1

« si j'ajoute un octet et la dernière adresse libre était de 0,4 devrait être 2.0 l'adresse suivante libre » comment est-ce calculé? –

+0

@ JakubDąbek: Ça n'a pas beaucoup de sens pour moi non plus ... – JuanR

Répondre

0

Le seul « truc » à votre problème est la notation de 0,0 à 0,7 pour les adresses de bits et les types C# ne correspondent pas exactement avec les types dans votre spécification.

La classe principale I présente ici stocke l'adresse en tant que décalage de bits en interne et fournit la fraction entière et décimale via la méthode fAddress().

Votre exemple montre l'alignement sur les limites d'octets, mais n'aligne pas les mots ou les doubles mots - c'est ce que j'ai implémenté. Les commentaires montrent comment faire cela différemment si le PLC se soucie.

Vous devrez ajouter le code pour stocker les valeurs aux adresses de type byte.bit.

using System; 

namespace PLCAddress 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      PLCAddress a = new PLCAddress(); 
      float address; 
      bool boolA = true; 
      byte byteA = 7; 
      ushort wordA = 65535; 
      uint dblwordA = 4294967295; 

      address = a.Store(boolA); 
      Console.WriteLine(address.ToString()); 

      address = a.Store(boolA); 
      Console.WriteLine(address.ToString()); 

      address = a.Store(byteA); 
      Console.WriteLine(address.ToString()); 

      address = a.Store(boolA); 
      Console.WriteLine(address.ToString()); 

      address = a.Store(wordA); 
      Console.WriteLine(address.ToString()); 

      address = a.Store(dblwordA); 
      Console.WriteLine(address.ToString()); 
     } 
    } 
    public class PLCAddress 
    { 
     protected uint _address; 
     public PLCAddress() 
     { 
      _address = 0; 
     } 

     public float Store(bool b) 
     { 
      float rv = fAddress(); 
      _address += 1; 
      return rv; 
     } 
     public float Store(byte b) 
     { 
      float rv = fAddress(8); 
      _address += 8; 
      return rv; 
     } 
     public float Store(ushort b) 
     { 
      float rv = fAddress(8); // use fAddress(16) if words need to be on word boundaries 
      _address += 16; 
      return rv; 
     } 
     public float Store(uint b) 
     { 
      float rv = fAddress(8); // use fAddress(32) if double words need to be on double word boundaries 
      _address += 32; 
      return rv; 
     } 

     protected float fAddress() 
     { 
      return (float)Whole + (float)Fraction/10; 
     } 

     protected float fAddress(uint alignment) 
     { 
      uint roundup = alignment - 1; 
      uint mask = ~roundup; 
      uint AlignedAddress = _address + roundup; 
      AlignedAddress = AlignedAddress & mask; 
      _address = AlignedAddress; 
      return fAddress(); 
     } 
     protected uint Whole 
     { 
      get { return _address/8; } 
     } 
     protected uint Fraction 
     { 
      get { return _address % 8; } 
     } 
    } 
} 
0

Vous pouvez stocker ces adresses dans un int - la partie inférieure dans les 3 premiers bits, le reste dans le reste des bits et obtenir l'adresse à partir de là. Cela vous permet de faire de l'arithmétique normale sur ces adresses et numéros. Si l'adresse est dans une chaîne que vous pouvez faire quelque chose comme ceci:

public static int ToIntAddress(this string str) 
{ 
    var values = str.Split('.'); 
    int lower = int.Parse(values[1]); 
    int higher = int.Parse(values[0]) << 3; 
    return lower + higher; 
} 

public static string ToAddress(this int address) => $"{address >> 3}.{address & 0b0111}"; 

("3.0".ToIntAddress() + 15).ToAddress() // "4.7" 
("5.0".ToIntAddress() + 31).ToAddress() // "8.7" 
("0.4".ToIntAddress() + 7).ToAddress() // "1.3" 
0

Personnellement, je préfère une approche orientée objet:

public class MemoryManager 
{ 
    private int _dataSize = 0; 

    public enum DataTypes 
    { 
     Bool = 1, 
     Byte = 8, 
     Word = 16, 
     DWord = 32 
    } 
    public MemoryLocation Add(DataTypes type) 
    {    
     var address = GetCurrentAddress(); 
     _dataSize += (int)type; 
     return address; 
    } 

    private MemoryLocation GetCurrentAddress() 
    { 
     int currentByteLocation = _dataSize/8; 
     int currentBitLocation = _dataSize % 8;    
     return new MemoryLocation(currentByteLocation, currentBitLocation); 
    }   
} 

public class MemoryLocation 
{ 
    public MemoryLocation(int byteLocation, int bitIndex) 
    { 
     ByteLocation = byteLocation; 
     BitIndex = bitIndex;    
    } 
    public int ByteLocation { get; private set; } 
    public int BitIndex { get; private set; }   
    public override string ToString() 
    { 
     return string.Format("[{0},{1}]", ByteLocation, BitIndex); 
    } 
} 

Je fouetté ceci réel rapide, mais vous pouvez utiliser d'autres méthodes plus simples pour générer l'adresse suivante.

0

Vous pouvez utiliser ceci:

public int BitWiseAdd() 
{ 
      int FirstNumber = 50; 
      int SecondNumber = 60; 
      while (SecondNumber !=0) 
      { 

       int carry = FirstNumber & SecondNumber; 
       FirstNumber = FirstNumber^SecondNumber; 
       SecondNumber = carry << 1; 
      } 
      return FirstNumber; 


}