Découpage de bytes

Résolu
Signaler
Messages postés
344
Date d'inscription
jeudi 1 mai 2003
Statut
Membre
Dernière intervention
4 avril 2011
-
Messages postés
215
Date d'inscription
mardi 29 juillet 2003
Statut
Membre
Dernière intervention
1 septembre 2006
-
Bonjour,

Je récupère des paquets via le port COM que je dois traiter ensuite.
Notament, dans ce paquet, il y a un timestamp sur 4 bytes répartis de cette manière:
seconds (6 bits)
minutes (6 bits)
hours (5 bits)
days (5 bits)
months (4 bits)
years (6 bits)

N'ayant jamais fait ce genre de chose, je vous demande de l'aide.

(Il faut transformer en binaire et recopier la longueur voulue dans un byte en rajoutant des 0 devant, nan ?)

Merci d'avance.

<!-- / message -->
<!-- sig -->
A voir également:

26 réponses

Messages postés
215
Date d'inscription
mardi 29 juillet 2003
Statut
Membre
Dernière intervention
1 septembre 2006

Erf, j'avoue que j'aimerais bien comprendre où merde mon code vu que c'est exactement ce que tu fais linéairement.
Pourrais-tu juste tester rapidement cette unité:

unit ComTimeStamp;


interface


uses
  Classes,
  Windows,
  SysUtils,
  Dialogs;


type


  {
  seconds (6 bits)
  minutes (6 bits)
  hours (5 bits)
  days (5 bits)
  months (4 bits)
  years (6 bits)
  }
  TCOMTimeStamp = class
     private
       FValues: array[0..5] of Dword;
       FPacket: DWORD;
       procedure GetCOMTimeStampFrom(Packet: DWORD);
       function GetValue(indice: integer): DWORD;
       function COMTimeStampToStr: string;
     public
       constructor Create(Packet: Dword);
       procedure Display;
     published
       property Seconds: DWord index 5 read GetValue;
       property Minutes: DWord index 4 read GetValue;
       property Hours: DWord index 3 read GetValue;
       property Days: DWord index 2 read GetValue;
       property Months: DWord index 1 read GetValue;
       property Years: DWord index 0 read GetValue;
       property COMTimeStamp: string read COMTimeStampToStr;
       property Packet read FPacket;
  end;




implementation


constructor TCOMTimeStamp.Create(Packet: DWord);
begin
GetCOMTimeStampFrom(Packet);
end;


procedure TCOMTimeStamp.GetCOMTimeStampFrom(Packet: DWord);
  const ShrValues: array[0..5] of Byte = (6,4,5,5,6,0);
  const MaskValues: array[0..5] of Byte = ($3f,$0f,$1f,$1f,$3f,$3f);
  var i: integer;
begin
//Sauvegarde
FPacket := Packet;
  for i := Low(MaskValues) to High(MaskValues) do
  begin
      FValues[i] := Packet and MaskValues[i] ;
      Packet := Packet shr ShrValues[i];
  end;
end;


function TCOMTimeStamp.GetValue(indice: integer):DWORD;
begin
result := FValues[indice];
end;


function TCOMTimeStamp.COMTimeStampToStr: string;
var tag: string;
begin
if Hours < 12 then
   tag := 'AM'
else tag := 'PM';
result := (Format('%d:%d:%d %s %d/%d/%.2d', [Hours, Minutes, Seconds,tag, Months, Days,Years]));
end;


procedure TCOMTimeStamp.Display;
begin
ShowMessage(COMTimeStampToStr);
end;


end.

Merci bien,

j!nH
Messages postés
1606
Date d'inscription
samedi 10 juillet 2004
Statut
Membre
Dernière intervention
25 juillet 2014
12
salut,

tu peux utliser un shr(valeur,decalage) puis faire un and 000xxx pour effacer les bits non significatifs


@+

jlen
Messages postés
344
Date d'inscription
jeudi 1 mai 2003
Statut
Membre
Dernière intervention
4 avril 2011
1
Messages postés
135
Date d'inscription
jeudi 14 août 2003
Statut
Membre
Dernière intervention
12 octobre 2006
1
Il n'y a pas besoin de "transformer" en binaire, une valeur entière est toujours représentée en binaire en mémoire.
tu dois te renseigner sur les opératiosn binaires en revanche
( 1 or 1 ) = 1
( 1 or 0 ) = 1
( 0 or 0 ) = 0

( 1 xor 1 ) = 0
( 1 xor 0 ) = 1
( 0 xor 0 ) = 0

( 1 and 1 ) = 1
( 1 and 0 ) = 0
( 0 and 0 ) = 0

