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): 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; 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.