LoRa Basics Modem and LoRa Edge documentation

Component - Reliable Octet Stream Encoding

Introduction

The Reliable Octet Stream Encoding (ROSE), available as a part of the LoRa Cloud™ Device & Application Services, is a fragmentation and reassembly service. ROSE serves two purposes:

  1. Provides a virtual MTU of 254 bytes, regardless of the underlying transport layer.

  2. Protects the data stream against packet loss via forward error correction.

In addition to respecting data privacy, the stream can be encrypted so that the LoRa Cloud Device & Application Services are not able to access the data.

Note

Abstracting the MTU is useful when the LoRa Basics™ Modem is used in the US915 region, where the size of a GNSS scan may exceed the maximum payload length.

Compatibility

LoRa Basics Modem

LoRa Basics Modem-E

Prerequisites

Common:

  • The device is connected to its application server.

  • The application server forwards messages on a configured Device Management FPort (FPort 199 by default) to das.loracloud.com.

Prerequisites for LoRa Basics Modem:

  • encryptionKey: the key may be personalized

Prerequisites for LoRa Basics Modem-E:

  • encryptionKey: the key used is the AppSKey

Step-by-Step Procedure

  1. Initiate the ROSE session with the StreamInit() command and the following parameters:

    • Select plain text or encrypted: If encrypted, the stream will not be seen as plain text by the LoRa Cloud Device & Application Services.

    • Select the FPort to send the byte stream to.

  2. Submit the records to be transferred to a 512-byte buffer by invoking SendStreamData().

  3. Whenever the modem’s internal buffer contains data records, packets are sent autonomously with redundancy and (optionally) with encryption.

  4. Use StreamStatus() to query the status of the streaming buffer on the specified FPort. This command returns the following:

    • Pending: Indicates the number of bytes pending transmission.

    • Free: Indicates the number of free bytes in the buffer.

  5. When all fragments (including redundancy) are sent, the modem will generate the event StreamingDone.

  6. Once the stream is reconstructed the LoRa Cloud Device & Application Services will return it in the UPLINK_RESPONSE JSON object stream_records.

Note

  • ROSE differs from Large File Upload (LFU) in that it does not generate a downlink when the stream is delivered to the LoRa Cloud Device & Application Services.

  • The maximum record size sent in one call to SendStreamData() is 254 bytes.

  • If the FPort value is 0, or is the same as the DM FPort (FPort 199 by default) the modem will encapsulate the streaming fragments in the modem sub-protocol.

Sample Code

End-Device Application

#include "lr1110_modem_lorawan.h"

// Initialize streaming
lr1110_modem_stream_init(
      &context,
      0,        // Steaming FPort. 0 = transported by modem sub-protocol
      LR1110_MODEM_FILE_ENCRYPTION_DISABLE,
);

// Add data to the stream buffer
uint8_t data_to_stream[200] = {0};
lr1110_modem_send_stream_data(
   &context,
   0,          // Same FPort than lr1110_modem_stream_init()
   data_to_stream,
   200
);

// Streaming starts immediately in background

// Add other data to the stream buffer, even if the first stream is not over
uint8_t other_data_to_stream[150] = {0};
lr1110_modem_send_stream_data(
   &context,
   0,          // Same FPort than lr1110_modem_stream_init()
   other_data_to_stream,
   150
);

// Get stream status
lr1110_modem_stream_status_t stream_status;
lr1110_modem_stream_status(
   &context,
   0,          // Same FPort than lr1110_modem_stream_init()
   &stream_status
);
printf(
   "%d bytes pending, %d bytes left\n",
   stream_status.pending,
   stream_status.free,
);

// Modem event call-back
customer_event_callback_streaming_done(  ) {
   printf( "Modem streaming buffer is empty\n" );
}

Application Server

Pseudocode to retrieve a stream when the LoRa Cloud Device & Application Services reassembles it.

# Call the LoRa Cloud Device & Application Services and get the answer to an uplink
res = call_das_device_send(uplink)  # /api/v1/device/send

# Extract stream_records array, if any
if ( res["stream_records"] != None or res["stream_records"] != []):
   for stream in res["stream_records"]
      printf( f"stream offset: {stream[0]}  - data: {stream[1]}" )

Pseudocode to retrieve the last eight (8) streams stored in the LoRa Cloud Device & Application Services from the device_info API.

# Call the LoRa Cloud Device & Application Services to query device information
res = call_das_device_info( devEUI )  # /api/v1/device/info
res = res["result"][devEUI]

# Extract stream_records array, if any
if ( res["result"]["uploaded_stream_records"] != None ):
   for stream in res["stream_records"]
      printf( f"stream offset: {stream.off}  - data: {stream.data}" )

In-depth Behavior

  • ROSE fragments should be sent in non-confirmed uplink frames.

  • A running stream is indicated in the Stream flag of the modem’s status.

  • New data records can be added to the buffer at any time during the stream, provided there is enough space available in the buffer.

  • When the upload stream is finished, and all fragments have been sent, a StreamingDone even is generated.

  • The streaming FPort can be changed after a reset or a streamingDone event by by calling StreamInit() again with the new FPort number.

@startumltitle Simplified Flow for\nROSE Streamskinparam linetype orthobox Deviceparticipant "End-Device\nApplication" as UC #99FF99participant "LR1110\nModem-E" as LR1110end boxbox Serversparticipant "Customer\nApplication Server" as AS #99FF99participant "LoRaCloud\nDAS" as DASend boxUC -> LR1110 : StreamInit( FPort, Plain/Encrypted )UC -> LR1110 : SendStreamData( FPort, Record )Loop As long as the Modem Stream buffer isn't empty    note right of LR1110: The modem transfers its Stream buffer content    LR1110 -> DAS ++ : Stream fragment    UC -> LR1110 ++ : StreamStatus( FPort )    LR1110 -> UC : StreamStatus( Pending, Free )    deactivate LR1110    LR1110 -> DAS : Stream fragment    DAS -> AS : Reconstructed stream as part of DAS answer to the uplink    note right of UC: Other records may be\n added on-the-fly    UC -> LR1110 ++ : StreamStatus( FPort )    LR1110 -> UC : StreamStatus( Pending, Free )    deactivate LR1110    UC -> LR1110 : SendStreamData( FPort, Record )    LR1110 -> DAS : Stream fragment    LR1110 ->x AS : Lost stream fragment    LR1110 -> DAS : Stream fragmentendLR1110 -> UC : Raises EVENT pin highUC -> LR1110 ++ : Command GetEvent( )LR1110 -> UC : Response to GetEvent( StreamDone )deactivate LR1110DAS -> AS : Reconstructed stream as part of DAS answer to the uplinkdeactivate DAS@enduml

Used by

Applications

References