Newsgroup: it.comp.lang.delphi
Titolo: IdTCPClient IOHandler socket write

Ciao a tutti,
avrei bisogno di qualche dritta per quanto riguarda l'invio di un
comando tramite IdTCPClient ma non mi è chiaro il comportamento.
Var
  GFixed, GPart1: byte;
begin
  GFixed := Byte($8001);
  GPart1 := Byte($00005358);
  IdTCPClient1.Socket.Write(GFixed+GPart1);
End;
In riferimento al codice postato, l'apparecchio che riceve il comando
si aspetta una serie di byte che devo poter parametrizzare prima di
inviarli in base alla configurazione selezionata e i primi due Byte
fissi sono $80 e $01. Premesso questo e che non ho molta dimestichezza
con i componenti Indy, potreste darmi qualche consiglio su come poter
gestire questa parte?
Spero di essere stato chiaro.
Grazie mille.

Non ho capito se non sai come inviare, se invii ma succede qualche
casino o se tu invii ma il device ti alza il dito medio..
A.


La seconda che hai detto.
Premesso che il device dovrebbe ricevere $80 $01 $00 $00 $53 $58 ti
faccio un esempio:
IdTCPClient1.Socket.Write($800100005358);
Con questo codice il device riceve: $00 $00 $80 $01 $00 $00 $53 $58
GFixed := Byte($8001);
IdTCPClient1.Socket.Write(GFixed);
Con questo codice il device riceve: $01
GFixed := Byte($80)+Byte($01);
IdTCPClient1.Socket.Write(GFixed);
Con questo codice il device riceve: $81
GFixed := Byte($80);
IdTCPClient1.Socket.Write(GFixed);
Con questo codice il device riceve: $80
A parte il terzo caso che mi è chiaro il motivo per cui il device
riceve $81 (somma dei due byte) e il quarto caso che riceve
correttamente $80, non mi è chiaro come fare per concatenare tutti i
byte da inviare in modo che il device riceva il comando corretto e che
in realtà si aspetta.
Spero di essermi spiegato meglio
Grazie


Ti stai incasinando un pochino.....
dunque se vuoi essere sicuro che il device riceva esattamente la 
sequenza devi spedire un byte alla volta.
Ovvero per $800100005358 dei inviare $80 $01 $00 $00 $53 $58
Ora spiego i tuoi dubbi (almeno ci provo)
Caso 1:
Il motivo per cui se invii $800100005358 il device riceve $00 $00 $80 
$01 $00 $00 $53 $58 è dato dal fatto che i numeri (e $800100005358 è un 
numero a tutti gli effetti) vengono inviati allineandoli a word (4 
byte): infatti se spezziamo $800100005358 in due otteniamo $00005358 
come word della parte bassa e $00008001 come word della parte alta (i 
due byte a zero iniziali vengono generati in automatico)
Vediamo il caso 2:
GFixed := Byte($8001);
la tipizzazione con Byte fa in modo da perdere i bit piu' significativi 
dopo l'ottavo ($01: parte bassa - 1 byte e $80: parte alta - 1 byte perso)
Invece di GFixed := Byte($8001); potevi scrivere GFixed := $8001 And 
$00FF; che è la stessa cosa in questo caso
Il caso 3 lo hai capito benissimo, mentre il 4° si rifà al caso 2
Scrivere $01 è uguale a scrivere $0001 ed il typecast Byte() con un 
qualsiasi numero superiore al byte provoca l'eliminazione dei bit superiori
Quindi Byte($01), Byte($1101), Byte($4512345601) da lo stesso risultato
Bye

 Quindi Byte($01), Byte($1101), Byte($4512345601) da lo stesso risultato
Capito, grazie
Mi è chiaro (spero) quello che hai scritto ma non mi è ancora chiaro
come posso inviare l'elenco completo di byte al device. Inoltre, in
base alle impostazioni scelte dall'utente, alcuni byte cambiano e devo
poterli parametrizzare in modo da inviare quelli corretti. Ti faccio
un esempio per essere più chiaro:
Cliccando il bottone "ciccio" devo inviare al device $80 $01 $00 $00
$53 $58
Clicando il bottone "pippo" devo inviare al device $80 $01 $18 $63 $25
$31
Sicuramente sono domande stupide ma non ho dimestichezza su queste
cose e faccio un po confusione, in ogni caso grazie mille per la
pazienza e per eventuali aiuti.

 un esempio per essere più chiaro:
