mikrocontroller.net

Forum: PC-Programmierung PHP byte array per tcp socket versenden


Autor: Lucas N. (derneumann)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

bin grade an einem Projekt dran wo ich an einen Dimmer auf ESP8266 Basis 
(Arduino Framework) über eine PHP Website mit TCP Sockets ein Bytearray 
senden will.

Mit VB.NET klappt das schon sehr gut, allerdings ist mein PHP Wissen 
extrem eingerostet (zuletzt mit PHP4 gearbeitet).

Im Wesentlichen hab ich ein Commandbyte, z.B. 0x20 und dann z.B. 12 Bit 
PWM Werte die unter VB.NET als unsigned 16 Bit Integer abgebildet, per 
Bitshifting in zwei einzelne Bytes zerlegt und dann ins Bytearray 
gepackt und versendet werden.

Genau hier scheitert es bei PHP bei mir. Habe schon die pack() Funktion 
gefunden und konnte auch schon einzelne Bytes versenden (sind auch 
richtig angekommen). Sobald es jedoch darum ging, unsigned 16 Bit 
Integer und unsigned 8 Bit Integer auf einmal zu versenden, also mit 
einem pack() in eine Variable zu speichern um diese dann zu verschicken, 
kam nur Müll an.
Habe es mit Little und Big Endian probiert.

Bin einfach überfordert und konnte trotz stundenlanger Recherche und 
Kopfzerbrechen nicht zu einer Lösung finden.

Für manche Dinge bin ich wohl einfach zu blöd bzw. verstehe sie erst, 
wenn ich die Lösung vor den Augen habe (sprich: wenn es mir jemand 
vorgekaut hat).
Bitte um Nachsicht diesbezüglich, habe mir echt schon die Doku u.a. von 
pack, unpack, ... reingezogen und etliche Threads auf stackoverflow 
umgegraben, verstehe es trotzdem nicht.

Danke für eure Hinweise!

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lucas N. schrieb:
> Im Wesentlichen hab ich ein Commandbyte, z.B. 0x20 und dann z.B. 12 Bit
> PWM Werte die unter VB.NET als unsigned 16 Bit Integer abgebildet, per
> Bitshifting in zwei einzelne Bytes zerlegt und dann ins Bytearray
> gepackt und versendet werden.

Das kannst Du genauso auch in PHP machen. Am besten zeigst Du mal den 
funktionierenden VB-Code.

Autor: Lucas N. (derneumann)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke dass du dir Zeit nimmst!
Private Sub SendColors()
 Dim ByteArray(17) As Byte
 ByteArray(0) = &H20
 ByteArray(1) = CByte(BitConverter.GetBytes(ch1.Value)(0))
 ByteArray(2) = CByte(BitConverter.GetBytes(ch1.Value)(1))
 ByteArray(3) = CByte(BitConverter.GetBytes(ch2.Value)(0))
 ByteArray(4) = CByte(BitConverter.GetBytes(ch2.Value)(1))
 ByteArray(5) = CByte(BitConverter.GetBytes(ch3.Value)(0))
 ByteArray(6) = CByte(BitConverter.GetBytes(ch3.Value)(1))
 ByteArray(7) = CByte(BitConverter.GetBytes(ch4.Value)(0))
 ByteArray(8) = CByte(BitConverter.GetBytes(ch4.Value)(1))
 ByteArray(9) = CByte(BitConverter.GetBytes(ch5.Value)(0))
 ByteArray(10) = CByte(BitConverter.GetBytes(ch5.Value)(1))
 ByteArray(11) = CByte(BitConverter.GetBytes(ch6.Value)(0))
 ByteArray(12) = CByte(BitConverter.GetBytes(ch6.Value)(1))
 ByteArray(13) = CByte(BitConverter.GetBytes(ch7.Value)(0))
 ByteArray(14) = CByte(BitConverter.GetBytes(ch7.Value)(1))
 ByteArray(15) = CByte(BitConverter.GetBytes(ch8.Value)(0))
 ByteArray(16) = CByte(BitConverter.GetBytes(ch8.Value)(1))
 ExecQuery(ByteArray)
End Sub

Private Sub ExecQuery(data As Byte())
  Dim tcpClient As New System.Net.Sockets.TcpClient()
  tcpClient.Connect(txtIP.Text, 5160)

  Dim networkStream As NetworkStream = tcpClient.GetStream()

  If networkStream.CanWrite And networkStream.CanRead Then
    ' Do a simple write.
    Dim numberOfBytesRead As Integer = 0

    Dim ResponseBytes(18) As Byte
    
    Dim ReceiveBuffer(0) As Byte

    networkStream.Write(data, 0, data.Length)

    Dim TimeOut As DateTime
    TimeOut = DateTime.Now

    While (networkStream.DataAvailable Or DateTime.Now.Subtract(TimeOut).Seconds <= 2)
      networkStream.Read(ReceiveBuffer, 0, 1)
      ResponseBytes(numberOfBytesRead) = ReceiveBuffer(0)
      numberOfBytesRead += 1
      TimeOut = DateTime.Now
      If numberOfBytesRead > 0 Then
        If ResponseBytes(0) = &HF0 Or ResponseBytes(0) = &H95 And numberOfBytesRead = 9 Then
          Exit While
        End If
      End If
    End While
    ' Do stuff

  Else
    If Not networkStream.CanRead Then
      Console.WriteLine("cannot not write data to this stream")
      tcpClient.Close()
    Else
      If Not networkStream.CanWrite Then
        Console.WriteLine("cannot read data from this stream")
        tcpClient.Close()
      End If
    End If
  End If
  tcpClient.Close()

