blob: 4a4d0c8caf9a811ead67a3c0fa0afaaf2165eb2d [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008-2017. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "ADXL362.h"
9
10#include "DigitalInput.h"
11#include "DigitalOutput.h"
12#include "DriverStation.h"
13#include "HAL/HAL.h"
14#include "LiveWindow/LiveWindow.h"
15
16using namespace frc;
17
18static int kRegWrite = 0x0A;
19static int kRegRead = 0x0B;
20
21static int kPartIdRegister = 0x02;
22static int kDataRegister = 0x0E;
23static int kFilterCtlRegister = 0x2C;
24static int kPowerCtlRegister = 0x2D;
25
26// static int kFilterCtl_Range2G = 0x00;
27// static int kFilterCtl_Range4G = 0x40;
28// static int kFilterCtl_Range8G = 0x80;
29static int kFilterCtl_ODR_100Hz = 0x03;
30
31static int kPowerCtl_UltraLowNoise = 0x20;
32// static int kPowerCtl_AutoSleep = 0x04;
33static int kPowerCtl_Measure = 0x02;
34
35/**
36 * Constructor. Uses the onboard CS1.
37 *
38 * @param range The range (+ or -) that the accelerometer will measure.
39 */
40ADXL362::ADXL362(Range range) : ADXL362(SPI::Port::kOnboardCS1, range) {}
41
42/**
43 * Constructor.
44 *
45 * @param port The SPI port the accelerometer is attached to
46 * @param range The range (+ or -) that the accelerometer will measure.
47 */
48ADXL362::ADXL362(SPI::Port port, Range range) : m_spi(port) {
49 m_spi.SetClockRate(3000000);
50 m_spi.SetMSBFirst();
51 m_spi.SetSampleDataOnFalling();
52 m_spi.SetClockActiveLow();
53 m_spi.SetChipSelectActiveLow();
54
55 // Validate the part ID
56 uint8_t commands[3];
57 commands[0] = kRegRead;
58 commands[1] = kPartIdRegister;
59 commands[2] = 0;
60 m_spi.Transaction(commands, commands, 3);
61 if (commands[2] != 0xF2) {
62 DriverStation::ReportError("could not find ADXL362");
63 m_gsPerLSB = 0.0;
64 return;
65 }
66
67 SetRange(range);
68
69 // Turn on the measurements
70 commands[0] = kRegWrite;
71 commands[1] = kPowerCtlRegister;
72 commands[2] = kPowerCtl_Measure | kPowerCtl_UltraLowNoise;
73 m_spi.Write(commands, 3);
74
75 HAL_Report(HALUsageReporting::kResourceType_ADXL362, port);
76
77 LiveWindow::GetInstance()->AddSensor("ADXL362", port, this);
78}
79
80void ADXL362::SetRange(Range range) {
81 if (m_gsPerLSB == 0.0) return;
82
83 uint8_t commands[3];
84
85 switch (range) {
86 case kRange_2G:
87 m_gsPerLSB = 0.001;
88 break;
89 case kRange_4G:
90 m_gsPerLSB = 0.002;
91 break;
92 case kRange_8G:
93 case kRange_16G: // 16G not supported; treat as 8G
94 m_gsPerLSB = 0.004;
95 break;
96 }
97
98 // Specify the data format to read
99 commands[0] = kRegWrite;
100 commands[1] = kFilterCtlRegister;
101 commands[2] =
102 kFilterCtl_ODR_100Hz | static_cast<uint8_t>((range & 0x03) << 6);
103 m_spi.Write(commands, 3);
104}
105
106double ADXL362::GetX() { return GetAcceleration(kAxis_X); }
107
108double ADXL362::GetY() { return GetAcceleration(kAxis_Y); }
109
110double ADXL362::GetZ() { return GetAcceleration(kAxis_Z); }
111
112/**
113 * Get the acceleration of one axis in Gs.
114 *
115 * @param axis The axis to read from.
116 * @return Acceleration of the ADXL362 in Gs.
117 */
118double ADXL362::GetAcceleration(ADXL362::Axes axis) {
119 if (m_gsPerLSB == 0.0) return 0.0;
120
121 uint8_t buffer[4];
122 uint8_t command[4] = {0, 0, 0, 0};
123 command[0] = kRegRead;
124 command[1] = kDataRegister + static_cast<uint8_t>(axis);
125 m_spi.Transaction(command, buffer, 4);
126
127 // Sensor is little endian... swap bytes
128 int16_t rawAccel = buffer[3] << 8 | buffer[2];
129 return rawAccel * m_gsPerLSB;
130}
131
132/**
133 * Get the acceleration of all axes in Gs.
134 *
135 * @return An object containing the acceleration measured on each axis of the
136 * ADXL362 in Gs.
137 */
138ADXL362::AllAxes ADXL362::GetAccelerations() {
139 AllAxes data = AllAxes();
140 if (m_gsPerLSB == 0.0) {
141 data.XAxis = data.YAxis = data.ZAxis = 0.0;
142 return data;
143 }
144
145 uint8_t dataBuffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
146 int16_t rawData[3];
147
148 // Select the data address.
149 dataBuffer[0] = kRegRead;
150 dataBuffer[1] = kDataRegister;
151 m_spi.Transaction(dataBuffer, dataBuffer, 8);
152
153 for (int i = 0; i < 3; i++) {
154 // Sensor is little endian... swap bytes
155 rawData[i] = dataBuffer[i * 2 + 3] << 8 | dataBuffer[i * 2 + 2];
156 }
157
158 data.XAxis = rawData[0] * m_gsPerLSB;
159 data.YAxis = rawData[1] * m_gsPerLSB;
160 data.ZAxis = rawData[2] * m_gsPerLSB;
161
162 return data;
163}
164
165std::string ADXL362::GetSmartDashboardType() const {
166 return "3AxisAccelerometer";
167}
168
169void ADXL362::InitTable(std::shared_ptr<ITable> subtable) {
170 m_table = subtable;
171 UpdateTable();
172}
173
174void ADXL362::UpdateTable() {
175 if (m_table != nullptr) {
176 m_table->PutNumber("X", GetX());
177 m_table->PutNumber("Y", GetY());
178 m_table->PutNumber("Z", GetZ());
179 }
180}
181
182std::shared_ptr<ITable> ADXL362::GetTable() const { return m_table; }