blob: f4b9f389345e67b2b40e92737595766e515ebb42 [file] [log] [blame]
Parker Schuhd3b7a8872018-02-19 16:42:27 -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 "frc971/wpilib/ahal/Utility.h"
9
10#include <cxxabi.h>
11#include <execinfo.h>
12
13#include <cstdio>
14#include <cstdlib>
15#include <cstring>
16#include <sstream>
17
Parker Schuhd3b7a8872018-02-19 16:42:27 -080018#include "frc971/wpilib/ahal/ErrorBase.h"
Austin Schuhf6b94632019-02-02 22:11:27 -080019#include "hal/DriverStation.h"
20#include "hal/HAL.h"
21#include "wpi/Path.h"
22#include "wpi/SmallString.h"
23#include "wpi/raw_ostream.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080024
25using namespace frc;
26
27/**
28 * Assert implementation.
29 * This allows breakpoints to be set on an assert.
30 * The users don't call this, but instead use the wpi_assert macros in
31 * Utility.h.
32 */
Austin Schuhf6b94632019-02-02 22:11:27 -080033bool wpi_assert_impl(bool conditionValue, const wpi::Twine &conditionText,
34 const wpi::Twine &message, wpi::StringRef fileName,
35 int lineNumber, wpi::StringRef funcName) {
Parker Schuhd3b7a8872018-02-19 16:42:27 -080036 if (!conditionValue) {
Austin Schuhf6b94632019-02-02 22:11:27 -080037 wpi::SmallString<128> locBuf;
38 wpi::raw_svector_ostream locStream(locBuf);
39 locStream << funcName << " [" << wpi::sys::path::filename(fileName) << ":"
40 << lineNumber << "]";
Parker Schuhd3b7a8872018-02-19 16:42:27 -080041
Austin Schuhf6b94632019-02-02 22:11:27 -080042 wpi::SmallString<128> errorBuf;
43 wpi::raw_svector_ostream errorStream(errorBuf);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080044
45 errorStream << "Assertion \"" << conditionText << "\" ";
46
Austin Schuhf6b94632019-02-02 22:11:27 -080047 if (message.isTriviallyEmpty() ||
48 (message.isSingleStringRef() && message.getSingleStringRef().empty())) {
49 errorStream << "failed.\n";
Parker Schuhd3b7a8872018-02-19 16:42:27 -080050 } else {
Austin Schuhf6b94632019-02-02 22:11:27 -080051 errorStream << "failed: " << message << "\n";
Parker Schuhd3b7a8872018-02-19 16:42:27 -080052 }
53
54 std::string stack = GetStackTrace(2);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080055
56 // Print the error and send it to the DriverStation
Austin Schuhf6b94632019-02-02 22:11:27 -080057 HAL_SendError(1, 1, 0, errorBuf.c_str(), locBuf.c_str(), stack.c_str(), 1);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080058 }
59
60 return conditionValue;
61}
62
63/**
64 * Common error routines for wpi_assertEqual_impl and wpi_assertNotEqual_impl
65 * This should not be called directly; it should only be used by
66 * wpi_assertEqual_impl and wpi_assertNotEqual_impl.
67 */
Austin Schuhf6b94632019-02-02 22:11:27 -080068void wpi_assertEqual_common_impl(const wpi::Twine &valueA,
69 const wpi::Twine &valueB,
70 const wpi::Twine &equalityType,
71 const wpi::Twine &message,
72 wpi::StringRef fileName, int lineNumber,
73 wpi::StringRef funcName) {
74 wpi::SmallString<128> locBuf;
75 wpi::raw_svector_ostream locStream(locBuf);
76 locStream << funcName << " [" << wpi::sys::path::filename(fileName) << ":"
77 << lineNumber << "]";
Parker Schuhd3b7a8872018-02-19 16:42:27 -080078
Austin Schuhf6b94632019-02-02 22:11:27 -080079 wpi::SmallString<128> errorBuf;
80 wpi::raw_svector_ostream errorStream(errorBuf);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080081
82 errorStream << "Assertion \"" << valueA << " " << equalityType << " "
83 << valueB << "\" ";
84
Austin Schuhf6b94632019-02-02 22:11:27 -080085 if (message.isTriviallyEmpty() ||
86 (message.isSingleStringRef() && message.getSingleStringRef().empty())) {
87 errorStream << "failed.\n";
Parker Schuhd3b7a8872018-02-19 16:42:27 -080088 } else {
Austin Schuhf6b94632019-02-02 22:11:27 -080089 errorStream << "failed: " << message << "\n";
Parker Schuhd3b7a8872018-02-19 16:42:27 -080090 }
91
92 std::string trace = GetStackTrace(3);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080093
94 // Print the error and send it to the DriverStation
Austin Schuhf6b94632019-02-02 22:11:27 -080095 HAL_SendError(1, 1, 0, errorBuf.c_str(), locBuf.c_str(), trace.c_str(), 1);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080096}
97
98/**
99 * Assert equal implementation.
100 * This determines whether the two given integers are equal. If not,
101 * the value of each is printed along with an optional message string.
102 * The users don't call this, but instead use the wpi_assertEqual macros in
103 * Utility.h.
104 */
Austin Schuhf6b94632019-02-02 22:11:27 -0800105bool wpi_assertEqual_impl(int valueA, int valueB,
106 const wpi::Twine &valueAString,
107 const wpi::Twine &valueBString,
108 const wpi::Twine &message, wpi::StringRef fileName,
109 int lineNumber, wpi::StringRef funcName) {
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800110 if (!(valueA == valueB)) {
111 wpi_assertEqual_common_impl(valueAString, valueBString, "==", message,
112 fileName, lineNumber, funcName);
113 }
114 return valueA == valueB;
115}
116
117/**
118 * Assert not equal implementation.
119 * This determines whether the two given integers are equal. If so,
120 * the value of each is printed along with an optional message string.
121 * The users don't call this, but instead use the wpi_assertNotEqual macros in
122 * Utility.h.
123 */
124bool wpi_assertNotEqual_impl(int valueA, int valueB,
Austin Schuhf6b94632019-02-02 22:11:27 -0800125 const wpi::Twine &valueAString,
126 const wpi::Twine &valueBString,
127 const wpi::Twine &message, wpi::StringRef fileName,
128 int lineNumber, wpi::StringRef funcName) {
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800129 if (!(valueA != valueB)) {
130 wpi_assertEqual_common_impl(valueAString, valueBString, "!=", message,
131 fileName, lineNumber, funcName);
132 }
133 return valueA != valueB;
134}
135
136namespace frc {
137
138/**
139 * Return the FPGA Version number.
140 *
141 * For now, expect this to be competition year.
142 * @return FPGA Version number.
143 */
144int GetFPGAVersion() {
145 int32_t status = 0;
146 int version = HAL_GetFPGAVersion(&status);
147 wpi_setGlobalErrorWithContext(status, HAL_GetErrorMessage(status));
148 return version;
149}
150
151/**
152 * Return the FPGA Revision number.
153 * The format of the revision is 3 numbers.
154 * The 12 most significant bits are the Major Revision.
155 * the next 8 bits are the Minor Revision.
156 * The 12 least significant bits are the Build Number.
157 * @return FPGA Revision number.
158 */
159int64_t GetFPGARevision() {
160 int32_t status = 0;
161 int64_t revision = HAL_GetFPGARevision(&status);
162 wpi_setGlobalErrorWithContext(status, HAL_GetErrorMessage(status));
163 return revision;
164}
165
166/**
167 * Read the microsecond-resolution timer on the FPGA.
168 *
169 * @return The current time in microseconds according to the FPGA (since FPGA
170 * reset).
171 */
172uint64_t GetFPGATime() {
173 int32_t status = 0;
174 uint64_t time = HAL_GetFPGATime(&status);
175 wpi_setGlobalErrorWithContext(status, HAL_GetErrorMessage(status));
176 return time;
177}
178
179/**
180 * Get the state of the "USER" button on the roboRIO.
181 *
182 * @return True if the button is currently pressed down
183 */
184bool GetUserButton() {
185 int32_t status = 0;
186
187 bool value = HAL_GetFPGAButton(&status);
188 wpi_setGlobalError(status);
189
190 return value;
191}
192
193/**
194 * Demangle a C++ symbol, used for printing stack traces.
195 */
196static std::string demangle(char const *mangledSymbol) {
197 char buffer[256];
198 size_t length;
199 int32_t status;
200
201 if (std::sscanf(mangledSymbol, "%*[^(]%*[(]%255[^)+]", buffer)) {
202 char *symbol = abi::__cxa_demangle(buffer, nullptr, &length, &status);
203 if (status == 0) {
204 return symbol;
205 } else {
206 // If the symbol couldn't be demangled, it's probably a C function,
207 // so just return it as-is.
208 return buffer;
209 }
210 }
211
212 // If everything else failed, just return the mangled symbol
213 return mangledSymbol;
214}
215
216/**
217 * Get a stack trace, ignoring the first "offset" symbols.
218 * @param offset The number of symbols at the top of the stack to ignore
219 */
220std::string GetStackTrace(int offset) {
221 void *stackTrace[128];
222 int stackSize = backtrace(stackTrace, 128);
223 char **mangledSymbols = backtrace_symbols(stackTrace, stackSize);
224 std::stringstream trace;
225
226 for (int i = offset; i < stackSize; i++) {
227 // Only print recursive functions once in a row.
228 if (i == 0 || stackTrace[i] != stackTrace[i - 1]) {
229 trace << "\tat " << demangle(mangledSymbols[i]) << std::endl;
230 }
231 }
232
233 std::free(mangledSymbols);
234
235 return trace.str();
236}
237
238} // namespace frc