Using Sensor APIs to configure and acquire sensor data
Please follow below steps as a guide to configure and acquire sensor data
1. Get sensor factory
auto &sensorFactory = telux::sensor::SensorFactory::getInstance();
2. Prepare a callback that is invoked when the sensor sub-system initialization is complete
std::promise<telux::common::ServiceStatus> p;
auto initCb = [&p](telux::common::ServiceStatus status) {
std::cout << "Received service status: " << static_cast<int>(status) << std::endl;
p.set_value(status);
};
3. Get the sensor manager. If initialization fails, perform necessary error handling
std::shared_ptr<telux::sensor::ISensorManager> sensorManager
= sensorFactory.getSensorManager(initCb);
if (sensorManager == nullptr) {
std::cout << "sensor manager is nullptr" << std::endl;
exit(1);
}
std::cout << "obtained sensor manager" << std::endl;
4. Wait until initialization is complete
p.get_future().get();
if (sensorManager->getServiceStatus() != telux::common::ServiceStatus::SERVICE_AVAILABLE) {
std::cout << "Sensor service not available" << std::endl;
exit(1);
}
5. Get information regarding available sensors in the system
std::cout << "Sensor service is now available" << std::endl;
std::vector<telux::sensor::SensorInfo> sensorInfo;
telux::common::Status status = sensorManager->getAvailableSensorInfo(sensorInfo);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to get information on available sensors" << static_cast<int>(status)
<< std::endl;
exit(1);
}
std::cout << "Received sensor information" << std::endl;
for (auto info : sensorInfo) {
printSensorInfo(info);
}
6. Request the ISensorManager for the desired sensor
std::shared_ptr<telux::sensor::ISensor> sensor;
std::cout << "Getting sensor: " << name << std::endl;
status = sensorManager->getSensor(sensor, name);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to get sensor: " << name << std::endl;
exit(1);
}
7. Create and register a sensor event listener for configuration updates and sensor events
The event listener extends the ISensorEventListener to receive notification about configuration and sensor events.
class SensorEventListener : public telux::sensor::ISensorEventListener {
public:
SensorEventListener(std::shared_ptr<telux::sensor::ISensor> sensor)
: sensor_(sensor)
, totalBatches_(0) {
}
virtual void onEvent(
std::shared_ptr<std::vector<telux::sensor::SensorEvent>> events) override {
PRINT_NOTIFICATION << ": Received " << events->size()
<< " events from sensor: "
<< sensor_->getSensorInfo().name << std::endl;
for (telux::sensor::SensorEvent s : *(events.get())) {
printSensorEvent(s);
}
++totalBatches_;
if (totalBatches_ > TOTAL_BATCHES_REQUIRED) {
totalBatches_ = 0;
std::thread t([&] {
sensor_->deactivate();
sensor_->configure(sensor_->getConfiguration());
sensor_->activate();
});
t.detach();
}
}
virtual void onConfigurationUpdate(
telux::sensor::SensorConfiguration configuration) override {
PRINT_NOTIFICATION
<< ": Received configuration update from sensor: " << sensor_->getSensorInfo().name
<< ": [" << configuration.samplingRate << ", " << configuration.batchCount << " ]"
<< std::endl;
}
private:
bool isUncalibratedSensor(telux::sensor::SensorType type) {
return ((type == telux::sensor::SensorType::GYROSCOPE_UNCALIBRATED)
|| (type == telux::sensor::SensorType::ACCELEROMETER_UNCALIBRATED));
}
void printSensorEvent(telux::sensor::SensorEvent &s) {
telux::sensor::SensorInfo info = sensor_->getSensorInfo();
if (isUncalibratedSensor(sensor_->getSensorInfo().type)) {
PRINT_NOTIFICATION << ": " << sensor_->getSensorInfo().name << ": " << s.timestamp
<< ", " << s.uncalibrated.data.x << ", " << s.uncalibrated.data.y
<< ", " << s.uncalibrated.data.z << ", " << s.uncalibrated.bias.x
<< ", " << s.uncalibrated.bias.y << ", " << s.uncalibrated.bias.z
<< std::endl;
} else {
PRINT_NOTIFICATION << ": " << sensor_->getSensorInfo().name << ": " << s.timestamp
<< ", " << s.calibrated.x << ", " << s.calibrated.y << ", "
<< s.calibrated.z << std::endl;
}
}
std::shared_ptr<telux::sensor::ISensor> sensor_;
uint32_t totalBatches_;
};
Create a event listener and register it with the sensor.
std::shared_ptr<SensorEventListener> sensorEventListener
= std::make_shared<SensorEventListener>(sensor->getSensorInfo());
sensor->registerListener(sensorEventListener);
8. Configure the sensor with required configuration setting the necessary validityMask
telux::sensor::SensorConfiguration config;
config.samplingRate = getMinimumSamplingRate(sensor->getSensorInfo());
config.batchCount = sensor->getSensorInfo().maxBatchCountSupported;
std::cout << "Configuring sensor with samplingRate, batchCount [" << config.samplingRate << ", "
<< config.batchCount << "]" << std::endl;
config.validityMask.set(telux::sensor::SensorConfigParams::SAMPLING_RATE);
config.validityMask.set(telux::sensor::SensorConfigParams::BATCH_COUNT);
status = sensor->configure(config);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to configure sensor: " << name << std::endl;
exit(1);
}
9. Receive updates on sensor configuration
virtual void onConfigurationUpdate(telux::sensor::SensorConfiguration configuration) override {
PRINT_NOTIFICATION << ": Received configuration update from sensor: " << info_.name << ": ["
<< configuration.samplingRate << ", " << configuration.batchCount << " ]"
<< std::endl;
}
10. Activate the sensor to receive sensor data
status = sensor->activate();
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to activate sensor: " << name << std::endl;
exit(1);
}
11. Receive sensor data with the registered listener
Avoid any time consuming operation in this callback. This thread should be released back the SDK library to avoid latency.
If any sensor APIs need to be called in this method, they should be done on a different thread. One such method is to spawn a detached thread that invokes the required API.
virtual void onEvent(std::shared_ptr<std::vector<telux::sensor::SensorEvent>> events) override {
PRINT_NOTIFICATION << ": Received " << events->size()
<< " events from sensor: " << sensor_->getSensorInfo().name << std::endl;
for (telux::sensor::SensorEvent s : *(events.get())) {
printSensorEvent(s);
}
++totalBatches_;
if (totalBatches_ > TOTAL_BATCHES_REQUIRED) {
totalBatches_ = 0;
std::thread t([&] {
sensor_->deactivate();
sensor_->configure(sensor_->getConfiguration());
sensor_->activate();
});
t.detach();
}
}
12. When data acquisition is no longer necessary, deactivate the sensor
status = sensor->deactivate();
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to deactivate sensor: " << name << std::endl;
exit(1);
}
13. Release the instance of ISensor if no longer required
14. Release the instance of ISensorManager to cleanup resources
Using Sensor APIs to initiate a self test and acquires the self test result
Please follow below steps as a guide to initiate a self test and acquires the self test result
1. Get sensor factory
auto &sensorFactory = telux::sensor::SensorFactory::getInstance();
2. Prepare a callback that is invoked when the sensor sub-system initialization is complete
std::promise<telux::common::ServiceStatus> p;
auto initCb = [&p](telux::common::ServiceStatus status) {
std::cout << "Received service status: " << static_cast<int>(status) << std::endl;
p.set_value(status);
};
3. Get the sensor manager. If initialization fails, perform necessary error handling
std::shared_ptr<telux::sensor::ISensorManager> sensorManager
= sensorFactory.getSensorManager(initCb);
if (sensorManager == nullptr) {
std::cout << "sensor manager is nullptr" << std::endl;
exit(1);
}
std::cout << "obtained sensor manager" << std::endl;
4. Wait until initialization is complete
p.get_future().get();
if (sensorManager->getServiceStatus() != telux::common::ServiceStatus::SERVICE_AVAILABLE) {
std::cout << "Sensor service not available" << std::endl;
exit(1);
}
5. Get information regarding available sensors in the system
std::cout << "Sensor service is now available" << std::endl;
std::vector<telux::sensor::SensorInfo> sensorInfo;
telux::common::Status status = sensorManager->getAvailableSensorInfo(sensorInfo);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to get information on available sensors" << static_cast<int>(status)
<< std::endl;
exit(1);
}
std::cout << "Received sensor information" << std::endl;
for (auto info : sensorInfo) {
printSensorInfo(info);
}
6. Request the ISensorManager for the desired sensor
std::shared_ptr<telux::sensor::ISensor> sensor;
std::cout << "Getting sensor: " << name << std::endl;
status = sensorManager->getSensor(sensor, name);
if (status != telux::common::Status::SUCCESS) {
std::cout << "Failed to get sensor: " << name << std::endl;
exit(1);
}
7. Invoke the self test with the required self test type and provide the callback
status = sensor->selfTest(selfTestType, [](telux::common::ErrorCode result) {
PRINT_CB << "Received self test response: " << static_cast<int>(result) << std::endl;
});
if (status != telux::common::Status::SUCCESS) {
std::cout << "Self test request failed";
} else {
std::cout << "Self test request successful, waiting for callback" << std::endl;
}
8. Release the instance of ISensor if no longer required
9. Release the instance of ISensorManager to cleanup resources