End Sub

Edit:
der Microcontrollerteil am ESP8266 schaut in C so aus:
if (client.available() > 16)
{
  client.readBytes(tcpServerInputBuffer, 17);
  client.flush();
  
  ....
  
  if (tcpServerInputBuffer[0] == TCP_CHANNELS_SET)
  {
    poweredOn = true;
    pwm_channels[0] = tcpServerInputBuffer[1] | uint16_t(tcpServerInputBuffer[2]) << 8;
    pwm_channels[1] = tcpServerInputBuffer[3] | uint16_t(tcpServerInputBuffer[4]) << 8;
    pwm_channels[2] = tcpServerInputBuffer[5] | uint16_t(tcpServerInputBuffer[6]) << 8;
    pwm_channels[3] = tcpServerInputBuffer[7] | uint16_t(tcpServerInputBuffer[8]) << 8;

    pwm_channels[4] = tcpServerInputBuffer[9] | uint16_t(tcpServerInputBuffer[10]) << 8;
    pwm_channels[5] = tcpServerInputBuffer[11] | uint16_t(tcpServerInputBuffer[12]) << 8;
    pwm_channels[6] = tcpServerInputBuffer[13] | uint16_t(tcpServerInputBuffer[14]) << 8;
    pwm_channels[7] = tcpServerInputBuffer[15] | uint16_t(tcpServerInputBuffer[16]) << 8;
    client.write(0xF0);
  }
  
  ...
}

: Bearbeitet durch User
Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Das Schreiben müsste folgendermaßen funktionieren:
$host = "127.0.0.1";
$port = 5160;

$packet = pack("CSSSSSSSS", 0x20, $ch1, $ch2, $ch3, $ch4, $ch5, $ch6, $ch7, $ch8);

$socket = socket_create(AF_INET, SOCK_STREAM, 0);
socket_connect($socket, $host, $port);
socket_write($socket, $packet, 17);

Danach muss man dann die Antwort lesen. In dem ESP-Beispiel-Code wird 
nur ein Byte (nämlich 0xF0) zurückgegeben, im VB-Code sehe ich 
irgendwelche möglichen Werte mit mit Datenlänge 9.

Du kannst ja mal selbst schauen, lesen der Antwort geht mit:
$maxlen = 9; // oder ein anderer Wert
$result = socket_read ($socket, $maxlen);
Notfalls machst Du auch eine Schleife über Read jedes einzelnen 
Zeichens:
$result = socket_read ($socket, 1);

Googlen nach "socket_read php" hilft weiter.

: Wiederhergestellt durch Moderator
Autor: Lucas N. (derneumann)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:

> $packet = pack("CSSSSSSSS", 0x20, $ch1, $ch2, $ch3, $ch4, $ch5, $ch6,
> $ch7, $ch8);

"CSSSS..." war die ausschlaggebende Information, vielen Dank! Könnte mir 
auf den Kopf greifen, das ist ja eh ähnlich wie printf in C.

> Danach muss man dann die Antwort lesen. In dem ESP-Beispiel-Code wird
> nur ein Byte (nämlich 0xF0) zurückgegeben, im VB-Code sehe ich
> irgendwelche möglichen Werte mit mit Datenlänge 9.

Die Länge der Antwort hängt vom Kommando ab. Manche Kommandos bekommen 
nur 0xF0 zurück (einfaches ACK), manche bekommen eine komplette Antwort 
inkl. Daten retour.

> Du kannst ja mal selbst schauen, lesen der Antwort geht mit:$maxlen = 9;
> // oder ein anderer Wert
> $result = socket_read ($socket, $maxlen);
> Notfalls machst Du auch eine Schleife über Read jedes einzelnen
> Zeichens:$result = socket_read ($socket, 1);
>
> Googlen nach "socket_read php" hilft weiter.

Danke, hast mir jedenfalls schon sehr weitergeholfen. Da hätte ich 
wieder mal echt selbst draufkommen können.

Mein Code hat, bis auf das von dir gelieferte "CSSSSSSSS" so ausgesehen, 
habe das mit fsockopen statt mit socket_create und socket_connect 
gemacht. Wo liegt denn da der Unterschied? Habe irgendwo gelesen, dass 
fsockopen viel langsamer sein soll, kann ich aber irgendwie nicht ganz 
glauben...
<?php
 $output = pack("CSSSSSSSS", 0x20, $r, $g, $b, 0, $r, $g, $b, 0);
 $socket = fsockopen("192.168.25.158", 5160);
 fwrite($socket, $output, 17);
 fclose($fp);
?>

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.