Shop OBEX P1 Docs P2 Docs Learn Events
How do you send ( And receive ) LONGS via FullDuplexSerial? — Parallax Forums

How do you send ( And receive ) LONGS via FullDuplexSerial?

DavidMDavidM Posts: 630
edited 2011-02-27 17:02 in Propeller 1
HI

Using FullDuplexSerial, I need to send ( and Receive) a LONG as 4 BYTES ( to keep my "Packet" Compact as possible).

but I don't believe this can be done because there is no "clean" Way to specify the end of the data as The default delimiter in Serial is a comma ",".

Having said that, any of my individual "byte values" could be that of the delimiter, which would confuse the reading of the values at the receiving end?

Also, What happens if my long value is zero , I would then be sending 4 bytes of zero! All of these are string terminating values.

The only thing I can see is to send each byte of the 4 bytes ( of the LONG) as 4 Hex values, Which I believe are really 8 bytes ( 2 bytes for each hex value) + a delimiter character, which will make 9 bytes overall.

What I can see sending everything as HEX is that the PACKETS will always be DOUBLE the amount of bytes really needed.

How can this be done?


Thanks
Dave

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2011-02-26 20:33
    DavidM wrote: »
    Also, What happens if my long value is zero , I would then be sending 4 bytes of zero! All of these are string terminating values.
    Why is this an issue? For practical purposes the receiver only receives bytes. It doesn't attach a meaning to it. So 4x zero is 4x zero or rather 4 bytes I don't want to know the meaning of. If some parser on top of that byte layer has a different idea then maybe you should use raw access. Just thinking aloud here ...
    DavidM wrote: »
    How can this be done?
    If you want to avoid special characters, what about encoding (e.g. UTF-8 which sends 1..6 bytes depending on your 32 bit value)? Of course sending it as hex string counts as encoding as well. Up to you really.

    As for sending a raw long:
    repeat 4
      serial.tx(value)
      value ->= 8
    
    ' or
    
    repeat n from 0 to 3
      serial.tx(value.byte[n])
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-02-26 20:43
    The way I do this, in those rare cases where hex is too wordy, is to designate an escape character. My usual choice is DLE ($10), but any character will work. The escape character signals that the character following it has special meaning. In your case, for example, you could designate, $10 $ff to be a substitute for $00. In any event, the way to send the escape character as data is simply to double it. So, to send DLE as data under my method, you'd send DLE DLE. On the receiving end, any time a DLE is seen followed by another DLE, one DLE is simply buffered as data, and the other is discarded. A DLE followed by anything else will (or might not) have special significance.

    -Phil
  • DavidMDavidM Posts: 630
    edited 2011-02-26 20:48
    HI Kuroneko,

    Thanks for the reply, I can see what you are saying, My problem is that ( I am using this for RS485 ) my TRANSMITTING device ( MASTER )may send data faster than the receiving device ( SLAVE) can process it.

    for example I am wanting to BROADCAST TIMECODE. my time code is basically the time represented in milliseconds. I will be broadcasting as fast as I can by doing this in a cog with minimum overhead.

    I have a 128 byte buffer ( in my modified FullDuplex serial object), so how does my receiver know when one packet finishes and the other starts. If the receiver does not read every packet, there will be an overflow. Some how I need to receive a packet and if its not used, then discard it so that I only have the most current value in the buffer before it gets read. remember this is broadcasting so no addressing or return messages are required.

    On my receiving side , my MAIN LOOP code checks for data coming in ( this is about 10 cycles per second) and processes this, it then checks the timecode arrived with the timer in my system and adjusts according.


    Thanks

    Dave M
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-26 21:03
    Is the packet size constant? If so you could simply count the bytes and apply a timeout (you mentioned 10Hz) in case you missed one. OTOH you could utilise STX/ETX markers which indicated start and end of the message/package. idbruce's InterComm object uses a similar approach (not sure though how much is still available in the forum). The packet format was STX|string encoded payload|unit separator|CRC|ETX.

    In case the MASTER sends faster than 10 packets/sec (i.e. faster than you intend to read) then you need some form of marker to distinguish the packets or some layer at the bottom should only keep the last e.g. 4 bytes or something (whatever size the packet is). Don't really know much about the protocol involved.
  • DavidMDavidM Posts: 630
    edited 2011-02-26 21:54
    HI kurenko,

    Come to think of it my packet size will be different depending on the way my devices will be working.

    I basically have 2 modes.

    1) SETUP MODE, where each slave will be asked by the ONE Master unit, what its status is, This may include uploading data to the SLAVE, Getting other data back from the slave to the master etc.

    2) SYNCHRONISING TIMECLOCKS across all slaves to match the master time clock, If possible I need this to be accurate to 1 millisecond. This process MAY take place on a one by one slave basis, or using BROADCAST TIMECODE each slave can SYNC themselves ( somehow).

    So The first PROCESS, involves one to one, and each PACKET may be different in length, but the advantage here is that the TIME of processing is not crucial to operations. So If I need to send any LONGS I can just transmit all data as strings as this may be complicated.

    2) At the end of the day, I need to synchronise all slaves to a millisecond clock ( to the master clock) , Do I need to broadcast at millisecond intervals to achieve this or could I broadcast at say 10hz? and the slave clock can work out what to do, if this is the case, then i can send the time code as HEX values. AND I then need to make sure that the transmitted data is read in a timely manner.


    I am thinking though, that I need to specify the PACKET LENGTH as suggested by you in another post of mine,


    Thanks

    Dave M
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-26 22:02
    DavidM wrote: »
    2) At the end of the day, I need to synchronise all slaves to a millisecond clock ( to the master clock) , Do I need to broadcast at millisecond intervals to achieve this or could I broadcast at say 10hz? and the slave clock can work out what to do, if this is the case, then i can send the time code as HEX values. AND I then need to make sure that the transmitted data is read in a timely manner.
    If the internal clock is stable enough I'd say even every 10sec or 1min should be fine. The problem I can see though is time spend in the receive buffer. Meaning the MASTER sends the timestamp reasonably accurate, it arrives packet time later at the receiver. If you don't act immediately on this it becomes worthless. That said, you could apply an incoming timestamp (e.g. cnt) and adjust accordingly once you come round to read it.
  • DavidMDavidM Posts: 630
    edited 2011-02-26 22:25
    HI kuroneko,

    thats a good idea, I could offset the value if I know the time it takes to receive and process the time data, and ASSUMING that processing time is consistent.

    But Also,

    I just did a simple test to send master time as STRING VALUE of a long, The number gets to the slave ok, But if my MASTER device is sending data FASTER than my SLAVE can read it, It gets all mucked up.

    So I need to .

    1) Make sure that the SLAVE device can read FASTER than the MASTER device ( slow down the intervals of the master), OR
    2) Somehow I need to clear the buffer FLUSH it, if its not used, I guess this receiving data routine needs to work in its own cog, which should solve both issues,

    thanks
    Dave M
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-26 22:34
    You could also force the MASTER to slow down, i.e. let it wait for an acknowledge from the slave (I know it's not an option with broadcast stuff). Otherwise, I'd go for a faster slave, e.g. if the data handler is done in PASM you can get more done while a new character is incoming (115200 baud -> 964 cycles per bit @80MHz -> nearly 10k cycles per character/byte). I'm sure you work something out.
  • DavidMDavidM Posts: 630
    edited 2011-02-26 23:00
    Hi kuroneko

    regarding a Faster Slave, This would be the best option, Its a shame that the whole serial object has a lot of SPIN code to manipulate the data, If this could be converted to PASM so its all in one , this would make it faster I wonder how much IDLE time the ASM cog has?.

    The issue of the receiver being slower than the transmitter has me worried, I believe I have had strange issues with other programs because of corrupt data, form ( overflowed buffers?? )

    I generally transmit and receive from my MAIN LOOP, which is about 10 HZ, Need to make better use of cogs!
    This curent project is using 7 cogs already,


    Can you tell me..

    Q1) What happens if the RX Buffer is Full and another message is sent to it?

    Q2) There is a FLUSH BUFFER command, Could this be used to clear the BUFFER , if a previous message has not been read?, and I guess that it should store only one message at a at a time.

    thanks

    Dave M
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-26 23:09
    DavidM wrote: »
    Q1) What happens if the RX Buffer is Full and another message is sent to it?
    From the looks of it it trashes the existing buffer, i.e. there is no buffer-full check.
    DavidM wrote: »
    Q2) There is a FLUSH BUFFER command, Could this be used to clear the BUFFER , if a previous message has not been read?
    You mean rxflush? Yes.
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2011-02-26 23:29
    If both ends of the RS485 are custom, i.e. Propeller driven, then driving the differential RS485 signal from the Server (Master) in open-drain and its complementary open-source would allow the Client(s) (Slave) to hold the respective state until the Client(s) was(were) ready to receive more data from the Server. This way the Server looks at the RS485 line to determine if it can send or not.
  • DavidMDavidM Posts: 630
    edited 2011-02-26 23:50
    HI Beau,

    I think I understand what you are saying, So because I am in "BROADCAST" Mode the MASTER should not try to send any data if ANY of the SLAVES are READING Data, Each slave has a 100 ms time out in reading, but they will try to read even if there is not data, and if I have many slaves, I doubt they there would be e time that is completely void of reads, But are you suggesting this could all be synchronised (readings) some how?


    My SLAVEs are PERIODICALLY READING, i.e I pull the RE line LOW to enable the receiver ( I am using the MAX3535ECWI Chip)!, How can the MASTER check this?

    I have already built my circuit!

    regards

    Dave M
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2011-02-27 08:18
    DaveM,

    It would need to be a situation where you have a Propeller on both ends and the Propeller's themselves would be generating/receiving the differential signal, not the MAX3535ECW.

    My suggestion was a means for the Server to detect if there were any Clients lagging without necessarily the need for the Clients to broadcast. .... basically the Clients listen, and when they receive something, they hold the line until they have finished processing what they have received... This in effect throttles the Server, preventing data from being missed. At best in a scenario that there is no throttling, the Clients might receive data from the Server on every other transmission.
  • DavidMDavidM Posts: 630
    edited 2011-02-27 15:10
    kuroneko wrote: »
    From the looks of it it trashes the existing buffer, i.e. there is no buffer-full check.
    .

    HI kuroneko,

    hmmm, If the buffer gets wiped when its full then how about this idea....

    I modify the PASM code to make a specific sized buffer, Say 16 bytes, ( which is original size, but mine is currently 128 bytes )

    And then I need to make sure that all my BROADCAST Messages are exactly 16 bytes, That way if a message is NOT READ, its is completely replaced by a new message, therefore there will be only one complete message in the buffer at a time.

    which bring me to my next question..

    What happens if I am reading the buffer, and a new message comes in DURING this time? Does this happen? or is there some kind of lock?


    What Do you think?

    Thanks

    Dave M
  • kuronekokuroneko Posts: 3,623
    edited 2011-02-27 17:02
    DavidM wrote: »
    What happens if I am reading the buffer, and a new message comes in DURING this time? Does this happen? or is there some kind of lock?
    You most likely get corrupted data unless you can stay just ahead of the changes (circular buffer). And yes it will happen if you don't read fast enough. One could argue that the receiver should not touch the buffer if it's full but as there is no handshake you'd lose the incoming character (MASTER keeps sending into a full buffer).
Sign In or Register to comment.