SerialMirror - Why does it work ? Xbee object array application !
Greg P
Posts: 58
Hi All,
I'm currently updating Martin Hebel's excellent Xbee object for use with "digimesh" firmware and 64-bit addressing. Hebel's code only works with 16-bit address frames. I prefer "digimesh" firmware as it supports mesh networking without ZB firmware configuration difficulties for rapid deployment.
So far, so good. I have local AT command/response packets, remote AT command/response packets, Tx packets with Tx response packets, and Rx packets fully functioning with 64-bit addressing. I'm at the point where I can send an ND (node discovery) command to the local Xbee, and receive AT remote response packets from all Xbees attached to the wireless networks. I have also updated i/o and analog input packet processing as these frames have also changed slightly. I hope to upload a fairly robust object to the forum in a few weeks.
As part of that effort, I would like a very object-oriented way of communicating with the individual Xbees. The declaration of an array of Xbee objects is appealing. It would allow me to have digital i/o and analog input updating take place "in the background." The state of these inputs could be read through object function calls.
I would like to handle more of the packet processing within the serial cog itself. If I could declare a "serialmirror"-like Xbee-Engine object at the top object and then have individual references to the Xbee-Engine in the array of Xbee objects (much like individual declarations of serialmirror are required in other objects current), then all calls to Xbee-Engine functions within the Xbee objects would channel into the single Xbee-Engine object declared at the top object level.
I understand that this serialmirror "trick" requires the elimination of all variable declarations within the object, substituting DAT memory space for variable use instead. I don't have a good handle on exactly what the compiler is doing when an object with no VAR section is replicated in multiple objects. I can see that a SPIN interpreter running in a cog could "read" the same spin code instruction in hub memory for an object provided that a separate copy of the VAR section is available in hub memory for each instance of the object used within the overall program. But what of the DAT section ? Is the DAT section also "shared" by multiple instances of an object, or is it also duplicated for each object instance. It would seem, based on the serialmirror object that this is not the case.
Wisdom on this topic would be greatly appreciated. Has there been a thread on this forum which has addressed in detail the means by which the serialmirror object performs its "magic" ?
Could anyone help me to understand the working of the serialmirror object in greater detail ? Even a "best guess" would be great at this point.
I'm currently updating Martin Hebel's excellent Xbee object for use with "digimesh" firmware and 64-bit addressing. Hebel's code only works with 16-bit address frames. I prefer "digimesh" firmware as it supports mesh networking without ZB firmware configuration difficulties for rapid deployment.
So far, so good. I have local AT command/response packets, remote AT command/response packets, Tx packets with Tx response packets, and Rx packets fully functioning with 64-bit addressing. I'm at the point where I can send an ND (node discovery) command to the local Xbee, and receive AT remote response packets from all Xbees attached to the wireless networks. I have also updated i/o and analog input packet processing as these frames have also changed slightly. I hope to upload a fairly robust object to the forum in a few weeks.
As part of that effort, I would like a very object-oriented way of communicating with the individual Xbees. The declaration of an array of Xbee objects is appealing. It would allow me to have digital i/o and analog input updating take place "in the background." The state of these inputs could be read through object function calls.
I would like to handle more of the packet processing within the serial cog itself. If I could declare a "serialmirror"-like Xbee-Engine object at the top object and then have individual references to the Xbee-Engine in the array of Xbee objects (much like individual declarations of serialmirror are required in other objects current), then all calls to Xbee-Engine functions within the Xbee objects would channel into the single Xbee-Engine object declared at the top object level.
I understand that this serialmirror "trick" requires the elimination of all variable declarations within the object, substituting DAT memory space for variable use instead. I don't have a good handle on exactly what the compiler is doing when an object with no VAR section is replicated in multiple objects. I can see that a SPIN interpreter running in a cog could "read" the same spin code instruction in hub memory for an object provided that a separate copy of the VAR section is available in hub memory for each instance of the object used within the overall program. But what of the DAT section ? Is the DAT section also "shared" by multiple instances of an object, or is it also duplicated for each object instance. It would seem, based on the serialmirror object that this is not the case.
Wisdom on this topic would be greatly appreciated. Has there been a thread on this forum which has addressed in detail the means by which the serialmirror object performs its "magic" ?
Could anyone help me to understand the working of the serialmirror object in greater detail ? Even a "best guess" would be great at this point.
Comments
Each object that uses another object causes a new set of variables to be allocated. If the "another object" uses other objects (like SerialMirror), those objects are treated like variables and any variables declared within those objects are duplicated as well.
A "mirror object" gets around this by putting all of its variables into a DAT section. A DAT section is allocated once no matter how many times the object is referenced from some other object(s). You can't put an object reference into a DAT section though, so anything referenced from your "xBee" object has to be written as a "mirror object" too. Also remember that the Propeller Tool only keeps one copy of an object's code, so you don't have to worry about that being duplicated.
Are the XBee's you are using the "Series 2" or "Series 2.5"? (I've been told XBee's don't use the Series numbers anymore but I'm not sure what else to call them.)
The XBee's I have say "Series 2" on them. There serial numbers are 64-bit. I don't know if these are the same as "64-bit addressing" you're referring to.
I haven't used SerialMirror but I've made lots of modifications to Tim Moore's pcFullDulplexFC4 (his four port serial driver). One of the changes I made was to check for an acknowledgment character within the driver. I've posted this code here. I haven't looked at if for a while. I'm not sure if our efforts are in the same direction or not. If they are it might be useful to work together.
I can't make any promises though. I have several other projects I need to give higher priority than my work with XBees.
Duane
Digimesh is a proprietary mesh protocol that runs on Digi series 1 XBee hardware. The alternative (usually the default) for the series 1 hardware is so called IEEE 802.15.4 compatible (with a couple of nice extensions possible).
Digi series 2 hardware (different, not necessarily better, repeat mantra) runs a fully zigbee compatible protocol that Digi calls "ZB". Digi had a preliminary less compatible version of firmware for series 2 that they called "znet 2.5".
Greg is talking about series 1 hardware here, loaded with the digimesh firmware. The 64 bit address (MAC address) is indeed the 64 bit serial number that is printed on a label on the XBee. IEEE 802.15.4 protocol can use that full MAC for addressing, but it alternatively has the ATMY command, whereupon each module is assigned a simple address like "0" or "1" or up to $FFFD using the ATMY command. In digimesh, the addressing is all done using the full 64 bit MAC address. On series 2 hardware, the MY command is informational only, and addressing can be done either via the full 64 bit MAC address, or by a shorthand address that is linked into the network by the coordinator XBee.
Greg,
I'm intrigued by what you mean by an array of XBee objects. How many serial ports will you need? There will be one for the home XBee, and maybe one for debug. More? If you use a program like SerialMirror, or Tim Moore's pcFullDuplexSerial4fc, or Duane's enhanced version, you can declare that serial i/o object in any or all of your subobjects, but there will be only one copy of the code in the hub. In your top object only, you will start the uart(s). In the case of pcFullDuplexSerial4fc, that involves an Init command, followed by 1 to 4 addUart commands to set up the individual pins and baud rates etc, and then a Start command. That will cause it to spawn one and only one additional cog, running the pasm machinery. Subsequently, from any other object, you can write and read data to and from any of the uart buffers, using any of the methods in the pcFullDuplexSerial4fc object. There is only one instance of the object. All of the UART buffers and pointers are held in the DAT section, and the access to them is via methods that can be available to all your other objects. You could modify the spin methods in the serial io object itself, or implement a separate object that does what you need. For something really tricky you could dig into the pasm code. Duane has made clever enhancements of that sort to expand the serial buffers and to add the special decoding that he mentioned.
Thank you very much for taking time to explain these differences (I'm afraid again). I'm thought maybe when Greg mentioned "ZB" that it might stand for zigbee.
I do like Greg's idea of moving housekeeping/bookkeeping methods to the PASM section of the driver.
Duane
Thanks for the explanation regarding how DAT & VAR sections are managed by the compiler. Just to be sure that I understand the main concepts, I'll repeat below what I believe to be your key ideas:
1) Object code is never duplicated in hub memory.
2) An object's DAT section is allocated within hub memory only once, regardless of # of instances.
3) An object's VAR section is duplicated within hub memory for each instance of an object.
4) A "mirror" object must have no variables within its VAR section.
5) A "mirror" object may contain sub-objects PROVIDED these objects are themselves "mirror" objects.
For example: SerialMirror object may be included within the OBJ section of a "mirror" object.
Are these correct ?
Below is an outline of what I wish to accomplish:
I would begin by substituting "SerialMirror" for my existing VAR-based serial object within working code. I would then modify my existing code so that all its VAR section variables are remapped to DAT section variables. Upon completion, this code would become the new Xbee_Link object (with no VAR section) that could then be referenced by each instance of XbeeArray[].
Any comments / suggestions would be greatly appreciated !
In the above three serial.dec calls, the value of "30" was returned even though the values of "10", "20", "30" were originally assigned to long(0) in the three mirrored objects.
It would be easier to read the code if you used code brackets.
[ Code]
Your code here.
[ /Code]
but without the space after the [.
Duane
Edit: I just noticed you don't have any loops or conditionals so technically the format doesn't matter much. It would still be easier to read in a code block.
As part of my effort to re-write the Xbee_Link_Control object using only DAT section 'variables' (so that multiple instances of this Link_Control object may be embedded within an array of Xbee_Access objects), I decided to substitute "SerialMirror" object (which is DAT only, no VAR section) for the original "FullDuplexSerial" object used by Martin Hebel.
My test program failed to communicate using the new serial object. What went wrong ?
First, I had already used another SerialMirror object for communication with the PC and the serial terminal program. BUT, I had renamed the SerialMirror object used within the Xbee_Link_Control object to "Xbee_SerialMirror," thinking that the unique name for the second instance of the SerialMirror object would be sufficient for the compiler.
I glanced at the object "pcFullDuplexSerial4FC" which is also a DAT-section only object for some clues and discovered the following code entry:
'If you want multiple copys of this driver in a project, then copy the file to multiple files and change
'version in each to be unique
version long 1
Interesting ! So I edited the Xbee_SerialMirror object and inserted the same 'version' long code within it. Now it works !!
Apparently, JUST RENAMING an object WITHOUT ALTERING in some manner its internal "checksum" will not fool the compiler into allocating separate hub memory space for the two SerialMirror objects. Once the two objects were truly UNIQUE in content, the compiler was happy to allocate hub memory for the two objects.
Is my thinking in error or does it need clarification ?
Thanks Duane ! I have edited my original remarks using your excellent suggestion.
I've found if I'm starting the same code in multiple cogs, I need to wait for the first cog to finish loading before loading the second. This is especially true it the start method sets variables that are to be loaded into the cog.