Brian Silverman | 7be68ba | 2020-01-08 22:08:40 -0800 | [diff] [blame] | 1 | #ifndef FRC971_WPILIB_ADIS16470_H_ |
| 2 | #define FRC971_WPILIB_ADIS16470_H_ |
| 3 | |
| 4 | #include "absl/types/span.h" |
| 5 | |
| 6 | #include "aos/events/event_loop.h" |
| 7 | #include "frc971/wpilib/ahal/DigitalInput.h" |
| 8 | #include "frc971/wpilib/ahal/DigitalOutput.h" |
| 9 | #include "frc971/wpilib/ahal/DigitalSource.h" |
| 10 | #include "frc971/wpilib/ahal/SPI.h" |
| 11 | #include "frc971/wpilib/fpga_time_conversion.h" |
Austin Schuh | ac17fba | 2020-03-28 15:55:33 -0700 | [diff] [blame] | 12 | #include "frc971/wpilib/imu_batch_generated.h" |
Brian Silverman | 7be68ba | 2020-01-08 22:08:40 -0800 | [diff] [blame] | 13 | #include "frc971/wpilib/imu_generated.h" |
| 14 | |
| 15 | namespace frc971 { |
| 16 | namespace wpilib { |
| 17 | |
| 18 | // Handles interfacing with an Analog Devices ADIS16470 over SPI and sending the |
| 19 | // resulting values out on a channel. |
| 20 | // |
| 21 | // This relies on the AutoRead functionality in the FPGA to read values when |
| 22 | // data is ready. It then allows the FPGA to buffer those until right before the |
| 23 | // relevant control loops run, at which point they are all sent out on the |
| 24 | // relevant channel. |
| 25 | class ADIS16470 { |
| 26 | public: |
| 27 | // event_loop's thread will be hijacked before processing any events. |
| 28 | // spi is how to talk to the sensor over SPI. |
| 29 | // data_ready is the Data Ready (DR) pin (J6). |
| 30 | // reset is the Reset (RST) pin (F3). |
| 31 | ADIS16470(aos::EventLoop *event_loop, frc::SPI *spi, |
| 32 | frc::DigitalInput *data_ready, frc::DigitalOutput *reset); |
| 33 | |
| 34 | ADIS16470(const ADIS16470 &) = delete; |
| 35 | ADIS16470 &operator=(const ADIS16470 &) = delete; |
| 36 | |
| 37 | // Reads all the queued-up data and sends out any complete readings. |
| 38 | void DoReads(); |
| 39 | |
| 40 | private: |
| 41 | enum class State { |
| 42 | kUninitialized, |
| 43 | kWaitForReset, |
| 44 | kRunning, |
| 45 | }; |
| 46 | |
| 47 | // Performs one (non-blocking) initialization step. |
| 48 | void DoInitializeStep(); |
| 49 | |
| 50 | // Processes a complete reading in read_data_. |
Austin Schuh | ac17fba | 2020-03-28 15:55:33 -0700 | [diff] [blame] | 51 | flatbuffers::Offset<IMUValues> ProcessReading( |
| 52 | flatbuffers::FlatBufferBuilder *fbb); |
Brian Silverman | 7be68ba | 2020-01-08 22:08:40 -0800 | [diff] [blame] | 53 | |
| 54 | // Converts a 32-bit value at data to a scaled output value where a value of 1 |
| 55 | // corresponds to lsb_per_output. |
| 56 | static double ConvertValue32(absl::Span<const uint32_t> data, |
| 57 | double lsb_per_output); |
| 58 | static double ConvertValue16(absl::Span<const uint32_t> data, |
| 59 | double lsb_per_output); |
| 60 | |
| 61 | static flatbuffers::Offset<ADIS16470DiagStat> PackDiagStat( |
| 62 | flatbuffers::FlatBufferBuilder *fbb, uint16_t value); |
| 63 | |
| 64 | static bool DiagStatHasError(const ADIS16470DiagStat &diag_stat); |
| 65 | |
| 66 | // These may only be called during configuration, when spi_ is not in |
| 67 | // automatic mode. |
| 68 | uint16_t ReadRegister(uint8_t register_address, |
| 69 | uint8_t next_register_address); |
| 70 | void WriteRegister(uint8_t register_address, uint16_t value); |
| 71 | |
| 72 | void BeginInitialization() { |
| 73 | state_ = State::kUninitialized; |
Philipp Schrader | a671252 | 2023-07-05 20:25:11 -0700 | [diff] [blame] | 74 | initialize_timer_->Schedule(event_loop_->monotonic_now() + |
| 75 | std::chrono::milliseconds(25)); |
Brian Silverman | 7be68ba | 2020-01-08 22:08:40 -0800 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | aos::EventLoop *const event_loop_; |
Austin Schuh | ac17fba | 2020-03-28 15:55:33 -0700 | [diff] [blame] | 79 | aos::Sender<::frc971::IMUValuesBatch> imu_values_sender_; |
Brian Silverman | 7be68ba | 2020-01-08 22:08:40 -0800 | [diff] [blame] | 80 | aos::TimerHandler *const initialize_timer_; |
| 81 | |
| 82 | frc::SPI *const spi_; |
| 83 | frc::DigitalInput *const data_ready_; |
| 84 | frc::DigitalOutput *const reset_; |
| 85 | |
| 86 | State state_ = State::kUninitialized; |
| 87 | |
| 88 | // Data we've read from the FPGA. |
| 89 | std::array<uint32_t, 23> read_data_; |
| 90 | // Data that we need to read from the FPGA to get a complete reading. |
| 91 | absl::Span<uint32_t> to_read_; |
| 92 | |
| 93 | FpgaTimeConverter time_converter_; |
| 94 | }; |
| 95 | |
| 96 | } // namespace wpilib |
| 97 | } // namespace frc971 |
| 98 | |
| 99 | #endif // FRC971_WPILIB_ADIS16470_H_ |