Creati un set di array di caratteri o byte che utilizzerai per l'invio a 
seconda della scelta dell'utente
Esempio
Const
   VetCiccio : Array[1..6] Of Byte = ($80, $01, $00, $00, $53, $58);
   VetPippo : Array[1..6] Of Byte = ($80, $01, $18, $63, $25, $31);
Meglio se tipizzi il tutto e chiami una procedura unica
Type
   Tvettore = Array[1..6] Of Byte;
Const
   VetCiccio : TVettore = ($80, $01, $00, $00, $53, $58);
   VetPippo : TVettore = ($80, $01, $18, $63, $25, $31);
Quindi l'unica procedura che ti occorrerà per inviare sarà una cosa tipo:
Procedure InviaComando(Comando : Tvettore);
Var
   I : Integer;
Begin
   For I := 1 To 6 Do IdTCPClient1.Socket.Write(Comando[I]);
End;
Se i vettori sono di lunghezza variabile la faccenda si complica solo 
nella procedura di invio che diventerà:
Procedure InviaComando(Comando : Array of byte);
Var
   I : Integer;
Begin
   For I := Low(Comando) To High(Comando) Do 
IdTCPClient1.Socket.Write(Comando[I]);
End;
ma forse sono andato oltre
Bye

 uguale - i dati vengono comunque serializzati per l'invio
Grazie per la spiegazione generale, gentilissimo.
Un'ultimo chiarimento: in caso dovessi inviare la stringa (decisamente
più comoda da gestire vista la moltitudine di comandi ed eccezioni)
invece del singolo carattere, sarebbe corretto fare ad esempio
write(Chr($80)+Chr($01))?
Ho fatto una prova veloce giusto per capire cosa spara in rete e il
Chr($80) diventa $3F
E' meglio se mi do all'ippica o mi manca qualche pezzo?
Grazie ancora.

 write(Chr($80)+Chr($01))?
no.
sostituisci il "+" con una virgola.
Ale


IdTCPClient1.Socket.Write(Chr($80),Chr($01));
[DCC Error] MainForm.pas(268): E2250 There is no overloaded version of
'Write' that can be called with these arguments

 'Write' that can be called with these arguments
bene. Allora risolvi con due write di seguito, oppure con un ciclo.
Ale


Non capisco se mi stai prendendo in giro o se sei seria.
L'uso della stringa era per evitare troppi cicli e array che
complicano il codice, come scritto nel post precedente.
Grazie comunque dell'intervento.

 Grazie comunque dell'intervento.
ti è già stato fatto notare che la stringa non è l'approccio corretto.
La write di una sequenza di byte, in un'unica istruzione, non è
prevista, quindi ti resta, per esclusione, solo il ciclo, che tra
l'altro è una cosa molto pulita. Incapsulalo in una procedura con
parametro array di lunghezza variabile e avrai una chiamata del tipo:
Spedisci(miasequenza:TMiaSequenza)
dove TMiaSequenza è un array of byte
Inutile cercare soluzioni bizzarre, quando c'è la soluzione semplice e
pulita a portata di mano.
Ale

 Spedisci(miasequenza:TMiaSequenza)
ancora meglio, puoi creare una procedura
Spedisci(x:ansistring);
che dentro avrà un banalissimo ciclo che considera i caratteri due a
due convertendoli da hex a byte, e che richiamerai con
Spedisci('80013F00BCAADD')
e questo ogni volta che vuoi spedire qualcosa.
non mi sembra una cosa nè complicata nè tantomeno inelegante.
Ale

 Grazie ancora.
Puoi crearti una stringa partendo da un numero anteponendo al singolo 
byte il carattere #
Se il tuo numero č $800118632531 puoi dichiararla cosi'
MiaStringa = #$80#$01#$18#$63#$25#$31
ma nel tuo caso, visto che lavori con sequenze di byte ti consiglio di 
continuare ad usare i numeri

 'Write' that can be called with these arguments
Write vuole solo un parametro


Questo sarebbe l'approccio migliore se si vuole lavorare con stringhe 
ma, credo, che gli complicherebbe la vita sul ciclo di spedizione.
Vabbè do una mano....
dunque quello proposto da Alessandra è ottimo, per cui
1) dichiarazioni
Const
   Stringa_Uno = '80013F00BCAADD';
   Stringa_Due = '87014F503CAA0D';
   .... eccetera .....
