Shop OBEX P1 Docs P2 Docs Learn Events
Need help - parsing serial input — Parallax Forums

Need help - parsing serial input

An old project needs updating... TL;DR: How do I synchronize on and input two different command strings, and parse them appropriately?

I have a ham antenna rotor controller that is driven by a Basic Stamp-II. It emulates a Yaesu GS-232B (at least partly), and it's been working flawlessly for more than 2 decades. Unfortunately, the host software that drives it was updated recently, so the controller needs to follow.

The commands from the host software consist of a "W" followed by two decimal numbers corresponding to the desired azimuth and elevation positions, followed by a carriage return. The string is repeated every few seconds. I'm using the following code to input the data:

serin serial,baud,2000,noserial,[wait("W"),DEC azinput,DEC elinput]

All's fine so far. The code waits for the "W" character, then slurps in the coordinates. The problem is that the host software now also sometimes sends the command "C2" instead of the "W" command, intending to poll my controller for where it's currently pointing. Receiving a C2 should trigger a response of 2 numbers; my controller doesn't respond, so the host times out and stops. I don't believe the sequence of W vs C commands is fixed (e.g. they don't strictly alternate), so I have to respond to either as requested.

Is there a way to wait for (i.e. synchronize to) either the W or C character, then pick up the rest of the string and act as necessary? I think I need something like wait("w"|"C"), but don't see such a construct in the programming guide.

I don't relish the idea of rebuilding something that's otherwise working just fine. Fixing software with hardware is wasteful... Thoughts?

Comments

  • JonnyMacJonnyMac Posts: 9,087

    The problem is the blocking nature of serial with the BASIC Stamp and the lack of RAM. If you have enough memory you could use a timeout to wait for characters and then parse them manual. This will take code, though, and you lose the DEC feature of SERIN.

  • Ugh, I was afraid of that. Looks like there might be an Arduino in the controller's future, though it would be a lot easier to modify the host driver (rotctld) to not care if the C2 times out. I looked for a config flag to turn it off, but no joy found.

    Thanks for the quick reply, Jon. Much appreciated.

  • JonnyMacJonnyMac Posts: 9,087

    The P1 is a good candidate -- and I have a parser library for it that can allow you to deal with up to 10 elements in your command string. It gets used in camera controllers and a medical instrument that uses microscopy to analyze blood. If you can program PBASIC, you can program Spin.

  • Thanks. Programming is not a problem - software engineer from way back (learned Basic and Fortran in 1973). Just thinking about rebuilding something that's been working for so long is a bit painful. I went back in my archive; version 1.0 of the code was written in Feb 2000; it's currently on version 1.4 from 2013.

    What might be interesting is to create a daughter board with a newer processor on it, and a header to plug into the existing Stamp-II socket. Need to count I/O pins and such. But the easiest approach is probably to just modify the host software. After all, what is open source software for if not for looking at it and making changes?

  • There is always a PIC micro as well. I do this all the time without any issues. However if you don't want to use a PIC, the fundamentals are really all you need and can be applied in just about any micro. I setup a FIFO (First In First Out) buffer and look for a valid sync character. In your case "C", "W", or "C2", etc. If the sync character is present, then I look at the other data to validate the packet, otherwise i ignore the data packet. I also implement a CRC to add robustness to the data packet. I particularly like MODBUS since it is easy to encode and decode. but you could just do a simple XOR of the data BYTES

  • MicksterMickster Posts: 2,691

    @"Beau Schwabe" said:
    There is always a PIC micro as well. I do this all the time without any issues. However if you don't want to use a PIC, the fundamentals are really all you need and can be applied in just about any micro. I setup a FIFO (First In First Out) buffer and look for a valid sync character. In your case "C", "W", or "C2", etc. If the sync character is present, then I look at the other data to validate the packet, otherwise i ignore the data packet. I also implement a CRC to add robustness to the data packet. I particularly like MODBUS since it is easy to encode and decode. but you could just do a simple XOR of the data BYTES

    Exactly what I've always done :+1:

    BASIC Interpreter: The PicoMite has a CRC function, built-in.

  • Beau SchwabeBeau Schwabe Posts: 6,566
    edited 2024-10-22 18:07

    @Mickster said:
    BASIC Interpreter: The PicoMite has a CRC function, built-in.

    Since I will usually have one project span multiple platforms all in communication with each other, I have a MODBUS CRC generator for each platform:

    PIC (MPASM)
    Python
    Arduino
    Javascript
    Perl

    Sorry, no Basic Stamp or Propeller

    Attached is the MODBUS code for Arduino ...

    MODBUS_SUBs::LOAD_CRC(0xFFFF);          // Load CRC with $FFFF or your desired Seed value
    
    MODBUS_SUBs::MODBUS_BYTE(BYTE);         // Call this for each BYTE in packet excluding the actual CRC byte(s)
    
    MODBUS_SUBs::CRC_SHORT();               // Do this to conserve bandwidth (Single BYTE version of CRC)
    
    MODBUS_SUBs::CRC_High();                // Read MODBUS CRC HIGHBYTE
    MODBUS_SUBs::CRC_Low();                 // Read MODBUS CRC LOWBYTE  
    
    
    Note: if you use CRC_SHORT then CRC_High and CRC_Low are invalid
    
  • Tracy AllenTracy Allen Posts: 6,663
    edited 2024-10-29 00:10

    Could you use the STR bytearray modifier? It takes a bit of available ram to hold the array, but the resulting string should be easy to parse.

    mystring VAR byte(16) ' for W aaaaa,eeeee CR. or for C2 CR
    serin serial,baud,2000,noserial,[STR mystring \15\13]
    ' string ends with 15 chars or at CR, remaining bytes are nulled.

    Then look for W or C at mystring(0). If yes, W or C, parse and respond appropriately. If not either W or C, then wait for a time interval likely to land you in a quiet spot between commands. It wouldn't sync well if the commands arrive too quickly.

Sign In or Register to comment.