TRX-1: Wendy, please update RCIP documentation.

Status
Not open for further replies.

strcpy

Member
Joined
Aug 2, 2015
Messages
21
Location
Cambridge, MA
Received: 241 bytes
024C 2020 2020 2020 2020 2020 2020 2020 .L..............
2020 2D53 6572 7669 6365 2053 6561 7263 ..-Service.Searc
682D 4C69 6D69 7420 5365 6172 6368 2020 h-Limit.Search..
2020 444D 5220 2020 3435 322E 3237 3530 ..DMR...452.2750
3030 536C 6F74 3A32 2020 436F 6C6F 723A 00Slot:2..Color:
2031 2020 2054 4749 443A 2020 2020 2020 .1...TGID:......
2032 4D82 0003 9A5F 4452 4C3A 3031 2030 .2M...._DRL:01.0
3020 3030 2030 3020 3030 2030 3020 3030 0.00.00.00.00.00
2030 3220 3030 2030 3020 3031 2030 3320 .02.00.00.01.03.
3030 200D 0A5F 4452 4C3A 3031 2030 3220 00..._DRL:01.02.
3030 2030 3020 3030 2030 3020 3030 2030 00.00.00.00.00.0
3220 3030 2030 3020 3031 2031 4520 3030 2.00.00.01.1E.00
200D 0A5F 4452 4C3A 3031 2030 3220 3030 ..._DRL:01.02.00
2030 3020 3030 2030 3020 3030 2030 3220 .00.00.00.00.02.
3030 2030 3020 3031 2031 4520 3030 200D 00.00.01.1E.00..
0A

When picking up a DMR signal, the USB endpoints will stall, the above data is NOT in the specification, not a CCDUMP, it's way off a single transaction via bisync, and the above data does not even represent the 16x16 matrix.

Can you please explain?
 

DonS

Member
Joined
Jun 17, 2003
Messages
4,102
Location
Franktown, CO
The first part of that data is a response to the 'L' command (send LCD contents):
Code:
024C 2020 2020 2020 2020 2020 2020 2020 .L..............
2020 2D53 6572 7669 6365 2053 6561 7263 ..-Service.Searc
682D 4C69 6D69 7420 5365 6172 6368 2020 h-Limit.Search..
2020 444D 5220 2020 3435 322E 3237 3530 ..DMR...452.2750
3030 536C 6F74 3A32 2020 436F 6C6F 723A 00Slot:2..Color:
2031 2020 2054 4749 443A 2020 2020 2020 .1...TGID:......
2032 4D82 0003 9A

The remainder is CCDump data:
Code:
                 5F 4452 4C3A 3031 2030 .2M...._DRL:01.0
3020 3030 2030 3020 3030 2030 3020 3030 0.00.00.00.00.00
2030 3220 3030 2030 3020 3031 2030 3320 .02.00.00.01.03.
3030 200D 0A5F 4452 4C3A 3031 2030 3220 00..._DRL:01.02.
3030 2030 3020 3030 2030 3020 3030 2030 00.00.00.00.00.0
3220 3030 2030 3020 3031 2031 4520 3030 2.00.00.01.1E.00
200D 0A5F 4452 4C3A 3031 2030 3220 3030 ..._DRL:01.02.00
2030 3020 3030 2030 3020 3030 2030 3220 .00.00.00.00.02.
3030 2030 3020 3031 2031 4520 3030 200D 00.00.01.1E.00..
0A
the CCDump data, as plain text, looks like:
_DRL:01 00 00 00 00 00 00 02 00 00 01 03 00
_DRL:01 02 00 00 00 00 00 02 00 00 01 1E 00
_DRL:01 02 00 00 00 00 00 02 00 00 01 1E 00
 

strcpy

Member
Joined
Aug 2, 2015
Messages
21
Location
Cambridge, MA
So CCDump auto-enables on DMR tune even though it's globally set to off?

If that's the case, the documentation *REALLY* needs an update; this might cause issues at 0x0040 sized frames.
 

DonS

