blob: dbb99f9b57b220015e82e2ab7a9ff64aa13fe038 [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
Austin Schuh1e69f942020-11-14 15:06:14 -08002/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
Brian Silverman8fce7482020-01-05 13:18:21 -08003/* 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/DriverStation.h"
9
10#include <chrono>
11
12#include <hal/DriverStation.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080013#include <hal/HALBase.h>
14#include <hal/Power.h>
15#include <networktables/NetworkTable.h>
16#include <networktables/NetworkTableEntry.h>
17#include <networktables/NetworkTableInstance.h>
18#include <wpi/SmallString.h>
19#include <wpi/StringRef.h>
20
Brian Silverman8fce7482020-01-05 13:18:21 -080021#include "frc/MotorSafety.h"
22#include "frc/Timer.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080023#include "frc/WPIErrors.h"
24
25namespace frc {
26
27class MatchDataSender {
28 public:
29 std::shared_ptr<nt::NetworkTable> table;
30 nt::NetworkTableEntry typeMetadata;
31 nt::NetworkTableEntry gameSpecificMessage;
32 nt::NetworkTableEntry eventName;
33 nt::NetworkTableEntry matchNumber;
34 nt::NetworkTableEntry replayNumber;
35 nt::NetworkTableEntry matchType;
36 nt::NetworkTableEntry alliance;
37 nt::NetworkTableEntry station;
38 nt::NetworkTableEntry controlWord;
39
40 MatchDataSender() {
41 table = nt::NetworkTableInstance::GetDefault().GetTable("FMSInfo");
42 typeMetadata = table->GetEntry(".type");
43 typeMetadata.ForceSetString("FMSInfo");
44 gameSpecificMessage = table->GetEntry("GameSpecificMessage");
45 gameSpecificMessage.ForceSetString("");
46 eventName = table->GetEntry("EventName");
47 eventName.ForceSetString("");
48 matchNumber = table->GetEntry("MatchNumber");
49 matchNumber.ForceSetDouble(0);
50 replayNumber = table->GetEntry("ReplayNumber");
51 replayNumber.ForceSetDouble(0);
52 matchType = table->GetEntry("MatchType");
53 matchType.ForceSetDouble(0);
54 alliance = table->GetEntry("IsRedAlliance");
55 alliance.ForceSetBoolean(true);
56 station = table->GetEntry("StationNumber");
57 station.ForceSetDouble(1);
58 controlWord = table->GetEntry("FMSControlData");
59 controlWord.ForceSetDouble(0);
60 }
61};
62} // namespace frc
63
64using namespace frc;
65
66static constexpr double kJoystickUnpluggedMessageInterval = 1.0;
67
Austin Schuh1e69f942020-11-14 15:06:14 -080068static int& GetDSLastCount() {
69 // There is a rollover error condition here. At Packet# = n * (uintmax), this
70 // will return false when instead it should return true. However, this at a
71 // 20ms rate occurs once every 2.7 years of DS connected runtime, so not
72 // worth the cycles to check.
73 thread_local int lastCount{0};
74 return lastCount;
75}
76
Brian Silverman8fce7482020-01-05 13:18:21 -080077DriverStation::~DriverStation() {
78 m_isRunning = false;
79 // Trigger a DS mutex release in case there is no driver station running.
80 HAL_ReleaseDSMutex();
81 m_dsThread.join();
82}
83
84DriverStation& DriverStation::GetInstance() {
85 static DriverStation instance;
86 return instance;
87}
88
89void DriverStation::ReportError(const wpi::Twine& error) {
90 wpi::SmallString<128> temp;
91 HAL_SendError(1, 1, 0, error.toNullTerminatedStringRef(temp).data(), "", "",
92 1);
93}
94
95void DriverStation::ReportWarning(const wpi::Twine& error) {
96 wpi::SmallString<128> temp;
97 HAL_SendError(0, 1, 0, error.toNullTerminatedStringRef(temp).data(), "", "",
98 1);
99}
100
101void DriverStation::ReportError(bool isError, int32_t code,
102 const wpi::Twine& error,
103 const wpi::Twine& location,
104 const wpi::Twine& stack) {
105 wpi::SmallString<128> errorTemp;
106 wpi::SmallString<128> locationTemp;
107 wpi::SmallString<128> stackTemp;
108 HAL_SendError(isError, code, 0,
109 error.toNullTerminatedStringRef(errorTemp).data(),
110 location.toNullTerminatedStringRef(locationTemp).data(),
111 stack.toNullTerminatedStringRef(stackTemp).data(), 1);
112}
113
114bool DriverStation::GetStickButton(int stick, int button) {
115 if (stick < 0 || stick >= kJoystickPorts) {
116 wpi_setWPIError(BadJoystickIndex);
117 return false;
118 }
119 if (button <= 0) {
120 ReportJoystickUnpluggedError(
121 "ERROR: Button indexes begin at 1 in WPILib for C++ and Java");
122 return false;
123 }
124
125 HAL_JoystickButtons buttons;
126 HAL_GetJoystickButtons(stick, &buttons);
127
128 if (button > buttons.count) {
129 ReportJoystickUnpluggedWarning(
130 "Joystick Button missing, check if all controllers are plugged in");
131 return false;
132 }
133
134 return buttons.buttons & 1 << (button - 1);
135}
136
137bool DriverStation::GetStickButtonPressed(int stick, int button) {
138 if (stick < 0 || stick >= kJoystickPorts) {
139 wpi_setWPIError(BadJoystickIndex);
140 return false;
141 }
142 if (button <= 0) {
143 ReportJoystickUnpluggedError(
144 "ERROR: Button indexes begin at 1 in WPILib for C++ and Java");
145 return false;
146 }
147
148 HAL_JoystickButtons buttons;
149 HAL_GetJoystickButtons(stick, &buttons);
150
151 if (button > buttons.count) {
152 ReportJoystickUnpluggedWarning(
153 "Joystick Button missing, check if all controllers are plugged in");
154 return false;
155 }
156 std::unique_lock lock(m_buttonEdgeMutex);
157 // If button was pressed, clear flag and return true
158 if (m_joystickButtonsPressed[stick] & 1 << (button - 1)) {
159 m_joystickButtonsPressed[stick] &= ~(1 << (button - 1));
160 return true;
161 } else {
162 return false;
163 }
164}
165
166bool DriverStation::GetStickButtonReleased(int stick, int button) {
167 if (stick < 0 || stick >= kJoystickPorts) {
168 wpi_setWPIError(BadJoystickIndex);
169 return false;
170 }
171 if (button <= 0) {
172 ReportJoystickUnpluggedError(
173 "ERROR: Button indexes begin at 1 in WPILib for C++ and Java");
174 return false;
175 }
176
177 HAL_JoystickButtons buttons;
178 HAL_GetJoystickButtons(stick, &buttons);
179
180 if (button > buttons.count) {
181 ReportJoystickUnpluggedWarning(
182 "Joystick Button missing, check if all controllers are plugged in");
183 return false;
184 }
185 std::unique_lock lock(m_buttonEdgeMutex);
186 // If button was released, clear flag and return true
187 if (m_joystickButtonsReleased[stick] & 1 << (button - 1)) {
188 m_joystickButtonsReleased[stick] &= ~(1 << (button - 1));
189 return true;
190 } else {
191 return false;
192 }
193}
194
195double DriverStation::GetStickAxis(int stick, int axis) {
196 if (stick < 0 || stick >= kJoystickPorts) {
197 wpi_setWPIError(BadJoystickIndex);
198 return 0.0;
199 }
200 if (axis < 0 || axis >= HAL_kMaxJoystickAxes) {
201 wpi_setWPIError(BadJoystickAxis);
202 return 0.0;
203 }
204
205 HAL_JoystickAxes axes;
206 HAL_GetJoystickAxes(stick, &axes);
207
208 if (axis >= axes.count) {
209 ReportJoystickUnpluggedWarning(
210 "Joystick Axis missing, check if all controllers are plugged in");
211 return 0.0;
212 }
213
214 return axes.axes[axis];
215}
216
217int DriverStation::GetStickPOV(int stick, int pov) {
218 if (stick < 0 || stick >= kJoystickPorts) {
219 wpi_setWPIError(BadJoystickIndex);
220 return -1;
221 }
222 if (pov < 0 || pov >= HAL_kMaxJoystickPOVs) {
223 wpi_setWPIError(BadJoystickAxis);
224 return -1;
225 }
226
227 HAL_JoystickPOVs povs;
228 HAL_GetJoystickPOVs(stick, &povs);
229
230 if (pov >= povs.count) {
231 ReportJoystickUnpluggedWarning(
232 "Joystick POV missing, check if all controllers are plugged in");
233 return -1;
234 }
235
236 return povs.povs[pov];
237}
238
239int DriverStation::GetStickButtons(int stick) const {
240 if (stick < 0 || stick >= kJoystickPorts) {
241 wpi_setWPIError(BadJoystickIndex);
242 return 0;
243 }
244
245 HAL_JoystickButtons buttons;
246 HAL_GetJoystickButtons(stick, &buttons);
247
248 return buttons.buttons;
249}
250
251int DriverStation::GetStickAxisCount(int stick) const {
252 if (stick < 0 || stick >= kJoystickPorts) {
253 wpi_setWPIError(BadJoystickIndex);
254 return 0;
255 }
256
257 HAL_JoystickAxes axes;
258 HAL_GetJoystickAxes(stick, &axes);
259
260 return axes.count;
261}
262
263int DriverStation::GetStickPOVCount(int stick) const {
264 if (stick < 0 || stick >= kJoystickPorts) {
265 wpi_setWPIError(BadJoystickIndex);
266 return 0;
267 }
268
269 HAL_JoystickPOVs povs;
270 HAL_GetJoystickPOVs(stick, &povs);
271
272 return povs.count;
273}
274
275int DriverStation::GetStickButtonCount(int stick) const {
276 if (stick < 0 || stick >= kJoystickPorts) {
277 wpi_setWPIError(BadJoystickIndex);
278 return 0;
279 }
280
281 HAL_JoystickButtons buttons;
282 HAL_GetJoystickButtons(stick, &buttons);
283
284 return buttons.count;
285}
286
287bool DriverStation::GetJoystickIsXbox(int stick) const {
288 if (stick < 0 || stick >= kJoystickPorts) {
289 wpi_setWPIError(BadJoystickIndex);
290 return false;
291 }
292
293 HAL_JoystickDescriptor descriptor;
294 HAL_GetJoystickDescriptor(stick, &descriptor);
295
296 return static_cast<bool>(descriptor.isXbox);
297}
298
299int DriverStation::GetJoystickType(int stick) const {
300 if (stick < 0 || stick >= kJoystickPorts) {
301 wpi_setWPIError(BadJoystickIndex);
302 return -1;
303 }
304
305 HAL_JoystickDescriptor descriptor;
306 HAL_GetJoystickDescriptor(stick, &descriptor);
307
308 return static_cast<int>(descriptor.type);
309}
310
311std::string DriverStation::GetJoystickName(int stick) const {
312 if (stick < 0 || stick >= kJoystickPorts) {
313 wpi_setWPIError(BadJoystickIndex);
314 }
315
316 HAL_JoystickDescriptor descriptor;
317 HAL_GetJoystickDescriptor(stick, &descriptor);
318
319 return descriptor.name;
320}
321
322int DriverStation::GetJoystickAxisType(int stick, int axis) const {
323 if (stick < 0 || stick >= kJoystickPorts) {
324 wpi_setWPIError(BadJoystickIndex);
325 return -1;
326 }
327
328 HAL_JoystickDescriptor descriptor;
329 HAL_GetJoystickDescriptor(stick, &descriptor);
330
331 return static_cast<bool>(descriptor.axisTypes);
332}
333
Austin Schuh1e69f942020-11-14 15:06:14 -0800334bool DriverStation::IsJoystickConnected(int stick) const {
335 return GetStickAxisCount(stick) > 0 || GetStickButtonCount(stick) > 0 ||
336 GetStickPOVCount(stick) > 0;
337}
338
Brian Silverman8fce7482020-01-05 13:18:21 -0800339bool DriverStation::IsEnabled() const {
340 HAL_ControlWord controlWord;
341 HAL_GetControlWord(&controlWord);
342 return controlWord.enabled && controlWord.dsAttached;
343}
344
345bool DriverStation::IsDisabled() const {
346 HAL_ControlWord controlWord;
347 HAL_GetControlWord(&controlWord);
348 return !(controlWord.enabled && controlWord.dsAttached);
349}
350
351bool DriverStation::IsEStopped() const {
352 HAL_ControlWord controlWord;
353 HAL_GetControlWord(&controlWord);
354 return controlWord.eStop;
355}
356
357bool DriverStation::IsAutonomous() const {
358 HAL_ControlWord controlWord;
359 HAL_GetControlWord(&controlWord);
360 return controlWord.autonomous;
361}
362
Austin Schuh1e69f942020-11-14 15:06:14 -0800363bool DriverStation::IsAutonomousEnabled() const {
364 HAL_ControlWord controlWord;
365 HAL_GetControlWord(&controlWord);
366 return controlWord.autonomous && controlWord.enabled;
367}
368
Brian Silverman8fce7482020-01-05 13:18:21 -0800369bool DriverStation::IsOperatorControl() const {
370 HAL_ControlWord controlWord;
371 HAL_GetControlWord(&controlWord);
372 return !(controlWord.autonomous || controlWord.test);
373}
374
Austin Schuh1e69f942020-11-14 15:06:14 -0800375bool DriverStation::IsOperatorControlEnabled() const {
376 HAL_ControlWord controlWord;
377 HAL_GetControlWord(&controlWord);
378 return !controlWord.autonomous && !controlWord.test && controlWord.enabled;
379}
380
Brian Silverman8fce7482020-01-05 13:18:21 -0800381bool DriverStation::IsTest() const {
382 HAL_ControlWord controlWord;
383 HAL_GetControlWord(&controlWord);
384 return controlWord.test;
385}
386
387bool DriverStation::IsDSAttached() const {
388 HAL_ControlWord controlWord;
389 HAL_GetControlWord(&controlWord);
390 return controlWord.dsAttached;
391}
392
Austin Schuh1e69f942020-11-14 15:06:14 -0800393bool DriverStation::IsNewControlData() const {
394 std::unique_lock lock(m_waitForDataMutex);
395 int& lastCount = GetDSLastCount();
396 int currentCount = m_waitForDataCounter;
397 if (lastCount == currentCount) return false;
398 lastCount = currentCount;
399 return true;
400}
Brian Silverman8fce7482020-01-05 13:18:21 -0800401
402bool DriverStation::IsFMSAttached() const {
403 HAL_ControlWord controlWord;
404 HAL_GetControlWord(&controlWord);
405 return controlWord.fmsAttached;
406}
407
408std::string DriverStation::GetGameSpecificMessage() const {
409 HAL_MatchInfo info;
410 HAL_GetMatchInfo(&info);
411 return std::string(reinterpret_cast<char*>(info.gameSpecificMessage),
412 info.gameSpecificMessageSize);
413}
414
415std::string DriverStation::GetEventName() const {
416 HAL_MatchInfo info;
417 HAL_GetMatchInfo(&info);
418 return info.eventName;
419}
420
421DriverStation::MatchType DriverStation::GetMatchType() const {
422 HAL_MatchInfo info;
423 HAL_GetMatchInfo(&info);
424 return static_cast<DriverStation::MatchType>(info.matchType);
425}
426
427int DriverStation::GetMatchNumber() const {
428 HAL_MatchInfo info;
429 HAL_GetMatchInfo(&info);
430 return info.matchNumber;
431}
432
433int DriverStation::GetReplayNumber() const {
434 HAL_MatchInfo info;
435 HAL_GetMatchInfo(&info);
436 return info.replayNumber;
437}
438
439DriverStation::Alliance DriverStation::GetAlliance() const {
440 int32_t status = 0;
441 auto allianceStationID = HAL_GetAllianceStation(&status);
442 switch (allianceStationID) {
443 case HAL_AllianceStationID_kRed1:
444 case HAL_AllianceStationID_kRed2:
445 case HAL_AllianceStationID_kRed3:
446 return kRed;
447 case HAL_AllianceStationID_kBlue1:
448 case HAL_AllianceStationID_kBlue2:
449 case HAL_AllianceStationID_kBlue3:
450 return kBlue;
451 default:
452 return kInvalid;
453 }
454}
455
456int DriverStation::GetLocation() const {
457 int32_t status = 0;
458 auto allianceStationID = HAL_GetAllianceStation(&status);
459 switch (allianceStationID) {
460 case HAL_AllianceStationID_kRed1:
461 case HAL_AllianceStationID_kBlue1:
462 return 1;
463 case HAL_AllianceStationID_kRed2:
464 case HAL_AllianceStationID_kBlue2:
465 return 2;
466 case HAL_AllianceStationID_kRed3:
467 case HAL_AllianceStationID_kBlue3:
468 return 3;
469 default:
470 return 0;
471 }
472}
473
474void DriverStation::WaitForData() { WaitForData(0); }
475
476bool DriverStation::WaitForData(double timeout) {
477 auto timeoutTime =
478 std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
479
480 std::unique_lock lock(m_waitForDataMutex);
Austin Schuh1e69f942020-11-14 15:06:14 -0800481 int& lastCount = GetDSLastCount();
Brian Silverman8fce7482020-01-05 13:18:21 -0800482 int currentCount = m_waitForDataCounter;
Austin Schuh1e69f942020-11-14 15:06:14 -0800483 if (lastCount != currentCount) {
484 lastCount = currentCount;
485 return true;
486 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800487 while (m_waitForDataCounter == currentCount) {
488 if (timeout > 0) {
489 auto timedOut = m_waitForDataCond.wait_until(lock, timeoutTime);
490 if (timedOut == std::cv_status::timeout) {
491 return false;
492 }
493 } else {
494 m_waitForDataCond.wait(lock);
495 }
496 }
Austin Schuh1e69f942020-11-14 15:06:14 -0800497 lastCount = m_waitForDataCounter;
Brian Silverman8fce7482020-01-05 13:18:21 -0800498 return true;
499}
500
501double DriverStation::GetMatchTime() const {
502 int32_t status;
503 return HAL_GetMatchTime(&status);
504}
505
506double DriverStation::GetBatteryVoltage() const {
507 int32_t status = 0;
508 double voltage = HAL_GetVinVoltage(&status);
509 wpi_setErrorWithContext(status, "getVinVoltage");
510
511 return voltage;
512}
513
514void DriverStation::WakeupWaitForData() {
515 std::scoped_lock waitLock(m_waitForDataMutex);
516 // Nofify all threads
517 m_waitForDataCounter++;
518 m_waitForDataCond.notify_all();
519}
520
521void DriverStation::GetData() {
522 {
523 // Compute the pressed and released buttons
524 HAL_JoystickButtons currentButtons;
525 std::unique_lock lock(m_buttonEdgeMutex);
526
527 for (int32_t i = 0; i < kJoystickPorts; i++) {
528 HAL_GetJoystickButtons(i, &currentButtons);
529
530 // If buttons weren't pressed and are now, set flags in m_buttonsPressed
531 m_joystickButtonsPressed[i] |=
532 ~m_previousButtonStates[i].buttons & currentButtons.buttons;
533
534 // If buttons were pressed and aren't now, set flags in m_buttonsReleased
535 m_joystickButtonsReleased[i] |=
536 m_previousButtonStates[i].buttons & ~currentButtons.buttons;
537
538 m_previousButtonStates[i] = currentButtons;
539 }
540 }
541
542 WakeupWaitForData();
543 SendMatchData();
544}
545
Austin Schuh1e69f942020-11-14 15:06:14 -0800546void DriverStation::SilenceJoystickConnectionWarning(bool silence) {
547 m_silenceJoystickWarning = silence;
548}
549
550bool DriverStation::IsJoystickConnectionWarningSilenced() const {
551 return !IsFMSAttached() && m_silenceJoystickWarning;
552}
553
Brian Silverman8fce7482020-01-05 13:18:21 -0800554DriverStation::DriverStation() {
555 HAL_Initialize(500, 0);
556 m_waitForDataCounter = 0;
557
558 m_matchDataSender = std::make_unique<MatchDataSender>();
559
560 // All joysticks should default to having zero axes, povs and buttons, so
561 // uninitialized memory doesn't get sent to speed controllers.
562 for (unsigned int i = 0; i < kJoystickPorts; i++) {
563 m_joystickButtonsPressed[i] = 0;
564 m_joystickButtonsReleased[i] = 0;
565 m_previousButtonStates[i].count = 0;
566 m_previousButtonStates[i].buttons = 0;
567 }
568
569 m_dsThread = std::thread(&DriverStation::Run, this);
570}
571
572void DriverStation::ReportJoystickUnpluggedError(const wpi::Twine& message) {
573 double currentTime = Timer::GetFPGATimestamp();
574 if (currentTime > m_nextMessageTime) {
575 ReportError(message);
576 m_nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
577 }
578}
579
580void DriverStation::ReportJoystickUnpluggedWarning(const wpi::Twine& message) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800581 if (IsFMSAttached() || !m_silenceJoystickWarning) {
582 double currentTime = Timer::GetFPGATimestamp();
583 if (currentTime > m_nextMessageTime) {
584 ReportWarning(message);
585 m_nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
586 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800587 }
588}
589
590void DriverStation::Run() {
591 m_isRunning = true;
592 int safetyCounter = 0;
593 while (m_isRunning) {
594 HAL_WaitForDSData();
595 GetData();
596
597 if (IsDisabled()) safetyCounter = 0;
598
599 if (++safetyCounter >= 4) {
600 MotorSafety::CheckMotors();
601 safetyCounter = 0;
602 }
603 if (m_userInDisabled) HAL_ObserveUserProgramDisabled();
604 if (m_userInAutonomous) HAL_ObserveUserProgramAutonomous();
605 if (m_userInTeleop) HAL_ObserveUserProgramTeleop();
606 if (m_userInTest) HAL_ObserveUserProgramTest();
607 }
608}
609
610void DriverStation::SendMatchData() {
611 int32_t status = 0;
612 HAL_AllianceStationID alliance = HAL_GetAllianceStation(&status);
613 bool isRedAlliance = false;
614 int stationNumber = 1;
615 switch (alliance) {
616 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue1:
617 isRedAlliance = false;
618 stationNumber = 1;
619 break;
620 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue2:
621 isRedAlliance = false;
622 stationNumber = 2;
623 break;
624 case HAL_AllianceStationID::HAL_AllianceStationID_kBlue3:
625 isRedAlliance = false;
626 stationNumber = 3;
627 break;
628 case HAL_AllianceStationID::HAL_AllianceStationID_kRed1:
629 isRedAlliance = true;
630 stationNumber = 1;
631 break;
632 case HAL_AllianceStationID::HAL_AllianceStationID_kRed2:
633 isRedAlliance = true;
634 stationNumber = 2;
635 break;
636 default:
637 isRedAlliance = true;
638 stationNumber = 3;
639 break;
640 }
641
642 HAL_MatchInfo tmpDataStore;
643 HAL_GetMatchInfo(&tmpDataStore);
644
645 m_matchDataSender->alliance.SetBoolean(isRedAlliance);
646 m_matchDataSender->station.SetDouble(stationNumber);
647 m_matchDataSender->eventName.SetString(tmpDataStore.eventName);
648 m_matchDataSender->gameSpecificMessage.SetString(
649 std::string(reinterpret_cast<char*>(tmpDataStore.gameSpecificMessage),
650 tmpDataStore.gameSpecificMessageSize));
651 m_matchDataSender->matchNumber.SetDouble(tmpDataStore.matchNumber);
652 m_matchDataSender->replayNumber.SetDouble(tmpDataStore.replayNumber);
653 m_matchDataSender->matchType.SetDouble(
654 static_cast<int>(tmpDataStore.matchType));
655
656 HAL_ControlWord ctlWord;
657 HAL_GetControlWord(&ctlWord);
658 int32_t wordInt = 0;
659 std::memcpy(&wordInt, &ctlWord, sizeof(wordInt));
660 m_matchDataSender->controlWord.SetDouble(wordInt);
661}