-
Notifications
You must be signed in to change notification settings - Fork 108
Layered Model
To conceptualize the disaster radio firmware, we created a layered model based largely on the OSI model used in teaching classical computer networking.
Layer 1 - Layer 2 - Layer 3 - Layer 4
raw data -> packet -> datagram -> message
raw data <- packet <- datagram <- message
LoRa (or simulated LoRa) physical layer, This is interfaced by the LoRa transceiver developed by Semtech, which handles the physical modulation and encoding of radio waves. In our code, we interface with the transceiver through the arduino-LoRa library, which is further abstracted by Layer1_LoRa (which exists mostly to allow the Layer 2 code to be tested in our simulator) Layer 1 receives raw data from the LoRa transceiver and sends packets to Layer2 to be interpreted,
char incoming[PACKET_LENGTH];
int incomingLength = 0;
while (LoRa.available()) {
incoming[incomingLength] = (char)LoRa.read();
incomingLength++;
}
LL2.packetReceived(incoming, incomingLength);
}
Layer 1 receives packets from Layer2 and sends raw data to the LoRa transceiver, Like so
if(LoRa.beginPacket()){
for( int i = 0 ; i < len ; i++){
LoRa.write(data[i]);
}
LoRa.endPacket(1);
LoRa.receive();
}
The routing layer. This is the LoRaLayer2 code which creates an ad-hoc packet switching network of nodes. Detailed information on the packet structure and routing protocol used by this layer can be found in the Protocol documentation https://github.com/sudomesh/disaster-radio/wiki/Protocol
struct Packet {
uint8_t ttl;
uint8_t totalLength;
uint8_t sender[ADDR_LENGTH];
uint8_t receiver[ADDR_LENGTH];
uint8_t sequence; // message count of packets tx by sender
uint8_t source[ADDR_LENGTH];
uint8_t hopCount; // start 0, incremented with each retransmit
uint8_t metric; // of source-receiver link
uint8_t datagram[239];
};
The nextHop bytes can be one of three values,
- the address of the neighbor node with the best route to the destination address
- the broadcast address FF:FF:FF:FF
- the routing address AF:FF:FF:FF which signifies that the packet contains routing table information
Layer 2 receives packets from Layer 1, interprets the header, and either forwards the packet by sending the packet back down to Layer 1 or it sends the packet to Layer 3 to be consumed by a service/application.
Layer 2 receives datagrams from Layer 3 along with information at about the destination address, appends a header to the front, creating a packet, and sends that packet to Layer 1.
The transport layer. This has some similarities to UDP. It made up of what we have typically referred to as the "firmware." That is, an arduino sketch that joins any number of clients/services and allows them to communicate, e.g. it allows a telnet session to send a message over the LoRa transceiver.
struct Datagram {
uint8_t destination[ADDR_LENGTH]; // all zeros for loopback, all Fs for broadcast
uint8_t type; // similar function to UDP port number
uint8_t message[234];
};
Layer 3 receives datagrams from Layer 2, interprets datagram header, and sends the datagram to Layer 4
Layer 3 receives messages from Layer 4 along with information about the destination address and type, using this to create a datagram that is sent to Layer 2
The application layer. Can be anything from a Serial console to a WebSocket application to a BLE-connected Android application. The message contained in the datagram (or the entire datagram itself) must be interpreted by the application. Any format can be used for the remaining 233 bytes as long as the intended recipient understands it (e.g. a type 'c' message intended for the chat app may be formatted differently from a type 'm' message intended mapping app). An application could choose to "listen" for specific types of datagrams and ignore any datagrams that are not relevant or cannot be interpreted.