On 12/04/2013 08:02 PM, Sylvain Joyeux wrote: > On 12/04/2013 02:10 PM, Martin Zenzes wrote: >> - Open more than one "file descriptor" to read and write encoded >> NDLCom Messages as serial data >> - `/dev/ttyUSB0` - profane tty >> - `$IP:port` -- TCP/UDP connections >> - `/dev/can0` -- No CAN in Sherpa, but others use this already >> - `/dev/ndlcom0` -- Custom kernel device from !GumBridge FPGA, >> providing parsed and decoded messages > Keep it simple, and have the class handle only one single I/O (i.e. be > one driver). You can always have a wrapper class on top that does the > I/O-to-deviceId mapping if it is really really needed. This is what I did for a little proof-of-concept -- subclass iodrivers_base::Driver as "ndlcom::Driver", implement extractPacket() there, and subclass this in "ndlcom::Interface" to wrap the encode/decode steps of NDLCom. There, a "sendPacket()" and "readPacket()" is provided to the routing layer in "ndlcom::Communication", which only handles valid, complete ndlcom::Message objects.
> In the same > effect, on the oroGen side, there should be IMO only one task per bus > (i.e. I/O) as well. What is an I/O (or Bus)? You mean to do the "routing" between of multiple Busses on the Orogen-level? This would move the routing code away from the cpp-library and make this whole "ndlcom routing layer" heavily rock-dependent. Not what everyone is looking for... But I see one point: putting everything in one big Task would lead to one process for all the (potentially blocking or slow) read/write systemcalls... Increasing latency... Motors are sending/receiving data with ~100Hz -- Now, some califications on for my initial wording: >> - Provide received Messages which are directed to the own receiverId >> as `ndlcom::Message` at the `readMessage()` function to a caller The "ndlcom::Communication" is supposed to make ndlcom-Messages sent by an STM32 (for example) to the deviceId of the "ndlcom::Communication" available in the "readMessage()" or "readPayload()" function, to be called by the Orogen-level update-hook. >> - Accept `ndlcom::Message` at the `writeMessage()` function to be sent >> to the correct hardware interface Some rock-task (or other calling code, using the cpp-library) calls "writePayload()" or "writeMessage()" in the Orogen-level and it is expected that the resulting ndlcom-Message is then sent at the correct Interface (or Bus) to be received by an STM32 >> - Forward messages not directed at the own deviceId to the correct >> hardware interface Some STM32 should also be able to sent a Message to another STM32, regardless of the structure of the used communication infrastructure. The "ndlcom::Communication" is able to reach every ndlcom-device, and should forward messages _not_ directed at the "ndlcom::Communication". The decision which Interface is used to reach a asked-for device is based on the origin observed messages in the past. If a device has not sent messages to "ndlcom::Communication" before, all interfaces have to be used. The same goes for broadcasts. --- >> - Handle broadcasts: resend the message on all other hardware interfaces >> - Mirror all received and transmitted `ndlcom::Message` as encoded raw >> NDLCom datastream via UDP. This would allow working with an unchanged >> iStruct Gui. This is transitory, for legacy support of the iStruct >> stack. Also easy access of all NDLCom-data without additional rock-code > IMO, you should just make a separate class that "listens" to everything > that goes through the iodrivers_base::Driver (you can add listeners...) > and mirror it to UDP instead of adding that as a core feature of the new > class. Adding the listeners and forward all ndlcom-raw-data 1:1 to the UDP mirror would double forwarded Messages: One STM32 sends a message which is received on /dev/ttyUSB0 and mirrored to the UDP-port. Then the routing-layer sees that the receiver is on /dev/ttyUSB2, and sends the packet that way. It is mirrored again... the UDP-Gui sees the message twice... Using the iodrivers_base::IOListeners to only mirror messages which where read at a hardware-interface, and mirroring the messages sent by the "writeMessage()" or "writePayload()" functions of "ndlcom::Communications" would do the Job? > >> So, after *lotoftext*: This cpp-library is finally to be embedded in a >> Rock-Task, providing the appropriate Rock-Ports and executing the >> needed Hooks. Everything else, mapping certain NDLCom-Payload to >> certain Rock-Types or providing services based on NDLCom Messages, is >> done by other Rock-Tasks. > I would definitely not go for mirroring the MARS design. The Mars design > communicates "behind the scene" between a core component and the > "device" components, constraining the device components to be in the > same process than the core, and in general giving headaches. Yes, I see the "same process" problem. But what do you mean with "general headaches"? What do you mean with "behind the scene"? > > Hopefully for us, there are indeed precedents for this kind of hardware: > the CAN bus integration as well as the Schilling DTS (the last one is > not in Rock proper). But in these, there is only one hardware-Interface (Bus)? NDLCom should have multiple of them. > > The general design there is to split the handling of the protocol between: > - a bus handling component, which represents a given bus and only does > the multiplexing/demultiplexing. It would create one port per deviceId > and only output, on this port, the raw data that is relevant for this > particular device. If your payload is only raw bytes, you could even use > iodrivers_base::RawPacket. Hm Ok. I can see your point, doing it like this. But I would argue that: - Much overhead for single messages? We are expecting around 2000 Messages per second in both directions, to be handled on a 700MHz ARM while still doing the motion control and kinematics... - Also, as said before, this would move all the "routing" into rock... Hence it will not be easily possible to reuse this ndlcom-routing-code outside of rock (standalone gui, bare-metal controller). + This would give multiple threads for handling the read/write systemcalls... > - one component per device, which takes the raw bytes and parse it into > actual data (and, if needed, is able to properly reply/configure/... the > device) One component (this is a rock task?) per device? For 25+ Motors, 10+ Sensorboards? I tought about using one rock-task per data-type, mapping "base/type/JointState" to "BLDCJointTelemetry" for example, with a fixed (configured) map from "rock-device-name" to "ndlcomId". Greetings -- M.Sc. Martin Zenzes Space Robotics Hauptgeschäftsstelle Standort Bremen: DFKI GmbH Robotics Innovation Center Robert-Hooke-Straße 5 28359 Bremen, Germany Phone: +49 (0) 421 178 45 - 6658 Fax: +49 (0) 421 178 45 - 4150 E-Mail: [email protected] Weitere Informationen: http://www.dfki.de/robotik ----------------------------------------------------------------------- Deutsches Forschungszentrum fuer Kuenstliche Intelligenz GmbH Firmensitz: Trippstadter Straße 122, D-67663 Kaiserslautern Geschaeftsfuehrung: Prof. Dr. Dr. h.c. mult. Wolfgang Wahlster (Vorsitzender) Dr. Walter Olthoff Vorsitzender des Aufsichtsrats: Prof. Dr. h.c. Hans A. Aukes Amtsgericht Kaiserslautern, HRB 2313 Sitz der Gesellschaft: Kaiserslautern (HRB 2313) USt-Id.Nr.: DE 148646973 Steuernummer: 19/673/0060/3 ----------------------------------------------------------------------- _______________________________________________ Rock-dev mailing list [email protected] http://www.dfki.de/mailman/cgi-bin/listinfo/rock-dev
