On Subject/Service ID ranges

The standard data type set PR that I submitted several days ago might look like a chunk of data that is too big to swallow in one PR. The motivation for pooling all of the items of the new data type set together was to encourage holistic approaches and reduce possible internal inconsistencies.

What we need to agree upon right now is the general structure and not bit-level implementation details. I probably made a mistake by assigning the version number 1 to most of the new data types – @kjetilkjeka was right to point out that some of them should be reverted to v0 pending stabilization. I am going to fix that right away.

Spreading the design process thinly over multiple subsequent PR might cause unnecessary delays, and we know that our design process is a soft real-time process, where delays can be harmful. I suggest we stick with that one PR unless we identified any particular blockers, in which case we can remove them from the PR and discuss separately later (although due to the above reasons that would be undesirable).


Seeing as my freshly coined term “vendor-specific public static” raised some eyebrows (justifiably), I should elaborate on that here.

As has been said elsewhere, the new standard UAVCAN data type set (can we call it “DTS”? yay another three-letter acronym) is not supposed to contain any domain-specific data types, rather it should be focused on very, very generic entities, such as physical quantities. Those should be sufficient to build very generic and flexible yet not very efficient interfaces.

Vendors and OEMs are encouraged to use the generic interfaces everywhere, resorting to vendor-specific data types where higher efficiency is desired. As I see it, there can be two kinds of vendor-specific DTS:

  • Vendor-specific DTS designed for closed ecosystems. For instance, a vendor is building a vehicle or a combination of UAVCAN-interfaced modules which are tightly integrated and are not supposed to interface with any other UAVCAN hardware from any other vendor. This scenario means that the outside world does not care about the DTS defined by the vendor (or OEM, which are the same thing for the purposes of this scenario). I suggest calling such DTS a “vendor-specific private data type set”. It is said to be “private” because no one else is supposed to know or see these definitions because no one else needs to.
  • Vendor-specific DTS designed for COTS equipment or open ecosystems. This is like the above, except that the equipment or vehicles designed by the vendor might need to be interfaced with third-party nodes. I suggest calling these “vendor-specific public data type set”, and I would like to further separate it into two sub-categories:
    • Data type definitions where the Subject or Service ID is assigned statically (i.e., in the name of the DSDL file, such as 123.GetCalibrationData.2.3.uavcan). As the ID is assigned statically, we call them “static”.
    • Data type definitions where the Subject ID is not assigned statically but rather chosen by the integrator or the application designer when configuring the node (perhaps this can be done automatically at some point in a future UAVCAN v1.x). As the ID is chosen at run-time rather than statically, we call these “dynamic”.

Upon closer review of the new concept of Subject and Service ID one might see that the requirement that the static ID to be changeable at runtime becomes unnecessary if we were to avoid assigning static IDs to data types where it might require changing in the first place. Therefore it seems sensible to remove that requirement, thereby declaring that if an ID is assigned statically, it is there to stay as long as the current version of the data type definition is not deprecated. This marginally simplifies implementations and removes a certain degree of uncertainty as integrators will always be certain that all static data types are always assigned a predetermined Subject/Service ID and therefore are always usable without the need for any pre-configuration.

The above has an implication that vendors can no longer define private DTS that contain static Subject/Service IDs, becase if that were the case, definitions from different vendors might conflict with each other and there would be no way of fixing that without modifying the DTS, because, see, the IDs are unchangeable. Public DTS, on the other hand, can rely on static ID as long as they are all centralized in one place, where the lack of collisions can be determined statically. Such centralized maintenance can be achieved by either assigning ID ranges to vendors (which seems wasteful, as the ID spaces are limited), or by keeping all vendor-specific definitions (in their respective namespaces) in one central repository, such as https://github.com/UAVCAN/vendor-specific-dsdl.

If the above reasoning is found sound, we are to end up with the following kinds of DTS:

  • Standard DTS, where identifiers can be static (conflicts are not possible because the set is the same for everyone) or dynamic.
  • Vendor-specific public DTS, where the identifiers can be static (conflicts are avoidable if we keep all definitions in one central repository or assign per-vendor ranges) or dynamic.
  • Vendor-specific private DTS, where the identifiers can be only dynamic, because vendors wouldn’t be able to guarantee collision-free coexistence of their data types.

