blob: 503b6d0797d78fb59b74d72d7570fb71a2730783 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2008-2018 FIRST. 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 "frc/Utility.h"
9
10#ifndef _WIN32
11#include <cxxabi.h>
12#include <execinfo.h>
13#endif
14
15#include <cstdio>
16#include <cstdlib>
17#include <cstring>
18
19#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>
24
25#include "frc/ErrorBase.h"
26
27using namespace frc;
28
29bool wpi_assert_impl(bool conditionValue, const wpi::Twine& conditionText,
30 const wpi::Twine& message, wpi::StringRef fileName,
31 int lineNumber, wpi::StringRef funcName) {
32 if (!conditionValue) {
33 wpi::SmallString<128> locBuf;
34 wpi::raw_svector_ostream locStream(locBuf);
35 locStream << funcName << " [" << wpi::sys::path::filename(fileName) << ":"
36 << lineNumber << "]";
37
38 wpi::SmallString<128> errorBuf;
39 wpi::raw_svector_ostream errorStream(errorBuf);
40
41 errorStream << "Assertion \"" << conditionText << "\" ";
42
43 if (message.isTriviallyEmpty() ||
44 (message.isSingleStringRef() && message.getSingleStringRef().empty())) {
45 errorStream << "failed.\n";
46 } else {
47 errorStream << "failed: " << message << "\n";
48 }
49
50 std::string stack = GetStackTrace(2);
51
52 // Print the error and send it to the DriverStation
53 HAL_SendError(1, 1, 0, errorBuf.c_str(), locBuf.c_str(), stack.c_str(), 1);
54 }
55
56 return conditionValue;
57}
58
59/**
60 * Common error routines for wpi_assertEqual_impl and wpi_assertNotEqual_impl.
61 *
62 * This should not be called directly; it should only be used by
63 * wpi_assertEqual_impl and wpi_assertNotEqual_impl.
64 */
65void wpi_assertEqual_common_impl(const wpi::Twine& valueA,
66 const wpi::Twine& valueB,
67 const wpi::Twine& equalityType,
68 const wpi::Twine& message,
69 wpi::StringRef fileName, int lineNumber,
70 wpi::StringRef funcName) {
71 wpi::SmallString<128> locBuf;
72 wpi::raw_svector_ostream locStream(locBuf);
73 locStream << funcName << " [" << wpi::sys::path::filename(fileName) << ":"
74 << lineNumber << "]";
75
76 wpi::SmallString<128> errorBuf;
77 wpi::raw_svector_ostream errorStream(errorBuf);
78
79 errorStream << "Assertion \"" << valueA << " " << equalityType << " "
80 << valueB << "\" ";
81
82 if (message.isTriviallyEmpty() ||
83 (message.isSingleStringRef() && message.getSingleStringRef().empty())) {
84 errorStream << "failed.\n";
85 } else {
86 errorStream << "failed: " << message << "\n";
87 }
88
89 std::string trace = GetStackTrace(3);
90
91 // Print the error and send it to the DriverStation
92 HAL_SendError(1, 1, 0, errorBuf.c_str(), locBuf.c_str(), trace.c_str(), 1);
93}
94
95bool wpi_assertEqual_impl(int valueA, int valueB,
96 const wpi::Twine& valueAString,
97 const wpi::Twine& valueBString,
98 const wpi::Twine& message, wpi::StringRef fileName,
99 int lineNumber, wpi::StringRef funcName) {
100 if (!(valueA == valueB)) {
101 wpi_assertEqual_common_impl(valueAString, valueBString, "==", message,
102 fileName, lineNumber, funcName);
103 }
104 return valueA == valueB;
105}
106
107bool wpi_assertNotEqual_impl(int valueA, int valueB,
108 const wpi::Twine& valueAString,
109 const wpi::Twine& valueBString,
110 const wpi::Twine& message, wpi::StringRef fileName,
111 int lineNumber, wpi::StringRef funcName) {
112 if (!(valueA != valueB)) {
113 wpi_assertEqual_common_impl(valueAString, valueBString, "!=", message,
114 fileName, lineNumber, funcName);
115 }
116 return valueA != valueB;
117}
118
119namespace frc {
120
121int GetFPGAVersion() {
122 int32_t status = 0;
123 int version = HAL_GetFPGAVersion(&status);
124 wpi_setGlobalErrorWithContext(status, HAL_GetErrorMessage(status));
125 return version;
126}
127
128int64_t GetFPGARevision() {
129 int32_t status = 0;
130 int64_t revision = HAL_GetFPGARevision(&status);
131 wpi_setGlobalErrorWithContext(status, HAL_GetErrorMessage(status));
132 return revision;
133}
134
135uint64_t GetFPGATime() {
136 int32_t status = 0;
137 uint64_t time = HAL_GetFPGATime(&status);
138 wpi_setGlobalErrorWithContext(status, HAL_GetErrorMessage(status));
139 return time;
140}
141
142bool GetUserButton() {
143 int32_t status = 0;
144
145 bool value = HAL_GetFPGAButton(&status);
146 wpi_setGlobalError(status);
147
148 return value;
149}
150
151#ifndef _WIN32
152
153/**
154 * Demangle a C++ symbol, used for printing stack traces.
155 */
156static std::string demangle(char const* mangledSymbol) {
157 char buffer[256];
158 size_t length;
159 int32_t status;
160
161 if (std::sscanf(mangledSymbol, "%*[^(]%*[(]%255[^)+]", buffer)) {
162 char* symbol = abi::__cxa_demangle(buffer, nullptr, &length, &status);
163 if (status == 0) {
164 return symbol;
165 } else {
166 // If the symbol couldn't be demangled, it's probably a C function,
167 // so just return it as-is.
168 return buffer;
169 }
170 }
171
172 // If everything else failed, just return the mangled symbol
173 return mangledSymbol;
174}
175
176std::string GetStackTrace(int offset) {
177 void* stackTrace[128];
178 int stackSize = backtrace(stackTrace, 128);
179 char** mangledSymbols = backtrace_symbols(stackTrace, stackSize);
180 wpi::SmallString<1024> buf;
181 wpi::raw_svector_ostream trace(buf);
182
183 for (int i = offset; i < stackSize; i++) {
184 // Only print recursive functions once in a row.
185 if (i == 0 || stackTrace[i] != stackTrace[i - 1]) {
186 trace << "\tat " << demangle(mangledSymbols[i]) << "\n";
187 }
188 }
189
190 std::free(mangledSymbols);
191
192 return trace.str();
193}
194
195#else
196static std::string demangle(char const* mangledSymbol) {
197 return "no demangling on windows";
198}
199
200std::string GetStackTrace(int offset) { return "no stack trace on windows"; }
201#endif
202
203} // namespace frc