-
Notifications
You must be signed in to change notification settings - Fork 0
Communication Management System
The Communication Management System offers a complex network control to allow seperation of data that passes through a single port. In essence, it allows managing of data transfer between 2 sides with ease. In addition, it allows users to send and receive data in any way possible, be it TCP sockets, UDP, UART and more.
Examples for the communications system can be found here: Examples->communications.
The Communication Management System manages communication between two different sides. Each side has an equal number of Sendable
objects, any of which sends and receives data individually:
When a Sendable
is added to a communications manager, it is assigned an ID. When connection is established with a remote side, data about each Sendable
is sent. If a Sendable with the same ID exists the 2 object begin communication, if not an attempt is done to create a Sendable
for communication according to the data of the remote Sendable
.
Creation of Sendable
objects by the manager is done using a SendableCreator
object. SendableCreator
s receive data about a Sendable
, specifically a byte indicating a type and a name, and create an object to communicate with that Sendable
. Creation of objects by type has to be implemented by users.
In order to allow flexibility with the system, the actual sending and receiving of data is seperated from the management system and is done using a CommInterface
. CommInterface
s serve as communication sockets. They are responsible for sending data to the other side, and receiving data from it, its implementation does not affect the operation of the manager. A CommInterface can use TCP or UDP sockets, UART ports or any other possible way to transfer data.
The Sendable
class provides abstract logic for a node in the communications system. Each Sendable
object conducts communications with a remote counterpart, and data between them is organized by the manager and transfered accordingly, so there is no need to worry about unwanted data.
A Sendable
object has an ID which is assigned to it by the communications manager. This ID is used to identify the object and its counterpart, making sure data is transfered currectly. So for two Sendable
objects to communicate, they must have the same ID.
In addition to an ID, each Sendable
object has a "type": a byte which can be used by users to dynamically create Sendable
objects. When connection is established by the manager, there is an attempt to locate the remote counterpart Sendable
with a matching ID. If non exist, it is possible to create one on the spot using a SendableCreator
object. The type byte can be used by users to identify which Sendable
object to create as the counterpart. This means, each Sendable
class should have a unique type.
A "name" is also available for each Sendable
, it is does not play an important rule, but rather it allows users to display data about their object easily, since the name is sent to the remote counterpart.
There are several methods that require implementation when extending the Sendable
class:
-
newData
: this method is for data receiving from the remote counterpart. It receives a byte array with the data. -
dataForTransmition
: this method is for data sending to the remote counterpart. It returns an array of bytes or null. -
hasChanged
: this method indicates whether or not the object has data to send and so it returns a boolean. Iftrue
is returned,dataForTransmition
will be called. -
onConnection
: called by the manager when connection with a remote counterpartSendable
was confirmed. If the communications manager has connected to a remote, but no counterpartSendable
is available,onConnection
will not be called. -
onDisconnection
: called by the manager when connection with a remote counterpartSendable
was lost. This does not necessarilly means the communications was all lost, but rather it called also mean the remoteSendable
object was removed by the user. If no counterpartSendable
was detected in the first placed, this will not be called.
Since ID allocation can sometimes be problematic. It sometimes a good idea to wait for a remote Sendable
detection and only then create a counterpart for it. For this reason, we provided the SendableCreator
interface.
When a connection between 2 managers is established, data about Sendable
objects from each side is transfered. If a remote Sendable
does not have a local one with the same ID, it is possible to create one locally. If a SendableCreator
object exists in the manager, the method create
from it will be called and both the name and the type of the remote Sendable
will be passed. Then by checking the value of the type, users can decide which object to create and return
it. If the method returns null, nothing will happen, if it returns an object an ID matching the remote will be allocated to it and connection between it and the remote Sendable
will be confirmed.
However, Sendable
objects created on the run, will no be saved after the communications manager was disconnected, or lost connection with the remote communications manager.
To allow flexibility for users, the actual transfer of data between communication manager is abstracted in the form of CommInterface
. This interface is responsible for sending data from one side to the other and is free to do so at will. Users can implement a simple UDP, create UDP with data recovery, even write and read from files if they wanted to.
The interface itself has a lot of methods to be implemented and has to offer a few capabilities, such as read timeouts.
When used by the communications manager, the following steps are taken:
-
setReadTimeout
is called, setting a timeout for data reading -
open
method is called to open the communications port - While
isConnected
returnsfalse
, the methodconnect
is called to try connection to the remote side - When
isConnected
returnstrue
connections is confirmed and data transfer starts - A loop starts and runs while
isConnected
returnstrue
-
write
andread
are called periodically to send and read data - The method
update
is also called periodically, allowingCommInterface
s to perform extra actions such as connection verification - When
isConnected
returnsfalse
, the manager loop stops,disconnect
is called and again connection is attempted - When the manager is closed, the method
close
is called
For reading data the Packet
class is used. It is a simple class, holding a byte array and an int variable. This class should hold the reading result in the byte array and the amount of bytes read in the int variable. If no bytes were read, the length should be 0. It is necessary to manually provide the array, since the array in the class will be uninitialized.
To help users in implementing CommInterface
s, FlashLib provies few extensions to CommInterface
with different implementations:
An abstract class which provides verification of connection by manually sending and reading handshakes.
It uses the update
method to periodically check the time that has passed since data was sent or received. If a defined amount of time has passed since sending data, it will send an handshake to the remote (call write
and pass the handshake byte array). If a defined amount of time has passed since receiving data, it will register a timeout. If a defined amount of timeouts has occured, disconnect
is called. Timeouts reset themselves over time.
This class only implements update
from CommInterface
.
If your protocol does not have connection handshake, such as the one provided by TCP, you may use the handshake provided by this class. The server should call the static handshakeServer
and the client should call handshakeClient
. Those method will use a 3 way handshake between two side to confirm connection and will return a boolean result indicating if the connection was successful.
When extending this, remember to follow the following rules:
- Each time connection is established, call 'resetData' to ready this class for use
- When receiving data, call
newDataRead
updating it that new data from the remote was received - When sending data, call
newDataSent
updating it that new data to the remote was sent - When analyzing received data, check if that data is the handshake array by calling
isHandshake
. If it is, just do nothing. - If you want to use the
update
method too, be sure to call itsupdate
method too or it will not function properly:
super.update(millis);
An abstract class for communication protocols using a data stream, such as a serial port. This class provides packets for data making sure data does not mix with each other. It also features a data corruption detection using CRC32, which is completely optional.
This class extends ManualConnectionVerifier
and implements all but open
, close
, isOpened
, connect
, disconnect
, isConnected
, setReadTimeout
and getReadTimeout
from CommInterface
. It also has 2 abstract method which require user implementation:
-
writeData
: receives a byte array, a start index and a length and should write this data to the used communications stream. -
readData
: receives a byte array, reads data from the stream into it and returns the amount of bytes read. If non were read, return 0, if an error has occurred which indicates disconnection from the stream, return -1.
If enabled, the corruption detection is done by attaching a checksum to each data packet sent. When received, the checksum is extracted and compared to a locally created checksum of the same data. If they do not match, the data is considered corruption and is ignored.
An extenstion of StreamCommInterface
, this class provides implementation for connect
, disconnect
and isConnected
. The implementation uses a manual connection handshake to perform connection.
In addition to provided abstract logic for CommInterface
, there are several full implementations:
-
TcpCommInterface
: uses the TCP protocol for communications. ExtendsStreamCommInterface
and can act as both server and client. -
UdpCommInterface
: uses the UDP protocol for communications. Extends 'ManualConnectionVerifier` and can act as both server and client. -
RxTxCommInterface
: uses the RXTXComm library and implements a serial communications interface. ExtendsSerialCommInterface
.
The Communications
class is the communications manager used in FlashLib. It performs the communication in a thread and can hold a collection of Sendable
objects and one SendableCreator
.
This class receives a CommInterface
in its constructor which is used for the communications transfer. If this manager should be a server, meaning it should wait for a client to connect to it, then the CommInterface
must be a server. Keep in mind that the manager was built to communicate with one remote manager and not several.
When connection with a remote manager is established, the preperation of Sendable
s is done. This is when ID are allocated and it is done sequentially - by the order of attachment to the manager. The allocation starts with a minimum ID which can be defined by users (setMinAllocationID(id)
). After a disconnection/connection loss, the ID are reset for its Sendable
so that they can be reallocated in the next connection, meaning that a Sendable
does not keep an ID forever. In addition, if a Sendable
was detached from the manager, this will mean that after another connection the ID previously allocated to it will be allocated to a different object.
If wanted, it is possible to force the allocation of an ID for a Sendable
by using attachForID
. If the manager is not connected and no other Sendable
was forced with this ID, then no problem. But if the manager is connected, then the ID might already be allocated by the manager and this cannot be done.
When planning communication with this system, there are a few possible designs:
- One side will attach
Sendable
s and the other will create them with aSendableCreator
. - Both sides attach
Sendable
objects with a matching order so that ID will be allocated accordingly. - Both sides attach
Sendable
objects but each side has a different minimum ID. Both sides will useSendableCreator
to create counterparts.
The second design is not recommanded since it is prone to possible user errors.