Extending the ideas towards the ID ranges, we might end up with the following. For Subjects:

From To Purpose
0 0 Reserved for convenience; e.g., to represent an invalid ID
1 32767 Dynamic (assigned by the integrator or the application designer)
61440 62803 Vendor-specific public static, centralized management to avoid conflicts
62804 65535 Standard static

For Services is likewise:

From To Purpose
0 0 Reserved
1 255 Dynamic (assigned by the integrator or the application designer)
256 383 Vendor-specific public static, centralized management to avoid conflicts
384 511 Standard static

Why standard definitions have been moved towards the end of the range: smaller numbers are easier to deal with, so by doing that we simplify the life of the integrator or application designer. The awkward looking range boundaries make more sense if viewed in base-16, e.g., 6144010 = F00016. The Subject ID 62805 used for uavcan.node.Status is of a particular interest, as it contains a long sequence of alternating bits: 6280510 = 11110101010101012 – this is important for automatic bit rate detection in CAN-based networks (I won’t elaborate on this further, that would be out of the scope of this post).

As previously mentioned I want to un-reserve 0 and make it a legal value for port.

Other than that I think we should start lower initially and expand when we have surveyed the user demands. I think more than 30k app specific ports wont be needed, while Vendor-specific is the space where we are going to need every ID we can get. My suggestion follows:

For Subjects:

From To Purpose
0 4095 Application-specific (dynamic) (assigned by the integrator or the application designer)
4096 40959 Intended to grow into “app specific” or “vendor static” when usage patterns are better known
40960 49151 Vendor-specific public static, centralized management to avoid conflicts
49152 62803 Intended to grow into “standard static” or “vendor static” when usage patterns are better known
62804 65535 Standard static

For Services:

From To Purpose
0 127 Application-specific (dynamic) (assigned by the integrator or the application designer)
128 255 Intended to grow into “dynamic” or “vendor static” when usage patterns are better known
256 287 Vendor-specific public static, centralized management to avoid conflicts
288 383 Intended to grow into “standard static” or “vendor static” when usage patterns are better known
384 511 Standard static

I think these ranges give us plenty of IDs to work with initially and allow us to grow all ranges as we see fit.

After the discussion we had on GitHub, yesterday I updated the PR to the following (copypasta):

From To Purpose
0 32767 Dynamic
61440 62803 Vendor-specific public static
62804 65535 Standard static
From To Purpose
0 127 Dynamic
256 383 Vendor-specific public static
384 511 Standard static

I agree with your suggestion except that I would like to keep the initial set of dynamic subject ID intentionally large (30k+ items) to support sophisticated application-specific ID distribution schemes. E.g., dedicated ranges for sensor data, actuator commands, per-subsystem division, and so on. Also 32 vendor-specific public static services might be too restrictive, considering that each new major version is supposed to consume a new static ID. Given that, I offer the following revised scheme:

From To Size Purpose
0 32767 32768 Dynamic
32768 57343 Intended to grow into adjacent ranges
57344 59391 2048 Vendor-specific public static
59392 62803 Intended to grow into adjacent ranges
62804 65535 2731 Standard static
From To Size Purpose
0 127 128 Dynamic
128 255 Intended to grow into adjacent ranges
256 319 64 Vendor-specific public static
320 383 Intended to grow into adjacent ranges
384 511 128 Standard static

One thing I’m struggling with is the term “dynamic”. We’re talking about determining “dynamic” identifiers at system definition time, not (necessarily) runtime; correct? If so then the term really is more used with things that happen at runtime and we should use a different term (e.g. we even have the dynamic node id assignment function). Perhaps static == regulated and dynamic == unregulated?

From To Size Regulated Purpose
0 32767 32768 private use by systems and applications
32768 57343 x Intended to grow into adjacent ranges
57344 59391 2048 x Vendor-specific public
59392 62803 x Intended to grow into adjacent ranges
62804 65535 2731 x Standard

Yes.

I am debating whether we should start saying “plug-and-play” instead.

Makes sense to me.

I agree with Scott, we should change the name to something reflecting that these are really application specific (and may be static or dynamic).

Other than that I’m on board with your updated ranges. :+1: