From: Radu B. R. <ru...@cs...> - 2006-06-29 17:21:01
|
Hi Shawn, You haven't replied to my last e-mail, and although I said I will reply with a longer e-mail (I just re-read my email), I completely forgot about it. So please accept my apologies in that sense. :) I started to work on Javaclient2 again today, to bring it up to date, fix some bugs, and so on, and ran over your e-mail again. Here are my "2 cents" on the matter: Shawn Lavelle wrote: > The problem we've encountered here pertains to requesting > interfaces. At the end of this note I included a copy of > requestGripperInterface for reference. My first question is, what > version of Java this is compiled against and why are generics not used, > or a general requestInterface where you pass in the interface you want? > Since all these functions are identical save for > "PLAYER_<interface>_CODE" or such they could easily be combined into one > method. First, I don't know if that is appropriate, since we want to keep a certain compatibility with the C and C++ clients, which both use the playerc_X_create(client, index)/XProxy cp(client, index) format. But, you're right, since the code is somehow redundant, I included the following in PlayerClient.java: /** * Request a generic device. Don't forget to cast the result to the * appropriate interface type. * @param type the interface type * @param index the device index * @param access access mode * @return a generic device if successful, null otherwise */ public PlayerDevice requestInterface (int type, int index, int access) { requestDeviceAccess (type, index, access); if (isReadyRequestDevice ()) return newpd; else return null; } So, on the user side, this: ... CameraInterface cam = robot.requestInterfaceCamera (0, PlayerConstants.PLAYER_OPEN_MODE); can be replaced by this: ... CameraInterface cam = (CameraInterface)robot.requestInterface(PlayerConstants.PLAYER_CAMERA_CODE, 0, PlayerConstants.PLAYER_OPEN_MODE); Both versions will be available from now, so the user can choose whatever (s)he wants. So thanks for pointing this one out. :) > > The second question is more of a bug and also is of more > consequence. Similar to the referenced post concerning reading, the > two methods requestDeviceAccess and isReadyRequestDevice come > immediately after each other. However, there is no guarantee that stage > has returned the device yet, especially in a resource limited platform. > This call then returns null. Let's assume, for a minute, that the > programmer decides to assume things have succeeded and a request is then > made for a different device. It executes the requestDeviceAccess method > but before isReadyRequestDevice is called, stage returns the first > interface while the 2nd is now delayed. isReadyRequestDevice now > returns true but the wrong interface is stored in newpd. With how this > is coded, the 2nd requestInterface will attempt to cast newpd as the 2nd > interface. This will throw the ClassCastException as newpd contains the > first interface. Okay, I haven't manage to replicate this one, so I might need some help from you (or anyone else who is willing to test and report). But first, let me explain how the mechanism of subscribing to a device works: - client issues a requestInterfaceX () - requestInterfaceX () calls requestDeviceAccess () with the appropriate interface:index and access types - requestDeviceAccess () packs the actual request in XDR-format and it sends it to the Player server. After that, it waits in a loop until the Player replies with an ACK (if NACK then an exception will be generated), by read ()-ing continuously and checking for the message/submessage type. - read() does a bunch of stuff (BTW: some checks like if the header size is smaller than X could be added to prevent using corrupt packets), but when it encounters ACK it checks for the subtype, and if PLAYER_REQ_DEV is found, it will actually add the device to the list by calling requestSatisfy () - in requestSatisfy () the global newpd object gets instantiated with the correct type and after that, in read() readyRequestDevice is set to true - back to the requestInterfaceX (), readyRequestDevice is checked and then the "casted" newpd object is returned to the client It's not the best scheme in the world, but it worked so far (at least I haven't manage to encounter a situation where it didn't - otherwise I would have already fixed it :). But I do see its weaknesses, thus I thought about the following improvements: - when requestDeviceAccess () calls read () it should also transmit the appropriate requested interface type, and the loop should keep on going until read returns ACK (for that interface type)... - requestSatisfy () could return newpd instead of short (which is not used now anyway). This way we stop using a global variable (which is sort of bad anyway). - I am not sure if the requesting of the devices should be done in a very relaxed manner (eg. sending bursts of requests and trying to see which one is which at the client end), but maybe with some small changes (see above), we could reach that point too. Best, Radu. -- | Radu Bogdan Rusu | http://rbrusu.com/ | http://www9.cs.tum.edu/people/rusu/ | Intelligent Autonomous Systems | Technische Universitaet Muenchen |