//Attention c'est en binaire 1=1, 10=2,  11=3, 100=4, etc...( 100 shr 0 ) 100   ( 1 shl 0 ) 1( 100 shr 1 ) 010   ( 1 shl 1 ) 10( 100 shr 2 ) 001   ( 1 shl 2 ) 100
bon, a supposer que les secondes soient dans les bits de gauche:

0000 0000  0000 0000   0000 0000  0000 0000

function COMTimeStampToString(TimeStamp: Cardinal): String;
Begin
    //Years
    Result:=IntToStr(TimeStamp And $0000003F) + 'Years, ';  // On  prend  que  les  6  derniers  bits de la variable et on masque les autres
    //Month
    Result:=Result+IntToStr((TimeStamp shr 6) And $0000000F)+'Months, ' // Idem, mais avant on décale de 6 bits vers la droite pour virrer l'année
    //Day
    result:=result+IntToStr((TimeStamp shr 10) And $0000001F)+'Days, ' // Idem mais on décale de 10 ( 6 + 4 )
    //etc.
End;

exemple
tes bits ( valeurs au pif ):
1100 1111   0000 1111  1010 1111   1111 0000
And
0000 0000   0000 0000  0011 1111 ( $0000003F en hexa )
=
0000 0000   0000 0000  0000 0000   0011 0000

autre example

1100 1111  0000 1111  1010 1111  1111 0000
shr 6 =
0100 1111  0011 1100   00111110  1011  1111
And

0000 0000  0000 0000   0000 0000  0000 1111 ( $0000001F en hexa )

=
0000 0000  0000 0000   0000 0000   0000 1111

voilà  voilà

bouh
Messages postés
135
Date d'inscription
jeudi 14 août 2003
Statut
Membre
Dernière intervention
12 octobre 2006
1
oops, j'ai oublié des zéros à la seconde ligne du premier exemple ^^'

bouh
Messages postés
135
Date d'inscription
jeudi 14 août 2003
Statut
Membre
Dernière intervention
12 octobre 2006
1
autre example:
1100 1111  0000 1111  1010 1111  1111 0000
shr 6 = ( tu décale de 6 vers la droite )
0000 0011  0011 1100   0011 1110  1011 1111
And
0000 0000  0000 0000   0000 0000  0000 1111 ( $0000001F en hexa )
=
0000 0000  0000 0000   0000 0000  0000 1111

là c'est mieu déjà ( j'sais pas ce que j'avais fouttu... fatigué moi... )

bouh
Messages postés
814
Date d'inscription
vendredi 3 novembre 2000
Statut
Membre
Dernière intervention
30 juillet 2009
3
en passant:

function EncodeDate(Year, Month, Day: Word): TDateTime;

ca risque de t'aider...
Messages postés
215
Date d'inscription
mardi 29 juillet 2003
Statut
Membre
Dernière intervention
1 septembre 2006

Salut,

Un petit exemple:

 {
  seconds (6 bits)
  minutes (6 bits)
  hours (5 bits)
  days (5 bits)
  months (4 bits)
  years (6 bits)
  }
  TCOMTimeStamp = class
     private

     FValues: array[0..5] of Dword;

     FPacket: DWORD;
     procedure Display;
     procedure GetCOMTimeStampFrom(Packet: DWORD);
     function GetValue(indice: integer): DWORD;
     public
     constructor Create(Packet: Dword);
     published
       property Seconds: DWord index 0 read GetValue;
       property Minutes: DWord index 1 read GetValue;
       property Hours: DWord index 2 read GetValue;
       property Days: DWord index 3 read GetValue;
       property Months: DWord index 4 read GetValue;
       property Years: DWord index 5 read GetValue;
  end;

constructor TCOMTimeStamp.Create(Packet: DWord);
begin
GetCOMTimeStampFrom(Packet);
end;

procedure TCOMTimeStamp.GetCOMTimeStampFrom(Packet: DWord);
  const ShrValues: array[0..5] of Byte = (6,6,5,5,4,0);
  const MaskValues: array[0..5] of Byte = ($3f,$3f,$1f,$1f,$0f,$ff);
  var i: integer;
begin
//Sauvegarde
FPacket := Packet;
  for i := Low(MaskValues) to High(MaskValues) do
  begin
      FValues[i] := Packet and MaskValues[i] ;
      Packet := Packet shr ShrValues[i];
  end;
end;

function TCOMTimeStamp.GetValue(indice: integer):DWORD;
begin
result := FValues[indice];
end;

procedure TCOMTimeStamp.Display;
begin
ShowMessage(Format('%d années : %d mois : %d jours : %d heures : %d minutes : %d secondes', [FValues[5],FValues[4],FValues[3],FValues[2],FValues[1],FValues[0]]));
end;

