Estoy tratando de resolver algo aquí
Tengo una 'secuencia' para ejecutar a través de un puerto serie (en un RPI).
Tengo un comando PHP supervisado en ejecución en Laravel que se conecta a un corredor MQTT.
Cuando envío un mensaje a ese corredor, el RPI lo recoge y lo procesa. Ahora, tengo un momento en el que espero la interacción del usuario. El problema aquí es que, a veces, el usuario no interactúa con el sistema y el PI sigue "esperando" los datos en serie. Cuando un usuario presiona un botón, obtengo datos en serie, que puedo procesar.
Intenté usar un bucle while (true) {} que lee los datos en serie, pero se detiene repentinamente. Aquí hay un código de ejemplo;
$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"); } } Cuando coloco registros en el bucle verdadero, veo que se repite, pero de repente deja de hacerlo (apuesto a que es $data2 = $this->serialPort->read(); eso simplemente "detiene" la lectura o sigue leyendo el puerto serie.
Quiero poder eliminar los bucles y hacer una llamada a la API para revertir algunos cambios que ocurrieron antes de esa acción.
es posible? ¿Si es así, cómo?
Paquetes que uso:
Si observa la fuente de lepiaf\SerialPort, encontrará que configura la transmisión en modo sin bloqueo, sin embargo, el método de lectura realiza un ciclo infinito hasta que encuentra el separador. Esto significa que nunca regresará a menos que se reciba el separador y, dependiendo de su configuración, su secuencia de comandos se eliminará una vez que se alcance el tiempo máximo de ejecución de php. Dado que la biblioteca es muy simple, la mejor opción es editar el método de lectura agregando un parámetro de tiempo de espera. Edite el archivo "lepiaf/SerialPort/SerialPort.php", desplácese hacia abajo hasta el método de lectura (línea 107) y cámbielo de la siguiente manera:
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); }Luego, en su código, llame al método como:
$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 }if (Str::contains($data2, "Whatever I want to check for"))el código anterior es tu culpable.
$data2 = $this->serialPort->read();Es posible que no lea toda la cadena a la vez, proporcionará datos cuando llegue al búfer de lectura. por lo tanto, es mejor recopilar datos en un búfer interno y verificar el búfer para su condición.
$data2 .= $this->serialPort->read();asegúrese de inicializar data2 antes del bucle.