DEMO: High Speed Multi-Prop to Prop Communication

I should have released this sooner... the "Saturday robotics club" that I participate in has a project going on where this is a perfect fit, and after cleaning it up a bit I thought I would pass it along.


Here is a derivative of the high speed 8.42 Meg Baud (1.05 Million Bytes per second) Prop-to-Prop communication that I wrote some time ago. Last March there were several changes to the front end of both the Receiver and the Transmitter in the way that the handshaking took place. Before you had to make sure that the Receiver was up and running before you Transmitted... this is no longer the case, now it doesn't matter making it more user friendly.

For just the average user, it's pretty straight forward... there is only one command to Send, and there is only one command to Receive.

Basic Use:
To receive, just specify the pin you want to listen on and the address of where you want the received data to go to. Remember, this transmission is designed to send large packets of data, so if your just sending a few bytes here and there, this object is probably not for you.

RX(_Pin,_DataAddress)

To Transmit, is basically the same thing with a few more parameters... you specify the pin you want to yell on, the address of where the data is coming from, How much data you want to send in longs.

TX(_Pin,_DataSamples,_DataAddress,_%0000, 0)

Note: the last two fields are not used in the Basic setup, they will be discussed in Advanced Use.

So that's it for basic use.

Advanced Use:

The Receive is just the same as before, but it can be used as a function to return additional. information from the Server.

Command := RX(_Pin,_DataAddress)

This will receive data just as before and place it in the assigned address, but Command contains the size of the transmitted packet, a destination offset, and a Packet Command. Organized as such...

%ssssssssssssss_aaaaaaaaaaaaaa_cccc

where:
s = 14-Bit Packet Size
a = 14-Bit Destination Offset
c = 4 Bit Command

The Packet Size is obviously useful for determining how much data you received and allows support for variable width packets.

The Destination Offset is unique in the sense that the Server has some control as to where the Data will end up on the receiver. Basically this value gets added to the DataAddress that you specify on the receiver so that the incoming data is written to a location starting at the DataAddress plus the Offset. This feature allows random block writes from the Server to the Client.

The 4-Bit Command is just a way for the server to pass a specific command to the receiver. It can be used for anything you want. It's up to you.

For Transmission, it's just the same as the Basic Transmission as well, except the two parameters that were Zero'd out now have some meaning.

TX(_Pin,_DataSamples,_DataAddress,_DataCommand,_Offset)

DataCommand as just mentioned is a 4-bit command you can pass directly to the Client and can be used for anything you want.

The Offset, also just mentioned, can be used to tell the receiver to write data to another location.
This is useful when you only want to update a block or section of memory on the Client.

Finally with the Demo programs supplied, shows a round-robin approach to sending data across multiple Propellers.

The Idea is that you have one buffer that every Propeller sends around the loop ... "infinitely"
To prevent collisions, ALL Propellers have access to reading the entire buffer, however, and this is what makes it work. Each Propeller can only write to a specific assigned location of that buffer. <- This isn't exactly true, but it's a good programming practice to implement. There aren't any collisions for similar reasons that you don't have collisions from COG to COG on a single Propeller.

