SmartData
SmartData is a data class for storing data and controlling data. While designed specifically with qControl and qCommand in mind, it can be used by itself as well. SmartData is a templated class, meaning it takes a type argument and the class has different properties for different types. To use data class, add the following line to the top your program:
#include "smartData.h"
The SmartData class can be broken down into two distinct categories: SmartaData for scalars (i.e. single data types like floats and ints) and SmartData for arrays (a collection of floats or ints). Each type has similar but slightly different behavior.
SmartData for Scalars
SmartData<DataType> Object(DataType init_value);
The above instantiation creates a SmartData object with type DataType
where DataType
can be bool
, uint8_t
,int8_t
, uint16_t
, int16_t
, uint32_t
, int32_t
, float
, double
or any type that reduces to one of those types (char
, int
, uint
). The object has the following member functions:
get
DataType get(void);
This function returns the current value of the underlying datatype.
Example
SmartData<int16_t> Data(34); //initialize SmartData scalar with type int16_t and value of 34
Serial.print(Data.get()); // prints 34
set
void set(DataType dataValue);
The set(DataType)
function sets the value of the SmartData object. Additionally, the sendUpdate function will get called internally when set is run, which tells the Quarto that the data in this object is stale and when qControl queries for new data, the Quarto will send the updated value. This allows qControl to automatically display the latest value of an object whenever the set
command is called.
Example
SmartData<int16_t> Data(34); //initialize SmartData scalar with type int16_t and value of 34
Serial.print(Data.get()); // prints 34
Data.set(15); // sets values to 15
Serial.print(Data.get()); // prints 15
setSetter
void setSetter(DataType(*)(DataType newValue, DataType oldValue));
The setSetter
command sets a custom control function to be called whenever the object's data is about to be updated. This control function can alter the new data value if necessary, before the object is updated. This can be used to coerce values into a range, or force an object to be read-only under certain conditions.
Example
uint16_t limitRange(uint16_t input, uint16_t oldValue) {
if (input > 100 ) {
return 100;
} else if (input < 20) {
return 20;
} else {
return input;
}
}
SmartData<uint16_t> Data(34); //initialize SmartData scalar with type uint16_t and value of 34
Data.setSetter(limitRange);
Data.set(150); // tries to set data to 150, but is limited by limitRange function to 100
Serial.print(Data.get()); // prints 100
Data.get(56); // set data to 56
Serial.print(Data.get()); // prints 56
Data.get(7); // tries to set data to 7, but is limited by limitRange function to 20
Serial.print(Data.get()); // prints 20
sendUpdate
void sendUpdate(void);
The sendUpdate
function is rarely called directly as it is is called automatically when set is called. When called, it flags the SmartData object as stale and when qControl queries the Quarto for new data, the Quarto will send the updated value. This allows qControl to display the latest value of an object.
Smart Data for Arrays
SmartData<DataType*> Object(DataType* dataObject);
Smart Data can also be used to manage an array of data. Unlike with scalar objects, the data array needs to be initialized externally and then SmartData is initialized with a pointer to that data. The DataType
can be any of the types allowed for SmartData for Scalars. Here's an example of how to instantiate both the underlying data array and the SmartData object for that data:
float floatData[100]; //initialize an array of 100 floats
SmartData<float*> Data(floatData); //initialize SmartData with type float* and pointing to the floatData
A SmartData object for arrays has the following member functions that can be called:
In addition to these member functions, the SmartData object also has an internal variable that tracks the index for where the next datapoint in the array can be stored. This index starts at zero (the beginning of the array) and can be changed with the set
and setNext
commands. Additionally, when qControl reads the data in this array, the index is reset back to zero.
get
DataType get(size_t element);
This function takes an argument element
which sets the index from the underling data array to use. The value of the data array at that index is returned.
Example
uint8_t dataArray[4]; //initialize an array of 4 uint8_t
dataArray[0] = 10;
dataArray[1] = 11;
dataArray[2] = 12;
dataArray[3] = 13;
SmartData<uint8_t*> Data(dataArray); //initialize SmartData with type uint8_t* and pointing to the dataArray
Serial.print(Data.get(2)); // prints 12
Serial.print(Data.get(0)); // prints 10
set
void set(DataType dataPoint, size_t element);
This function takes two arguments: the first one, dataPoint
, is the value to set and the second one, element
, is the index in which to store it. In additional to storing the data, it sets the internal index to the next value in the array.
Example
uint8_t dataArray[4]; //initialize an array of 4 uint8_t
SmartData<uint8_t*> Data(dataArray); //initialize SmartData with type uint8_t* and pointing to the dataArray
Data.set(10,0); // set value of 10 at index 0;
Data.set(11,1); // set value of 11 at index 1;
Data.set(12,2); // set value of 12 at index 2;
Data.set(13,3); // set value of 13 at index 3;
Serial.print(Data.get(2)); // prints 12
Serial.print(Data.get(0)); // prints 10
setNext
bool setNext(DataType dataPoint);
setNext
is a simplified version of set
that handles the array index internally. Every time it is called, it stores the data at the location set by the internal index (starting at 0) and increments that index by 1. When the array is full, the function calls sendUpdate and ignores subsequent calls to write to data as the array is full. However, because sendUpdate is called, qControl will query for this data, and when the data is received, the index will get reset. So after the data is read, sendNext
will next update the value and index 0, then index 1 and the process will repeat. sendNext
returns a boolean that is true if data was written to the array and false if it was not. This can be used to wait until the array has been read before updating the data. For applications are can handle data loss between updates, sendUpdate
can simply be run in a loop.
Example
float floatData[4]; // An array of floats will only 4 elements
SmartData<float*> Data(floatData);
Data.setNext(1.23); // set element 0 to 1.23, returns true
Data.setNext(2.34); // set element 1 to 2.34, returns true
Data.setNext(3.45); // set element 2 to 3.45, returns true
Data.setNext(4.56); // set element 3 to 4.56, returns true. Array full, sendUpdate is run
Data.setNext(5.67); // array full, nothing happens, returns false
Data.setNext(6.78); // array full, nothing happens, returns false
// qControl queries Data and display new data: 1.23,2.34,3.45,4.56. Internal index reset to 0.
Data.setNext(7.89); // set element 0 to 7.89, returns true
Data.setNext(8.90); // set element 1 to 8.90, returns true
Data.setNext(9.01); // set element 2 to 9.01, returns true
Data.setNext(10.12); // set element 3 to 10.12, returns true
Data.setNext(11.23); // array full, nothing happens, returns false
Data.setNext(12.34); // array full, nothing happens, returns false
// qControl queries Data and display new data: 7.89, 8.90, 9.01, 10.12
getCurrentElement
size_t getCurrentElement(void);
This function returns the value of the internal index to the array. This value is incremented by setNext and reset to zero when qControl reads the data. It is also set by the set function.
Example
float floatData[4]; // An array of floats will only 4 elements
SmartData<float*> Data(floatData);
Serial.print(Data.getCurrentElement); // returns 0;
Data.setNext(1.23); // set element 0 to 1.23, returns true
Serial.print(Data.getCurrentElement); // returns 1;
Data.setNext(2.34); // set element 1 to 2.34, returns true
Data.setNext(3.45); // set element 2 to 3.45, returns true
Serial.print(Data.getCurrentElement); // returns 3;
Data.setNext(4.56); // set element 3 to 4.56, returns true. Array full, sendUpdate is run
Serial.print(Data.getCurrentElement); // returns 4;
Data.setNext(5.67); // array full, nothing happens, returns false
Serial.print(Data.getCurrentElement); // returns 4;
// qControl queries Data and display new data: 1.23,2.34,3.45,4.56. Internal index reset to 0.
Serial.print(Data.getCurrentElement); // returns 0;
Data.set(8.76,2); // set element 2 to 8.76 and sets index (for next write) to 3
Serial.print(Data.getCurrentElement); // returns 3;
resetCurrentElement
void resetCurrentElement(void);
The current index element will be reset to 0 when resetCurrentElement()
is called.
getTotalElements
size_t getTotalElements(void);
The function returns the number of elements in the array
sendUpdate
void sendUpdate(void);
When called, sendUpdate
flags the SmartData object as stale and when qControl queries the Quarto for new data, the Quarto will send the updated value. The function is automatically called when setNext causes the array to become full. However, when using set to control the array, sendUpdate
will need to be called when the data is to be read by qControl.
isEmpty
bool isEmpty(void);
Simple helper function that returns if the internal index is set to 0. Useful for checking if qControl has queried the data (and reset the index) before writing new data.
isFull
bool isFull(void);
Simpler helper function that returns if the internal index is set to the number of elements in the array. Useful for checking if the array is full and needs to be reset by qControl before writing more data.