-
Notifications
You must be signed in to change notification settings - Fork 0
/
ComponentBase.cpp
147 lines (119 loc) · 3.43 KB
/
ComponentBase.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/** \file
* Component base class implementation.
*
* In the RhsRobot Framework, each physical subsystem has a corresponding component class.
* These component classes should inherit the ComponentBase class for access to functions that
* all components use.
*/
#include "ComponentBase.h"
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/types.h>
//Local
//Robot
class RhsRobot;
#include "RobotMessage.h"
ComponentBase::ComponentBase(const char* componentName, const char *queueName, int priority)
{
iLoop = 0;
iPipeRcv = -1;
iPipeXmt = -1;
pTask = NULL;
pRemoteUpdateTimer = new Timer();
pRemoteUpdateTimer->Start();
pAutoTimer = new Timer();
pAutoTimer->Start();
pDebugTimer = new Timer();
pDebugTimer->Start();
pSafetyTimer = new Timer();
pSafetyTimer->Start();
mkfifo(queueName, 0666);
queueLocal = queueName;
}
void ComponentBase::SendMessage(RobotMessage* robotMessage)
{
RobotMessage message = *robotMessage;
if(iPipeXmt < 0)
{
iPipeXmt = open(queueLocal.c_str(), O_WRONLY);
//fcntl(iPipeXmt, F_SETFL, fcntl(iPipeXmt, F_GETFL) | O_NONBLOCK);
assert(iPipeXmt > 0);
}
write(iPipeXmt, (char*)&message, sizeof(RobotMessage));
}
void ComponentBase::ReceiveMessage() //Receives a message and copies it into localMessage
{
fd_set selectSet;
struct timeval timeout;
if(iPipeRcv < 0)
{
iPipeRcv = open(queueLocal.c_str(), O_RDONLY);
assert(iPipeRcv > 0);
}
FD_ZERO(&selectSet);
FD_SET(iPipeRcv, &selectSet);
timeout.tv_sec = 0;
timeout.tv_usec = 40000;
if(select(iPipeRcv + 1, &selectSet, NULL, NULL, &timeout) == 0)
{
localMessage.command = COMMAND_SYSTEM_MSGTIMEOUT;
}
else
{
read(iPipeRcv, (char*)&localMessage, sizeof(RobotMessage));
}
}
void ComponentBase::ClearMessages(void)
{
RobotMessage eatMessage;
// eat all the messages in the queue
fcntl(iPipeRcv, F_SETFL, O_NONBLOCK);
while(read(iPipeRcv, (char*)&eatMessage, sizeof(RobotMessage)) > 0)
{
// intentionally empty
}
fcntl(iPipeRcv, F_SETFL, 0);
// make sure the localMessage is innocuous
localMessage.command = COMMAND_SYSTEM_MSGTIMEOUT;
}
void ComponentBase::DoWork()
{
while(true)
{
ReceiveMessage(); //Receives a message and copies it into localMessage
if(localMessage.command == COMMAND_ROBOT_STATE_DISABLED || //Tests for state change messages
localMessage.command == COMMAND_ROBOT_STATE_AUTONOMOUS ||
localMessage.command == COMMAND_ROBOT_STATE_TELEOPERATED ||
localMessage.command == COMMAND_ROBOT_STATE_TEST ||
localMessage.command == COMMAND_ROBOT_STATE_UNKNOWN)
{
OnStateChange(); //Handles state changes
}
Run(); //Component logic
//
//if(ISAUTO) { AutoBehavior(); } //TODO should we add AutoBehavior?
//AutoBehavior is where the actual auto stuff is called - it should be periodic rather than stop up the thread
//It should be structured as a state machine; Run will change the state.
if (pRemoteUpdateTimer->Get() > fUpdateDelay)
{
pRemoteUpdateTimer->Reset();
SmartDashboardUpdate();
}
lastCommand = localMessage.command;
iLoop++;
}
}
void ComponentBase::SendCommandResponse(MessageCommand command)
{
RobotMessage replyMessage;
replyMessage.command = command;
//Send a message back to auto to tell it that code is done.
int iPipeXmt = open(localMessage.replyQ, O_WRONLY);
assert(iPipeXmt > 0);
write(iPipeXmt, (char*) &replyMessage, sizeof(RobotMessage));
close(iPipeXmt);
}