Shop OBEX P1 Docs P2 Docs Learn Events
Does the Prop Tool look for identical blocks of code? — Parallax Forums

Does the Prop Tool look for identical blocks of code?

Duane DegnDuane Degn Posts: 10,588
edited 2011-03-02 13:54 in Propeller 1
I'm trying to use two instances of a modified serial driver. The driver uses the cog image as its rx buffer so I need two cog images one for each instance of the driver.

Fine, I think, I'll just rename a second copy and use that. Wrong! The image is only in the ram once.

If I change the second copy a bit, I can get it to load into RAM. In the object I have a single long with the value of 1 in the midst of many zero valued longs. When viewing the hex after pressing F8, I can only find this isolated 1 a single time in the code. If I change several other zeros to one in the second copy, I can then find the isolated 1 as well as the group of ones from the second copy cog image.

When the second copy only has a different name but with identical code the program space is 4,138 longs. But if I alter the code of the second copy a little then the program space increases to 4,944 longs. What the heck is going on?

Does the Propeller Tool look for identical code? I thought it only saved space by only keeping one image of an object that may be used multiple times. I thought saving a copy of an object with a different name keep the Prop Tool from reusing the same code.

How do I make sure the Prop Tool isn't doing me favors I don't want? Aarrgh!! I thought I had a bug but it turns out it's the Prop Tool is cutting out RAM space I need.

