-
Notifications
You must be signed in to change notification settings - Fork 3
Networking
You'll obviously want to send data back & forth between the base station and your on-rover system. Scarlet has flexible and easy systems to do this.
Packet Structure:
You'll need to understand how packets are structured in order to be able to create, send, receive, interpret, and inspect them. We've made a very simple structure that is flexible enough to do everything we need. Here's how it works:
Timestamp | ID | Data |
---|---|---|
0x59 47 27 6F |
0x03 |
0x00 45 00 72 00 7A 00 61 |
- Timestamp
- All packets begin with a 4-byte Timestamp that corresponds to the current Unix timestamp. (Yes, this technically means our library will stop working in 2038, but I don't think this is a priority concern now.)
- This timestamp is usually handled for you by Scarlet, unless you specifically override it for whatever reason.
- ID
- The ID tells the recipient what the packet's content will be, and what subsystem is responsible for handling it. For example, the science station uses 0x80 for an emergency stop, and 0x01 for an error.
- This is handled by you. You'll need to come up with a list of packet IDs and their meanings. We recommend you follow our style of splitting the 240 available IDs into sections depending on which direction they can be sent in. Our packet IDs are defined in PacketType, with documentation on our Packets page.
- For 2017-18, here's the list of packet IDs and who is using what.
- NOTE: Scarlet uses packet IDs F0 through FF for internal use. You cannot use these.
- Data
- This section is optional. If you can convey your message using only the packet ID (we ignore the data field for emergency stops, as an example), then feel free to leave this null. Otherwise, you'll want to come up with a rigid definition of where data will be placed here to make sending and receiving easy and reliable.
- For cross-compatibility, it is recommended that you use Scarlet's UtilData class for converting to and from other datatypes, such as string, double, etc. That way, systems use the same packet formatting, making troubleshooting easier.
- You should define your packet types and data structure before you start implementing packet sending/receiving. You can look at our structures as an example to help you get started, especially the Sensor Readings packet.
Client and Server:
Scarlet implements a client-server model. The base station will be a server, while all other systems (on rover and elsewhere) are to be clients. Clients are able to connect to a single server, and servers are able to handle any number of clients. Clients need to have a unique identifier, like "RoverScience". The server simply uses "Server".
Preparing a Client:
In order to be ready to send and receive packets as a client, you'll need to set up a few things. First, you'll need to call this before you attempt any communication:
Client.Start(string ServerIP, int PortTCP, int PortUDP, string ClientName, [int ReceiveBufferSize = 64], [int OperationPeriod = 20]);
Parameter | Description |
---|---|
ServerIP | The IP that the Client will attempt to connect to. This will usually be the base station. |
PortTCP | The port that the Server is listening for TCP connections on. Should be > 1024. |
PortUDP | The port that the Server is listening for UDP traffic on. Should be > 1024, and different from PortTCP. |
ClientName | A unique identifier for your Client. Make sure it is not the same as any other Scarlet client connecting to the server. |
ReceiveBufferSize | Optional This can be changed if you have packets larger than 64 bytes that you'll need to be able to receive. |
OperationPeriod | Optional The period (in ms) between operations, such as packet sending, receiving, and processing. Lower this if packets are not being processed fast enough and you have CPU to spare. |
Preparing a Server:
In order to be ready to accept clients and send/receive data, you'll need to set up the Server. Start by calling this method:
Server.Start(int PortTCP, int PortUDP, [int ReceiveBufferSize = 64], [int OperationPeriod = 20]);
Parameter | Description |
---|---|
PortTCP | The port that the Server will listen for TCP connections on. Should be > 1024. |
PortUDP | The port that the Server will listen for UDP traffic on. Should be > 1024, and different from PortTCP. |
ReceiveBufferSize | Optional This can be changed if you have packets larger than 64 bytes that you'll need to be able to receive. |
OperationPeriod | Optional The period (in ms) between operations, such as packet sending, receiving, and processing. Lower this if packets are not being processed fast enough and you have CPU to spare. |
Registering handlers:
In order for Server or Client to know how to process incoming packets, you'll need to register your handlers. Every packet ID that you can receive needs to have a delegate (method) defined for it. The same delegate can be used for multiple IDs if you so choose. To register a handler, call the this method:
Parse.SetParseHandler(int MessageID, delegate ParseMethod(Message));
Now, whenever a packet is received with the packed ID you registered, your ParseMethod will be called with the packet's Message object.
Sending a packet:
Receiving is great, but you'll also want to send packets.
Start by constructing a Packet object to send. Here's an example:
Packet MyPack = new Packet(0x80);
MyPack.AppendData(UtilData.ToBytes("Homura"));
MyPack.IsUDP = false;
Client.Send(MyPack);
// or Server.Send(MyPack);
That's it. (Notice usage of UtilData instead of other conversion methods) Your packet will get placed into a Queue and sent when a connection is available, in the order it was given to Client or Server. If IsUDP is true, it will get sent immediately.
Priority Packets:
Sometimes, you need to skip the Queue, and have your packet sent immediately. One example of this is the emergency stop packet. Instead of calling Client.Send(Packet)
, simply call Client.SendNow(Packet)
. You'll need to handle exceptions such as TimeoutException
yourself when doing this (the regular Send()
method will handle exceptions and retry sending.)
Connection management:
Scarlet will handle connection management for you, and is usually able to deal with connection delays, connection drops, software lockups, and software restarts gracefully. This is done using watchdog packets that get sent in both directions via UDP. If one side doesn’t receive any of these for a couple of cycles, it assumes there is a connection issue, drops the connection, and attempts to reconnect when possible. TCP packets in the queue are held during this time, and UDP packets are dropped.
Server Events:
The server sends off a ClientConnectionChange
event whenever a TCP connection is started (after the client has sent a name and is validated), and after the TCP connection gets closed.
Quick Links:
NuGet
Pin Diagrams: RPi | BBB
Developers: CaiB, Baldstrom
General Info:
Home
Common Issues
Getting Started
Supported Devices
Sections:
Logging
DataLog
Filters
Hardware I/O:
- BeagleBone Black
- Raspberry Pi
- Pin Diagrams: RPi | BBB
- GPIO: Using | For Beginners
- PWM: Using | For Beginners
- ADC: Using | For Beginners
- I2C: Using | For Beginners
- SPI: Using | For Beginners
- UART: Using | For Beginners
- CAN: Using | For Beginners
Networking
Sensors
StateStore
Other: Interesting Case Studies