Newsgroup: it.comp.lang.delphi
Titolo: CRC 16

ho trovato in rete un po di esempi anche se tutte "Procedure"
problema:
ho una serie di byte dei quali calcolare il relativo CRC16
una volta calcolato devo inserire i due byte in una posizione definita
mi servirebbe, data una certa stringa (stringa perchè mi risulta più
facile in base alle mie conoscenze attuali di delphi... praticamente
stringa composta dai codici ASCII dey bytes in questione), di
calcolarne il CRC16
secondo me dovrei fare una function e non una procedure ... qualche
help ???
implementation
procedure CalcCRC16(p: pointer; n: integer; var crc16: word);
const
  crc16table: array[0..255] of word = (
    $0000, $c0c1, $c181, $0140, $c301, $03c0, $0280, $c241,
    $c601, $06c0, $0780, $c741, $0500, $c5c1, $c481, $0440,
    $cc01, $0cc0, $0d80, $cd41, $0f00, $cfc1, $ce81, $0e40,
    $0a00, $cac1, $cb81, $0b40, $c901, $09c0, $0880, $c841,
    $d801, $18c0, $1980, $d941, $1b00, $dbc1, $da81, $1a40,
    $1e00, $dec1, $df81, $1f40, $dd01, $1dc0, $1c80, $dc41,
    $1400, $d4c1, $d581, $1540, $d701, $17c0, $1680, $d641,
    $d201, $12c0, $1380, $d341, $1100, $d1c1, $d081, $1040,
    $f001, $30c0, $3180, $f141, $3300, $f3c1, $f281, $3240,
    $3600, $f6c1, $f781, $3740, $f501, $35c0, $3480, $f441,
    $3c00, $fcc1, $fd81, $3d40, $ff01, $3fc0, $3e80, $fe41,
    $fa01, $3ac0, $3b80, $fb41, $3900, $f9c1, $f881, $3840,
    $2800, $e8c1, $e981, $2940, $eb01, $2bc0, $2a80, $ea41,
    $ee01, $2ec0, $2f80, $ef41, $2d00, $edc1, $ec81, $2c40,
    $e401, $24c0, $2580, $e541, $2700, $e7c1, $e681, $2640,
    $2200, $e2c1, $e381, $2340, $e101, $21c0, $2080, $e041,
    $a001, $60c0, $6180, $a141, $6300, $a3c1, $a281, $6240,
    $6600, $a6c1, $a781, $6740, $a501, $65c0, $6480, $a441,
    $6c00, $acc1, $ad81, $6d40, $af01, $6fc0, $6e80, $ae41,
    $aa01, $6ac0, $6b80, $ab41, $6900, $a9c1, $a881, $6840,
    $7800, $b8c1, $b981, $7940, $bb01, $7bc0, $7a80, $ba41,
    $be01, $7ec0, $7f80, $bf41, $7d00, $bdc1, $bc81, $7c40,
    $b401, $74c0, $7580, $b541, $7700, $b7c1, $b681, $7640,
    $7200, $b2c1, $b381, $7340, $b101, $71c0, $7080, $b041,
    $5000, $90c1, $9181, $5140, $9301, $53c0, $5280, $9241,
    $9601, $56c0, $5780, $9741, $5500, $95c1, $9481, $5440,
    $9c01, $5cc0, $5d80, $9d41, $5f00, $9fc1, $9e81, $5e40,
    $5a00, $9ac1, $9b81, $5b40, $9901, $59c0, $5880, $9841,
    $8801, $48c0, $4980, $8941, $4b00, $8bc1, $8a81, $4a40,
    $4e00, $8ec1, $8f81, $4f40, $8d01, $4dc0, $4c80, $8c41,
    $4400, $84c1, $8581, $4540, $8701, $47c0, $4680, $8641,
    $8201, $42c0, $4380, $8341, $4100, $81c1, $8081, $4040
  );
type
  buffer = array[0..0] of byte;
var
  i: integer;
  q: ^buffer;
begin
  q := p;
  for i := 0 to n-1 do
    crc16 := hi(crc16) xor crc16table[ q^[i] xor lo(crc16) ];
