kopia lustrzana https://github.com/lora-aprs/LoRa_APRS_iGate
push a lot of changes...
rodzic
295feb98cc
commit
d5c015f4b9
|
@ -1,3 +0,0 @@
|
|||
[submodule "lib"]
|
||||
path = lib/common
|
||||
url = ../LoRa_APRS_Common
|
|
@ -2,7 +2,6 @@
|
|||
"callsign":"NOCALL-10",
|
||||
"wifi":
|
||||
{
|
||||
"active":false,
|
||||
"AP": [
|
||||
{ "SSID":"YOURSSID", "password":"YOURPASSWORD" }
|
||||
]
|
||||
|
@ -18,7 +17,6 @@
|
|||
},
|
||||
"aprs_is":
|
||||
{
|
||||
"active":false,
|
||||
"password":"",
|
||||
"server":"euro.aprs2.net",
|
||||
"port":14580,
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
#include "APRS-IS.h"
|
||||
|
||||
APRS_IS::APRS_IS(const String & user, const String & passcode, const String & tool_name, const String & version)
|
||||
: _user(user), _passcode(passcode), _tool_name(tool_name), _version(version)
|
||||
{
|
||||
}
|
||||
|
||||
bool APRS_IS::connect(const String & server, const int port)
|
||||
{
|
||||
const String login = "user " + _user + " pass " + _passcode + " vers " + _tool_name + " " + _version + "\n\r";
|
||||
return connect_(server, port, login);
|
||||
}
|
||||
|
||||
bool APRS_IS::connect(const String & server, const int port, const String & filter)
|
||||
{
|
||||
const String login = "user " + _user + " pass " + _passcode + " vers " + _tool_name + " " + _version + " filter " + filter + "\n\r";
|
||||
return connect_(server, port, login);
|
||||
}
|
||||
|
||||
bool APRS_IS::connect_(const String & server, const int port, const String & login_line)
|
||||
{
|
||||
if(!_client.connect(server.c_str(), port))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
sendMessage(login_line);
|
||||
// TODO: implement check if auth was successfull!
|
||||
//while(!available());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool APRS_IS::connected()
|
||||
{
|
||||
return _client.connected();
|
||||
}
|
||||
|
||||
bool APRS_IS::sendMessage(const String & message)
|
||||
{
|
||||
if(!connected())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_client.println(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool APRS_IS::sendMessage(const std::shared_ptr<APRSMessage> message)
|
||||
{
|
||||
if(!connected())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_client.println(message->encode());
|
||||
return true;
|
||||
}
|
||||
|
||||
void APRS_IS::action(std::shared_ptr<APRSMessage> elem, int rssi, float snr)
|
||||
{
|
||||
sendMessage(elem);
|
||||
}
|
||||
|
||||
int APRS_IS::available()
|
||||
{
|
||||
return _client.available();
|
||||
}
|
||||
|
||||
String APRS_IS::getMessage()
|
||||
{
|
||||
String line;
|
||||
if (_client.available() > 0)
|
||||
{
|
||||
line = _client.readStringUntil('\n');
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
std::shared_ptr<APRSMessage> APRS_IS::getAPRSMessage()
|
||||
{
|
||||
String line;
|
||||
if (_client.available() > 0)
|
||||
{
|
||||
line = _client.readStringUntil('\n');
|
||||
}
|
||||
if(line.length() == 0 || line.startsWith("#"))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
std::shared_ptr<APRSMessage> msg = std::shared_ptr<APRSMessage>(new APRSMessage());
|
||||
msg->decode(line);
|
||||
emit(msg);
|
||||
return msg;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
#ifndef APRS_IS_Lib_h_
|
||||
#define APRS_IS_Lib_h_
|
||||
|
||||
#include <SignalSlot.h>
|
||||
#include <WiFi.h>
|
||||
#include <APRS-Decoder.h>
|
||||
|
||||
class APRS_IS : public Signal1<const std::shared_ptr<APRSMessage>>, public Slot3<std::shared_ptr<APRSMessage>, int, float>
|
||||
{
|
||||
public:
|
||||
APRS_IS(const String & user, const String & passcode, const String & tool_name, const String & version);
|
||||
|
||||
bool connect(const String & server, const int port);
|
||||
bool connect(const String & server, const int port, const String & filter);
|
||||
bool connect_(const String & server, const int port, const String & login_line);
|
||||
bool connected();
|
||||
|
||||
bool sendMessage(const String & message);
|
||||
bool sendMessage(const std::shared_ptr<APRSMessage> message);
|
||||
void action(std::shared_ptr<APRSMessage> msg, int rssi, float snr) override;
|
||||
|
||||
int available();
|
||||
|
||||
String getMessage();
|
||||
std::shared_ptr<APRSMessage> getAPRSMessage();
|
||||
|
||||
private:
|
||||
const String _user;
|
||||
const String _passcode;
|
||||
const String _tool_name;
|
||||
const String _version;
|
||||
WiFiClient _client;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
#include <logger.h>
|
||||
#include <power_management.h>
|
||||
#include "BoardFinder.h"
|
||||
|
||||
BoardConfig::BoardConfig(
|
||||
String name, BoardType type,
|
||||
uint8_t oledsda, uint8_t oledscl, uint8_t oledaddr, uint8_t oledreset,
|
||||
uint8_t lorasck, uint8_t loramiso, uint8_t loramosi, uint8_t loracs, uint8_t lorareset, uint8_t lorairq,
|
||||
bool needcheckpowerchip, bool powercheckstatus)
|
||||
:
|
||||
Name(name), Type(type),
|
||||
OledSda(oledsda), OledScl(oledscl), OledAddr(oledaddr), OledReset(oledreset),
|
||||
LoraSck(lorasck), LoraMiso(loramiso), LoraMosi(loramosi), LoraCS(loracs), LoraReset(lorareset), LoraIRQ(lorairq),
|
||||
needCheckPowerChip(needcheckpowerchip), powerCheckStatus(powercheckstatus)
|
||||
{
|
||||
}
|
||||
|
||||
BoardFinder::BoardFinder(std::list<std::shared_ptr<BoardConfig>> boardConfigs)
|
||||
{
|
||||
_boardConfigs = boardConfigs;
|
||||
}
|
||||
|
||||
std::shared_ptr<BoardConfig> BoardFinder::searchBoardConfig()
|
||||
{
|
||||
logPrintlnI("looking for a board config.");
|
||||
logPrintlnI("searching for OLED...");
|
||||
|
||||
for(std::shared_ptr<BoardConfig> boardconf : _boardConfigs)
|
||||
{
|
||||
if(boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus)
|
||||
{
|
||||
PowerManagement powerManagement;
|
||||
TwoWire wire(0);
|
||||
wire.begin(boardconf->OledSda, boardconf->OledScl);
|
||||
powerManagement.begin(wire);
|
||||
powerManagement.activateOLED();
|
||||
}
|
||||
else if(boardconf->needCheckPowerChip)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(checkOledConfig(boardconf))
|
||||
{
|
||||
logPrintI("found a board config: ");
|
||||
logPrintlnI(boardconf->Name);
|
||||
return boardconf;
|
||||
}
|
||||
}
|
||||
|
||||
logPrintlnW("could not find OLED, will search for the modem now...");
|
||||
|
||||
for(std::shared_ptr<BoardConfig> boardconf : _boardConfigs)
|
||||
{
|
||||
if(boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus)
|
||||
{
|
||||
PowerManagement powerManagement;
|
||||
TwoWire wire(0);
|
||||
wire.begin(boardconf->OledSda, boardconf->OledScl);
|
||||
powerManagement.begin(wire);
|
||||
powerManagement.activateLoRa();
|
||||
}
|
||||
if(checkModemConfig(boardconf))
|
||||
{
|
||||
logPrintI("found a board config: ");
|
||||
logPrintlnI(boardconf->Name);
|
||||
return boardconf;
|
||||
}
|
||||
}
|
||||
|
||||
logPrintlnW("could not find a board config!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<BoardConfig> BoardFinder::getBoardConfig(String name)
|
||||
{
|
||||
std::_List_iterator<std::shared_ptr<BoardConfig>> elem = std::find_if(_boardConfigs.begin(), _boardConfigs.end(), [&](std::shared_ptr<BoardConfig> conf)
|
||||
{
|
||||
return conf->Name == name;
|
||||
});
|
||||
if(elem == _boardConfigs.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return *elem;
|
||||
}
|
||||
|
||||
bool BoardFinder::checkOledConfig(std::shared_ptr<BoardConfig> boardConfig)
|
||||
{
|
||||
if(boardConfig->OledReset > 0)
|
||||
{
|
||||
pinMode(boardConfig->OledReset, OUTPUT);
|
||||
digitalWrite(boardConfig->OledReset, HIGH);
|
||||
delay(1);
|
||||
digitalWrite(boardConfig->OledReset, LOW);
|
||||
delay(10);
|
||||
digitalWrite(boardConfig->OledReset, HIGH);
|
||||
}
|
||||
TwoWire wire(0);
|
||||
if(!wire.begin(boardConfig->OledSda, boardConfig->OledScl))
|
||||
{
|
||||
logPrintlnW("issue with wire");
|
||||
return false;
|
||||
}
|
||||
wire.beginTransmission(boardConfig->OledAddr);
|
||||
if(!wire.endTransmission())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BoardFinder::checkModemConfig(std::shared_ptr<BoardConfig> boardConfig)
|
||||
{
|
||||
pinMode(boardConfig->LoraReset, OUTPUT);
|
||||
digitalWrite(boardConfig->LoraReset, LOW);
|
||||
delay(10);
|
||||
digitalWrite(boardConfig->LoraReset, HIGH);
|
||||
delay(10);
|
||||
|
||||
pinMode(boardConfig->LoraCS, OUTPUT);
|
||||
digitalWrite(boardConfig->LoraCS, HIGH);
|
||||
|
||||
SPIClass spi;
|
||||
spi.begin(boardConfig->LoraSck, boardConfig->LoraMiso, boardConfig->LoraMosi, boardConfig->LoraCS);
|
||||
|
||||
digitalWrite(boardConfig->LoraCS, LOW);
|
||||
|
||||
spi.beginTransaction(SPISettings(8E6, MSBFIRST, SPI_MODE0));
|
||||
spi.transfer(0x42);
|
||||
uint8_t response = spi.transfer(0x00);
|
||||
spi.endTransaction();
|
||||
|
||||
digitalWrite(boardConfig->LoraCS, HIGH);
|
||||
|
||||
if(response == 0x12)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BoardFinder::checkPowerConfig(std::shared_ptr<BoardConfig> boardConfig)
|
||||
{
|
||||
TwoWire wire(0);
|
||||
if(!wire.begin(boardConfig->OledSda, boardConfig->OledScl))
|
||||
{
|
||||
logPrintlnW("issue with wire");
|
||||
return false;
|
||||
}
|
||||
wire.beginTransmission(0x34);
|
||||
wire.write(0x03);
|
||||
wire.endTransmission();
|
||||
|
||||
wire.requestFrom(0x34, 1);
|
||||
int response = wire.read();
|
||||
wire.endTransmission();
|
||||
|
||||
logPrintlnD(String(response));
|
||||
if(response == 0x03)
|
||||
{
|
||||
logPrintlnD("power chip found!");
|
||||
return true;
|
||||
}
|
||||
logPrintlnD("power chip NOT found");
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef BOARD_FINDER_H_
|
||||
#define BOARD_FINDER_H_
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
|
||||
enum BoardType
|
||||
{
|
||||
eHELTEC_WIFI_LORA_32_V1,
|
||||
eHELTEC_WIFI_LORA_32_V2,
|
||||
eTTGO_LORA32_V1,
|
||||
eTTGO_LORA32_V2,
|
||||
eTTGO_T_Beam_V0_7,
|
||||
eTTGO_T_Beam_V1_0,
|
||||
eETH_BOARD,
|
||||
eTRACKERD
|
||||
};
|
||||
|
||||
class BoardConfig
|
||||
{
|
||||
public:
|
||||
BoardConfig(
|
||||
String name, BoardType type,
|
||||
uint8_t oledsda, uint8_t oledscl, uint8_t oledaddr, uint8_t oledreset,
|
||||
uint8_t lorasck, uint8_t loramiso, uint8_t loramosi, uint8_t loracs, uint8_t lorareset, uint8_t lorairq,
|
||||
bool needcheckpowerchip = false, bool powercheckstatus = false);
|
||||
|
||||
String Name;
|
||||
BoardType Type;
|
||||
|
||||
uint8_t OledSda;
|
||||
uint8_t OledScl;
|
||||
uint8_t OledAddr;
|
||||
uint8_t OledReset;
|
||||
|
||||
uint8_t LoraSck;
|
||||
uint8_t LoraMiso;
|
||||
uint8_t LoraMosi;
|
||||
uint8_t LoraCS;
|
||||
uint8_t LoraReset;
|
||||
uint8_t LoraIRQ;
|
||||
|
||||
bool needCheckPowerChip;
|
||||
bool powerCheckStatus;
|
||||
};
|
||||
|
||||
class BoardFinder
|
||||
{
|
||||
public:
|
||||
BoardFinder(std::list<std::shared_ptr<BoardConfig>> boardConfigs);
|
||||
|
||||
std::shared_ptr<BoardConfig> searchBoardConfig();
|
||||
|
||||
std::shared_ptr<BoardConfig> getBoardConfig(String name);
|
||||
|
||||
private:
|
||||
std::list<std::shared_ptr<BoardConfig>> _boardConfigs;
|
||||
|
||||
bool checkOledConfig(std::shared_ptr<BoardConfig> boardConfig);
|
||||
bool checkModemConfig(std::shared_ptr<BoardConfig> boardConfig);
|
||||
bool checkPowerConfig(std::shared_ptr<BoardConfig> boardConfig);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,65 @@
|
|||
#include <SPIFFS.h>
|
||||
#include <logger.h>
|
||||
#include "configuration.h"
|
||||
|
||||
ConfigurationManagement::ConfigurationManagement(String FilePath)
|
||||
: mFilePath(FilePath)
|
||||
{
|
||||
if(!SPIFFS.begin(true))
|
||||
{
|
||||
logPrintlnE("Mounting SPIFFS was not possible. Trying to format SPIFFS...");
|
||||
SPIFFS.format();
|
||||
if(!SPIFFS.begin())
|
||||
{
|
||||
logPrintlnE("Formating SPIFFS was not okay!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigurationManagement::~ConfigurationManagement()
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<Configuration> ConfigurationManagement::readConfiguration()
|
||||
{
|
||||
File file = SPIFFS.open(mFilePath);
|
||||
if(!file)
|
||||
{
|
||||
logPrintlnE("Failed to open file for reading...");
|
||||
return 0;
|
||||
}
|
||||
DynamicJsonDocument data(2048);
|
||||
DeserializationError error = deserializeJson(data, file);
|
||||
if(error)
|
||||
{
|
||||
logPrintlnW("Failed to read file, using default configuration.");
|
||||
}
|
||||
//serializeJson(data, Serial);
|
||||
//Serial.println();
|
||||
file.close();
|
||||
|
||||
std::shared_ptr<Configuration> conf = readProjectConfiguration(data);
|
||||
|
||||
// update config in memory to get the new fields:
|
||||
writeConfiguration(conf);
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
void ConfigurationManagement::writeConfiguration(std::shared_ptr<Configuration> conf)
|
||||
{
|
||||
File file = SPIFFS.open(mFilePath, "w");
|
||||
if(!file)
|
||||
{
|
||||
logPrintlnE("Failed to open file for writing...");
|
||||
return;
|
||||
}
|
||||
DynamicJsonDocument data(2048);
|
||||
|
||||
writeProjectConfiguration(conf, data);
|
||||
|
||||
serializeJson(data, file);
|
||||
//serializeJson(data, Serial);
|
||||
//Serial.println();
|
||||
file.close();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef CONFIGURATION_H_
|
||||
#define CONFIGURATION_H_
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
class Configuration;
|
||||
|
||||
class ConfigurationManagement
|
||||
{
|
||||
public:
|
||||
explicit ConfigurationManagement(String FilePath);
|
||||
virtual ~ConfigurationManagement();
|
||||
|
||||
std::shared_ptr<Configuration> readConfiguration();
|
||||
void writeConfiguration(std::shared_ptr<Configuration> conf);
|
||||
|
||||
private:
|
||||
virtual std::shared_ptr<Configuration> readProjectConfiguration(DynamicJsonDocument & data) = 0;
|
||||
virtual void writeProjectConfiguration(std::shared_ptr<Configuration> conf, DynamicJsonDocument & data) = 0;
|
||||
|
||||
const String mFilePath;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,673 @@
|
|||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include <LoRa.h>
|
||||
|
||||
// registers
|
||||
#define REG_FIFO 0x00
|
||||
#define REG_OP_MODE 0x01
|
||||
#define REG_FRF_MSB 0x06
|
||||
#define REG_FRF_MID 0x07
|
||||
#define REG_FRF_LSB 0x08
|
||||
#define REG_PA_CONFIG 0x09
|
||||
#define REG_OCP 0x0b
|
||||
#define REG_LNA 0x0c
|
||||
#define REG_FIFO_ADDR_PTR 0x0d
|
||||
#define REG_FIFO_TX_BASE_ADDR 0x0e
|
||||
#define REG_FIFO_RX_BASE_ADDR 0x0f
|
||||
#define REG_FIFO_RX_CURRENT_ADDR 0x10
|
||||
#define REG_IRQ_FLAGS 0x12
|
||||
#define REG_RX_NB_BYTES 0x13
|
||||
#define REG_PKT_SNR_VALUE 0x19
|
||||
#define REG_PKT_RSSI_VALUE 0x1a
|
||||
#define REG_RSSI_VALUE 0x1b
|
||||
#define REG_MODEM_CONFIG_1 0x1d
|
||||
#define REG_MODEM_CONFIG_2 0x1e
|
||||
#define REG_PREAMBLE_MSB 0x20
|
||||
#define REG_PREAMBLE_LSB 0x21
|
||||
#define REG_PAYLOAD_LENGTH 0x22
|
||||
#define REG_MODEM_CONFIG_3 0x26
|
||||
#define REG_FREQ_ERROR_MSB 0x28
|
||||
#define REG_FREQ_ERROR_MID 0x29
|
||||
#define REG_FREQ_ERROR_LSB 0x2a
|
||||
#define REG_RSSI_WIDEBAND 0x2c
|
||||
#define REG_DETECTION_OPTIMIZE 0x31
|
||||
#define REG_INVERTIQ 0x33
|
||||
#define REG_DETECTION_THRESHOLD 0x37
|
||||
#define REG_SYNC_WORD 0x39
|
||||
#define REG_INVERTIQ2 0x3b
|
||||
#define REG_DIO_MAPPING_1 0x40
|
||||
#define REG_VERSION 0x42
|
||||
#define REG_PA_DAC 0x4d
|
||||
|
||||
// modes
|
||||
#define MODE_LONG_RANGE_MODE 0x80
|
||||
#define MODE_SLEEP 0x00
|
||||
#define MODE_STDBY 0x01
|
||||
#define MODE_TX 0x03
|
||||
#define MODE_RX_CONTINUOUS 0x05
|
||||
#define MODE_RX_SINGLE 0x06
|
||||
|
||||
// PA config
|
||||
#define PA_BOOST 0x80
|
||||
|
||||
// IRQ masks
|
||||
#define IRQ_TX_DONE_MASK 0x08
|
||||
#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20
|
||||
#define IRQ_RX_DONE_MASK 0x40
|
||||
|
||||
#define RF_MID_BAND_THRESHOLD 525E6
|
||||
#define RSSI_OFFSET_HF_PORT 157
|
||||
#define RSSI_OFFSET_LF_PORT 164
|
||||
|
||||
#define MAX_PKT_LENGTH 255
|
||||
|
||||
#if (ESP8266 || ESP32)
|
||||
#define ISR_PREFIX ICACHE_RAM_ATTR
|
||||
#else
|
||||
#define ISR_PREFIX
|
||||
#endif
|
||||
|
||||
LoRaClass::LoRaClass() :
|
||||
_spiSettings(LORA_DEFAULT_SPI_FREQUENCY, MSBFIRST, SPI_MODE0),
|
||||
_spi(&LORA_DEFAULT_SPI),
|
||||
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN),
|
||||
_frequency(0),
|
||||
_packetIndex(0),
|
||||
_implicitHeaderMode(0)
|
||||
{
|
||||
// overide Stream timeout value
|
||||
setTimeout(0);
|
||||
}
|
||||
|
||||
int LoRaClass::begin(long frequency)
|
||||
{
|
||||
#if defined(ARDUINO_SAMD_MKRWAN1300) || defined(ARDUINO_SAMD_MKRWAN1310)
|
||||
pinMode(LORA_IRQ_DUMB, OUTPUT);
|
||||
digitalWrite(LORA_IRQ_DUMB, LOW);
|
||||
|
||||
// Hardware reset
|
||||
pinMode(LORA_BOOT0, OUTPUT);
|
||||
digitalWrite(LORA_BOOT0, LOW);
|
||||
|
||||
pinMode(LORA_RESET, OUTPUT);
|
||||
digitalWrite(LORA_RESET, HIGH);
|
||||
delay(200);
|
||||
digitalWrite(LORA_RESET, LOW);
|
||||
delay(200);
|
||||
digitalWrite(LORA_RESET, HIGH);
|
||||
delay(50);
|
||||
#endif
|
||||
|
||||
// setup pins
|
||||
pinMode(_ss, OUTPUT);
|
||||
// set SS high
|
||||
digitalWrite(_ss, HIGH);
|
||||
|
||||
if (_reset != -1) {
|
||||
pinMode(_reset, OUTPUT);
|
||||
|
||||
// perform reset
|
||||
digitalWrite(_reset, LOW);
|
||||
delay(10);
|
||||
digitalWrite(_reset, HIGH);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
// start SPI
|
||||
_spi->begin();
|
||||
|
||||
// check version
|
||||
uint8_t version = readRegister(REG_VERSION);
|
||||
if (version != 0x12) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// put in sleep mode
|
||||
sleep();
|
||||
|
||||
// set frequency
|
||||
setFrequency(frequency);
|
||||
|
||||
// set base addresses
|
||||
writeRegister(REG_FIFO_TX_BASE_ADDR, 0);
|
||||
writeRegister(REG_FIFO_RX_BASE_ADDR, 0);
|
||||
|
||||
// set LNA boost
|
||||
writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03);
|
||||
|
||||
// set auto AGC
|
||||
writeRegister(REG_MODEM_CONFIG_3, 0x04);
|
||||
|
||||
// set output power to 17 dBm
|
||||
setTxPower(17);
|
||||
|
||||
// put in standby mode
|
||||
idle();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LoRaClass::end()
|
||||
{
|
||||
// put in sleep mode
|
||||
sleep();
|
||||
|
||||
// stop SPI
|
||||
_spi->end();
|
||||
}
|
||||
|
||||
int LoRaClass::beginPacket(int implicitHeader)
|
||||
{
|
||||
if (isTransmitting()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// put in standby mode
|
||||
idle();
|
||||
|
||||
if (implicitHeader) {
|
||||
implicitHeaderMode();
|
||||
} else {
|
||||
explicitHeaderMode();
|
||||
}
|
||||
|
||||
// reset FIFO address and paload length
|
||||
writeRegister(REG_FIFO_ADDR_PTR, 0);
|
||||
writeRegister(REG_PAYLOAD_LENGTH, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LoRaClass::endPacket(bool async)
|
||||
{
|
||||
|
||||
// put in TX mode
|
||||
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);
|
||||
|
||||
if (!async) {
|
||||
// wait for TX done
|
||||
while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) {
|
||||
yield();
|
||||
}
|
||||
// clear IRQ's
|
||||
writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool LoRaClass::isTransmitting()
|
||||
{
|
||||
if ((readRegister(REG_OP_MODE) & MODE_TX) == MODE_TX) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) {
|
||||
// clear IRQ's
|
||||
writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int LoRaClass::parsePacket(int size)
|
||||
{
|
||||
int packetLength = 0;
|
||||
int irqFlags = readRegister(REG_IRQ_FLAGS);
|
||||
|
||||
if (size > 0) {
|
||||
implicitHeaderMode();
|
||||
|
||||
writeRegister(REG_PAYLOAD_LENGTH, size & 0xff);
|
||||
} else {
|
||||
explicitHeaderMode();
|
||||
}
|
||||
|
||||
// clear IRQ's
|
||||
writeRegister(REG_IRQ_FLAGS, irqFlags);
|
||||
|
||||
if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
|
||||
// received a packet
|
||||
_packetIndex = 0;
|
||||
|
||||
// read packet length
|
||||
if (_implicitHeaderMode) {
|
||||
packetLength = readRegister(REG_PAYLOAD_LENGTH);
|
||||
} else {
|
||||
packetLength = readRegister(REG_RX_NB_BYTES);
|
||||
}
|
||||
|
||||
// set FIFO address to current RX address
|
||||
writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));
|
||||
|
||||
// put in standby mode
|
||||
idle();
|
||||
} else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) {
|
||||
// not currently in RX mode
|
||||
|
||||
// reset FIFO address
|
||||
writeRegister(REG_FIFO_ADDR_PTR, 0);
|
||||
|
||||
// put in single RX mode
|
||||
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE);
|
||||
}
|
||||
|
||||
return packetLength;
|
||||
}
|
||||
|
||||
int LoRaClass::packetRssi()
|
||||
{
|
||||
return (readRegister(REG_PKT_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT));
|
||||
}
|
||||
|
||||
float LoRaClass::packetSnr()
|
||||
{
|
||||
return ((int8_t)readRegister(REG_PKT_SNR_VALUE)) * 0.25;
|
||||
}
|
||||
|
||||
long LoRaClass::packetFrequencyError()
|
||||
{
|
||||
int32_t freqError = 0;
|
||||
freqError = static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MSB) & B111);
|
||||
freqError <<= 8L;
|
||||
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MID));
|
||||
freqError <<= 8L;
|
||||
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_LSB));
|
||||
|
||||
if (readRegister(REG_FREQ_ERROR_MSB) & B1000) { // Sign bit is on
|
||||
freqError -= 524288; // B1000'0000'0000'0000'0000
|
||||
}
|
||||
|
||||
const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14)
|
||||
const float fError = ((static_cast<float>(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); // p. 37
|
||||
|
||||
return static_cast<long>(fError);
|
||||
}
|
||||
|
||||
int LoRaClass::rssi()
|
||||
{
|
||||
return (readRegister(REG_RSSI_VALUE) - (_frequency < RF_MID_BAND_THRESHOLD ? RSSI_OFFSET_LF_PORT : RSSI_OFFSET_HF_PORT));
|
||||
}
|
||||
|
||||
size_t LoRaClass::write(uint8_t byte)
|
||||
{
|
||||
return write(&byte, sizeof(byte));
|
||||
}
|
||||
|
||||
size_t LoRaClass::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
int currentLength = readRegister(REG_PAYLOAD_LENGTH);
|
||||
|
||||
// check size
|
||||
if ((currentLength + size) > MAX_PKT_LENGTH) {
|
||||
size = MAX_PKT_LENGTH - currentLength;
|
||||
}
|
||||
|
||||
// write data
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
writeRegister(REG_FIFO, buffer[i]);
|
||||
}
|
||||
|
||||
// update length
|
||||
writeRegister(REG_PAYLOAD_LENGTH, currentLength + size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int LoRaClass::available()
|
||||
{
|
||||
return (readRegister(REG_RX_NB_BYTES) - _packetIndex);
|
||||
}
|
||||
|
||||
int LoRaClass::read()
|
||||
{
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_packetIndex++;
|
||||
|
||||
return readRegister(REG_FIFO);
|
||||
}
|
||||
|
||||
int LoRaClass::peek()
|
||||
{
|
||||
if (!available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// store current FIFO address
|
||||
int currentAddress = readRegister(REG_FIFO_ADDR_PTR);
|
||||
|
||||
// read
|
||||
uint8_t b = readRegister(REG_FIFO);
|
||||
|
||||
// restore FIFO address
|
||||
writeRegister(REG_FIFO_ADDR_PTR, currentAddress);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void LoRaClass::flush()
|
||||
{
|
||||
}
|
||||
|
||||
void LoRaClass::receive(int size)
|
||||
{
|
||||
|
||||
writeRegister(REG_DIO_MAPPING_1, 0x00); // DIO0 => RXDONE
|
||||
|
||||
if (size > 0) {
|
||||
implicitHeaderMode();
|
||||
|
||||
writeRegister(REG_PAYLOAD_LENGTH, size & 0xff);
|
||||
} else {
|
||||
explicitHeaderMode();
|
||||
}
|
||||
|
||||
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS);
|
||||
}
|
||||
|
||||
void LoRaClass::idle()
|
||||
{
|
||||
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY);
|
||||
}
|
||||
|
||||
void LoRaClass::sleep()
|
||||
{
|
||||
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP);
|
||||
}
|
||||
|
||||
void LoRaClass::setTxPower(int level, int outputPin)
|
||||
{
|
||||
if (PA_OUTPUT_RFO_PIN == outputPin) {
|
||||
// RFO
|
||||
if (level < 0) {
|
||||
level = 0;
|
||||
} else if (level > 14) {
|
||||
level = 14;
|
||||
}
|
||||
|
||||
writeRegister(REG_PA_CONFIG, 0x70 | level);
|
||||
} else {
|
||||
// PA BOOST
|
||||
if (level > 17) {
|
||||
if (level > 20) {
|
||||
level = 20;
|
||||
}
|
||||
|
||||
// subtract 3 from level, so 18 - 20 maps to 15 - 17
|
||||
level -= 3;
|
||||
|
||||
// High Power +20 dBm Operation (Semtech SX1276/77/78/79 5.4.3.)
|
||||
writeRegister(REG_PA_DAC, 0x87);
|
||||
setOCP(140);
|
||||
} else {
|
||||
if (level < 2) {
|
||||
level = 2;
|
||||
}
|
||||
//Default value PA_HF/LF or +17dBm
|
||||
writeRegister(REG_PA_DAC, 0x84);
|
||||
setOCP(100);
|
||||
}
|
||||
|
||||
writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2));
|
||||
}
|
||||
}
|
||||
|
||||
void LoRaClass::setFrequency(long frequency)
|
||||
{
|
||||
_frequency = frequency;
|
||||
|
||||
uint64_t frf = ((uint64_t)frequency << 19) / 32000000;
|
||||
|
||||
writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16));
|
||||
writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8));
|
||||
writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0));
|
||||
}
|
||||
|
||||
int LoRaClass::getSpreadingFactor()
|
||||
{
|
||||
return readRegister(REG_MODEM_CONFIG_2) >> 4;
|
||||
}
|
||||
|
||||
void LoRaClass::setSpreadingFactor(int sf)
|
||||
{
|
||||
if (sf < 6) {
|
||||
sf = 6;
|
||||
} else if (sf > 12) {
|
||||
sf = 12;
|
||||
}
|
||||
|
||||
if (sf == 6) {
|
||||
writeRegister(REG_DETECTION_OPTIMIZE, 0xc5);
|
||||
writeRegister(REG_DETECTION_THRESHOLD, 0x0c);
|
||||
} else {
|
||||
writeRegister(REG_DETECTION_OPTIMIZE, 0xc3);
|
||||
writeRegister(REG_DETECTION_THRESHOLD, 0x0a);
|
||||
}
|
||||
|
||||
writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0));
|
||||
setLdoFlag();
|
||||
}
|
||||
|
||||
long LoRaClass::getSignalBandwidth()
|
||||
{
|
||||
byte bw = (readRegister(REG_MODEM_CONFIG_1) >> 4);
|
||||
|
||||
switch (bw) {
|
||||
case 0: return 7.8E3;
|
||||
case 1: return 10.4E3;
|
||||
case 2: return 15.6E3;
|
||||
case 3: return 20.8E3;
|
||||
case 4: return 31.25E3;
|
||||
case 5: return 41.7E3;
|
||||
case 6: return 62.5E3;
|
||||
case 7: return 125E3;
|
||||
case 8: return 250E3;
|
||||
case 9: return 500E3;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void LoRaClass::setSignalBandwidth(long sbw)
|
||||
{
|
||||
int bw;
|
||||
|
||||
if (sbw <= 7.8E3) {
|
||||
bw = 0;
|
||||
} else if (sbw <= 10.4E3) {
|
||||
bw = 1;
|
||||
} else if (sbw <= 15.6E3) {
|
||||
bw = 2;
|
||||
} else if (sbw <= 20.8E3) {
|
||||
bw = 3;
|
||||
} else if (sbw <= 31.25E3) {
|
||||
bw = 4;
|
||||
} else if (sbw <= 41.7E3) {
|
||||
bw = 5;
|
||||
} else if (sbw <= 62.5E3) {
|
||||
bw = 6;
|
||||
} else if (sbw <= 125E3) {
|
||||
bw = 7;
|
||||
} else if (sbw <= 250E3) {
|
||||
bw = 8;
|
||||
} else /*if (sbw <= 250E3)*/ {
|
||||
bw = 9;
|
||||
}
|
||||
|
||||
writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4));
|
||||
setLdoFlag();
|
||||
}
|
||||
|
||||
void LoRaClass::setLdoFlag()
|
||||
{
|
||||
// Section 4.1.1.5
|
||||
long symbolDuration = 1000 / ( getSignalBandwidth() / (1L << getSpreadingFactor()) ) ;
|
||||
|
||||
// Section 4.1.1.6
|
||||
boolean ldoOn = symbolDuration > 16;
|
||||
|
||||
uint8_t config3 = readRegister(REG_MODEM_CONFIG_3);
|
||||
bitWrite(config3, 3, ldoOn);
|
||||
writeRegister(REG_MODEM_CONFIG_3, config3);
|
||||
}
|
||||
|
||||
void LoRaClass::setCodingRate4(int denominator)
|
||||
{
|
||||
if (denominator < 5) {
|
||||
denominator = 5;
|
||||
} else if (denominator > 8) {
|
||||
denominator = 8;
|
||||
}
|
||||
|
||||
int cr = denominator - 4;
|
||||
|
||||
writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1));
|
||||
}
|
||||
|
||||
void LoRaClass::setPreambleLength(long length)
|
||||
{
|
||||
writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8));
|
||||
writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0));
|
||||
}
|
||||
|
||||
void LoRaClass::setSyncWord(int sw)
|
||||
{
|
||||
writeRegister(REG_SYNC_WORD, sw);
|
||||
}
|
||||
|
||||
void LoRaClass::enableCrc()
|
||||
{
|
||||
writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04);
|
||||
}
|
||||
|
||||
void LoRaClass::disableCrc()
|
||||
{
|
||||
writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb);
|
||||
}
|
||||
|
||||
void LoRaClass::enableInvertIQ()
|
||||
{
|
||||
writeRegister(REG_INVERTIQ, 0x66);
|
||||
writeRegister(REG_INVERTIQ2, 0x19);
|
||||
}
|
||||
|
||||
void LoRaClass::disableInvertIQ()
|
||||
{
|
||||
writeRegister(REG_INVERTIQ, 0x27);
|
||||
writeRegister(REG_INVERTIQ2, 0x1d);
|
||||
}
|
||||
|
||||
void LoRaClass::setOCP(uint8_t mA)
|
||||
{
|
||||
uint8_t ocpTrim = 27;
|
||||
|
||||
if (mA <= 120) {
|
||||
ocpTrim = (mA - 45) / 5;
|
||||
} else if (mA <=240) {
|
||||
ocpTrim = (mA + 30) / 10;
|
||||
}
|
||||
|
||||
writeRegister(REG_OCP, 0x20 | (0x1F & ocpTrim));
|
||||
}
|
||||
|
||||
void LoRaClass::setGain(uint8_t gain)
|
||||
{
|
||||
// check allowed range
|
||||
if (gain > 6) {
|
||||
gain = 6;
|
||||
}
|
||||
|
||||
// set to standby
|
||||
idle();
|
||||
|
||||
// set gain
|
||||
if (gain == 0) {
|
||||
// if gain = 0, enable AGC
|
||||
writeRegister(REG_MODEM_CONFIG_3, 0x04);
|
||||
} else {
|
||||
// disable AGC
|
||||
writeRegister(REG_MODEM_CONFIG_3, 0x00);
|
||||
|
||||
// clear Gain and set LNA boost
|
||||
writeRegister(REG_LNA, 0x03);
|
||||
|
||||
// set gain
|
||||
writeRegister(REG_LNA, readRegister(REG_LNA) | (gain << 5));
|
||||
}
|
||||
}
|
||||
|
||||
byte LoRaClass::random()
|
||||
{
|
||||
return readRegister(REG_RSSI_WIDEBAND);
|
||||
}
|
||||
|
||||
void LoRaClass::setPins(int ss, int reset, int dio0)
|
||||
{
|
||||
_ss = ss;
|
||||
_reset = reset;
|
||||
_dio0 = dio0;
|
||||
}
|
||||
|
||||
void LoRaClass::setSPI(SPIClass& spi)
|
||||
{
|
||||
_spi = &spi;
|
||||
}
|
||||
|
||||
void LoRaClass::setSPIFrequency(uint32_t frequency)
|
||||
{
|
||||
_spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0);
|
||||
}
|
||||
|
||||
void LoRaClass::dumpRegisters(Stream& out)
|
||||
{
|
||||
for (int i = 0; i < 128; i++) {
|
||||
out.print("0x");
|
||||
out.print(i, HEX);
|
||||
out.print(": 0x");
|
||||
out.println(readRegister(i), HEX);
|
||||
}
|
||||
}
|
||||
|
||||
void LoRaClass::explicitHeaderMode()
|
||||
{
|
||||
_implicitHeaderMode = 0;
|
||||
|
||||
writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe);
|
||||
}
|
||||
|
||||
void LoRaClass::implicitHeaderMode()
|
||||
{
|
||||
_implicitHeaderMode = 1;
|
||||
|
||||
writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01);
|
||||
}
|
||||
|
||||
uint8_t LoRaClass::readRegister(uint8_t address)
|
||||
{
|
||||
return singleTransfer(address & 0x7f, 0x00);
|
||||
}
|
||||
|
||||
void LoRaClass::writeRegister(uint8_t address, uint8_t value)
|
||||
{
|
||||
singleTransfer(address | 0x80, value);
|
||||
}
|
||||
|
||||
uint8_t LoRaClass::singleTransfer(uint8_t address, uint8_t value)
|
||||
{
|
||||
uint8_t response;
|
||||
|
||||
digitalWrite(_ss, LOW);
|
||||
|
||||
_spi->beginTransaction(_spiSettings);
|
||||
_spi->transfer(address);
|
||||
response = _spi->transfer(value);
|
||||
_spi->endTransaction();
|
||||
|
||||
digitalWrite(_ss, HIGH);
|
||||
|
||||
return response;
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) Sandeep Mistry. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef LORA_H
|
||||
#define LORA_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#if defined(ARDUINO_SAMD_MKRWAN1300)
|
||||
#define LORA_DEFAULT_SPI SPI1
|
||||
#define LORA_DEFAULT_SPI_FREQUENCY 200000
|
||||
#define LORA_DEFAULT_SS_PIN LORA_IRQ_DUMB
|
||||
#define LORA_DEFAULT_RESET_PIN -1
|
||||
#define LORA_DEFAULT_DIO0_PIN -1
|
||||
#elif defined(ARDUINO_SAMD_MKRWAN1310)
|
||||
#define LORA_DEFAULT_SPI SPI1
|
||||
#define LORA_DEFAULT_SPI_FREQUENCY 200000
|
||||
#define LORA_DEFAULT_SS_PIN LORA_IRQ_DUMB
|
||||
#define LORA_DEFAULT_RESET_PIN -1
|
||||
#define LORA_DEFAULT_DIO0_PIN LORA_IRQ
|
||||
#else
|
||||
#define LORA_DEFAULT_SPI SPI
|
||||
#define LORA_DEFAULT_SPI_FREQUENCY 8E6
|
||||
#define LORA_DEFAULT_SS_PIN 10
|
||||
#define LORA_DEFAULT_RESET_PIN 9
|
||||
#define LORA_DEFAULT_DIO0_PIN 2
|
||||
#endif
|
||||
|
||||
#define PA_OUTPUT_RFO_PIN 0
|
||||
#define PA_OUTPUT_PA_BOOST_PIN 1
|
||||
|
||||
class LoRaClass : public Stream {
|
||||
public:
|
||||
LoRaClass();
|
||||
|
||||
int begin(long frequency);
|
||||
void end();
|
||||
|
||||
int beginPacket(int implicitHeader = false);
|
||||
int endPacket(bool async = false);
|
||||
|
||||
int parsePacket(int size = 0);
|
||||
int packetRssi();
|
||||
float packetSnr();
|
||||
long packetFrequencyError();
|
||||
|
||||
int rssi();
|
||||
|
||||
// from Print
|
||||
virtual size_t write(uint8_t byte);
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
// from Stream
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual int peek();
|
||||
virtual void flush();
|
||||
|
||||
void receive(int size = 0);
|
||||
|
||||
void idle();
|
||||
void sleep();
|
||||
|
||||
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
|
||||
void setFrequency(long frequency);
|
||||
void setSpreadingFactor(int sf);
|
||||
void setSignalBandwidth(long sbw);
|
||||
void setCodingRate4(int denominator);
|
||||
void setPreambleLength(long length);
|
||||
void setSyncWord(int sw);
|
||||
void enableCrc();
|
||||
void disableCrc();
|
||||
void enableInvertIQ();
|
||||
void disableInvertIQ();
|
||||
|
||||
void setOCP(uint8_t mA); // Over Current Protection control
|
||||
|
||||
void setGain(uint8_t gain); // Set LNA gain
|
||||
|
||||
// deprecated
|
||||
void crc() { enableCrc(); }
|
||||
void noCrc() { disableCrc(); }
|
||||
|
||||
byte random();
|
||||
|
||||
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN);
|
||||
void setSPI(SPIClass& spi);
|
||||
void setSPIFrequency(uint32_t frequency);
|
||||
|
||||
void dumpRegisters(Stream& out);
|
||||
|
||||
private:
|
||||
void explicitHeaderMode();
|
||||
void implicitHeaderMode();
|
||||
|
||||
bool isTransmitting();
|
||||
|
||||
int getSpreadingFactor();
|
||||
long getSignalBandwidth();
|
||||
|
||||
void setLdoFlag();
|
||||
|
||||
uint8_t readRegister(uint8_t address);
|
||||
void writeRegister(uint8_t address, uint8_t value);
|
||||
uint8_t singleTransfer(uint8_t address, uint8_t value);
|
||||
|
||||
private:
|
||||
SPISettings _spiSettings;
|
||||
SPIClass* _spi;
|
||||
int _ss;
|
||||
int _reset;
|
||||
int _dio0;
|
||||
long _frequency;
|
||||
int _packetIndex;
|
||||
int _implicitHeaderMode;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,87 @@
|
|||
#include <BoardFinder.h>
|
||||
#include "LoRa_APRS.h"
|
||||
|
||||
LoRa_APRS::LoRa_APRS(std::shared_ptr<BoardConfig> boardConfig)
|
||||
: _LastReceivedMsg(0), _RxFrequency(LORA_RX_FREQUENCY), _TxFrequency(LORA_TX_FREQUENCY)
|
||||
{
|
||||
SPI.begin(boardConfig->LoraSck, boardConfig->LoraMiso, boardConfig->LoraMosi, boardConfig->LoraCS);
|
||||
setPins(boardConfig->LoraCS, boardConfig->LoraReset, boardConfig->LoraIRQ);
|
||||
}
|
||||
|
||||
bool LoRa_APRS::checkMessage()
|
||||
{
|
||||
if(!parsePacket())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// read header:
|
||||
char dummy[4];
|
||||
readBytes(dummy, 3);
|
||||
if(dummy[0] != '<')
|
||||
{
|
||||
// is no APRS message, ignore message
|
||||
while(available())
|
||||
{
|
||||
read();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// read APRS data:
|
||||
String str;
|
||||
while(available())
|
||||
{
|
||||
str += (char)read();
|
||||
}
|
||||
_LastReceivedMsg = std::shared_ptr<APRSMessage>(new APRSMessage());
|
||||
_LastReceivedMsg->decode(str);
|
||||
emit(_LastReceivedMsg, packetRssi(), packetSnr());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<APRSMessage> LoRa_APRS::getMessage()
|
||||
{
|
||||
return _LastReceivedMsg;
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
void LoRa_APRS::sendMessage(const std::shared_ptr<APRSMessage> msg)
|
||||
{
|
||||
setFrequency(_TxFrequency);
|
||||
String data = msg->encode();
|
||||
beginPacket();
|
||||
// Header:
|
||||
write('<');
|
||||
write(0xFF);
|
||||
write(0x01);
|
||||
// APRS Data:
|
||||
write((const uint8_t *)data.c_str(), data.length());
|
||||
endPacket();
|
||||
setFrequency(_RxFrequency);
|
||||
}
|
||||
|
||||
void LoRa_APRS::setRxFrequency(long frequency)
|
||||
{
|
||||
_RxFrequency = frequency;
|
||||
setFrequency(_RxFrequency);
|
||||
}
|
||||
|
||||
long LoRa_APRS::getRxFrequency() const
|
||||
{
|
||||
return _RxFrequency;
|
||||
}
|
||||
|
||||
void LoRa_APRS::setTxFrequency(long frequency)
|
||||
{
|
||||
_TxFrequency = frequency;
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
long LoRa_APRS::getTxFrequency() const
|
||||
{
|
||||
return _TxFrequency;
|
||||
}
|
||||
|
||||
void LoRa_APRS::action(const std::shared_ptr<APRSMessage> elem)
|
||||
{
|
||||
sendMessage(elem);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef LORA_H_
|
||||
#define LORA_H_
|
||||
|
||||
#include <memory>
|
||||
#include <Arduino.h>
|
||||
#include <LoRa.h>
|
||||
#include <APRS-Decoder.h>
|
||||
#include <SignalSlot.h>
|
||||
|
||||
#define LORA_RX_FREQUENCY (433775000)
|
||||
#define LORA_TX_FREQUENCY (433900000)
|
||||
#define LORA_SPREADING_FACTOR (12)
|
||||
#define LORA_SIGNAL_BANDWIDTH (125E3)
|
||||
#define LORA_CODING_RATE4 (5)
|
||||
|
||||
class LoRa_APRS : public LoRaClass, public Slot1<const std::shared_ptr<APRSMessage>>, public Signal3<std::shared_ptr<APRSMessage>, int, float>
|
||||
{
|
||||
public:
|
||||
explicit LoRa_APRS(std::shared_ptr<BoardConfig> boardConfig);
|
||||
|
||||
bool checkMessage();
|
||||
std::shared_ptr<APRSMessage> getMessage();
|
||||
|
||||
void sendMessage(const std::shared_ptr<APRSMessage> msg);
|
||||
|
||||
void setRxFrequency(long frequency);
|
||||
long getRxFrequency() const;
|
||||
|
||||
void setTxFrequency(long frequency);
|
||||
long getTxFrequency() const;
|
||||
|
||||
void action(const std::shared_ptr<APRSMessage> elem) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<APRSMessage> _LastReceivedMsg;
|
||||
long _RxFrequency;
|
||||
long _TxFrequency;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,202 @@
|
|||
/**
|
||||
* The MIT License (MIT)
|
||||
* Copyright (c) 2015 by Fabrice Weinberg
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "NTPClient.h"
|
||||
|
||||
NTPClient::NTPClient() {
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(long timeOffset) {
|
||||
this->_timeOffset = timeOffset;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(const char* poolServerName) {
|
||||
this->_poolServerName = poolServerName;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(IPAddress poolServerIP) {
|
||||
this->_poolServerIP = poolServerIP;
|
||||
this->_poolServerName = NULL;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(const char* poolServerName, long timeOffset) {
|
||||
this->_timeOffset = timeOffset;
|
||||
this->_poolServerName = poolServerName;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(IPAddress poolServerIP, long timeOffset){
|
||||
this->_timeOffset = timeOffset;
|
||||
this->_poolServerIP = poolServerIP;
|
||||
this->_poolServerName = NULL;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(const char* poolServerName, long timeOffset, unsigned long updateInterval) {
|
||||
this->_timeOffset = timeOffset;
|
||||
this->_poolServerName = poolServerName;
|
||||
this->_updateInterval = updateInterval;
|
||||
}
|
||||
|
||||
NTPClient::NTPClient(IPAddress poolServerIP, long timeOffset, unsigned long updateInterval) {
|
||||
this->_timeOffset = timeOffset;
|
||||
this->_poolServerIP = poolServerIP;
|
||||
this->_poolServerName = NULL;
|
||||
this->_updateInterval = updateInterval;
|
||||
}
|
||||
|
||||
void NTPClient::begin() {
|
||||
this->begin(NTP_DEFAULT_LOCAL_PORT);
|
||||
}
|
||||
|
||||
void NTPClient::begin(unsigned int port) {
|
||||
this->_port = port;
|
||||
|
||||
this->_udp.begin(this->_port);
|
||||
|
||||
this->_udpSetup = true;
|
||||
}
|
||||
|
||||
bool NTPClient::forceUpdate() {
|
||||
#ifdef DEBUG_NTPClient
|
||||
Serial.println("Update from NTP Server");
|
||||
#endif
|
||||
|
||||
// flush any existing packets
|
||||
while(this->_udp.parsePacket() != 0)
|
||||
this->_udp.flush();
|
||||
|
||||
this->sendNTPPacket();
|
||||
|
||||
// Wait till data is there or timeout...
|
||||
byte timeout = 0;
|
||||
int cb = 0;
|
||||
do {
|
||||
delay ( 10 );
|
||||
cb = this->_udp.parsePacket();
|
||||
if (timeout > 100) return false; // timeout after 1000 ms
|
||||
timeout++;
|
||||
} while (cb == 0);
|
||||
|
||||
this->_lastUpdate = millis() - (10 * (timeout + 1)); // Account for delay in reading the time
|
||||
|
||||
this->_udp.read(this->_packetBuffer, NTP_PACKET_SIZE);
|
||||
|
||||
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
|
||||
unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]);
|
||||
// combine the four bytes (two words) into a long integer
|
||||
// this is NTP time (seconds since Jan 1 1900):
|
||||
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
||||
|
||||
this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
|
||||
|
||||
return true; // return true after successful update
|
||||
}
|
||||
|
||||
bool NTPClient::update() {
|
||||
if ((millis() - this->_lastUpdate >= this->_updateInterval) // Update after _updateInterval
|
||||
|| this->_lastUpdate == 0) { // Update if there was no update yet.
|
||||
if (!this->_udpSetup || this->_port != NTP_DEFAULT_LOCAL_PORT) this->begin(this->_port); // setup the UDP client if needed
|
||||
return this->forceUpdate();
|
||||
}
|
||||
return false; // return false if update does not occur
|
||||
}
|
||||
|
||||
unsigned long NTPClient::getEpochTime() const {
|
||||
return this->_timeOffset + // User offset
|
||||
this->_currentEpoc + // Epoc returned by the NTP server
|
||||
((millis() - this->_lastUpdate) / 1000); // Time since last update
|
||||
}
|
||||
|
||||
int NTPClient::getDay() const {
|
||||
return (((this->getEpochTime() / 86400L) + 4 ) % 7); //0 is Sunday
|
||||
}
|
||||
int NTPClient::getHours() const {
|
||||
return ((this->getEpochTime() % 86400L) / 3600);
|
||||
}
|
||||
int NTPClient::getMinutes() const {
|
||||
return ((this->getEpochTime() % 3600) / 60);
|
||||
}
|
||||
int NTPClient::getSeconds() const {
|
||||
return (this->getEpochTime() % 60);
|
||||
}
|
||||
|
||||
String NTPClient::getFormattedTime() const {
|
||||
unsigned long rawTime = this->getEpochTime();
|
||||
unsigned long hours = (rawTime % 86400L) / 3600;
|
||||
String hoursStr = hours < 10 ? "0" + String(hours) : String(hours);
|
||||
|
||||
unsigned long minutes = (rawTime % 3600) / 60;
|
||||
String minuteStr = minutes < 10 ? "0" + String(minutes) : String(minutes);
|
||||
|
||||
unsigned long seconds = rawTime % 60;
|
||||
String secondStr = seconds < 10 ? "0" + String(seconds) : String(seconds);
|
||||
|
||||
return hoursStr + ":" + minuteStr + ":" + secondStr;
|
||||
}
|
||||
|
||||
void NTPClient::end() {
|
||||
this->_udp.stop();
|
||||
|
||||
this->_udpSetup = false;
|
||||
}
|
||||
|
||||
void NTPClient::setTimeOffset(int timeOffset) {
|
||||
this->_timeOffset = timeOffset;
|
||||
}
|
||||
|
||||
void NTPClient::setUpdateInterval(unsigned long updateInterval) {
|
||||
this->_updateInterval = updateInterval;
|
||||
}
|
||||
|
||||
void NTPClient::setPoolServerName(const char* poolServerName) {
|
||||
this->_poolServerName = poolServerName;
|
||||
}
|
||||
|
||||
void NTPClient::sendNTPPacket() {
|
||||
// set all bytes in the buffer to 0
|
||||
memset(this->_packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
// Initialize values needed to form NTP request
|
||||
// (see URL above for details on the packets)
|
||||
|
||||
this->_packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
this->_packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
this->_packetBuffer[2] = 6; // Polling Interval
|
||||
this->_packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||
this->_packetBuffer[12] = 49;
|
||||
this->_packetBuffer[13] = 0x4E;
|
||||
this->_packetBuffer[14] = 49;
|
||||
this->_packetBuffer[15] = 52;
|
||||
|
||||
// all NTP fields have been given values, now
|
||||
// you can send a packet requesting a timestamp:
|
||||
if (this->_poolServerName) {
|
||||
this->_udp.beginPacket(this->_poolServerName, 123);
|
||||
} else {
|
||||
this->_udp.beginPacket(this->_poolServerIP, 123);
|
||||
}
|
||||
this->_udp.write(this->_packetBuffer, NTP_PACKET_SIZE);
|
||||
this->_udp.endPacket();
|
||||
}
|
||||
|
||||
void NTPClient::setRandomPort(unsigned int minValue, unsigned int maxValue) {
|
||||
randomSeed(analogRead(0));
|
||||
this->_port = random(minValue, maxValue);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
#define SEVENZYYEARS 2208988800UL
|
||||
#define NTP_PACKET_SIZE 48
|
||||
#define NTP_DEFAULT_LOCAL_PORT 1337
|
||||
|
||||
class NTPClient {
|
||||
private:
|
||||
WiFiUDP _udp;
|
||||
bool _udpSetup = false;
|
||||
|
||||
const char* _poolServerName = "pool.ntp.org"; // Default time server
|
||||
IPAddress _poolServerIP;
|
||||
unsigned int _port = NTP_DEFAULT_LOCAL_PORT;
|
||||
long _timeOffset = 0;
|
||||
|
||||
unsigned long _updateInterval = 60000; // In ms
|
||||
|
||||
unsigned long _currentEpoc = 0; // In s
|
||||
unsigned long _lastUpdate = 0; // In ms
|
||||
|
||||
byte _packetBuffer[NTP_PACKET_SIZE];
|
||||
|
||||
void sendNTPPacket();
|
||||
|
||||
public:
|
||||
NTPClient();
|
||||
NTPClient(long timeOffset);
|
||||
NTPClient(const char* poolServerName);
|
||||
NTPClient(const char* poolServerName, long timeOffset);
|
||||
NTPClient(const char* poolServerName, long timeOffset, unsigned long updateInterval);
|
||||
NTPClient(IPAddress poolServerIP);
|
||||
NTPClient(IPAddress poolServerIP, long timeOffset);
|
||||
NTPClient(IPAddress poolServerIP, long timeOffset, unsigned long updateInterval);
|
||||
|
||||
/**
|
||||
* Set time server name
|
||||
*
|
||||
* @param poolServerName
|
||||
*/
|
||||
void setPoolServerName(const char* poolServerName);
|
||||
|
||||
/**
|
||||
* Set random local port
|
||||
*/
|
||||
void setRandomPort(unsigned int minValue = 49152, unsigned int maxValue = 65535);
|
||||
|
||||
/**
|
||||
* Starts the underlying UDP client with the default local port
|
||||
*/
|
||||
void begin();
|
||||
|
||||
/**
|
||||
* Starts the underlying UDP client with the specified local port
|
||||
*/
|
||||
void begin(unsigned int port);
|
||||
|
||||
/**
|
||||
* This should be called in the main loop of your application. By default an update from the NTP Server is only
|
||||
* made every 60 seconds. This can be configured in the NTPClient constructor.
|
||||
*
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool update();
|
||||
|
||||
/**
|
||||
* This will force the update from the NTP Server.
|
||||
*
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool forceUpdate();
|
||||
|
||||
int getDay() const;
|
||||
int getHours() const;
|
||||
int getMinutes() const;
|
||||
int getSeconds() const;
|
||||
|
||||
/**
|
||||
* Changes the time offset. Useful for changing timezones dynamically
|
||||
*/
|
||||
void setTimeOffset(int timeOffset);
|
||||
|
||||
/**
|
||||
* Set the update interval to another frequency. E.g. useful when the
|
||||
* timeOffset should not be set in the constructor
|
||||
*/
|
||||
void setUpdateInterval(unsigned long updateInterval);
|
||||
|
||||
/**
|
||||
* @return time formatted like `hh:mm:ss`
|
||||
*/
|
||||
String getFormattedTime() const;
|
||||
|
||||
/**
|
||||
* @return time in seconds since Jan. 1, 1970
|
||||
*/
|
||||
unsigned long getEpochTime() const;
|
||||
|
||||
/**
|
||||
* Stops the underlying UDP client
|
||||
*/
|
||||
void end();
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
#include "power_management.h"
|
||||
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
PowerManagement::PowerManagement()
|
||||
{
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
bool PowerManagement::begin(TwoWire & port)
|
||||
{
|
||||
bool result = axp.begin(port, AXP192_SLAVE_ADDRESS);
|
||||
if(!result)
|
||||
{
|
||||
axp.setDCDC1Voltage(3300);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
void PowerManagement::activateLoRa()
|
||||
{
|
||||
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON);
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
void PowerManagement::deactivateLoRa()
|
||||
{
|
||||
axp.setPowerOutPut(AXP192_LDO2, AXP202_OFF);
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
void PowerManagement::activateGPS()
|
||||
{
|
||||
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON);
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
void PowerManagement::deactivateGPS()
|
||||
{
|
||||
axp.setPowerOutPut(AXP192_LDO3, AXP202_OFF);
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
void PowerManagement::activateOLED()
|
||||
{
|
||||
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
void PowerManagement::decativateOLED()
|
||||
{
|
||||
axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF);
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef POWER_MANAGEMENT_H_
|
||||
#define POWER_MANAGEMENT_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <axp20x.h>
|
||||
|
||||
class PowerManagement
|
||||
{
|
||||
public:
|
||||
PowerManagement();
|
||||
bool begin(TwoWire & port);
|
||||
|
||||
void activateLoRa();
|
||||
void deactivateLoRa();
|
||||
|
||||
void activateGPS();
|
||||
void deactivateGPS();
|
||||
|
||||
void activateOLED();
|
||||
void decativateOLED();
|
||||
|
||||
private:
|
||||
AXP20X_Class axp;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,116 @@
|
|||
#ifndef SIGNAL_SLOT_H_
|
||||
#define SIGNAL_SLOT_H_
|
||||
|
||||
#include <list>
|
||||
|
||||
class Slot0
|
||||
{
|
||||
public:
|
||||
virtual void action() = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Slot1
|
||||
{
|
||||
public:
|
||||
virtual void action(T elem1) = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename H>
|
||||
class Slot2
|
||||
{
|
||||
public:
|
||||
virtual void action(T elem1, H elem2) = 0;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename K>
|
||||
class Slot3
|
||||
{
|
||||
public:
|
||||
virtual void action(T elem1, H elem2, K elem3) = 0;
|
||||
};
|
||||
|
||||
class Signal0
|
||||
{
|
||||
public:
|
||||
void emit()
|
||||
{
|
||||
for(Slot0 * slot: _slots)
|
||||
{
|
||||
slot->action();
|
||||
}
|
||||
}
|
||||
|
||||
void connectSlot(Slot0 * slot)
|
||||
{
|
||||
_slots.push_back(slot);
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<Slot0 *> _slots;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Signal1
|
||||
{
|
||||
public:
|
||||
void emit(T elem1)
|
||||
{
|
||||
for(Slot1<T> * slot: _slots)
|
||||
{
|
||||
slot->action(elem1);
|
||||
}
|
||||
}
|
||||
|
||||
void connectSlot(Slot1<T> * slot)
|
||||
{
|
||||
_slots.push_back(slot);
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<Slot1<T> *> _slots;
|
||||
};
|
||||
|
||||
template <typename T, typename H>
|
||||
class Signal2
|
||||
{
|
||||
public:
|
||||
void emit(T elem1, H elem2)
|
||||
{
|
||||
for(Slot2<T, H> * slot: _slots)
|
||||
{
|
||||
slot->action(elem1, elem2);
|
||||
}
|
||||
}
|
||||
|
||||
void connectSlot(Slot2<T, H> * slot)
|
||||
{
|
||||
_slots.push_back(slot);
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<Slot2<T, H> *> _slots;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename K>
|
||||
class Signal3
|
||||
{
|
||||
public:
|
||||
void emit(T elem1, H elem2, K elem3)
|
||||
{
|
||||
for(Slot3<T, H, K> * slot: _slots)
|
||||
{
|
||||
slot->action(elem1, elem2, elem3);
|
||||
}
|
||||
}
|
||||
|
||||
void connectSlot(Slot3<T, H, K> * slot)
|
||||
{
|
||||
_slots.push_back(slot);
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<Slot3<T, H, K> *> _slots;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
time.c - low level time and date functions
|
||||
Copyright (c) Michael Margolis 2009-2014
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
1.0 6 Jan 2010 - initial release
|
||||
1.1 12 Feb 2010 - fixed leap year calculation error
|
||||
1.2 1 Nov 2010 - fixed setTime bug (thanks to Korman for this)
|
||||
1.3 24 Mar 2012 - many edits by Paul Stoffregen: fixed timeStatus() to update
|
||||
status, updated examples for Arduino 1.0, fixed ARM
|
||||
compatibility issues, added TimeArduinoDue and TimeTeensy3
|
||||
examples, add error checking and messages to RTC examples,
|
||||
add examples to DS1307RTC library.
|
||||
1.4 5 Sep 2014 - compatibility with Arduino 1.5.7
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "TimeLib.h"
|
||||
|
||||
static tmElements_t tm; // a cache of time elements
|
||||
static time_t cacheTime; // the time the cache was updated
|
||||
static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds
|
||||
|
||||
void refreshCache(time_t t) {
|
||||
if (t != cacheTime) {
|
||||
breakTime(t, tm);
|
||||
cacheTime = t;
|
||||
}
|
||||
}
|
||||
|
||||
int hour() { // the hour now
|
||||
return hour(now());
|
||||
}
|
||||
|
||||
int hour(time_t t) { // the hour for the given time
|
||||
refreshCache(t);
|
||||
return tm.Hour;
|
||||
}
|
||||
|
||||
int hourFormat12() { // the hour now in 12 hour format
|
||||
return hourFormat12(now());
|
||||
}
|
||||
|
||||
int hourFormat12(time_t t) { // the hour for the given time in 12 hour format
|
||||
refreshCache(t);
|
||||
if( tm.Hour == 0 )
|
||||
return 12; // 12 midnight
|
||||
else if( tm.Hour > 12)
|
||||
return tm.Hour - 12 ;
|
||||
else
|
||||
return tm.Hour ;
|
||||
}
|
||||
|
||||
uint8_t isAM() { // returns true if time now is AM
|
||||
return !isPM(now());
|
||||
}
|
||||
|
||||
uint8_t isAM(time_t t) { // returns true if given time is AM
|
||||
return !isPM(t);
|
||||
}
|
||||
|
||||
uint8_t isPM() { // returns true if PM
|
||||
return isPM(now());
|
||||
}
|
||||
|
||||
uint8_t isPM(time_t t) { // returns true if PM
|
||||
return (hour(t) >= 12);
|
||||
}
|
||||
|
||||
int minute() {
|
||||
return minute(now());
|
||||
}
|
||||
|
||||
int minute(time_t t) { // the minute for the given time
|
||||
refreshCache(t);
|
||||
return tm.Minute;
|
||||
}
|
||||
|
||||
int second() {
|
||||
return second(now());
|
||||
}
|
||||
|
||||
int second(time_t t) { // the second for the given time
|
||||
refreshCache(t);
|
||||
return tm.Second;
|
||||
}
|
||||
|
||||
int day(){
|
||||
return(day(now()));
|
||||
}
|
||||
|
||||
int day(time_t t) { // the day for the given time (0-6)
|
||||
refreshCache(t);
|
||||
return tm.Day;
|
||||
}
|
||||
|
||||
int weekday() { // Sunday is day 1
|
||||
return weekday(now());
|
||||
}
|
||||
|
||||
int weekday(time_t t) {
|
||||
refreshCache(t);
|
||||
return tm.Wday;
|
||||
}
|
||||
|
||||
int month(){
|
||||
return month(now());
|
||||
}
|
||||
|
||||
int month(time_t t) { // the month for the given time
|
||||
refreshCache(t);
|
||||
return tm.Month;
|
||||
}
|
||||
|
||||
int year() { // as in Processing, the full four digit year: (2009, 2010 etc)
|
||||
return year(now());
|
||||
}
|
||||
|
||||
int year(time_t t) { // the year for the given time
|
||||
refreshCache(t);
|
||||
return tmYearToCalendar(tm.Year);
|
||||
}
|
||||
|
||||
const String timeString()
|
||||
{
|
||||
return timeString(now());
|
||||
}
|
||||
|
||||
const String timeString(time_t t)
|
||||
{
|
||||
char line[30];
|
||||
sprintf(line, "%02d:%02d:%02d", hour(t), minute(t), second(t));
|
||||
return String(line);
|
||||
}
|
||||
|
||||
/*============================================================================*/
|
||||
/* functions to convert to and from system time */
|
||||
/* These are for interfacing with time services and are not normally needed in a sketch */
|
||||
|
||||
// leap year calculator expects year argument as years offset from 1970
|
||||
#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) )
|
||||
|
||||
static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0
|
||||
|
||||
void breakTime(time_t timeInput, tmElements_t &tm){
|
||||
// break the given time_t into time components
|
||||
// this is a more compact version of the C library localtime function
|
||||
// note that year is offset from 1970 !!!
|
||||
|
||||
uint8_t year;
|
||||
uint8_t month, monthLength;
|
||||
uint32_t time;
|
||||
unsigned long days;
|
||||
|
||||
time = (uint32_t)timeInput;
|
||||
tm.Second = time % 60;
|
||||
time /= 60; // now it is minutes
|
||||
tm.Minute = time % 60;
|
||||
time /= 60; // now it is hours
|
||||
tm.Hour = time % 24;
|
||||
time /= 24; // now it is days
|
||||
tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1
|
||||
|
||||
year = 0;
|
||||
days = 0;
|
||||
while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
|
||||
year++;
|
||||
}
|
||||
tm.Year = year; // year is offset from 1970
|
||||
|
||||
days -= LEAP_YEAR(year) ? 366 : 365;
|
||||
time -= days; // now it is days in this year, starting at 0
|
||||
|
||||
days=0;
|
||||
month=0;
|
||||
monthLength=0;
|
||||
for (month=0; month<12; month++) {
|
||||
if (month==1) { // february
|
||||
if (LEAP_YEAR(year)) {
|
||||
monthLength=29;
|
||||
} else {
|
||||
monthLength=28;
|
||||
}
|
||||
} else {
|
||||
monthLength = monthDays[month];
|
||||
}
|
||||
|
||||
if (time >= monthLength) {
|
||||
time -= monthLength;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tm.Month = month + 1; // jan is month 1
|
||||
tm.Day = time + 1; // day of month
|
||||
}
|
||||
|
||||
time_t makeTime(const tmElements_t &tm){
|
||||
// assemble time elements into time_t
|
||||
// note year argument is offset from 1970 (see macros in time.h to convert to other formats)
|
||||
// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9
|
||||
|
||||
int i;
|
||||
uint32_t seconds;
|
||||
|
||||
// seconds from 1970 till 1 jan 00:00:00 of the given year
|
||||
seconds= tm.Year*(SECS_PER_DAY * 365);
|
||||
for (i = 0; i < tm.Year; i++) {
|
||||
if (LEAP_YEAR(i)) {
|
||||
seconds += SECS_PER_DAY; // add extra days for leap years
|
||||
}
|
||||
}
|
||||
|
||||
// add days for this year, months start from 1
|
||||
for (i = 1; i < tm.Month; i++) {
|
||||
if ( (i == 2) && LEAP_YEAR(tm.Year)) {
|
||||
seconds += SECS_PER_DAY * 29;
|
||||
} else {
|
||||
seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0
|
||||
}
|
||||
}
|
||||
seconds+= (tm.Day-1) * SECS_PER_DAY;
|
||||
seconds+= tm.Hour * SECS_PER_HOUR;
|
||||
seconds+= tm.Minute * SECS_PER_MIN;
|
||||
seconds+= tm.Second;
|
||||
return (time_t)seconds;
|
||||
}
|
||||
/*=====================================================*/
|
||||
/* Low level system time functions */
|
||||
|
||||
static uint32_t sysTime = 0;
|
||||
static uint32_t prevMillis = 0;
|
||||
static uint32_t nextSyncTime = 0;
|
||||
static timeStatus_t Status = timeNotSet;
|
||||
|
||||
getExternalTime getTimePtr; // pointer to external sync function
|
||||
//setExternalTime setTimePtr; // not used in this version
|
||||
|
||||
#ifdef TIME_DRIFT_INFO // define this to get drift data
|
||||
time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync
|
||||
#endif
|
||||
|
||||
|
||||
time_t now() {
|
||||
// calculate number of seconds passed since last call to now()
|
||||
while (millis() - prevMillis >= 1000) {
|
||||
// millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference
|
||||
sysTime++;
|
||||
prevMillis += 1000;
|
||||
#ifdef TIME_DRIFT_INFO
|
||||
sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift
|
||||
#endif
|
||||
}
|
||||
if (nextSyncTime <= sysTime) {
|
||||
if (getTimePtr != 0) {
|
||||
time_t t = getTimePtr();
|
||||
if (t != 0) {
|
||||
setTime(t);
|
||||
} else {
|
||||
nextSyncTime = sysTime + syncInterval;
|
||||
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (time_t)sysTime;
|
||||
}
|
||||
|
||||
void setTime(time_t t) {
|
||||
#ifdef TIME_DRIFT_INFO
|
||||
if(sysUnsyncedTime == 0)
|
||||
sysUnsyncedTime = t; // store the time of the first call to set a valid Time
|
||||
#endif
|
||||
|
||||
sysTime = (uint32_t)t;
|
||||
nextSyncTime = (uint32_t)t + syncInterval;
|
||||
Status = timeSet;
|
||||
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
|
||||
}
|
||||
|
||||
void setTime(int hr,int min,int sec,int dy, int mnth, int yr){
|
||||
// year can be given as full four digit year or two digts (2010 or 10 for 2010);
|
||||
//it is converted to years since 1970
|
||||
if( yr > 99)
|
||||
yr = yr - 1970;
|
||||
else
|
||||
yr += 30;
|
||||
tm.Year = yr;
|
||||
tm.Month = mnth;
|
||||
tm.Day = dy;
|
||||
tm.Hour = hr;
|
||||
tm.Minute = min;
|
||||
tm.Second = sec;
|
||||
setTime(makeTime(tm));
|
||||
}
|
||||
|
||||
void adjustTime(long adjustment) {
|
||||
sysTime += adjustment;
|
||||
}
|
||||
|
||||
// indicates if time has been set and recently synchronized
|
||||
timeStatus_t timeStatus() {
|
||||
now(); // required to actually update the status
|
||||
return Status;
|
||||
}
|
||||
|
||||
void setSyncProvider( getExternalTime getTimeFunction){
|
||||
getTimePtr = getTimeFunction;
|
||||
nextSyncTime = sysTime;
|
||||
now(); // this will sync the clock
|
||||
}
|
||||
|
||||
void setSyncInterval(time_t interval){ // set the number of seconds between re-sync
|
||||
syncInterval = (uint32_t)interval;
|
||||
nextSyncTime = sysTime + syncInterval;
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
time.h - low level time and date functions
|
||||
*/
|
||||
|
||||
/*
|
||||
July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this)
|
||||
- fixed daysToTime_t macro (thanks maniacbug)
|
||||
*/
|
||||
|
||||
#ifndef _Time_h
|
||||
#define _Time_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef enum {timeNotSet, timeNeedsSync, timeSet
|
||||
} timeStatus_t ;
|
||||
|
||||
typedef enum {
|
||||
dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday
|
||||
} timeDayOfWeek_t;
|
||||
|
||||
typedef enum {
|
||||
tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields
|
||||
} tmByteFields;
|
||||
|
||||
typedef struct {
|
||||
uint8_t Second;
|
||||
uint8_t Minute;
|
||||
uint8_t Hour;
|
||||
uint8_t Wday; // day of week, sunday is day 1
|
||||
uint8_t Day;
|
||||
uint8_t Month;
|
||||
uint8_t Year; // offset from 1970;
|
||||
} tmElements_t, TimeElements, *tmElementsPtr_t;
|
||||
|
||||
//convenience macros to convert to and from tm years
|
||||
#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year
|
||||
#define CalendarYrToTm(Y) ((Y) - 1970)
|
||||
#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000
|
||||
#define y2kYearToTm(Y) ((Y) + 30)
|
||||
|
||||
typedef time_t(*getExternalTime)();
|
||||
//typedef void (*setExternalTime)(const time_t); // not used in this version
|
||||
|
||||
|
||||
/*==============================================================================*/
|
||||
/* Useful Constants */
|
||||
#define SECS_PER_MIN ((time_t)(60UL))
|
||||
#define SECS_PER_HOUR ((time_t)(3600UL))
|
||||
#define SECS_PER_DAY ((time_t)(SECS_PER_HOUR * 24UL))
|
||||
#define DAYS_PER_WEEK ((time_t)(7UL))
|
||||
#define SECS_PER_WEEK ((time_t)(SECS_PER_DAY * DAYS_PER_WEEK))
|
||||
#define SECS_PER_YEAR ((time_t)(SECS_PER_DAY * 365UL)) // TODO: ought to handle leap years
|
||||
#define SECS_YR_2000 ((time_t)(946684800UL)) // the time at the start of y2k
|
||||
|
||||
/* Useful Macros for getting elapsed time */
|
||||
#define numberOfSeconds(_time_) ((_time_) % SECS_PER_MIN)
|
||||
#define numberOfMinutes(_time_) (((_time_) / SECS_PER_MIN) % SECS_PER_MIN)
|
||||
#define numberOfHours(_time_) (((_time_) % SECS_PER_DAY) / SECS_PER_HOUR)
|
||||
#define dayOfWeek(_time_) ((((_time_) / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday
|
||||
#define elapsedDays(_time_) ((_time_) / SECS_PER_DAY) // this is number of days since Jan 1 1970
|
||||
#define elapsedSecsToday(_time_) ((_time_) % SECS_PER_DAY) // the number of seconds since last midnight
|
||||
// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971
|
||||
// Always set the correct time before setting alarms
|
||||
#define previousMidnight(_time_) (((_time_) / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day
|
||||
#define nextMidnight(_time_) (previousMidnight(_time_) + SECS_PER_DAY) // time at the end of the given day
|
||||
#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY)) // note that week starts on day 1
|
||||
#define previousSunday(_time_) ((_time_) - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time
|
||||
#define nextSunday(_time_) (previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time
|
||||
|
||||
|
||||
/* Useful Macros for converting elapsed time to a time_t */
|
||||
#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN)
|
||||
#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR)
|
||||
#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011
|
||||
#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK)
|
||||
|
||||
/*============================================================================*/
|
||||
/* time and date functions */
|
||||
int hour(); // the hour now
|
||||
int hour(time_t t); // the hour for the given time
|
||||
int hourFormat12(); // the hour now in 12 hour format
|
||||
int hourFormat12(time_t t); // the hour for the given time in 12 hour format
|
||||
uint8_t isAM(); // returns true if time now is AM
|
||||
uint8_t isAM(time_t t); // returns true the given time is AM
|
||||
uint8_t isPM(); // returns true if time now is PM
|
||||
uint8_t isPM(time_t t); // returns true the given time is PM
|
||||
int minute(); // the minute now
|
||||
int minute(time_t t); // the minute for the given time
|
||||
int second(); // the second now
|
||||
int second(time_t t); // the second for the given time
|
||||
int day(); // the day now
|
||||
int day(time_t t); // the day for the given time
|
||||
int weekday(); // the weekday now (Sunday is day 1)
|
||||
int weekday(time_t t); // the weekday for the given time
|
||||
int month(); // the month now (Jan is month 1)
|
||||
int month(time_t t); // the month for the given time
|
||||
int year(); // the full four digit year: (2009, 2010 etc)
|
||||
int year(time_t t); // the year for the given time
|
||||
|
||||
const String timeString();
|
||||
const String timeString(time_t t);
|
||||
|
||||
time_t now(); // return the current time as seconds since Jan 1 1970
|
||||
void setTime(time_t t);
|
||||
void setTime(int hr,int min,int sec,int day, int month, int yr);
|
||||
void adjustTime(long adjustment);
|
||||
|
||||
/* date strings */
|
||||
#define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null)
|
||||
const String monthStr(uint8_t month);
|
||||
const String dayStr(uint8_t day);
|
||||
const String monthShortStr(uint8_t month);
|
||||
const String dayShortStr(uint8_t day);
|
||||
|
||||
/* time sync functions */
|
||||
timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized
|
||||
void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider
|
||||
void setSyncInterval(time_t interval); // set the number of seconds between re-sync
|
||||
|
||||
/* low level functions to convert to and from system time */
|
||||
void breakTime(time_t time, tmElements_t &tm); // break time_t into elements
|
||||
time_t makeTime(const tmElements_t &tm); // convert time elements into time_t
|
||||
|
||||
#endif /* _Time_h */
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/* DateStrings.cpp
|
||||
* Definitions for date strings for use with the Time library
|
||||
*
|
||||
* Updated for Arduino 1.5.7 18 July 2014
|
||||
*
|
||||
* No memory is consumed in the sketch if your code does not call any of the string methods
|
||||
* You can change the text of the strings, make sure the short strings are each exactly 3 characters
|
||||
* the long strings can be any length up to the constant dt_MAX_STRING_LEN defined in TimeLib.h
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "TimeLib.h"
|
||||
|
||||
const String monthNames[] =
|
||||
{
|
||||
"Error", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
|
||||
};
|
||||
|
||||
const String monthStr(uint8_t month)
|
||||
{
|
||||
return monthNames[month];
|
||||
}
|
||||
|
||||
|
||||
const String monthShortNames[] =
|
||||
{
|
||||
"Err", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
const String monthShortStr(uint8_t month)
|
||||
{
|
||||
return monthShortNames[month];
|
||||
}
|
||||
|
||||
|
||||
const String dayNames[] =
|
||||
{
|
||||
"Err", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
|
||||
};
|
||||
|
||||
const String dayStr(uint8_t day)
|
||||
{
|
||||
return dayNames[day];
|
||||
}
|
||||
|
||||
|
||||
const String dayShortNames[] =
|
||||
{
|
||||
"Err", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
|
||||
const String dayShortStr(uint8_t day)
|
||||
{
|
||||
return dayShortNames[day];
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 285c641c628e803e54d847d65165a7dbbbe271df
|
|
@ -4,14 +4,12 @@ framework = arduino
|
|||
lib_ldf_mode = deep+
|
||||
monitor_speed = 115200
|
||||
lib_deps =
|
||||
arduino-libraries/NTPClient @ 3.1.0
|
||||
adafruit/Adafruit GFX Library @ 1.7.5
|
||||
adafruit/Adafruit SSD1306 @ 2.4.0
|
||||
bblanchon/ArduinoJson @ 6.17.0
|
||||
lewisxhe/AXP202X_Library @ 1.1.2
|
||||
sandeepmistry/LoRa @ 0.7.2
|
||||
peterus/APRS-Decoder-Lib @ 0.0.5
|
||||
peterus/APRS-IS-Lib @ 0.0.7
|
||||
peterus/esp-logger @ 0.0.1
|
||||
peterus/ESP-FTP-Server-Lib @ 0.9.5
|
||||
check_tool = cppcheck
|
||||
check_flags =
|
||||
|
|
|
@ -1,65 +1,37 @@
|
|||
#include <map>
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ETH.h>
|
||||
#include <WiFiMulti.h>
|
||||
#include <NTPClient.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <ArduinoOTA.h>
|
||||
#include <logger.h>
|
||||
#include <APRS-IS.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <ESP-FTP-Server-Lib.h>
|
||||
#include <FTPFilesystem.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include <TimeLib.h>
|
||||
#include "SignalSlot.h"
|
||||
#include "BoardFinder.h"
|
||||
#include "LoRa_APRS.h"
|
||||
#include "pins.h"
|
||||
#include "display.h"
|
||||
#include "project_configuration.h"
|
||||
|
||||
#ifdef NO_GLOBAL_INSTANCES
|
||||
HardwareSerial Serial(0);
|
||||
ArduinoOTAClass ArduinoOTA;
|
||||
#endif
|
||||
|
||||
#include "power_management.h"
|
||||
PowerManagement powerManagement;
|
||||
#include "project_configuration.h"
|
||||
#include "connection.h"
|
||||
|
||||
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
hw_timer_t * timer = NULL;
|
||||
volatile uint secondsSinceLastAPRSISBeacon = 0;
|
||||
volatile uint secondsSinceStartup = 0;
|
||||
volatile uint secondsSinceDisplay = 0;
|
||||
HardwareSerial Serial(0);
|
||||
|
||||
WiFiMulti WiFiMulti;
|
||||
WiFiUDP ntpUDP;
|
||||
NTPClient * timeClient;
|
||||
FTPServer ftpServer;
|
||||
Configuration * Config;
|
||||
std::shared_ptr<ArduinoOTAClass> OTA;
|
||||
std::shared_ptr<PowerManagement> powerManagement;
|
||||
std::shared_ptr<WiFiMulti> WiFiMulti;
|
||||
std::shared_ptr<NTPClient> ntpClient;
|
||||
std::shared_ptr<FTPServer> ftpServer;
|
||||
std::shared_ptr<Configuration> userConfig;
|
||||
std::shared_ptr<BoardConfig> boardConfig;
|
||||
APRS_IS * aprs_is = 0;
|
||||
LoRa_APRS * lora_aprs;
|
||||
std::shared_ptr<APRS_IS> aprs_is;
|
||||
std::shared_ptr<LoRa_APRS> lora_aprs;
|
||||
std::shared_ptr<APRSMessage> BeaconMsg;
|
||||
|
||||
volatile bool eth_connected = false;
|
||||
|
||||
String create_lat_aprs(double lat);
|
||||
String create_long_aprs(double lng);
|
||||
|
||||
void setup_eth();
|
||||
void setup_wifi();
|
||||
std::shared_ptr<LoRa_APRS> setup_lora();
|
||||
|
||||
void load_config();
|
||||
void setup_wifi();
|
||||
void setup_ota();
|
||||
void setup_lora();
|
||||
void setup_ntp();
|
||||
void setup_aprs_is();
|
||||
void setup_timer();
|
||||
void setup_ftp();
|
||||
|
||||
std::map<uint, std::shared_ptr<APRSMessage>> lastMessages;
|
||||
PrintMessageToConsole printMessageConsole;
|
||||
bool ethEnabled = false;
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
void setup()
|
||||
|
@ -69,22 +41,31 @@ void setup()
|
|||
delay(500);
|
||||
|
||||
ProjectConfigurationManagement confmg;
|
||||
Config = confmg.readConfiguration();
|
||||
userConfig = confmg.readConfiguration();
|
||||
|
||||
BoardFinder finder;
|
||||
boardConfig = finder.getBoardConfig(Config->board);
|
||||
std::list<std::shared_ptr<BoardConfig>> boardConfigs;
|
||||
boardConfigs.push_back(std::shared_ptr<BoardConfig>(new BoardConfig("TTGO_LORA32_V1", eTTGO_LORA32_V1, 4, 15, 0x3C, 0, 5, 19, 27, 18, 14, 26)));
|
||||
boardConfigs.push_back(std::shared_ptr<BoardConfig>(new BoardConfig("TTGO_LORA32_V2", eTTGO_LORA32_V2, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true)));
|
||||
boardConfigs.push_back(std::shared_ptr<BoardConfig>(new BoardConfig("TTGO_T_Beam_V0_7", eTTGO_T_Beam_V0_7, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true)));
|
||||
boardConfigs.push_back(std::shared_ptr<BoardConfig>(new BoardConfig("TTGO_T_Beam_V1_0", eTTGO_T_Beam_V1_0, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true, true)));
|
||||
boardConfigs.push_back(std::shared_ptr<BoardConfig>(new BoardConfig("ETH_BOARD", eETH_BOARD, 33, 32, 0x3C, 0, 14, 2, 15, 12, 4, 36)));
|
||||
boardConfigs.push_back(std::shared_ptr<BoardConfig>(new BoardConfig("TRACKERD", eTRACKERD, 5, 4, 0x3C, 0, 18, 19, 23, 16, 14, 26)));
|
||||
boardConfigs.push_back(std::shared_ptr<BoardConfig>(new BoardConfig("HELTEC_WIFI_LORA_32_V1", eHELTEC_WIFI_LORA_32_V1, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26)));
|
||||
boardConfigs.push_back(std::shared_ptr<BoardConfig>(new BoardConfig("HELTEC_WIFI_LORA_32_V2", eHELTEC_WIFI_LORA_32_V2, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26)));
|
||||
|
||||
BoardFinder finder(boardConfigs);
|
||||
boardConfig = finder.getBoardConfig(userConfig->board);
|
||||
if(boardConfig == 0)
|
||||
{
|
||||
boardConfig = finder.searchBoardConfig();
|
||||
if(boardConfig == 0)
|
||||
{
|
||||
logPrintlnE("Board config not set and search failed!");
|
||||
while (true)
|
||||
{
|
||||
}
|
||||
while(true)
|
||||
{}
|
||||
}
|
||||
Config->board = boardConfig->Name;
|
||||
confmg.writeConfiguration(Config);
|
||||
userConfig->board = boardConfig->Name;
|
||||
confmg.writeConfiguration(userConfig);
|
||||
logPrintlnI("will restart board now!");
|
||||
ESP.restart();
|
||||
}
|
||||
|
@ -96,7 +77,8 @@ void setup()
|
|||
{
|
||||
TwoWire wire(0);
|
||||
wire.begin(boardConfig->OledSda, boardConfig->OledScl);
|
||||
if (!powerManagement.begin(wire))
|
||||
std::shared_ptr<PowerManagement> powerManagement = std::shared_ptr<PowerManagement>(new PowerManagement);
|
||||
if (!powerManagement->begin(wire))
|
||||
{
|
||||
logPrintlnI("AXP192 init done!");
|
||||
}
|
||||
|
@ -104,9 +86,9 @@ void setup()
|
|||
{
|
||||
logPrintlnE("AXP192 init failed!");
|
||||
}
|
||||
powerManagement.activateLoRa();
|
||||
powerManagement.activateOLED();
|
||||
powerManagement.deactivateGPS();
|
||||
powerManagement->activateLoRa();
|
||||
powerManagement->activateOLED();
|
||||
powerManagement->deactivateGPS();
|
||||
}
|
||||
|
||||
logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)");
|
||||
|
@ -114,107 +96,76 @@ void setup()
|
|||
setup_display(boardConfig);
|
||||
show_display("OE5BPA", "LoRa APRS iGate", "by Peter Buchegger", "20.49.0-dev", 3000);
|
||||
|
||||
load_config();
|
||||
setup_lora();
|
||||
timeClient = new NTPClient(ntpUDP, Config->ntpServer.c_str());
|
||||
load_config(boardConfig);
|
||||
lora_aprs = setup_lora();
|
||||
if(boardConfig->Type == eETH_BOARD)
|
||||
{
|
||||
setup_eth();
|
||||
setup_ota();
|
||||
setup_ntp();
|
||||
setup_ftp();
|
||||
setup_aprs_is();
|
||||
ethEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(Config->wifi.active)
|
||||
{
|
||||
setup_wifi();
|
||||
setup_ota();
|
||||
setup_ntp();
|
||||
setup_ftp();
|
||||
}
|
||||
else
|
||||
{
|
||||
// make sure wifi and bt is off if we don't need it:
|
||||
WiFi.mode(WIFI_OFF);
|
||||
btStop();
|
||||
}
|
||||
if(Config->aprs_is.active) setup_aprs_is();
|
||||
}
|
||||
setup_timer();
|
||||
WiFiMulti = setup_wifi(userConfig);
|
||||
OTA = setup_ota(userConfig);
|
||||
ntpClient = setup_ntp(userConfig);
|
||||
ftpServer = setup_ftp(userConfig);
|
||||
aprs_is = std::shared_ptr<APRS_IS>(new APRS_IS(userConfig->callsign, userConfig->aprs_is.password , "ESP32-APRS-IS", "0.1"));
|
||||
|
||||
if(Config->display.overwritePin != 0)
|
||||
if(userConfig->display.overwritePin != 0)
|
||||
{
|
||||
pinMode(Config->display.overwritePin, INPUT);
|
||||
pinMode(Config->display.overwritePin, INPUT_PULLUP);
|
||||
pinMode(userConfig->display.overwritePin, INPUT);
|
||||
pinMode(userConfig->display.overwritePin, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
logPrintlnD("connect objects...");
|
||||
lora_aprs->connectSlot(&printMessageConsole);
|
||||
lora_aprs->connectSlot(aprs_is.get());
|
||||
|
||||
delay(500);
|
||||
logPrintlnI("setup done...");
|
||||
secondsSinceDisplay = 0;
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
void loop()
|
||||
{
|
||||
static bool display_is_on = true;
|
||||
if(Config->display.overwritePin != 0 && !digitalRead(Config->display.overwritePin))
|
||||
static bool beacon_aprs_is = true;
|
||||
if(userConfig->ftp.active)
|
||||
{
|
||||
secondsSinceDisplay = 0;
|
||||
display_is_on = true;
|
||||
setup_display(boardConfig);
|
||||
} else
|
||||
if(!Config->display.alwaysOn && secondsSinceDisplay > Config->display.timeout && display_is_on)
|
||||
{
|
||||
turn_off_display();
|
||||
display_is_on = false;
|
||||
}
|
||||
|
||||
static bool beacon_aprs_is = Config->aprs_is.active && Config->aprs_is.beacon;
|
||||
|
||||
if(Config->aprs_is.active && Config->aprs_is.beacon && secondsSinceLastAPRSISBeacon >= (Config->aprs_is.beaconTimeout*60))
|
||||
{
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
secondsSinceLastAPRSISBeacon -= (Config->aprs_is.beaconTimeout*60);
|
||||
portEXIT_CRITICAL(&timerMux);
|
||||
beacon_aprs_is = true;
|
||||
}
|
||||
|
||||
if(Config->ftp.active)
|
||||
{
|
||||
ftpServer.handle();
|
||||
ftpServer->handle();
|
||||
static bool configWasOpen = false;
|
||||
if(configWasOpen && ftpServer.countConnections() == 0)
|
||||
if(configWasOpen && ftpServer->countConnections() == 0)
|
||||
{
|
||||
logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config...");
|
||||
Serial.println();
|
||||
ESP.restart();
|
||||
}
|
||||
if(ftpServer.countConnections() > 0)
|
||||
if(ftpServer->countConnections() > 0)
|
||||
{
|
||||
configWasOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(Config->wifi.active || eth_connected) ArduinoOTA.handle();
|
||||
if(Config->wifi.active && WiFiMulti.run() != WL_CONNECTED)
|
||||
const uint8_t wifi_status = WiFiMulti->run();
|
||||
if(!ethEnabled && wifi_status != WL_CONNECTED)
|
||||
{
|
||||
setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true;
|
||||
logPrintlnE("WiFi not connected!");
|
||||
show_display("ERROR", "WiFi not connected!");
|
||||
delay(1000);
|
||||
return;
|
||||
}
|
||||
if((eth_connected && !aprs_is->connected()) || (Config->aprs_is.active && !aprs_is->connected()))
|
||||
|
||||
OTA->handle();
|
||||
if(ntpClient->update())
|
||||
{
|
||||
setTime(ntpClient->getEpochTime());
|
||||
}
|
||||
|
||||
if(!aprs_is->connected())
|
||||
{
|
||||
setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true;
|
||||
logPrintI("connecting to APRS-IS server: ");
|
||||
logPrintI(Config->aprs_is.server);
|
||||
logPrintI(userConfig->aprs_is.server);
|
||||
logPrintI(" on port: ");
|
||||
logPrintlnI(String(Config->aprs_is.port));
|
||||
logPrintlnI(String(userConfig->aprs_is.port));
|
||||
show_display("INFO", "Connecting to APRS-IS server");
|
||||
if(!aprs_is->connect(Config->aprs_is.server, Config->aprs_is.port))
|
||||
if(!aprs_is->connect(userConfig->aprs_is.server, userConfig->aprs_is.port))
|
||||
{
|
||||
logPrintlnE("Connection failed.");
|
||||
logPrintlnI("Waiting 5 seconds before retrying...");
|
||||
|
@ -224,274 +175,48 @@ void loop()
|
|||
}
|
||||
logPrintlnI("Connected to APRS-IS server!");
|
||||
}
|
||||
if(Config->aprs_is.active && aprs_is->available() > 0)
|
||||
{
|
||||
String str = aprs_is->getMessage();
|
||||
logPrintD("[" + timeClient->getFormattedTime() + "] ");
|
||||
logPrintlnD(str);
|
||||
}
|
||||
if(lora_aprs->hasMessage())
|
||||
{
|
||||
std::shared_ptr<APRSMessage> msg = lora_aprs->getMessage();
|
||||
|
||||
setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true;
|
||||
show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), msg->toString());
|
||||
logPrintD("[" + timeClient->getFormattedTime() + "] ");
|
||||
logPrintD(" Received packet '");
|
||||
logPrintD(msg->toString());
|
||||
logPrintD("' with RSSI ");
|
||||
logPrintD(String(lora_aprs->packetRssi()));
|
||||
logPrintD(" and SNR ");
|
||||
logPrintlnD(String(lora_aprs->packetSnr()));
|
||||
|
||||
if(Config->aprs_is.active)
|
||||
{
|
||||
aprs_is->sendMessage(msg->encode());
|
||||
}
|
||||
}
|
||||
if(beacon_aprs_is)
|
||||
aprs_is->getAPRSMessage();
|
||||
lora_aprs->checkMessage();
|
||||
|
||||
if(false) //beacon_aprs_is
|
||||
{
|
||||
beacon_aprs_is = false;
|
||||
setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true;
|
||||
show_display(Config->callsign, "Beacon to APRS-IS Server...");
|
||||
logPrintD("[" + timeClient->getFormattedTime() + "] ");
|
||||
show_display(userConfig->callsign, "Beacon to APRS-IS Server...");
|
||||
logPrintD("[" + ntpClient->getFormattedTime() + "] ");
|
||||
logPrintlnD(BeaconMsg->encode());
|
||||
aprs_is->sendMessage(BeaconMsg);
|
||||
show_display(Config->callsign, "Standby...");
|
||||
show_display(userConfig->callsign, "Standby...");
|
||||
}
|
||||
}
|
||||
|
||||
void load_config()
|
||||
std::shared_ptr<LoRa_APRS> setup_lora()
|
||||
{
|
||||
ProjectConfigurationManagement confmg;
|
||||
Config = confmg.readConfiguration();
|
||||
if(Config->callsign == "NOCALL-10")
|
||||
{
|
||||
logPrintlnE("You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!");
|
||||
show_display("ERROR", "You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!");
|
||||
while (true)
|
||||
{}
|
||||
}
|
||||
|
||||
if(boardConfig->Type != eETH_BOARD && Config->aprs_is.active && !Config->wifi.active)
|
||||
{
|
||||
logPrintlnE("You have to activate Wifi for APRS IS to work, please check your settings!");
|
||||
show_display("ERROR", "You have to activate Wifi for APRS IS to work, please check your settings!");
|
||||
while (true)
|
||||
{}
|
||||
}
|
||||
|
||||
if(KEY_BUILTIN != 0 && Config->display.overwritePin == 0)
|
||||
{
|
||||
Config->display.overwritePin = KEY_BUILTIN;
|
||||
}
|
||||
logPrintlnI("Configuration loaded!");
|
||||
}
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
switch (event) {
|
||||
case SYSTEM_EVENT_ETH_START:
|
||||
logPrintlnI("ETH Started");
|
||||
ETH.setHostname("esp32-ethernet");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_CONNECTED:
|
||||
logPrintlnI("ETH Connected");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||
logPrintI("ETH MAC: ");
|
||||
logPrintI(ETH.macAddress());
|
||||
logPrintI(", IPv4: ");
|
||||
logPrintI(ETH.localIP().toString());
|
||||
if (ETH.fullDuplex()) {
|
||||
logPrintI(", FULL_DUPLEX");
|
||||
}
|
||||
logPrintI(", ");
|
||||
logPrintI(String(ETH.linkSpeed()));
|
||||
logPrintlnI("Mbps");
|
||||
eth_connected = true;
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||
logPrintlnW("ETH Disconnected");
|
||||
eth_connected = false;
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_STOP:
|
||||
logPrintlnW("ETH Stopped");
|
||||
eth_connected = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setup_eth()
|
||||
{
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
|
||||
#define ETH_POWER_PIN -1
|
||||
#define ETH_TYPE ETH_PHY_LAN8720
|
||||
#define ETH_ADDR 0
|
||||
#define ETH_MDC_PIN 23
|
||||
#define ETH_MDIO_PIN 18
|
||||
#define ETH_NRST 5
|
||||
#define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0
|
||||
//#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2
|
||||
|
||||
pinMode(ETH_NRST, OUTPUT);
|
||||
digitalWrite(ETH_NRST, 0);
|
||||
delay(200);
|
||||
digitalWrite(ETH_NRST, 1);
|
||||
delay(200);
|
||||
digitalWrite(ETH_NRST, 0);
|
||||
delay(200);
|
||||
digitalWrite(ETH_NRST, 1);
|
||||
|
||||
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK);
|
||||
while(!eth_connected)
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
void setup_wifi()
|
||||
{
|
||||
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
WiFi.setHostname(Config->callsign.c_str());
|
||||
for(Configuration::Wifi::AP ap : Config->wifi.APs)
|
||||
{
|
||||
logPrintD("Looking for AP: ");
|
||||
logPrintlnD(ap.SSID);
|
||||
WiFiMulti.addAP(ap.SSID.c_str(), ap.password.c_str());
|
||||
}
|
||||
logPrintlnI("Waiting for WiFi");
|
||||
show_display("INFO", "Waiting for WiFi");
|
||||
while(WiFiMulti.run() != WL_CONNECTED)
|
||||
{
|
||||
show_display("INFO", "Waiting for WiFi", "....");
|
||||
delay(500);
|
||||
}
|
||||
logPrintlnI("WiFi connected");
|
||||
logPrintD("IP address: ");
|
||||
logPrintlnD(WiFi.localIP().toString());
|
||||
show_display("INFO", "WiFi connected", "IP: ", WiFi.localIP().toString(), 2000);
|
||||
}
|
||||
|
||||
void setup_ota()
|
||||
{
|
||||
ArduinoOTA
|
||||
.onStart([]()
|
||||
{
|
||||
String type;
|
||||
if (ArduinoOTA.getCommand() == U_FLASH)
|
||||
type = "sketch";
|
||||
else // U_SPIFFS
|
||||
type = "filesystem";
|
||||
Serial.println("Start updating " + type);
|
||||
show_display("OTA UPDATE", "Start update", type);
|
||||
})
|
||||
.onEnd([]()
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println("End");
|
||||
})
|
||||
.onProgress([](unsigned int progress, unsigned int total)
|
||||
{
|
||||
Serial.print("Progress: ");
|
||||
Serial.print(progress / (total / 100));
|
||||
Serial.println("%");
|
||||
show_display("OTA UPDATE", "Progress: ", String(progress / (total / 100)) + "%");
|
||||
})
|
||||
.onError([](ota_error_t error) {
|
||||
Serial.print("Error[");
|
||||
Serial.print(error);
|
||||
Serial.print("]: ");
|
||||
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||
});
|
||||
ArduinoOTA.setHostname(Config->callsign.c_str());
|
||||
ArduinoOTA.begin();
|
||||
logPrintlnI("OTA init done!");
|
||||
}
|
||||
|
||||
void setup_lora()
|
||||
{
|
||||
lora_aprs = new LoRa_APRS(boardConfig);
|
||||
if (!lora_aprs->begin(lora_aprs->getRxFrequency()))
|
||||
std::shared_ptr<LoRa_APRS> lora_aprs = std::shared_ptr<LoRa_APRS>(new LoRa_APRS(boardConfig));
|
||||
if(!lora_aprs->begin(lora_aprs->getRxFrequency()))
|
||||
{
|
||||
logPrintlnE("Starting LoRa failed!");
|
||||
show_display("ERROR", "Starting LoRa failed!");
|
||||
while (1);
|
||||
while(true);
|
||||
}
|
||||
lora_aprs->setRxFrequency(Config->lora.frequencyRx);
|
||||
lora_aprs->setTxFrequency(Config->lora.frequencyTx);
|
||||
lora_aprs->setTxPower(Config->lora.power);
|
||||
lora_aprs->setSpreadingFactor(Config->lora.spreadingFactor);
|
||||
lora_aprs->setSignalBandwidth(Config->lora.signalBandwidth);
|
||||
lora_aprs->setCodingRate4(Config->lora.codingRate4);
|
||||
lora_aprs->setRxFrequency(userConfig->lora.frequencyRx);
|
||||
lora_aprs->setTxFrequency(userConfig->lora.frequencyTx);
|
||||
lora_aprs->setTxPower(userConfig->lora.power);
|
||||
lora_aprs->setSpreadingFactor(userConfig->lora.spreadingFactor);
|
||||
lora_aprs->setSignalBandwidth(userConfig->lora.signalBandwidth);
|
||||
lora_aprs->setCodingRate4(userConfig->lora.codingRate4);
|
||||
lora_aprs->enableCrc();
|
||||
logPrintlnI("LoRa init done!");
|
||||
show_display("INFO", "LoRa init done!", 2000);
|
||||
|
||||
BeaconMsg = std::shared_ptr<APRSMessage>(new APRSMessage());
|
||||
BeaconMsg->setSource(Config->callsign);
|
||||
BeaconMsg->setSource(userConfig->callsign);
|
||||
BeaconMsg->setDestination("APLG0");
|
||||
String lat = create_lat_aprs(Config->beacon.positionLatitude);
|
||||
String lng = create_long_aprs(Config->beacon.positionLongitude);
|
||||
BeaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + Config->beacon.message);
|
||||
}
|
||||
String lat = create_lat_aprs(userConfig->beacon.positionLatitude);
|
||||
String lng = create_long_aprs(userConfig->beacon.positionLongitude);
|
||||
BeaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + userConfig->beacon.message);
|
||||
|
||||
void setup_ntp()
|
||||
{
|
||||
timeClient->begin();
|
||||
while(!timeClient->forceUpdate())
|
||||
{
|
||||
logPrintlnW("NTP Client force update issue! Waiting 1 sek...");
|
||||
show_display("WARN", "NTP Client force update issue! Waiting 1 sek...", 1000);
|
||||
}
|
||||
logPrintlnI("NTP Client init done!");
|
||||
show_display("INFO", "NTP Client init done!", 2000);
|
||||
}
|
||||
|
||||
void setup_aprs_is()
|
||||
{
|
||||
aprs_is = new APRS_IS(Config->callsign, Config->aprs_is.password , "ESP32-APRS-IS", "0.1");
|
||||
}
|
||||
|
||||
void IRAM_ATTR onTimer()
|
||||
{
|
||||
portENTER_CRITICAL_ISR(&timerMux);
|
||||
secondsSinceLastAPRSISBeacon++;
|
||||
secondsSinceStartup++;
|
||||
secondsSinceDisplay++;
|
||||
portEXIT_CRITICAL_ISR(&timerMux);
|
||||
}
|
||||
|
||||
void setup_timer()
|
||||
{
|
||||
timer = timerBegin(0, 80, true);
|
||||
timerAlarmWrite(timer, 1000000, true);
|
||||
timerAttachInterrupt(timer, &onTimer, true);
|
||||
timerAlarmEnable(timer);
|
||||
}
|
||||
|
||||
void setup_ftp()
|
||||
{
|
||||
if(!Config->ftp.active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for(Configuration::Ftp::User user : Config->ftp.users)
|
||||
{
|
||||
logPrintD("Adding user to FTP Server: ");
|
||||
logPrintlnD(user.name);
|
||||
ftpServer.addUser(user.name, user.password);
|
||||
}
|
||||
ftpServer.addFilesystem("SPIFFS", &SPIFFS);
|
||||
ftpServer.begin();
|
||||
logPrintlnI("FTP Server init done!");
|
||||
return lora_aprs;
|
||||
}
|
||||
|
||||
String create_lat_aprs(double lat)
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
|
||||
#include <Arduino.h>
|
||||
#include <ETH.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <logger.h>
|
||||
#include <TimeLib.h>
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
volatile bool eth_connected = false;
|
||||
|
||||
static void WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
switch (event) {
|
||||
case SYSTEM_EVENT_ETH_START:
|
||||
logPrintlnI("ETH Started");
|
||||
ETH.setHostname("esp32-ethernet");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_CONNECTED:
|
||||
logPrintlnI("ETH Connected");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||
logPrintI("ETH MAC: ");
|
||||
logPrintI(ETH.macAddress());
|
||||
logPrintI(", IPv4: ");
|
||||
logPrintI(ETH.localIP().toString());
|
||||
if (ETH.fullDuplex()) {
|
||||
logPrintI(", FULL_DUPLEX");
|
||||
}
|
||||
logPrintI(", ");
|
||||
logPrintI(String(ETH.linkSpeed()));
|
||||
logPrintlnI("Mbps");
|
||||
eth_connected = true;
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||
logPrintlnW("ETH Disconnected");
|
||||
eth_connected = false;
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_STOP:
|
||||
logPrintlnW("ETH Stopped");
|
||||
eth_connected = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool isEthConnected()
|
||||
{
|
||||
return eth_connected;
|
||||
}
|
||||
|
||||
void setup_eth()
|
||||
{
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
|
||||
#define ETH_POWER_PIN -1
|
||||
#define ETH_TYPE ETH_PHY_LAN8720
|
||||
#define ETH_ADDR 0
|
||||
#define ETH_MDC_PIN 23
|
||||
#define ETH_MDIO_PIN 18
|
||||
#define ETH_NRST 5
|
||||
#define ETH_CLK ETH_CLOCK_GPIO17_OUT // TTGO PoE V1.0
|
||||
//#define ETH_CLK ETH_CLOCK_GPIO0_OUT // TTGO PoE V1.2
|
||||
|
||||
pinMode(ETH_NRST, OUTPUT);
|
||||
digitalWrite(ETH_NRST, 0);
|
||||
delay(200);
|
||||
digitalWrite(ETH_NRST, 1);
|
||||
delay(200);
|
||||
digitalWrite(ETH_NRST, 0);
|
||||
delay(200);
|
||||
digitalWrite(ETH_NRST, 1);
|
||||
|
||||
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK);
|
||||
while(!eth_connected)
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<WiFiMulti> setup_wifi(std::shared_ptr<Configuration> config)
|
||||
{
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
//WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE);
|
||||
WiFi.setHostname(config->callsign.c_str());
|
||||
std::shared_ptr<WiFiMulti> wiFiMulti = std::shared_ptr<WiFiMulti>(new WiFiMulti());;
|
||||
for(Configuration::Wifi::AP ap : config->wifi.APs)
|
||||
{
|
||||
logPrintD("Looking for AP: ");
|
||||
logPrintlnD(ap.SSID);
|
||||
wiFiMulti->addAP(ap.SSID.c_str(), ap.password.c_str());
|
||||
}
|
||||
logPrintlnI("Waiting for WiFi");
|
||||
//show_display("INFO", "Waiting for WiFi");
|
||||
while(wiFiMulti->run() != WL_CONNECTED)
|
||||
{
|
||||
//show_display("INFO", "Waiting for WiFi", "....");
|
||||
delay(500);
|
||||
}
|
||||
logPrintlnI("WiFi connected");
|
||||
logPrintD("IP address: ");
|
||||
logPrintlnD(WiFi.localIP().toString());
|
||||
//show_display("INFO", "WiFi connected", "IP: ", WiFi.localIP().toString(), 2000);
|
||||
return wiFiMulti;
|
||||
}
|
||||
|
||||
std::shared_ptr<ArduinoOTAClass> setup_ota(std::shared_ptr<Configuration> config)
|
||||
{
|
||||
std::shared_ptr<ArduinoOTAClass> ota = std::shared_ptr<ArduinoOTAClass>(new ArduinoOTAClass());
|
||||
ota->onStart([&]()
|
||||
{
|
||||
String type;
|
||||
if (ota->getCommand() == U_FLASH)
|
||||
type = "sketch";
|
||||
else // U_SPIFFS
|
||||
type = "filesystem";
|
||||
logPrintlnI("Start updating " + type);
|
||||
//show_display("OTA UPDATE", "Start update", type);
|
||||
})
|
||||
.onEnd([]()
|
||||
{
|
||||
logPrintlnI("");
|
||||
logPrintlnI("OTA End");
|
||||
})
|
||||
.onProgress([](unsigned int progress, unsigned int total)
|
||||
{
|
||||
logPrintI("Progress: ");
|
||||
logPrintI(String(progress / (total / 100)));
|
||||
logPrintlnI("%");
|
||||
//show_display("OTA UPDATE", "Progress: ", String(progress / (total / 100)) + "%");
|
||||
})
|
||||
.onError([](ota_error_t error)
|
||||
{
|
||||
logPrintE("Error[");
|
||||
logPrintE(String(error));
|
||||
logPrintE("]: ");
|
||||
if (error == OTA_AUTH_ERROR) logPrintlnE("Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) logPrintlnE("Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) logPrintlnE("Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) logPrintlnE("Receive Failed");
|
||||
else if (error == OTA_END_ERROR) logPrintlnE("End Failed");
|
||||
});
|
||||
ota->setHostname(config->callsign.c_str());
|
||||
ota->begin();
|
||||
logPrintlnI("OTA init done!");
|
||||
return ota;
|
||||
}
|
||||
|
||||
std::shared_ptr<NTPClient> setup_ntp(std::shared_ptr<Configuration> config)
|
||||
{
|
||||
std::shared_ptr<NTPClient> ntpClient = std::shared_ptr<NTPClient>(new NTPClient(config->ntpServer.c_str()));
|
||||
ntpClient->begin();
|
||||
while(!ntpClient->forceUpdate())
|
||||
{
|
||||
logPrintlnW("NTP Client force update issue! Waiting 1 sek...");
|
||||
logPrintlnD(ntpClient->getFormattedTime());
|
||||
//show_display("WARN", "NTP Client force update issue! Waiting 1 sek...", 1000);
|
||||
sleep(1);
|
||||
}
|
||||
setTime(ntpClient->getEpochTime());
|
||||
logPrintlnI("NTP Client init done!");
|
||||
//show_display("INFO", "NTP Client init done!", 2000);
|
||||
return ntpClient;
|
||||
}
|
||||
|
||||
std::shared_ptr<FTPServer> setup_ftp(std::shared_ptr<Configuration> config)
|
||||
{
|
||||
std::shared_ptr<FTPServer> ftpServer = std::shared_ptr<FTPServer>(new FTPServer());
|
||||
if(config->ftp.active)
|
||||
{
|
||||
for(Configuration::Ftp::User user : config->ftp.users)
|
||||
{
|
||||
logPrintD("Adding user to FTP Server: ");
|
||||
logPrintlnD(user.name);
|
||||
ftpServer->addUser(user.name, user.password);
|
||||
}
|
||||
ftpServer->addFilesystem("SPIFFS", &SPIFFS);
|
||||
ftpServer->begin();
|
||||
logPrintlnI("FTP Server init done!");
|
||||
}
|
||||
return ftpServer;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
#ifndef CONNECTION_H_
|
||||
#define CONNECTION_H_
|
||||
|
||||
#include <ArduinoOTA.h>
|
||||
#include <WiFiMulti.h>
|
||||
#include <ESP-FTP-Server-Lib.h>
|
||||
#include <FTPFilesystem.h>
|
||||
#include <NTPClient.h>
|
||||
#include "project_configuration.h"
|
||||
|
||||
bool isEthConnected();
|
||||
void setup_eth();
|
||||
std::shared_ptr<WiFiMulti> setup_wifi(std::shared_ptr<Configuration> config);
|
||||
std::shared_ptr<ArduinoOTAClass> setup_ota(std::shared_ptr<Configuration> config);
|
||||
std::shared_ptr<NTPClient> setup_ntp(std::shared_ptr<Configuration> config);
|
||||
std::shared_ptr<FTPServer> setup_ftp(std::shared_ptr<Configuration> config);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,142 @@
|
|||
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
#include "BoardFinder.h"
|
||||
#include "display.h"
|
||||
#include "logger.h"
|
||||
|
||||
Adafruit_SSD1306 * display = 0;
|
||||
TwoWire * wire = 0;
|
||||
|
||||
void setup_display(std::shared_ptr<BoardConfig> boardConfig)
|
||||
{
|
||||
if(display == 0)
|
||||
{
|
||||
wire = new TwoWire(0);
|
||||
wire->begin(boardConfig->OledSda, boardConfig->OledScl);
|
||||
if(boardConfig->OledReset > 0)
|
||||
{
|
||||
display = new Adafruit_SSD1306(128, 64, wire, boardConfig->OledReset);
|
||||
logPrintlnI("with reset");
|
||||
}
|
||||
else
|
||||
{
|
||||
display = new Adafruit_SSD1306(128, 64, wire);
|
||||
logPrintlnI("with NO reset");
|
||||
}
|
||||
}
|
||||
if(!display->begin(SSD1306_SWITCHCAPVCC, boardConfig->OledAddr, false, false))
|
||||
{
|
||||
logPrintlnE("SSD1306 allocation failed");
|
||||
while (1);
|
||||
}
|
||||
logPrintlnI("Display init done!");
|
||||
}
|
||||
|
||||
void turn_off_display()
|
||||
{
|
||||
display->ssd1306_command(SSD1306_DISPLAYOFF);
|
||||
}
|
||||
|
||||
void show_display(String header, int wait)
|
||||
{
|
||||
display->clearDisplay();
|
||||
display->setTextColor(WHITE);
|
||||
display->setTextSize(2);
|
||||
display->setCursor(0,0);
|
||||
display->println(header);
|
||||
display->display();
|
||||
delay(wait);
|
||||
}
|
||||
|
||||
void show_display(String header, String line1, int wait)
|
||||
{
|
||||
display->clearDisplay();
|
||||
display->setTextColor(WHITE);
|
||||
display->setTextSize(2);
|
||||
display->setCursor(0,0);
|
||||
display->println(header);
|
||||
display->setTextSize(1);
|
||||
display->setCursor(0,16);
|
||||
display->println(line1);
|
||||
display->display();
|
||||
delay(wait);
|
||||
}
|
||||
|
||||
void show_display(String header, String line1, String line2, int wait)
|
||||
{
|
||||
display->clearDisplay();
|
||||
display->setTextColor(WHITE);
|
||||
display->setTextSize(2);
|
||||
display->setCursor(0,0);
|
||||
display->println(header);
|
||||
display->setTextSize(1);
|
||||
display->setCursor(0,16);
|
||||
display->println(line1);
|
||||
display->setCursor(0,26);
|
||||
display->println(line2);
|
||||
display->display();
|
||||
delay(wait);
|
||||
}
|
||||
|
||||
void show_display(String header, String line1, String line2, String line3, int wait)
|
||||
{
|
||||
display->clearDisplay();
|
||||
display->setTextColor(WHITE);
|
||||
display->setTextSize(2);
|
||||
display->setCursor(0,0);
|
||||
display->println(header);
|
||||
display->setTextSize(1);
|
||||
display->setCursor(0,16);
|
||||
display->println(line1);
|
||||
display->setCursor(0,26);
|
||||
display->println(line2);
|
||||
display->setCursor(0,36);
|
||||
display->println(line3);
|
||||
display->display();
|
||||
delay(wait);
|
||||
}
|
||||
|
||||
void show_display(String header, String line1, String line2, String line3, String line4, int wait)
|
||||
{
|
||||
display->clearDisplay();
|
||||
display->setTextColor(WHITE);
|
||||
display->setTextSize(2);
|
||||
display->setCursor(0,0);
|
||||
display->println(header);
|
||||
display->setTextSize(1);
|
||||
display->setCursor(0,16);
|
||||
display->println(line1);
|
||||
display->setCursor(0,26);
|
||||
display->println(line2);
|
||||
display->setCursor(0,36);
|
||||
display->println(line3);
|
||||
display->setCursor(0,46);
|
||||
display->println(line4);
|
||||
display->display();
|
||||
delay(wait);
|
||||
}
|
||||
|
||||
void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait)
|
||||
{
|
||||
display->clearDisplay();
|
||||
display->setTextColor(WHITE);
|
||||
display->setTextSize(2);
|
||||
display->setCursor(0,0);
|
||||
display->println(header);
|
||||
display->setTextSize(1);
|
||||
display->setCursor(0,16);
|
||||
display->println(line1);
|
||||
display->setCursor(0,26);
|
||||
display->println(line2);
|
||||
display->setCursor(0,36);
|
||||
display->println(line3);
|
||||
display->setCursor(0,46);
|
||||
display->println(line4);
|
||||
display->setCursor(0,56);
|
||||
display->println(line5);
|
||||
display->display();
|
||||
delay(wait);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
#ifndef DISPLAY_H_
|
||||
#define DISPLAY_H_
|
||||
|
||||
void setup_display(std::shared_ptr<BoardConfig> boardConfig);
|
||||
void turn_off_display();
|
||||
|
||||
void show_display(String header, int wait = 0);
|
||||
void show_display(String header, String line1, int wait = 0);
|
||||
void show_display(String header, String line1, String line2, int wait = 0);
|
||||
void show_display(String header, String line1, String line2, String line3, int wait = 0);
|
||||
void show_display(String header, String line1, String line2, String line3, String line4, int wait = 0);
|
||||
void show_display(String header, String line1, String line2, String line3, String line4, String line5, int wait = 0);
|
||||
|
||||
#include <APRSMessage.h>
|
||||
#include "SignalSlot.h"
|
||||
#include "TimeLib.h"
|
||||
#include "logger.h"
|
||||
|
||||
class PrintMessageToConsole : public Slot1<std::shared_ptr<APRSMessage>>, public Slot3<std::shared_ptr<APRSMessage>, int, float>
|
||||
{
|
||||
public:
|
||||
void action(std::shared_ptr<APRSMessage> msg, int rssi, float snr) override
|
||||
{
|
||||
//setup_display(boardConfig); secondsSinceDisplay = 0; //display_is_on = true;
|
||||
//show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), elem->toString());
|
||||
logPrintD("[" + timeString() + "] ");
|
||||
logPrintD("Received packet '");
|
||||
logPrintD(msg->toString());
|
||||
logPrintD("' with RSSI ");
|
||||
logPrintD(String(rssi));
|
||||
logPrintD(" and SNR ");
|
||||
logPrintlnD(String(snr));
|
||||
}
|
||||
|
||||
void action(std::shared_ptr<APRSMessage> msg) override
|
||||
{
|
||||
//setup_display(boardConfig); secondsSinceDisplay = 0; //display_is_on = true;
|
||||
//show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), elem->toString());
|
||||
logPrintD("[" + timeString() + "] ");
|
||||
logPrintD("Received packet '");
|
||||
logPrintD(msg->toString());
|
||||
logPrintD("'");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -3,13 +3,12 @@
|
|||
#include "project_configuration.h"
|
||||
#include "logger.h"
|
||||
|
||||
Configuration * ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocument & data)
|
||||
std::shared_ptr<Configuration> ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocument & data)
|
||||
{
|
||||
Configuration * conf = new Configuration;
|
||||
std::shared_ptr<Configuration> conf = std::shared_ptr<Configuration>(new Configuration);
|
||||
if(data.containsKey("callsign"))
|
||||
conf->callsign = data["callsign"].as<String>();
|
||||
|
||||
conf->wifi.active = data["wifi"]["active"] | false;
|
||||
JsonArray aps = data["wifi"]["AP"].as<JsonArray>();
|
||||
for(JsonVariant v : aps)
|
||||
{
|
||||
|
@ -22,7 +21,6 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic
|
|||
conf->beacon.message = data["beacon"]["message"].as<String>();
|
||||
conf->beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0;
|
||||
conf->beacon.positionLongitude = data["beacon"]["position"]["longitude"] | 0.0;
|
||||
conf->aprs_is.active = data["aprs_is"]["active"] | false;
|
||||
if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("password"))
|
||||
conf->aprs_is.password = data["aprs_is"]["password"].as<String>();
|
||||
if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("server"))
|
||||
|
@ -66,10 +64,9 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic
|
|||
return conf;
|
||||
}
|
||||
|
||||
void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * conf, DynamicJsonDocument & data)
|
||||
void ProjectConfigurationManagement::writeProjectConfiguration(std::shared_ptr<Configuration> conf, DynamicJsonDocument & data)
|
||||
{
|
||||
data["callsign"] = conf->callsign;
|
||||
data["wifi"]["active"] = conf->wifi.active;
|
||||
JsonArray aps = data["wifi"].createNestedArray("AP");
|
||||
for(Configuration::Wifi::AP ap : conf->wifi.APs)
|
||||
{
|
||||
|
@ -80,7 +77,6 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * c
|
|||
data["beacon"]["message"] = conf->beacon.message;
|
||||
data["beacon"]["position"]["latitude"] = conf->beacon.positionLatitude;
|
||||
data["beacon"]["position"]["longitude"] = conf->beacon.positionLongitude;
|
||||
data["aprs_is"]["active"] = conf->aprs_is.active;
|
||||
data["aprs_is"]["password"] = conf->aprs_is.password;
|
||||
data["aprs_is"]["server"] = conf->aprs_is.server;
|
||||
data["aprs_is"]["port"] = conf->aprs_is.port;
|
||||
|
@ -107,3 +103,23 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * c
|
|||
|
||||
data["board"] = conf->board;
|
||||
}
|
||||
|
||||
std::shared_ptr<Configuration> load_config(std::shared_ptr<BoardConfig> boardConfig)
|
||||
{
|
||||
ProjectConfigurationManagement confmg;
|
||||
std::shared_ptr<Configuration> config = confmg.readConfiguration();
|
||||
if(config->callsign == "NOCALL-10")
|
||||
{
|
||||
logPrintlnE("You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!");
|
||||
//show_display("ERROR", "You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!");
|
||||
while (true)
|
||||
{}
|
||||
}
|
||||
|
||||
/*if(KEY_BUILTIN != 0 && Config->display.overwritePin == 0)
|
||||
{
|
||||
Config->display.overwritePin = KEY_BUILTIN;
|
||||
}*/
|
||||
logPrintlnI("Configuration loaded!");
|
||||
return config;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define PROJECT_CONFIGURATION_H_
|
||||
|
||||
#include "configuration.h"
|
||||
#include "BoardFinder.h"
|
||||
|
||||
class Configuration
|
||||
{
|
||||
|
@ -16,9 +17,8 @@ public:
|
|||
String password;
|
||||
};
|
||||
|
||||
Wifi() : active(false) {}
|
||||
Wifi() {}
|
||||
|
||||
bool active;
|
||||
std::list<AP> APs;
|
||||
};
|
||||
|
||||
|
@ -35,9 +35,8 @@ public:
|
|||
class APRS_IS
|
||||
{
|
||||
public:
|
||||
APRS_IS() : active(false), server("euro.aprs2.net"), port(14580), beacon(true), beaconTimeout(15) {}
|
||||
APRS_IS() : server("euro.aprs2.net"), port(14580), beacon(true), beaconTimeout(15) {}
|
||||
|
||||
bool active;
|
||||
String password;
|
||||
String server;
|
||||
int port;
|
||||
|
@ -104,8 +103,10 @@ public:
|
|||
virtual ~ProjectConfigurationManagement() {}
|
||||
|
||||
private:
|
||||
virtual Configuration * readProjectConfiguration(DynamicJsonDocument & data) override;
|
||||
virtual void writeProjectConfiguration(Configuration * conf, DynamicJsonDocument & data) override;
|
||||
virtual std::shared_ptr<Configuration> readProjectConfiguration(DynamicJsonDocument & data) override;
|
||||
virtual void writeProjectConfiguration(std::shared_ptr<Configuration> conf, DynamicJsonDocument & data) override;
|
||||
};
|
||||
|
||||
std::shared_ptr<Configuration> load_config(std::shared_ptr<BoardConfig> boardConfig);
|
||||
|
||||
#endif
|
||||
|
|
Ładowanie…
Reference in New Issue