Saturday, February 4, 2012

Sat., Feb. 4th

Fixed a couple of errors in the new model.py that were due simply to not importing the communicator module (which is now referenced explicitly by the WiFi_Module proxy).

Unable to connect from the Wi-Fi board I have at home to my server at home, because my DHCP address assignment changed.  It would be really good to have a protocol whereby the server broadcasts its IP address so that nodes can find it without having to have it hard-coded.

Let's see, http://en.wikipedia.org/wiki/Broadcast_address reminds me that it should work to just send the broadcast announcement to 255.255.255.255; all nodes on the local network should be able to see that, if configured to receive broadcast packets.  This would be, I think, a UDP packet, so we'd have to configure the nodes to receive those.  Not sure yet if the EZURiO boards can be configured that way...  Looking at the UWScript Programmers Reference Manual (version 0v67, Jan. 2008, for firmware release 6.2.4.0).  

Yep, it looks like it's possible...  We do something akin to the following:
  • slong bc_sock, ret_code
  • string bc_addr, rcv_data
  • bc_addr = _getmybrdaddr$()   ' returns broadcast address string
  • ret_code = _sockudpcreate(bc_sock, 1)     ' 1 = broadcast-capable socket
  • ret_code = _sockconnect(bc_sock, bc_addr)   ' bind socket to broadcast address
  • ret_code = _sockrecv(bc_sock, rcv_data, 0x80, 128)   ' nonblock, maxbytes=128
  • ' lather, rinse, repeat...
Will need to experiment to see if this works.  Meanwhile, on the server side, I can set up a thread that periodically broadcasts a "here I am" UDP packet, say once every second or so.  Going to create a new server module called "broadcaster" to do this.

Now, I just have to figure out how to send a datagram to a broadcast address on the Python side.  I'll probably want to use the low-level "socket" module interface.  There is a setsockopt() option called SO_BROADCAST which looks appropriate.  Let's start writing the new module.

OK, the new module is written, although I'm not yet sure if it will actually work.  Perhaps I should write a test script for the EZURiO to see if I can see the broadcast packets from the server, before I integrate that code into the main autorun script?

OK, that's done and after some fiddling I got it to work.  The test script on the EZURiO (debug statements removed for readability) is:

uword uw_rc
slong bc_sock
slong ret_code
string rcv_data
uword i

uw_rc = _wlanattach("ClaireNet")
ret_code = _sockudpcreate(bc_sock, 1)
ret_code = _sockbind(bc_sock, ":0")
for i = 1 to 1000
ret_code = _sockrecv(bc_sock, rcv_data, 0, 128)
print "Received broadcast packet: [" + rcv_data + "].\n"
next

When run, while the new version of the server is running, we see the following output, about once per second (UDP does not guarantee transmission, so occasionally a packet is missed):

Received broadcast packet: [COSMICi_server host=192.168.0.23\04].
Received broadcast packet: [COSMICi_server host=192.168.0.23\04].
...

That is exactly the string that is being sent once per second by my Broadcaster module.  Thus, we now have the capability for the nodes to discover the server address!  I just need to integrate this code into the autorun script.

Contemplating now that it would really make more sense for the node to broadcast a request to the server when it starts up, requesting the server to broadcast its IP, and then the server wouldn't need to broadcast its IP all the time, but only for a little while after the nodes first start up.  I did another version of my little test script test_bcrcv.uws, this one broadcasts a message "COSMICi,REQ_SRVR_IP", and then it listens for broadcast responses.  Of course, the first "response" it sees is this same message itself (broadcast by itself), but then the second one it sees is an IP broadcast from the server and then it stops waiting for more.  It would be easy to formalize this protocol and build it into the COSMICi_server and the autorun script.

The protocol would be simple:
  • When the server starts, it starts a "DiscoveryResponder" thread that binds to the broadcast address and waits for requests.
  • When the node powers up, after attaching to the wireless LAN, it invokes a module "discovery.uwi" which broadcasts the server IP request, and then reads several messages from the broadcast channel looking for a response.  If it doesn't receive it within a few seconds, it sends the request again, and repeats this a number of times as necessary.
  • Meanwhile, the DiscoveryResponder is waiting for broadcast requests.  When it sees one, it starts the Broadcaster, and keeps broadcasting the server IP for say 10 seconds or so.  Then it suspends or terminates the Broadcaster until it sees another request.  (Well, each time it sees a request, it can push back the end of the broadcast to 10 seconds from now...  That will handle overlapping requests better.)
Only problem: The present version of my code isn't reliably receiving the broadcast packets from the server. Sometimes it works, sometimes it doesn't!  Sometimes, I seem to have to power-cycle the wireless board before it will work.  One time (so far), I seemed to have to disable and re-enable the server's interface card before it started working.  Possibly the DHCP config was messed up, although I wouldn't think that would matter if we're only using broadcast addresses.

No comments:

Post a Comment