end;
end.

 help ???
La procedura in questione ha un parametro per riferimento: usalo.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 questo articolo e` stato inviato via web dal servizio gratuitohttp://
www.newsland.it/newssegnala
 gli abusi ad 
a...@newsland.it
premesso che mi piacciono le risposte che portano a pensare con la
propria testa ...
però se c'è qualcuno che vi fa innervosire e/o siete nervosi per
problemi vostri ... prendete una camomilla ... con molta
filosofia ...
starete meglio voi e di conseguenza anche noi (intendo i principianti
che magari fanno domande stupide ... )
mi ricollego anche ad un altro 3d in cui avete maltrattato il poverino
di turno ...
chiudo qui dato che non mi piace fare polemiche sterili ... e prendo
la risposta come ironica ...
Se sapessi usare il paramentro in questione, credo "var crc16: word"
non avrei certo fatto la domanda ... ;)

 non avrei certo fatto la domanda ... ;)
Non prendertela: Andrea č fatto cosě, prendere o lasciare :)
In fondo poteva andarti peggio, poteva risponderti Alberto :D
-- 
Jax

in realtà il mio vuole essere un consiglio ... ci mancherebbe ... ho
ben altro a cui pensare per innervosirmi anche in rete :))))

 non avrei certo fatto la domanda ... ;)
Mi spieghi, di grazia, che cosa c'è da "saper usare" ?
Ti viene dato un prototipo:
procedure CalcCRC16(p: pointer; n: integer; var crc16: word);
Ci vuole tanto a capire come diamine si usa ?
-- 
questo articolo e` stato inviato via web dal servizio gratuito 


 Non prendertela: Andrea č fatto cosě, prendere o lasciare :)
Tu non lo sai come fatto, quindi evita di esprimerti.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 


 in realtà il mio vuole essere un consiglio ... 
Risparmiati i consigli, personalmente non ne ho bisogno. Questo è un ng
tecnico, non un jamboree di scout.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 


Mi sembra di capire:
- passi il puntatore al 1° elemento della stringa (p)
- passi la lunghezza della stringa (n)
- passi una word per il risultato (crc16)
Nota: nel tuo caso, passa crc16 inizializzata a 0 (poiché 0 xor n = n) 
le AnsiString credo facciano casino visto che potrebbero non essere 
contigue quindi rimani su normali "string" 255 caratteri.
Esempio:
var
   ugo: string;
   ugocrc: word;
begin
   ugocrc:= 0;
   ugo:= 'cippirimerlo';
   CalcCRC16(cippirimerlo[1], byte(cippirimerlo[0]), ugocrc),
   ShowMessage(IntToStr(ugocrc));
end;
scriptors ha scritto:


ho dimenticato il puntatore
CalcCRC16(^cippirimerlo[1], byte(cippirimerlo[0]), ugocrc)
o Pcar
Alex ha scritto:


Ti becchi 1800 euro al mese per lavorare in questo NG.
Se vuoi guadagnarti la pagnotta è meglio se non dai risposte inutili...!
*Noi* non abbiamo tempo da perdere,
Ciao ;-)
--- posted by geoForum on 
http://www.delphiedintorni.it


La riposta era per Andrew, ma andata fuori post ;-)


Mi sa che merito una punizione :)
Magari stasera mi porto avanti con qualche frustata...
Gatto RossoNero ha scritto:


Magari stasera mi porto avanti con qualche frustata...
Meglio col Cilicio
http://it.wikipedia.org/wiki/Cilicio


 contigue quindi rimani su normali "string" 255 caratteri.
Le AnsiString non fanno nessun casino (sono i programmatori, semmai, che
fanno casino) e sono equivalenti ai char* del C e C++ (stringhe ASCIIZ e a
meno dei meccanismi di copy-on-write e reference counting built-in di
Delphi), quindi i dati in memoria *SONO* contigui.  Il consiglio,
pertanto, di affidarsi a "normali" stringa di 255 caratteri, non ha senso.


 ho dimenticato il puntatore
Non solo, hai dimenticato anche di quotare ;)
-- 
This is my useless sign.

