push a lot of changes...

pull/74/head
Peter Buchegger 2021-01-01 23:23:27 +01:00
rodzic 295feb98cc
commit d5c015f4b9
29 zmienionych plików z 2907 dodań i 391 usunięć

3
.gitmodules vendored
Wyświetl plik

@ -1,3 +0,0 @@
[submodule "lib"]
path = lib/common
url = ../LoRa_APRS_Common

Wyświetl plik

@ -2,7 +2,6 @@
"callsign":"NOCALL-10", "callsign":"NOCALL-10",
"wifi": "wifi":
{ {
"active":false,
"AP": [ "AP": [
{ "SSID":"YOURSSID", "password":"YOURPASSWORD" } { "SSID":"YOURSSID", "password":"YOURPASSWORD" }
] ]
@ -18,7 +17,6 @@
}, },
"aprs_is": "aprs_is":
{ {
"active":false,
"password":"", "password":"",
"server":"euro.aprs2.net", "server":"euro.aprs2.net",
"port":14580, "port":14580,

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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();
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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();
};

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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

Wyświetl plik

@ -4,14 +4,12 @@ framework = arduino
lib_ldf_mode = deep+ lib_ldf_mode = deep+
monitor_speed = 115200 monitor_speed = 115200
lib_deps = lib_deps =
arduino-libraries/NTPClient @ 3.1.0
adafruit/Adafruit GFX Library @ 1.7.5 adafruit/Adafruit GFX Library @ 1.7.5
adafruit/Adafruit SSD1306 @ 2.4.0 adafruit/Adafruit SSD1306 @ 2.4.0
bblanchon/ArduinoJson @ 6.17.0 bblanchon/ArduinoJson @ 6.17.0
lewisxhe/AXP202X_Library @ 1.1.2 lewisxhe/AXP202X_Library @ 1.1.2
sandeepmistry/LoRa @ 0.7.2
peterus/APRS-Decoder-Lib @ 0.0.5 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 peterus/ESP-FTP-Server-Lib @ 0.9.5
check_tool = cppcheck check_tool = cppcheck
check_flags = check_flags =

Wyświetl plik

@ -1,65 +1,37 @@
#include <map> #include <map>
#include <Arduino.h> #include <logger.h>
#include <ETH.h>
#include <WiFiMulti.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <APRS-IS.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 "BoardFinder.h"
#include "LoRa_APRS.h" #include "LoRa_APRS.h"
#include "pins.h"
#include "display.h" #include "display.h"
#include "project_configuration.h"
#ifdef NO_GLOBAL_INSTANCES
HardwareSerial Serial(0);
ArduinoOTAClass ArduinoOTA;
#endif
#include "power_management.h" #include "power_management.h"
PowerManagement powerManagement; #include "project_configuration.h"
#include "connection.h"
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED; HardwareSerial Serial(0);
hw_timer_t * timer = NULL;
volatile uint secondsSinceLastAPRSISBeacon = 0;
volatile uint secondsSinceStartup = 0;
volatile uint secondsSinceDisplay = 0;
WiFiMulti WiFiMulti; std::shared_ptr<ArduinoOTAClass> OTA;
WiFiUDP ntpUDP; std::shared_ptr<PowerManagement> powerManagement;
NTPClient * timeClient; std::shared_ptr<WiFiMulti> WiFiMulti;
FTPServer ftpServer; std::shared_ptr<NTPClient> ntpClient;
Configuration * Config; std::shared_ptr<FTPServer> ftpServer;
std::shared_ptr<Configuration> userConfig;
std::shared_ptr<BoardConfig> boardConfig; std::shared_ptr<BoardConfig> boardConfig;
APRS_IS * aprs_is = 0; std::shared_ptr<APRS_IS> aprs_is;
LoRa_APRS * lora_aprs; std::shared_ptr<LoRa_APRS> lora_aprs;
std::shared_ptr<APRSMessage> BeaconMsg; std::shared_ptr<APRSMessage> BeaconMsg;
volatile bool eth_connected = false;
String create_lat_aprs(double lat); String create_lat_aprs(double lat);
String create_long_aprs(double lng); String create_long_aprs(double lng);
void setup_eth(); std::shared_ptr<LoRa_APRS> setup_lora();
void setup_wifi();
void load_config(); PrintMessageToConsole printMessageConsole;
void setup_wifi(); bool ethEnabled = false;
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;
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void setup() void setup()
@ -69,22 +41,31 @@ void setup()
delay(500); delay(500);
ProjectConfigurationManagement confmg; ProjectConfigurationManagement confmg;
Config = confmg.readConfiguration(); userConfig = confmg.readConfiguration();
BoardFinder finder; std::list<std::shared_ptr<BoardConfig>> boardConfigs;
boardConfig = finder.getBoardConfig(Config->board); 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) if(boardConfig == 0)
{ {
boardConfig = finder.searchBoardConfig(); boardConfig = finder.searchBoardConfig();
if(boardConfig == 0) if(boardConfig == 0)
{ {
logPrintlnE("Board config not set and search failed!"); logPrintlnE("Board config not set and search failed!");
while (true) while(true)
{ {}
}
} }
Config->board = boardConfig->Name; userConfig->board = boardConfig->Name;
confmg.writeConfiguration(Config); confmg.writeConfiguration(userConfig);
logPrintlnI("will restart board now!"); logPrintlnI("will restart board now!");
ESP.restart(); ESP.restart();
} }
@ -96,7 +77,8 @@ void setup()
{ {
TwoWire wire(0); TwoWire wire(0);
wire.begin(boardConfig->OledSda, boardConfig->OledScl); 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!"); logPrintlnI("AXP192 init done!");
} }
@ -104,9 +86,9 @@ void setup()
{ {
logPrintlnE("AXP192 init failed!"); logPrintlnE("AXP192 init failed!");
} }
powerManagement.activateLoRa(); powerManagement->activateLoRa();
powerManagement.activateOLED(); powerManagement->activateOLED();
powerManagement.deactivateGPS(); powerManagement->deactivateGPS();
} }
logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)"); logPrintlnW("LoRa APRS iGate by OE5BPA (Peter Buchegger)");
@ -114,107 +96,76 @@ void setup()
setup_display(boardConfig); setup_display(boardConfig);
show_display("OE5BPA", "LoRa APRS iGate", "by Peter Buchegger", "20.49.0-dev", 3000); show_display("OE5BPA", "LoRa APRS iGate", "by Peter Buchegger", "20.49.0-dev", 3000);
load_config(); load_config(boardConfig);
setup_lora(); lora_aprs = setup_lora();
timeClient = new NTPClient(ntpUDP, Config->ntpServer.c_str());
if(boardConfig->Type == eETH_BOARD) if(boardConfig->Type == eETH_BOARD)
{ {
setup_eth(); setup_eth();
setup_ota(); ethEnabled = true;
setup_ntp();
setup_ftp();
setup_aprs_is();
} }
else WiFiMulti = setup_wifi(userConfig);
{ OTA = setup_ota(userConfig);
if(Config->wifi.active) ntpClient = setup_ntp(userConfig);
{ ftpServer = setup_ftp(userConfig);
setup_wifi(); aprs_is = std::shared_ptr<APRS_IS>(new APRS_IS(userConfig->callsign, userConfig->aprs_is.password , "ESP32-APRS-IS", "0.1"));
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();
if(Config->display.overwritePin != 0) if(userConfig->display.overwritePin != 0)
{ {
pinMode(Config->display.overwritePin, INPUT); pinMode(userConfig->display.overwritePin, INPUT);
pinMode(Config->display.overwritePin, INPUT_PULLUP); pinMode(userConfig->display.overwritePin, INPUT_PULLUP);
} }
logPrintlnD("connect objects...");
lora_aprs->connectSlot(&printMessageConsole);
lora_aprs->connectSlot(aprs_is.get());
delay(500); delay(500);
logPrintlnI("setup done..."); logPrintlnI("setup done...");
secondsSinceDisplay = 0;
} }
// cppcheck-suppress unusedFunction // cppcheck-suppress unusedFunction
void loop() void loop()
{ {
static bool display_is_on = true; static bool beacon_aprs_is = true;
if(Config->display.overwritePin != 0 && !digitalRead(Config->display.overwritePin)) if(userConfig->ftp.active)
{ {
secondsSinceDisplay = 0; ftpServer->handle();
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();
static bool configWasOpen = false; 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..."); logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config...");
Serial.println(); Serial.println();
ESP.restart(); ESP.restart();
} }
if(ftpServer.countConnections() > 0) if(ftpServer->countConnections() > 0)
{ {
configWasOpen = true; configWasOpen = true;
} }
} }
if(Config->wifi.active || eth_connected) ArduinoOTA.handle(); const uint8_t wifi_status = WiFiMulti->run();
if(Config->wifi.active && WiFiMulti.run() != WL_CONNECTED) if(!ethEnabled && wifi_status != WL_CONNECTED)
{ {
setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true;
logPrintlnE("WiFi not connected!"); logPrintlnE("WiFi not connected!");
show_display("ERROR", "WiFi not connected!"); show_display("ERROR", "WiFi not connected!");
delay(1000); delay(1000);
return; 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("connecting to APRS-IS server: ");
logPrintI(Config->aprs_is.server); logPrintI(userConfig->aprs_is.server);
logPrintI(" on port: "); logPrintI(" on port: ");
logPrintlnI(String(Config->aprs_is.port)); logPrintlnI(String(userConfig->aprs_is.port));
show_display("INFO", "Connecting to APRS-IS server"); 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."); logPrintlnE("Connection failed.");
logPrintlnI("Waiting 5 seconds before retrying..."); logPrintlnI("Waiting 5 seconds before retrying...");
@ -224,274 +175,48 @@ void loop()
} }
logPrintlnI("Connected to APRS-IS server!"); 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; aprs_is->getAPRSMessage();
show_display(Config->callsign, timeClient->getFormattedTime() + " LoRa", "RSSI: " + String(lora_aprs->packetRssi()) + ", SNR: " + String(lora_aprs->packetSnr()), msg->toString()); lora_aprs->checkMessage();
logPrintD("[" + timeClient->getFormattedTime() + "] ");
logPrintD(" Received packet '"); if(false) //beacon_aprs_is
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)
{ {
beacon_aprs_is = false; beacon_aprs_is = false;
setup_display(boardConfig); secondsSinceDisplay = 0; display_is_on = true; show_display(userConfig->callsign, "Beacon to APRS-IS Server...");
show_display(Config->callsign, "Beacon to APRS-IS Server..."); logPrintD("[" + ntpClient->getFormattedTime() + "] ");
logPrintD("[" + timeClient->getFormattedTime() + "] ");
logPrintlnD(BeaconMsg->encode()); logPrintlnD(BeaconMsg->encode());
aprs_is->sendMessage(BeaconMsg); 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; std::shared_ptr<LoRa_APRS> lora_aprs = std::shared_ptr<LoRa_APRS>(new LoRa_APRS(boardConfig));
Config = confmg.readConfiguration(); if(!lora_aprs->begin(lora_aprs->getRxFrequency()))
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()))
{ {
logPrintlnE("Starting LoRa failed!"); logPrintlnE("Starting LoRa failed!");
show_display("ERROR", "Starting LoRa failed!"); show_display("ERROR", "Starting LoRa failed!");
while (1); while(true);
} }
lora_aprs->setRxFrequency(Config->lora.frequencyRx); lora_aprs->setRxFrequency(userConfig->lora.frequencyRx);
lora_aprs->setTxFrequency(Config->lora.frequencyTx); lora_aprs->setTxFrequency(userConfig->lora.frequencyTx);
lora_aprs->setTxPower(Config->lora.power); lora_aprs->setTxPower(userConfig->lora.power);
lora_aprs->setSpreadingFactor(Config->lora.spreadingFactor); lora_aprs->setSpreadingFactor(userConfig->lora.spreadingFactor);
lora_aprs->setSignalBandwidth(Config->lora.signalBandwidth); lora_aprs->setSignalBandwidth(userConfig->lora.signalBandwidth);
lora_aprs->setCodingRate4(Config->lora.codingRate4); lora_aprs->setCodingRate4(userConfig->lora.codingRate4);
lora_aprs->enableCrc(); lora_aprs->enableCrc();
logPrintlnI("LoRa init done!"); logPrintlnI("LoRa init done!");
show_display("INFO", "LoRa init done!", 2000); show_display("INFO", "LoRa init done!", 2000);
BeaconMsg = std::shared_ptr<APRSMessage>(new APRSMessage()); BeaconMsg = std::shared_ptr<APRSMessage>(new APRSMessage());
BeaconMsg->setSource(Config->callsign); BeaconMsg->setSource(userConfig->callsign);
BeaconMsg->setDestination("APLG0"); BeaconMsg->setDestination("APLG0");
String lat = create_lat_aprs(Config->beacon.positionLatitude); String lat = create_lat_aprs(userConfig->beacon.positionLatitude);
String lng = create_long_aprs(Config->beacon.positionLongitude); String lng = create_long_aprs(userConfig->beacon.positionLongitude);
BeaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + Config->beacon.message); BeaconMsg->getAPRSBody()->setData(String("=") + lat + "I" + lng + "&" + userConfig->beacon.message);
}
void setup_ntp() return lora_aprs;
{
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!");
} }
String create_lat_aprs(double lat) String create_lat_aprs(double lat)

