Missing serial data

Status
Not open for further replies.

JasonH

Member
The application I am working on reads an 8 byte packet from the serial port. It then translates that to mouse movement.
Unfortunately what happens is eventually a byte or more gets lost from the serial, which then means my packets don't line up.
Format is CXXYYW00 where
C command byte (243 is the mouse move relative function code)
XX big endian signed int for X
YY big endian signed int for Y
W signed byte wheel

243 0 0 0 14 0 0 243 incrementalMouseMove 0 14 0
0 0 0 11 0 0 0 243 ????
this should be:
243 0 0 0 14 0 0 0 incrementalMouseMove 0 14 0


So a byte was "lost". Both the reading and writing are dead simple:
Remote:
Code:
	for ( char c : {b1, b2, b3, b4, b5, b6, b7, b8}) {
		serialPort.write(&c, 1);
		serialPort.flush();
	}
Teensy:
Code:
while (COMMAND_PORT.available() >= 8) {
  b1 = COMMAND_PORT.read();
  b2 = COMMAND_PORT.read();
  b3 = COMMAND_PORT.read();
  b4 = COMMAND_PORT.read();
  b5 = COMMAND_PORT.read();
  b6 = COMMAND_PORT.read();
  b7 = COMMAND_PORT.read();
  b8 = COMMAND_PORT.read();

  printBytes(b1, b2, b3, b4, b5, b6, b7, b8);
  ...eventually it gets unpacked and calls ...
 incrementalMouseMove(x, y, w);
}

The issue seems to be coming from use of delay() in the incrementalMouseMove() function which will move the full distance. https://www.pjrc.com/teensy/td_mouse.html states that "For natural looking motion, many small moves performed slowly are needed." I've found that when dragging the mouse the target environments are particularly sensitive to this, so there is a loop that divides the movement up into smaller increments. This uses delay() because I read somewhere that the HID needs delay between commands. But it seems that this use of delay is causing me to miss bytes on the serial port. When I use a longer delay, or more delays, it gets worse.

Mouse.move(x,y,w); is limited to +/-127, but I allow larger values in the serial protocol and break it down into smaller increments, because I have to anyway. The goal is for the remote to be able to issue mouseDown(LeftButton), then mouseMove(2048, 0,w)

So I'm stuck between being HID friendly and getting all the data on the serial port it seems.

Help?
 
Maybe restructure your program, so you do not use delay(). One approach is to create an elapsedMillis variable which you check in loop(), and usually 1 or more other variable to remember what you will send next.

Or you could edit serial1.c to increase the serial receive buffer. While not as good as a better program structure without delay(), just editing the file to increase one number may be easier than rewriting your code.
 
Yeah, I was hoping the unit would be able to keep up, but it just can't.

I restructured it in a few ways. I have consolidated the mouse move commands, and supplied:
1. an off-board function that consolidates mouse movements < 25ms apart. This cuts down on the serial chatter substantially.
2. an on-board function to linear interpolate between the start and end mouse movements. The novelties here are that
a. you can only move the mouse integer amounts.
b. you don't exceed +/- 127 on the relative move
c. it is perceived as a smooth movement, i.e. dragging, and not jumping.

With those two features, I can move the mouse anywhere in just a few bytes
Code:
void incrementalMouseMove(int16_t x, int16_t y, int8_t w1, int responseDelay) {
  int steps = sqrt(x*x + y*y);
  int movedX=0; 
  int movedY=0;
  double rateX = x/(double) steps;
  double rateY = y/(double) steps;
  int currentX = 0;
  int currentY = 0;
  int dx = 0;
  int dy = 0;

  for (int i=0; i<=steps; i++){
    currentX = i*rateX;
    currentY = i*rateY;
    dx = currentX - movedX;
    dy = currentY - movedY;
    if (dx || dy) {
      Mouse.move(dx, dy, 0);
      delay(responseDelay);
      movedX = currentX;
      movedY = currentY;
    }
  }
}

Edit: I also found out that as a Teensy LC, I only have a soft serial buffer and not a real FIFO.
 
Last edited:
Status
Not open for further replies.
Back
Top