in parte ci sono "quasi" riuscito ... anche se in vie traverse (il
problema reale è comprendere il funzionamento del decoder, leggere la
porzione di RAM che mi interessa e calcolarne il CRC considerando che
ad ogni stand-by alcuni bytes cambiano ... ma questi sono problemi
miei)
provo a postare quello che ho fatto (probabilmente sbagliato anche se
funzionante ... quasi ... nel senso che alcune volte mi da quello
giusto mentre altre no ... ma ho avuto poco tempo per le prove reali
dato che ci ho messo molto per trovare una qualche strada per far
funzionale il calcolo del CRC ... in mancanza di "pappa pronta")
funzione che legge la RAM
___________________________
//###################### READ Block1 FROM RAM Preferences
#################################
function TRAMPageFrame.ReadB1FromRamPrefs(const RamAddress: LongWord;
Length: integer): TbyteDynArray;
var
  Data: TbyteDynArray;
begin
  @HRCReadBytes := GetProcAddress(MainForm.DLLHandle, 'HRCReadBytes');
  SetLength(Data,Length);
  FillChar(Data[0],Length,0);
  HRCReadBytes(@Data[0],RamAddress,Length,1);
  Result := @Data[0];
  SetLength(Data, 0);
end;
___________________________
//###################### Read Prefs Block1
###########################################
procedure TRAMPageFrame.Button2Click(Sender: TObject);
var code : TbyteDynArray;
crc16 : word;
begin
code := ReadB1FromRamPrefs($8C13A944,8190);
CalcCRC16(code, 8190, crc16);
end;
__________________________
al momento ho aggiunto un showmessage alla fine del calcCRC postato
nel primo post
showmessage((inttostr((crc16))));
le parentesi perchè sto facendo altre prove
il risultato sono due byte HEX ma probabilmente sbaglio qualcosa dato
che alcune volte funziona bene mentre altre mi da un risultato
sbagliato (devo verificare se il problema è dovuto ad una mia erronea
trasformazione da decimale ad esadecimale .. sicuramente)

Dunque, sempre valutando questo caso...
le AnsiString non sono contigue ma il compilatore permette un accesso 
contiguo poiché "sotto" gestisce autonomamente i puntatori 
(difficilmente l'heap ha 32bit di memoria contigua disponibile) quindi 
in questa procedura Ansistring funzionerebbe esattamente come string 
(con @cippirimerlo[1] come riferimento al primo carattere) poiché 
l'accesso è all'elemento q^[i] ma se si usasse Inc(q^) il meccanismo 
cadrebbe per le AnsiString ma funzionebbe per le string e vettori 
byte/char. Se poi vogliamo fare le pulci alla procedura, sarebbe 
opportuno disabilitare il range checking visto che "buffer = array[0..0] 
of byte" determinerebbe l'accesso solo all'elemento con indice 0. Il 
senso di ciò che ho detto è quindi relativo al fatto che spesso alcune 
procedure si personalizzano e alcune regole escludono errori sopratutto 
per chi gioca parecchio con i puntatori.
Andrea Laforgia ha scritto:


 miei)
In un vecchio componente ho trovato questa funzione in assembler (dovrai 
riunire le righe lunghe purtroppo).
Il funzionamento sembra simile alla funzione che hai trovato tu, devi 
semplicemente passargli il puntatore all'area di memoria e la lunghezza 
in byte dell'area.
Sotto trovi un esempio di come utilizzarlo su un array casuale di 1024 
byte... spero di non aver fatto bestialità ;)
//calculate CRCR16 Checksum, CRC is default $FFFF,
//after calc you must inverse Result with NOT
function CRC16(CRC: Word; Data: Pointer; DataSize: LongWord): Word; 
assembler;
asm
          AND    EDX,EDX
          JZ     @Exit
          AND    ECX,ECX
          JLE    @Exit
          PUSH   EBX
          PUSH   EDI
          XOR    EBX,EBX
          LEA    EDI,CS:[OFFSET @CRC16]
