blob: 3323fe21c9792eda7875aeefc75cbf55e99070e9 [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 "ErrorBase.h"
9
10#include <cerrno>
11#include <cstdio>
12#include <cstring>
13#include <iomanip>
14#include <sstream>
15
16#define WPI_ERRORS_DEFINE_STRINGS
17#include "WPIErrors.h"
18
19using namespace frc;
20
21priority_mutex ErrorBase::_globalErrorMutex;
22Error ErrorBase::_globalError;
23
24/**
25 * @brief Retrieve the current error.
26 * Get the current error information associated with this sensor.
27 */
28Error& ErrorBase::GetError() { return m_error; }
29
30const Error& ErrorBase::GetError() const { return m_error; }
31
32/**
33 * @brief Clear the current error information associated with this sensor.
34 */
35void ErrorBase::ClearError() const { m_error.Clear(); }
36
37/**
38 * @brief Set error information associated with a C library call that set an
39 * error to the "errno" global variable.
40 *
41 * @param contextMessage A custom message from the code that set the error.
42 * @param filename Filename of the error source
43 * @param function Function of the error source
44 * @param lineNumber Line number of the error source
45 */
46void ErrorBase::SetErrnoError(llvm::StringRef contextMessage,
47 llvm::StringRef filename,
48 llvm::StringRef function, int lineNumber) const {
49 std::string err;
50 int errNo = errno;
51 if (errNo == 0) {
52 err = "OK: ";
53 err += contextMessage;
54 } else {
55 std::ostringstream oss;
56 oss << std::strerror(errNo) << " (0x" << std::setfill('0') << std::hex
57 << std::uppercase << std::setw(8) << errNo << "): " << contextMessage;
58 err = oss.str();
59 }
60
61 // Set the current error information for this object.
62 m_error.Set(-1, err, filename, function, lineNumber, this);
63
64 // Update the global error if there is not one already set.
65 std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
66 if (_globalError.GetCode() == 0) {
67 _globalError.Clone(m_error);
68 }
69}
70
71/**
72 * @brief Set the current error information associated from the nivision Imaq
73 * API.
74 *
75 * @param success The return from the function
76 * @param contextMessage A custom message from the code that set the error.
77 * @param filename Filename of the error source
78 * @param function Function of the error source
79 * @param lineNumber Line number of the error source
80 */
81void ErrorBase::SetImaqError(int success, llvm::StringRef contextMessage,
82 llvm::StringRef filename, llvm::StringRef function,
83 int lineNumber) const {
84 // If there was an error
85 if (success <= 0) {
86 std::stringstream err;
87 err << success << ": " << contextMessage;
88
89 // Set the current error information for this object.
90 m_error.Set(success, err.str(), filename, function, lineNumber, this);
91
92 // Update the global error if there is not one already set.
93 std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
94 if (_globalError.GetCode() == 0) {
95 _globalError.Clone(m_error);
96 }
97 }
98}
99
100/**
101 * @brief Set the current error information associated with this sensor.
102 *
103 * @param code The error code
104 * @param contextMessage A custom message from the code that set the error.
105 * @param filename Filename of the error source
106 * @param function Function of the error source
107 * @param lineNumber Line number of the error source
108 */
109void ErrorBase::SetError(Error::Code code, llvm::StringRef contextMessage,
110 llvm::StringRef filename, llvm::StringRef function,
111 int lineNumber) const {
112 // If there was an error
113 if (code != 0) {
114 // Set the current error information for this object.
115 m_error.Set(code, contextMessage, filename, function, lineNumber, this);
116
117 // Update the global error if there is not one already set.
118 std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
119 if (_globalError.GetCode() == 0) {
120 _globalError.Clone(m_error);
121 }
122 }
123}
124
125/**
126 * @brief Set the current error information associated with this sensor.
127 * Range versions use for initialization code.
128 *
129 * @param code The error code
130 * @param minRange The minimum allowed allocation range
131 * @param maxRange The maximum allowed allocation range
132 * @param requestedValue The requested value to allocate
133 * @param contextMessage A custom message from the code that set the error.
134 * @param filename Filename of the error source
135 * @param function Function of the error source
136 * @param lineNumber Line number of the error source
137 */
138void ErrorBase::SetErrorRange(Error::Code code, int32_t minRange,
139 int32_t maxRange, int32_t requestedValue,
140 llvm::StringRef contextMessage,
141 llvm::StringRef filename,
142 llvm::StringRef function, int lineNumber) const {
143 // If there was an error
144 if (code != 0) {
145 size_t size = contextMessage.size() + 100;
146 char* buf = new char[size];
147 std::snprintf(
148 buf, size,
149 "%s, Minimum Value: %d, Maximum Value: %d, Requested Value: %d",
150 contextMessage.data(), minRange, maxRange, requestedValue);
151 // Set the current error information for this object.
152 m_error.Set(code, buf, filename, function, lineNumber, this);
153 delete[] buf;
154
155 // Update the global error if there is not one already set.
156 std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
157 if (_globalError.GetCode() == 0) {
158 _globalError.Clone(m_error);
159 }
160 }
161}
162
163/**
164 * @brief Set the current error information associated with this sensor.
165 *
166 * @param errorMessage The error message from WPIErrors.h
167 * @param contextMessage A custom message from the code that set the error.
168 * @param filename Filename of the error source
169 * @param function Function of the error source
170 * @param lineNumber Line number of the error source
171 */
172void ErrorBase::SetWPIError(llvm::StringRef errorMessage, Error::Code code,
173 llvm::StringRef contextMessage,
174 llvm::StringRef filename, llvm::StringRef function,
175 int lineNumber) const {
176 std::string err = errorMessage.str() + ": " + contextMessage.str();
177
178 // Set the current error information for this object.
179 m_error.Set(code, err, filename, function, lineNumber, this);
180
181 // Update the global error if there is not one already set.
182 std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
183 if (_globalError.GetCode() == 0) {
184 _globalError.Clone(m_error);
185 }
186}
187
188void ErrorBase::CloneError(const ErrorBase& rhs) const {
189 m_error.Clone(rhs.GetError());
190}
191
192/**
193 * @brief Check if the current error code represents a fatal error.
194 *
195 * @return true if the current error is fatal.
196 */
197bool ErrorBase::StatusIsFatal() const { return m_error.GetCode() < 0; }
198
199void ErrorBase::SetGlobalError(Error::Code code, llvm::StringRef contextMessage,
200 llvm::StringRef filename,
201 llvm::StringRef function, int lineNumber) {
202 // If there was an error
203 if (code != 0) {
204 std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
205
206 // Set the current error information for this object.
207 _globalError.Set(code, contextMessage, filename, function, lineNumber,
208 nullptr);
209 }
210}
211
212void ErrorBase::SetGlobalWPIError(llvm::StringRef errorMessage,
213 llvm::StringRef contextMessage,
214 llvm::StringRef filename,
215 llvm::StringRef function, int lineNumber) {
216 std::string err = errorMessage.str() + ": " + contextMessage.str();
217
218 std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
219 if (_globalError.GetCode() != 0) {
220 _globalError.Clear();
221 }
222 _globalError.Set(-1, err, filename, function, lineNumber, nullptr);
223}
224
225/**
226 * Retrieve the current global error.
227 */
228Error& ErrorBase::GetGlobalError() {
229 std::lock_guard<priority_mutex> mutex(_globalErrorMutex);
230 return _globalError;
231}