Skip to content

Instantly share code, notes, and snippets.

@NeoCat
Created April 9, 2022 09:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NeoCat/3c77ecdb19b9479228f6b2a09c64bb1e to your computer and use it in GitHub Desktop.
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)
#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();
}
#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