@Start:  MOV    BL,[EDX]
          XOR    BL,AL
          SHR    AX,8
          XOR    AX,[EDI + EBX * 2]
          INC    EDX
          DEC    ECX
          JNZ    @Start
          POP    EDI
          POP    EBX
@Exit:   RET
          NOP
@CRC16:  DW     00000h, 0C0C1h, 0C181h, 00140h, 0C301h, 003C0h, 00280h, 
0C241h
          DW     0C601h, 006C0h, 00780h, 0C741h, 00500h, 0C5C1h, 0C481h, 
00440h
          DW     0CC01h, 00CC0h, 00D80h, 0CD41h, 00F00h, 0CFC1h, 0CE81h, 
00E40h
          DW     00A00h, 0CAC1h, 0CB81h, 00B40h, 0C901h, 009C0h, 00880h, 
0C841h
          DW     0D801h, 018C0h, 01980h, 0D941h, 01B00h, 0DBC1h, 0DA81h, 
01A40h
          DW     01E00h, 0DEC1h, 0DF81h, 01F40h, 0DD01h, 01DC0h, 01C80h, 
0DC41h
          DW     01400h, 0D4C1h, 0D581h, 01540h, 0D701h, 017C0h, 01680h, 
0D641h
          DW     0D201h, 012C0h, 01380h, 0D341h, 01100h, 0D1C1h, 0D081h, 
01040h
          DW     0F001h, 030C0h, 03180h, 0F141h, 03300h, 0F3C1h, 0F281h, 
03240h
          DW     03600h, 0F6C1h, 0F781h, 03740h, 0F501h, 035C0h, 03480h, 
0F441h
          DW     03C00h, 0FCC1h, 0FD81h, 03D40h, 0FF01h, 03FC0h, 03E80h, 
0FE41h
          DW     0FA01h, 03AC0h, 03B80h, 0FB41h, 03900h, 0F9C1h, 0F881h, 
03840h
          DW     02800h, 0E8C1h, 0E981h, 02940h, 0EB01h, 02BC0h, 02A80h, 
0EA41h
          DW     0EE01h, 02EC0h, 02F80h, 0EF41h, 02D00h, 0EDC1h, 0EC81h, 
02C40h
          DW     0E401h, 024C0h, 02580h, 0E541h, 02700h, 0E7C1h, 0E681h, 
02640h
          DW     02200h, 0E2C1h, 0E381h, 02340h, 0E101h, 021C0h, 02080h, 
0E041h
          DW     0A001h, 060C0h, 06180h, 0A141h, 06300h, 0A3C1h, 0A281h, 
06240h
          DW     06600h, 0A6C1h, 0A781h, 06740h, 0A501h, 065C0h, 06480h, 
0A441h
          DW     06C00h, 0ACC1h, 0AD81h, 06D40h, 0AF01h, 06FC0h, 06E80h, 
0AE41h
          DW     0AA01h, 06AC0h, 06B80h, 0AB41h, 06900h, 0A9C1h, 0A881h, 
06840h
          DW     07800h, 0B8C1h, 0B981h, 07940h, 0BB01h, 07BC0h, 07A80h, 
0BA41h
          DW     0BE01h, 07EC0h, 07F80h, 0BF41h, 07D00h, 0BDC1h, 0BC81h, 
07C40h
          DW     0B401h, 074C0h, 07580h, 0B541h, 07700h, 0B7C1h, 0B681h, 
07640h
          DW     07200h, 0B2C1h, 0B381h, 07340h, 0B101h, 071C0h, 07080h, 
0B041h
          DW     05000h, 090C1h, 09181h, 05140h, 09301h, 053C0h, 05280h, 
09241h
          DW     09601h, 056C0h, 05780h, 09741h, 05500h, 095C1h, 09481h, 
05440h
          DW     09C01h, 05CC0h, 05D80h, 09D41h, 05F00h, 09FC1h, 09E81h, 
05E40h
          DW     05A00h, 09AC1h, 09B81h, 05B40h, 09901h, 059C0h, 05880h, 
09841h
          DW     08801h, 048C0h, 04980h, 08941h, 04B00h, 08BC1h, 08A81h, 
