Découpage de bytes

Résolu
cs_nitrique Messages postés 344 Date d'inscription jeudi 1 mai 2003 Statut Membre Dernière intervention 4 avril 2011 - 31 août 2006 à 10:15
jinh68 Messages postés 215 Date d'inscription mardi 29 juillet 2003 Statut Membre Dernière intervention 1 septembre 2006 - 1 sept. 2006 à 11:28
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 -->

26 réponses

jinh68 Messages postés 215 Date d'inscription mardi 29 juillet 2003 Statut Membre Dernière intervention 1 septembre 2006
1 sept. 2006 à 09:53
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
3
jlen100 Messages postés 1606 Date d'inscription samedi 10 juillet 2004 Statut Membre Dernière intervention 25 juillet 2014 13
31 août 2006 à 11:34
salut,

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


@+

jlen
0
cs_nitrique Messages postés 344 Date d'inscription jeudi 1 mai 2003 Statut Membre Dernière intervention 4 avril 2011 1
31 août 2006 à 11:59
0
cs_neko Messages postés 135 Date d'inscription jeudi 14 août 2003 Statut Membre Dernière intervention 12 octobre 2006 1
31 août 2006 à 13:12
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
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

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

bouh
0
cs_neko Messages postés 135 Date d'inscription jeudi 14 août 2003 Statut Membre Dernière intervention 12 octobre 2006 1
31 août 2006 à 13:19
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
0
cs_Loda Messages postés 814 Date d'inscription vendredi 3 novembre 2000 Statut Membre Dernière intervention 30 juillet 2009 3
31 août 2006 à 13:54
en passant:

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

ca risque de t'aider...
0
jinh68 Messages postés 215 Date d'inscription mardi 29 juillet 2003 Statut Membre Dernière intervention 1 septembre 2006
31 août 2006 à 14:22
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
0
jinh68 Messages postés 215 Date d'inscription mardi 29 juillet 2003 Statut Membre Dernière intervention 1 septembre 2006
31 août 2006 à 14:24
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
0
cs_nitrique Messages postés 344 Date d'inscription jeudi 1 mai 2003 Statut Membre Dernière intervention 4 avril 2011 1
31 août 2006 à 15:06
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 ?
0
jinh68 Messages postés 215 Date d'inscription mardi 29 juillet 2003 Statut Membre Dernière intervention 1 septembre 2006
31 août 2006 à 15:12
Quelle valeur a ma Var?

j!nH
0
cs_nitrique Messages postés 344 Date d'inscription jeudi 1 mai 2003 Statut Membre Dernière intervention 4 avril 2011 1
31 août 2006 à 15:15
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 !
0
jinh68 Messages postés 215 Date d'inscription mardi 29 juillet 2003 Statut Membre Dernière intervention 1 septembre 2006
31 août 2006 à 15:38
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
0
cs_nitrique Messages postés 344 Date d'inscription jeudi 1 mai 2003 Statut Membre Dernière intervention 4 avril 2011 1
31 août 2006 à 15:52
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 ?
0
cs_nitrique Messages postés 344 Date d'inscription jeudi 1 mai 2003 Statut Membre Dernière intervention 4 avril 2011 1
31 août 2006 à 15:56
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).
0
jinh68 Messages postés 215 Date d'inscription mardi 29 juillet 2003 Statut Membre Dernière intervention 1 septembre 2006
31 août 2006 à 16:11
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
0
jinh68 Messages postés 215 Date d'inscription mardi 29 juillet 2003 Statut Membre Dernière intervention 1 septembre 2006
31 août 2006 à 16:23
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
0
cs_nitrique Messages postés 344 Date d'inscription jeudi 1 mai 2003 Statut Membre Dernière intervention 4 avril 2011 1
31 août 2006 à 16:41
J'ai essayé et non, le résultat correspond encore mois.
0
jinh68 Messages postés 215 Date d'inscription mardi 29 juillet 2003 Statut Membre Dernière intervention 1 septembre 2006
31 août 2006 à 16:46
Il faudrait se mettre d'accord là, si tu me dis que ton timestamp commence à nblue - 4, ça devrait marcher....

j!nH
0
cs_nitrique Messages postés 344 Date d'inscription jeudi 1 mai 2003 Statut Membre Dernière intervention 4 avril 2011 1
31 août 2006 à 17:03
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));
0
Rejoignez-nous