183
src/connection.cpp 100644
Wyświetl plik

@ -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;
}

19
src/connection.h 100644
Wyświetl plik

@ -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

142
src/display.cpp 100644
Wyświetl plik

@ -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);
}

47
src/display.h 100644
Wyświetl plik

@ -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

Wyświetl plik

@ -3,13 +3,12 @@
#include "project_configuration.h" #include "project_configuration.h"
#include "logger.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")) if(data.containsKey("callsign"))
conf->callsign = data["callsign"].as<String>(); conf->callsign = data["callsign"].as<String>();
conf->wifi.active = data["wifi"]["active"] | false;
JsonArray aps = data["wifi"]["AP"].as<JsonArray>(); JsonArray aps = data["wifi"]["AP"].as<JsonArray>();
for(JsonVariant v : aps) for(JsonVariant v : aps)
{ {
@ -22,7 +21,6 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic
conf->beacon.message = data["beacon"]["message"].as<String>(); conf->beacon.message = data["beacon"]["message"].as<String>();
conf->beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0; conf->beacon.positionLatitude = data["beacon"]["position"]["latitude"] | 0.0;
conf->beacon.positionLongitude = data["beacon"]["position"]["longitude"] | 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")) if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("password"))
conf->aprs_is.password = data["aprs_is"]["password"].as<String>(); conf->aprs_is.password = data["aprs_is"]["password"].as<String>();
if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("server")) if(data.containsKey("aprs_is") && data["aprs_is"].containsKey("server"))
@ -66,10 +64,9 @@ Configuration * ProjectConfigurationManagement::readProjectConfiguration(Dynamic
return conf; return conf;
} }
void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * conf, DynamicJsonDocument & data) void ProjectConfigurationManagement::writeProjectConfiguration(std::shared_ptr<Configuration> conf, DynamicJsonDocument & data)
{ {
data["callsign"] = conf->callsign; data["callsign"] = conf->callsign;
data["wifi"]["active"] = conf->wifi.active;
JsonArray aps = data["wifi"].createNestedArray("AP"); JsonArray aps = data["wifi"].createNestedArray("AP");
for(Configuration::Wifi::AP ap : conf->wifi.APs) 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"]["message"] = conf->beacon.message;
data["beacon"]["position"]["latitude"] = conf->beacon.positionLatitude; data["beacon"]["position"]["latitude"] = conf->beacon.positionLatitude;
data["beacon"]["position"]["longitude"] = conf->beacon.positionLongitude; 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"]["password"] = conf->aprs_is.password;
data["aprs_is"]["server"] = conf->aprs_is.server; data["aprs_is"]["server"] = conf->aprs_is.server;
data["aprs_is"]["port"] = conf->aprs_is.port; data["aprs_is"]["port"] = conf->aprs_is.port;
@ -107,3 +103,23 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration * c
data["board"] = conf->board; 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;
}

Wyświetl plik

@ -2,6 +2,7 @@
#define PROJECT_CONFIGURATION_H_ #define PROJECT_CONFIGURATION_H_
#include "configuration.h" #include "configuration.h"
#include "BoardFinder.h"
class Configuration class Configuration
{ {
@ -16,9 +17,8 @@ public:
String password; String password;
}; };
Wifi() : active(false) {} Wifi() {}
bool active;
std::list<AP> APs; std::list<AP> APs;
}; };
@ -35,9 +35,8 @@ public:
class APRS_IS class APRS_IS
{ {
public: 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 password;
String server; String server;
int port; int port;
@ -104,8 +103,10 @@ public:
virtual ~ProjectConfigurationManagement() {} virtual ~ProjectConfigurationManagement() {}
private: private:
virtual Configuration * readProjectConfiguration(DynamicJsonDocument & data) override; virtual std::shared_ptr<Configuration> readProjectConfiguration(DynamicJsonDocument & data) override;
virtual void writeProjectConfiguration(Configuration * conf, 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 #endif