Plancia configurabile su Modbus RTU

Due programmi che condividono uModbusRTU e uGauge:

- Console/PlanciaConsole: plancia nautica descritta da file XML, con
  modalita' plancia e modalita' configurazione. Comandi, spie, selettori,
  strumenti e allarmi sonori; il bus gira in un thread suo perche' la
  finestra non si fermi mai.
- ProjectPlancia: il programma di prova piu' vecchio, usato per collaudare
  i canali.

Le plance sono in Console/*.xml, la documentazione in Console/LEGGIMI.md.
Esclusi dal versionamento i compilati (.exe, .dcu), i file dell'IDE e un
audio da 17 MB.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
f.bittiandClaude Opus 5 committed 2026-09-22 16:56:34 +02:00
commit 4a01a2ec88
69 files changed
+11658

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
program monitorio;
{
Mostra in tempo reale gli ingressi digitali di un modulo IO.
Serve al banco, quando si collega un morsetto e si vuole vedere subito quale
canale si muove. Stampa una riga solo quando qualcosa cambia, cosi' la
finestra non scorre da sola e la cronologia resta leggibile.
Uso: monitorio [porta] [baud] [slave] [canali] [cicli]
cicli = quante letture fare prima di uscire; 0 o assente = per sempre
Es.: monitorio COM7 9600 2 8
Si chiude con Ctrl+C.
}
{$APPTYPE CONSOLE}
uses
System.SysUtils,
uModbusRTU in '..\..\uModbusRTU.pas';
/// "1 0 0 1 . . . ." con i canali spenti resi come punto: gli accesi saltano all'occhio.
function Render(const ABits: TArray<Boolean>): string;
var
I: Integer;
begin
Result := '';
for I := 0 to High(ABits) do
if ABits[I] then
Result := Result + '[1]'
else
Result := Result + ' . ';
end;
function Header(ACount: Integer): string;
var
I: Integer;
begin
Result := '';
for I := 0 to ACount - 1 do
Result := Result + Format(' %d ', [I]);
end;
var
Port: string;
Baud, Slave, Count, Cycles, Done: Integer;
Bus: TModbusRTU;
Bits, Prev: TArray<Boolean>;
First: Boolean;
Changed: Boolean;
I, Errors: Integer;
LastErr: string;
begin
Port := 'COM7'; Baud := 9600; Slave := 2; Count := 8; Cycles := 0; Done := 0;
if ParamCount >= 1 then Port := ParamStr(1);
if ParamCount >= 2 then Baud := StrToIntDef(ParamStr(2), 9600);
if ParamCount >= 3 then Slave := StrToIntDef(ParamStr(3), 2);
if ParamCount >= 4 then Count := StrToIntDef(ParamStr(4), 8);
if ParamCount >= 5 then Cycles := StrToIntDef(ParamStr(5), 0);
Writeln(Format('Ingressi dello slave %d su %s a %d baud. Ctrl+C per uscire.',
[Slave, Port, Baud]));
Writeln;
Writeln(' canale: ' + Header(Count));
Writeln;
Bus := TModbusRTU.Create(Port, Baud, 500);
try
Bus.Connect;
First := True;
Errors := 0;
LastErr := '';
SetLength(Prev, 0);
while True do
begin
try
Bits := Bus.ReadDiscreteInputs(Slave, 0, Count);
if Errors > 0 then
begin
Writeln(Format('%s ... ripristinato dopo %d letture fallite',
[FormatDateTime('hh:nn:ss', Now), Errors]));
Errors := 0;
end;
Changed := First or (Length(Prev) <> Length(Bits));
if not Changed then
for I := 0 to High(Bits) do
if Bits[I] <> Prev[I] then
begin
Changed := True;
Break;
end;
if Changed then
begin
Writeln(FormatDateTime('hh:nn:ss', Now) + ' ' + Render(Bits));
Prev := Copy(Bits);
First := False;
end;
except
on E: Exception do
begin
// Un errore ripetuto non deve riempire lo schermo: lo si stampa
// la prima volta e poi si tace finche' non cambia.
Inc(Errors);
if E.Message <> LastErr then
begin
Writeln(FormatDateTime('hh:nn:ss', Now) + ' ERRORE: ' + E.Message);
LastErr := E.Message;
end;
end;
end;
Sleep(200);
Inc(Done);
if (Cycles > 0) and (Done >= Cycles) then
Break;
end;
finally
Bus.Free;
end;
end.