[LORA] Added WiPhone LoRa support (#1458)

* Added WiPhone LoRa support

* Centralised raw-hex functions
This commit is contained in:
xopr authored and GitHub committed 2023-03-12 12:09:45 -05:00
1 parent c7547044fe
commit 504463c5c2
4 files changed
+170 -35

No files matched your search

+141 -7
View File
@@ -33,6 +33,96 @@
# include <SPI.h> # include <SPI.h>
# include <Wire.h> # include <Wire.h>
# define WIPHONE_MESSAGE_MAGIC 0x6c6d
# define WIPHONE_MESSAGE_MIN_LEN sizeof(wiphone_message) - WIPHONE_MAX_MESSAGE_LEN
# define WIPHONE_MAX_MESSAGE_LEN 230
typedef struct __attribute__((packed)) {
// WiPhone uses RadioHead library which has additional (unused) headers
uint8_t rh_to;
uint8_t rh_from;
uint8_t rh_id;
uint8_t rh_flags;
uint16_t magic;
uint32_t to;
uint32_t from;
char message[WIPHONE_MAX_MESSAGE_LEN];
} wiphone_message;
enum LORA_ID_NUM {
UNKNOWN_DEVICE = -1,
WIPHONE,
};
typedef enum LORA_ID_NUM LORA_ID_NUM;
/*
Try and determine device given the payload
*/
uint8_t _determineDevice(byte* packet, int packetSize) {
// Check WiPhone header
if (packetSize >= WIPHONE_MESSAGE_MIN_LEN && ((wiphone_message*)packet)->magic == WIPHONE_MESSAGE_MAGIC)
return WIPHONE;
// No matches
return UNKNOWN_DEVICE;
}
/*
Try and determine device given the JSON type
*/
uint8_t _determineDevice(JsonObject& LORAdata) {
const char* protocol_name = LORAdata["type"];
if (strcmp(protocol_name, "WiPhone") == 0)
return WIPHONE;
// No matches
return UNKNOWN_DEVICE;
}
/*
Create JSON information from WiPhone packet
*/
boolean _WiPhoneToMQTT(byte* packet, JsonObject& LORAdata) {
// Decode the LoRa packet and send over MQTT
wiphone_message* msg = (wiphone_message*)packet;
// Set the header information
char from[9] = {0};
char to[9] = {0};
snprintf(from, 9, "%06X", msg->from);
snprintf(to, 9, "%06X", msg->to);
// From and To are the last 3 octets from the WiPhone's ESP32 chip ID
// Special case is 0x000000: "broadcast"
LORAdata["from"] = from;
LORAdata["to"] = to;
LORAdata["message"] = msg->message;
LORAdata["type"] = "WiPhone";
return true;
}
/*
Create WiPhone packet from JSON
*/
boolean _MQTTtoWiPhone(JsonObject& LORAdata) {
// Prepare a LoRa packet to send to the WiPhone
wiphone_message wiphonemsg;
wiphonemsg.rh_to = 0xff;
wiphonemsg.rh_from = 0xff;
wiphonemsg.rh_id = 0x00;
wiphonemsg.rh_flags = 0x00;
wiphonemsg.magic = WIPHONE_MESSAGE_MAGIC;
wiphonemsg.from = strtol(LORAdata["from"], NULL, 16);
wiphonemsg.to = strtol(LORAdata["to"], NULL, 16);
const char* message = LORAdata["message"];
strlcpy(wiphonemsg.message, message, WIPHONE_MAX_MESSAGE_LEN);
LoRa.write((uint8_t*)&wiphonemsg, strlen(message) + WIPHONE_MESSAGE_MIN_LEN + 1);
return true;
}
void setupLORA() { void setupLORA() {
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_SS); SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_SS);
LoRa.setPins(LORA_SS, LORA_RST, LORA_DI0); LoRa.setPins(LORA_SS, LORA_RST, LORA_DI0);
@@ -69,16 +159,38 @@ void LORAtoMQTT() {
taskMessage = taskMessage + xPortGetCoreID(); taskMessage = taskMessage + xPortGetCoreID();
//trc(taskMessage); //trc(taskMessage);
# endif # endif
String packet; // Create packet and reserve null terminator space
packet = ""; byte packet[packetSize + 1];
boolean binary = false;
for (int i = 0; i < packetSize; i++) { for (int i = 0; i < packetSize; i++) {
packet += (char)LoRa.read(); packet[i] = (char)LoRa.read();
if (packet[i] < 32 || packet[i] > 127)
binary = true;
} }
// Terminate with a null character in case we have a string
packet[packetSize] = 0;
LORAdata["rssi"] = (int)LoRa.packetRssi(); LORAdata["rssi"] = (int)LoRa.packetRssi();
LORAdata["snr"] = (float)LoRa.packetSnr(); LORAdata["snr"] = (float)LoRa.packetSnr();
LORAdata["pferror"] = (float)LoRa.packetFrequencyError(); LORAdata["pferror"] = (float)LoRa.packetFrequencyError();
LORAdata["packetSize"] = (int)packetSize; LORAdata["packetSize"] = (int)packetSize;
LORAdata["message"] = (char*)packet.c_str();
uint8_t deviceId = _determineDevice(packet, packetSize);
if (deviceId == WIPHONE) {
_WiPhoneToMQTT(packet, LORAdata);
} else if (binary) {
// We have non-ascii data: create hex string of the data
char hex[packetSize * 2 + 1];
_rawToHex(packet, hex, packetSize);
// Terminate with a null character
hex[packetSize * 2] = 0;
LORAdata["hex"] = hex;
} else {
// ascii payload
LORAdata["message"] = packet;
}
pub(subjectLORAtoMQTT, LORAdata); pub(subjectLORAtoMQTT, LORAdata);
if (repeatLORAwMQTT) { if (repeatLORAwMQTT) {
Log.trace(F("Pub LORA for rpt" CR)); Log.trace(F("Pub LORA for rpt" CR));
@@ -92,6 +204,7 @@ void MQTTtoLORA(char* topicOri, JsonObject& LORAdata) { // json object decoding
if (cmpToMainTopic(topicOri, subjectMQTTtoLORA)) { if (cmpToMainTopic(topicOri, subjectMQTTtoLORA)) {
Log.trace(F("MQTTtoLORA json" CR)); Log.trace(F("MQTTtoLORA json" CR));
const char* message = LORAdata["message"]; const char* message = LORAdata["message"];
const char* hex = LORAdata["hex"];
int txPower = LORAdata["txpower"] | LORA_TX_POWER; int txPower = LORAdata["txpower"] | LORA_TX_POWER;
int spreadingFactor = LORAdata["spreadingfactor"] | LORA_SPREADING_FACTOR; int spreadingFactor = LORAdata["spreadingfactor"] | LORA_SPREADING_FACTOR;
long int frequency = LORAdata["frequency "] | LORA_BAND; long int frequency = LORAdata["frequency "] | LORA_BAND;
@@ -99,8 +212,9 @@ void MQTTtoLORA(char* topicOri, JsonObject& LORAdata) { // json object decoding
int codingRateDenominator = LORAdata["codingrate"] | LORA_CODING_RATE; int codingRateDenominator = LORAdata["codingrate"] | LORA_CODING_RATE;
int preambleLength = LORAdata["preamblelength"] | LORA_PREAMBLE_LENGTH; int preambleLength = LORAdata["preamblelength"] | LORA_PREAMBLE_LENGTH;
byte syncWord = LORAdata["syncword"] | LORA_SYNC_WORD; byte syncWord = LORAdata["syncword"] | LORA_SYNC_WORD;
bool Crc = LORAdata["enablecrc"] | DEFAULT_CRC; bool crc = LORAdata["enablecrc"] | DEFAULT_CRC;
if (message) { bool invertIQ = LORAdata["invertiq"] | INVERT_IQ;
if (message || hex) {
LoRa.setTxPower(txPower); LoRa.setTxPower(txPower);
LoRa.setFrequency(frequency); LoRa.setFrequency(frequency);
LoRa.setSpreadingFactor(spreadingFactor); LoRa.setSpreadingFactor(spreadingFactor);
@@ -108,10 +222,30 @@ void MQTTtoLORA(char* topicOri, JsonObject& LORAdata) { // json object decoding
LoRa.setCodingRate4(codingRateDenominator); LoRa.setCodingRate4(codingRateDenominator);
LoRa.setPreambleLength(preambleLength); LoRa.setPreambleLength(preambleLength);
LoRa.setSyncWord(syncWord); LoRa.setSyncWord(syncWord);
if (Crc) if (crc)
LoRa.enableCrc(); LoRa.enableCrc();
else
LoRa.disableCrc();
if (invertIQ)
LoRa.enableInvertIQ();
else
LoRa.disableInvertIQ();
LoRa.beginPacket(); LoRa.beginPacket();
uint8_t deviceId = _determineDevice(LORAdata);
if (deviceId == WIPHONE) {
_MQTTtoWiPhone(LORAdata);
} else if (hex) {
// We have hex data: create convert to binary
byte raw[strlen(hex) / 2];
_hexToRaw(hex, raw, sizeof(raw));
LoRa.print((char*)raw);
} else {
// ascii payload
LoRa.print(message); LoRa.print(message);
}
LoRa.endPacket(); LoRa.endPacket();
Log.trace(F("MQTTtoLORA OK" CR)); Log.trace(F("MQTTtoLORA OK" CR));
pub(subjectGTWLORAtoMQTT, LORAdata); // we acknowledge the sending by publishing the value to an acknowledgement topic, for the moment even if it is a signal repetition we acknowledge also pub(subjectGTWLORAtoMQTT, LORAdata); // we acknowledge the sending by publishing the value to an acknowledgement topic, for the moment even if it is a signal repetition we acknowledge also
+4 -28
View File
@@ -54,7 +54,7 @@ void _rfbSend(byte* message) {
void _rfbSend(byte* message, int times) { void _rfbSend(byte* message, int times) {
char buffer[RF_MESSAGE_SIZE]; char buffer[RF_MESSAGE_SIZE];
_rfbToChar(message, buffer); _rawToHex(message, buffer, RF_MESSAGE_SIZE);
Log.notice(F("[RFBRIDGE] Sending MESSAGE" CR)); Log.notice(F("[RFBRIDGE] Sending MESSAGE" CR));
for (int i = 0; i < times; i++) { for (int i = 0; i < times; i++) {
@@ -99,7 +99,7 @@ void _rfbDecode() {
char buffer[RF_MESSAGE_SIZE * 2 + 1] = {0}; char buffer[RF_MESSAGE_SIZE * 2 + 1] = {0};
if (action == RF_CODE_RFIN) { if (action == RF_CODE_RFIN) {
_rfbToChar(&_uartbuf[1], buffer); _rawToHex(&_uartbuf[1], buffer, RF_MESSAGE_SIZE);
Log.trace(F("Creating SRFB buffer" CR)); Log.trace(F("Creating SRFB buffer" CR));
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer; StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
@@ -142,30 +142,6 @@ void _rfbAck() {
Serial.println(); Serial.println();
} }
/*
From an hexa char array ("A220EE...") to a byte array (half the size)
*/
bool _rfbToArray(const char* in, byte* out) {
if (strlen(in) != RF_MESSAGE_SIZE * 2)
return false;
char tmp[3] = {0};
for (unsigned char p = 0; p < RF_MESSAGE_SIZE; p++) {
memcpy(tmp, &in[p * 2], 2);
out[p] = strtol(tmp, NULL, 16);
}
return true;
}
/*
From a byte array to an hexa char array ("A220EE...", double the size)
*/
bool _rfbToChar(byte* in, char* out) {
for (unsigned char p = 0; p < RF_MESSAGE_SIZE; p++) {
sprintf_P(&out[p * 2], PSTR("%02X" CR), in[p]);
}
return true;
}
# if simpleReceiving # if simpleReceiving
void MQTTtoSRFB(char* topicOri, char* datacallback) { void MQTTtoSRFB(char* topicOri, char* datacallback) {
// RF DATA ANALYSIS // RF DATA ANALYSIS
@@ -255,7 +231,7 @@ void MQTTtoSRFB(char* topicOri, char* datacallback) {
valueRPT = 1; valueRPT = 1;
byte message_b[RF_MESSAGE_SIZE]; byte message_b[RF_MESSAGE_SIZE];
_rfbToArray(datacallback, message_b); _hexToRaw(datacallback, message_b, RF_MESSAGE_SIZE);
_rfbSend(message_b, valueRPT); _rfbSend(message_b, valueRPT);
// Acknowledgement to the GTWRF topic // Acknowledgement to the GTWRF topic
pub(subjectGTWSRFBtoMQTT, datacallback); // we acknowledge the sending by publishing the value to an acknowledgement topic, for the moment even if it is a signal repetition we acknowledge also pub(subjectGTWSRFBtoMQTT, datacallback); // we acknowledge the sending by publishing the value to an acknowledgement topic, for the moment even if it is a signal repetition we acknowledge also
@@ -272,7 +248,7 @@ void MQTTtoSRFB(char* topicOri, JsonObject& SRFBdata) {
if (raw) { // send raw in priority when defined in the json if (raw) { // send raw in priority when defined in the json
Log.trace(F("MQTTtoSRFB raw ok" CR)); Log.trace(F("MQTTtoSRFB raw ok" CR));
byte message_b[RF_MESSAGE_SIZE]; byte message_b[RF_MESSAGE_SIZE];
_rfbToArray(raw, message_b); _hexToRaw(raw, message_b, RF_MESSAGE_SIZE);
_rfbSend(message_b, valueRPT); _rfbSend(message_b, valueRPT);
} else { } else {
unsigned long data = SRFBdata["value"]; unsigned long data = SRFBdata["value"];
+1
View File
@@ -46,6 +46,7 @@ extern void MQTTtoLORA(char* topicOri, JsonObject& RFdata);
#define LORA_PREAMBLE_LENGTH 8 #define LORA_PREAMBLE_LENGTH 8
#define LORA_SYNC_WORD 0x12 #define LORA_SYNC_WORD 0x12
#define DEFAULT_CRC true #define DEFAULT_CRC true
#define INVERT_IQ false
#define repeatLORAwMQTT false // do we repeat a received signal by using MQTT with LORA gateway #define repeatLORAwMQTT false // do we repeat a received signal by using MQTT with LORA gateway
+24
View File
@@ -330,6 +330,30 @@ long value_from_hex_data(const char* service_data, int offset, int data_length,
return value; return value;
} }
/*
From an hexa char array ("A220EE...") to a byte array (half the size)
*/
bool _hexToRaw(const char* in, byte* out, int rawSize) {
if (strlen(in) != rawSize * 2)
return false;
char tmp[3] = {0};
for (unsigned char p = 0; p < rawSize; p++) {
memcpy(tmp, &in[p * 2], 2);
out[p] = strtol(tmp, NULL, 16);
}
return true;
}
/*
From a byte array to an hexa char array ("A220EE...", double the size)
*/
bool _rawToHex(byte* in, char* out, int rawSize) {
for (unsigned char p = 0; p < rawSize; p++) {
sprintf_P(&out[p * 2], PSTR("%02X" CR), in[p]);
}
return true;
}
char* ip2CharArray(IPAddress ip) { //from Nick Lee https://stackoverflow.com/questions/28119653/arduino-display-ethernet-localip char* ip2CharArray(IPAddress ip) { //from Nick Lee https://stackoverflow.com/questions/28119653/arduino-display-ethernet-localip
static char a[16]; static char a[16];
sprintf(a, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); sprintf(a, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);