6#ifndef BNO085_HEADER_INCLUDED
29template <
typename CommType>
31 halWrapper_.comm = &io_;
32 halWrapper_.hal.open = halOpen;
33 halWrapper_.hal.close = halClose;
34 halWrapper_.hal.read = halRead;
35 halWrapper_.hal.write = halWrite;
36 halWrapper_.hal.getTimeUs = halGetTimeUs;
39template <
typename CommType>
44 last_error_ = SH2_ERR_OP_IN_PROGRESS;
48 last_error_ = SH2_ERR_BAD_PARAM;
53 if (!acquireSh2Session()) {
61 int status = sh2_open(halWrapper_.asHal(), asyncCallback,
this);
62 if (status != SH2_OK) {
68 status = sh2_reinitialize();
69 if (status != SH2_OK) {
76 status = sh2_setSensorCallback(sensorCallback,
this);
77 if (status != SH2_OK) {
85 new_flag_.fill(
false);
86 last_interval_.fill(0);
87 last_sensitivity_.fill(0);
99template <
typename CommType>
101 float sensitivity)
noexcept {
103 last_error_ = SH2_ERR_OP_IN_PROGRESS;
106 auto id =
static_cast<uint8_t
>(sensor);
107 if (
id >= last_interval_.size())
109 uint32_t interval_us = interval_ms * 1000;
110 if (!configure(sensor, interval_us, sensitivity, 0))
112 last_interval_[id] = interval_us;
113 last_sensitivity_[id] = sensitivity;
118template <
typename CommType>
121 last_error_ = SH2_ERR_OP_IN_PROGRESS;
124 auto id =
static_cast<uint8_t
>(sensor);
125 if (
id >= last_interval_.size())
127 if (!configure(sensor, 0, 0, 0))
129 last_interval_[id] = 0;
130 last_sensitivity_[id] = 0.0f;
131 new_flag_[id] =
false;
136template <
typename CommType>
142template <
typename CommType>
148template <
typename CommType>
152 auto id =
static_cast<uint8_t
>(sensor);
153 if (
id >= new_flag_.size())
155 return new_flag_[id];
161template <
typename CommType>
163 const sh2_SensorValue_t& val)
const noexcept {
166 out.timestamp = val.timestamp;
167 out.detected =
false;
168 const uint8_t accuracy = val.status & 0x03;
172 out.raw.x = val.un.rawAccelerometer.x;
173 out.raw.y = val.un.rawAccelerometer.y;
174 out.raw.z = val.un.rawAccelerometer.z;
175 out.raw.sensorTimeUs = val.un.rawAccelerometer.timestamp;
178 out.vector.x = val.un.accelerometer.x;
179 out.vector.y = val.un.accelerometer.y;
180 out.vector.z = val.un.accelerometer.z;
181 out.vector.accuracy = accuracy;
184 out.vector.x = val.un.linearAcceleration.x;
185 out.vector.y = val.un.linearAcceleration.y;
186 out.vector.z = val.un.linearAcceleration.z;
187 out.vector.accuracy = accuracy;
190 out.vector.x = val.un.gravity.x;
191 out.vector.y = val.un.gravity.y;
192 out.vector.z = val.un.gravity.z;
193 out.vector.accuracy = accuracy;
196 out.raw.x = val.un.rawGyroscope.x;
197 out.raw.y = val.un.rawGyroscope.y;
198 out.raw.z = val.un.rawGyroscope.z;
199 out.raw.temperature = val.un.rawGyroscope.temperature;
200 out.raw.sensorTimeUs = val.un.rawGyroscope.timestamp;
203 out.vector.x = val.un.gyroscope.x;
204 out.vector.y = val.un.gyroscope.y;
205 out.vector.z = val.un.gyroscope.z;
206 out.vector.accuracy = accuracy;
209 out.vector.x = val.un.gyroscopeUncal.x;
210 out.vector.y = val.un.gyroscopeUncal.y;
211 out.vector.z = val.un.gyroscopeUncal.z;
212 out.vector.accuracy = accuracy;
213 out.bias.x = val.un.gyroscopeUncal.biasX;
214 out.bias.y = val.un.gyroscopeUncal.biasY;
215 out.bias.z = val.un.gyroscopeUncal.biasZ;
218 out.raw.x = val.un.rawMagnetometer.x;
219 out.raw.y = val.un.rawMagnetometer.y;
220 out.raw.z = val.un.rawMagnetometer.z;
221 out.raw.sensorTimeUs = val.un.rawMagnetometer.timestamp;
224 out.vector.x = val.un.magneticField.x;
225 out.vector.y = val.un.magneticField.y;
226 out.vector.z = val.un.magneticField.z;
227 out.vector.accuracy = accuracy;
230 out.vector.x = val.un.magneticFieldUncal.x;
231 out.vector.y = val.un.magneticFieldUncal.y;
232 out.vector.z = val.un.magneticFieldUncal.z;
233 out.vector.accuracy = accuracy;
234 out.bias.x = val.un.magneticFieldUncal.biasX;
235 out.bias.y = val.un.magneticFieldUncal.biasY;
236 out.bias.z = val.un.magneticFieldUncal.biasZ;
239 out.rotation.w = val.un.rotationVector.real;
240 out.rotation.x = val.un.rotationVector.i;
241 out.rotation.y = val.un.rotationVector.j;
242 out.rotation.z = val.un.rotationVector.k;
243 out.rotation.accuracy = accuracy;
246 out.rotation.w = val.un.gameRotationVector.real;
247 out.rotation.x = val.un.gameRotationVector.i;
248 out.rotation.y = val.un.gameRotationVector.j;
249 out.rotation.z = val.un.gameRotationVector.k;
250 out.rotation.accuracy = accuracy;
253 out.rotation.w = val.un.geoMagRotationVector.real;
254 out.rotation.x = val.un.geoMagRotationVector.i;
255 out.rotation.y = val.un.geoMagRotationVector.j;
256 out.rotation.z = val.un.geoMagRotationVector.k;
257 out.rotation.accuracy = accuracy;
260 out.rotation.w = val.un.arvrStabilizedRV.real;
261 out.rotation.x = val.un.arvrStabilizedRV.i;
262 out.rotation.y = val.un.arvrStabilizedRV.j;
263 out.rotation.z = val.un.arvrStabilizedRV.k;
264 out.rotation.accuracy = accuracy;
267 out.rotation.w = val.un.arvrStabilizedGRV.real;
268 out.rotation.x = val.un.arvrStabilizedGRV.i;
269 out.rotation.y = val.un.arvrStabilizedGRV.j;
270 out.rotation.z = val.un.arvrStabilizedGRV.k;
271 out.rotation.accuracy = accuracy;
274 out.rotation.w = val.un.gyroIntegratedRV.real;
275 out.rotation.x = val.un.gyroIntegratedRV.i;
276 out.rotation.y = val.un.gyroIntegratedRV.j;
277 out.rotation.z = val.un.gyroIntegratedRV.k;
278 out.rotation.accuracy = accuracy;
279 out.angularVelocity.x = val.un.gyroIntegratedRV.angVelX;
280 out.angularVelocity.y = val.un.gyroIntegratedRV.angVelY;
281 out.angularVelocity.z = val.un.gyroIntegratedRV.angVelZ;
284 out.scalar = val.un.pressure.value;
287 out.scalar = val.un.ambientLight.value;
290 out.scalar = val.un.humidity.value;
293 out.scalar = val.un.proximity.value;
296 out.scalar = val.un.temperature.value;
299 out.latencyUs = val.un.stepDetector.latency;
304 out.latencyUs = val.un.stepCounter.latency;
305 out.stepCount = val.un.stepCounter.steps;
308 out.eventFlags = val.un.sigMotion.motion;
309 out.detected = out.eventFlags != 0;
312 out.classification = val.un.stabilityClassifier.classification;
315 out.eventFlags = val.un.tapDetector.flags;
316 out.tap.doubleTap = (val.un.tapDetector.flags & TAPDET_DOUBLE);
317 if (val.un.tapDetector.flags & TAPDET_X)
318 out.tap.direction = (val.un.tapDetector.flags & TAPDET_X_POS) ? 0 : 1;
319 else if (val.un.tapDetector.flags & TAPDET_Y)
320 out.tap.direction = (val.un.tapDetector.flags & TAPDET_Y_POS) ? 2 : 3;
321 else if (val.un.tapDetector.flags & TAPDET_Z)
322 out.tap.direction = (val.un.tapDetector.flags & TAPDET_Z_POS) ? 4 : 5;
324 out.tap.direction = 0;
325 out.detected = val.un.tapDetector.flags & (TAPDET_X | TAPDET_Y | TAPDET_Z);
328 out.eventFlags = val.un.shakeDetector.shake;
329 out.detected = out.eventFlags != 0;
332 out.eventFlags = val.un.flipDetector.flip;
333 out.detected = out.eventFlags != 0;
336 out.eventFlags = val.un.pickupDetector.pickup;
337 out.detected = out.eventFlags != 0;
340 out.eventFlags = val.un.stabilityDetector.stability;
341 out.detected = out.eventFlags != 0;
344 out.activity.page = val.un.personalActivityClassifier.page;
345 out.activity.lastPage = val.un.personalActivityClassifier.lastPage;
346 out.activity.mostLikelyState = val.un.personalActivityClassifier.mostLikelyState;
347 for (std::size_t i = 0; i < out.activity.confidence.size(); ++i) {
348 out.activity.confidence[i] = val.un.personalActivityClassifier.confidence[i];
350 out.classification = out.activity.mostLikelyState;
353 out.sleepState = val.un.sleepDetector.sleepState;
354 out.detected = out.sleepState != 0;
357 out.eventFlags = val.un.tiltDetector.tilt;
358 out.detected = out.eventFlags != 0;
361 out.eventFlags = val.un.pocketDetector.pocket;
362 out.detected = out.eventFlags != 0;
365 out.eventFlags = val.un.circleDetector.circle;
366 out.detected = out.eventFlags != 0;
369 out.scalar =
static_cast<float>(val.un.heartRateMonitor.heartRate);
372 out.motionIntent =
static_cast<uint8_t
>(val.un.izroRequest.intent);
373 out.motionRequest =
static_cast<uint8_t
>(val.un.izroRequest.request);
376 out.rawOpticalFlow.timestamp = val.un.rawOptFlow.timestamp;
377 out.rawOpticalFlow.dt = val.un.rawOptFlow.dt;
378 out.rawOpticalFlow.dx = val.un.rawOptFlow.dx;
379 out.rawOpticalFlow.dy = val.un.rawOptFlow.dy;
380 out.rawOpticalFlow.iq = val.un.rawOptFlow.iq;
381 out.rawOpticalFlow.resX = val.un.rawOptFlow.resX;
382 out.rawOpticalFlow.resY = val.un.rawOptFlow.resY;
383 out.rawOpticalFlow.shutter = val.un.rawOptFlow.shutter;
384 out.rawOpticalFlow.frameMax = val.un.rawOptFlow.frameMax;
385 out.rawOpticalFlow.frameAvg = val.un.rawOptFlow.frameAvg;
386 out.rawOpticalFlow.frameMin = val.un.rawOptFlow.frameMin;
387 out.rawOpticalFlow.laserOn = val.un.rawOptFlow.laserOn;
390 out.deadReckoningPose.timestamp = val.un.deadReckoningPose.timestamp;
391 out.deadReckoningPose.linearPosition.x = val.un.deadReckoningPose.linPosX;
392 out.deadReckoningPose.linearPosition.y = val.un.deadReckoningPose.linPosY;
393 out.deadReckoningPose.linearPosition.z = val.un.deadReckoningPose.linPosZ;
394 out.deadReckoningPose.rotation.w = val.un.deadReckoningPose.real;
395 out.deadReckoningPose.rotation.x = val.un.deadReckoningPose.i;
396 out.deadReckoningPose.rotation.y = val.un.deadReckoningPose.j;
397 out.deadReckoningPose.rotation.z = val.un.deadReckoningPose.k;
398 out.deadReckoningPose.linearVelocity.x = val.un.deadReckoningPose.linVelX;
399 out.deadReckoningPose.linearVelocity.y = val.un.deadReckoningPose.linVelY;
400 out.deadReckoningPose.linearVelocity.z = val.un.deadReckoningPose.linVelZ;
401 out.deadReckoningPose.angularVelocity.x = val.un.deadReckoningPose.angVelX;
402 out.deadReckoningPose.angularVelocity.y = val.un.deadReckoningPose.angVelY;
403 out.deadReckoningPose.angularVelocity.z = val.un.deadReckoningPose.angVelZ;
406 out.wheelEncoder.timestamp = val.un.wheelEncoder.timestamp;
407 out.wheelEncoder.wheelIndex = val.un.wheelEncoder.wheelIndex;
408 out.wheelEncoder.dataType = val.un.wheelEncoder.dataType;
409 out.wheelEncoder.data = val.un.wheelEncoder.data;
420template <
typename CommType>
426 const auto id =
static_cast<uint8_t
>(sensor);
427 if (
id >= latest_.size())
429 out = toSensorEvent(sensor, latest_[
id]);
430 new_flag_[id] =
false;
435template <
typename CommType>
443template <
typename CommType>
446 last_error_ = SH2_ERR_OP_IN_PROGRESS;
461 new_flag_.fill(
false);
462 last_interval_.fill(0);
463 last_sensitivity_.fill(0.0f);
467template <
typename CommType>
469 const void* expected =
nullptr;
475template <
typename CommType>
477 const void* expected =
this;
484template <
typename CommType>
486 auto* t =
reinterpret_cast<CommHal*
>(self);
487 return t->comm->Open() ? SH2_OK : SH2_ERR;
491template <
typename CommType>
493 reinterpret_cast<CommHal*
>(self)->comm->
Close();
497template <
typename CommType>
499 auto* th =
reinterpret_cast<CommHal*
>(self);
500 int ret = th->comm->Read(buf, len);
501 *t = th->comm->GetTimeUs();
506template <
typename CommType>
508 return reinterpret_cast<CommHal*
>(self)->comm->Write(buf, len);
512template <
typename CommType>
514 return reinterpret_cast<CommHal*
>(self)->comm->GetTimeUs();
520template <
typename CommType>
526template <
typename CommType>
537template <
typename CommType>
539 sh2_SensorValue_t value;
540 int decode_status = sh2_decodeSensorEvent(&value, event);
541 if (decode_status != SH2_OK) {
542 last_error_ = decode_status;
545 uint8_t
id = value.sensorId;
546 if (
id >= latest_.size())
549 new_flag_[id] =
true;
551 callback_(toSensorEvent(
static_cast<BNO085Sensor>(
id), value));
561template <
typename CommType>
563 if (event->eventId == SH2_RESET) {
564 for (uint8_t
id = 0;
id < last_interval_.size(); ++id) {
565 if (last_interval_[
id])
566 configure(
static_cast<BNO085Sensor>(
id), last_interval_[
id], last_sensitivity_[
id], 0);
580template <
typename CommType>
582 uint32_t batch_us)
noexcept {
583 sh2_SensorConfig_t cfg{};
584 cfg.reportInterval_us = interval_us;
585 cfg.batchInterval_us = batch_us;
586 cfg.sensorSpecific = 0;
587 const float clamped_sensitivity = std::clamp(sensitivity, 0.0f, 65535.0f);
588 cfg.changeSensitivity =
static_cast<uint16_t
>(clamped_sensitivity + 0.5f);
589 cfg.changeSensitivityEnabled = clamped_sensitivity > 0.0f;
590 int status = sh2_setSensorConfig(
static_cast<sh2_SensorId_t
>(sensor), &cfg);
591 if (status != SH2_OK) {
592 last_error_ = status;
609template <
typename CommType>
626template <
typename CommType>
629 if (!setPin(CtrlPin::RSTN,
true)) {
633 if (!setPin(CtrlPin::RSTN,
false)) {
636 io_.Delay(RESET_STARTUP_MS);
641template <
typename CommType>
647template <
typename CommType>
650 last_error_ = SH2_ERR_BAD_PARAM;
654 last_error_ = SH2_ERR_OP_IN_PROGRESS;
661 last_error_ = SH2_ERR_OP_IN_PROGRESS;
666 last_error_ = SH2_ERR;
672 if (!ok || !released) {
674 last_error_ = SH2_ERR_IO;
680 last_error_ = SH2_OK;
685template <
typename CommType>
688 last_error_ = SH2_ERR_BAD_PARAM;
692 last_error_ = SH2_ERR_OP_IN_PROGRESS;
699 last_error_ = SH2_ERR_OP_IN_PROGRESS;
704 last_error_ = SH2_ERR;
710 last_error_ = SH2_ERR_IO;
716 last_error_ = SH2_OK;
721template <
typename CommType>
735template <
typename CommType>
738 const auto bits =
static_cast<uint8_t
>(iface);
742 const bool ps1 = setPin(CtrlPin::PS1, (bits & 0x2U) != 0);
743 const bool ps0 = setPin(CtrlPin::PS0, (bits & 0x1U) != 0);
773template <
typename CommType>
778 last_error_ = SH2_ERR_OP_IN_PROGRESS;
782 last_error_ = SH2_ERR_BAD_PARAM;
786 last_error_ = SH2_ERR;
789 last_error_ = SH2_OK;
802template <
typename CommType>
807 while (io_.Read(&c, 1) == 1) {
813template <
typename CommType>
832template <
typename CommType>
834 if (rvc_frame_len_ == RVC_FRAME_LEN_) {
835 std::memmove(rvc_frame_, rvc_frame_ + 1, RVC_FRAME_LEN_ - 1);
836 rvc_frame_[RVC_FRAME_LEN_ - 1] = c;
838 rvc_frame_[rvc_frame_len_++] = c;
841 if (rvc_frame_len_ == RVC_FRAME_LEN_ && rvc_frame_[0] == 0xAA && rvc_frame_[1] == 0xAA) {
843 for (
int i = 2; i < RVC_FRAME_LEN_ - 1; ++i)
844 check += rvc_frame_[i];
846 if (check == rvc_frame_[RVC_FRAME_LEN_ - 1]) {
849 event.index = rvc_frame_[2];
850 event.yaw =
static_cast<int16_t
>((rvc_frame_[4] << 8) | rvc_frame_[3]);
851 event.pitch =
static_cast<int16_t
>((rvc_frame_[6] << 8) | rvc_frame_[5]);
852 event.roll =
static_cast<int16_t
>((rvc_frame_[8] << 8) | rvc_frame_[7]);
853 event.acc_x =
static_cast<int16_t
>((rvc_frame_[10] << 8) | rvc_frame_[9]);
854 event.acc_y =
static_cast<int16_t
>((rvc_frame_[12] << 8) | rvc_frame_[11]);
855 event.acc_z =
static_cast<int16_t
>((rvc_frame_[14] << 8) | rvc_frame_[13]);
856 event.mi = rvc_frame_[15];
857 event.mr = rvc_frame_[16];
861 decodeRvc(&val, &event);
875template <
typename CommType>
877 out->index = in->index;
878 out->yaw_deg = 0.01f * in->yaw;
879 out->pitch_deg = 0.01f * in->pitch;
880 out->roll_deg = 0.01f * in->roll;
881 out->acc_x_g = 0.001f * in->acc_x;
882 out->acc_y_g = 0.001f * in->acc_y;
883 out->acc_z_g = 0.001f * in->acc_z;
886 out->timestamp_uS = in->timestamp_uS;
906static constexpr uint8_t DFU_ACK =
's';
907static constexpr uint32_t DFU_MAX_PACKET_LEN = 64;
908static constexpr uint32_t DFU_MAX_ATTEMPTS = 5;
909static constexpr uint32_t DFU_DELAY_POST_US = 10000;
910static constexpr uint32_t DFU_SEND_TIMEOUT_US = 100000;
913template <
typename CommType>
917 return std::strcmp(part,
"1000-3608") == 0 || std::strcmp(part,
"1000-3676") == 0 ||
918 std::strcmp(part,
"1000-4148") == 0 || std::strcmp(part,
"1000-4563") == 0;
922template <
typename CommType>
924 *buf++ = (value >> 24) & 0xFF;
925 *buf++ = (value >> 16) & 0xFF;
926 *buf++ = (value >> 8) & 0xFF;
927 *buf++ = (value >> 0) & 0xFF;
931template <
typename CommType>
933 uint16_t crc = 0xFFFF;
934 for (
int n = 0; n < len; n++) {
935 uint16_t x =
static_cast<uint16_t
>(packet[n]) << 8;
936 for (
int i = 0; i < 8; i++) {
937 if ((crc ^ x) & 0x8000)
938 crc = (crc << 1) ^ 0x1021;
944 packet[len] = (crc >> 8) & 0xFF;
945 packet[len + 1] = crc & 0xFF;
956template <
typename CommType>
958 unsigned int retries = 0;
961 bool got_ack =
false;
963 sh2_Hal_t* hal = halWrapper_.asHal();
965 while (!got_ack && (retries < DFU_MAX_ATTEMPTS)) {
966 uint32_t now = hal->getTimeUs(hal);
967 uint32_t start = now;
969 while ((status == 0) && ((now - start) < DFU_SEND_TIMEOUT_US)) {
970 status = hal->write(hal, p_data, len);
971 now = hal->getTimeUs(hal);
974 status = SH2_ERR_TIMEOUT;
977 while ((status == 0) && ((now - start) < DFU_SEND_TIMEOUT_US)) {
978 status = hal->read(hal, &ack, 1, &t);
979 now = hal->getTimeUs(hal);
982 status = SH2_ERR_TIMEOUT;
985 if (ack == DFU_ACK) {
990 status = SH2_ERR_HUB;
996 return (status >= 0) ? SH2_OK : status;
1000template <
typename CommType>
1002 dfuWrite32be(dfu_buff, app_size);
1003 dfuAppendCrc(dfu_buff, 4);
1004 return dfuSend(dfu_buff, 6);
1008template <
typename CommType>
1010 dfu_buff[0] = packet_len;
1011 dfuAppendCrc(dfu_buff, 1);
1012 return dfuSend(dfu_buff, 3);
1016template <
typename CommType>
1018 std::memcpy(dfu_buff, p_data, len);
1019 dfuAppendCrc(dfu_buff, len);
1020 return dfuSend(dfu_buff, len + 2);
1033template <
typename CommType>
1038 appAddress = io_.GetI2cAddress();
1039 const uint8_t boot = BootloaderI2cAddress(appAddress);
1041 return SH2_ERR_BAD_PARAM;
1043 if (boot == appAddress) {
1046 if (!io_.SetI2cAddress(boot)) {
1055template <
typename CommType>
1058 return io_.SetI2cAddress(appAddress);
1066template <
typename CommType>
1069 return DfuWithOptions(fw, options);
1073template <
typename CommType>
1076 if (!image.data || image.length == 0) {
1077 last_error_ = SH2_ERR_BAD_PARAM;
1078 return SH2_ERR_BAD_PARAM;
1080 MemoryFirmware memfw(image.data, image.length, image.format ? image.format :
"BNO_V1",
1081 image.partNumber ? image.partNumber :
"unknown", image.preferredPacketLen);
1082 return DfuWithOptions(memfw.hcbin(), options);
1086template <
typename CommType>
1092 image.partNumber = partNumber ? partNumber :
"unknown";
1093 return DfuFromMemory(image, options);
1097template <
typename CommType>
1099 uint32_t enterResetLowMs, uint32_t enterSettleMs,
1100 uint32_t exitResetLowMs, uint32_t exitSettleMs)
noexcept {
1101 if (!EnterBootloader(enterResetLowMs, enterSettleMs))
1104 int status = DfuFromMemory(image, options);
1105 const int dfu_status = status;
1106 if (!ExitBootloaderAndReboot(exitResetLowMs, exitSettleMs) && status == SH2_OK) {
1108 status = last_error_;
1111 if (dfu_status != SH2_OK) {
1124template <
typename CommType>
1127 last_error_ = SH2_ERR_BAD_PARAM;
1128 return SH2_ERR_BAD_PARAM;
1131 last_error_ = SH2_ERR_OP_IN_PROGRESS;
1132 return SH2_ERR_OP_IN_PROGRESS;
1139 last_error_ = SH2_ERR_OP_IN_PROGRESS;
1140 return SH2_ERR_OP_IN_PROGRESS;
1143 prepareHalWrapper();
1145 int rc, status = SH2_OK;
1146 uint32_t app_len = 0;
1147 uint8_t packet_len = 0;
1148 uint32_t offset = 0;
1149 const char* meta =
nullptr;
1150 bool fw_opened =
false;
1151 bool hal_opened =
false;
1152 uint8_t app_address = 0;
1153 bool address_switched =
false;
1154 uint8_t dfu_buff[DFU_MAX_PACKET_LEN + 2];
1155 sh2_Hal_t* hal = halWrapper_.asHal();
1164 if (options.requireFormatMatch) {
1165 const char* expected_format = options.requiredFormat ? options.requiredFormat :
"BNO_V1";
1166 meta = fw.getMeta(
"FW-Format");
1167 if (!meta || std::strcmp(meta, expected_format) != 0) {
1168 status = SH2_ERR_BAD_PARAM;
1173 if (options.requirePartNumber) {
1174 meta = fw.getMeta(
"SW-Part-Number");
1176 status = SH2_ERR_BAD_PARAM;
1179 if (options.requiredPartNumber) {
1180 if (std::strcmp(meta, options.requiredPartNumber) != 0) {
1181 status = SH2_ERR_BAD_PARAM;
1184 }
else if (!dfuIsKnownPartNumber(meta)) {
1185 status = SH2_ERR_BAD_PARAM;
1190 app_len = fw.getAppLen();
1191 if (app_len < 1024) {
1192 status = SH2_ERR_BAD_PARAM;
1196 packet_len = fw.getPacketLen();
1197 if (options.packetLenOverride != 0) {
1198 packet_len = options.packetLenOverride;
1200 if (packet_len == 0 || packet_len > DFU_MAX_PACKET_LEN)
1201 packet_len = DFU_MAX_PACKET_LEN;
1205 status = dfuSelectBootloaderAddress(app_address, address_switched);
1206 if (status != SH2_OK)
1210 status = hal->open(hal);
1211 if (status != SH2_OK)
1215 status = dfuSendAppSize(dfu_buff, app_len);
1216 if (status != SH2_OK)
1218 status = dfuSendPktSize(dfu_buff, packet_len);
1219 if (status != SH2_OK)
1222 if (options.progress) {
1227 while (offset < app_len) {
1228 uint32_t to_send = app_len - offset;
1229 if (to_send > packet_len)
1230 to_send = packet_len;
1231 status = fw.getAppData(dfu_buff, offset, to_send);
1232 if (status != SH2_OK) {
1236 status = dfuSendPkt(dfu_buff, dfu_buff, to_send);
1237 if (status != SH2_OK)
1240 if (options.progress) {
1248 if (status == SH2_OK && hal_opened) {
1249 uint32_t now = hal->getTimeUs(hal), start = now;
1250 while ((now - start) < DFU_DELAY_POST_US)
1251 now = hal->getTimeUs(hal);
1255 if (address_switched && !dfuRestoreAppAddress(app_address) && status == SH2_OK)
1256 status = SH2_ERR_IO;
1260 last_error_ = status;
High-level C++ driver for the BNO08x 9-axis IMU family.
constexpr int BNO08X_ERR_SH2_SESSION_IN_USE
GetLastError() value when Begin() is refused because another BNO085 object already holds the SH-2 ses...
Definition bno08x.hpp:33
BNO085Interface
Identifies the host interface type that a CommInterface provides.
Definition bno08x_comm_interface.hpp:27
@ UARTRVC
UART in RVC mode (PS1=0, PS0=1). RVC frames only.
@ I2C
I2C bus (PS1=0, PS0=0). Supports SH-2 and DFU.
Unified driver for the BNO08x IMU – SH-2 mode, RVC mode, and DFU.
Definition bno08x.hpp:400
int DfuWithOptions(const HcBin_t &fw, const DfuOptions &options) noexcept
Perform DFU with explicit validation and transfer options.
Definition bno08x.ipp:1125
bool DisableSensor(BNO085Sensor sensor) noexcept
Disable reporting for a sensor.
Definition bno08x.ipp:119
bool SetBootPin(bool state) noexcept
Drive the BOOTN pin to enter/exit DFU bootloader mode.
Definition bno08x.ipp:642
bool BeginRvc() noexcept
Initialise RVC mode.
Definition bno08x.ipp:774
bool HasNewData(BNO085Sensor sensor) const
Check if new data is available for a sensor.
Definition bno08x.ipp:149
SensorEvent GetLatest(BNO085Sensor sensor) noexcept
Retrieve the most recent event for a sensor.
Definition bno08x.ipp:421
bool EnableSensor(BNO085Sensor sensor, uint32_t interval_ms, float sensitivity=0.0f) noexcept
Enable periodic reporting for a sensor.
Definition bno08x.ipp:100
void ServiceRvc() noexcept
Poll for RVC frames and dispatch callbacks.
Definition bno08x.ipp:803
void SetCallback(SensorCallback cb) noexcept
Register a callback for SH-2 sensor events.
Definition bno08x.ipp:137
void CloseRvc() noexcept
Stop RVC processing and close the transport.
Definition bno08x.ipp:814
int DfuFromMemory(const DfuMemoryImage &image, const DfuOptions &options={}) noexcept
Perform DFU from an in-memory firmware image.
Definition bno08x.ipp:1074
void Update() noexcept
Pump the SH-2 service loop.
Definition bno08x.ipp:436
int RunDfuFromMemory(const DfuMemoryImage &image, const DfuOptions &options={}, uint32_t enterResetLowMs=10, uint32_t enterSettleMs=50, uint32_t exitResetLowMs=2, uint32_t exitSettleMs=100) noexcept
Full class-aware DFU workflow: enter bootloader -> transfer firmware -> reboot to app.
Definition bno08x.ipp:1098
void Close() noexcept
Close the currently active session and release transport resources.
Definition bno08x.ipp:444
int Dfu(const HcBin_t &fw=firmware) noexcept
Perform a Device Firmware Update (DFU).
Definition bno08x.ipp:1067
bool Begin() noexcept
Initialise the sensor in SH-2 mode.
Definition bno08x.ipp:40
bool EnterBootloader(uint32_t resetLowMs=10, uint32_t settleMs=50) noexcept
Enter bootloader mode using BOOTN + reset pin sequence.
Definition bno08x.ipp:648
bool SetWakePin(bool state) noexcept
Drive the WAKE pin (SPI mode only).
Definition bno08x.ipp:722
bool ExitBootloaderAndReboot(uint32_t resetLowMs=2, uint32_t settleMs=100) noexcept
Exit bootloader mode and reboot into application firmware.
Definition bno08x.ipp:686
bool SelectInterface(BNO085Interface iface) noexcept
Select the host interface by driving PS0/PS1 pins.
Definition bno08x.ipp:736
bool HardwareReset(uint32_t lowMs=2) noexcept
Perform a hardware reset via the RSTN pin.
Definition bno08x.ipp:627
void SetRvcCallback(RvcCallback cb) noexcept
Register a callback for decoded RVC frames.
Definition bno08x.ipp:143
HcBin_t implementation for firmware stored in memory.
Definition MemoryFirmware.hpp:16
std::function< void(const RvcSensorValue &)> RvcCallback
Callback invoked when a decoded RVC frame is available.
Definition bno08x.hpp:299
BNO085Sensor
Identifiers for all SH-2 sensor reports supported by the BNO08x.
Definition bno08x.hpp:70
std::function< void(const SensorEvent &)> SensorCallback
Callback invoked when a new SH-2 sensor event is received.
Definition bno08x.hpp:296
@ HeartRateMonitor
Heart rate data.
@ MagneticFieldUncalibrated
Raw magnetic field (uT)
@ GyroUncalibrated
Raw angular velocity (rad/s)
@ PersonalActivityClassifier
Activity classification (walking, running, etc.)
@ StepDetector
Individual step detected.
@ ShakeDetector
Shake gesture detected.
@ PickupDetector
Pickup gesture detected.
@ ARVRStabilizedRV
AR/VR stabilised rotation vector.
@ CircleDetector
Circular motion detected.
@ IZroMotionRequest
Interactive ZRO motion intent/request.
@ RawOpticalFlow
Raw optical flow report.
@ GeomagneticRotationVector
Orientation using magnetometer for heading.
@ FlipDetector
Flip gesture detected.
@ StepCounter
Cumulative step count.
@ Gravity
Gravity vector (m/s^2)
@ SleepDetector
Sleep state detected.
@ WheelEncoder
Wheel encoder report.
@ RotationVector
Fused absolute orientation quaternion.
@ SignificantMotion
Significant motion detected.
@ AmbientLight
Ambient light level (lux)
@ Magnetometer
Calibrated magnetic field (uT)
@ TiltDetector
Tilt event detected.
@ RawMagnetometer
Raw magnetometer ADC counts.
@ TapDetector
Single or double tap event.
@ Pressure
Barometric pressure (hPa)
@ StabilityClassifier
Device stability state (on table, in hand, etc.)
@ Accelerometer
Calibrated acceleration vector (m/s^2)
@ LinearAcceleration
Acceleration minus gravity (m/s^2)
@ Gyroscope
Calibrated angular velocity (rad/s)
@ StabilityDetector
Stability change detected.
@ GyroIntegratedRV
High-rate gyro-integrated rotation vector.
@ GameRotationVector
Orientation without magnetometer heading.
@ RawAccelerometer
Raw accelerometer ADC counts.
@ ARVRStabilizedGameRV
AR/VR stabilised game rotation vector.
@ Humidity
Relative humidity (%)
@ DeadReckoningPose
Dead reckoning pose estimate.
@ Temperature
Temperature (deg C)
@ RawGyroscope
Raw gyroscope ADC counts.
@ Proximity
Proximity detector (cm)
@ PocketDetector
Device-in-pocket detected.
std::atomic< const void * > & Sh2SessionOwner() noexcept
Owner of the process-wide SH-2 session (nullptr when free).
Definition bno08x.hpp:42
constexpr bool kGpioSetReportsStatus
True when the port's GpioSet() reports a status (returns bool).
Definition bno08x_comm_interface.hpp:90
bool GpioSet(Port &port, CtrlPin pin, GpioSignal signal) noexcept
Call the port's GpioSet() and return its status.
Definition bno08x_comm_interface.hpp:102
CtrlPin
Identifies the hardware control pins of the BNO08x.
Definition bno08x_comm_interface.hpp:60
@ BOOTN
Bootloader entry (active-low on the physical pin)
@ WAKE
Wake from suspend, SPI mode only (active-low on the physical pin)
GpioSignal
Abstract signal level for control pins.
Definition bno08x_comm_interface.hpp:76
@ ACTIVE
Pin function is asserted.
@ INACTIVE
Pin function is deasserted.
Firmware image descriptor for class-aware memory DFU.
Definition bno08x.hpp:342
const uint8_t * data
Pointer to firmware bytes.
Definition bno08x.hpp:343
Controls DFU validation and transfer behavior.
Definition bno08x.hpp:329
Progress sample emitted during DFU transfers.
Definition bno08x.hpp:317
Raw RVC frame data in integer fixed-point format.
Definition bno08x.hpp:261
uint64_t timestamp_uS
Timestamp in microseconds (set by the driver)
Definition bno08x.hpp:271
Decoded RVC frame data in floating-point natural units.
Definition bno08x.hpp:280
Container for a single decoded SH-2 sensor report.
Definition bno08x.hpp:227
BNO085Sensor sensor
Which sensor produced this event.
Definition bno08x.hpp:228