-
-
Notifications
You must be signed in to change notification settings - Fork 8
Objects & Data
Objects and data are specific inside of Simple Hydroponics, as they accomplish two different but related things.
Objects, such as actuators and sensors, form the basis of the Hydroponics system definition. It gives all main objects the ability to be:
- Identified by a custom identity object that uniquely identifies it.
- Wrapped in a
shared_ptr
reference for longer-than-current-scope usage to prevent premature deletion. - Attached to other objects, thus forming object chains that define connections, relationships, etc.
- Custom RTTI so that non-RTTI architectures (such as AVR) can perform basic reflection.
- Ability to be updated, resolve dynamic links, alerted to reduce memory consumption, and serialized in and out of storage.
Data, such as system and scheduler data, can be more thought of as the customization options of the system. It gives the system the ability to:
- Identify data chunks by a custom 4-char string (e.g.
HSYS
- which in binary serialization mode is exposed in hex dumps/editors and used as an initial check byte), or custom 4-byte Identity-like storage mechanism (for object storage, including class type used, explained below). - Provide a basic structure that can be easily chunked and serialized in/out of the system through both JSON (via ArduinoJSON) and binary 1:1 streaming (so long as endianness isn't a concern).
- Limit what needs saved so that only the data that is needing to be saved/loaded is saved/loaded (reducing memory fragmentation).
- Tends to pack variant-exclusive data together with the use of union, to reduce memory consumption, be more versatile, as well provide the bare necessity for proper data storage (as opposed to Objects that prefer unpacked data to limit conversions back/forth during operation).
- Custom RTTI so that non-RTTI architectures (such as AVR) can perform basic reflection.
- Basic modified flag, version, and revision tracking capabilities.
Both the Object and Data classes also come with their SubObject and SubData variants. These Sub-variants are expected to be placed inside of parent Object/Data classes (aka composited), and provide a way for those objects to be reused. Triggers are an excellent example of this mechanism, as the Trigger object itself is a SubObject that can live inside of Crops, Reservoirs, etc., if the attachment is available/provided. From there, the Trigger SubData object embeds itself in the Trigger's parent's main Data class, which allows it to piggy-back off its serialization. Since SubData does not contain any virtual methods it can be safely serialized in and out without fancy footwork to get around the virtual table pointer (wee, C++).
The way identity works in Simple Hydroponics is split between Objects and Data. For Objects, each is associated with 4 values: an overall base type enumeration (what it is: actuator, sensor, etc.), object type enumeration (what kind it is: actuator type, sensor type, etc.), position index (to uniquely identify consecutive objects of the same kind), and a class type enumeration (to identify which class runs it). For Data, each is associated with 4-byte character string to identify the kind of data object it is (and, as mentioned, be able to tell what it is when looking at a binary hex dump).
The reason that Identity is split into 4-byte values is to allow the system to not just uniquely identify an object, but also regenerate an entire key-string that then gets assigned to an object to be able to reference it by name. For example, a nutrient premix reservoir may be assigned the key-string "NutrientPremixReservoir1", which would receive the overall ID of 3,2,0,0. This is because Reservoirs are ID type 3 (for Reservoir), NutrientPremix being object type 2 (ReservoirType, in this case), index position 0 (first position, zero-indexed), and then FluidReservoir being class type 0 (which supports the NutrientPremix type).
Note that class type, in the preceding example, is kinda wonky in that the key-string name isn't directly based on it. This means it is a one-way hash - given a key-string the system can locate an object, but without the class type it cannot recreate it properly. This is intentional, as the idea with key-strings is to allow human-readable naming of objects while in more-readable of storage formats (such as JSON), which get resolved to actual objects after being fully loaded via simple hashing.
Additionally, this mechanism also allows us to reverse grab the shared_ptr instance managing any given registered object in the system, if needed, without the burden of additional overhead for storing that in data. This is a well known limitation of shared_ptr
objects that Simple Hydroponics effectively side steps.
To facilitate the use of dynamic/delayed linking during object loading, the system uses a special dynamic link object as a wrapper to the shared_ptr
object. This class essentially just manages an Identity at first, but after load is completed gets notified to resolve its linkage, which establishes the proper shared_ptr
reference and performs any subsequent operations used in object attachment.
These objects otherwise can be treated as pseudo-shared_ptr objects in their usage, but it recommended to instead always go through the Object's get<Whatnot>
methods to ensure proper linkage attachment when necessary.
Brought to you by the generous support of our Patreons. Please consider a subscription if you find this software useful.