Skip to main content

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.