2) Procedura di invio
Procedure Spedisci(Const Stringa : String);
Var
   St : String;
   B  : Byte;
Begin
   St := Stringa;
   While (St <> '') Do
	Begin
           B := StrToInt('$'+Copy(St, 1, 2));
           IdTCPClient1.Socket.Write(B)
           Delete(St, 1, 2);
	End;
End;
chiaro no?

usando invece la libreria ICS di Piette c'è un comodissimo
WSocket1.SendStr(... inoltre questa libreria ha anche il supporto SSL

 gestire questa parte?
Qualunque ottetto è un byte, o un carattere, o mezza word. Per
combinare più caratteri (o byte) in una stringa, puoi usare ad
esempio:
aStr := aStr + aChar1 + aChar2;
aStr := aStr + chr(aByte);
Ovviamente, se ciò che devi inviare è "fisso", ti conviene dichiarare
tutte le stringhe come costanti:
const
aSimpleStr: string = 'Ciao, sono una stringa di testo';
aBinStr: string = #80#01#127#00#255;  // a string with NULL and
control chars
Ancora, se hai a che fare con un protocollo, ti può essere utile
definire una serie di stati a cui associare le stringhe (array
costante indicizzato con un tipo enumerativo)
type
  TStringCommands = (scOpen, scCommand, scAck, scNak);
const
  StringCommands = array[TStringCommands] of string:
    ( #08#01 ,    // apertura connessione
      #01#01#02,  // comando
      #88#55#55,  // ack
      #88#00#00   // nak  );
Se devi aprire la connessione avrai la tua classe TProtocolHandler,
col suo metodo Open che semplicemente farà
myTcpConnection.Write(StringCommands[scOpen]);
e gestirà la risposta (o non risposta), cambiando opportunamente le
sue proprietà (active, connected o quant'altro).
Saluti
Paolo Arosio

Grazie mille a tutti dei consigli preziosi.
Alla fine sto utilizzando una serie di array di byte dove gran parte
di loro sono dichiarati come costanti; sto gestendo il tutto in OOP
così dovrei riuscire a creare in modo pulito le singole chiamate
associando i vari array a seconda del comando da inviare al device.
Tutto sommato se questa struttura logica è solida dovrei avere qualche
vantaggio in più rispetto all'uso di stringhe semplificando il
sorgente ed evitando conversioni inutili.
Grazie ancora e buon weekend.

Ciao a tutti,
sono ancora qui con qualche problemino; premesso e appurato che il
device non accetta comandi a byte singoli (lo sniffer me li
pacchettizza correttamente ma il device non mi risponde) devo per
forza inviare una stringa.
In buona sostanza questo codice (dove GCommandDevice[I] è in formato
byte) non viene accettato:
For I := Low(GCommandDevice) To High(GCommandDevice) Do
IdTCPClient1.Socket.Write(GCommandDevice[I]);
A questo punto ho convertito l'array di byte in stringa ma il byte $80
risulta sempre $3F.
Var
  I: Integer;
  MessageToSend : widestring;
for I := Low(GCommandDevice) To High(GCommandDevice) Do
    MessageToSend := MessageToSend + Chr(GCommandDevice[I]);
  IdTCPClient1.Socket.Write(MessageToSend);
Ho provato a usare sia ansistring che widestring ma non cambia nulla.
Ho trovato in rete questa guida:
http://docwiki.embarcadero.com/RADStudio/en/HIGHCHARUNICODE_directive_%28Delphi%29
ho inserito la direttiva {$HIGHCHARUNICODE OFF} come suggerito ma
nulla.
Qualcuno sa darmi una dritta? Non so più come diavolo fare per inviare
al device $80 e non $3F.
Grazie mille di nuovo

Ho risolto in questo modo:
Var
  I: Integer;
  MessageToSend : TBytes;
begin
  SetLength(MessageToSend,Length(GCommandDevice));
  for I := Low(GCommandDevice) To High(GCommandDevice) Do
    MessageToSend[I] := GCommandDevice[I];
  IdTCPClient1.Socket.Write(MessageToSend);
End;
Grazie ugualmente.