04A40h
          DW     04E00h, 08EC1h, 08F81h, 04F40h, 08D01h, 04DC0h, 04C80h, 
08C41h
          DW     04400h, 084C1h, 08581h, 04540h, 08701h, 047C0h, 04680h, 
08641h
          DW     08201h, 042C0h, 04380h, 08341h, 04100h, 081C1h, 08081h, 
04040h
end;
procedure TForm1.Button1Click(Sender: TObject);
var
   aArr: Array [0..1023] of Byte;
   i: Integer;
begin
   Randomize;
   for i := Low(aArr) to High(aArr) do
   begin
     aArr[i] := Random(255);
   end;
   Button1.Caption := Format('%.2x', [not CRC16($FFFF, @aArr, 
SizeOf(aArr))]);
end;
-- 
Jax

In Button2Click manca crc16:= 0
Non capisco il motivo di SetLength(Data, 0) in ReadB1FromRamPrefs
scriptors ha scritto:


 in questa procedura Ansistring funzionerebbe esattamente come string 
Il tipo "string" può coincidere esattamente con "AnsiString" ed è il
default, per tua informazione.  Il seguente esempio ti chiarirà le idee:
procedure TForm1.Button1Click(Sender: TObject);
var
  Str, Str2: AnsiString;
  P: PChar;
begin
  Str := 'Sarebbe bene se si studiasse da un manuale';
  Str2 := '';
  P := @Str[1];
  while P^ <> #0 do
  begin
    Str2 := Str2 + P^;
    Inc(P);
  end;
  ShowMessage('"'+Str2+'"');
end;


grazie per le informazioni
potro provarle questa sera con il decoder collegato
(se non bastasse i byte da inserire sono il CRC ottenuto con ulteriori
modifiche)

 
grazie per l'utile esempio!

Mi sa che qualcosa non quadra, non è detto che i parametri passino dai 
registri piuttosto che dallo stack, anzi in sistemi multitask ho dei 
seri dubbi, mi sarei apettato qualcosa tipo:
       mov EDX, Data
       mov EBX, CRC
       mov EDI, DataSize
       e
       mov @result, ax
ma forse c'è qualche opzione di compilazione ad hoc
Jax ha scritto:


 quando dico 32bit intendo 2^31 byte di dati (mi sembrava ovvio)
32 bit significa 2^32, non 2^31 e la considerazione sui bit, ancora, non
c'entra nulla con quanto si sta dicendo.


 c'entra nulla con quanto si sta dicendo.
32 bit è l'indirizzamento!! quindi 4294967296 o 4gb
e per 2^31 mi riferisco a: AnsiString ~2^31 characters 4 bytes to 2GB 
8-bit (ANSI) characters (come da manuale)

 8-bit (ANSI) characters (come da manuale)
Stai generando una confusione ingiustificata.
"AnsiString, also called a long string, represents a dynamically allocated
string whose maximum length is limited only by available memory. It uses
8-bit ANSI characters. A long-string variable is a pointer occupying four
bytes of memory. When the variable is empty—that is, when it contains a
zero-length string—the pointer is nil and the string uses no additional
storage. When the variable is nonempty, it points to a dynamically
allocated block of memory that contains the string value, a 32-bit length
indicator, and a 32-bit reference count. This memory is allocated on the
heap, but its management is entirely automatic and requires no user code."
Lo spazio indirizzabile è 2^32, non 2^31.


 seri dubbi, mi sarei apettato qualcosa tipo:
Non saprei, io di assembler non so assolutamente niente.
La funzione dovrebbe funzionare, comunque :)
-- 
Jax

 2^31.
ti ho già risposto sotto, ti reincollo ciò che l'help in linea di delphi 
6 mostra tramite l'auslio del magico F1
A string represents a sequence of characters. Object Pascal supports the 
following predefined string types.
Type	Maximum length	Memory required	Used for
ShortString	255 characters	2 to 256 bytes	backward compatibility
AnsiString	~2^31 characters	4 bytes to 2GB	8-bit (ANSI) characters
WideString	~2^30 characters	4 bytes to 2GB	Unicode characters;
multi-user servers and multi-language applications
poi che sia un errore è un altro conto, ma la cosa mi interessa poco, il 
cruccio era l'indirizzamento a 32 bit in grado di indirizzare per 
l'appunto 4gb. Magari il "~2^31 characters" di borland è riferito a 
2^32-2 dove 2 potrebbe essere l'emento 0 e il terminatore #0


 ti ho giÃ  risposto sotto, 
