Hello everyone,
I am trying to send LoRaWAN messages from a Heltec Wifi LoRa v3 to a Milesight Gateway connected via Semtech UDP with The Things Network.
I need to send LoRaWAN messages with specific payloads and on defined freqs/sf in order to test some common vulnerabilities for a practical part in my master thesis.
Sending messages with the code example LoRaWan_OLED_sender.ino works fine, but I have problems using the example LoRaSender.ino and the library lora-packet to generate the PHYPayloads.
I have also a CatSniffer from ElectronicCats to sniff all messages.
CatSniffer can receive both - the LoRaWAN MAC implementation of Heltec (LoRaWan_APP) and the custom implementation with manual PHYPayload generation (RadioLib). And the PhyPayloads are valid.
Example generated PhyPayload (Join Request) with Fake IDs: 00F7F885B1569199A901010000009199A9DD63099FC5BB
I tried also to analyse the UDP packets sent from Gateway to TTN with Wireshark - but the Gateway does not receive any packets.
Does anyone have an idea?
Is there a better way to set the public sync word instead Radio.SetSyncWord(52);?
Library for PHYPayloads: https://github.com/anthonykirby/lora-packet
Example LoRaSender.ino: https://github.com/HelTecAutomation/Heltec_ESP32/blob/master/examples/LoRa/LoRaSender/LoRaSender.ino
Custom Code to send HEX based PHYPayloads:
#define SERIALCOMMAND_HARDWAREONLY
#include “HT_SSD1306Wire.h”
#include “LoRaWan_APP.h”
#include <RadioLib.h>
#include “Arduino.h”
SSD1306Wire display1(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED); // addr , freq , i2c group , resolution , rst
#define RF_FREQUENCY 867300000 // Hz
#define TX_OUTPUT_POWER 20 // dBm
#define LORA_BANDWIDTH 0 // [0: 125 kHz,
// 1: 250 kHz,
// 2: 500 kHz,
// 3: Reserved]
#define LORA_SPREADING_FACTOR 7 // [SF7…SF12]
#define LORA_CODINGRATE 1 // [1: 4/5,
// 2: 4/6,
// 3: 4/7,
// 4: 4/8]
#define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx
#define LORA_SYMBOL_TIMEOUT 0 // Symbols
#define LORA_FIX_LENGTH_PAYLOAD_ON false
#define LORA_IQ_INVERSION_ON false
#define BUFFER_SIZE 100
char rxpacket[BUFFER_SIZE];
bool lora_idle = true;
bool rx_on = false;
int rx_progress = 0;
int16_t rssi, rxSize;
static RadioEvents_t RadioEvents;
void OnTxDone(void);
void OnTxTimeout(void);
void OnRxError(void);
void setup() {
Serial.begin(115200);
Mcu.begin();
VextON();
display1.init();
displayText(“Setup LoRa Rx/Tx…”);
RadioEvents.TxDone = OnTxDone;
RadioEvents.TxTimeout = OnTxTimeout;
RadioEvents.RxDone = OnRxDone;
RadioEvents.RxError = OnRxError;
Radio.Init(&RadioEvents);
Radio.SetChannel(RF_FREQUENCY);
Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
LORA_SPREADING_FACTOR, LORA_CODINGRATE,
LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
true, 0, 0, LORA_IQ_INVERSION_ON, 3000);
Radio.SetSyncWord(52);
rssi = 0;
displayText(“Waiting For Cmd…”);
}
void VextON(void) {
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW);
}
void loop() {
if (Serial.available()) {
String command = Serial.readStringUntil(’\n’);
if (command.startsWith("tx ")) {
displayText("Got Tx Cmd......");
tx_sent(command.substring(3));
} else {
displayText("Cmd not found......");
showDisplayStartView();
}
}
if (rx_on) {
if (rx_progress == 100) {
rx_on = false;
rx_progress = 0;
displayText("Waiting For Cmd.........");
return;
}
drawRxProgress();
rx_progress++;
delay(80);
}
Radio.IrqProcess();
}
void OnTxDone(void) {
displayText(“TX done…”);
listenToRxTemporarily();
lora_idle = true;
}
void OnTxTimeout(void) {
Radio.Sleep();
displayText(“TX Timeout…”);
showDisplayStartView();
lora_idle = true;
}
void OnRxDone(uint8_t* payload, uint16_t size, int16_t rssi, int8_t snr) {
rssi = rssi;
rxSize = size;
memcpy(rxpacket, payload, size);
rxpacket[size] = ‘\0’;
Radio.Sleep();
Serial.printf("\r\nreceived packet “%s” with rssi %d , length %d\r\n", rxpacket, rssi, rxSize);
displayText(“Received Packet… :/”);
showDisplayStartView();
lora_idle = true;
}
void OnRxError(void) {
displayText(“RX Error… :/”);
showDisplayStartView();
lora_idle = true;
}
void tx_sent(String message) {
if (lora_idle == true) {
int message_len = message.length() + 1;
char char_array[message_len];
message.toCharArray(char_array, message_len);
int outDataLength = (sizeof(char_array) - 1) / 2;
byte outData[outDataLength];
Serial.printf("\r\nsending packet \"%s\" , length %d, bytes %d\r\n", char_array, strlen(char_array), outDataLength);
hexCharacterStringToBytes(outData, char_array);
Radio.Send(outData, outDataLength);
displayText("Sending Package......");
lora_idle = false;
} else {
displayText(“LoRa is NOT idle…”);
}
}
void displayText(String text) {
Serial.println(text);
display1.clear();
display1.setFont(ArialMT_Plain_10);
display1.setTextAlignment(TEXT_ALIGN_LEFT);
display1.drawString(0, 26, text);
display1.display();
}
void drawRxProgress() {
display1.clear();
display1.drawProgressBar(0, 32, 120, 10, rx_progress);
display1.setTextAlignment(TEXT_ALIGN_CENTER);
display1.drawString(64, 15, “RX mode on”);
display1.display();
}
void showDisplayStartView() {
delay(1000);
displayText(“Waiting For Cmd…”);
}
void listenToRxTemporarily(void) {
rx_on = true;
Serial.println(“Listen to Rx for 8 Seconds”);
Radio.Rx(8000);
}
void hexCharacterStringToBytes(byte* byteArray, const char* hexString) {
bool oddLength = strlen(hexString) & 1;
byte currentByte = 0;
byte byteIndex = 0;
for (byte charIndex = 0; charIndex < strlen(hexString); charIndex++) {
bool oddCharIndex = charIndex & 1;
if (oddLength) {
// If the length is odd
if (oddCharIndex) {
// odd characters go in high nibble
currentByte = nibble(hexString[charIndex]) << 4;
} else {
// Even characters go into low nibble
currentByte |= nibble(hexString[charIndex]);
byteArray[byteIndex++] = currentByte;
currentByte = 0;
}
} else {
// If the length is even
if (!oddCharIndex) {
// Odd characters go into the high nibble
currentByte = nibble(hexString[charIndex]) << 4;
} else {
// Odd characters go into low nibble
currentByte |= nibble(hexString[charIndex]);
byteArray[byteIndex++] = currentByte;
currentByte = 0;
}
}
}
}
byte nibble(char c) {
if (c >= ‘0’ && c <= ‘9’)
return c - ‘0’;
if (c >= ‘a’ && c <= ‘f’)
return c - ‘a’ + 10;
if (c >= ‘A’ && c <= ‘F’)
return c - ‘A’ + 10;
return 0; // Not a valid hexadecimal character
}