ArPiRobot-CoreLib C++
C++ library for ArPiRobot robots
NetworkManager.hpp
1 /*
2  * Copyright 2021 Marcus Behel
3  *
4  * This file is part of ArPiRobot-CoreLib.
5  *
6  * ArPiRobot-CoreLib is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * ArPiRobot-CoreLib is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with ArPiRobot-CoreLib. If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #pragma once
21 
22 #include <asio.hpp>
23 #include <functional>
24 #include <array>
25 #include <thread>
26 #include <mutex>
27 #include <unordered_map>
28 #include <memory>
29 
30 #include <arpirobot/core/network/MainVmon.hpp>
31 #include <arpirobot/core/network/ControllerData.hpp>
32 #include <arpirobot/core/network/NetworkTable.hpp>
33 
34 using namespace asio::ip;
35 using namespace asio;
36 
37 namespace arpirobot{
38 
39  /*
40  *
41  * Networking protocol
42  * The drive station uses four ports to communicate with the robot.
43  * Controller Port (UDP 8090):
44  * Data is only received from the DS. Data is not sent from the robot to the DS on this port.
45  * The controller port is a UDP port on port 8090. It is used to send controller data in the following packet format
46  * [controllerNumber,axisCount,buttonCount,dpadCount,axis1_h,axis1_l,...,buttons1,buttons2,...,dpads1,dpads2,...,\n]
47  *
48  * - The controller number and counts are 8 bit integers (unsigned)
49  * - axes are sent as signed 16-bit integers (high byte, low byte)
50  * - buttons are 1 (pressed) or 0 (not pressed) Each button byte encodes the state of eight buttons.
51  * The most significant bit is the smallest numbered button. For example in the first
52  * button byte sent (buttons1) the most significant bit is button #0's state. The MSB of the
53  * second byte (buttons2) is the 9th button's state.
54  * - the dpad is 0 (no direction) or 1-8 (where 1 is up rotate clockwise)
55  * 8 1 2
56  * 7 0 3
57  * 6 5 4
58  * Two dpads are sent per byte. As with the buttons the most significant 4 bits represent
59  * the lowest numbered dpad.
60  * Command port (TCP 8091):
61  * Data is only received from the DS. Data is not sent from the robot to the DS on this port. Commands end with a newline.
62  * Commands are sent to the robot on this port as ASCII strings
63  * Some commands include:
64  * "ENABLE" = Enable the robot
65  * "DISABLE" = Disable the robot
66  * "NT_SYNC" = Start network table sync (always triggered by drive station)
67  * Net Table port (TCP 8092):
68  * Data is sent and received on the net table port.
69  * New keys are sent to the drive station in the format shown below
70  * "[KEY]",255,"[VALUE]"
71  * Key and value are ASCII text. 255 is an unsigned int (this is used because it is not a valid ASCII character)
72  * Data received from the DS is in the same format and will cause the robot's net table to
73  * set the given key to the given value.
74  * During a sync (sync must be started from the drive station by sending a command to the robot)
75  * the robot sends the net table sync start sequence then sends all key/value pairs followed by the
76  * net table sync stop sequence. The robot then waits for the drive station to send any key/value pairs
77  * that the robot is missing. The drive station then sends the net table sync stop sequence and the robot
78  * then "ends" the sync.
79  * Log port (TCP 8093):
80  * Log messages are sent as strings from the robot to the drive station on this port. No data is sent to the robot
81  * from the drive station on this port.
82  *
83  */
84 
85 
86  // Commands from drive station
87  const extern std::string COMMAND_ENABLE;
88  const extern std::string COMMAND_DISABLE;
89  const extern std::string COMMAND_NET_TABLE_SYNC;
90 
91  // Pre-defined (special) data packets
92  const extern uint8_t NET_TABLE_START_SYNC_DATA[];
93  const extern std::string NET_TABLE_END_SYNC_DATA;
94 
102  public:
103 
109  static void startNetworking(std::function<void()> enableFunc, std::function<void()> disableFunc);
110 
114  static void stopNetworking();
115 
116  private:
117 
122  static bool sendNtRaw(const_buffer buffer);
123 
129  static bool sendNt(std::string key, std::string value);
130 
135  static void sendLogMessage(std::string message);
136 
141  static void setMainVmon(MainVmon *vmon);
142 
148  static bool isMainVmon(MainVmon *vmon);
149 
154  static void sendMainBatteryVoltage(double voltage);
155 
159  static void runNetworking();
160 
165  static void receiveFrom(const tcp::socket &client);
166 
170  static void handleConnectionStatusChanged();
171 
172  // Boost async handler functions
173 
174  static void handleAccept(const tcp::socket &client, const std::error_code &ec);
175  static void handleDisconnect(const tcp::socket &client);
176  static void handleTcpReceive(const tcp::socket &client, const std::error_code &ec, std::size_t count);
177  static void handleUdpReceive(const std::error_code &ec, std::size_t count);
178 
179  static void handleCommand();
180 
181  static void handleNetTableData();
182 
183  static void handleControllerData(std::vector<uint8_t> &data);
184 
185  static std::unordered_map<int, std::shared_ptr<ControllerData>> controllerData;
186 
187  // Thread for network io service
188  static std::thread *networkThread;
189 
190  // Status
191  static bool isDsConnected;
192  static bool networkingStarted;
193 
194  // TODO: Main vmon
195 
196  // Read buffers (only receive data from command, controller, net table ports)
197  static std::array<uint8_t, 32> tmpCommandRxBuf;
198  static std::array<uint8_t, 32> tmpNetTableRxBuf;
199  static std::array<uint8_t, 32> tmpControllerRxBuf;
200 
201  // These hold data received from multiple packets (above buffers are one packet use)
202  static std::vector<uint8_t> commandRxData;
203  static std::vector<uint8_t> netTableRxData;
204 
205  // Boost ASIO stuff
206  static io_service io;
207  static io_service::work wk; // Keep run from exiting
208 
209  static udp::socket controllerSocket;
210  static tcp::acceptor commandSocketAcceptor;
211  static tcp::acceptor netTableSocketAcceptor;
212  static tcp::acceptor logSocketAcceptor;
213 
214  // Connected clients (drive station)
215  static udp::endpoint controllerDataEndpoint;
216  static tcp::socket commandClient;
217  static tcp::socket netTableClient;
218  static tcp::socket logClient;
219 
220  // Callback for enable and disable events (this are private functions in BaseRobot)
221  // Doing this way makes it hard for other code to call enable / disable for the robot
222  static std::function<void()> enableFunc;
223  static std::function<void()> disableFunc;
224 
225  static std::unordered_map<std::string, std::string> ntSyncData;
226 
227  static MainVmon *mainVmon;
228 
229 
230  friend class MainVmon;
231  friend class Logger;
232  friend class NetworkTable;
233  friend class Gamepad;
234  };
235 }
Definition: Gamepad.hpp:34
Definition: Logger.hpp:33
Definition: MainVmon.hpp:30
Definition: NetworkManager.hpp:101
static void stopNetworking()
static void startNetworking(std::function< void()> enableFunc, std::function< void()> disableFunc)
Definition: NetworkTable.hpp:32
Definition: ArduinoDevice.hpp:27