Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

357
Visualizações
PHP Serial connection read timeout

I'm trying to figure something out here

I have a 'sequence' to be executed via a serial port (on an RPI).

I have an supervisored PHP command in Laravel running that connects to a MQTT broker.

When I send a message to that broker, the RPI picks it up and processes it. Now, I have a moment in which I wait for user interaction. The issue here is, sometimes the user does not interact with the system and the PI keeps "waiting" for serial data. When a user presses a button, I get serial data, which I can process.

I tried to use a while (true) {} loop that reads the serial data, but it just stops suddenly. Here is some example code;

$configure = new TTYConfigure();
$configure->removeOption("9600");
$configure->setOption("115200");

$this->serialPort = new SerialPort(new SeparatorParser("\n"), $configure);

$serialDevice = config('app.device_type') === 'usb' ? '/dev/ttyACM0' : '/dev/ttyAMA0';

$this->serialPort->open($serialDevice);

// this is a special one, we add an timeout here of 15 seconds, to prevent that the machine would get stuck.
$timeoutStart = time();
$timeout = $timeoutStart + 15; // 15 seconds of timeout.
$aborted = false;

while (true) {
    $data2 = $this->serialPort->read();

    if (Str::contains($data2, "Whatever I want to check for")) {
        // Process the data and get out of this loop via a 'break;' statement
    }


    // check if 15 seconds have passed, if so, then we want to stop the vend sequence.
    if (time() >= $timeout) {
        $this->serialPort->write("C,STOP\n"); // STOP vending
        $aborted = true;
        $this->alert("vending sequence stopped");
    }
}

When I place logs in the true loop, I see it loops, but suddenly stops looping (I bet it's the $data2 = $this->serialPort->read(); that just "stops" reading or keeps reading the serial port.

I want to be able to kill the loops and do an API call to revert some changes that hapend before that action.

Is this possible? If so how?

Packages I use:

  • Laravel lumen
  • PhpMqtt
  • lepiaf\SerialPort
over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

If you look at the source of lepiaf\SerialPort you'll find it sets the stream in non blocking mode, however the read method does an infinite loop until it finds the separator. This means it will never return unless the separator is received, and depending on your configuration your script will be killed once the php max execution time is reached. Since the library is very simple the better option is to edit the read method adding a timeout parameter. Edit the file "lepiaf/SerialPort/SerialPort.php", scroll down to the read method (line 107) and change it as follows:

public function read($maxElapsed = 'infinite')
{
    $this->ensureDeviceOpen();
    
    $chars = [];
    $timeout = $maxElapsed == 'infinite' ? 1.7976931348623E+308 : (microtime(true) + $maxElapsed);
    do {
        $char = fread($this->fd, 1);
        if ($char === '') {
            if (microtime(true) > $timeout) return false;
            usleep(100);    //Why waste CPU?
            continue;
        }
        $chars[] = $char;
    } while ($char !== $this->getParser()->getSeparator());

    return $this->getParser()->parse($chars);
}

Then in your code call the method as:

$data2 = $this->serialPort->read(15);
if ($data2 === false) {
    //Timeout occurred
} elseif (Str::contains($data2, "Whatever I want to check for")) {
    //String found
} else {
    //Data received but string not found
}
over 4 years ago · Santiago Trujillo Relatório

0

if (Str::contains($data2, "Whatever I want to check for"))

above code is your culprit.

$data2 = $this->serialPort->read();

might not read the whole string at once it will give data when it gets in to the read buffer. so best to collect data in an internal buffer and check the buffer for your condition.

$data2 .= $this->serialPort->read();

make sure to initialize data2 before the loop.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda