Customizing the LoRa Protocol --- Enhancing Data Reliability

by makerfabs in Circuits > Arduino

72 Views, 0 Favorites, 0 Comments

Customizing the LoRa Protocol --- Enhancing Data Reliability

lora-logo-574x360.png
5592F42960BC1A81E2DC4299DB64C16B.jpg

What is LoRa?

LoRa (Long Range) is a Low Power Wide Area Network (LPWAN) wireless communication technology developed by Semtech. Its core advantage lies in enabling communication over several kilometers—or even tens of kilometers—while consuming extremely low power, making it highly suitable for data transmission between Internet of Things (IoT) devices. It has the following features: Long-range transmission, Low power consumption, Low data rate, Strong penetration capability.


Problems with LoRa

Although LoRa technology has clear advantages in low power consumption and long-range communication, but it also faces some common issues in practical use:

  1. No confirmation of data reception: LoRa is connectionless by default, so the sender cannot confirm whether the receiver has successfully received the data.
  2. Low data transmission rate: The amount of data transmitted each time is limited, making it unsuitable for large-volume data communication.
  3. Data loss or corruption: In environments with multiple nodes or signal interference, data packets may be lost or received incompletely.


How to solve it?

To address the issue of data reliability, we have designed a communication mechanism:

1.CRC Validation Mechanism

When sending data, we introduce CRC (Cyclic Redundancy Check) to ensure data integrity:

  1. The sender appends a calculated CRC value to the end of the data before transmission.
  2. Upon receiving the data, the receiver recalculates the CRC and compares it with the appended CRC value.
  3. If they match, the data is considered intact; otherwise, the packet is discarded.


2.Data Acknowledgment Mechanism

We have introduced a bidirectional communication protocol:

  1. After sending the data, the sender waits for an acknowledgment from the receiver.
  2. If no acknowledgment is received within a timeout period, the sender automatically retransmits the data.

Supplies

QQ20250606-163204.png

We use the Makerfabs LoRa Soil Monitoring & Irrigation Kit, This Kit is based on ESP32 and Lora. The MaTouch 3.5 inch display is the console for the system:

  1. Receives the Lora message from Lora moisture sensors (Lora moisture sensorsMaTouch) and display on the screen.
  2. Send control commands to Lora 4-chnanel MOSFET (MaTouchLora 4-chnanel MOSFET).


LoRa Soil Monitoring & Irrigation Kit

MaTouch_ESP32-S3 SPI TFT with Touch 3.5'' ILI9488 *1;

Lora Expansion for ESP32 Display *1;

Lora Moisture Sensor *1;

Lora 4 Channel MOSFET *1;

12V Power Supply *1;

Data Packet Format

QQ20250606-091329.png

We modified the LoRa transmission and reception part by adding a custom protocol, which includes CRC validation and data acknowledgment. On top of the original system, we added:

  1. CRC is appended to each data packet to verify data integrity and correctness during transmission and reception.
  2. An acknowledgment mechanism is implemented on both the LoRa transmitter and receiver sides to guarantee that the receiver has successfully received the transmitted data.

LoRa Communication Protocol From Lora Moisture Sensor to MaTouch

QQ20250607-113414.png

Lora Moisture Sensor→MaTouch

  1. Sensor Data Collection

We amplify the collected data by 10 times before transmission, preserves one decimal place while saving space.

temperature = humiditySensor.getTemperature();
humidity = humiditySensor.getHumidity();

temp_value = (uint16_t)(temperature * 10);
humi_value = (uint16_t)(humidity * 10);
  1. Data Packet Assembly

The data length is added to the packet to provide the receiver with a CRC calculation;

uint8_t len = i;
send_data[i++] = len;

And the CRC value is calculated once locally to provide the receiver with a comparison.

uint16_t crc = CRC16_CCITT(send_data, len);
send_data[i++] = crc >> 8;
send_data[i++] = crc & 0xff;
  1. Send to MaTouch
radio.transmit(send_data, i);
  1. Wait for Response

Upon receiving an acknowledgment from MaTouch, the sensor enters sleep mode.

if (command_explain(receive_data))
{
Serial.println("rx ok!!! go to sleep");
radio.sleep();
packetnum++;
readSensorStatus = false;
digitalWrite(SENSOR_POWER_PIN, LOW); // Sensor/RF95 power off
delay(100);
rx_timeout_cnts = 0;
lora_mode = Lora_Sleep;
break;
}

Otherwise, it will retry sending. If no acknowledgment is received after two retries, the sensor enters sleep mode.

else if (state == ERR_RX_TIMEOUT)
{
// timeout occurred while waiting for a packet
Serial.println(F("timeout!"));
rx_timeout_cnts++;
if(rx_timeout_cnts > 2)
{
rx_timeout_cnts = 0;
lora_mode = Lora_Init;
break;
}
}


MaTouch → LoRa moisture sensors

  1. Receive Data from LoRa Moisture Sensor
  2. CRC Validation
uint16_t analyse_crc = CRC16_CCITT(data, data[16]); // Calculate the CRC
uint16_t crc = (data[17] << 8) | data[18]; // Extract the CRC value from the data packet

If the CRC check passes, a confirmation packet is sent back to the LoRa Moisture Sensor, and the soil moisture value is displayed on the screen.

if(analyse_crc == crc)
{
Serial.print("CRC check pass");
...
}

If the CRC check fails, the system continues waiting to receive data.

else
{
start_receive();
}

LoRa Communication Protocol From MaTouch to MOSFET

QQ20250607-113446.png

MaTouch→Lora 4-channel MOSFET

  1. After pressing the Send button on the screen, the system starts building the data packet.

The packet includes the MOS value set on the screen, the data length (for CRC calculation on the receiver side), and a locally calculated CRC value for verification.

lora_send_len = 0;
memset(lora_send_data, 0, sizeof(lora_send_data));

memcpy(lora_send_data, mos_id0, 6); //MOS ID
lora_send_len += 6;
mos0_cnts++;
lora_send_data[lora_send_len++] = mos0_cnts >> 8; //Serial Number
lora_send_data[lora_send_len++] = mos0_cnts & 0xff;
lora_send_data[lora_send_len++] = 0x02; //MOS Module Flag
lora_send_data[lora_send_len++] = mos0_control_flag; //4-Channel MOSFET Switch Control
uint8_t len = lora_send_len;
lora_send_data[lora_send_len++] = len; //Total Byte Length

uint16_t crc_mos0_send = CRC16_CCITT(lora_send_data, len); //CRC
lora_send_data[lora_send_len++] = crc_mos0_send >> 8;
lora_send_data[lora_send_len++] = crc_mos0_send & 0xff;
  1. Send to Lora 4-channel MOSFET
radio.transmit(lora_send_data, lora_send_len);
  1. Wait for a response
start_receive();
memset(receive_data, 0, sizeof(receive_data));
recv_interrupt_flag = true;

Upon receiving a reply from the LoRa 4-Channel MOSFET, the system performs a CRC check.

uint16_t mos_analyse_crc = CRC16_CCITT(data, data[10]);
uint16_t mos_crc = (data[11] << 8) | data[12];

If CRC validation, verifies whether the actual MOS status matches the intended control state.

If status match pass, the system enters data-receiving mode.

Otherwise, the system resending the packet.

if((memcmp(data, mos_id0, 6) == 0) && mos0_control_flag == data[9])
{
Serial.print("mos_id0 control ok!\n");
lv_label_set_text(ui_Label18, "Send OK");
mos0_send_flag = 0;
start_receive();
memset(receive_data, 0, sizeof(receive_data));
}
else
{
Serial.print("mos_id0 control error! send again\n");
xEventGroupSetBits(eventGroup, LORA_SEND_EV);
}

If the CRC check fails, the system resending the packet.

if(mos1_resend_cnts <= 2)
{
xEventGroupSetBits(eventGroup, LORA_SEND_EV);
}

If retransmission fails twice, the UI displays "Send Error".

else
{
lv_label_set_text(ui_Label19, "Send Error");
mos1_send_flag = 0;
mos1_one_seconde_cnts = 0;
mos1_resend_cnts = 0;
mos1_first_send_flag = 0;
}


Lora 4-channel MOSFET→MaTouch

  1. Receive data from MaTouch
int state = radio.receive(receive_data,20);
  1. Parse the data

Perform CRC validation.

uint16_t mos_analyse_crc = CRC16_CCITT(data, data[10]);
uint16_t mos_crc = (data[11] << 8) | data[12];

If the CRC check passes, parse the MOS data and execute the corresponding switch control.

Serial.println("This is my MOS data");
mos_control_flag = data[9];
mos_control(mos_control_flag);

Then, build a response data packet containing the actual control status and send it back to MaTouch.

lora_send_len = 0;
memset(lora_send_data, 0, sizeof(lora_send_data));
memcpy(lora_send_data, data, 8);
lora_send_len += 8;
lora_send_data[lora_send_len++] = 0x02;
lora_send_data[lora_send_len++] = mos_control_flag;
uint8_t len = lora_send_len;
lora_send_data[lora_send_len++] = len;
uint16_t crc_send = CRC16_CCITT(lora_send_data, len);
lora_send_data[lora_send_len++] = crc_send >> 8;
lora_send_data[lora_send_len++] = crc_send & 0xff;

If the CRC check fails, remain in data-receiving mode.

else
{
Serial.println("This is not my MOS data");
}

Conclusion

IMG_20250606_134409.jpg
IMG_20250606_134539.jpg
IMG20250606134852.jpg
IMG20250606134833.jpg
  1. With CRC verification, data reception is 100% accurate and complete.
  2. With the acknowledgment mechanism, data communication achieves 100% success.

In addition to upgrading the LoRa protocol, we also enhanced the screen UI using SquareLine Studio and improved user interaction with LVGL. Come and experience it!

Code

For detailed code and implementation, please refer to the project on Github.