The Broadcom GLL or GLCT API can accept direct sensor input from a wide variety of raw and processed sources. The GL_EXT_SENS_TYPE lists each type supported.
Multiple sensor data streams are collected into one GlExtSensInfo structure and sent to the GLL or GLCT. Each sensor reading is of type ::SampleValues, a union of several possible data formats.
Each sensor can have different data rates, reporting rates, uncertainties, and data type. Most sensor data arrives at a 1Hz interval. Higher-rate sensor data should be collected at the higher data rate and sent to the GLL as an array of samples at the one Hertz rate. Avoiding measurement lag is very important for good performance.
Uncertainties can be either an RMSE (sigma plus offset), ellipsoid (major axis, minor axis, degrees relative to North), or unused (for state sensors). In the case of an RMSE, the offset is never explicitly passed to the GLL. The driver should remove the offset from the sensor value or should increase the uncertainty (unc.fValue) reported. The uncertainty is of type ::SampleUncertainty.
There are five broad classes of inputs into the GLL:
Device drivers (typically in kernel space) take readings from the sensor hardware to deliver sensor data to the GLL periodically.
Sensor Data Notes
Software output of the GLL are via the GL_FIX_STATUS structure. This includes time, position, heading, speed, and various quality, uncertainty, or uncertainty values.
Hardware output of the GLL is via the 1pps sync pulse. Customer's sensor-related hardware can use this signal as a timing reference. Field GlExtSensData::eSensorTime should be GL_EXT_SENS_TIME_PPS for these cases.
There are three types of state sensors: turn, move, mount. These are GL_TURN_SENSOR_STATE, GL_MOVE_SENSOR_STATE, and GL_MOUNT_SENSOR_STATE. The last received state is assume valid until another state is received. There is an unknown state to indicate either we don't know or the input stream is no longer available. Since these are highly filtered and processed inputs, no uncertainty is required for these sensors so the unc value should be set to UNKNOWN (GLTS_UNKNOWN,GLMS_UNKNOWN,GLMTS_UNKNOWN).
The basic operation is to call GlEngine::SetExtSensData() with a pointer to a GlExtSensInfo.
The GlExtSensInfo points to an array of GlExtSensData. Each entry in the array contains one type of timestamped sensor input.
For example, if you have one pressure reading, two temperature readings, and 10 X-axis gyro samples for the past second, create a GlExtSensData structure for all of them and a convenience pointer to each.
GlExtSensData myThreeSensors[3]; GlExtSensData *baro = myThreeSensors; baro->eSensorType = GL_EXT_SENS_BARO; GlExtSensData *temp = myThreeSensors + 1; temp->eSensorType = GL_EXT_SENS_TEMP; GlExtSensData *gyro = myThreeSensors + 2; gyro->eSensorType = GL_EXT_SENS_GYRO_X;
You'll also need to specify the type of timestamps used for each one:
baro->eSensorTime = GL_EXT_SENS_TIME_UTC; temp->eSensorTime = GL_EXT_SENS_TIME_UTC; gyro->eSensorTime = GL_EXT_SENS_TIME_UTC;
Since we chose UTC-relative timestamps, we must fill in the utcBase:
UTC_TIME utc = {0}; customer_utc_fill(&utc); memcpy(&baro->utcBase, utc, sizeof(utc)); memcpy(&temp->utcBase, utc, sizeof(utc)); memcpy(&gyro->utcBase, utc, sizeof(utc));
Fill in the pressure sample from the current reading:
baro.nNumSamples = 1; GlExtSensSample* pSamp = baro->aSamples; pSamp->sDeltaTime = 0; // we're collecting the sample now! pSamp->v.fValue = read_barometer(); pSamp->unc.fValue = -1.0 // none
Fill in the temperature sample from the past and current readings:
temp->nNumSamples = 2; pSamp = temp.aSamples; pSamp->sDeltaTime = -500; // we collected the temp 1/2 sec ago. pSamp->v.fValue = gf_prior_temp; pSamp->unc.fValue = -1.0 // none ++pSamp; pSamp->sDeltaTime = 0; // we're collecting the sample now! pSamp->v.fValue = read_temperature(); pSamp->unc.fValue = -1.0 // none
This is an artificial example because you'd generally expect to have at least one accelerometer with a gyro, or multiple gyros. For this example, the customer_device_gyro_read() is assumed to maintain a running history of gyro samples and the variance of each sample. It can also generate an array of delta timestamps from when the gyros are read. In this example, the age[] array would most likely be filled in with these values: {-900, -800, -700, -600, .... -200, -100, 0} reflecting the relative age of the gyro samples (and variances). Example code to fill in the gyro samples from a device driver input:
gyro->nNumSamples = 10; pSamp = gyro->aSamples; float raw_gyro[10] = {0}; float variance[10] = {0}; int age[10] = {0}; customer_device_driver_gyro_read(10, &raw_gyro, &age, &variance); for (int i = 0; i < 10; ++pSamp, ++i) { pSamp->sDeltaTime = age[i]; pSamp->v.fValue = raw_gyro[i]; // degrees per second per second. pSamp->unc.fValue = variance[i]; // the gyro driver computes the RMSE. }
Now combine all three sensor streams into one GlExtSensInfo structure.
GlExtSensInfo sensor_info = {0}; sensor_info.sSensNum = 3; sensor_info.pSensData = myThreeSensors;
Send the sensor information to the GlEngine:
GlEngine* pEngine = NULL; // ... pEngine->SetExtSensInfo(&sensor_info);
Or you can send the data to the GLCT:
int GpsHalWaitForEvent(GpsHal* pHal, GPSCTRL_EVENT* potEvent, int iTimeoutMs) { //... if (have_sensor_data) { potEvent->eCode = GLCTEV_PAL_EXT_SENS; potEvent->pData = &sensor_info; return 1; } //... }