Sono io che rispondo a te dicendoti che:
1) Quando l'help di Delphi dice "~2^31 characters" non intende una
dimensione di 2^31 byte, ma comunque e sempre 32 bit come spazio
totalmente indirizzato, di cui una parte vengono usati per il reference
counting e per tenere traccia della lunghezza della stringa.
2) i 32 bit che hai citato non c'entrano una beneamata mazza nell'intera
discussione.


discussione.
Mi sa che non hai capito la questione, Se si usa semplicemente il tipo 
stringa, si ottiene il tipo short string o ANSI string, dipendente dal 
valore della direttiva $H del compilatore. $H+ (il default) indica le 
long string (il tipo ANSIString), che e' quello usato dai componenti 
della VCL. 
Le long string di Delphi sono basate sul meccanismo del reference-
counting, che tengono traccia di quante variabili stringa stanno 
referenziando la stessa stringa in memoria. Questo reference-counting e' 
anche usato per liberare memoria quando una stringa non e' piu' usata, 
quando il reference-count raggiunge zero. 
Se si vuole incrementare la dimensione di una stringa in memoria ma c'e' 
qualcosa d'altro nella memoria adiacente, allora la stringa non puo' 
aumentare nella stessa locazione di memoria, e una completa copia della 
stringa deve percio' essere fatta in un'altra locazione. Quando capita 
questa situazione, il supporto run-time di Delphi rialloca la stringa in 
modo completamente trasparente. Semplicemente regolare la dimensione 
della stringa con la procedura SetLength procedure, allocando 
efficacemente la quantita' di memoria richiesta: 
SetLength (String1, 200);
La procedura SetLength esegue la richiesta di memoria, non una vera 
allocazione di memoria. Essa riserva la memoria richiesta per un uso 
futuro, senza realmente usare la memoria. Questa tecnica e' basata su 
una caratteristica del sistema operativo Windows ed e' usata da Delphi 
per tutte le allocazioni dinamiche di memoria. Ad esempio, quando si 
richiede un array di notevoli dimensioni, la memoria e' riservata ma non 
allocata. 
Impostare la lunghezza di una stringa raramente necessario. Il solo caso 
nel quale si deve allocare memoria per una long string usando la 
procedura SetLength e' quando bisogna passare la stringa come un 
parametro ad una funzione API (dopo un opportuno typecast), come 
mostrato piu' avanti.


 
ahahaaha sei forte va! non so quante volte ho detto che l'indirizzamento 
è a 32 bit (quindi 2^32 byte) e il contenuto della stringa (quindi 
nel'heap) è a 2^31 bit circa. Questo proprio per il reference counting 
che citi. Passando a cose più interessanti (altrimenti si finisce per 
annoiarsi) come mai non si può assegnare una stringa maggiore di 255 
caratteri senza doverla concatenare?
Es:
//questo non va
miaAnsiString:= 'testo lunghissimo...... oltre 255 caratteri... String 
literals may have at most 255 elements';
//questo va
miaAnsiString:= 'testo lunghissimo......'+ 'oltre 255 caratteri... 
String literals may have at most 255 elements';
saluti

caratteri senza doverla concatenare?
come sotto:
SetLength (String1, 300);


>annoiarsi) come mai non si puň assegnare una stringa maggiore di 255


Compili male tesoro...
$H (No default $H+)


>Compili male tesoro...
Le direttive di compilazione non servono !
DEVI SPEZZARE l'ASSEGNAMENTO alla stringa '+' per intendersi, prova 
sotto :
procedure TForm1.Button1Click(Sender: TObject);
var
  test: Ansistring;
begin
Setlength(test, 3000);
  test:='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'+
        'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
end;
