-
-
Notifications
You must be signed in to change notification settings - Fork 3
Objects & Data
Objects and Data are specific inside of Helioduino, as they accomplish two different but related things.
Objects, such as actuators and sensors, form the basis of the controller system. It gives all mainline objects the ability to be:
- Identified by an Identity object that uniquely identifies it.
- Wrapped in a
SharedPtr<>
reference for longer-than-current-scope usage & automatic management of memory allocation/deallocation. - Attachments to other objects, thus forming object chains that define connections, relationships, etc.
- Custom RTTI so that non-RTTI architectures (such as AVR/SAM) can perform basic reflection.
- Ability to be updated, resolve dynamic links, alerted to reduce memory consumption, and serialized in and out of storage.
- Basic modified flag and revision tracking capabilities.
Data, such as system and scheduler data, can be more thought of as the customization options of the system (model data). 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 direct binary.
- 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 run data).
- Custom RTTI so that non-RTTI architectures (such as AVR/SAM) can perform basic reflection.
- Basic modified flag, version, and revision tracking capabilities.
Both the Object and Data classes also come with their own SubObject and SubData variants. These Sub-variants are 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 type that can live inside of parent Object types like Panels, Rails, etc., if the attachment is available/provided. From there, the Trigger SubData object embeds itself in the Trigger's parent's main Data object, which allows it to piggy-back off its serialization.
For mainline Objects, the Identity
class is used to identify an Object, and 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), encoded into object-based Data as a series of 4 integers.
For non-object Data, a 4 character string is used to identify what kind of Data 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 and what class it is, 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 gimballed tracking panel may be assigned the key-string "Gimballed #1", which would be produced from an ID encoding of "2,2,0,1". This is because Panels are base ID type 2 (from Identity), Gimballed being object type 2 (PanelType, in this case), index position 0 (first position, zero-indexed), and then class type 1 (for TrackingPanel).
Note that 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 upon system launch. Additionally, this mechanism also allows us to reverse grab the SharedPtr<>
instance managing any given registered object in the system as needed. This is a well known pain point of SharedPtr<>
usage that the controller effectively handles.
To facilitate the use of dynamic/delayed linking of objects during system load, the system uses a special dynamic link object as a wrapper to the SharedPtr<>
object. This DLinkObject<>
class essentially just manages an Identity at first, but after load is completed and gets notified to resolve its linkage it establishes the proper SharedPtr<>
reference and performs any subsequent attach/detach operations used in object attachment. This attach/detach scenario is what makes up the bulk of the attachment system, and gives it the ability to delay resolve linkages.
Attachment points in this system use the Attachment
class and can be treated as pseudo-SharedPtr objects in their usage, which attach and detach to their linked objects as necessary. Attachments also come with data relevant to their type, so e.g. a SensorAttachment
instance has a copy of the sensor's latest measurement, in the units needed for that attachment to function, while an ActuatorAttachment
instance has its own Activation
object, which is used in signaling actuator enablement and storing activation setup data.
The kinds of system data that is available/can be customized include:
- Operational modes (balancing vs tracking, Imperial vs Metric, etc.)
- System name
- Time zone offset
- Sensor data polling interval
- Autosave interval & fallbacks
- Networking info (wifi password stored encrypted, but not secure)
- System location (for tracking calculations)
TODO
Brought to you by the generous support of our Patreons. Please consider a subscription if you find this software useful.