Fully featured I2C and SPI driver for CEVA (Hilcrest)'s BNO080 and FSM300 Inertial Measurement Units.

Dependents:   BNO080-Examples BNO080-Examples

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BNO080.h Source File

BNO080.h

00001 /*
00002  * This is USC RPL's ARM MBed BNO080 IMU driver, by Jamie Smith.
00003  *
00004  * It is based on SparkFun and Nathan Seidle's Arduino driver for this chip, but is substantially rewritten and adapted.
00005  * It also supports some extra features, such as setting the mounting orientation and
00006  * enabling some additional data reports.
00007  *
00008  * This driver uses no dynamic allocation, but does allocate a couple hundred bytes of class variables as buffers.
00009  * This should allow you to monitor its memory usage using MBed's size printout.
00010  *
00011  * The BNO080 is a very complex chip; it's capable of monitoring and controlling other sensors and making
00012  * intelligent decisions and calculations using its data.  Accordingly, the protocol for communicating with it
00013  * is quite complex, and it took me quite a while to wrap my head around it.  If you need to modify or debug
00014  * this driver, look at the CPP file for an overview of the chip's communication protocol.
00015  *
00016  * Note: this driver only supports I2C.  I attempted to create an SPI version, but as far as I can tell,
00017  * the BNO's SPI interface has a bug that causes you to be unable to wake the chip from sleep in some conditions.
00018  * Until this is fixed, SPI on it is virtually unusable.
00019  */
00020 
00021 #ifndef HAMSTER_BNO080_H
00022 #define HAMSTER_BNO080_H
00023 
00024 #include <mbed.h>
00025 #include <Stream.h>
00026 #include <quaternion.h>
00027 
00028 #include "BNO080Constants.h"
00029 
00030 // useful define when working with orientation quaternions
00031 #define SQRT_2 1.414213562f
00032 
00033 // Enable this to enable experimental support for Mbed's asynchronous SPI transfer API.
00034 // This will allow your processor to do other things while long SPI transfers are taking place
00035 // (and this IMU can end up transferring hundreds of bytes per packet, so this is useful).
00036 // To get this to work, you may need to use a slower clock rate (<1MHz on the STM32F429ZI I tested).
00037 // You also will need to edit Mbed OS code in order to use 0x00 as the SPI fill character for
00038 // asynchronous transfers (the API currently only allows changing this for synchronous transfers)
00039 // (I had to edit the SPI_FILL_CHAR constant in stm_spi_api.c).
00040 #define USE_ASYNC_SPI 0
00041 
00042 // Note: I filed a bug about the SPI fill char issue: https://github.com/ARMmbed/mbed-os/issues/13941
00043 
00044 /**
00045   Class to drive the BNO080 9-axis IMU.
00046   
00047   There should be one instance of this class per IMU chip. I2C address and pin assignments are passed in the constructor.
00048 */
00049 class BNO080Base
00050 {
00051 protected:
00052     /**
00053      * Serial stream to print debug info to.  Used for errors, and debugging output if debugging is enabled.
00054      */
00055     Stream * _debugPort;
00056 
00057     /// Interrupt pin -- signals to the host that the IMU has data to send
00058     // Note: only ever used as a digital input by BNO080.
00059     // Used for interrupts by BNO080Async.
00060     InterruptIn _int;
00061     
00062     // Reset pin -- resets IMU when held low.
00063     DigitalOut _rst;
00064 
00065     // packet storage
00066     //-----------------------------------------------------------------------------------------------------------------
00067 
00068 #define SHTP_HEADER_SIZE 4
00069 
00070     // Size of the largest individual packet we can receive.
00071     // Min value is set by the advertisement packet (272 bytes)
00072     // If you enable lots of sensor reports and get an error, you might need to increase this.
00073 #define SHTP_RX_PACKET_SIZE 272
00074 
00075     // Size of largest packet that we need to transmit (not including header)
00076 #define SHTP_MAX_TX_PACKET_SIZE 17
00077 
00078     // scratch space buffers
00079     uint8_t txPacketBuffer[SHTP_HEADER_SIZE + SHTP_MAX_TX_PACKET_SIZE];
00080     uint8_t rxPacketBuffer[SHTP_HEADER_SIZE + SHTP_RX_PACKET_SIZE + SHTP_HEADER_SIZE];  // need a second header worth of extra scratch space to write the header of a continued packet
00081 
00082     /// Each SHTP packet starts with a header of 4 uint8_ts
00083     uint8_t * txShtpHeader = txPacketBuffer;
00084     uint8_t * rxShtpHeader = rxPacketBuffer;
00085 
00086     /// Stores data contained in each packet.  Packets can contain an arbitrary amount of data, but
00087     /// rarely get over a hundred bytes unless you have a million sensor reports enabled.
00088     /// The only long packets we actually care about are batched sensor data packets.
00089     uint8_t * txShtpData = txPacketBuffer + SHTP_HEADER_SIZE;
00090     uint8_t * rxShtpData = rxPacketBuffer + SHTP_HEADER_SIZE;
00091 
00092     /// Length of packet that was received into buffer.  Does NOT include header bytes.
00093     uint16_t rxPacketLength;
00094 
00095     /// Current sequence number for each channel, incremented after transmission. 
00096     uint8_t sequenceNumber[6];
00097 
00098     /// Commands have a seqNum as well. These are inside command packet, the header uses its own seqNum per channel
00099     uint8_t commandSequenceNumber;
00100 
00101     // frs metadata
00102     //-----------------------------------------------------------------------------------------------------------------
00103 
00104     /// Record ID of the metadata record currently stored in the metadataRecord[] buffer.
00105     /// Used so that we can avoid requerying the FRS record if we need to make multiple metadata reads
00106     /// in succession.
00107     uint16_t bufferMetadataRecord;
00108 
00109     /// currently we only need the first 10 words of the metadata
00110 #define METADATA_BUFFER_LEN 10
00111 
00112     /// Buffer for current metadata record.
00113     uint32_t metadataRecord[METADATA_BUFFER_LEN];
00114 
00115     // data storage
00116     //-----------------------------------------------------------------------------------------------------------------
00117 
00118     // 1 larger than the largest sensor report ID
00119 #define STATUS_ARRAY_LEN MAX_SENSOR_REPORTID + 1
00120 
00121     /// stores status of each sensor, indexed by report ID
00122     uint8_t reportStatus[STATUS_ARRAY_LEN];
00123 
00124     /// stores whether a sensor has been updated since the last call to hasNewData()
00125     bool reportHasBeenUpdated[STATUS_ARRAY_LEN];
00126 
00127 public:
00128 
00129     // list of reports
00130     //-----------------------------------------------------------------------------------------------------------------
00131 
00132     /// List of all sensor reports that the IMU supports.
00133     enum Report
00134     {
00135         /**
00136          * Total acceleration of the IMU in world space.
00137          * See BNO datasheet section 2.1.1
00138          */
00139         TOTAL_ACCELERATION = SENSOR_REPORTID_ACCELEROMETER,
00140 
00141         /**
00142          * Acceleration of the IMU not including the acceleration of gravity.
00143          * See BNO datasheet section 2.1.1
00144          */
00145         LINEAR_ACCELERATION = SENSOR_REPORTID_LINEAR_ACCELERATION,
00146 
00147         /**
00148          * Acceleration of gravity felt by the IMU.
00149          * See BNO datasheet section 2.1.1
00150          */
00151         GRAVITY_ACCELERATION = SENSOR_REPORTID_GRAVITY,
00152 
00153         /**
00154          * (calibrated) gyroscope reading of the rotational speed of the IMU.
00155          * See BNO datasheet section 2.1.2
00156          */
00157         GYROSCOPE = SENSOR_REPORTID_GYROSCOPE_CALIBRATED,
00158 
00159         /**
00160          * (calibrated) reading of Earth's magnetic field levels.
00161          * See BNO datasheet section 2.1.3
00162          */
00163         MAG_FIELD = SENSOR_REPORTID_MAGNETIC_FIELD_CALIBRATED,
00164 
00165         /**
00166         * Uncalibrated reading of magnetic field levels, without any hard iron offsets applied
00167         * See BNO datasheet section 2.1.3
00168         */
00169         MAG_FIELD_UNCALIBRATED = SENSOR_REPORTID_MAGNETIC_FIELD_UNCALIBRATED,
00170 
00171         /**
00172          * Fused reading of the IMU's rotation in space using all three sensors.  This is the most accurate reading
00173          * of absolute orientation that the IMU can provide.
00174          * See BNO datasheet section 2.2.4
00175          */
00176         ROTATION = SENSOR_REPORTID_ROTATION_VECTOR,
00177 
00178         /**
00179          * Fused reading of rotation from accelerometer and magnetometer readings.  This report is designed to decrease
00180          * power consumption (by turning off the gyroscope) in exchange for reduced responsiveness.
00181          */
00182         GEOMAGNETIC_ROTATION = SENSOR_REPORTID_GEOMAGNETIC_ROTATION_VECTOR,
00183 
00184         /**
00185          * Fused reading of the IMU's rotation in space.  Unlike the regular rotation vector, the Game Rotation Vector
00186          * is not referenced against the magnetic field and the "zero yaw" point is arbitrary.
00187          * See BNO datasheet section 2.2.2
00188          */
00189         GAME_ROTATION = SENSOR_REPORTID_GAME_ROTATION_VECTOR,
00190 
00191         /**
00192          * Detects a user tapping on the device containing the IMU.
00193          * See BNO datasheet section 2.4.2
00194          */
00195         TAP_DETECTOR = SENSOR_REPORTID_TAP_DETECTOR,
00196 
00197         /**
00198          * Detects whether the device is on a table, being held stably, or being moved.
00199          * See BNO datasheet section 2.4.1
00200          */
00201         STABILITY_CLASSIFIER = SENSOR_REPORTID_STABILITY_CLASSIFIER,
00202 
00203         /**
00204          * Detects a user taking a step with the IMU worn on their person.
00205          * See BNO datasheet section 2.4.3
00206          */
00207         STEP_DETECTOR = SENSOR_REPORTID_STEP_DETECTOR,
00208 
00209         /**
00210          * Detects how many steps a user has taken.
00211          * See BNO datasheet section 2.4.4
00212          */
00213         STEP_COUNTER = SENSOR_REPORTID_STEP_COUNTER,
00214 
00215         /**
00216          * Detects when the IMU has made a "significant" motion, defined as moving a few steps and/or accelerating significantly.
00217          *
00218          * NOTE: this report automatically disables itself after sending a report, so you'll have to reenable it each time a motion i s detected.
00219          * See BNO datasheet section 2.4.6
00220          */
00221         SIGNIFICANT_MOTION = SENSOR_REPORTID_SIGNIFICANT_MOTION,
00222 
00223         /**
00224          * Detects when the IMU is being shaken.
00225          * See BNO datasheet section 2.4.7
00226          */
00227         SHAKE_DETECTOR = SENSOR_REPORTID_SHAKE_DETECTOR
00228     };
00229 
00230     // data variables to read reports from
00231     //-----------------------------------------------------------------------------------------------------------------
00232 
00233     // @{
00234     /// Version info read from the IMU when it starts up
00235     uint8_t majorSoftwareVersion;
00236     uint8_t minorSoftwareVersion;
00237     uint16_t patchSoftwareVersion;
00238     uint32_t partNumber;
00239     uint32_t buildNumber;
00240     // @}
00241 
00242 
00243     /**
00244      * Readout from Accleration report.
00245      * Represents total acceleration in m/s^2 felt by the BNO's accelerometer.
00246      */
00247     TVector3  totalAcceleration;
00248 
00249     /**
00250      * Readout from Linear Acceleration report.
00251      * Represents acceleration felt in m/s^2 by the BNO's accelerometer not including the force of gravity.
00252      */
00253     TVector3  linearAcceleration;
00254 
00255     /**
00256      * Readout from Gravity report.
00257      * Represents the force of gravity in m/s^2 felt by the BNO's accelerometer.
00258      */
00259     TVector3  gravityAcceleration;
00260 
00261     /**
00262      * Readout from Calibrated Gyroscope report
00263      * Represents the angular velocities of the chip in rad/s in the X, Y, and Z axes
00264      */
00265     TVector3  gyroRotation;
00266 
00267     /**
00268      * Readout from the Magnetic Field Calibrated report.
00269      * Represents the magnetic field read by the chip in uT in the X, Y, and Z axes
00270      */
00271     TVector3  magField;
00272 
00273     /**
00274      * Readout from the Magnetic Field Uncalibrated report.
00275      * Represents the magnetic field read by the chip in uT in the X, Y, and Z axes, without hard iron offsets applied
00276      */
00277     TVector3  magFieldUncalibrated;
00278 
00279     /**
00280      * Auxiliary readout from the Magnetic Field Uncalibrated report.
00281      * Represents the hard iron offsets that the chip is using in each axis in uT.
00282      */
00283     TVector3  hardIronOffset;
00284 
00285     /**
00286      * Readout from the Rotation Vector report.
00287      * Represents the rotation of the IMU (relative to magnetic north) in radians.
00288      */
00289     Quaternion rotationVector;
00290 
00291     /**
00292      * Auxiliary accuracy readout from the Rotation Vector report.
00293      * Represents the estimated accuracy of the rotation vector in radians.
00294      */
00295     float rotationAccuracy;
00296 
00297     /**
00298      * Readout from the Game Rotation Vector report.
00299      * Represents the rotation of the IMU in radians.  Unlike the regular rotation vector, the Game Rotation Vector
00300      * is not referenced against the magnetic field and the "zero yaw" point is arbitrary.
00301      */
00302     Quaternion gameRotationVector;
00303 
00304     /**
00305      * Readout from the Geomagnetic Rotation Vector report.
00306      * Represents the geomagnetic rotation of the IMU (relative to magnetic north) in radians.
00307      */
00308     Quaternion geomagneticRotationVector;
00309 
00310     /**
00311      * Auxiliary accuracy readout from the Geomagnetic Rotation Vector report.
00312      * Represents the estimated accuracy of the rotation vector in radians.
00313      */
00314     float geomagneticRotationAccuracy;
00315 
00316     /**
00317      * Tap readout from the Tap Detector report.  This flag is set to true whenever a tap is detected, and you should
00318      * manually clear it when you have processed the tap.
00319      */
00320     bool tapDetected;
00321 
00322     /**
00323      * Whether the last tap detected was a single or double tap.
00324      */
00325     bool doubleTap;
00326 
00327     /**
00328      * Enum to represent the different stability types.
00329      *
00330      * See BNO datasheet section 2.4.1 and SH-2 section 6.5.31.2 for details.
00331      */
00332     enum Stability
00333     {
00334         /// Unknown stability type.
00335         UNKNOWN = 0,
00336 
00337         /// At rest on a stable surface with very little motion
00338         ON_TABLE = 1,
00339 
00340         /// Motion is stable, but the duration requirement for stability has not been met.
00341         /// Can only occur during gyroscope calibration (why? beats me!)
00342         STATIONARY = 2,
00343 
00344         /// Stable (has been below the acceleration threshold for the required duration)
00345         STABLE = 3,
00346 
00347         /// IMU is moving.
00348         MOTION = 4
00349     };
00350 
00351     /**
00352      * Readout from the stability classifier.
00353      * Current stability status of the IMU.
00354      */
00355     Stability stability;
00356 
00357     /**
00358      * Readout from the Step Detector report.  This flag is set to true whenever a step is detected, and you should
00359      * manually clear it when you have processed the step.
00360      */
00361     bool stepDetected;
00362 
00363     /**
00364      * Readout from the Step Counter report.  This count increases as the user takes steps, but can also decrease
00365      * if the IMU decides that a motion was not a step.
00366      */
00367     uint16_t stepCount;
00368 
00369     /**
00370      * Readout from the Significant Motion Detector report.  This flag is set to true whenever significant motion is detected, and you should
00371      * manually clear it when you have processed the event.
00372      */
00373     bool significantMotionDetected;
00374 
00375     /**
00376      * Readout from the Shake Detector report.  This flag is set to true whenever shaking is detected, and you should
00377      * manually clear it when you have processed the event.
00378      */
00379     bool shakeDetected;
00380 
00381     // @{
00382     /// The axis/axes that shaking was detected in in the latest shaking report.
00383     bool xAxisShake;
00384     bool yAxisShake;
00385     bool zAxisShake;
00386     // @}
00387 
00388     // Management functions
00389     //-----------------------------------------------------------------------------------------------------------------
00390 
00391     /**
00392      * Construct a BNO080, providing pins and parameters.
00393      *
00394      * This doesn't actally initialize the chip, you will need to call begin() for that.
00395      *
00396      * NOTE: while some schematics tell you to connect the BOOTN pin to the processor, this driver does not use or require it.
00397      * Just tie it to VCC per the datasheet.
00398      *
00399      * @param debugPort Serial port to write output to.  Cannot be nullptr.
00400      */
00401     BNO080Base(Stream *debugPort, PinName user_INTPin, PinName user_RSTPin);
00402 
00403     /**
00404      * Resets and connects to the IMU.  Verifies that it's connected, and reads out its version
00405      * info into the class variables above.
00406      *
00407      * If this function is failing, it would be a good idea to turn on BNO_DEBUG in the cpp file to get detailed output.
00408      *
00409      * Note: this function takes several hundred ms to execute, mainly due to waiting for the BNO to boot.
00410      *
00411      * @return whether or not initialization was successful
00412      */
00413     virtual bool begin();
00414 
00415     /**
00416      * Tells the IMU to use its current rotation vector as the "zero" rotation vector and to reorient
00417      * all outputs accordingly.
00418      *
00419      * @param zOnly If true, only the rotation about the Z axis (the heading) will be tared.
00420      */
00421     void tare(bool zOnly = false);
00422 
00423     /**
00424      * Tells the IMU to begin a dynamic sensor calibration.  To calibrate the IMU, call this function and move
00425      * the IMU according to the instructions in the "BNO080 Sensor Calibration Procedure" app note
00426      * (http://www.hillcrestlabs.com/download/59de9014566d0727bd002ae7).
00427      *
00428      * To tell when the calibration is complete, look at the status bits for Game Rotation Vector (for accel and gyro)
00429      * and Magnetic Field (for the magnetometer).
00430      *
00431      * The gyro and accelerometer should only need to be calibrated once, but the magnetometer will need to be recalibrated
00432      * every time the orientation of ferrous metals around the IMU changes (e.g. when it is put into a new enclosure).
00433      *
00434      * The new calibration will not be saved in flash until you call saveCalibration().
00435      *
00436      * NOTE: calling this with all false values will cancel any calibration in progress.  However, the calibration data being created will
00437      * remain in use until the next chip reset (I think!)
00438      *
00439      * @param calibrateAccel Whether to calibrate the accelerometer.
00440      * @param calibrateGyro Whether to calibrate the gyro.
00441      * @param calibrateMag Whether to calibrate the magnetometer.
00442      *
00443      * @return whether the operation succeeded
00444      */
00445     bool enableCalibration(bool calibrateAccel, bool calibrateGyro, bool calibrateMag);
00446 
00447     /**
00448      * Saves the calibration started with startCalibration() and ends the calibration.
00449      * You will want to call this once the status bits read as "accuracy high".
00450      *
00451      * WARNING: if you paid for a factory calibrated IMU, then this WILL OVERWRITE THE FACTORY CALIBRATION in whatever sensors
00452      * are being calibrated.  Use with caution!
00453      *
00454      * @return whether the operation succeeded
00455      */
00456     bool saveCalibration();
00457 
00458     /**
00459      * Sets the orientation quaternion, telling the sensor how it's mounted
00460      * in relation to world space.
00461      * See page 40 of the BNO080 datasheet.
00462      *
00463      * NOTE: this driver provides the macro SQRT_2 to help with entering values from that table.
00464      *
00465      * NOTE 2: this setting does not persist and will have to be re-applied every time the chip is reset.
00466      * Use setPermanentOrientation() for that.
00467      *
00468      * @param orientation quaternion mapping from IMU space to world space.
00469      */
00470     void setSensorOrientation(Quaternion orientation);
00471 
00472     /**
00473      * Sets the orientation quaternion, telling the sensor how it's mounted
00474      * in relation to world space. See page 40 of the BNO080 datasheet.
00475      *
00476      * Unlike setSensorOrientation(), this setting will persist across sensor restarts.
00477      * However, it will also take a few hundred milliseconds to write.
00478      *
00479      * @param orientation quaternion mapping from IMU space to world space.
00480      *
00481      * @return true if the operation succeeded, false if it failed.
00482     */
00483     bool setPermanentOrientation(Quaternion orientation);
00484 
00485     /**
00486      * No-op on synchronous driver.  For compatibility with BNO080Async
00487      */
00488     virtual void lockMutex()
00489     {}
00490 
00491     /**
00492      * No-op on synchronous driver.  For compatibility with BNO080Async
00493      */
00494     virtual void unlockMutex()
00495     {}
00496     
00497     // Report functions
00498     //-----------------------------------------------------------------------------------------------------------------
00499 
00500     /**
00501      * Checks for new data packets queued on the IMU.
00502      * If there are packets queued, receives all of them and updates
00503      * the class variables with the results.
00504      *
00505      * Note that with some backends (SPI), sending commands will also update data, which can
00506      * cause updateData() to return false even though new data has been received.  hasNewData()
00507      * is a more reliable way to determine if a sensor has new data.
00508      *
00509      * @return True iff new data packets of any kind were received.  If you need more fine-grained data change reporting,
00510      * check out hasNewData().
00511      */
00512     virtual bool updateData();
00513 
00514     /**
00515      * Gets the status of a report as a 2 bit number.
00516      * per SH-2 section 6.5.1, this is interpreted as: <br>
00517      * 0 - unreliable <br>
00518      * 1 - accuracy low <br>
00519      * 2 - accuracy medium <br>
00520      * 3 - accuracy high <br>
00521      * of course, these are only updated if a given report is enabled.
00522      * @param report
00523      * @return
00524      */
00525     uint8_t getReportStatus(Report report);
00526 
00527     /**
00528      * Get a string for printout describing the status of a sensor.
00529      * @return
00530      */
00531     const char* getReportStatusString(Report report);
00532 
00533     /**
00534      * Checks if a specific report has gotten new data since the last call to this function.
00535      * @param report The report to check.
00536      * @return Whether the report has received new data.
00537      */
00538     bool hasNewData(Report report);
00539 
00540     /**
00541      * Enable a data report from the IMU.  Look at the comments above to see what the reports do.
00542      * This function checks your polling period against the report's max speed in the IMU's metadata,
00543      * and reports an error if you're trying to poll too fast.
00544      *
00545      * @param timeBetweenReports time in milliseconds between data updates.
00546      */
00547     void enableReport(Report report, uint16_t timeBetweenReports);
00548 
00549     /**
00550      * Disable a data report from the IMU.
00551      *
00552      * @param report The report to disable.
00553      */
00554     void disableReport(Report report);
00555 
00556     /**
00557      * Gets the serial number (used to uniquely identify each individual device).
00558      *
00559      * NOTE: this function should work according to the datasheet, but the device I was testing with appears to have
00560      * an empty serial number record as shipped, and I could never get anything out of it. Your mileage may vary.
00561      *
00562      * @return The serial number, or 0 on error.
00563      */
00564     uint32_t getSerialNumber();
00565 
00566     // Metadata functions
00567     //-----------------------------------------------------------------------------------------------------------------
00568 
00569     /**
00570      * Gets the range of a report as reported by the IMU.   Units are the same as the report's output data.
00571      * @return
00572      */
00573     float getRange(Report report);
00574 
00575     /**
00576      * Gets the resolution of a report as reported by the IMU.  Units are the same as the report's output data.
00577      * @param report
00578      * @return
00579      */
00580     float getResolution(Report report);
00581 
00582     /**
00583      * Get the power used by a report when it's operating, according to the IMU.
00584      * @param report
00585      * @return Power used in mA.
00586      */
00587     float getPower(Report report);
00588 
00589     /**
00590      * Gets the smallest polling period that a report supports.
00591      * @return Period in seconds.
00592      */
00593     float getMinPeriod(Report report);
00594 
00595     /**
00596      * Gets the larges polling period that a report supports.
00597      * Some reports don't have a max period, in which case this function will return -1.0.
00598      *
00599      * @return Period in seconds, or -1.0 on error.
00600      */
00601     float getMaxPeriod(Report report);
00602 
00603     /**
00604      * Prints a summary of a report's metadata to the
00605      * debug stream.  Should be useful for debugging and setting up reports since lots of this data
00606      * isn't given in the datasheets.
00607      *
00608      * Note: to save string constant space, this function is only available when BNO_DEBUG is 1.
00609      */
00610     void printMetadataSummary(Report report);
00611 
00612 protected:
00613 
00614     // Internal metadata functions
00615     //-----------------------------------------------------------------------------------------------------------------
00616 
00617     /**
00618      * Gets the version of the metadata stored in the buffer.
00619      * We might see version 3 and 4 records, and they have different layouts.
00620      * @return
00621      */
00622     uint16_t getMetaVersion() {return static_cast<uint16_t>(metadataRecord[3] >> 16);}
00623 
00624     // @{
00625     /**
00626      * Gets the Q point from a report's metadata, which essentially defines where the decimal point goes in the sensor's output.
00627      * The 1/2/3 Q values are used in different places in the metadata, see SH-2 section 5.1 for details.
00628      * @param report
00629      * @return
00630      */
00631     int16_t getQ1(Report report);
00632     int16_t getQ2(Report report);
00633     int16_t getQ3(Report report);
00634     // @}
00635 
00636     // internal utility functions
00637     //-----------------------------------------------------------------------------------------------------------------
00638 
00639     /**
00640      * Processes the packet currently stored in the buffer, and updates class variables to reflect the data it contains
00641      */
00642     void processPacket();
00643 
00644     /**
00645      * Processes the sensor data packet currently stored in the buffer.
00646      * Only called from processPacket()
00647      */
00648     void parseSensorDataPacket();
00649 
00650     /**
00651      * Call to wait for a packet with the given parameters to come in.
00652      *
00653      * Note: on BNO080Async, the received packet data will stay in the RX buffer
00654      * until either the public IMU function that was called returns, or you
00655      * call sendPacket() or waitForPacket() again.
00656      *
00657      * @param channel Channel of the packet
00658      * @param reportID Report ID (first data byte) of the packet
00659      * @param timeout how long to wait for the packet
00660      * @return true if the packet has been received, false if it timed out
00661      */
00662     virtual bool waitForPacket(int channel, uint8_t reportID, std::chrono::milliseconds timeout = 125ms);
00663 
00664     /**
00665      * Given a Q value, converts fixed point floating to regular floating point number.
00666      * @param fixedPointValue
00667      * @param qPoint
00668      * @return
00669      */
00670     float qToFloat(int16_t fixedPointValue, uint8_t qPoint);
00671 
00672     /**
00673      * Given a Q value, converts fixed point floating to regular floating point number.
00674      * This version is used for the unsigned 32-bit values in metadata records.
00675      * @param fixedPointValue
00676      * @param qPoint
00677      * @return
00678      */
00679     float qToFloat_dword(uint32_t fixedPointValue, int16_t qPoint);
00680 
00681     /**
00682      * Given a floating point value and a Q point, convert to Q
00683      * See https://en.wikipedia.org/wiki/Q_(number_format)
00684      * @param qFloat
00685      * @param qPoint
00686      * @return
00687      */
00688     int16_t floatToQ(float qFloat, uint8_t qPoint);
00689 
00690     /**
00691      * Given a floating point value and a Q point, convert to Q
00692      * See https://en.wikipedia.org/wiki/Q_(number_format)
00693      *
00694      * This version is used for the signed 32-bit values in metadata records.
00695      *
00696      * @param qFloat
00697      * @param qPoint
00698      * @return
00699      */
00700     int32_t floatToQ_dword(float qFloat, uint16_t qPoint);
00701 
00702     /**
00703      *  Tell the sensor to do a command.
00704      *  See SH-2 Reference Manual section 6.3.8 page 42, Command request
00705      *  The caller is expected to set shtpData 3 though 11 prior to calling
00706      */
00707     void sendCommand(uint8_t command);
00708 
00709     /**
00710      * Given a sensor's report ID, this tells the BNO080 to begin reporting the values.
00711      *
00712      * @param reportID
00713      * @param timeBetweenReports
00714      * @param specificConfig the specific config word. Useful for personal activity classifier.
00715      */
00716     void setFeatureCommand(uint8_t reportID, uint16_t timeBetweenReports, uint32_t specificConfig = 0);
00717 
00718     /**
00719      * Read a record from the FRS (Flash Record System) on the IMU.  FRS records are composed of 32-bit words,
00720      * with the size of each record determined by the record type.
00721      *
00722      * Will block until the entire record has been read.
00723      * @param recordID Record ID to read.  See SH-2 figures 28 and 29 for a list of these.  Sometimes also called
00724      * the "FRS Type" by the datasheet (???).
00725      * @param readBuffer Buffer to read data into.
00726      * @param readLength Amount of words to read from the record.  Must be <= the length of the record.
00727      *
00728      * @return whether the request succeeded
00729      */
00730     bool readFRSRecord(uint16_t recordID, uint32_t* readBuffer, uint16_t readLength);
00731 
00732     /**
00733      * Write a record to the FRS (Flash Record System) on the IMU.  FRS records are composed of 32-bit words,
00734      * with the size of each record determined by the record type.
00735      *
00736      * Will block until the entire record has been written.
00737      * @param recordID Record ID to write.  See SH-2 figures 28 and 29 for a list of these.  Sometimes also called
00738      * the "FRS Type" by the datasheet (???).
00739      * @param buffer Buffer to write data into.
00740      * @param length Amount of words to write to the record.  Must be <= the length of the record.
00741      *
00742      * @return whether the request succeeded
00743      */
00744     bool writeFRSRecord(uint16_t recordID, uint32_t* buffer, uint16_t length);
00745 
00746     /**
00747      * Reads a packet from the IMU and stores it in the class variables.
00748      *
00749      * @param timeout how long to wait for there to be a packet
00750      *
00751      * @return whether a packet was recieved.
00752      */
00753     virtual bool receivePacket(std::chrono::milliseconds timeout=200ms) = 0;
00754 
00755     /**
00756      * Sends the current shtpData contents to the BNO.  It's a good idea to disable interrupts before you call this.
00757      *
00758      * @param channelNumber the channel to send on
00759      * @param dataLength How many bits of shtpData to send
00760      * @return
00761      */
00762     virtual bool sendPacket(uint8_t channelNumber, uint8_t dataLength) = 0;
00763 
00764     /**
00765      * Prints the current shtp packet stored in the buffer.
00766      * @param length
00767      */
00768     void printPacket(uint8_t * buffer);
00769 
00770     /**
00771      * Erases the current SHTP TX packet buffer.
00772      * In BNO080Async, this blocks until the buffer is available.
00773      */
00774      virtual void clearSendBuffer();
00775 
00776      /**
00777       * Loads the metadata for this report into the metadata buffer.
00778       * @param report
00779       * @return Whether the operation succeeded.
00780       */
00781      bool loadReportMetadata(Report report);
00782 
00783 };
00784 
00785 /**
00786  * Version of the BNO080 driver which uses the I2C interface
00787  */
00788 class BNO080I2C : public BNO080Base
00789 {
00790     /**
00791      * I2C port object.  Provides physical layer communications with the chip.
00792      */
00793     I2C _i2cPort;
00794 
00795     /// user defined port speed
00796     int  _i2cPortSpeed;
00797 
00798     /// i2c address of IMU (7 bits)
00799     uint8_t _i2cAddress;
00800 public:
00801 
00802     /**
00803      * Construct a BNO080 driver for the I2C bus, providing pins and parameters.
00804      *
00805      * This doesn't actally initialize the chip, you will need to call begin() for that.
00806      *
00807      * NOTE: while some schematics tell you to connect the BOOTN pin to the processor, this driver does not use or require it.
00808      * Just tie it to VCC per the datasheet.
00809      *
00810      * @param debugPort Serial port to write output to.  Cannot be nullptr.
00811      * @param user_SDApin Hardware I2C SDA pin connected to the IMU
00812      * @param user_SCLpin Hardware I2C SCL pin connected to the IMU
00813      * @param user_INTPin Input pin connected to HINTN
00814      * @param user_RSTPin Output pin connected to NRST
00815      * @param i2cAddress I2C address.  The BNO defaults to 0x4a, but can also be set to 0x4b via a pin.
00816      * @param i2cPortSpeed I2C frequency.  The BNO's max is 400kHz.
00817      */
00818     BNO080I2C(Stream *debugPort, PinName user_SDApin, PinName user_SCLpin, PinName user_INTPin, PinName user_RSTPin, uint8_t i2cAddress=0x4a, int i2cPortSpeed=400000);
00819 
00820 private:
00821 
00822     bool receivePacket(std::chrono::milliseconds timeout=200ms) override;
00823 
00824     bool sendPacket(uint8_t channelNumber, uint8_t dataLength) override;
00825 };
00826 
00827 // typedef for compatibility with old version of driver where there was no SPI
00828 typedef BNO080I2C BNO080;
00829 
00830 /**
00831  * Version of the BNO080 driver which uses the SPI interface.
00832  * WARNING: The SPI interface, unlike the I2C interface, of this chip
00833  * has some god-awful timing requirements that are difficult to satisfy.
00834  *
00835  * In order for the chip to produce data, you must call updateData() at at more than
00836  * twice the frequency of the fastest sensor poll rate you have set.
00837  * Otherwise, for reasons that I don't exactly understand, the IMU
00838  * will have some kind of internal watchdog timeout error and shut itself down.
00839  * Also, you have about 500ms after calling begin() to configure reports and start
00840  * receiving data, or the same thing happens.
00841  *
00842  * If this timing error happens to you, the symptoms are strange: the IMU will just stop sending data, several seconds later.
00843  * No error or anything, just no data.
00844  * To recover from the error, you would have to call begin() again and reconfigure it from scratch.
00845  *
00846  */
00847 class BNO080SPI : public BNO080Base
00848 {
00849 protected:
00850     /**
00851      * I2C port object.  Provides physical layer communications with the chip.
00852      */
00853     SPI _spiPort;
00854 
00855     // Wake pin to signal the IMU to wake up
00856     DigitalOut _wakePin;
00857 
00858     /// user defined port speed
00859     int  _spiSpeed;
00860 public:
00861 
00862     /**
00863      * Construct a BNO080 driver for the SPI bus, providing pins and parameters.
00864      *
00865      * This doesn't actually initialize the chip, you will need to call begin() for that.
00866      *
00867      * NOTE: while some schematics tell you to connect the BOOTN pin to the processor, this driver does not use or require it.
00868      * Just tie it to VCC per the datasheet.
00869      *
00870      * @param debugPort Serial port to write output to.  Cannot be nullptr.
00871      * @param rstPin Hardware reset pin, resets the IMU
00872      * @param intPin Hardware interrupt pin, this is used for the IMU to signal the host that it has a message to send
00873      * @param wakePin Hardware wake pin, this is used by the processor to signal the BNO to wake up and receive a message
00874      * @param misoPin SPI MISO pin
00875      * @param mosiPin SPI MOSI pin
00876      * @param sclkPin SPI SCLK pin
00877      * @param csPin SPI CS pin
00878      * @param spiSpeed SPI frequency.  The BNO's max is 3MHz.
00879      */
00880     BNO080SPI(Stream *debugPort, PinName rstPin, PinName intPin, PinName wakePin, PinName misoPin, PinName mosiPin, PinName sclkPin, PinName csPin, int spiSpeed=3000000);
00881 
00882 protected:
00883 
00884     bool receivePacket(std::chrono::milliseconds timeout=200ms) override;
00885 
00886     bool sendPacket(uint8_t channelNumber, uint8_t dataLength) override;
00887 
00888     /**
00889      * Assuming that at least a packet header has been read into the RX buffer, receive the remainder of the packet.
00890      * @param bytesRead The number of bytes (including the header) of the packet that have already been read.
00891      * @return
00892      */
00893     bool receiveCompletePacket(size_t bytesRead, std::chrono::milliseconds timeout=200ms);
00894 
00895 #if USE_ASYNC_SPI
00896 
00897     /**
00898      * Start an SPI transfer and suspend the current thread until it is complete.
00899      * Used by functions in BNO080SPI.
00900      * Note: should only be called by one thread at a time.
00901      * @param tx_buffer
00902      * @param tx_length
00903      * @param rx_buffer
00904      * @param rx_length
00905      */
00906     void spiTransferAndWait(const uint8_t *tx_buffer, int tx_length, uint8_t *rx_buffer, int rx_length);
00907 
00908     // callback for finished SPI transfers
00909     void onSPITransferComplete(int event);
00910 
00911     // Signal whan an SPI transfer is complete.
00912     EventFlags spiCompleteFlag;
00913 
00914 #else
00915 
00916     /**
00917      * Start an SPI transfer and wait for it to complete.
00918      * BNO080Async swaps in a threaded implementation here.
00919      * API same as SPI::write().
00920      */
00921     void spiTransferAndWait(const uint8_t *tx_buffer, int tx_length, uint8_t *rx_buffer, int rx_length)
00922     {
00923         _spiPort.write(reinterpret_cast<const char *>(tx_buffer), tx_length, reinterpret_cast<char *>(rx_buffer), rx_length);
00924     }
00925 #endif
00926 };
00927 
00928 #endif //HAMSTER_BNO080_H