Member
Joined
Jun 17, 2003
Messages
4,102
Location
Franktown, CO
No, that's actually an artifact of some DMR debugging.

In general, though, a utility that is going to connect to the scanner for "monitor & control" should be able to handle CCDump data in the same data stream.

I'm not sure what you mean by "0x0040 sized frames".
 

strcpy

Member
Joined
Aug 2, 2015
Messages
21
Location
Cambridge, MA
In general, though, a utility that is going to connect to the scanner for "monitor & control" should be able to handle CCDump data in the same data stream.

Good enough, my testing has been done with CCDump turned off globally. I figured I would deal with that data and "rcip" later. But if what you are saying is correct:

"CCDump = Off".

Really means

"CCDump = Off... Unless some unknown flag is set by the scanner and starts cc without requesting".

The latter expectation doesn't cause potential stalls.

So STX ETX bytes can be a part of the payload. This is the fault of whistler not using the standard bisync protocol (<stx><size><data><etx><crc>), opting to use something that requires an understanding of the data sizes and structure of each request and response.

Without specifications, the logic would have to be something along the lines of this pseudocode: https://gitlab.com/snippets/1658237

I'm not being a jerk here, quite the opposite. I honestly don't see how you could blindly read in data without knowing what it is. The above has to calculate the bcc each time it sees etx.

When the documentation continues to age, and the more features added - third party software becomes a risk to all users; not just security wise, but performance wise (the pseudocode posted above could go into an endless loop until OOM).

Even as a use-at-your-own-risk feature, I would nice to have documentation that wasn't 4-5 releases behind without breaking out IDA again.

Thank you very much for the response, I look forward to the next.
 
Last edited:

DonS

Member
Joined
Jun 17, 2003
Messages
4,102
Location
Franktown, CO
So STX ETX bytes can be a part of the payload. This is the fault of whistler not using the standard bisync protocol (<stx><size><data><etx><crc>), opting to use something that requires an understanding of the data sizes and structure of each request and response.

Actually, it goes back to GRE and the PSR-500.

Yes, it's presumed that before a third-party app sends a request for data that it's going to use, the third-party app will know the format of the response that contains that data.

While STX and ETX can appear in the payload of the response to a third-party app's request, they will never be part of CCDump data.

If I was to write code to handle this (like I did for my Win500 app), it would go something like the below. I'd call this after each request sent. NOTE: this is pseudo-code only for illustrative purposes; I have not attempted to compile or run it.

When I'm not sending requests and expecting responses, I'd be looking for, reading, and processing CCDump data. Whether that's necessary really depends on how frequently I'm sending requests to the scanner. For example, if I'm sending status requests every 10 milliseconds, I probably don't need to look for CCDump data separately from the routine that handles responses.

