blob: ed8e09165b30eb135c4f4eabb9920efb7f4974dd [file] [log] [blame]
Brian Silverman5f17a972016-02-28 01:49:32 -05001#ifndef FRC971_WPILIB_ADIS16448_H_
2#define FRC971_WPILIB_ADIS16448_H_
3
Brian Silverman5f17a972016-02-28 01:49:32 -05004#include <atomic>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07005#include <cstdint>
Parker Schuhd3b7a8872018-02-19 16:42:27 -08006#include <memory>
Brian Silverman5f17a972016-02-28 01:49:32 -05007
Parker Schuhd3b7a8872018-02-19 16:42:27 -08008#include "frc971/wpilib/ahal/DigitalInput.h"
9#include "frc971/wpilib/ahal/DigitalOutput.h"
10#include "frc971/wpilib/ahal/SPI.h"
Brian Silverman5f17a972016-02-28 01:49:32 -050011#undef ERROR
12
Austin Schuh217a9782019-12-21 23:02:50 -080013#include "aos/events/shm_event_loop.h"
John Park33858a32018-09-28 23:05:48 -070014#include "aos/logging/logging.h"
Brian Silverman7be68ba2020-01-08 22:08:40 -080015#include "frc971/wpilib/fpga_time_conversion.h"
Austin Schuhdd7ded62021-06-20 14:35:56 -070016#include "frc971/wpilib/imu_batch_generated.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070017#include "frc971/wpilib/imu_generated.h"
Brian Silverman003a4732018-03-11 14:02:15 -070018#include "frc971/wpilib/spi_rx_clearer.h"
Brian Silverman5f17a972016-02-28 01:49:32 -050019
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080020namespace frc971::wpilib {
Brian Silverman5f17a972016-02-28 01:49:32 -050021
22// Handles interfacing with an Analog Devices ADIS16448 Inertial Sensor over
23// SPI and sending values out on a queue.
24//
25// The sensor is configured to generate samples at 204.8 Hz, and the values are
26// sent out as each sample is received.
27//
28// This is designed to be passed into ::std::thread's constructor so it will run
29// as a separate thread.
30class ADIS16448 {
31 public:
32 // port is where to find the sensor over SPI.
33 // dio1 must be connected to DIO1 on the sensor.
Austin Schuh217a9782019-12-21 23:02:50 -080034 ADIS16448(::aos::ShmEventLoop *event_loop, frc::SPI::Port port,
Austin Schuhdf6cbb12019-02-02 13:46:52 -080035 frc::DigitalInput *dio1);
Brian Silverman5f17a972016-02-28 01:49:32 -050036
Brian Silvermana70994f2017-03-16 22:32:55 -070037 // Sets the dummy SPI port to send values on to make the roboRIO deassert the
38 // chip select line. This is mainly useful when there are no other devices
39 // sharing the bus.
Parker Schuhd3b7a8872018-02-19 16:42:27 -080040 void SetDummySPI(frc::SPI::Port port);
Brian Silvermana70994f2017-03-16 22:32:55 -070041
42 // Sets the reset line for the IMU to use for error recovery.
Parker Schuhd3b7a8872018-02-19 16:42:27 -080043 void set_reset(frc::DigitalOutput *output) { reset_ = output; }
Brian Silvermana70994f2017-03-16 22:32:55 -070044
Brian Silvermancfc8fa42019-03-30 21:07:39 -060045 // Sets a function to be called immediately after each time this class uses
46 // the SPI bus. This is a good place to do other things on the bus.
Brian Silverman56c2bcb2019-02-24 15:10:18 -080047 void set_spi_idle_callback(std::function<void()> spi_idle_callback) {
48 spi_idle_callback_ = std::move(spi_idle_callback);
49 }
50
Brian Silverman5f17a972016-02-28 01:49:32 -050051 private:
Brian Silverman7be68ba2020-01-08 22:08:40 -080052 // Initializes the sensor and then takes readings until Quit() is called.
Austin Schuhbd1fe9c2019-06-29 16:35:48 -070053 void DoRun();
54
Brian Silvermana70994f2017-03-16 22:32:55 -070055 // Try to initialize repeatedly as long as we're supposed to be running.
56 void InitializeUntilSuccessful();
57
Brian Silverman5f17a972016-02-28 01:49:32 -050058 // Converts a 16-bit value at data to a scaled output value where a value of 1
59 // corresponds to lsb_per_output.
60 float ConvertValue(uint8_t *data, double lsb_per_output, bool sign = true);
61
62 // Performs an SPI transaction.
63 // Returns true if it succeeds.
64 template <uint8_t size>
65 bool DoTransaction(uint8_t to_send[size], uint8_t to_receive[size]);
66
67 // Reads one of the gyro's registers and returns the value in value.
68 // next_address is the address of the *next* register to read.
69 // Not sure what gets stored in value for the first read, but it should be
70 // ignored. Passing nullptr for value is allowed to completely ignore it.
71 // Returns true if it succeeds.
72 bool ReadRegister(uint8_t next_address, uint16_t *value);
73
74 // Writes a value to one of the registers.
75 // Returns true if it succeeds.
76 bool WriteRegister(uint8_t address, uint16_t value);
77
78 // Checks the given value of the DIAG_STAT register and logs any errors.
79 // Returns true if there are no errors we care about.
80 bool CheckDiagStatValue(uint16_t value) const;
81
82 // Starts everything up and runs a self test.
83 // Returns true if it succeeds.
84 bool Initialize();
85
Austin Schuhdf6cbb12019-02-02 13:46:52 -080086 ::aos::EventLoop *event_loop_;
Austin Schuhdd7ded62021-06-20 14:35:56 -070087 ::aos::Sender<::frc971::IMUValuesBatch> imu_values_sender_;
Austin Schuhdf6cbb12019-02-02 13:46:52 -080088
Brian Silvermana70994f2017-03-16 22:32:55 -070089 // TODO(Brian): This object has no business owning these ones.
Parker Schuhd3b7a8872018-02-19 16:42:27 -080090 const ::std::unique_ptr<frc::SPI> spi_;
91 ::std::unique_ptr<frc::SPI> dummy_spi_;
92 frc::DigitalInput *const dio1_;
93 frc::DigitalOutput *reset_ = nullptr;
Brian Silverman5f17a972016-02-28 01:49:32 -050094
Brian Silverman56c2bcb2019-02-24 15:10:18 -080095 std::function<void()> spi_idle_callback_ = []() {};
Philipp Schrader29d54f22016-04-02 22:14:48 +000096
Brian Silverman003a4732018-03-11 14:02:15 -070097 SpiRxClearer rx_clearer_;
Brian Silverman7be68ba2020-01-08 22:08:40 -080098
99 FpgaTimeConverter time_converter_;
Brian Silverman5f17a972016-02-28 01:49:32 -0500100};
101
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800102} // namespace frc971::wpilib
Brian Silverman5f17a972016-02-28 01:49:32 -0500103
104#endif // FRC971_WPILIB_ADIS16448_H_