Hello.
Right now we're working on integrating UmTRX support into host UHD code.
The dboard_iface is obviously different from usrp2 and got to be written from scratch (with compatible interfaces if possible).
As for plugging UmTRX into uhd::usrp::multi_usrp - there're several options in here:
1) Add support for UmTRX-specific clock and codec controllers into usrp2_impl with boolean flag to differentiate between USRP2 and UmTRX. 2) Create dedicated "class umtrx_impl : public uhd::device" and implement codec and clock controllers logic in there or inside UmTRX's dboard_iface. 3) Create separate lib/umtrx/* implementation without reuse\adoption of code from lib/usrp2/*
What would be better option and why?
Bear in mind that the final goal is to run OpenBTS+UHD on UmTRX so we're interested only in functions essential to OpenBTS. Though we want to keep changes to the original code as small as possible and still reuse it as much as possible.
On Fri, Feb 10, 2012 at 2:24 PM, Max.Suraev@fairwaves.ru wrote:
As for plugging UmTRX into uhd::usrp::multi_usrp - there're several options in here:
- Add support for UmTRX-specific clock and codec controllers into usrp2_impl with
boolean flag to differentiate between USRP2 and UmTRX. 2) Create dedicated "class umtrx_impl : public uhd::device" and implement codec and clock controllers logic in there or inside UmTRX's dboard_iface. 3) Create separate lib/umtrx/* implementation without reuse\adoption of code from lib/usrp2/*
How messy would option 1 be? Option 2 (or 3) more closely follows the existing UHD model where the shared code is mainly limited to the transport. I think that would be the best approach unless option 1 can be done very cleanly.
What is the difference between option 2 and 3? Does option 2 create a second impl class within the usrp2 directory? I think a separate directory is appropriate.
b100 and usrp1 implementations were created based on copies of existing usrp2 / e100 code without explicit class reuse. For example, b100 / e100 / usrp1 exist separately, but share the same ad9862 codec. There is some copied code between the three codec versions, but that was less messy than creating a unified codec impl for all three.
Thomas
Thank you for prompt reply Thomas. Some additional questions are inline.
11.02.2012 02:00, Thomas Tsou пишет:
How messy would option 1 be? Option 2 (or 3) more closely follows the existing UHD model where the shared code is mainly limited to the transport. I think that would be the best approach unless option 1 can be done very cleanly.
I think we would stick to option 3 (separate umtrx folder) - because it'll become pretty messy over time (essentially every place where clock or codec controller is used requires alteration). Also It seems that with this approach it will be easier to push UMTRX support into upstream once it's mature enough.
What is the difference between option 2 and 3? Does option 2 create a second impl class within the usrp2 directory? I think a separate directory is appropriate.
This brings up another question: where does dispatching happens? E. g. which codepath is used to choose between usrp1, usrp2 and umtrx?
For example If we use option 2 (separate impl file inside usrp2) and treat UmTRX as a special revision of usrp2 than dispatching happens in usrp2_iface.hpp: "enum rev_type" and every time get_rev() is checked.
b100 and usrp1 implementations were created based on copies of existing usrp2 / e100 code without explicit class reuse. For example, b100 / e100 / usrp1 exist separately, but share the same ad9862 codec. There is some copied code between the three codec versions, but that was less messy than creating a unified codec impl for all three.
Is there some technical reason why we can't use something like '#include "../usrp2/io_impl.cpp"' inside /umtrx/umtrx_iface.hpp for example? Or it's purely question of aesthetics?
On Sat, Feb 11, 2012 at 6:47 AM, Max.Suraev@fairwaves.ru wrote:
I think we would stick to option 3 (separate umtrx folder) - because it'll become pretty messy over time (essentially every place where clock or codec controller is used requires alteration). Also It seems that with this approach it will be easier to push UMTRX support into upstream once it's mature enough.
Those are good points. I agree.
This brings up another question: where does dispatching happens? E. g. which codepath is used to choose between usrp1, usrp2 and umtrx?
Each "usrp" has it's own find / make calls that are registered into the "device function registry container" before main(). That occurs with the UHD_STATIC_BLOCK macro, which is basically a memberless, constructor object. When called, the device::find and device::make iterate through the registered find / make tuples. I think 'make' uses the first discovered device if no arguments are passed in.
Is there some technical reason why we can't use something like '#include "../usrp2/io_impl.cpp"' inside /umtrx/umtrx_iface.hpp for example? Or it's purely question of aesthetics?
Not really. For the current Ettus devices, the io_impl.cpp implementations really are different, so it doesn't make any sense.
Thomas
13.02.2012 11:18, Thomas Tsou пишет:
Each "usrp" has it's own find / make calls that are registered into the "device function registry container" before main(). That occurs with the UHD_STATIC_BLOCK macro, which is basically a memberless, constructor object. When called, the device::find and device::make iterate through the registered find / make tuples. I think 'make' uses the first discovered device if no arguments are passed in.
Thanks. It seems to "work" good enough (I mean it crashes in runtime over this and that not yet implemented :)
However there's one thing which still puzzles me:
host/lib/usrp/dboard/db_unknown.cpp contains following:
UHD_STATIC_BLOCK(reg_unknown_dboards) { dboard_manager::register_dboard(0xfff0, &make_unknown_tx, "Unknown TX"); dboard_manager::register_dboard(0xfff1, &make_unknown_rx, "Unknown RX"); }
It's pretty obvious what this code does but where do those _magic_ numbers come from? Should I burn something into particular address in dboard eeprom? Should I override some function to return special values?
Not really. For the current Ettus devices, the io_impl.cpp implementations really are different, so it doesn't make any sense.
That was just example. For instance I do not want to umtrx_iface if I could use usrp2_iface - because devices are rather close I think I can get away with this. Time will tell though.