blob: 6d82af8ca2edab6e0bed8cac9879c6b67aff6d62 [file] [log] [blame]
Brian Silvermanb5b46ca2016-03-13 01:14:17 -05001#ifndef FRC971_WPILIB_DMA_H_
2#define FRC971_WPILIB_DMA_H_
Brian Silverman2aa83d72015-01-24 18:03:11 -05003
Brian Silvermand49fd782015-01-30 16:43:17 -05004// Interface to the roboRIO FPGA's DMA features.
Brian Silvermanb5b46ca2016-03-13 01:14:17 -05005// TODO(Brian): Make this less wpilib-like and more frc971-like.
Brian Silvermand49fd782015-01-30 16:43:17 -05006
Brian Silverman2aa83d72015-01-24 18:03:11 -05007#include <stdint.h>
8
9#include <array>
10#include <memory>
11
Austin Schuhf6b94632019-02-02 22:11:27 -080012#include "hal/ChipObject.h"
Brian Silverman2aa83d72015-01-24 18:03:11 -050013
14class DMA;
Brian Silvermane48dbc12017-02-04 20:06:29 -080015namespace frc {
Brian Silvermand49fd782015-01-30 16:43:17 -050016class DigitalSource;
17class AnalogInput;
18class Encoder;
Brian Silvermane48dbc12017-02-04 20:06:29 -080019} // namespace frc
Brian Silverman2aa83d72015-01-24 18:03:11 -050020
Brian Silvermand49fd782015-01-30 16:43:17 -050021// A POD class which stores the data from a DMA sample and provides safe ways to
22// access it.
Brian Silverman2aa83d72015-01-24 18:03:11 -050023class DMASample {
24 public:
Brian Silvermand49fd782015-01-30 16:43:17 -050025 DMASample() = default;
Brian Silverman2aa83d72015-01-24 18:03:11 -050026
Austin Schuh8f314a92015-11-22 21:35:40 -080027 // Returns the FPGA timestamp of the sample in seconds.
Brian Silverman2aa83d72015-01-24 18:03:11 -050028 double GetTimestamp() const;
Austin Schuh8f314a92015-11-22 21:35:40 -080029 // Returns the FPGA timestamp of the sample in microseconds.
Austin Schuh94f51e92017-10-30 19:25:32 -070030 uint64_t GetTime() const;
Brian Silverman2aa83d72015-01-24 18:03:11 -050031
32 // All Get methods either return the requested value, or set the Error.
33
34 // Returns the value of the digital input in the sample.
Parker Schuhd3b7a8872018-02-19 16:42:27 -080035 bool Get(frc::DigitalSource *input) const;
Brian Silverman2aa83d72015-01-24 18:03:11 -050036 // Returns the raw value of the encoder in the sample.
Parker Schuhd3b7a8872018-02-19 16:42:27 -080037 int32_t GetRaw(frc::Encoder *input) const;
Brian Silverman2aa83d72015-01-24 18:03:11 -050038 // Returns the {1, 2, or 4} X scaled value of the encoder in the sample.
Parker Schuhd3b7a8872018-02-19 16:42:27 -080039 int32_t Get(frc::Encoder *input) const;
Brian Silvermand49fd782015-01-30 16:43:17 -050040 // Returns the raw 12-bit value from the ADC.
Parker Schuhd3b7a8872018-02-19 16:42:27 -080041 uint16_t GetValue(frc::AnalogInput *input) const;
Brian Silvermand49fd782015-01-30 16:43:17 -050042 // Returns the scaled value of an analog input.
Parker Schuhd3b7a8872018-02-19 16:42:27 -080043 float GetVoltage(frc::AnalogInput *input) const;
Brian Silverman2aa83d72015-01-24 18:03:11 -050044
45 private:
46 friend DMA;
47
Austin Schuh94f51e92017-10-30 19:25:32 -070048 void CalculateTimestamp();
49
Brian Silverman2aa83d72015-01-24 18:03:11 -050050 // Returns the offset of the sample type in the buffer, or -1 if it isn't in
51 // the sample.
52 ssize_t offset(int index) const;
53
54 // TODO(austin): This should be re-used from WPILib... Once I merge this back
55 // into WPILib.
56
57 DMA *dma_;
Austin Schuh94f51e92017-10-30 19:25:32 -070058 uint64_t fpga_timestamp_;
Brian Silverman2aa83d72015-01-24 18:03:11 -050059 uint32_t read_buffer_[64];
60};
61
Parker Schuhd3b7a8872018-02-19 16:42:27 -080062class DMA {
Brian Silverman2aa83d72015-01-24 18:03:11 -050063 public:
64 DMA();
65 virtual ~DMA();
66
67 // Sets whether or not DMA is paused.
Austin Schuh91c75562015-12-20 22:23:10 -080068 // If not specified, the default is false.
Brian Silverman2aa83d72015-01-24 18:03:11 -050069 void SetPause(bool pause);
70
71 // Sets the number of triggers that need to occur before a sample is saved.
Austin Schuh91c75562015-12-20 22:23:10 -080072 // If not specified, the default is 1.
Brian Silverman2aa83d72015-01-24 18:03:11 -050073 void SetRate(uint32_t cycles);
74
75 // Adds the input signal to the state to snapshot on the trigger event.
Brian Silvermand49fd782015-01-30 16:43:17 -050076 // It is safe to add the same input multiple times, but there is currently
77 // no way to remove one once it has been added.
Brian Silverman2aa83d72015-01-24 18:03:11 -050078 // Call Add() and SetExternalTrigger() before Start().
Parker Schuhd3b7a8872018-02-19 16:42:27 -080079 void Add(frc::Encoder *encoder);
80 void Add(frc::DigitalSource *input);
81 void Add(frc::AnalogInput *input);
Brian Silverman2aa83d72015-01-24 18:03:11 -050082
83 // Configures DMA to trigger on an external trigger. There can only be 4
84 // external triggers.
85 // Call Add() and SetExternalTrigger() before Start().
Parker Schuhd3b7a8872018-02-19 16:42:27 -080086 void SetExternalTrigger(frc::DigitalSource *input, bool rising, bool falling);
Brian Silverman2aa83d72015-01-24 18:03:11 -050087
88 // Starts reading samples into the buffer. Clears all previous samples before
89 // starting.
90 // Call Start() before Read().
91 void Start(size_t queue_depth);
92
93 enum ReadStatus {
94 STATUS_OK = 0,
95 STATUS_TIMEOUT = 1,
96 STATUS_ERROR = 2,
97 };
98
99 // Reads a sample from the DMA buffer, waiting up to timeout_ms for it.
100 // Returns a status code indicating whether the read worked, timed out, or
101 // failed.
Brian Silvermand49fd782015-01-30 16:43:17 -0500102 // Returns in *remaining_out the number of DMA samples still queued after this
103 // Read().
Brian Silverman2aa83d72015-01-24 18:03:11 -0500104 // Call Add() and SetExternalTrigger() then Start() before Read().
105 // The sample is only usable while this DMA object is left started.
Brian Silvermand49fd782015-01-30 16:43:17 -0500106 ReadStatus Read(DMASample *sample, uint32_t timeout_ms,
107 size_t *remaining_out);
108
109 // Translates a ReadStatus code to a string name.
110 static const char *NameOfReadStatus(ReadStatus s);
Brian Silverman2aa83d72015-01-24 18:03:11 -0500111
112 private:
113 ::std::unique_ptr<nFPGA::tDMAManager> manager_; // set by Start()
114 typedef nFPGA::nRoboRIO_FPGANamespace::tDMA tDMA;
115 friend DMASample;
116
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800117// The offsets into the sample structure for each DMA type, or -1 if it isn't
118// in the set of values.
Austin Schuh91c75562015-12-20 22:23:10 -0800119#ifdef WPILIB2015
Brian Silverman2aa83d72015-01-24 18:03:11 -0500120 ssize_t channel_offsets_[18];
Austin Schuh91c75562015-12-20 22:23:10 -0800121#else
122 ssize_t channel_offsets_[20];
123#endif
Brian Silverman2aa83d72015-01-24 18:03:11 -0500124
125 // The size of the data to read to get a sample.
126 size_t capture_size_ = 0;
127 tDMA::tConfig tconfig_;
128 tDMA *tdma_config_;
129
Austin Schuh91c75562015-12-20 22:23:10 -0800130#ifndef WPILIB2015
131 ::std::array<bool, 8> trigger_channels_ = {
132 {false, false, false, false, false, false, false, false}};
133#else
Brian Silverman2aa83d72015-01-24 18:03:11 -0500134 ::std::array<bool, 4> trigger_channels_ = {{false, false, false, false}};
Austin Schuh91c75562015-12-20 22:23:10 -0800135#endif
Brian Silverman2aa83d72015-01-24 18:03:11 -0500136};
137
Brian Silvermanb5b46ca2016-03-13 01:14:17 -0500138#endif // FRC971_WPILIB_DMA_H_