Code:
/* int GetResponse( unsigned char *destbuf, int payloadlen )

   Reads data from input stream, looking for an expected response to a sent request

   returns non-zero if response of expected length received and checksum passed.
   returns zero if timed out waiting for response or checksum failed.

   destbuf = Pointer to buffer in which to store the received response. Must be
             large enough to hold full expected response.

   payloadlen = Length of payload in expected response
*/
int GetResponse( unsigned char *destbuf, int payloadlen )
  {
  #define _TmpBufSize   32
  unsigned char tmpbuf[_TmpBufSize];
  int timedout, rxoffset, remaining, haveSTX, avail, index, goodsum;

  /* offset into destbuf[] for placing rx data */
  rxoffset = 0;

  /* remaining bytes include STX <cmd> ETX <sum> */
  remaining = payloadlen + 4;

  /* flag for "saw start of response */
  havestx = 0;

  /* initialize some timeout criteria */
  timedout = 0;
  InitTimeout(1000);


  /* as long as there are bytes remaining int expected response */
  while ( remaining && !timedout )
    {
    /* check for timeout and update the flag */
    timedout = CheckTimeout();
    /* even if we've "timed out", go ahead and see if there are any
       rx bytes for us in this pass */

    /* see if there are any bytes available in the input stream */
    avail = GetAvailableBytes();

    /* if so, read whatever's available and process it */
    while ( avail )
      {
      int toread = avail;

      /* don't overrun our local buffer */
      if ( toread > _TmpBufSize )
        toread = _TmpBufSize;

      /* subtract what we're going to read from what's available */
      avail -= toread;

      /* get bytes from input stream */
      ReadBytes( tmpbuf, toread );
    
      /* if we haven't yet received STX */
      if ( !haveSTX )
        {
        /* look for it */
        index = 0;
        while ( !haveSTX && index < toread )
          {
          /* if this is STX */
          if ( tmpbuf[index] == STX )
            {
            /* set the flag (causes loop exit) */
            haveSTX = 1;
            }
          else
            {
            /* otherwise, it's CCDump data - do whatever with that byte */
            ProcessCCDump( tmpbuf[index++] );
            }
          }
        }

      /* if we've seen STX and we still have bytes to process */
      if ( haveSTX && index < toread )
        {
        /* bytes to copy is whatever we have left in our local buffer */.
        int tocopy = toread-index;

        /* but, only up to expected response bytes */
        if ( tocopy > remaining )
          tocopy = remaining;

        /* stuff those bytes into the passed destination buffer */
        memcpy( destbuf+rxoffset, tmpbuf+index, tocopy );

        /* adjust the dest buffer index */
        rxoffset += tocopy;

        /* adjust the remaining response bytes */
        remaining -= tocopy;

        /* adjust index into what we've read from stream */
        index += tocopy;
        }

      /* in case there are still extra bytes that we read (i.e. CCDump bytes
         after end of expected response), process them */
      while ( index < toread )
        {
        ProcessCCDump( tmpbuf[index++] );
        }
      }
    }

  /* if we got the full expected response */
  if ( !remaining )
    {
    // calculate sum, compare to received, set flag
    unsigned char sum = 0;
    int sumcount = payloadlen + 3;
    for ( index=1; index < sumcount; sum += destbuf[index++] );
    goodsum = sum == destbuf[index];
    }

  /* return non-zero if we got a valid response packet,
     zero if we timed out or the sum was bad */
  return !remaining && goodsum;
  #undef _TmpBufSize
  }
 

DonS

Member
Joined
Jun 17, 2003
Messages
4,102
Location
Franktown, CO
I honestly don't see how you could blindly read in data without knowing what it is.

Any time you get an STX, it's in response to a request you sent. The scanner never sends an STX <data> ETX <sum> packet unless you expressly request it. Also, it's a one-to-one mapping - one request, one response.

Thus, by definition, you always know what type of packets are coming. Anything that is not part of such a packet is CCDump data.
 

strcpy

Member
Joined
Aug 2, 2015
Messages
21
Location
Cambridge, MA
Any time you get an STX, it's in response to a request you sent. The scanner never sends an STX <data> ETX <sum> packet unless you expressly request it. Also, it's a one-to-one mapping - one request, one response.

Thus, by definition, you always know what type of packets are coming. Anything that is not part of such a packet is CCDump data.

Your pseudocode and mine didn't match up very close :) though both suffer from performance problems,

But this has been derailed, my point was the outdated documentation.
 
Last edited:

DonS

Member
Joined
Jun 17, 2003
Messages
4,102
Location
Franktown, CO
Your pseudocode and mine didn't match up very close :) though both suffer from performance problems,

But this has been derailed, my point was the outdated documentation.

Yes, mine could use some mods to reduce CPU cycles when no data is available. In Win32, I'd probably ::Sleep(0) to yield the rest of the time slice if "GetAvailableBytes()" returned zero.

I don't believe there's anything wrong with the documentation. As mentioned above, the "unexpected" CCDump data is due to debugging code that was left in the released version of the firmware. It's more properly classified as a "bug", rather than "outdated documentation". It will be removed from the next release of the firmware (all platforms).

Unless there's something in the documentation's description of the STX / ETX packets that's wrong?
 
Status
Not open for further replies.
Top