Duane

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-03-01 23:23
    Does the Propeller Tool look for identical code?
    Yes, it does; and it eliminates duplicate objects.

    Why not use VAR variables for your buffers and buffer pointers instead of DAT variables? Then you could declare multiple instances of the same object without issue. And you would save hub RAM by not having multiple copies of your code.

    -Phil
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-03-01 23:50
    Phil,

    Thanks for your reply. I have the buffers in the DAT section so I can reuse the cog image. The idea was to save hub RAM.

    Normally, I would only be using one instance of the object. But I'm trying to test the object by having one cog talk to another cog with two XBees.

    I know the Propeller Tool eliminates duplicate objects but I thought changing the name of the object kept it from doing so.

    Since I first posted I found the difference in the size of program space is the exact about of space the program of the object I want to duplicate takes. It seems changing a couple (probably one) long is enough to keep the object from being duplicated.

    This just adds an extra step in my testing. Instead of just saving the object as a different name, I have to change some of the code as well.

    I think I recall a tutorial that instructed the user to save an object with a different name in order to keep the DAT sections separate. I don't remember if was in the PEK or not. Now I wonder if an earlier version of the Prop Tool worked the same way as the most recent versions with regards to identical objects with different names.

    It seems odd the Prop Tool would do this. It must have an algorithm to test for identical files.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-03-02 00:53
    I looked through the PEK and other tutorials I have on my hard drive and couldn't find a reference about saving an object with a different name.

    I tried compiling with BST both with the "Eliminate unused SPIN methods" checked and unchecked.

    It appears BST handles renamed objects the same way the Prop Tool does.

    I have found that changing the value of one long is enough to have the object duplicated in RAM.

    I do wish there were a way to turn off this feature.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-03-02 08:19
    Duane,

    How big are those buffers? It's not clear to me that you're saving any hub RAM if you have to do it by doubling the size of your driver's code image.

    -Phil
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-03-02 08:45
    You could split up your serial driver into two objects. One object would contain the Spin methods used for serial I/O, such as tx, rx, str, etc. The other object would contain the start method and the PASM code. This way you could reuse the cog image in DAT after you call the start method. You could actually reuse the entire object including the method table and the space used by the start method if you're careful.

    EDIT: I re-read your initial post, and I realized that you want two instances of the serial driver. Do you need to use two cogs, or could your run a dual-serial driver in one cog? There are some objects that have been developed that do that.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-03-02 10:58
    Phil, The buffers are 512 bytes. Four of them. I'm using a modified version of Tim Moore's pcFullDuplex . . . (the four port one).

    I initially tested my changes with just one instance of the object running and I'd have the different ports communicate with each other.

    I wanted to modify the code again to add extra features to just one of the ports. I want to have the serial object take care of wireless communication acknowledgments within the PASM section of code. I'm hoping to make the Spin section of my top object less awkward. It will send a transmission including one byte which is a counter of the number of transmissions sent. The sending object waits a set about of time for an acknowledgment flag to change. I want this acknowledgment flag to be changed by the serial driver. The serial driver will watch for a message starting with the acknowledgment character. The character following the acknowledgment character should be the setCount being sent back by the other XBee in indicate it received the original message.

    To send the original message, I use this method:
    (The parameters "sourceNumber" and "targetNumber" are not presently used.)
    PUB TransmitString(sourceNumber, targetNumber, pointer) | size, localIndex, attempts, localBufferIndex, localCount
    '' String needs to terminate with a carriage return
    '' There may be a zero after carriage return but it will not be transmitted.
      ' XBee enumeration
    '  #0, _XBeeA, _XBeeE, _XBeeH
     
      size := strsize(pointer)                              
     
      setCount++  
      if setCount == 13 or setCount == 0
        setCount++ ' I don't want setCount to be either 0 or 13
      attempts := 0
      Com.str(_DebugCom, string(13, "TransmitString method", 13))
     
      acknowledgeFlag := 0
      '  targetLetter = "s"
      '  sourceLetter = "a"
      repeat
        Com.tx(_XBeeCom, Header#_StartOfHeader)
        Com.tx(_XBeeCom, Header#_StartOfText)
        Com.tx(_XBeeCom, targetLetter)             ' destination board
        Com.tx(_XBeeCom, sourceLetter)    
        Com.tx(_XBeeCom, setCount)
        Com.str(_XBeeCom, pointer)                       ' ** okay if all data is ASCII
        if byte[pointer + size - 1] <> 13
          Com.str(_DebugCom, string(13, "byte[pointer + size - 1] <> 13")) 
          Com.tx(_XBeeCom, 13)      ' I want the transmission to end with a carriage return
     
        localCount := cnt
        repeat while (acknowledgeFlag == 0) and Header#_XBeeTimeoutRx => cnt - localCount
     
        attempts++                                                                                                           
     
     ' Header#_TxAttempts = 32               
      while ((attempts < Header#_TxAttempts) and (acknowledgeFlag == 0))
     
      if acknowledgeFlag == 0
     
        Com.str(_DebugCom, string(13, "tries = "))
        Com.dec(_DebugCom, attempts)
        Com.tx(_DebugCom, 13) 
     
      else
     
        Com.str(_DebugCom, string(13, "successful tx"))
     
      result := acknowledgeFlag
     
    

    I've modified the serial driver to watch for an end of message character (I'm using 13). The driver then increments a counter "rxFlag" (one for each port). The top object can tell if there is a new message by checking the rxFlag counter against its previous value (held in "oldRxFlag").

    I'm trying to modify the serial driver to also write a 1 to the variable "acknowledgeFlag" when the correct acknowledgment is received.

    In the method FlushBuffer the "setCount" value is immediately sent back in a reply to indicate the message has been received. The method only watches for the setCount on the wireless port (port zero "_XBeeCom").

    One of my instruments outputs three lines of data at once. I use the variable "linesToExpectCom" in order to retrieve multiple lines at once. For now all the "linesToExpectCom" are set to equal one.
    PRI FlushBuffer(localBufferIndex) | localCharacter, localIndex, linesOut, previousWirelessCharacter
       if rxFlag[localBufferIndex] == oldRxFlag[localBufferIndex]       
        ' Tbug is a method that makes it easier for me to change how data is displayed (terminal and/or TV)                  
        Tbug(string(13, "No buffer data, rxFlag["))
        TbugDec(localBufferIndex)
        Tbug(string("] = "))
        TbugDec(rxFlag[localBufferIndex])
        return 0
      previousWirelessCharacter := 0
      localIndex := 0
      linesOut := linesToExpectCom[localBufferIndex]
      repeat while linesOut > 0
        if localIndex => Header#_LargeBufferSize
          Tbug(string(13, "tempBuffer full!", 13))
          Tbug(string("This shouldn't happen.", 13)) 
          quit
        localCharacter := Com.rx(localBufferIndex)
        tempBuffer[localIndex] := localCharacter
     
        if localBufferIndex == WirelessCom
          if localIndex == 0
            previousWirelessCharacter := localCharacter
              elseif localIndex == 4
     
            Com.tx(_XBeeCom, Header#_WirelessAck)
            Com.tx(_XBeeCom, localCharacter)
            Com.tx(_XBeeCom, endChar)
        if localCharacter == endChar   ' endChar = 13
          linesOut--
        localIndex++
      tempBuffer[localIndex] := 0   ' is this needed?
      oldRxFlag[localBufferIndex]++
      SafeBug(@tempBuffer, localIndex)
      ' SafeBug is a method that displays non ASCII characters as hex.
      result := localIndex 
     
    

    Since only one of the four ports is setup to watch for the wireless information, I need two instances of the object to test it.

    I normally will only be using one instance of the object so I don't need to make using two more efficient.

    The top object launches an almost identical version of itself into another cog. This second version launches its own serial driver. Since I'm constantly making changes and testing the new changes, I'd like a fast way of making sure two full copies of the serial object are used. I thought changing the name of the object was enough. Now I know it's not.

    I was using two Propellers to test serial objects. I thought it would make the testing go faster if I only needed to load one Propeller with the new code. I want the single Propeller to act as if it were two and only let the two sets of cogs communicate through serial lines.

    Sorry about all the information. But I don't think I was making myself clear with my short descriptions of what I'm doing.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-03-02 11:11
    Here's a link to the modified serial drivers.

    The code attached to post #9 uses the end of message flags.
  • Dave HeinDave Hein Posts: 6,347
    edited 2011-03-02 12:13
    Duane,

    So it seems that you need two different version of the serial driver so that you can put the acknowledgments into the PASM code for one of them. Is that correct? Why do you need to do this? Is the Spin acknowledgment too slow? It seems like it would be better to use one PASM driver and do the acknowlegement in Spin.

    How many serial ports do you need? Is four enough? With two drivers you'll have 8 ports. Do you need that many?

    Dave
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-03-02 13:54
    Dave, Thanks for your interest in my serial problems.
    So it seems that you need two different version of the serial driver so that you can put the acknowledgments into the PASM code for one of them. Is that correct?

    No, I want the two drivers to be the same. I'm adding the acknowledgments to just one of the four ports. I need one instance of the driver to send the original message and the second instance (simulating a separate Propeller) to reply to the message by sending the setCount number back to the original instance. The code has to be changed for both the tx side and the rx for the acknowledgment to work.
    Why do you need to do this?

    The short answer is because it's there.

    After modifying Tim's object to have larger buffers I thought "Hey, this PASM stuff is cool, maybe I can put some of my other data manipulation stuff into the same cog as the driver."

    Now that the rx buffers are so large, I can leisurely process the incoming data. While most data doesn't need to be acted on immediately, I do want to acknowledge wireless transmissions immediately so the transmitting Propeller doesn't have to keep trying to resend the data.
    Is the Spin acknowledgment too slow?

    Sort of. I don't want to have transfer the rx data to a different buffer as I look for the acknowledgment. There might be incoming transmissions that aren't acknowledgments so the acknowledgment might be buried inside the rx buffer among other data.
    How many serial ports do you need? Is four enough?

    Usually four is enough. I will need more than four ports on one of my boards but for now I'm just trying to test the driver using only one Propeller chip. The wireless acknowledgment is only added to one of the four ports so I need two instances of the object to test it. I want to be able to test the serial object in a single Propeller so I don't have to load the program into two different Propellers each time I make a change to the code. Once I get the object working the way I want, I'll use it (only one instance) in several of my Propeller boards that use wireless communication.

    I'm a chemist and I use the Propeller to collect data from a variety of instruments. I've put barcodes on all my vials and bottles so one of the ports is connected to a barcode reader. I've also made one of my barcode readers wireless by adding a Propeller and XBee. I have lots of serial lines that need to be monitored. Having large rx buffers should make it easier to handle large bursts of data from multiple sources. If I could have wireless transmissions acknowledged quickly I could keep bursts of data in the rx buffer as it waits to be processed.

    As I mentioned previously, I had thought changing the name of an object would cause the Propeller Tool to treat it as a completely different object and not as an instance of a previously used object. Now know I need to change more than the name of the file.
Sign In or Register to comment.