Created
April 9, 2022 09:39
-
-
Save NeoCat/3c77ecdb19b9479228f6b2a09c64bb1e to your computer and use it in GitHub Desktop.
LoRa GPS Node & Gateway Sample for Arduino MKR WAN 1310 (freq. = 923MHz used in Japan)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ChaCha.h> | |
#include <SPI.h> // include libraries | |
#include <LoRa.h> | |
const long frequency = 923E6; // LoRa Frequency | |
byte message[64]; | |
int msg_len = 0; | |
struct { | |
float lat, lng; | |
byte num; | |
} data; | |
void decrypt_data() { | |
unsigned int salt = (((unsigned int)message[0] << 8) | message[1]) ^ 0x51b; | |
ChaCha chacha; | |
byte key[16] = {11, 22, 33, 44, 55, 99, 88, 77, 66, 0, 1, 2, 3, 4, 5, 6}; // 暗号鍵. ランダムな値を指定 | |
byte iv[8] = {111, 222, 111, 222, 111 ^ (salt >> 8), 222, 111, salt & 0xff}; // IV. saltの位置を含めランダム値に指定 | |
chacha.setKey(key, 16); | |
chacha.setIV(iv, 8); | |
memset(&data, 0, sizeof(data)); | |
chacha.decrypt((byte*)&data, message+2, 9); | |
} | |
void setup() { | |
Serial.begin(115200); | |
unsigned long start = millis(); | |
pinMode(LED_BUILTIN, OUTPUT); | |
digitalWrite(LED_BUILTIN, HIGH); | |
while (millis() < start + 3000 && !Serial); | |
digitalWrite(LED_BUILTIN, LOW); | |
//LoRa.setPins(csPin, resetPin, irqPin); | |
if (!LoRa.begin(frequency)) { | |
Serial.println("LoRa init failed. Check your connections."); | |
while (true) { | |
digitalWrite(LED_BUILTIN, HIGH); | |
delay(100); | |
digitalWrite(LED_BUILTIN, LOW); | |
delay(100); | |
} | |
} | |
LoRa.setSpreadingFactor(10); // SF | |
LoRa.setSignalBandwidth(125e3); // 帯域幅 | |
LoRa.onReceive(onReceive); | |
LoRa_rxMode(); | |
Serial.println("LoRa init succeeded."); | |
Serial.println("LoRa GPS Gateway"); | |
Serial.println(); | |
} | |
void loop() { | |
if (msg_len) { | |
int rssi = LoRa.packetRssi(); | |
String msg = "Gateway Receive: '"; | |
for (int i = 0; i < msg_len; i++) { | |
char buf[16]; | |
sprintf(buf, "%02x ", message[i]); | |
msg += buf; | |
} | |
msg += "' with RSSI "; | |
msg += rssi; | |
Serial.println(msg); | |
if (msg_len == 11) { | |
digitalWrite(LED_BUILTIN, HIGH); | |
unsigned long tx_start = millis(); | |
byte ack_rssi[2] = {'A', -rssi}; | |
LoRa_sendMessage(ack_rssi, 2); // send a message | |
Serial.print("sent ACK in "); | |
Serial.print(millis() - tx_start); | |
Serial.println(" ms"); | |
digitalWrite(LED_BUILTIN, LOW); | |
decrypt_data(); | |
char buffer[64]; | |
snprintf(buffer, 63, "#SAT=%d LAT=%.6f LNG=%.6f", data.num, data.lat, data.lng); | |
Serial.println(buffer); | |
} | |
msg_len = 0; | |
} | |
} | |
void LoRa_rxMode(){ | |
LoRa.disableInvertIQ(); // normal mode | |
LoRa.receive(); // set receive mode | |
} | |
void LoRa_txMode(){ | |
LoRa.idle(); // set standby mode | |
LoRa.enableInvertIQ(); // active invert I and Q signals | |
} | |
void LoRa_sendMessage(byte message[], int size) { | |
LoRa_txMode(); // set tx mode | |
LoRa.beginPacket(); // start packet | |
LoRa.write(message, size); // add payload | |
LoRa.endPacket(false); // finish packet and send it | |
Serial.println("TxDone"); | |
LoRa_rxMode(); | |
} | |
void onReceive(int packetSize) { | |
for (msg_len = 0; msg_len < 64 && LoRa.available(); msg_len++) | |
message[msg_len] = LoRa.read(); | |
while (LoRa.available()) | |
LoRa.read(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ChaCha.h> | |
#include <SPI.h> | |
#include <LoRa.h> | |
#include <Wire.h> | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_SSD1306.h> | |
#include <ArduinoECCX08.h> | |
#include <ArduinoLowPower.h> | |
#include "TinyGPS++.h" | |
TinyGPSPlus gps; | |
Adafruit_SSD1306 display(128, 32, &Wire, -1); | |
const long frequency = 923E6; // LoRa Frequency | |
char message[64]; | |
int msg_len = 0; | |
unsigned long deep_sleep_at = 0; | |
unsigned long first_at = 0; | |
struct { | |
float lat, lng; | |
byte num; | |
} data; | |
byte encrypted[11]; | |
bool gps_loc_ok = false, gps_sat_ok = false; | |
void error() { | |
while (true) { | |
digitalWrite(LED_BUILTIN, HIGH); | |
delay(100); | |
digitalWrite(LED_BUILTIN, LOW); | |
delay(100); | |
} | |
} | |
void encrypt_data() { | |
unsigned int salt = random(0xfff); | |
ChaCha chacha; | |
byte key[16] = {11, 22, 33, 44, 55, 99, 88, 77, 66, 0, 1, 2, 3, 4, 5, 6}; // 暗号鍵. ランダムな値を指定 | |
byte iv[8] = {111, 222, 111, 222, 111 ^ (salt >> 8), 222, 111, salt & 0xff}; // IV. saltの位置を含めランダム値に指定 | |
chacha.setKey(key, 16); | |
chacha.setIV(iv, 8); | |
chacha.encrypt(encrypted+2, (byte*)&data, 9); | |
salt ^= 0x51b; | |
encrypted[0] = salt >> 8; | |
encrypted[1] = salt & 0xff; | |
} | |
void setupLoRa() { | |
if (!ECCX08.begin()) { | |
Serial.println("Failed to communicate with ECC508/ECC608!"); | |
error(); | |
} | |
if (!ECCX08.locked()) { | |
Serial.println("The ECC508/ECC608 is not locked!"); | |
error(); | |
} | |
randomSeed(ECCX08.random(LONG_MAX)); | |
if (!LoRa.begin(frequency)) { | |
Serial.println("LoRa init failed. Check your connections."); | |
error(); | |
} | |
LoRa.setSpreadingFactor(10); // SF | |
LoRa.setSignalBandwidth(125e3); // 帯域幅 | |
LoRa.onReceive(onReceive); | |
LoRa_rxMode(); | |
Serial.println("LoRa init succeeded."); | |
Serial.println("LoRa GPS Node"); | |
Serial.println(); | |
} | |
void drawText(int x, int y, int w, char *buffer) { | |
display.fillRect(x, y, w, 10, SSD1306_BLACK); | |
display.setTextSize(1); | |
display.setTextColor(SSD1306_WHITE); | |
display.setCursor(x, y); | |
display.print(buffer); | |
display.display(); | |
} | |
void enterDeepSleep() { | |
digitalWrite(LED_BUILTIN, LOW); // 省電力のためデバイスを停止 | |
LoRa.sleep(); | |
Serial1.end(); | |
Serial.end(); | |
USBDevice.detach(); | |
LowPower.deepSleep(5000); // 5秒後にOLED表示を消す | |
display.clearDisplay(); | |
display.display(); | |
LowPower.deepSleep(25000); // 5 + 25秒間スリープさせる | |
first_at = millis(); | |
deep_sleep_at = 0; | |
digitalWrite(LED_BUILTIN, HIGH); | |
USBDevice.attach(); | |
Serial.begin(115200); | |
Serial1.begin(115200); | |
setupLoRa(); | |
} | |
void setup() { | |
Serial.begin(115200); | |
unsigned long start = millis(); | |
while (millis() < start + 3000 && !Serial); | |
pinMode(LED_BUILTIN, OUTPUT); | |
digitalWrite(LED_BUILTIN, LOW); | |
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) { | |
Serial.println(F("SSD1306 allocation failed")); | |
error(); | |
} | |
display.clearDisplay(); | |
display.setTextSize(2); | |
display.setTextColor(SSD1306_WHITE); | |
display.setCursor(16, 10); | |
display.println(F("LoRa GPS")); | |
display.display(); | |
display.clearDisplay(); | |
setupLoRa(); | |
// Setup GPS | |
Serial1.begin(9600); | |
Serial1.print("$PCAS01,5*19\r\n"); // Set baud rate to 115200 | |
delay(100); | |
Serial1.end(); | |
Serial1.begin(115200); | |
Serial1.println("$PCAS04,7*1E\r\n"); // Activate GPS/GLONASS/BDS | |
first_at = millis(); | |
} | |
void loop() { | |
char buffer[64]; | |
digitalWrite(LED_BUILTIN, LOW); | |
bool deep_sleep = deep_sleep_at && millis() >= deep_sleep_at; | |
if (Serial1.available()) { | |
int r = Serial1.read(); | |
gps.encode(r); | |
//Serial.write(r); | |
} | |
if (gps.time.isValid() && gps.time.isUpdated()) { | |
sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d", | |
gps.date.year(), gps.date.month(), gps.date.day(), | |
gps.time.hour(), gps.time.minute(), gps.time.second()); | |
Serial.println(buffer); | |
drawText(0, 0, 128, buffer); | |
} | |
if (gps.satellites.isUpdated()) { | |
data.num = gps.satellites.value(); | |
snprintf(buffer, 63, "# Sat = %d", data.num); | |
Serial.println(buffer); | |
snprintf(buffer, 63, "#%d", data.num); | |
drawText(32, 22, 32, buffer); | |
gps_sat_ok = true; | |
} | |
if (gps.location.isUpdated()) { | |
data.lat = gps.location.lat(); | |
data.lng = gps.location.lng(); | |
snprintf(buffer, 63, "%.6f %.6f %.1fm", | |
data.lat, data.lng, gps.altitude.meters()); | |
Serial.println(buffer); | |
snprintf(buffer, 63, "%.6f %.6f", data.lat, data.lng); | |
drawText(0, 11, 128, buffer); | |
snprintf(buffer, 63, "%dm", (int)gps.altitude.meters()); | |
drawText(0, 22, 32, buffer); | |
gps_loc_ok = true; | |
} | |
if (msg_len > 0) { | |
int rssi = LoRa.packetRssi(); | |
Serial.print("Node Receive: '"); | |
if (msg_len == 2 && message[0] == 'A') { | |
Serial.print("ACK -"); | |
Serial.print(message[1], DEC); | |
deep_sleep = true; | |
snprintf(buffer, 63, "OK %d/%d", -rssi, message[0]); | |
drawText(64, 22, 64, buffer); | |
} else { | |
Serial.write(message, msg_len); | |
} | |
Serial.print("' with RSSI "); | |
Serial.println(rssi); | |
msg_len = 0; | |
} | |
if (deep_sleep_at) { | |
gps_loc_ok = gps_sat_ok = false; | |
if (deep_sleep) { | |
enterDeepSleep(); | |
} | |
} else if (gps_loc_ok && gps_sat_ok || millis() >= first_at + 2000) { | |
drawText(64, 22, 64, "SENDING..."); | |
gps_loc_ok = gps_sat_ok = false; | |
encrypt_data(); | |
digitalWrite(LED_BUILTIN, HIGH); | |
unsigned long tx_start = millis(); | |
LoRa_sendMessage(encrypted, 11); | |
snprintf(buffer, 63, "SENT %dms", millis() - tx_start); | |
Serial.print("**** "); | |
Serial.println(buffer); | |
drawText(64, 22, 64, buffer); | |
digitalWrite(LED_BUILTIN, LOW); | |
deep_sleep_at = millis() + 1000; | |
} | |
} | |
void LoRa_rxMode() { | |
LoRa.enableInvertIQ(); // active invert I and Q signals | |
LoRa.receive(); // set receive mode | |
} | |
void LoRa_txMode() { | |
LoRa.idle(); // set standby mode | |
LoRa.disableInvertIQ(); // normal mode | |
LoRa.enableCrc(); | |
} | |
void LoRa_sendMessage(byte message[], int len) { | |
LoRa_txMode(); // set tx mode | |
LoRa.beginPacket(); // start packet | |
LoRa.write(message, len); // add payload | |
LoRa.endPacket(false); // finish packet and send it | |
LoRa_rxMode(); | |
} | |
void onReceive(int packetSize) { | |
for (msg_len = 0; msg_len < 64 && LoRa.available(); msg_len++) | |
message[msg_len] = LoRa.read(); | |
while (LoRa.available()) | |
LoRa.read(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment