Shop OBEX P1 Docs P2 Docs Learn Events
help with Xbee and multiple cogs — Parallax Forums

help with Xbee and multiple cogs

JBWolfJBWolf Posts: 405
edited 2013-02-21 11:24 in Propeller 1
I am having a very odd problem i just cannot figure out.
I have 2 props communicating via xbee just fine right now.... I'm using buttons on one to set a variable status of 1 or 0 then transmit.
Right now this is setup as one way communication, the "transmitter" prop station has buttons and a repeat loop with:
Repeat

if ina[button] == 1
   device1 := 1
   state := 1

XB.Tx("!")                                    ' Send start delimiter
XB.Dec(State)                             ' Send decimal value of button state
XB.CR                                        ' Send Carriage Return

The "Receiver" prop station has a repeat loop with:
repeat                                ' Start Wireless Receiving
    DataIn := XB.Rx                 ' Accept incoming byte
    If DataIn == "!"                   ' If start delimiter
       DataIn := XB.RxDec           ' Accept value  
      if DataIn <> -1                  ' If wasn't time out
         XB.CR                         ' Carraige Return
         Input := DataIn               ' Move data
     XB.RxFlush

case input
   1: !outa[device1]
       device1tracker++
          if device1tracker > 2
             device1tracker := 1
   2: !outa[device2]
       device2tracker++
          if device2tracker > 2
             device2tracker := 1
   3: .....
   4: .....

Since this works perfectly, I decided to add a function to allow the receiver station to send it's current variable values back to the transmitter station if the transmitter is power cycled.
Since both stations reset all button states and variables on a power cycle, the transmitter station would lose track of the receiver station variables if it was powercycled and the receiver was not.
i.e.. transmitter sets button state #3 to ON... receiver gets the data and turns on device corresponding to button #3. powercycle transmitter station and it thinks button #3 status is OFF on the receiver.

I thought this would be a simple deal by sending a decimal value to the receiver station. the receiver and transmitter stations would then reverse roles for 3 decimal values only, then resume normal operation.
Both the receiver and transmitter are running 2 cogs each... one cog for xbee communication, another cog for actions.
I am using Long's to facilitate passing variable values between cogs.
I have tried over and over every possible method I could think of and finally decided to break it down to the most simple method imaginable... but this still will not work:

Receiver station:
VAR 
Long Input

PUB Main(Input) | DataIn
XB.start(XB_Rx, XB_Tx, 0, XB_Baud)     ' Initialize comms for XBee
 waitcnt(clkfreq / 500 + cnt)
 
Cognew(Actions, @stack[200])           ' Initialize Actions Processor - Uses incoming data
 waitcnt(clkfreq / 500 + cnt)

repeat                                ' Start Wireless Receiving
    DataIn := XB.Rx          ' Accept incoming byte
    If DataIn == "!"                   ' If start delimiter
       DataIn := XB.RxDec      ' Accept value  
      if DataIn <> -1                  ' If wasn't time out
         XB.CR                         ' Carraige Return
         Input := DataIn               ' Move data
     XB.RxFlush
      
   If DataIn == 11                     ' If Recover Received
        Input := DataIn
        waitcnt(clkfreq * 2 + cnt)             
  
   waitcnt(clkfreq / 1000 + cnt)


Pub Actions
Repeat                                ' Start program - endless loop
    tmp1 := long[@Input]               ' move new incoming data to tmp1
    long[@Input] := -1                 ' clear buffer
   Case tmp1
          11: ' Data Recover Initiate             
              waitcnt(clkfreq / 100 + cnt)
              XB.Tx("!")                    ' Send start delimiter
              XB.Dec(99)                    ' Send recovery ack
              XB.CR                         ' Carraige Return
              waitcnt(clkfreq / 100 + cnt)
              '------------
              XB.Tx("!")                    ' Send start delimiter
              XB.Dec(device1)              ' Send #1 Status
              XB.CR                         ' Carraige Return
              waitcnt(clkfreq / 100 + cnt)
              '------------              
              XB.Tx("!")                    ' Send start delimiter
              XB.Dec(device2)                ' Send #2 Status
              XB.CR                         ' Carraige Return
              waitcnt(clkfreq / 100 + cnt)
              '------------              
              XB.Tx("!")                    ' Send start delimiter
              XB.Dec(device3)                ' Send #3 Status
              XB.CR                         ' Carraige Return

Transmitter Station:
VAR
Long ButtonState

Pub Main 
Cognew(Buttons(@ButtonState), @stack[200])    ' Start Button Monitor
Cognew(Wireless(@ButtonState), @stack[400])  ' Start Wireless
 Repeat

PUB Wireless(BtnIn) | State, DataIn, Temp, RecovTrack, StartRecov
State := -1
XB.start(XB_Rx, XB_Tx, 0, XB_Baud)                  ' Initialize XBee
waitcnt(clkfreq / 100 + cnt)
Temp := 0
StartRecov := 1
RecovTrack := 0

Repeat
  State := long[BtnIn] 
  IF State > -1 and State < 12                      ' If ButtonState range 0-11
      XB.Tx("!")                                    ' Send start delimiter
      XB.Dec(State)                                 ' Send decimal value of PB state
      XB.CR                                         ' Send Carriage Return
      
        IF State == 11                              ' If Recovery Startup
           waitcnt(clkfreq * 2 + cnt)
                 
      State := -1                                   ' Clear Output Buffer 'State' 
      long[BtnIn] := -1                             ' Reset Buttons Input Value         
  waitcnt(clkfreq / 500 + cnt)                      ' Matched with receiver


PUB Buttons(State) | Device1, Device2, Device3

 StartRecovery := 1
  Repeat
      if StartRecovery > 0
         long[State] := 11  
         'waitcnt(clkfreq / 400 + cnt)            

                 DataIn := XB.Rx                    ' Accept incoming byte
                 If DataIn == "!"                   ' If start delimiter
                    DataIn := XB.RxDec              ' Accept value  
                    if DataIn <> -1                 ' If wasn't time out
                       XB.CR                        ' Send Carriage Return
                    XB.RxFlush                      ' Clear Buffer
                  if dataIn == 99
                    repeat TempQ from 1 to 3
                       DataIn := XB.Rx                    ' Accept incoming byte
                       If DataIn == "!"                   ' If start delimiter
                          DataIn := XB.RxDec              ' Accept value  
                          if DataIn <> -1                 ' If wasn't time out
                             XB.CR                         ' Send Carriage Return
                          XB.RxFlush                      ' Clear Buffer
                       Case TempQ
                         1: Device1 := DataIn
                         2: Device2 := DataIn
                         3: Device3 := DataIn
                      waitcnt(clkfreq / 100 + cnt)
            StartRecovery := 0  
 long[State] := Temp1                          ' Move to Wireless cog
    waitcnt(clkfreq / 500 + cnt)                  ' Matched with Receiver
    Temp1 := -1                                   ' Erase temporary button input


I added an LCD for debugging and am finding that the transmitter station is not receiving a value back from the receiver.
I dont understand why. I have tried directly sending with XB.DEC(long[device1]), I have tried moving the data from the long to a local variable and then sending with XB.DEC(tempvalue).... I can not get these to work.
everything else works fine... I cut the button input and device outa operations from the code above since it's about 3 pages long, I'm using over 2 dozen buttons/devices all together.
Everything else works great... I press a button on the transmitter which sets the long[state] variable to a value of 1 through 10 and the wireless cog transmits... the receiver gets it and moves to long[input] where the actions cog operates devices correctly corresponding to received value. But I just cannot get it to reverse. When I added an LCD to the transmitter station and had it display the received DEC, it was blank... it is not getting anything.
Please help, I am at my wits end... been 2 nights now wasted on this

If you would like the full code let me know... it seriously long though

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2013-02-15 15:52
    From a quick glance this looks suspicious, SPIN stacks are growing upwards. IOW I'd expect @stack[0] and @stack[200] to be used here.
    Pub Main 
    Cognew(Buttons(@ButtonState), @stack[200])    ' Start Button Monitor
    Cognew(Wireless(@ButtonState), @stack[400])  ' Start Wireless
     Repeat
    
    How big is your stack?
  • JBWolfJBWolf Posts: 405
    edited 2013-02-15 15:54
    A note I should add... I do have a DS1620 thermometer on the receiver which does properly send back the temperature data to the transmitter.
    Since I can get this to work fine, it driving me crazy not being able to simply send back other variables.

    Heres how I am running the temp probe.
    Transmitter station:
    PUB Wireless(BtnIn, Temperature2, LCDState2)
    Repeat
      State := long[BtnIn] 
      IF State > -1 and State < 12                      ' If ButtonState range 0-11
          XB.Tx("!")                                    ' Send start delimiter
          XB.Dec(State)                                 ' Send decimal value of PB state
          XB.CR                                         ' Send Carriage Return
          
            IF State == 10                              ' THERMOMETER Data Receiving Button
               State := -1
               long[BtnIn] := -1           
               Temp++                                   ' Increment LCD indicator
                 If Temp > 2                            ' Limit to 0/1/2
                    Temp := 0
    
               If Temp == 2                          
                  long[LCDState2] := 2                  ' Send LCD OFF Variable   
    
               If Temp == 1                             ' Make sure button press wasnt to turn off LCD display
                  long[LCDState2] := 1                  ' Send LCD ON 
                  long[Temperature2] := 000             ' Reset Temp value
                  waitcnt(clkfreq / 100 + cnt)
                  Repeat 10                             ' Start Wireless Receiving
                     DataIn := XB.RxTime(2)             ' Accept incoming byte
                     If DataIn == "!"                   ' If start delimiter
                        DataIn := XB.RxDecTime(3)       ' Accept value  
                        if DataIn <> -1                 ' If wasn't time out
                          XB.CR                         ' Send Carriage Return
                          long[Temperature2] := DataIn  ' Move data
                        XB.RxFlush                      ' Clear Buffer
                
                    waitcnt(clkfreq / 2 + cnt)
    
          State := -1                                   ' Clear Output Buffer 'State' 
          long[BtnIn] := -1                             ' Reset Buttons Input Value         
      waitcnt(clkfreq / 500 + cnt)                      ' Matched with receiver
    
    
    PUB Buttons(State)
    if Ina[Thermo] == 1                         ' Momentary P9  - Digital Thermometer           
             long[state] := 10                        ' Matched with receiver
             waitcnt(clkfreq / 500 + cnt)
             Temp1 := -1
             waitcnt(clkfreq + cnt)
    
     long[State] := Temp1                          ' Move to Wireless cog
        waitcnt(clkfreq / 500 + cnt)                  ' Matched with Receiver
        Temp1 := -1                                   ' Erase temporary button input
    

    Receiver Station:
    repeat                                ' Start Wireless Receiving
        DataIn := XB.Rx 'Time(10)          ' Accept incoming byte
        If DataIn == "!"                   ' If start delimiter
           DataIn := XB.RxDec 'Time(1)     ' Accept value  
          if DataIn <> -1                  ' If wasn't time out
             XB.CR                         ' Carraige Return
             Input := DataIn               ' Move data
         XB.RxFlush
          
       If DataIn == 10                     ' If Thermo Button Received
          Repeat 10                        ' 10/2 = 5sec
             XB.Tx("!")                    ' Send start delimiter
             XB.Dec(Thermo.gettempf)       ' Send decimal value of temperature
             XB.CR                         ' Carraige Return
            waitcnt(clkfreq / 2 + cnt)     ' 1/2sec Repeat   
      
       waitcnt(clkfreq / 500 + cnt)
    
  • JBWolfJBWolf Posts: 405
    edited 2013-02-15 15:55
    bigger than it needs to be... plenty of space available and I would rather have the space and not need it, than need it and not have it
  • kuronekokuroneko Posts: 3,623
    edited 2013-02-15 16:11
    JBWolf wrote: »
    bigger than it needs to be... plenty of space available and I would rather have the space and not need it, than need it and not have it
    VAR
       [COLOR="#FF0000"]Long stack[500][/COLOR]
       Byte cog[2]
       Long ButtonState
       Long Temperature
       Long LCDState
    
    
         
    OBJ
       XB    : "XBee_Object"
       LCD   : "FullDuplexSerial.spin"
       PST   : "Parallax Serial Terminal"        
       
    Pub Main 
    
    Cognew(Buttons(@ButtonState), [COLOR="#FF0000"]@stack[200][/COLOR])                            ' Start Button Monitor
    Cognew(Wireless(@ButtonState, @Temperature, @LCDState), [COLOR="#FF0000"]@stack[400][/COLOR])  ' Start Wireless
    Cognew(Display(@Temperature, @LCDState), [COLOR="#FF0000"]@stack[500][/COLOR])                 ' Start Display Processor  
    
    Repeat
    
    This is exactly what I mean. Buttons's stack is from 200..399 and Wireless's stack from 400..499. Display's is invalid.
  • JBWolfJBWolf Posts: 405
    edited 2013-02-15 16:27
    I thought it was the other way....
    buttons = 0-200
    wireless = 201-400
    temperature = 401 - 500

    and if it does mark the start of the stack and not the end.... how could display be invalid... is 500 the maximum?
    Wouldnt display be 500+
  • kuronekokuroneko Posts: 3,623
    edited 2013-02-15 16:31
    JBWolf wrote: »
    and if it does mark the start of the stack and not the end.... how could display be invalid... is 500 the maximum?
    Wouldnt display be 500+
    Well, you only defined stack to be 500 longs in size which makes the last valid entry stack[499]. 500+ will then mis/use the other VAR members.
  • JBWolfJBWolf Posts: 405
    edited 2013-02-15 22:24
    ohhh lol sry i missed that, easy fix... the 3 cognew's were 100, 200, 300 but during troubleshooting i added more to wireless. One of the previous attempts to add a restore made wireless 5 long's longerer :)
    Thanks for pointing out. I have corrected it and tried again, no luck
    Any ideas as to why im not getting any results back from that restore attempt?

    Is XB.DEC(long[variable]) a valid use?
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-02-15 22:55
    JBWolf wrote: »
    XB.DEC(long[variable]) a valid use?

    Yes, that's valid if "variable" is the address of the long you want to send.

    It looks like you're passing addresses okay but you don't need to pass variable address between cogs running Spin. You only need to pass address the way you are between objects.

    Nothing else in the code above sticks out to me.
  • JBWolfJBWolf Posts: 405
    edited 2013-02-16 01:30
    well I dont want xbee to send the address, I want to send the decimal value stored at that address.
    what do you mean by "you don't need to pass variable address between cogs"... I dont completely follow. can you quote a piece of code and show correct way?

    I have been doing it via:
    VAR 
    long longvariable1
    long longvariable2
    
    PUB main
    cognew(something(@longvariable1, @longvariable2), @stack[100])
    cognew(something2(@longvariable1, @longvariable2), @stack[200])
    repeat
       if longvariable1 <> longvariable2
          .....
    
    PUB Something(longvartemp) | TemporaryA
    repeat 
    TemporaryA++
    long[longvartemp] := TemporaryA
    
    PUB Something2(longvartemp2) | TemporaryA
    repeat 
    TemporaryA++
    long[longvartemp2] := TemporaryA
    

    If I do xb.rx instead of xb.rxtime(ms)
    does it wait/pause until any data is received? or does it just do a check at that moment and moves on?
  • JBWolfJBWolf Posts: 405
    edited 2013-02-21 01:59
    I have resolved this problem.
    Found the receiver code was fine, it was the timing between cogs on the transmitter that was causing the issue.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-02-21 11:24
    JBWolf wrote: »
    what do you mean by "you don't need to pass variable address between cogs"... I dont completely follow. can you quote a piece of code and show correct way?

    Gobal variables may be used by any method within an object irrespective of which cog is using the variable. You can run into problems when you have multiple cogs that can change a global variable but multiple cogs testing the value of the variable shouldn't be a problem.

    Here's the "transmitter station" code from post #1 without the use of "long[variableAddress]". This code would work exactly the same as the code in post #1. The "long[variableAddress]" trick is needed when you're using a method in a different object than where the global variable is declared.
    VAR
    Long ButtonState
    Pub Main 
    Cognew(Buttons, @stack[200])    ' Start Button Monitor
    Cognew(Wireless, @stack[400])  ' Start Wireless
     Repeat
    
    PUB Wireless | State, DataIn, Temp, RecovTrack, StartRecov
    State := -1
    XB.start(XB_Rx, XB_Tx, 0, XB_Baud)                  ' Initialize XBee
    waitcnt(clkfreq / 100 + cnt)
    Temp := 0
    StartRecov := 1
    RecovTrack := 0
    Repeat
      State := [B]ButtonState[/B] 
      IF State > -1 and State < 12                      ' If ButtonState range 0-11
          XB.Tx("!")                                    ' Send start delimiter
          XB.Dec(State)                                 ' Send decimal value of PB state
          XB.CR                                         ' Send Carriage Return
          
            IF State == 11                              ' If Recovery Startup
               waitcnt(clkfreq * 2 + cnt)
                     
          State := -1                                   ' Clear Output Buffer 'State' 
          [B]ButtonState[/B] := -1                             ' Reset Buttons Input Value         
      waitcnt(clkfreq / 500 + cnt)                      ' Matched with receiver
    
    PUB Buttons | Device1, Device2, Device3
     StartRecovery := 1
      Repeat
          if StartRecovery > 0
             [B]ButtonState[/B] := 11  
             'waitcnt(clkfreq / 400 + cnt)            
                     DataIn := XB.Rx                    ' Accept incoming byte
                     If DataIn == "!"                   ' If start delimiter
                        DataIn := XB.RxDec              ' Accept value  
                        if DataIn <> -1                 ' If wasn't time out
                           XB.CR                        ' Send Carriage Return
                        XB.RxFlush                      ' Clear Buffer
                      if dataIn == 99
                        repeat TempQ from 1 to 3
                           DataIn := XB.Rx                    ' Accept incoming byte
                           If DataIn == "!"                   ' If start delimiter
                              DataIn := XB.RxDec              ' Accept value  
                              if DataIn <> -1                 ' If wasn't time out
                                 XB.CR                         ' Send Carriage Return
                              XB.RxFlush                      ' Clear Buffer
                           Case TempQ
                             1: Device1 := DataIn
                             2: Device2 := DataIn
                             3: Device3 := DataIn
                          waitcnt(clkfreq / 100 + cnt)
                StartRecovery := 0  
     [B]ButtonState[/B] := Temp1                          ' Move to Wireless cog
        waitcnt(clkfreq / 500 + cnt)                  ' Matched with Receiver
        Temp1 := -1                                   ' Erase temporary button input
    

    The above code wastes a cog. The "repeat" at the end of the Main method keeps the cog alive but the cog isn't doing anything. I suggest changing the method to:
    Pub Main 
    
    Cognew(Buttons, @stack[200])    ' Start Button Monitor
    Wireless
     
    

    I didn't fix the stack issues in any of the above code.
    JBWolf wrote:
    If I do xb.rx instead of xb.rxtime(ms)
    does it wait/pause until any data is received? or does it just do a check at that moment and moves on?

    In FullDuplexSerial, the method "rx" waits for a byte to be received. If no data is received it blocks the progress of the program. I don't recall if the XBee object works the same way. My guess is the "rx" method in the XBee object behaves the same as the "rx" method in FullDuplexSerial.
Sign In or Register to comment.