More Serial Info Required, If Possible.

Discussion in 'General Discussion' started by xrmichael, Feb 5, 2008.

  1. xrmichael

    xrmichael

    Joined:
    Nov 20, 2006
    Messages:
    93
    Likes Received:
    0
    Location:
    uk
    Further to my last coding escapes, I thou gt i would try a more challenging task, and have ran straight into what seems like a unsurmountable problem, so hence a post to the forum.

    I can request a menu listing from my sound server using a writeserial command and then want to read this back into a string for display.

    The resulting string is around 111 bytes long, flicking through a pascal book, strings seem to be 255 bytes by default (i could be wrong).

    I have knocked up some code to try and read and display the string but it only seems to contain the first few bytes ?

    Code

    WriteSerial(1, #$55#$09#$90#$41#$00#$00#$00#$00#$00#$D1);
    {sync, comm lth, comm, dev add, res, state stamp must be sam as prev state stamp, res, dev command, command data, checksum}
    ReadSerial(1,serialin, ''); {read serial port to string serialin}
    Writeln ('POSITION = ', serialin);
    position := pos(#$55,serialIn);{find #$55}
    Writeln ('POSITION = ', POSITION); {test line remove when done}

    if (POSITION > 0) AND (SERIALIN[POSITION+1]<>#$00) and (SERIALIN[POSITION+2]=#$94) AND
    (SERIALIN[POSITION+3]=#$41) AND (SERIALIN[POSITION+4]=#$27) then

    begin
    Copy(metadata,serialin,position,255);
    for counter2 := 0 to 255 do
    begin
    TextPos(50,counter1);
    writeln(metadata[counter2]);
    counter1:=counter1+1;
    counter2:=counter2+1;
    delay(0.2);
    end;
    end;
    exitmodule

    Thanks.
     
    xrmichael, Feb 5, 2008
    #1
    1. Advertisements

  2. xrmichael

    froop

    Joined:
    Dec 23, 2007
    Messages:
    124
    Likes Received:
    0
    Location:
    Melbourne, Australia
    The ReadSerial command will read whatever is currently in the serial buffer.
    You are sending WriteSerial and then immediately reading the response from the buffer. What is most likely happening, is that you're reading the serial buffer before it as filled up with the full response.

    Ie,
    1. Send request to device
    2. Device starts sending info back, which populates the serial buffer
    3. ReadSerial pulls whatever is in the buffer
    4. Device sends rest of its string, which gets stored in the buffer
    5. You never check the buffer again to make sure you got everything

    There's a couple of ways around this. I've never used serial programming in PICED, but I'm drawing of a long history of serial programming with other devices..

    The "proper" way is to build a state machine which keeps reading data until you've got a full message, as mentioned in your other serial thread.

    A pseudo state machine solution would be to continue looping until you have a full message, then quit the loop. But this could bring in other issues.

    A quick and dirty method is to simply put a small delay between WriteSerial and ReadSerial to allow time for the full string to be received into the serial buffer before reading it. But assuming the device is running at 9600,n,8,1 that means 9600 bits per second. 8 data and 1 stop bit translates to 1066 bytes per second. A string of 111 characters should take approximately 100ms to be fully transmitted. To put a delay of 100ms into a cycle which runs every 200ms is probably not a Good Thing.

    (I think my calculations are right, but 100ms for 110 bytes seems long. Or maybe I'm just too used to ethernet and broadband speeds these days :) )

    Mark.

    Edit:
    I just quickly re-read some of the other thread (http://cbusforums.com/forums/showthread.php?t=3947) and it seems that you had the hang of the idea of a state machine when reading your zone statuses. If you are using this in the same project, you could include this in the same state machine. Your states could be something like:
    State 1 = idle/unknown
    State 2 = receiving message (with an identifier msgtype = 1 for status or 2 for menu)
    State 3 = received message
     
    Last edited by a moderator: Feb 6, 2008
    froop, Feb 6, 2008
    #2
    1. Advertisements

  3. xrmichael

    xrmichael

    Joined:
    Nov 20, 2006
    Messages:
    93
    Likes Received:
    0
    Location:
    uk
    Serial

    Its going at 57600, ill look at the state machine again i think i got half of it.
     
    xrmichael, Feb 6, 2008
    #3
  4. xrmichael

    froop

    Joined:
    Dec 23, 2007
    Messages:
    124
    Likes Received:
    0
    Location:
    Melbourne, Australia
    There is another alternative which takes advantage of the loop cycle of the Cbus logic engine 200ms loop cycle. Keep a simple two-state flag, and use it to send/receive on alternating cycles.

    Eg;

    Code:
    { Initialisation }
    SendRecvFlag := 0;
    
    { Serial Module }
    if (SendRecvFlag = 0) then
    begin
      SendRecvFlag := 1;
      WriteSerial... ;
    end
    else
    begin
      SendRecvFlag := 0;
      ReadSerial... ;
      ...
    end;
    
    What that will do is automatically allow for a 200ms delay after sending the request string before trying to read the response, which will be enough for full string to be sent.

    You may want to slow down the requests, and send a request only every 5 or ten cycles.
    Maybe something like this could work:

    Code:
    { Serial Module }
    if (SendRecvFlag mod 5 = 0) then
    begin
      WriteSerial... ;
    end;
    if (SendRecvFlag mod 5 = 1)
    begin
      SendRecvFlag := 0;
      ReadSerial... ;
      ...
    end;
    SendRecvFlag := SendRecvFlag + 1;
    
    Using this exampe, you can also allow a little more time for the buffer to fill by using
    Code:
    if (SendRecvFlag mod 5 = 3)
    to allow 600ms to pass between sending the request and reading the response.
     
    Last edited by a moderator: Feb 6, 2008
    froop, Feb 6, 2008
    #4
  5. xrmichael

    Darren Senior Member

    Joined:
    Jul 29, 2004
    Messages:
    2,361
    Likes Received:
    0
    Location:
    Adelaide, South Australia
    The default string length in the logic engine is 50 characters. If you want it longer, you need to declare it that way. See the logic help file topic "string type".

    The reasons that Froop has given are correct. The easiest way to get around this is to put a delay between the write and read. See the logic help file topic "serial IO" where it discusses exactly this problem.
     
    Darren, Feb 6, 2008
    #5
  6. xrmichael

    Wire_Bug

    Joined:
    May 6, 2009
    Messages:
    22
    Likes Received:
    0
    Hi XRMichael -

    I know it's been a while since this thread has been active, I'm hoping you'll see this since I happen to be fighting the same battle as you were last year. I'm curious if you were able to find a solution to this and actually print the metadata to the CTC successfully? If so, is there any chance you'd be willing to post it here?

    I'm having a hell of a time trying to consistently get the correct information into my string variable and parse it since this manufacturer so cleverly uses NUL characters as the delimiters between the information when requesting metadata. I keep hitting walls figuratively and I'm about ready to start hitting it literally with my head if I can't figure this out soon!

    Cheers!
     
    Wire_Bug, May 6, 2009
    #6
  7. xrmichael

    RossW

    Joined:
    Oct 10, 2005
    Messages:
    118
    Likes Received:
    0
    Is it only showing the first 4 bytes?

    Many environments consider "strings" to be null-terminated, and your 5th byte is hex 00 (null).
     
    RossW, May 6, 2009
    #7
  8. xrmichael

    Wire_Bug

    Joined:
    May 6, 2009
    Messages:
    22
    Likes Received:
    0
    The string you quoted there is what you send to the device to request the menu information, but nonetheless, the string that you get back can be of varying lengths depending on how much information is there. It is specified in the protocol that the information you receive back will have 42 bytes of standard information, then at the 43rd byte, the data that you would want to display on the CTC starts, which in almost all cases for this particular Speakercraft product, is (7) individual pieces of information separated by NUL's.

    It's not so much a problem to get to and start reading from the 43rd byte:
    Code:
    WriteSerial(1, #$55#$09#$90#$31#$00#$00#$00#$00#$01#$E0);
        delay(0.2); {maybe this needs to be extended???}
        ReadSerial(1, iPodMenuStringFull, '');
        TextPos(10, 10); {This is for testing, remove before final}
        DrawText(iPodMenuStringFull); {This is for testing, remove before final}
        Copy (iPodMenuString2, iPodMenuStringFull, 43, 50);
        TextPos(80, 80);
        DrawText(iPodMenuString2);
    The problems are a many, but to start with, the fact that a string variable in the logic engine is (50) characters, although I think I found a way around that by (but unable to test at the moment):
    Code:
    iPodMenuStringFull : array[0..200] of char;
    The next problem, assuming that solves my string length problem is how exactly to parse all pieces of the information between NUL's. Again, I've got a few ideas, but I haven't been able to test them yet so I may come back to that one.

    And the next Major problem is the fact that this device sends out a status update every 2 seconds and there's no embedded way in their system to turn that off or reduce the frequency on that. The problem is that if your timing on the request string happens to be right before one of those 2 second marks, your readserial procedure gets filled up with a bunch of 'garbage' (and that garbage has a whole slew of \x00's in there). I think XRMichael may have been onto something good for avoiding this problem, but because I'm not in front of the equipment right now, I don't know if the status messages and the requested messages have the same starting sequences or if there's a way to tell them apart from each other.
     
    Wire_Bug, May 6, 2009
    #8
  9. xrmichael

    xrmichael

    Joined:
    Nov 20, 2006
    Messages:
    93
    Likes Received:
    0
    Location:
    uk
    Mzc - cbus

    I did get it working but removed the Ctouch shortly after and put in a AMX panel, i have the code i am using in the AMX you should be able to work it back to Pascal, i did a Pronto Module to take the ipod info from the dock that may help (it ran very slow though) drop me a PM if you want it.
     
    xrmichael, May 6, 2009
    #9
  10. xrmichael

    xrmichael

    Joined:
    Nov 20, 2006
    Messages:
    93
    Likes Received:
    0
    Location:
    uk
    Mzc

    Also don't request a menu status from the MZC it will send 1 every 2secs anyway, and will also send another after every menu up/down, and also if a user alter anything on the mode, so asking for the menu was not needed in my system.
     
    xrmichael, May 6, 2009
    #10
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.