CTRE Phoenix Pro C++ 23.0.12
ParentDevice.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) Cross The Road Electronics.  All rights reserved.
3 * License information can be found in CTRE_LICENSE.txt
4 * For support and suggestions contact support@ctr-electronics.com or file
5 * an issue tracker at https://github.com/CrossTheRoadElec/Phoenix-Releases
6 */
7#pragma once
8
17#include <map>
18#include <memory>
19#include <mutex>
20#include <units/dimensionless.h>
21
22namespace ctre {
23namespace phoenixpro {
24namespace hardware {
25
26 /**
27 * Parent class for all devices
28 */
30 {
31 protected:
33
34 virtual void ReportIfTooOld() = 0;
35
36 private:
37 std::map<uint32_t, std::unique_ptr<BaseStatusSignalValue>> _signalValues;
38 std::recursive_mutex _signalValuesLck;
39 /**
40 * Use a shared pointer so users that access the control request via #GetAppliedControl has a copy
41 * of the pointer without risk of it becoming a dangling pointer due to parallel operations
42 */
43 std::shared_ptr<controls::ControlRequest> _controlReq = std::make_shared<controls::EmptyControl>();
44 std::mutex _controlReqLck;
45
46 units::time::second_t _resetTimestamp{};
47
48 template <typename T>
49 StatusSignalValue<T> &LookupCommon(uint16_t spn, uint16_t mapper_iter, std::function<std::map<int, StatusSignalValue<T>>()> map_filler, std::string signalName, bool reportOnConstruction)
50 {
52 {
53 /* lock access to the map */
54 std::lock_guard<std::recursive_mutex> lock{_signalValuesLck};
55
56 const uint32_t totalHash = spn | ((uint32_t)mapper_iter << 16);
57 /* lookup and return if found */
58 auto iter = _signalValues.find(totalHash);
59 if (iter != _signalValues.end())
60 {
61 /* Found it, toFind is now the found StatusSignalValue */
62 toFind = iter->second.get();
63 /* since we didn't construct, report errors */
64 reportOnConstruction = true;
65 }
66 else
67 {
68 /* insert into map */
69 /* Mapper_iter is 0 when using straight SPNs, otherwise it's nonzero for switchable SPNs */
70 if (mapper_iter != 0)
71 {
72 /* Switchable spn, so generate the map to switch with */
73 _signalValues.emplace(totalHash, std::unique_ptr<StatusSignalValue<T>>{new StatusSignalValue<T>{
74 deviceIdentifier, spn, [this]()
75 { ReportIfTooOld(); },
76 map_filler, std::move(signalName)}});
77 }
78 else
79 {
80 /* Non-switchable spn, so just add the SPN plain */
81 _signalValues.emplace(totalHash, std::unique_ptr<StatusSignalValue<T>>{new StatusSignalValue<T>{
82 deviceIdentifier, spn, [this]()
83 { ReportIfTooOld(); },
84 std::move(signalName)}});
85 }
86
87 /* look up and return */
88 iter = _signalValues.find(totalHash);
89 toFind = iter->second.get();
90 }
91 }
92
93 /* Now cast it up to the StatusSignalValue */
94 StatusSignalValue<T> *ret = dynamic_cast<StatusSignalValue<T> *>(toFind);
95 /* If ret is null, that means the cast failed. Otherwise we can return it */
96 if (ret == nullptr)
97 {
98 /* Cast failed, let user know this doesn't exist */
99 static StatusSignalValue<T> failure{ctre::phoenix::StatusCode::InvalidParamValue};
100 return failure;
101 }
102 else
103 {
104 /* Good cast, refresh it and return this now */
105 ret->Refresh(reportOnConstruction);
106 return *ret;
107 }
108 }
109
110 public:
111 ParentDevice(int deviceID, std::string model, std::string canbus) :
112 deviceIdentifier{DeviceIdentifier{deviceID, std::move(model), std::move(canbus)}}
113 {
114 ctre::phoenix::platform::FRC_Report(model, deviceID + 1, canbus, 1);
115 }
116
117 /**
118 * \returns the device ID of this device [0,62].
119 */
120 int GetDeviceID() const
121 {
123 }
124
125 /**
126 * \returns name of the CAN bus this device is on.
127 */
128 const std::string &GetCANBus() const
129 {
131 }
132
133 static constexpr double kDefaultControlRatePeriodsSec = 0.010;
134
135 /**
136 * \brief Get the latest applied control.
137 *
138 * \details This returns a shared pointer to avoid becoming a dangling pointer
139 * due to parallel operations changing the underlying data.
140 *
141 * \returns Latest applied control
142 */
143 std::shared_ptr<const controls::ControlRequest> GetAppliedControl() const
144 {
145 return _controlReq;
146 }
147
148 /**
149 * \brief Get the latest applied control.
150 *
151 * \details This returns a shared pointer to avoid becoming a dangling pointer
152 * due to parallel operations changing the underlying data.
153 *
154 * \returns Latest applied control
155 */
156 std::shared_ptr<controls::ControlRequest> GetAppliedControl()
157 {
158 return _controlReq;
159 }
160
161 protected:
162 virtual ctre::phoenix::StatusCode SetControlPrivate(controls::ControlRequest &request);
163
164 template <typename T>
165 StatusSignalValue<T> &LookupStatusSignalValue(uint16_t spn, std::string signalName, bool reportOnConstruction)
166 {
167 std::function<std::map<int, StatusSignalValue<T>>()> emptyMapFiller = []
168 {
169 return std::map<int, StatusSignalValue<T>>{};
170 };
171 return LookupCommon<T>(spn, 0, emptyMapFiller, std::move(signalName), reportOnConstruction);
172 }
173
174 template <typename T>
175 StatusSignalValue<T> &LookupStatusSignalValue(uint16_t spn, uint16_t mapper_iter, std::function<std::map<int, StatusSignalValue<T>>()> map_filler, std::string signalName, bool reportOnConstruction)
176 {
177 return LookupCommon<T>(spn, mapper_iter, map_filler, std::move(signalName), reportOnConstruction);
178 }
179
180 /** Returns a unitless version of the StatusSignalValue by value. Do not store the result in a reference. */
181 template <typename T, typename U>
182 StatusSignalValue<T> LookupDimensionlessStatusSignalValue(uint16_t spn, std::string signalName)
183 {
184 return StatusSignalValue<T>{LookupStatusSignalValue<U>(spn, std::move(signalName), true)};
185 }
186
187 void ReportIfTooOld(int minMajor, int minMinor, int minBugfix, int minBuild);
188 };
189
190}
191}
192}
@ InvalidParamValue
Incorrect argument passed into function/VI.
Definition: StatusCodes.h:1425
Definition: StatusSignalValue.hpp:40
Definition: StatusSignalValue.hpp:320
Abstract Control Request class that other control requests extend for use.
Definition: ControlRequest.hpp:65
Definition: DeviceIdentifier.hpp:19
int deviceID
Definition: DeviceIdentifier.hpp:23
std::string network
Definition: DeviceIdentifier.hpp:21
Parent class for all devices.
Definition: ParentDevice.hpp:30
static constexpr double kDefaultControlRatePeriodsSec
Definition: ParentDevice.hpp:133
std::shared_ptr< controls::ControlRequest > GetAppliedControl()
Get the latest applied control.
Definition: ParentDevice.hpp:156
std::shared_ptr< const controls::ControlRequest > GetAppliedControl() const
Get the latest applied control.
Definition: ParentDevice.hpp:143
StatusSignalValue< T > & LookupStatusSignalValue(uint16_t spn, uint16_t mapper_iter, std::function< std::map< int, StatusSignalValue< T > >()> map_filler, std::string signalName, bool reportOnConstruction)
Definition: ParentDevice.hpp:175
void ReportIfTooOld(int minMajor, int minMinor, int minBugfix, int minBuild)
StatusSignalValue< T > LookupDimensionlessStatusSignalValue(uint16_t spn, std::string signalName)
Returns a unitless version of the StatusSignalValue by value.
Definition: ParentDevice.hpp:182
ParentDevice(int deviceID, std::string model, std::string canbus)
Definition: ParentDevice.hpp:111
int GetDeviceID() const
Definition: ParentDevice.hpp:120
const std::string & GetCANBus() const
Definition: ParentDevice.hpp:128
virtual ctre::phoenix::StatusCode SetControlPrivate(controls::ControlRequest &request)
StatusSignalValue< T > & LookupStatusSignalValue(uint16_t spn, std::string signalName, bool reportOnConstruction)
Definition: ParentDevice.hpp:165
DeviceIdentifier deviceIdentifier
Definition: ParentDevice.hpp:32
CTREXPORT int FRC_Report(int resource, int instanceNumber, std::string const &canbus="", int callerIdx=0, int context=0, const char *feature=nullptr)
Definition: string_util.hpp:14