|
Registriert seit: 13. Jan 2004 Ort: Hamm(Westf) 2.064 Beiträge Delphi 12 Athens |
#5
Hmm..
Mal nach RS232 Adroid API gegoogelt und dann das gefunden ![]() Generell ist es gleich, ob TTY / RS232 / RS485.... Es sind alles serielle Protokolle, welche einen Adapter brauchen. Optional kannst Du aber auch ComServer nehmen ( so was wie ![]() diese gab es früher auch für TTY... Dann kannst du direkt per TCP/IP auf die Serielle Schnittstelle zugreifen. Hatte bei W&T mal ein Handbuch mit den Protokolldetails und Beispielen gesehen... Solche ComServer gibt es auch von anderen Herstellern (z.B. Moxa). Holger Und die Kurze recherche im internet (Gemini pro 2.5) sagt ich bräuchte eine java library die TTY kann , die ich in delphi einbinde per Marhsalling... habe aber nichts davon verstanden. EDIT: Gemini pro 2.5 hat doch noch was ausgespukt was vielleicht geht. werde es nächste woche testen. Es hängt alles an der funktion fcntl . Delphi liefert anscheinend wrapper für lowlevel posix funktionen. Yay.
Delphi-Quellcode:
unit Android.Serial;
{ //usage // In your FMX Form unit... uses System.IOUtils, Android.Serial; // <-- Add the new unit ... procedure TMyForm.Button1Click(Sender: TObject); var SerialPort: TAndroidSerialPort; DataToSend: string; Buffer: TBytes; BytesRead: Integer; begin // Create an instance for /dev/ttyS9 SerialPort := TAndroidSerialPort.Create('ttyS9'); MemoLog.Lines.Add('Attempting to communicate with ' + SerialPort.DeviceName); try try // 1. Open the port SerialPort.Open; MemoLog.Lines.Add('Port opened successfully.'); // 2. Configure the port settings (e.g., 9600 baud, 8 data bits, No parity, 1 stop bit) SerialPort.Configure(9600, 8, 'N', 1); MemoLog.Lines.Add('Port configured: 9600, 8N1'); // 3. Write data to the peripheral DataToSend := 'Hello from Delphi App!'; SerialPort.WriteString(DataToSend + #13#10); // Send string with CR+LF MemoLog.Lines.Add('Sent: ' + DataToSend); // 4. Wait a bit for the device to respond // IMPORTANT: In a real app, do not sleep the main thread! // Use a TThread or TTask for reading. This is just for a simple example. Sleep(500); // 5. Read data back // The Read method will return immediately or after a short timeout (set in Configure) BytesRead := SerialPort.Read(Buffer, 256); // Attempt to read up to 256 bytes if BytesRead > 0 then begin MemoLog.Lines.Add(Format('Received %d bytes: %s', [BytesRead, TEncoding.UTF8.GetString(Buffer)])); end else begin MemoLog.Lines.Add('No data received.'); end; except on E: ESerialPortError do begin MemoLog.Lines.Add('ERROR: ' + E.Message); end; end; finally // 6. Ensure the port is closed and the object is freed if Assigned(SerialPort) then begin SerialPort.Close; SerialPort.Free; MemoLog.Lines.Add('Port closed and resources freed.'); end; end; end; } interface uses System.SysUtils, System.Classes, System.SyncObjs; type // Exception class for serial port errors ESerialPortError = class(Exception); // A class to encapsulate low-level TTY communication on Android TAndroidSerialPort = class private FDeviceName: string; FFileDescriptor: Integer; FIsOpened: Boolean; procedure SetBaudRate(const Value: Integer); procedure SetDataBits(const Value: Integer); procedure SetParity(const Value: Char); // 'N', 'E', 'O' procedure SetStopBits(const Value: Integer); function CheckOpened: Boolean; public constructor Create(const ADeviceName: string); destructor Destroy; override; // --- Core Methods --- procedure Open; procedure Close; procedure Configure(BaudRate: Integer; DataBits: Integer; Parity: Char; StopBits: Integer); // --- Read/Write Methods --- function Read(var Buffer: TBytes; Count: Integer): Integer; function Write(const Buffer: TBytes; Count: Integer): Integer; procedure WriteString(const s: string); // --- Properties --- property IsOpened: Boolean read FIsOpened; property DeviceName: string read FDeviceName; property FileDescriptor: Integer read FFileDescriptor; end; //------------------------------------------------------------------------------ // Implementation //------------------------------------------------------------------------------ implementation // We need to import the low-level POSIX functions for Android. // These units contain the definitions for open, read, write, close, tcgetattr, etc. {$IFDEF ANDROID} uses Posix.Fcntl, Posix.SysStat, Posix.Termios, Posix.Unistd, Androidapi.Log; {$ENDIF} const TAG = 'AndroidSerial'; // For logging in logcat { TAndroidSerialPort } constructor TAndroidSerialPort.Create(const ADeviceName: string); begin inherited Create; if not ADeviceName.StartsWith('/dev/') then FDeviceName := '/dev/' + ADeviceName else FDeviceName := ADeviceName; FFileDescriptor := -1; FIsOpened := False; end; destructor TAndroidSerialPort.Destroy; begin if FIsOpened then Close; inherited Destroy; end; procedure TAndroidSerialPort.Open; {$IFDEF ANDROID} begin if FIsOpened then Exit; // O_RDWR: Open for reading and writing. // O_NOCTTY: The port will not become the controlling terminal of the process. // O_NDELAY: Don't wait for DCD line (data carrier detect). FFileDescriptor := Posix.Fcntl.open(PAnsiChar(AnsiString(FDeviceName)), O_RDWR or O_NOCTTY or O_NDELAY); if FFileDescriptor = -1 then begin FIsOpened := False; // Log the specific error for debugging via logcat Androidapi.Log.d(TAG, 'Failed to open serial port %s. Error: %s', [FDeviceName, strerror(errno)]); raise ESerialPortError.CreateFmt('Cannot open serial port %s. Check permissions or if the device exists. Error: %s', [FDeviceName, strerror(errno)]); end else begin FIsOpened := True; // Set file status flags fcntl(FFileDescriptor, F_SETFL, 0); Androidapi.Log.d(TAG, 'Successfully opened port %s with FD: %d', [FDeviceName, FFileDescriptor]); end; end; {$ELSE} begin // This is a placeholder for non-Android platforms raise ESerialPortError.Create('This class is only for the Android platform.'); end; {$ENDIF} procedure TAndroidSerialPort.Close; {$IFDEF ANDROID} begin if not FIsOpened then Exit; if FFileDescriptor <> -1 then begin Posix.Unistd.close(FFileDescriptor); FFileDescriptor := -1; FIsOpened := False; Androidapi.Log.d(TAG, 'Closed port %s', [FDeviceName]); end; end; {$ELSE} begin // Placeholder end; {$ENDIF} procedure TAndroidSerialPort.Configure(BaudRate: Integer; DataBits: Integer; Parity: Char; StopBits: Integer); {$IFDEF ANDROID} var options: termios; baudConstant: Integer; begin if not CheckOpened then Exit; // 1. Get the current options for the port if tcgetattr(FFileDescriptor, options) <> 0 then begin Androidapi.Log.d(TAG, 'Failed to get termios attributes. Error: %s', [strerror(errno)]); raise ESerialPortError.Create('Failed to get terminal attributes.'); end; // 2. Set the baud rate (input and output) case BaudRate of 9600: baudConstant := B9600; 19200: baudConstant := B19200; 38400: baudConstant := B38400; 57600: baudConstant := B57600; 115200: baudConstant := B115200; else baudConstant := B9600; // Default end; cfsetispeed(options, baudConstant); cfsetospeed(options, baudConstant); // 3. Set control flags (c_cflag) options.c_cflag := options.c_cflag or CLOCAL or CREAD; // Enable receiver, ignore modem control lines // 4. Set data bits options.c_cflag := options.c_cflag and not CSIZE; // Clear the mask case DataBits of 7: options.c_cflag := options.c_cflag or CS7; 8: options.c_cflag := options.c_cflag or CS8; else options.c_cflag := options.c_cflag or CS8; // Default to 8 end; // 5. Set parity case UpCase(Parity) of 'N': begin // No parity options.c_cflag := options.c_cflag and not PARENB; options.c_iflag := options.c_iflag and not INPCK; end; 'E': begin // Even parity options.c_cflag := options.c_cflag or PARENB; options.c_cflag := options.c_cflag and not PARODD; options.c_iflag := options.c_iflag or INPCK; end; 'O': begin // Odd parity options.c_cflag := options.c_cflag or PARENB or PARODD; options.c_iflag := options.c_iflag or INPCK; end; end; // 6. Set stop bits if StopBits = 2 then options.c_cflag := options.c_cflag or CSTOPB // 2 stop bits else options.c_cflag := options.c_cflag and not CSTOPB; // 1 stop bit (default) // 7. Set local flags (c_lflag) -> RAW MODE // This makes the terminal input and output raw. options.c_lflag := options.c_lflag and not (ICANON or ECHO or ECHOE or ISIG); // 8. Set output flags (c_oflag) -> RAW MODE options.c_oflag := options.c_oflag and not OPOST; // 9. Set read timeout settings options.c_cc[VMIN] := 0; // Minimum number of characters for non-canonical read options.c_cc[VTIME] := 10; // Timeout in deciseconds (e.g., 10 = 1 second) for non-canonical read // 10. Apply the new options // TCSANOW: the change occurs immediately. if tcsetattr(FFileDescriptor, TCSANOW, options) <> 0 then begin Androidapi.Log.d(TAG, 'Failed to set termios attributes. Error: %s', [strerror(errno)]); raise ESerialPortError.Create('Failed to set terminal attributes.'); end; // Flush the port tcflush(FFileDescriptor, TCIFLUSH); Androidapi.Log.d(TAG, 'Successfully configured port %s', [FDeviceName]); end; {$ELSE} begin // Placeholder end; {$ENDIF} function TAndroidSerialPort.CheckOpened: Boolean; begin Result := FIsOpened; if not Result then raise ESerialPortError.Create('Serial port is not open.'); end; function TAndroidSerialPort.Read(var Buffer: TBytes; Count: Integer): Integer; {$IFDEF ANDROID} begin if not CheckOpened then Exit(0); if Count <= 0 then Exit(0); SetLength(Buffer, Count); Result := Posix.Unistd.read(FFileDescriptor, Buffer, Count); if Result < 0 then begin // An error occurred Androidapi.Log.d(TAG, 'Error reading from serial port. Error: %s', [strerror(errno)]); raise ESerialPortError.CreateFmt('Error reading from serial port: %s', [strerror(errno)]); end; // Resize buffer to actual number of bytes read SetLength(Buffer, Result); end; {$ELSE} begin Result := 0; // Placeholder end; {$ENDIF} function TAndroidSerialPort.Write(const Buffer: TBytes; Count: Integer): Integer; {$IFDEF ANDROID} begin if not CheckOpened then Exit(0); if Count <= 0 then Exit(0); Result := Posix.Unistd.write(FFileDescriptor, Buffer, Count); if Result < 0 then begin Androidapi.Log.d(TAG, 'Error writing to serial port. Error: %s', [strerror(errno)]); raise ESerialPortError.CreateFmt('Error writing to serial port: %s', [strerror(errno)]); end; end; {$ELSE} begin Result := 0; // Placeholder end; {$ENDIF} procedure TAndroidSerialPort.WriteString(const s: string); var bytesToWrite: TBytes; begin // Convert Delphi string to TBytes for writing bytesToWrite := TEncoding.UTF8.GetBytes(s); Write(bytesToWrite, Length(bytesToWrite)); end; // --- These are just placeholders for the property setters for now --- // A real implementation might re-call Configure. procedure TAndroidSerialPort.SetBaudRate(const Value: Integer); begin // Re-configure would be needed here end; procedure TAndroidSerialPort.SetDataBits(const Value: Integer); begin // Re-configure would be needed here end; procedure TAndroidSerialPort.SetParity(const Value: Char); begin // Re-configure would be needed here end; procedure TAndroidSerialPort.SetStopBits(const Value: Integer); begin // Re-configure would be needed here end; end.
Andreas
Nobody goes there anymore. It's too crowded! Geändert von QuickAndDirty (18. Jun 2025 um 10:43 Uhr) |
![]() |
Themen-Optionen | Thema durchsuchen |
Ansicht | |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
LinkBack |
![]() |
![]() |