j!nH
Messages postés
215
Date d'inscription
mardi 29 juillet 2003
Statut
Membre
Dernière intervention
1 septembre 2006

Oups place juste la procédure Display en public.

C'est bien sûr optimisable et tu peux enjoliver le tout avec des constantes pour les indices.
C'est uniquement conceptuel comme code...

j!nH
Messages postés
344
Date d'inscription
jeudi 1 mai 2003
Statut
Membre
Dernière intervention
4 avril 2011
1
Bonjour à tous et merci pour votre rapidité,

J'ai essayé la classe et le resultat de display n'est pas correct:
maVar,maVarTemp: LongWord;
cts: TCOMTimeStamp;

temp := '';
MaVar := 0;
for j := 0 to 3 do begin
MaVar := MaVar+LongWord(tampon[nblu-4+j]) shl (j*8);
end;
cts := TCOMTimeStamp.Create(MaVar);
cts.Display;
cts.Free;

Voyez vous le pb ?
Messages postés
215
Date d'inscription
mardi 29 juillet 2003
Statut
Membre
Dernière intervention
1 septembre 2006

Quelle valeur a ma Var?

j!nH
Messages postés
344
Date d'inscription
jeudi 1 mai 2003
Statut
Membre
Dernière intervention
4 avril 2011
1
Voici les 4 bits pour 11:28:37 AM 8/31/06: (149)(197)(254)(6)
149 en binaire donne: 10010101
Les 6 premiers bits sont: 100101 et ça fait bien 37 secondes !

J'espère que maVar à cette valeur: 149 197 254 6 (je n'en suis même pas sur...).
En fait, comment affecter le paramètre attendu par ta classe ?

Seulement je n'arrive pas jongler comme ça avec Delphi !
Messages postés
215
Date d'inscription
mardi 29 juillet 2003
Statut
Membre
Dernière intervention
1 septembre 2006

Récapitulons ma méthode:

Si tu me donnes

binaire : 10010101110001111111111000000110
octet:(149)(197)(254)(6)
décimal:2512911878

37 années, 7 mois, 3 jours, 31 heures, 56 minutes et 6 secondes

Pour moi les secondes commencent à partir de la droite(donc 6).
Tu pars de l'autre sens toi?(d'ailleurs j'espère parce que les résultats sont aberrants là).

j!nH
Messages postés
344
Date d'inscription
jeudi 1 mai 2003
Statut
Membre
Dernière intervention
4 avril 2011
1
Je récapitule parce que je me perds:
les 4 bytes: (149)(197)(254)(6) doivent donner: 11:28:37 AM 8/31/06. (format americain)

Exemple pour les secondes:
(149)(197)(254)(6) donne:
10010101 11000101 11111110 00000110
Les 6 premiers bits sont: 100101 et ça fait bien 37 secondes
les 6 suivants sont: 011100 donnent bien 28 minutes.
...

C'est ce comportement que je m'efforce de reproduire avec delphi.
C'est tellement simple sur papier !

Déjà, comment les concatener dans un word (est ce que mon for est bon) ?
Ensuite, le découper selon les longueur à extraire ?
Messages postés
344
Date d'inscription
jeudi 1 mai 2003
Statut
Membre
Dernière intervention
4 avril 2011
1
Déjà, mon for n'est pas bon vu que ça me retourne
2512780806 au lieu de
2504610384

Voici ma boucle:
MaVar := 0;
for j := 0 to 3 do begin
MaVar := MaVar+LongWord(tampon[nblu-4+j-3]) shl (j*8);
end;