When a Propeller reads the Buffer, he is only allowed to write to the section that he is assigned to before sending the Buffer on to the next Propeller. (Note the Demo Code has this restriction lifted and can write to any location on the Buffer... But in my description, that's how you would typically manage the data across multiple Propellers and avoid collision. It works in the Demo, because there is only one Propeller writing to the buffer)

In the Ring, you can have as many Propellers as you want, with each Propeller only having a 3-wire interface... (Ground, TX, and RX) ... I have tested up to 5 Propellers with the supplied demo code.

One Propeller must be identified as the Server to initiate the data ring, but all of the other Propellers are identified as Clients.

Within each Propeller regardless of Server or Client ALL Propellers have equal access to the Data Buffer.


I Hope this makes sense... Enjoy!!

EDIT: added a slightly newer version that addresses detection of the USB plugged into the PC. This prevents unwanted resets.

EDIT: Check this link out for a way to control switches across multiple Propellers, i.e. for lighting
"Irony hides in the deception of your current view of the situation" - Me ....
In other words, do not believe what you are told and what you immediately perceive until you find out the absolute truth for yourself from all possible angles.

www.Kit-Start.com
bschwabe@Kit-Start.com

www.BScircuitDesigns.com
icbeau@bscircuitdesigns.com
Tagged:
«1

Comments

  • 31 Comments sorted by Votes Date Added
  • edited September 2011 Posts: 0Vote Up0Vote Down
    Beau,

    Cool!

    Any idea how far separated the props can be from adjacent Props?

    And do you mean there is no upper limit as to the number of Props?
    Harley Shanko
  • edited September 2011 Posts: 5,995Vote Up0Vote Down
    "Any idea how far separated the props can be from adjacent Props?" - I did some crude testing under poor conditions on purpose, using about 10 feet of unshielded speaker wire.... After 100's of billions of Bits that were transferred there were Zero Packet losses. I used Pseudo random data, as well as pattern testing.

    "And do you mean there is no upper limit as to the number of Props? " - within reason to the amount of speed that your willing to sacrifice. The data transmits at just over 1 Million Bytes per second. Propagation delay on per Propeller basis "IF" a Propeller needs to write to the buffer will contribute to that propagation delay.
    "Irony hides in the deception of your current view of the situation" - Me ....
    In other words, do not believe what you are told and what you immediately perceive until you find out the absolute truth for yourself from all possible angles.

    www.Kit-Start.com
    bschwabe@Kit-Start.com

    www.BScircuitDesigns.com
    icbeau@bscircuitdesigns.com
  • edited September 2011 Posts: 0Vote Up0Vote Down
    Nice work Beau. Thankyou. Seems to be just what the doctor ordered (No not Drac).

    Once I get a few of my miniature prop pcbs built I should be able to give this a workout :) I am sure jazzed could too.
    My Prop boards: CpuBlade, TriBlade, RamBlade, www.clusos.com
    Prop Tools (Index)
    Emulators (Index) ZiCog (Z80)
    Prop OS (also see Sphinx, PropDos, PropCmd)
  • edited September 2011 Posts: 0Vote Up0Vote Down
    Seems to be just what the doctor ordered (No not Drac).

    Oh, but it is! This is going to be perfect for talking to the 256x224 full color video propeller. 8 megbaud is fast enough to run video at that resolution. Sweet. Thanks Beau!
    Answers: 1) A quadcopter. 2) Very high. 3) The internet. 4) A lot. 5) No.
  • edited November 2011 Posts: 0Vote Up0Vote Down
    How did I miss this!? Great work Beau. I'll give it a whirl soon as I can - thanks :)
    Cheers,
    Simon
  • edited December 2011 Posts: 0Vote Up0Vote Down
    For my next project I am thinking about using this to communicate when a different microcontroller that is 5v...the 5v microcontroller would be the server...what resistors values should I use....the write up show 100ohms on the tx with 330 going to ground on both the TX and RX...

    Thanks
  • edited December 2011 Posts: 5,995Vote Up0Vote Down
    dr hydra,

    The 330 Ohm resistors form a transmission line between One Propeller and another Propeller and should be of equal value for proper matching on both ends. This Transmission line helps to reduce any external RF interference that could enter the line due to antenna effects.

    The 100 Ohm resistor is there for protection in a situation where both the Server and Client could potentially drive the line in disagreement.

    That said, you need to treat both of the 330 Ohm resistors as if they are in parallel with each other... so the circuit now becomes a voltage divider between the 100 Ohms protection resistor and 165 Ohms (1/2 of 330 Ohms). Using a 100 Ohm resistor is about as high as you can go and still have a signal on the receivers side that is above the voltage threshold of the I/O.


    ...So using 3.3V on the TX side, the receiving voltage level should be about 2.05V ... using 5V on the TX side, the receiving voltage level should be about 3.12V

    In which case, the 3V logic should be ok ... the question is, is 2.05V enough for the 5V logic to determine a logic "1"



    The biggest problem I see will be getting the timing just right with your 5V micro processor. The timing needs to be within 25ns to 50ns or it won't work correctly.
    "Irony hides in the deception of your current view of the situation" - Me ....
    In other words, do not believe what you are told and what you immediately perceive until you find out the absolute truth for yourself from all possible angles.

    www.Kit-Start.com
    bschwabe@Kit-Start.com

    www.BScircuitDesigns.com
    icbeau@bscircuitdesigns.com
  • edited December 2011 Posts: 0Vote Up0Vote Down
    If the 2 Props are about 1cm apart, may I know will 1 x 330ohm for each Rx & Tx line be sufficient instead of 2?
  • edited December 2011 Posts: 5,995Vote Up0Vote Down
    If the Propellers are that close, then yes, you could use one resistor, and the value of 330 is fine as well.

    I'm confused though, I thought you were wanting to communicate using the same high speed protocol with a 5V micro?
    "Irony hides in the deception of your current view of the situation" - Me ....
    In other words, do not believe what you are told and what you immediately perceive until you find out the absolute truth for yourself from all possible angles.

    www.Kit-Start.com
    bschwabe@Kit-Start.com

    www.BScircuitDesigns.com
    icbeau@bscircuitdesigns.com
  • edited December 2011 Posts: 0Vote Up0Vote Down
    Thanks Beau.

    Erm, its dr hydra working with 5v. I doing a dual-prop design.
  • edited December 2011 Posts: 0Vote Up0Vote Down
    Nice work Beau.
    This will work prefect for me as well.
    William Stefan
    The Basic Stamp Nut with some Spin
  • edited December 2011 Posts: 0Vote Up0Vote Down
    Beau,

    I have another idea, what do you think?

    Add an "assert" that is pulled high by an external resistor, then assert low before transmitting a message. The prop does a listen for assert, then pulls it low, then transmits a packet with a source and destination ID, then lets go of assert. This is a more rudimentary method if CSMA/CD and gives you more payload space in the packet. It also avoids the token ring effect.

    I'm sure there are some clever ways of reducing the instruction count so that collisions are very unlikely.

    If you get rid of the wire count limitation, do an I2C like data, clock, and select. You pull select low, then wait for the same number of clocks as it took to do the check and set for select, then check that the clock isn't low, then bring the clock low to signal the begin of transmission. Doing the select, then waiting, then bringing clock low would ensure a foolproof protocol for collision avoidance.

    Then you just put multiple props on a bus and just run a simple wait loop to receive all the time, or break in to send.
  • edited October 2012 Posts: 0Vote Up0Vote Down
    I love this code.

    I am using it to run a common memory buffer between 3 props. 24 core processing with 1K shared RAM.

    Is there a way to pack it into one cog? Right now I dedicate a cog to write my process variables into out of the shared memory plus the HS_Rx and HS_Tx cog. That takes up 25% of my oompf.

    If the user modifying memory code could reside in one cog along with the Tx and Rx methods that would be great. Right now my 3 props are indeed maxed out.

    sm
  • edited October 2012 Posts: 5,995Vote Up0Vote Down
    Glad you like the code, it was fun to write once it came alive :-)

    Because of speed requirements, the code needs to have it's own cog, but the cog only gets launched when you call the command. After the request is done it should release the cog. Perhaps the duty requirements can be shared with another cog that doesn't need to continuously run as well.
    "Irony hides in the deception of your current view of the situation" - Me ....
    In other words, do not believe what you are told and what you immediately perceive until you find out the absolute truth for yourself from all possible angles.

    www.Kit-Start.com
    bschwabe@Kit-Start.com

    www.BScircuitDesigns.com
    icbeau@bscircuitdesigns.com
  • edited October 2012 Posts: 0Vote Up0Vote Down
    I was wondering if the Rx and Tx code sections could be loaded into one PASM cog, called alternately from within, with a small section to transfer user defined registers into the transfer buffer in between calls to Rx and Tx. It would require each client to be custom configured
  • edited February 2013 Posts: 0Vote Up0Vote Down
    Hey everyone, I'm sure that this is a very simple question, but I'm a bit stumped. I've been able to connect my two props and the demo is working perfectly, but what I'd like to be able to do is be able to have the server send values from variables, not a data block. What I'm trying to do is have one propeller that is monitoring a number of sensors (~10) and sending the data back to the other propeller. I'm using v2 from above. I think that I should be able to modify this "bytemove(@Buffer,@TestMessage,strsize(@TestMessage))" section of the code and replace the "@TestMessage" with my variable in the server side, but no luck. Any suggestions or ideas would be great! Thanks!

    Dave
    My wife is very, very understanding

    Prospero: Robot Farmer
    http://www.youtube.com/watch?v=ACtihXjq2B0
    www.DorhoutRD.com
  • edited February 2013 Posts: 0Vote Up0Vote Down
    The only difference between variables and a data block is a matter of semantics and location. If you define variables all of the same type (byte / word / long) and define them in order (as VARs), they will in fact become a data block (a contiguous series of bytes / words / longs in memory and can be manipulated by having the address of the first location and the length of the block. If the variables can't be all of the same type and/or can't be contiguous, then you'll have to move them to or from an area where that's true.

    Another thing you can do is define a DAT block and put your variables in there ... aligned properly. Like this:
    DAT
    firstByte  BYTE  0
    padding1 BYTE  0
    firstWord WORD 0
    padding2 WORD 0
    firstLong LONG 0
    
    This is just to illustrate padding when a BYTE is followed by a WORD or LONG or a WORD is followed by a LONG. If you have a LONG first, you don't need padding for WORDs or BYTEs and if you have a WORD first, you don't need padding for BYTEs. These variables can be used in Spin just like a VAR. Here an initial value has to be specified and, if you're making an object that will be defined multiple times in your program, there will be only one DAT for that object ... not one copy per object reference as with VARs.
  • edited February 2013 Posts: 0Vote Up0Vote Down
    Hi Mike,

    Thanks for the info. I've been giving it a try and I'm still not able to get it to work.

    On the Client side I've just changed the last line PST.str(@buffer) to PST.dec(@Buffer)

    On the Server side I've made a couple of changes.

    The result is that I see "2308" in the terminal window, regardless of what I set the variable "SensorData" as. Any suggestions?

    Thanks!



    Client:

    VAR

    long Buffer[1024],Stack[400]

    OBJ
    hsRX : "HSp2pRX" 'High Speed Receive driver
    hsTX : "HSp2pTX" 'High Speed Transmit driver
    PST : "Parallax Serial Terminal" 'RS232 Serial Driver

    PUB start|debugLED
    '
    if ina[USB_Rx] == 0 '' Check to see if USB port is powered
    outa[USB_Tx] := 0 '' Force Propeller Tx line LOW if USB not connected
    else
    cognew(SerialDisplay,@Stack) '' Initialize serial communication to the PC

    '
    dira[23..16]~~ '<- I/O direction for debug LEDs
    '
    repeat
    hsRX.RX(RX_Pin,@Buffer) '<- Receive Data from External Propeller
    hsTX.TX(TX_Pin,1024,@Buffer,Command,Offset) '<- Transmit Data to External Propeller

    '
    debugLED++ '<- debug LED section
    if debugLED > 60
    outa[23..16] := $FF - outa[23..16]
    debugLED := 0
    '
    PUB SerialDisplay 'DEBUG ONLY
    PST.Start(19200)
    repeat
    PST.HOME
    PST.dec(@Buffer) '<- Display Data







    Server side:




    long Buffer[1024]

    long SensorData

    Con



    OBJ
    hsRX : "HSp2pRX" 'High Speed Receive driver
    hsTX : "HSp2pTX" 'High Speed Transmit driver


    PUB start|debugLED


    SensorData := 12345

    longmove(@Buffer,SensorData,1) '<- Moves TestMessage into Buffer

    dira[23..16]~~

    repeat
    hsTX.TX(TX_Pin,1024,@Buffer,Command,Offset) '<- Transmit Data to External Propeller
    hsRX.RX(RX_Pin,@Buffer) '<- Receive Data from External Propeller

    debugLED++
    if debugLED > 60
    outa[23..16] := $FF - outa[23..16]
    debugLED := 0



    'Dat

    'SensorData long 0
    My wife is very, very understanding

    Prospero: Robot Farmer
    http://www.youtube.com/watch?v=ACtihXjq2B0
    www.DorhoutRD.com
  • edited February 2013 Posts: 0Vote Up0Vote Down
    You really have to use the [ code ] and [ /code ] tags when posting code, particularly Spin code. See this:
    attachment.php?attachmentid=78421&d=1297987572
  • edited February 2013 Posts: 0Vote Up0Vote Down
    Thanks, I was looking for how to do that.


    Client side:
    VAR
    
    long    Buffer[1024],Stack[400]
                                      
    OBJ
      hsRX   : "HSp2pRX"                       'High Speed Receive driver
      hsTX   : "HSp2pTX"                       'High Speed Transmit driver
      PST    : "Parallax Serial Terminal"      'RS232 Serial Driver              
      
    PUB start|debugLED
    '-------------------------------------------------------------------------------------------
         if ina[USB_Rx] == 0        '' Check to see if USB port is powered
            outa[USB_Tx] := 0       '' Force Propeller Tx line LOW if USB not connected
         else
            cognew(SerialDisplay,@Stack)    '' Initialize serial communication to the PC
    
    '-------------------------------------------------------------------------------------------                                                        
        dira[23..16]~~                                      '<- I/O direction for debug LEDs
    '-------------------------------------------------------------------------------------------     
        repeat
          hsRX.RX(RX_Pin,@Buffer)                           '<- Receive Data from External Propeller
          hsTX.TX(TX_Pin,1024,@Buffer,Command,Offset)       '<- Transmit Data to External Propeller
    
    '-------------------------------------------------------------------------------------------
          debugLED++                                        '<- debug LED section
          if debugLED > 60
             outa[23..16] := $FF - outa[23..16]
             debugLED := 0
    '-------------------------------------------------------------------------------------------      
    PUB SerialDisplay               'DEBUG ONLY
        PST.Start(19200)
        repeat
          PST.HOME
          PST.dec(@Buffer)                                  '<- Display Data
    

    Server side:
    VAR
    
    long    Buffer[1024]  
    
    long    SensorData
    
    Con
    
    
    
    OBJ
      hsRX   : "HSp2pRX"                       'High Speed Receive driver
      hsTX   : "HSp2pTX"                       'High Speed Transmit driver
    
      
    PUB start|debugLED
    
    
    SensorData :=  12345
    
        longmove(@Buffer,SensorData,1) '<- Moves TestMessage into Buffer
    
        dira[23..16]~~
    
        repeat
          hsTX.TX(TX_Pin,1024,@Buffer,Command,Offset)       '<- Transmit Data to External Propeller
          hsRX.RX(RX_Pin,@Buffer)                           '<- Receive Data from External Propeller
          
          debugLED++
          if debugLED > 60
             outa[23..16] := $FF - outa[23..16]
             debugLED := 0
          
                
    
    'Dat
    
    'SensorData   long 0
    
    My wife is very, very understanding

    Prospero: Robot Farmer
    http://www.youtube.com/watch?v=ACtihXjq2B0
    www.DorhoutRD.com
  • edited February 2013 Posts: 5,995Vote Up0Vote Down
    Just place your sensor variables in front of the Buffer array and instead of pointing to @Buffer ... point to @SensorData instead. Keep the same order with your longs between Prop Client and PropServer and the /same/ variables on the other Clients will contain the same value. The Clients can also change a variable the same way, by just setting it equal to something locally. The change will propagate to the other Propellers.
    {{
    ***************************************
    *  HighSpeed Client        DEMO v1.0a *
    *  Author: Beau Schwabe               *
    *  Copyright (c) 2011 Parallax, Inc.  *               
    *  See end of file for terms of use.  *               
    ***************************************
    
    Revision History:
      Version 1.0   - (09/20/2011) initial release
      Version 1.0a  - (09/26/2011) minor change to detect When the USB plug is connected
                                   to the PC.  This prevents unwanted resets.
    Client:
    }}
    CON
      ' Set up the processor clock in the standard way for 80MHz on DemoBoard
      _CLKMODE      = xtal1 + pll16x
      _XINFREQ      = 5_000_000 + 0000
    
        RX_Pin       = 1
        TX_Pin       = 0
        Command      = %0000  '' Feature not used in this demo
        Offset       = 0      '' Feature not used in this demo
    
        USB_Rx       = 31
        USB_Tx       = 30
    
    {{
    
    Round Robin configuration using 2 Propellers:
    
       &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;//&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
       &#9474; &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;               &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;    &#9474;
       &#9474; &#9474;   Propeller 1   &#9474;               &#9474;   Propeller 2   &#9474;    &#9474;
       &#9507;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9523;&#9472;&#9472;&#9472;//&#9472;&#9472;&#9472;&#9523;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9515;
       &#61628; &#9474;     Client      &#9474;    &#61628;        &#61628; &#9474;     Server      &#9474;    &#61628;
       &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;        &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;
      Vss                      Vss      Vss                      Vss
           
    
    Round Robin configuration using 3 or more Propellers:
    
       &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
       &#9474; &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;                  &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;                  &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;    &#9474;
       &#9474; &#9474;   Propeller 2   &#9474;                  &#9474;   Propeller N   &#9474;                  &#9474;   Propeller 1   &#9474;    &#9474;
       &#9507;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9523;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9523;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9523;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9523;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9515;
       &#61628; &#9474;     Client      &#9474;    &#61628;           &#61628; &#9474;     Client      &#9474;    &#61628;           &#61628; &#9474;     Server      &#9474;    &#61628;
       &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;           &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;           &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;
      Vss                      Vss         Vss                      Vss         Vss                      Vss
    
    
    
    Note: All resistors tied to Vss are 330 Ohm and are there to establish a transmission line
    Note: All resistors between TX and RX are 100 Ohm and are there to current limit the I/O's in the chance
          of a collision.
    
    
    With round robin, the idea is that you have one buffer that propagated around and around inside the
    round robin loop.  To avoid any data collisions, all Propellers are capable of reading any location
    within the buffer, however each Propeller has a specific (assigned by the programmer) location that
    it can write to.
    
    So in the Demo, there is a 1K long buffer (4K bytes).  As an example Propeller 1 may only write to
    locations 0 to 255.  While Propeller 2 can write to locations 256 to 511.  Propellers 3 & 4 depicted
    as N because of the expandable nature of round robin would write to the remaining 512 to 1023 locations.
     
    
    }}
    VAR
    
    long    SensorData, Buffer[1024],Stack[400]
                                      
    OBJ
      hsRX   : "HSp2pRX"                       'High Speed Receive driver
      hsTX   : "HSp2pTX"                       'High Speed Transmit driver
      PST    : "Parallax Serial Terminal"      'RS232 Serial Driver              
      
    PUB start|debugLED
    '-------------------------------------------------------------------------------------------
         if ina[USB_Rx] == 0        '' Check to see if USB port is powered
            outa[USB_Tx] := 0       '' Force Propeller Tx line LOW if USB not connected
         else
            cognew(SerialDisplay,@Stack)    '' Initialize serial communication to the PC
    
    '-------------------------------------------------------------------------------------------                                                        
        dira[23..16]~~                                      '<- I/O direction for debug LEDs
    '-------------------------------------------------------------------------------------------     
        repeat
          'hsRX.RX(RX_Pin,@Buffer)                           '<- Receive Data from External Propeller
          'hsTX.TX(TX_Pin,1024,@Buffer,Command,Offset)       '<- Transmit Data to External Propeller
    
          hsRX.RX(RX_Pin,@SensorData)                        '<- Receive Data from External Propeller
          hsTX.TX(TX_Pin,1024,@SensorData,Command,Offset)    '<- Transmit Data to External Propeller
    
          'Note: point to SensorData as the first Buffer location.
          '      this eliminates the need for a longmove with SensorData.
    
    
    '-------------------------------------------------------------------------------------------
          debugLED++                                        '<- debug LED section
          if debugLED > 60
             outa[23..16] := $FF - outa[23..16]
             debugLED := 0
    '-------------------------------------------------------------------------------------------      
    PUB SerialDisplay               'DEBUG ONLY
        PST.Start(19200)
        repeat
          PST.HOME
          PST.Dec(SensorData)                                  '<- Display Data
    
    CON
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                     TERMS OF USE: MIT License                                     &#9474;                                                            
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and  &#9474;
    &#9474;associated documentation files (the "Software"), to deal in the Software without restriction,      &#9474;
    &#9474;including without limitation the rights to use, copy, modify, merge, publish, distribute,          &#9474;
    &#9474;sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is      &#9474;
    &#9474;furnished to do so, subject to the following conditions:                                           &#9474;
    &#9474;                                                                                                   &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or           &#9474;
    &#9474; substantial portions of the Software.                                                             &#9474;
    &#9474;                                                                                                   &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT  &#9474;
    &#9474;NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND             &#9474;
    &#9474;NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,       &#9474;
    &#9474;DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,                   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE        &#9474;
    &#9474;SOFTWARE.                                                                                          &#9474;     
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}    
    

    Server:
    {{
    ***************************************
    *  HighSpeed Server         DEMO v1.0 *
    *  Author: Beau Schwabe               *
    *  Copyright (c) 2011 Parallax, Inc.  *               
    *  See end of file for terms of use.  *               
    ***************************************
    
    Revision History:
      Version 1.0   - (09/20/2011) initial release
    
    
    }}
    CON
      ' Set up the processor clock in the standard way for 80MHz on DemoBoard
      _CLKMODE      = xtal1 + pll16x
      _XINFREQ      = 5_000_000 + 0000
    
        RX_Pin       = 1
        TX_Pin       = 0
        Command      = %0000  '' Feature not used in this demo
        Offset       = 0      '' Feature not used in this demo
    
    
    {{
    
    Round Robin configuration using 2 Propellers:
    
       &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;//&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
       &#9474; &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;               &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;    &#9474;
       &#9474; &#9474;   Propeller 1   &#9474;               &#9474;   Propeller 2   &#9474;    &#9474;
       &#9507;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9523;&#9472;&#9472;&#9472;//&#9472;&#9472;&#9472;&#9523;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9515;
       &#61628; &#9474;     Client      &#9474;    &#61628;        &#61628; &#9474;     Server      &#9474;    &#61628;
       &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;        &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;
      Vss                      Vss      Vss                      Vss
           
    
    Round Robin configuration using 3 or more Propellers:
    
       &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
       &#9474; &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;                  &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;                  &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;    &#9474;
       &#9474; &#9474;   Propeller 2   &#9474;                  &#9474;   Propeller N   &#9474;                  &#9474;   Propeller 1   &#9474;    &#9474;
       &#9507;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9523;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9523;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9523;&#9472;&#9472;&#9472;/.../&#9472;&#9472;&#9472;&#9523;&#9472;&#9508;RX             TX&#9500;&#9472;&#61629;&#61630;&#9472;&#9515;
       &#61628; &#9474;     Client      &#9474;    &#61628;           &#61628; &#9474;     Client      &#9474;    &#61628;           &#61628; &#9474;     Server      &#9474;    &#61628;
       &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;           &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;           &#61464; &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;    &#61464;
      Vss                      Vss         Vss                      Vss         Vss                      Vss
    
    
    
    Note: All resistors tied to Vss are 330 Ohm and are there to establish a transmission line
    Note: All resistors between TX and RX are 100 Ohm and are there to current limit the I/O's in the chance
          of a collision.
    
    
    With round robin, the idea is that you have one buffer that propagated around and around inside the
    round robin loop.  To avoid any data collisions, all Propellers are capable of reading any location
    within the buffer, however each Propeller has a specific (assigned by the programmer) location that
    it can write to.
    
    So in the Demo, there is a 1K long buffer (4K bytes).  As an example Propeller 1 may only write to
    locations 0 to 255.  While Propeller 2 can write to locations 256 to 511.  Propellers 3 & 4 depicted
    as N because of the expandable nature of round robin would write to the remaining 512 to 1023 locations.
     
    
    }}
    VAR
    
    long    SensorData,Buffer[1024]
    
    OBJ
      hsRX   : "HSp2pRX"                       'High Speed Receive driver
      hsTX   : "HSp2pTX"                       'High Speed Transmit driver
    
      
    PUB start|debugLED
    
        SensorData := 12345 '<- Moves 12345 into SensorData
    
        dira[23..16]~~
    
        repeat
          'hsTX.TX(TX_Pin,1024,@Buffer,Command,Offset)       '<- Transmit Data to External Propeller
          'hsRX.RX(RX_Pin,@Buffer)                           '<- Receive Data from External Propeller
    
    
          hsTX.TX(TX_Pin,1024,@SensorData,Command,Offset)    '<- Transmit Data to External Propeller
          hsRX.RX(RX_Pin,@SensorData)                        '<- Receive Data from External Propeller
    
          'Note: point to SensorData as the first Buffer location.
          '      this eliminates the need for a longmove with SensorData.
    
          
          
          debugLED++
          if debugLED > 60
             outa[23..16] := $FF - outa[23..16]
             debugLED := 0
          
                
    
    CON
    {{
    &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    &#9474;                                     TERMS OF USE: MIT License                                     &#9474;                                                            
    &#9500;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9508;
    &#9474;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and  &#9474;
    &#9474;associated documentation files (the "Software"), to deal in the Software without restriction,      &#9474;
    &#9474;including without limitation the rights to use, copy, modify, merge, publish, distribute,          &#9474;
    &#9474;sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is      &#9474;
    &#9474;furnished to do so, subject to the following conditions:                                           &#9474;
    &#9474;                                                                                                   &#9474;
    &#9474;The above copyright notice and this permission notice shall be included in all copies or           &#9474;
    &#9474; substantial portions of the Software.                                                             &#9474;
    &#9474;                                                                                                   &#9474;
    &#9474;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT  &#9474;
    &#9474;NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND             &#9474;
    &#9474;NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,       &#9474;
    &#9474;DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,                   &#9474;
    &#9474;ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE        &#9474;
    &#9474;SOFTWARE.                                                                                          &#9474;     
    &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    }}
    
    "Irony hides in the deception of your current view of the situation" - Me ....
    In other words, do not believe what you are told and what you immediately perceive until you find out the absolute truth for yourself from all possible angles.

    www.Kit-Start.com
    bschwabe@Kit-Start.com

    www.BScircuitDesigns.com
    icbeau@bscircuitdesigns.com
  • edited February 2013 Posts: 0Vote Up0Vote Down
    Thanks!!! It's working for me now! This is so cool... You'll have to let me buy you a soda at Pops next time we're in OK. :)
    My wife is very, very understanding

    Prospero: Robot Farmer
    http://www.youtube.com/watch?v=ACtihXjq2B0
    www.DorhoutRD.com
  • edited May 2013 Posts: 0Vote Up0Vote Down
    Hi Beau and all you other Propeller Geeks :-)

    First of all, thanks for the code, it's great.

    Now, how would one implement some sort of error detection with Round Robin? What I mean is: if e.g. the connection between the 3rd and 4th Prop is broken, the buffer can't travel around anymore and the TX/RX routine is stuck and the calling routine is stuck, too. I was thinking of ABORT traps but don't want to mess with Beau's code.
    I was also thinking of starting a counter when calling the TX or RX routine, wait a few milliseconds and if it doesn't finish in that time assume that something went wrong. But how would I force the Prop to abort the routine that is stuck, give out an error message and then go on with the next commands?
    CON
      
      _CLKMODE      = xtal1 + pll16x   'Standard clock mode * crystal frequency = 80 MHz
      _XINFREQ      = 5_000_000
    
      NumberClients = 5
    
    ' Set up Ports
    '**************
      Start_P       = 17
      Switch_IP_FP  = 18
      Stop_P        = 10
      Dig_Out_P     = 9
      LED           = 2
      RX_Pin        = 1
      TX_Pin        = 0
      
      _dopin        = 8                          'SD DataOut (MISO)
      _clkpin       = 7                          'SD Clock
      _dipin        = 6                          'SD DataIn (MOSI) 
      _cspin        = 5                          'CipSelect  
      _cdpin        = -1                         '-1 if unused.
      _wppin        = -1                         '-1 if unused.
      _rtcclkpin    = 28                         '-1 if unused.
      _rtcdatpin    = 29                         '-1 if unused.
      _rtcbuslck    = -1                         '-1 if unused
    
    'Set up HSP2P Ring Buffer
    '************************
      Command      = 00        'tell the client what to do
      Offset       = 0            '0
      B_Size       = 12 + NumberClients*8   'Buffer Size in longs                      
    
    
    VAR
    
      long  Buffer[B_Size]                   
      byte  SD_Buffer[512] 
      long  SD_Stack[32]                    
      long  packet, com
      byte  flag, recordFlag, errorflag
      long  setYearTo, setMonthTo, setDateTo, setDayTo, setHoursTo, setMinutesTo, setSecondsTo
      
        
    OBJ
      hsRX  : "HSp2pRX"                       'High Speed Receive driver
      hsTX  : "HSp2pTX"                       'High Speed Transmit driver
      PST   : "Parallax Serial Terminal"      'RS232 Serial Driver
      loader: "PropellerLoader"
      fat   : "DS1307_SD-MMC_FATEngine.spin"   'µSD Card driver w/ DS1307 RTC
      rtc   : "DS1307_RTCEngine.spin"
    
    
    'Main Method
    '***********  
    PUB main | input, error, sensitivity
      
      ''Parallax Serial Terminal
      PST.Start(256000)
    
      ''Port directions; DON'T change!!!
      dira[Start_P]~~
      dira[Switch_IP_FP]~~
      dira[Stop_P]~~
      dira[Dig_Out_P]~~
      dira[LED]~~
    
      ''Port Output States
      outa[Switch_IP_FP]~  ''HIGH = FP (fixed) ; LOW = IP (infinite)
      outa[Stop_P]~~       'Stop = HIGH => LOW on SPG because of OC Transistor (inverting)
    
    
      ''Initialise some variables
      '**************************
      input := 0
    
      ''Start some drivers and new Cogs
      '********************************
      
      ' "rtcEngineStart" must be called first to setup and pins and lock number.
      rtc.rtcEngineStart(_rtcdatpin, _rtcclkpin, _rtcbuslck)
       
        
      ''Main loop
      '**********
      REPEAT
    
        pst.str(string("*** Main Menu ***   System Time: "))
        rtc.readTime
        pst.dec(rtc.clockHour)
        pst.char(":")
        pst.dec(rtc.clockMinute)
        pst.char(":")
        pst.dec(rtc.clockSecond)
        pst.newline     
        pst.str(string("1) Get mean value, one client",pst#NL)) '
        pst.str(string("2) Program all clients with binary",pst#NL))
        pst.str(string("3) Re-arm DigOut; one client",pst#NL))
        pst.str(string("4) Set new reference level; one client",pst#NL))
        pst.str(string("5) Start continuous recording; all clients",pst#NL))   
        pst.str(string("6) Serial File copy",pst#NL))
        pst.str(string("7) Start recording on Client SD; one client",pst#NL))
        pst.str(string("8) Stop recording on Client SD; one client",pst#NL))
        pst.str(string("9) List Files on microSD Card",pst#NL))  
        pst.str(string("10) Set 'Counts' for mean; one client",pst#NL))    
        pst.str(string("11) set 'delta' for DigOut; one client",pst#NL))
        pst.str(string("12) Firmware update",pst#NL))
        pst.str(string("13) Reset ErrorFlag",pst#NL))
        pst.str(string("14) Set System Time; important for File Time Stamps!",pst#NL))
       
        
        pst.str(string(":> "))
        input:=pst.decin                               ''wait for user input
    
    [B]    'make sure Round Robin is still working
        com := Buffer[0] := input
        hsTX.TX(TX_Pin,B_Size,@Buffer,com,Offset)     ''Transmit Data to External Propeller
        packet:=hsRX.RX(RX_Pin,@Buffer)               ''Receive Data from External Propeller   [/B] 
           
        pst.newline
    
        Buffer[8] := 0
    
        CASE input
          1:                                  ''1) get mean values
            com := input                      'set com to 1 -> client sends mean value
            pst.str(string("Enter client ID: "))
            input := pst.decin                 'now input := client ID
            Buffer[0] := input                 'Buffer[0] := client ID
            hsTX.TX(TX_Pin,B_Size,@Buffer,com,Offset)     ''Transmit Data to External Propeller
            packet:=hsRX.RX(RX_Pin,@Buffer)               ''Receive Data from External Propeller
            pst.str(string("Client reply: "))             ''display mean value
            pst.dec(Buffer[input*8+8])
            pst.newLine
            pst.newline
    
    ... more CASE statements PUB and PRI routines not shown
    
    

    My Buffer looks like this:
    [TABLE="class: grid, width: 100%, align: center"]
    [TR]
    [TD]Buffer[0][/TD]
    [TD]Buffer[4][/TD]
    [TD]Buffer[8][/TD]
    [TD]Buffer[12][/TD]
    [TD]Buffer[16][/TD]
    [TD]Buffer[20][/TD]
    [TD]Buffer[24][/TD]
    [TD]Buffer[28][/TD]
    [TD]Buffer[32][/TD]
    [/TR]
    [TR]
    [TD]ID sent by Master, compared to Buffer[8][/TD]
    [TD]some value to pass to clients[/TD]
    [TD]the client ID, increased by each client[/TD]
    [TD]value sent back to master from client 1[/TD]
    [TD]value sent back to master from client 1[/TD]
    [TD]value sent back to master from client 2[/TD]
    [TD]value sent back to master from client 2[/TD]
    [TD]value sent back to master from client 3[/TD]
    [TD]value sent back to master from client 3[/TD]
    [/TR]
    [/TABLE]


    So, my Buffer is not travelling around all the time but only on demand.

    The bold snippet in the code above is an example where I thought I could check if the Round Robin is still working, right after the user entered his command. But how exactly?

    Thanks in advance.

    Akkarin
  • edited May 2013 Posts: 0Vote Up0Vote Down
    The way you're doing it is in batch process. If your project could spare its resources, I might suggest:

    As for communication between Props: Assign a cog in each prop as controller to take/pass the block of packets from/to other props. That way, the round-robin communication is travelling constantly regardless of whether the particular prop needs it or not. And, you can assign a byte as flag where the controller will see if other cogs within its prop needs to modify any part of the packet when it arrives.

    As for error checking: One way is you can do polling but frankly, I don't see the point as if the communication does break, most likely than not, its hardware related by that time...
  • edited May 2013 Posts: 0Vote Up0Vote Down
    Hi,

    I'm just beginning to understand how this thing is supposed to be used. I'll try to set up a constantly travelling round-robin buffer.
    One thing to clarify here: I want to check for connection breaks in the wiring. My system consists of several boards in an 19" rack which are interconnectet by a backplane. If e.g. one board is taken out or for some reason is not connected to the backplane anymore, the whole round robin doesn't work anymore. I'd like to check for that and than post an appropriate message to the user so that he can check the boards for poor connections or whatever.
    But the main reason is that I don't want my program to get stuck and this I can accomplish by assigning a cog on its own for the round robin, right?

    Thanks

    Akkarin
  • edited May 2013 Posts: 0Vote Up0Vote Down
    OK, now I understand what your requirements are. I feel there are a number of ways to do this and I assume that each prop/board does one set task before passing over to the next prop/board? Meaning, you would not be in a situation where a cog in prop/board A will process & update some information to cog in prop/board B simulatenously. If so, may I suggest:

    1. Before you transmit data to external propeller, do a ping by sending a byte, say $5E, & poll (in a cog) for an acknowledgement with a specific time (say, 5ms). It'll act like a watchdog so if you don't get an acknowledgement byte example $7F from the external propeller, you can send a message to the user that that particular prop/board is not responding. In either case, you'll cogstop the cog that's polling
  • edited May 2013 Posts: 0Vote Up0Vote Down
    Hi,
    last 2 days I was trying to set up the constantly travelling buffer, but I can't get it to work reliably. Some times it works, sometimes not ...
    I reckon my problem is how I access the buffer from different cogs ... I have to update the buffer in main ram and read from main ram if different cogs want to use the buffer, right? I decided to use LONG[@Buffer][index] to access the buffer in main ram from different cogs, but it doesn't work 100%.
    I'll go back a step, to batch mode, and try to implement what you suggested before.

    EDIT: I think the round robin is working OK, but my accessing the buffer not.

    Thanks

    Akkarin
  • edited May 2013 Posts: 0Vote Up0Vote Down
    Akkarin,

    Please wait a minute, I'm a little confused. You mentioned that your project setup is such that it has a backplane that connects all your clients to the server, am I correct? In that case, having a continuous round-robin communication would sure to pose a problem if any of the 5 client boards were to be removed, as you have also mentioned. Therefore, I suggested you perform a check on the next client before launching hxTX.TX. E.g.:

    CON
      _waitCheckClient = 40_000_000
    
    VAR
      long  checkClientStack[128]
      byte ackByte
    
    OBJ
      Com  :  "FullDuplexSerialExt.spin"
    
    'Server Board
    PUB Main | stopCnt, cogNum
    :
    :
    
        pst.str(string(":> "))
        input:=pst.decin                               ''wait for user input
    
    
        'make sure Round Robin is still working
        com := Buffer[0] := input
    
      'Check if next Client (2) is still connected
      ackByte := $FF
      stopCnt := cnt + _waitCheckClient + 1088
      cogNum := cognew(CheckClient(@ackByte), @checkClientStack) + 1
      repeat while cnt < stopCnt
      cogstop(cogNum~ -1)
      if(ackByte == $FF )
        'Send an error msg to user that comm to Client 2 cannot be established
      else
        waitcnt(cnt + clkfreq/5)
        hxTX.TX(.....
    
    PRI CheckClient(mainByte)
      Com.Start(6, 7, 0, 115_200)
      waitcnt(cnt + clkfreq/5)
    
      Com.Tx($5E)
      BYTE[mainByte] := Com.Rx
    
      repeat
    

    Then, on your Client 2, you would be listening for $5E from Master. When it received it, send the acknowledgement byte ($7F) over then launch the hxRX.

    And, to your latest question, if you want other cogs to update the hub ram before sending over to Client 2, you'll need to pass the hub address over to the cog. Then, for each cog, you'll need to ensure they update into their correct/assigned offset area else the cogs will be fighting to write on the same section. Also, within cog, you'll access its data as LONG[Buffer][Index] since Buffer is already the address.

    Hope the above helps. I just typed out the above code just to show you the idea so I didn't test it.
  • edited May 2013 Posts: 0Vote Up0Vote Down
    Hi,

    sorry I didn't have the time to reply, yet.
    I implemented the connection check such that I open a new cog directly after the user entered a command in the main menu. This new cog sends a message to the clients and waits for the reply. If it times out after, say, 5ms, the main routine stops the cog and I know that there is a connection problem. If not, the cog stops itself after reception of the client reply. The main routine reads the correct reply and goes on with the program. This way it's not continuously checking, but good enough for me right now.
    Also, within cog, you'll access its data as LONG[Buffer][Index] since Buffer is already the address.

    That's a good hint! Thanks :)
  • edited December 2014 Posts: 0Vote Up0Vote Down
    Hi,

    I realize I'm a bit late to the game, but I just discovered this code for a project I'm doing. Beau, the code is great! Thanks for posting it. I have it working within my old code, which is now split between two Props, but I have one obstacle I can't seem to overcome. Anytime I run the code with the USB cables plugged into my boards (Propsticks) it runs and the debug LEDs blink on the client side letting me know the buffer is being passed around. Looking into the terminal I have good data. However I am unable to get it to work without the USB cables plugged in (to both client and server). I tried to remove the code that looks at the USB power and then starts PST but no matter what I try the LEDs never start. Then as soon as I plug them in (and have the client PST code back in place) and cycle the power, the LEDs start blinking. My question is "Does PST need to be running for this to work?" I looks like it is for debugging only and in my final setup I don't plan on having a PC hooked up.
    Thanks,

    -Brian

    *****EDIT**********

    Found the issue. Client not properly grounded. Looks like the USB provided an acceptable ground while connected but when unplugged the loop was broken.
Sign In or Register to comment.