Lectura de serie a través de USB con problemas de octava GNU

Tengo dificultades para leer un puerto de comunicación virtual USB en GNU Octave, y hay algunos sucesos extraños sobre los que me gustaría recibir información.

Actualmente tengo un dispositivo de puerto de comunicación virtual USB CDC que programé para responder a los comandos en serie con la computadora. El dispositivo es una placa de microcontrolador (placa Discovery STM32F401C) con un giroscopio. El giroscopio se lee sobre SPI en el microcontrolador y luego el micro transmite los datos a la computadora. Espera hasta que recibe los comandos "x", "y" o "z" para enviar datos y luego continúa enviando datos para esa coordenada hasta un bit de parada (cualquier cosa que no sea "x", "y" o " z", normalmente uso "s").

Usando CuteCom puedo interactuar bien con el dispositivo, por ejemplo, enviar el comando "xs" devolverá un solo paquete de 6 bytes de los datos de velocidad angular del eje x (tal vez algo así como "+00021"). Usando GNU Octave y su paquete de control de instrumentos, puedo leer en todas las coordenadas, pero enviar la cadena "xs" hará que el dispositivo solo reciba el byte "x" y transmitirá datos del eje x continuamente.

Esto se puede solucionar agregando un retraso de carácter de 1 ms. El dispositivo STM que lee los comandos en serie también espera 1 ms entre los bytes que lee, porque anteriormente podía enviar muchas cadenas para el eje x antes de recibir el comando "s".

Entonces funciona, ¿verdad? Aparentemente no. El comportamiento extraño comienza aquí, ya que cuando ejecuto la secuencia de comando y luego lectura en Octave una vez todo funciona, pero en un bucle, los datos leídos son solo el eje x. Pensé que se trataba de un problema de sincronización y tenía curiosidad por ver qué se estaba leyendo directamente desde el puerto usando CuteCom.

Cuando CuteCom está monitoreando el puerto serie en busca de datos, Octave lee los datos correctamente durante la duración del bucle. Pero cuando no está monitoreando el puerto serie, solo leerá el eje x.

No entiendo por qué tener CuteCom ejecutándose en paralelo con el script de Octave haría que el proceso funcionara como se esperaba, pero sin CuteCom ejecutándose, los datos se corrompen. Aquí está el script de GNU Octave:

pkg load instrument-control;
pkg load signal;

s1 = serial("/dev/ttyACM0");
set(s1,'baudrate',115200);
set(s1, 'bytesize',8);
set(s1,'parity','n');
set(s1,'stopbits',1);
set(s1,'timeout',100); %10.0 seconds

sleep(0.5);
srl_flush(s1);

datax = [];
datay = [];
dataz = [];
negativex = false;
negativey = false;
negativez = false;
xd = 0;
yd = 0;
zd = 0;
delaytime = 1000; %delay time in microseconds (us)

hold on;
for i = 1:500
  srl_write(s1,"x");
  usleep(delaytime);
  xd = str2num(char(srl_read(s1,6)));
  srl_write(s1,"s");
  usleep(delaytime);

  srl_write(s1,"y");
  usleep(delaytime);
  yd = str2num(char(srl_read(s1,6)));
  srl_write(s1,"s");
  usleep(delaytime);

  srl_write(s1,"z");
  usleep(delaytime);
  zd = str2num(char(srl_read(s1,6)));
  srl_write(s1,"s");
  usleep(delaytime);

  datax = [datax xd];
  datay = [datay yd];
  dataz = [dataz zd];

  if mod(i, 10) == 0
    hold off;
    plot(datax,'r');
    hold on;
    plot(datay,'b');
    plot(dataz,'g');
    drawnow;
  endif
endfor
%

El resultado de los tres ejes cuando CuteCom no se está ejecutando (observe cómo se copian los datos para las tres líneas, con un pequeño retraso entre ellos):

Resultado de datos erróneos (CuteCom no se está ejecutando)

El resultado de la buena salida de datos, cuando CuteCom se está ejecutando (tenga en cuenta que los datos de cada eje son coherentes y claros):

Buen resultado de datos (CuteCom ejecutándose)

¿Alguien se ha encontrado con algo como esto antes? ¿Qué errores se cometieron para que esto sucediera?

Gracias de antemano.

Sam

Es probable que esto sea un problema con la configuración del controlador del puerto serie (terminación de línea, mapeo de caracteres, el infame modo canónico, etc.) o suposiciones inválidas que se originan con un malentendido de lo que tiene un flujo serie normalmente byte empaquetado para USB a los tiempos entre llegadas y agrupaciones como se ve a través de llamadas a read()o incluso peor fread(). Es posible que desee desarrollar una herramienta (en python, C o lo que sea) que obtenga datos de manera confiable y luego los canalice a su programa de trazado.
Preferiría no agregar otro nivel de abstracción al sistema, aunque no estoy completamente en contra de agregar la interfaz. ¿Qué puedo hacer para solucionar el problema a través de Octave? No asumo que esté particularmente bien informado sobre la mecánica de Octave, y lo elegí para la trama en lugar de la interfaz en serie. Pero se prefiere la homogeneidad, así que me interesan las opciones.
Podría intentar ejecutarlo bajo strace - ¡prepárese para hacer un grepping del resultado! Creo que también puedes usar algo como wireshark para obtener las transferencias USB sin procesar desde ese lado. También use stty para examinar y comparar la configuración de la línea cuando los dos programas se están ejecutando. Las soluciones todo en uno son buenas, pero no olvide las virtudes del "estilo Unix" con pequeños programas de una sola tarea encadenados con salida canalizada a entrada.

Respuestas (1)

He resuelto el problema, así que publicaré la respuesta. De hecho, fue un problema de tiempo. Para reparar el programa anterior, eliminé el retraso entre el comando "x" y la lectura. No puedo decir con seguridad por qué el programa no se comportaría correctamente con este retraso, pero la mejor manera de obtener los datos era eliminarlos: enviar el comando, leer inmediatamente, enviar el comando de parada, retrasar.

Gracias por la ayuda @Chris Stratton. ¡Aunque el problema era más pequeño de lo esperado!

Sam