NbLue C'est la quantité de bytes dans le paquet, le timestamp commence à l'incide NbLue-4.
(Le paquet à une longueur variable et il y a d'autres données avant le timestamp).
Messages postés
215
Date d'inscription
mardi 29 juillet 2003
Statut
Membre
Dernière intervention
1 septembre 2006

Voici l'unit corrigée:

unit ComTimeStamp;


interface


uses
  Classes,
  Windows,
  SysUtils,
  Dialogs;


type


  {
  seconds (6 bits)
  minutes (6 bits)
  hours (5 bits)
  days (5 bits)
  months (4 bits)
  years (6 bits)
  }
  TCOMTimeStamp = class
     private
       FValues: array[0..5] of Dword;
       FPacket: DWORD;
     procedure GetCOMTimeStampFrom(Packet: DWORD);
       function GetValue(indice: integer): DWORD;
     public
       constructor Create(Packet: Dword);
       procedure Display;
     published
       property Seconds: DWord index 5 read GetValue;
       property Minutes: DWord index 4 read GetValue;
       property Hours: DWord index 3 read GetValue;
       property Days: DWord index 2 read GetValue;
       property Months: DWord index 1 read GetValue;
       property Years: DWord index 0 read GetValue;
  end;




implementation




constructor TCOMTimeStamp.Create(Packet: DWord);
begin
GetCOMTimeStampFrom(Packet);
end;


procedure TCOMTimeStamp.GetCOMTimeStampFrom(Packet: DWord);
  const ShrValues: array[0..5] of Byte = (6,4,5,5,6,0);
  const MaskValues: array[0..5] of Byte = ($3f,$0f,$1f,$1f,$3f,$ff);
  var i: integer;
begin
//Sauvegarde
FPacket := Packet;
  for i := Low(MaskValues) to High(MaskValues) do
  begin
      FValues[i] := Packet and MaskValues[i] ;
      Packet := Packet shr ShrValues[i];
  end;
end;


function TCOMTimeStamp.GetValue(indice: integer):DWORD;
begin
result := FValues[indice];
end;


procedure TCOMTimeStamp.Display;
var tag: string;
begin
if Hours < 12 then
   tag := 'AM'
else tag := 'PM';
ShowMessage(Format('%d:%d:%d %s %d/%d/%.2d', [Hours,Minutes,Seconds,tag ,Months,Days,Years]));
end;


end.

Je regarde pour ta boucle..

j!nH
Messages postés
215
Date d'inscription
mardi 29 juillet 2003
Statut
Membre
Dernière intervention
1 septembre 2006

En fait la finale:

unit ComTimeStamp;


interface


uses
  Classes,
  Windows,
  SysUtils,
  Dialogs;


type


  {
  seconds (6 bits)
  minutes (6 bits)
  hours (5 bits)
  days (5 bits)
  months (4 bits)
  years (6 bits)
  }
  TCOMTimeStamp = class
     private
       FValues: array[0..5] of Dword;
       FPacket: DWORD;
       procedure GetCOMTimeStampFrom(Packet: DWORD);
       function GetValue(indice: integer): DWORD;
       function COMTimeStampToStr: string;
     public
       constructor Create(Packet: Dword);
       procedure Display;
     published
       property Seconds: DWord index 5 read GetValue;
       property Minutes: DWord index 4 read GetValue;
       property Hours: DWord index 3 read GetValue;
       property Days: DWord index 2 read GetValue;
       property Months: DWord index 1 read GetValue;
       property Years: DWord index 0 read GetValue;
       property COMTimeStamp: string read COMTimeStampToStr;
       property Packet read FPacket;
  end;




implementation


constructor TCOMTimeStamp.Create(Packet: DWord);
begin
GetCOMTimeStampFrom(Packet);
end;


procedure TCOMTimeStamp.GetCOMTimeStampFrom(Packet: DWord);
  const ShrValues: array[0..5] of Byte = (6,4,5,5,6,0);
  const MaskValues: array[0..5] of Byte = ($3f,$0f,$1f,$1f,$3f,$ff);
  var i: integer;
begin
//Sauvegarde
FPacket := Packet;
  for i := Low(MaskValues) to High(MaskValues) do
  begin
      FValues[i] := Packet and MaskValues[i] ;
      Packet := Packet shr ShrValues[i];
  end;
end;


function TCOMTimeStamp.GetValue(indice: integer):DWORD;
begin
result := FValues[indice];
end;


function TCOMTimeStamp.COMTimeStampToStr: string;
var tag: string;
begin
if Hours < 12 then
   tag := 'AM'
else tag := 'PM';
result := (Format('%d:%d:%d %s %d/%d/%.2d', [Hours, Minutes, Seconds,tag, Months, Days,Years]));
end;


procedure TCOMTimeStamp.Display;
begin
ShowMessage(COMTimeStampToStr);
end;


end.

Pour ta boucle, ne serait pas plutôt :

tampon[nblue - 4 + j] tout simplement?

j!nH
Messages postés
344
Date d'inscription
jeudi 1 mai 2003
Statut
Membre
Dernière intervention
4 avril 2011
1
J'ai essayé et non, le résultat correspond encore mois.
Messages postés
215
Date d'inscription
mardi 29 juillet 2003
Statut
Membre
Dernière intervention
1 septembre 2006

Il faudrait se mettre d'accord là, si tu me dis que ton timestamp commence à nblue - 4, ça devrait marcher....

j!nH
Messages postés
344
Date d'inscription
jeudi 1 mai 2003
Statut
Membre
Dernière intervention
4 avril 2011
1
Ca y est, la boucle for marche à merveille:
MaVar := 0;
for j := 0 to 3 do
MaVar := MaVar+(LongWord(byte(tampon[nblu-1-j])) shl (j*8));