Al solicitar el puerto de comunicación, se devuelve la misma solicitud

Estoy tratando de enviar un comando AT a través del puerto COM, pero reseveé solo el mismo comando.

package SerialConnections; import jssc.SerialPort; import jssc.SerialPortEvent; import jssc.SerialPortEventListener; import jssc.SerialPortException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static ru.telemetria.qa.utils.Utilities.waitTime; public class M234Serial { private static Logger log = LoggerFactory.getLogger(M234Serial.class); private SerialPort serialPort; private byte[] receivedData; private boolean isReceived; public M234Serial() throws Exception { serialPort = new SerialPort("COM55"); } public void sendCommand() throws Exception { open(); String command = "AT^SCFG?"; serialPort.writeBytes(command.getBytes()); log.debug("Send request: " + command); while (!isReceived) {} close(); } private void open() throws Exception { serialPort.openPort(); serialPort.setParams(SerialPort.BAUDRATE_115200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); serialPort.addEventListener(new SerialPortEventListener() { @Override public void serialEvent(SerialPortEvent serialPortEvent) { try { waitTime(System.currentTimeMillis(), 2000); receivedData = serialPort.readBytes(); log.debug("Received message: " + StringUtils.asciiToString(receivedData)); isReceived = true; serialPort.removeEventListener(); } catch (SerialPortException spe) { spe.printStackTrace(); } } }); } private void close() throws Exception { serialPort.closePort(); } public static void main(String[] args) throws Exception { log.debug("Create instance.."); M234Serial serial = new M234Serial(); serial.sendCommand(); log.debug("End"); } } 

Iniciar sesión:

16: 19: 21.910 [main] DEBUG SerialConnections.M234Serial – Crear instancia …

16: 19: 21.974 [principal] DEBUG SerialConnections.M234Serial – Solicitud de envío: AT ^ SCFG?

16: 19: 23.976 [EventThread COM55] DEBUG SerialConnections.M234Serial – Mensaje recibido: AT ^ SCFG?

16: 19: 23.977 [main] DEBUG SerialConnections.M234Serial – Fin

¿Qué estoy haciendo mal y cómo puedo solucionarlo?

La espera ocupada como while (!isReceived) {} producirá un rendimiento horrible, por lo que si mantiene esa estructura, debe cambiar la variable de booleano a mutex / semáforo o algo similar. Pero no debes guardarlo, así que lo menciono solo como referencia.


Comience por buscar una copia del estándar de módem V.250 y lea al menos todo el capítulo 5. Esto le enseñará una gran cantidad de manejo básico de comandos AT, como por ejemplo que una línea de comando AT debe terminar con \r .

El comando AT ^ SCFG obviamente es un comando específico del fabricante propietario por lo que no tengo una referencia de documentación para eso. La mayoría de los comandos AT relacionados con teléfonos móviles estandarizados por 3GPP se dan en 27.007 , aunque algunos (relacionados con SMS) se dan en 27.005.

Como se mencionó al principio, la estructura debe ser modificada. Nunca, nunca, nunca, nunca use waitTime , sleep o algo similar para esperar la respuesta de un módem. Es tan útil como patear perros que se interponen en tu camino para que se muevan. Sí, es posible que tengas suerte y que en realidad funcione a veces, pero en algún momento lamentarás haber adoptado ese enfoque …

El único enfoque confiable es hacer algo similar a

 serialPort.openPort(); ... // start sending AT^SCFG? serialPort.writeBytes("AT^SCFG?\r"); do { line = readLine(serialPort); } while (! is_final_result_code(line)) // Sending of AT^SCFG? command finished (successfully or not) ... serialPort.closePort(); 

donde la función readLine lee uno y un byte del puerto serie hasta que haya recibido una línea completa terminada con \r\n y luego devuelve esa línea.

Puede ver el código de un ejemplo para la función is_final_result_code (también puede comparar isFinalResponseError y isFinalResponseSuccess en U300 RIL de ST-Ericsson , aunque tenga en cuenta que CONNECT no es un código de resultado final, es un código de resultado intermedio, por lo que el nombre esFinalResponseSuccess estrictamente hablando no es 100% correcto).


El problema con el envío de comando que se está recibiendo está relacionado con el módem que hace eco del comando. Esto se puede deshabilitar con el comando ATE pero con una estructura de análisis adecuada como la anterior, esto normalmente no importa porque simplemente lee el comando repetido como una línea que será ignorada.

Sugiero las siguientes mejoras a tu código:

  • Reemplazar waitTime(System.currentTimeMillis(), 2000); en el evento listener with if ( serialPortEvent.isRXCHAR() ) { ...
  • Asegúrese de terminar su comando AT correctamente; generalmente se requiere un salto de línea y / o un retorno de carro al final de cada cadena de comando. Verifique la documentación de su dispositivo.
  • Make isReceived volátil , es decir, private volatile boolean isReceived; , si se va a compartir entre diferentes hilos.

Para evitar la espera de ocupado, puede usar primitivas de sincronización Java estándar, como esta:

 private volatile boolean isReceived; private final Object syncObject = new Object(); // ... private void waitForReceived() { synchronized(syncObject) { while( !isReceived ) { syncObject.wait(); } } } private void signalReceived() { synchronized(syncObject) { isReceived = true; syncObject.notifyAll(); } }