kopia lustrzana https://github.com/lora-aprs/LoRa_APRS_iGate
Merge branch 'master' into python_test_framework
commit
99be71263a
|
@ -0,0 +1,6 @@
|
|||
ARG VARIANT="3.10-bullseye"
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
|
||||
|
||||
RUN apt-get update && apt-get install -y clang-format-11
|
||||
|
||||
RUN pip3 --disable-pip-version-check --no-cache-dir install platformio
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "Python 3",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"context": "..",
|
||||
"args": {
|
||||
"VARIANT": "3.10-bullseye"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"python.defaultInterpreterPath": "/usr/local/bin/python",
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": true,
|
||||
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
|
||||
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
|
||||
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
|
||||
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
|
||||
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
|
||||
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
|
||||
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
|
||||
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
|
||||
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint",
|
||||
"clang-format.executable": "clang-format-11"
|
||||
},
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"platformio.platformio-ide",
|
||||
"xaver.clang-format"
|
||||
],
|
||||
"postCreateCommand": "pip3 install --user platformio",
|
||||
//"remoteUser": "vscode"
|
||||
}
|
|
@ -1,6 +1,13 @@
|
|||
name: Integreation Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
- '!master'
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
@ -31,8 +38,6 @@ jobs:
|
|||
- 'lib/BoardFinder'
|
||||
- 'lib/ConfigurationManagement'
|
||||
#- 'lib/Display'
|
||||
#- 'lib/LoRa'
|
||||
- 'lib/LoRa_APRS'
|
||||
#- 'lib/NTPClient'
|
||||
- 'lib/PowerManagement'
|
||||
- 'lib/System'
|
||||
|
@ -41,7 +46,7 @@ jobs:
|
|||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Run clang-format style check for C/C++ programs.
|
||||
uses: jidicula/clang-format-action@v3.2.0
|
||||
uses: jidicula/clang-format-action@v4.5.0
|
||||
with:
|
||||
clang-format-version: '11'
|
||||
check-path: ${{ matrix.path }}
|
||||
|
|
|
@ -1,46 +1,39 @@
|
|||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
name: Create new release
|
||||
|
||||
name: Upload Release Assets
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Upload Release Assets
|
||||
version_check:
|
||||
name: Version Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
- run: pip install GitPython
|
||||
- name: check version
|
||||
run: ./scripts/check_version.py
|
||||
|
||||
create_release:
|
||||
needs: version_check
|
||||
name: Create new release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: sudo apt-get install python3-setuptools python3-wheel
|
||||
- run: pip3 install platformio
|
||||
- run: echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- run: platformio run
|
||||
- id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- run: echo "VERSION=$(./scripts/create_version_tag.py)" >> $GITHUB_ENV
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
# upload firmware bin
|
||||
- uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: .pio/build/lora_board/firmware.bin
|
||||
asset_name: lora_board.bin
|
||||
asset_content_type: application/bin
|
||||
# upload json file
|
||||
- uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: data/is-cfg.json
|
||||
asset_name: is-cfg.json
|
||||
asset_content_type: application/json
|
||||
tag: ${{ env.VERSION }}
|
||||
commit: master
|
||||
generateReleaseNotes: true
|
||||
artifacts: ".pio/build/lora_board/firmware.bin,data/is-cfg.json"
|
||||
owner: ${{ secrets.OWNER }}
|
||||
token: ${{ secrets.PAT }}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
name: tweet-release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
tweet:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Eomm/why-don-t-you-tweet@v1
|
||||
if: ${{ !github.event.repository.private }}
|
||||
with:
|
||||
tweet-message: "New ${{ github.event.repository.name }} release ${{ github.event.release.tag_name }}! ${{ github.event.release.html_url }} #LoRa #APRS #HAM #hamradio #iGate"
|
||||
env:
|
||||
TWITTER_CONSUMER_API_KEY: ${{ secrets.TWITTER_CONSUMER_API_KEY }}
|
||||
TWITTER_CONSUMER_API_SECRET: ${{ secrets.TWITTER_CONSUMER_API_SECRET }}
|
||||
TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
|
||||
TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
|
26
README.md
26
README.md
|
@ -18,11 +18,11 @@ Try it out and be part of the APRS network.
|
|||
* [Manuel Lausmann - Tracker](https://www.youtube.com/watch?v=clIlTEFbWLk) (youtube - german - OLD) 02.11.2020
|
||||
* [OE1ROT](https://www.aronaut.at/2019/12/lora-aprs-tracker-mit-ttgo-t-beam-433mhz/) (blog post - german) 09.12.2019
|
||||
|
||||
feel free to add yours or create a ticket if you want to be added.
|
||||
Feel free to add yours or create a ticket if you want to be added.
|
||||
|
||||
## Supported boards
|
||||
|
||||
You can use one of the Lora32 boards without changings:
|
||||
You can use one of the Lora32 boards without changes:
|
||||
|
||||
* Heltec WiFi LoRa 32 V1 (433MHz SX1278)
|
||||
* Heltec WiFi LoRa 32 V2 (433MHz SX1278)
|
||||
|
@ -42,7 +42,7 @@ Here are some amazon-de links for some example boards:
|
|||
* [T-Beam V1.0](https://www.amazon.de/dp/B07RT9FKPL)
|
||||
|
||||
This boards cost around 20 Euros, they are very cheap and perfect for an LoRa iGate.
|
||||
Keep in minde: you need a 433MHz version!
|
||||
Keep in mind: you need a 433MHz version!
|
||||
|
||||
## Compiling and configuration
|
||||
|
||||
|
@ -63,22 +63,12 @@ The best success is to use PlatformIO (and it is the only platform where I can s
|
|||
|
||||
* You can find all nessesary settings to change for your configuration in **data/is-cfg.json**.
|
||||
* To upload it to your board you have to do this via **Upload File System image** in PlatformIO!
|
||||
* To find the 'Upload File System image' click the PlatformIO symbol (the little alien) on the left side, choos your configuration, click on 'Platform' and search for 'Upload File System image'.
|
||||
* To find the 'Upload File System image' click the PlatformIO symbol (the little alien) on the left side, choose your configuration, click on 'Platform' and search for 'Upload File System image'.
|
||||
|
||||
## Branches in this repository and version system
|
||||
|
||||
This firmware is developed in a rolling release system: everyday a new release could be created. But there are still rules where new pull requests has to go and and how the version system looks like.
|
||||
|
||||
### Branches
|
||||
|
||||
There are 2 main branches:
|
||||
* *master* and
|
||||
* *develop*
|
||||
|
||||
The *master* branch has all releases and is the most stable one. With the different tags you can jump to different versions or if you take the most current *master* branch you will just get the latest, stable version. There will be no side releases which are branched of from *master*. If there is a bugfix version it will be done directly on the *master* branch and a tag will be generated with a new version.
|
||||
|
||||
The *develop* branch is used for new feature development. It will be also used to stabilize the current development to create a new stable version (pull request to *master* branch). **Again:** all new development (pull requests) has to go directly into the *develop* branch!
|
||||
|
||||
### Version system
|
||||
|
||||
If the *develop* branch is stable enough for a new release it will be merged with a pull request to the *master* branch and a new version will be generated.
|
||||
|
@ -116,13 +106,15 @@ Look at my other project: a [LoRa Tracker](https://github.com/peterus/LoRa_APRS_
|
|||
|
||||
### Here are some peculiarities of the different boards
|
||||
|
||||
* TTGO T-Beam V1
|
||||
* TTGO T-Beam V1.0 and V1.1 and SSD1306 OLED display
|
||||
|
||||
When adding a 0,96" OLED display direct to the board you have to be careful, there are two different pinout
|
||||
When adding an SSD1306 0,96" OLED display direct to the board you have to be careful, there are two different pinout
|
||||
versions on the market.
|
||||
For direct mount you need a display with this Pinout -> [VCC - GND - SCL - SDA](pics/display-right.jpg).
|
||||
A direct mount of the [other display](pics/display-wrong.jpg) is not possible without damage the display!
|
||||
The 'wrong' display works too but you have to change VCC and GND by wire !
|
||||
|
||||
feel free to add hints!
|
||||
The [LoRa APRS WiKi Displays](https://github.com/lora-aprs/LoRa_APRS_Tracker/wiki/Displays) page has more details.
|
||||
|
||||
Feel free to add hints!
|
||||
|
||||
|
|
|
@ -2,13 +2,20 @@
|
|||
"callsign": "NOCALL-10",
|
||||
"network": {
|
||||
"DHCP": true,
|
||||
"staticIP": "192.0.2.100",
|
||||
"subnet": "255.255.255.0",
|
||||
"gateway": "192.0.2.1",
|
||||
"dns1": "192.0.2.1",
|
||||
"dns2": "192.0.2.2"
|
||||
"static": {
|
||||
"ip": "192.168.0.100",
|
||||
"subnet": "255.255.255.0",
|
||||
"gateway": "192.168.0.1",
|
||||
"dns1": "192.168.0.1",
|
||||
"dns2": "192.168.0.2"
|
||||
},
|
||||
"hostname": {
|
||||
"overwrite": false,
|
||||
"name": "NOCALL-10"
|
||||
}
|
||||
},
|
||||
"wifi": {
|
||||
"active": true,
|
||||
"AP": [
|
||||
{
|
||||
"SSID": "YOURSSID",
|
||||
|
@ -22,6 +29,7 @@
|
|||
"latitude": 0.000000,
|
||||
"longitude": 0.000000
|
||||
},
|
||||
"use_gps": false,
|
||||
"timeout": 15
|
||||
},
|
||||
"aprs_is": {
|
||||
|
@ -36,11 +44,13 @@
|
|||
},
|
||||
"lora": {
|
||||
"frequency_rx": 433775000,
|
||||
"gain_rx": 0,
|
||||
"frequency_tx": 433775000,
|
||||
"power": 20,
|
||||
"spreading_factor": 12,
|
||||
"signal_bandwidth": 125000,
|
||||
"coding_rate4": 5
|
||||
"coding_rate4": 5,
|
||||
"tx_enable": false
|
||||
},
|
||||
"display": {
|
||||
"always_on": true,
|
||||
|
@ -57,5 +67,18 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"mqtt": {
|
||||
"active": false,
|
||||
"server": "",
|
||||
"port": 1883,
|
||||
"name": "",
|
||||
"password": "",
|
||||
"topic": "LoraAPRS/Data"
|
||||
},
|
||||
"syslog": {
|
||||
"active": true,
|
||||
"server": "syslog.lora-aprs.info",
|
||||
"port": 514
|
||||
},
|
||||
"ntp_server": "pool.ntp.org"
|
||||
}
|
||||
|
|
|
@ -8,34 +8,32 @@ void APRS_IS::setup(const String &user, const String &passcode, const String &to
|
|||
_version = version;
|
||||
}
|
||||
|
||||
bool APRS_IS::connect(const String &server, const int port) {
|
||||
APRS_IS::ConnectionStatus 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) {
|
||||
APRS_IS::ConnectionStatus 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) {
|
||||
APRS_IS::ConnectionStatus APRS_IS::_connect(const String &server, const int port, const String &login_line) {
|
||||
if (!_client.connect(server.c_str(), port)) {
|
||||
logPrintlnE("Something went wrong on connecting! Is the server reachable?");
|
||||
return false;
|
||||
return ERROR_CONNECTION;
|
||||
}
|
||||
sendMessage(login_line);
|
||||
while (true) {
|
||||
String line = _client.readStringUntil('\n');
|
||||
if (line.indexOf("logresp") != -1) {
|
||||
if (line.indexOf("unverified") == -1) {
|
||||
return true;
|
||||
return SUCCESS;
|
||||
} else {
|
||||
logPrintlnE("User can not be verified with passcode!");
|
||||
return false;
|
||||
return ERROR_PASSCODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
bool APRS_IS::connected() {
|
||||
|
@ -76,7 +74,6 @@ std::shared_ptr<APRSMessage> APRS_IS::getAPRSMessage() {
|
|||
line = _client.readStringUntil('\n');
|
||||
}
|
||||
if (line.startsWith("#")) {
|
||||
logPrintlnD(line);
|
||||
return 0;
|
||||
}
|
||||
if (line.length() == 0) {
|
||||
|
|
|
@ -9,9 +9,16 @@ class APRS_IS {
|
|||
public:
|
||||
void setup(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 connected();
|
||||
enum ConnectionStatus
|
||||
{
|
||||
SUCCESS,
|
||||
ERROR_CONNECTION,
|
||||
ERROR_PASSCODE,
|
||||
};
|
||||
|
||||
ConnectionStatus connect(const String &server, const int port);
|
||||
ConnectionStatus connect(const String &server, const int port, const String &filter);
|
||||
bool connected();
|
||||
|
||||
bool sendMessage(const String &message);
|
||||
bool sendMessage(const std::shared_ptr<APRSMessage> message);
|
||||
|
@ -28,7 +35,7 @@ private:
|
|||
String _version;
|
||||
WiFiClient _client;
|
||||
|
||||
bool _connect(const String &server, const int port, const String &login_line);
|
||||
ConnectionStatus _connect(const String &server, const int port, const String &login_line);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,19 +2,21 @@
|
|||
#include <logger.h>
|
||||
#include <power_management.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) {
|
||||
#define MODULE_NAME "BoardFinder"
|
||||
|
||||
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, uint8_t gpsrx, uint8_t gpstx, uint8_t button, 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), GpsRx(gpsrx), GpsTx(gpstx), Button(button), needCheckPowerChip(needcheckpowerchip), powerCheckStatus(powercheckstatus) {
|
||||
}
|
||||
|
||||
BoardFinder::BoardFinder(const std::list<BoardConfig const *> &boardConfigs) : _boardConfigs(boardConfigs) {
|
||||
}
|
||||
|
||||
BoardConfig const *BoardFinder::searchBoardConfig() {
|
||||
logPrintlnI("looking for a board config.");
|
||||
logPrintlnI("searching for OLED...");
|
||||
BoardConfig const *BoardFinder::searchBoardConfig(logging::Logger &logger) {
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "looking for a board config.");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "searching for OLED...");
|
||||
|
||||
for (BoardConfig const *boardconf : _boardConfigs) {
|
||||
if (boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus) {
|
||||
if (boardconf->needCheckPowerChip && checkPowerConfig(boardconf, logger) == boardconf->powerCheckStatus) {
|
||||
PowerManagement powerManagement;
|
||||
Wire.begin(boardconf->OledSda, boardconf->OledScl);
|
||||
powerManagement.begin(Wire);
|
||||
|
@ -22,30 +24,28 @@ BoardConfig const *BoardFinder::searchBoardConfig() {
|
|||
} else if (boardconf->needCheckPowerChip) {
|
||||
continue;
|
||||
}
|
||||
if (checkOledConfig(boardconf)) {
|
||||
logPrintI("found a board config: ");
|
||||
logPrintlnI(boardconf->Name);
|
||||
if (checkOledConfig(boardconf, logger)) {
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "found a board config: %s", boardconf->Name.c_str());
|
||||
return boardconf;
|
||||
}
|
||||
}
|
||||
|
||||
logPrintlnI("could not find OLED, will search for the modem now...");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "could not find OLED, will search for the modem now...");
|
||||
|
||||
for (BoardConfig const *boardconf : _boardConfigs) {
|
||||
if (boardconf->needCheckPowerChip && checkPowerConfig(boardconf) == boardconf->powerCheckStatus) {
|
||||
if (boardconf->needCheckPowerChip && checkPowerConfig(boardconf, logger) == boardconf->powerCheckStatus) {
|
||||
PowerManagement powerManagement;
|
||||
Wire.begin(boardconf->OledSda, boardconf->OledScl);
|
||||
powerManagement.begin(Wire);
|
||||
powerManagement.activateLoRa();
|
||||
}
|
||||
if (checkModemConfig(boardconf)) {
|
||||
logPrintI("found a board config: ");
|
||||
logPrintlnI(boardconf->Name);
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "found a board config: %s", boardconf->Name.c_str());
|
||||
return boardconf;
|
||||
}
|
||||
}
|
||||
|
||||
logPrintlnE("could not find a board config!");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, MODULE_NAME, "could not find a board config!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ BoardConfig const *BoardFinder::getBoardConfig(String name) {
|
|||
return *elem;
|
||||
}
|
||||
|
||||
bool BoardFinder::checkOledConfig(BoardConfig const *boardConfig) {
|
||||
bool BoardFinder::checkOledConfig(BoardConfig const *boardConfig, logging::Logger &logger) {
|
||||
if (boardConfig->OledReset > 0) {
|
||||
pinMode(boardConfig->OledReset, OUTPUT);
|
||||
digitalWrite(boardConfig->OledReset, HIGH);
|
||||
|
@ -70,7 +70,7 @@ bool BoardFinder::checkOledConfig(BoardConfig const *boardConfig) {
|
|||
digitalWrite(boardConfig->OledReset, HIGH);
|
||||
}
|
||||
if (!Wire.begin(boardConfig->OledSda, boardConfig->OledScl)) {
|
||||
logPrintlnW("issue with wire");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, MODULE_NAME, "issue with wire");
|
||||
return false;
|
||||
}
|
||||
Wire.beginTransmission(boardConfig->OledAddr);
|
||||
|
@ -107,9 +107,9 @@ bool BoardFinder::checkModemConfig(BoardConfig const *boardConfig) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool BoardFinder::checkPowerConfig(BoardConfig const *boardConfig) {
|
||||
bool BoardFinder::checkPowerConfig(BoardConfig const *boardConfig, logging::Logger &logger) {
|
||||
if (!Wire.begin(boardConfig->OledSda, boardConfig->OledScl)) {
|
||||
logPrintlnW("issue with wire");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, MODULE_NAME, "issue with wire");
|
||||
return false;
|
||||
}
|
||||
Wire.beginTransmission(0x34);
|
||||
|
@ -120,22 +120,22 @@ bool BoardFinder::checkPowerConfig(BoardConfig const *boardConfig) {
|
|||
int response = Wire.read();
|
||||
Wire.endTransmission();
|
||||
|
||||
logPrintlnD(String(response));
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, MODULE_NAME, "wire response: %d", response);
|
||||
if (response == 0x03) {
|
||||
logPrintlnD("power chip found!");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, MODULE_NAME, "power chip found!");
|
||||
return true;
|
||||
}
|
||||
logPrintlnD("power chip NOT found");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, MODULE_NAME, "power chip NOT found");
|
||||
return false;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
BoardConfig TTGO_LORA32_V1 ("TTGO_LORA32_V1", eTTGO_LORA32_V1, 4, 15, 0x3C, 0, 5, 19, 27, 18, 14, 26);
|
||||
BoardConfig TTGO_LORA32_V2 ("TTGO_LORA32_V2", eTTGO_LORA32_V2, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true);
|
||||
BoardConfig TTGO_T_Beam_V0_7 ("TTGO_T_Beam_V0_7", eTTGO_T_Beam_V0_7, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true);
|
||||
BoardConfig TTGO_T_Beam_V1_0 ("TTGO_T_Beam_V1_0", eTTGO_T_Beam_V1_0, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, true, true);
|
||||
BoardConfig ETH_BOARD ("ETH_BOARD", eETH_BOARD, 33, 32, 0x3C, 0, 14, 2, 15, 12, 4, 36);
|
||||
BoardConfig TRACKERD ("TRACKERD", eTRACKERD, 5, 4, 0x3C, 0, 18, 19, 23, 16, 14, 26);
|
||||
BoardConfig HELTEC_WIFI_LORA_32_V1("HELTEC_WIFI_LORA_32_V1", eHELTEC_WIFI_LORA_32_V1, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26);
|
||||
BoardConfig HELTEC_WIFI_LORA_32_V2("HELTEC_WIFI_LORA_32_V2", eHELTEC_WIFI_LORA_32_V2, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26);
|
||||
BoardConfig TTGO_LORA32_V1 ("TTGO_LORA32_V1", eTTGO_LORA32_V1, 4, 15, 0x3C, 0, 5, 19, 27, 18, 14, 26, 0, 0, 0);
|
||||
BoardConfig TTGO_LORA32_V2 ("TTGO_LORA32_V2", eTTGO_LORA32_V2, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, 0, 0, 0, true);
|
||||
BoardConfig TTGO_T_Beam_V0_7 ("TTGO_T_Beam_V0_7", eTTGO_T_Beam_V0_7, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, 15, 12, 38, true);
|
||||
BoardConfig TTGO_T_Beam_V1_0 ("TTGO_T_Beam_V1_0", eTTGO_T_Beam_V1_0, 21, 22, 0x3C, 0, 5, 19, 27, 18, 14, 26, 12, 34, 38, true, true);
|
||||
BoardConfig ETH_BOARD ("ETH_BOARD", eETH_BOARD, 33, 32, 0x3C, 0, 14, 2, 15, 12, 4, 36, 0, 0, 0);
|
||||
BoardConfig TRACKERD ("TRACKERD", eTRACKERD, 5, 4, 0x3C, 0, 18, 19, 23, 16, 14, 26, 0, 0, 0);
|
||||
BoardConfig HELTEC_WIFI_LORA_32_V1("HELTEC_WIFI_LORA_32_V1", eHELTEC_WIFI_LORA_32_V1, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26, 0, 0, 0);
|
||||
BoardConfig HELTEC_WIFI_LORA_32_V2("HELTEC_WIFI_LORA_32_V2", eHELTEC_WIFI_LORA_32_V2, 4, 15, 0x3C, 16, 5, 19, 27, 18, 14, 26, 0, 0, 0);
|
||||
// clang-format on
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
|
||||
#include <logger.h>
|
||||
|
||||
enum BoardType
|
||||
{
|
||||
eHELTEC_WIFI_LORA_32_V1,
|
||||
|
@ -22,7 +24,7 @@ enum BoardType
|
|||
|
||||
class BoardConfig {
|
||||
public:
|
||||
explicit 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);
|
||||
explicit 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, uint8_t gpsrx, uint8_t gpstx, uint8_t button, bool needcheckpowerchip = false, bool powercheckstatus = false);
|
||||
|
||||
String Name;
|
||||
BoardType Type;
|
||||
|
@ -38,6 +40,9 @@ public:
|
|||
uint8_t LoraCS;
|
||||
uint8_t LoraReset;
|
||||
uint8_t LoraIRQ;
|
||||
uint8_t GpsRx;
|
||||
uint8_t GpsTx;
|
||||
uint8_t Button;
|
||||
|
||||
bool needCheckPowerChip;
|
||||
bool powerCheckStatus;
|
||||
|
@ -47,16 +52,16 @@ class BoardFinder {
|
|||
public:
|
||||
explicit BoardFinder(const std::list<BoardConfig const *> &boardConfigs);
|
||||
|
||||
BoardConfig const *searchBoardConfig();
|
||||
BoardConfig const *searchBoardConfig(logging::Logger &logger);
|
||||
|
||||
BoardConfig const *getBoardConfig(String name);
|
||||
|
||||
private:
|
||||
const std::list<BoardConfig const *> &_boardConfigs;
|
||||
|
||||
bool checkOledConfig(BoardConfig const *boardConfig);
|
||||
bool checkOledConfig(BoardConfig const *boardConfig, logging::Logger &logger);
|
||||
bool checkModemConfig(BoardConfig const *boardConfig);
|
||||
bool checkPowerConfig(BoardConfig const *boardConfig);
|
||||
bool checkPowerConfig(BoardConfig const *boardConfig, logging::Logger &logger);
|
||||
};
|
||||
|
||||
extern BoardConfig TTGO_LORA32_V1;
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
#include <SPIFFS.h>
|
||||
#include <logger.h>
|
||||
|
||||
ConfigurationManagement::ConfigurationManagement(String FilePath) : mFilePath(FilePath) {
|
||||
#define MODULE_NAME "ConfigurationManagement"
|
||||
|
||||
ConfigurationManagement::ConfigurationManagement(logging::Logger &logger, String FilePath) : mFilePath(FilePath) {
|
||||
if (!SPIFFS.begin(true)) {
|
||||
logPrintlnI("Mounting SPIFFS was not possible. Trying to format SPIFFS...");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "Mounting SPIFFS was not possible. Trying to format SPIFFS...");
|
||||
SPIFFS.format();
|
||||
if (!SPIFFS.begin()) {
|
||||
logPrintlnE("Formating SPIFFS was not okay!");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, MODULE_NAME, "Formating SPIFFS was not okay!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,16 +17,16 @@ ConfigurationManagement::ConfigurationManagement(String FilePath) : mFilePath(Fi
|
|||
ConfigurationManagement::~ConfigurationManagement() {
|
||||
}
|
||||
|
||||
void ConfigurationManagement::readConfiguration(Configuration &conf) {
|
||||
void ConfigurationManagement::readConfiguration(logging::Logger &logger, Configuration &conf) {
|
||||
File file = SPIFFS.open(mFilePath);
|
||||
if (!file) {
|
||||
logPrintlnE("Failed to open file for reading, using default configuration.");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, MODULE_NAME, "Failed to open file for reading, using default configuration.");
|
||||
return;
|
||||
}
|
||||
DynamicJsonDocument data(2048);
|
||||
DeserializationError error = deserializeJson(data, file);
|
||||
if (error) {
|
||||
logPrintlnW("Failed to read file, using default configuration.");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_WARN, MODULE_NAME, "Failed to read file, using default configuration.");
|
||||
}
|
||||
// serializeJson(data, Serial);
|
||||
// Serial.println();
|
||||
|
@ -33,13 +35,13 @@ void ConfigurationManagement::readConfiguration(Configuration &conf) {
|
|||
readProjectConfiguration(data, conf);
|
||||
|
||||
// update config in memory to get the new fields:
|
||||
writeConfiguration(conf);
|
||||
// writeConfiguration(logger, conf);
|
||||
}
|
||||
|
||||
void ConfigurationManagement::writeConfiguration(Configuration &conf) {
|
||||
void ConfigurationManagement::writeConfiguration(logging::Logger &logger, Configuration &conf) {
|
||||
File file = SPIFFS.open(mFilePath, "w");
|
||||
if (!file) {
|
||||
logPrintlnE("Failed to open file for writing...");
|
||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, MODULE_NAME, "Failed to open file for writing...");
|
||||
return;
|
||||
}
|
||||
DynamicJsonDocument data(2048);
|
||||
|
|
|
@ -9,15 +9,17 @@
|
|||
#include <ArduinoJson.h>
|
||||
#endif
|
||||
|
||||
#include <logger.h>
|
||||
|
||||
class Configuration;
|
||||
|
||||
class ConfigurationManagement {
|
||||
public:
|
||||
explicit ConfigurationManagement(String FilePath);
|
||||
explicit ConfigurationManagement(logging::Logger &logger, String FilePath);
|
||||
virtual ~ConfigurationManagement();
|
||||
|
||||
void readConfiguration(Configuration &conf);
|
||||
void writeConfiguration(Configuration &conf);
|
||||
void readConfiguration(logging::Logger &logger, Configuration &conf);
|
||||
void writeConfiguration(logging::Logger &logger, Configuration &conf);
|
||||
|
||||
private:
|
||||
virtual void readProjectConfiguration(DynamicJsonDocument &data, Configuration &conf) = 0;
|
||||
|
|
|
@ -1,673 +0,0 @@
|
|||
// 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;
|
||||
}
|
119
lib/LoRa/LoRa.h
119
lib/LoRa/LoRa.h
|
@ -1,119 +0,0 @@
|
|||
// 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
|
|
@ -1,65 +0,0 @@
|
|||
#include "LoRa_APRS.h"
|
||||
|
||||
LoRa_APRS::LoRa_APRS() : _RxFrequency(433775000), _TxFrequency(433775000) {
|
||||
}
|
||||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<APRSMessage> LoRa_APRS::getMessage() {
|
||||
return _LastReceivedMsg;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// cppcheck-suppress unusedFunction
|
||||
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;
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef LORA_H_
|
||||
#define LORA_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <APRS-Decoder.h>
|
||||
#include <LoRa.h>
|
||||
#include <memory>
|
||||
|
||||
class LoRa_APRS : public LoRaClass {
|
||||
public:
|
||||
LoRa_APRS();
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
std::shared_ptr<APRSMessage> _LastReceivedMsg;
|
||||
long _RxFrequency;
|
||||
long _TxFrequency;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -17,7 +17,7 @@ class NTPClient {
|
|||
unsigned int _port = NTP_DEFAULT_LOCAL_PORT;
|
||||
long _timeOffset = 0;
|
||||
|
||||
unsigned long _updateInterval = 60000; // In ms
|
||||
unsigned long _updateInterval = 3600000; // In ms
|
||||
|
||||
unsigned long _currentEpoc = 0; // In s
|
||||
unsigned long _lastUpdate = 0; // In ms
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
#include "System.h"
|
||||
|
||||
System::System() : _boardConfig(0), _userConfig(0), _isWifiEthConnected(false) {
|
||||
System::System() : _boardConfig(0), _userConfig(0), _isEthConnected(false), _isWifiConnected(false) {
|
||||
}
|
||||
|
||||
System::~System() {
|
||||
|
@ -31,10 +31,18 @@ Display &System::getDisplay() {
|
|||
return _display;
|
||||
}
|
||||
|
||||
bool System::isWifiEthConnected() const {
|
||||
return _isWifiEthConnected;
|
||||
bool System::isWifiOrEthConnected() const {
|
||||
return _isEthConnected || _isWifiConnected;
|
||||
}
|
||||
|
||||
void System::connectedViaWifiEth(bool status) {
|
||||
_isWifiEthConnected = status;
|
||||
void System::connectedViaEth(bool status) {
|
||||
_isEthConnected = status;
|
||||
}
|
||||
|
||||
void System::connectedViaWifi(bool status) {
|
||||
_isWifiConnected = status;
|
||||
}
|
||||
|
||||
logging::Logger &System::getLogger() {
|
||||
return _logger;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef SYSTEM_H_
|
||||
#define SYSTEM_H_
|
||||
|
||||
#include <logger.h>
|
||||
#include <memory>
|
||||
|
||||
#include "TaskManager.h"
|
||||
|
@ -20,15 +21,19 @@ public:
|
|||
Configuration const *const getUserConfig() const;
|
||||
TaskManager & getTaskManager();
|
||||
Display & getDisplay();
|
||||
bool isWifiEthConnected() const;
|
||||
void connectedViaWifiEth(bool status);
|
||||
bool isWifiOrEthConnected() const;
|
||||
void connectedViaEth(bool status);
|
||||
void connectedViaWifi(bool status);
|
||||
logging::Logger & getLogger();
|
||||
|
||||
private:
|
||||
BoardConfig const * _boardConfig;
|
||||
Configuration const *_userConfig;
|
||||
TaskManager _taskManager;
|
||||
Display _display;
|
||||
bool _isWifiEthConnected;
|
||||
bool _isEthConnected;
|
||||
bool _isWifiConnected;
|
||||
logging::Logger _logger;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#include <FontConfig.h>
|
||||
#include <logger.h>
|
||||
|
||||
#define MODULE_NAME "TaskManager"
|
||||
|
||||
TaskManager::TaskManager() {
|
||||
}
|
||||
|
||||
|
@ -20,15 +22,13 @@ std::list<Task *> TaskManager::getTasks() {
|
|||
}
|
||||
|
||||
bool TaskManager::setup(System &system) {
|
||||
logPrintlnV("will setup all tasks...");
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "will setup all tasks...");
|
||||
for (Task *elem : _alwaysRunTasks) {
|
||||
logPrintD("call setup from ");
|
||||
logPrintlnD(elem->getName());
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, MODULE_NAME, "call setup for %s", elem->getName().c_str());
|
||||
elem->setup(system);
|
||||
}
|
||||
for (Task *elem : _tasks) {
|
||||
logPrintD("call setup from ");
|
||||
logPrintlnD(elem->getName());
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, MODULE_NAME, "call setup for %s", elem->getName().c_str());
|
||||
elem->setup(system);
|
||||
}
|
||||
_nextTask = _tasks.begin();
|
||||
|
@ -36,10 +36,7 @@ bool TaskManager::setup(System &system) {
|
|||
}
|
||||
|
||||
bool TaskManager::loop(System &system) {
|
||||
// logPrintlnD("will loop all tasks...");
|
||||
for (Task *elem : _alwaysRunTasks) {
|
||||
// logPrintD("call loop from ");
|
||||
// logPrintlnD(elem->getName());
|
||||
elem->loop(system);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,12 @@ lib_deps =
|
|||
bblanchon/ArduinoJson @ 6.17.0
|
||||
lewisxhe/AXP202X_Library @ 1.1.2
|
||||
peterus/APRS-Decoder-Lib @ 0.0.6
|
||||
peterus/esp-logger @ 0.0.1
|
||||
peterus/esp-logger @ 1.0.0
|
||||
peterus/ESP-FTP-Server-Lib @ 0.9.5
|
||||
knolleary/PubSubClient@^2.8
|
||||
mikalhart/TinyGPSPlus @ 1.0.2
|
||||
shaggydog/OneButton @ 1.5.0
|
||||
jgromes/RadioLib @ 5.1.2
|
||||
check_tool = cppcheck
|
||||
check_flags =
|
||||
cppcheck: --suppress=*:*.pio\* --inline-suppr -DCPPCHECK --force lib -ilib/TimeLib -ilib/LoRa -ilib/NTPClient
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import git
|
||||
from datetime import date
|
||||
|
||||
today = date.today()
|
||||
|
||||
current_year = int(str(today.isocalendar()[0])[2:])
|
||||
current_week = int(today.isocalendar()[1])
|
||||
|
||||
version = None
|
||||
with open("src/LoRa_APRS_iGate.cpp") as f:
|
||||
for line in f:
|
||||
if line.startswith("#define VERSION"):
|
||||
version = line.strip().split(" ")[-1].replace('"', "")
|
||||
|
||||
version_split = version.split(".")
|
||||
version_year = int(version_split[0])
|
||||
version_week = int(version_split[1])
|
||||
version_vers = int(version_split[2])
|
||||
|
||||
print(f"[INFO] firmware version year: {version_year}")
|
||||
print(f"[INFO] firmware version week: {version_week}")
|
||||
print(f"[INFO] firmware version version: {version_vers}")
|
||||
print(f"[INFO] -> {version}")
|
||||
|
||||
print(f"[INFO] current year: {current_year}")
|
||||
print(f"[INFO] current week: {current_week}")
|
||||
print(f"[INFO] -> {current_year}.{current_week}.x")
|
||||
|
||||
error = False
|
||||
if version_year != current_year:
|
||||
print("[ERROR] firmware version is not current year!")
|
||||
error = True
|
||||
|
||||
if version_week != current_week:
|
||||
print("[ERROR] firmware version is not current week!")
|
||||
error = True
|
||||
|
||||
repo = git.Repo('.')
|
||||
print(f"[INFO] found {len(repo.tags)} tags in repo")
|
||||
if f"v{version}" in repo.tags:
|
||||
print("[ERROR] tag with this version is already existing")
|
||||
error = True
|
||||
|
||||
if error:
|
||||
print("[ERROR] check/update VERSION define in src/LoRa_APRS_iGate.cpp to fix this issue")
|
||||
|
||||
exit(error)
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from datetime import date
|
||||
|
||||
today = date.today()
|
||||
|
||||
current_year = int(str(today.isocalendar()[0])[2:])
|
||||
current_week = int(today.isocalendar()[1])
|
||||
|
||||
version = None
|
||||
with open("src/LoRa_APRS_iGate.cpp") as f:
|
||||
for line in f:
|
||||
if line.startswith("#define VERSION"):
|
||||
version = line.strip().split(" ")[-1].replace('"', "")
|
||||
|
||||
version_split = version.split(".")
|
||||
version_year = int(version_split[0])
|
||||
version_week = int(version_split[1])
|
||||
version_vers = int(version_split[2])
|
||||
|
||||
print(f"v{version_year}.{version_week}.{version_vers}")
|
|
@ -8,17 +8,20 @@
|
|||
#include <power_management.h>
|
||||
|
||||
#include "TaskAprsIs.h"
|
||||
#include "TaskBeacon.h"
|
||||
#include "TaskDisplay.h"
|
||||
#include "TaskEth.h"
|
||||
#include "TaskFTP.h"
|
||||
#include "TaskModem.h"
|
||||
#include "TaskMQTT.h"
|
||||
#include "TaskNTP.h"
|
||||
#include "TaskOTA.h"
|
||||
#include "TaskRadiolib.h"
|
||||
#include "TaskRouter.h"
|
||||
#include "TaskWifi.h"
|
||||
#include "project_configuration.h"
|
||||
|
||||
#define VERSION "21.35.0-dev"
|
||||
#define VERSION "22.20.0"
|
||||
#define MODULE_NAME "Main"
|
||||
|
||||
String create_lat_aprs(double lat);
|
||||
String create_long_aprs(double lng);
|
||||
|
@ -26,26 +29,31 @@ String create_long_aprs(double lng);
|
|||
TaskQueue<std::shared_ptr<APRSMessage>> toAprsIs;
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> fromModem;
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> toModem;
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> toMQTT;
|
||||
|
||||
System LoRaSystem;
|
||||
Configuration userConfig;
|
||||
|
||||
DisplayTask displayTask;
|
||||
ModemTask modemTask(fromModem, toModem);
|
||||
EthTask ethTask;
|
||||
WifiTask wifiTask;
|
||||
OTATask otaTask;
|
||||
NTPTask ntpTask;
|
||||
FTPTask ftpTask;
|
||||
AprsIsTask aprsIsTask(toAprsIs);
|
||||
RouterTask routerTask(fromModem, toModem, toAprsIs);
|
||||
// ModemTask modemTask(fromModem, toModem);
|
||||
RadiolibTask modemTask(fromModem, toModem);
|
||||
EthTask ethTask;
|
||||
WifiTask wifiTask;
|
||||
OTATask otaTask;
|
||||
NTPTask ntpTask;
|
||||
FTPTask ftpTask;
|
||||
MQTTTask mqttTask(toMQTT);
|
||||
AprsIsTask aprsIsTask(toAprsIs);
|
||||
RouterTask routerTask(fromModem, toModem, toAprsIs, toMQTT);
|
||||
BeaconTask beaconTask(toModem, toAprsIs);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Logger::instance().setSerial(&Serial);
|
||||
LoRaSystem.getLogger().setSerial(&Serial);
|
||||
setWiFiLogger(&LoRaSystem.getLogger());
|
||||
delay(500);
|
||||
logPrintlnI("LoRa APRS iGate by OE5BPA (Peter Buchegger)");
|
||||
logPrintlnI("Version: " VERSION);
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "LoRa APRS iGate by OE5BPA (Peter Buchegger)");
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "Version: %s", VERSION);
|
||||
|
||||
std::list<BoardConfig const *> boardConfigs;
|
||||
boardConfigs.push_back(&TTGO_LORA32_V1);
|
||||
|
@ -57,40 +65,42 @@ void setup() {
|
|||
boardConfigs.push_back(&HELTEC_WIFI_LORA_32_V1);
|
||||
boardConfigs.push_back(&HELTEC_WIFI_LORA_32_V2);
|
||||
|
||||
ProjectConfigurationManagement confmg;
|
||||
confmg.readConfiguration(userConfig);
|
||||
ProjectConfigurationManagement confmg(LoRaSystem.getLogger());
|
||||
confmg.readConfiguration(LoRaSystem.getLogger(), userConfig);
|
||||
|
||||
BoardFinder finder(boardConfigs);
|
||||
BoardConfig const *boardConfig = finder.getBoardConfig(userConfig.board);
|
||||
if (!boardConfig) {
|
||||
boardConfig = finder.searchBoardConfig();
|
||||
boardConfig = finder.searchBoardConfig(LoRaSystem.getLogger());
|
||||
if (!boardConfig) {
|
||||
logPrintlnE("Board config not set and search failed!");
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, MODULE_NAME, "Board config not set and search failed!");
|
||||
while (true)
|
||||
;
|
||||
} else {
|
||||
userConfig.board = boardConfig->Name;
|
||||
confmg.writeConfiguration(userConfig);
|
||||
logPrintlnI("will restart board now!");
|
||||
confmg.writeConfiguration(LoRaSystem.getLogger(), userConfig);
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "will restart board now!");
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
|
||||
logPrintI("Board ");
|
||||
logPrintI(boardConfig->Name);
|
||||
logPrintlnI(" loaded.");
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "Board %s loaded.", boardConfig->Name.c_str());
|
||||
|
||||
if (boardConfig->Type == eTTGO_T_Beam_V1_0) {
|
||||
Wire.begin(boardConfig->OledSda, boardConfig->OledScl);
|
||||
PowerManagement powerManagement;
|
||||
if (!powerManagement.begin(Wire)) {
|
||||
logPrintlnI("AXP192 init done!");
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "AXP192 init done!");
|
||||
} else {
|
||||
logPrintlnE("AXP192 init failed!");
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, MODULE_NAME, "AXP192 init failed!");
|
||||
}
|
||||
powerManagement.activateLoRa();
|
||||
powerManagement.activateOLED();
|
||||
powerManagement.deactivateGPS();
|
||||
if (userConfig.beacon.use_gps) {
|
||||
powerManagement.activateGPS();
|
||||
} else {
|
||||
powerManagement.deactivateGPS();
|
||||
}
|
||||
}
|
||||
|
||||
LoRaSystem.setBoardConfig(boardConfig);
|
||||
|
@ -98,19 +108,33 @@ void setup() {
|
|||
LoRaSystem.getTaskManager().addTask(&displayTask);
|
||||
LoRaSystem.getTaskManager().addTask(&modemTask);
|
||||
LoRaSystem.getTaskManager().addTask(&routerTask);
|
||||
LoRaSystem.getTaskManager().addTask(&beaconTask);
|
||||
|
||||
if (userConfig.aprs_is.active) {
|
||||
if (boardConfig->Type == eETH_BOARD) {
|
||||
LoRaSystem.getTaskManager().addAlwaysRunTask(ðTask);
|
||||
} else {
|
||||
LoRaSystem.getTaskManager().addAlwaysRunTask(&wifiTask);
|
||||
}
|
||||
bool tcpip = false;
|
||||
|
||||
if (userConfig.wifi.active) {
|
||||
LoRaSystem.getTaskManager().addAlwaysRunTask(&wifiTask);
|
||||
tcpip = true;
|
||||
}
|
||||
if (boardConfig->Type == eETH_BOARD) {
|
||||
LoRaSystem.getTaskManager().addAlwaysRunTask(ðTask);
|
||||
tcpip = true;
|
||||
}
|
||||
|
||||
if (tcpip) {
|
||||
LoRaSystem.getTaskManager().addTask(&otaTask);
|
||||
LoRaSystem.getTaskManager().addTask(&ntpTask);
|
||||
if (userConfig.ftp.active) {
|
||||
LoRaSystem.getTaskManager().addTask(&ftpTask);
|
||||
}
|
||||
LoRaSystem.getTaskManager().addTask(&aprsIsTask);
|
||||
|
||||
if (userConfig.aprs_is.active) {
|
||||
LoRaSystem.getTaskManager().addTask(&aprsIsTask);
|
||||
}
|
||||
|
||||
if (userConfig.mqtt.active) {
|
||||
LoRaSystem.getTaskManager().addTask(&mqttTask);
|
||||
}
|
||||
}
|
||||
|
||||
LoRaSystem.getTaskManager().setup(LoRaSystem);
|
||||
|
@ -118,13 +142,13 @@ void setup() {
|
|||
LoRaSystem.getDisplay().showSpashScreen("LoRa APRS iGate", VERSION);
|
||||
|
||||
if (userConfig.callsign == "NOCALL-10") {
|
||||
logPrintlnE("You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!");
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, MODULE_NAME, "You have to change your settings in 'data/is-cfg.json' and upload it via 'Upload File System image'!");
|
||||
LoRaSystem.getDisplay().showStatusScreen("ERROR", "You have to change your settings in 'data/is-cfg.json' and upload it via \"Upload File System image\"!");
|
||||
while (true)
|
||||
;
|
||||
}
|
||||
if ((!userConfig.aprs_is.active) && !(userConfig.digi.active)) {
|
||||
logPrintlnE("No mode selected (iGate or Digi)! You have to activate one of iGate or Digi.");
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, MODULE_NAME, "No mode selected (iGate or Digi)! You have to activate one of iGate or Digi.");
|
||||
LoRaSystem.getDisplay().showStatusScreen("ERROR", "No mode selected (iGate or Digi)! You have to activate one of iGate or Digi.");
|
||||
while (true)
|
||||
;
|
||||
|
@ -136,33 +160,16 @@ void setup() {
|
|||
}
|
||||
|
||||
delay(5000);
|
||||
logPrintlnI("setup done...");
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "setup done...");
|
||||
}
|
||||
|
||||
volatile bool syslogSet = false;
|
||||
|
||||
void loop() {
|
||||
LoRaSystem.getTaskManager().loop(LoRaSystem);
|
||||
}
|
||||
|
||||
String create_lat_aprs(double lat) {
|
||||
char str[20];
|
||||
char n_s = 'N';
|
||||
if (lat < 0) {
|
||||
n_s = 'S';
|
||||
if (LoRaSystem.isWifiOrEthConnected() && LoRaSystem.getUserConfig()->syslog.active && !syslogSet) {
|
||||
LoRaSystem.getLogger().setSyslogServer(LoRaSystem.getUserConfig()->syslog.server, LoRaSystem.getUserConfig()->syslog.port, LoRaSystem.getUserConfig()->callsign);
|
||||
LoRaSystem.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, MODULE_NAME, "System connected after a restart to the network, syslog server set");
|
||||
syslogSet = true;
|
||||
}
|
||||
lat = std::abs(lat);
|
||||
sprintf(str, "%02d%05.2f%c", (int)lat, (lat - (double)((int)lat)) * 60.0, n_s);
|
||||
String lat_str(str);
|
||||
return lat_str;
|
||||
}
|
||||
|
||||
String create_long_aprs(double lng) {
|
||||
char str[20];
|
||||
char e_w = 'E';
|
||||
if (lng < 0) {
|
||||
e_w = 'W';
|
||||
}
|
||||
lng = std::abs(lng);
|
||||
sprintf(str, "%03d%05.2f%c", (int)lng, (lng - (double)((int)lng)) * 60.0, e_w);
|
||||
String lng_str(str);
|
||||
return lng_str;
|
||||
}
|
||||
|
|
24
src/Task.h
24
src/Task.h
|
@ -7,20 +7,26 @@ enum TaskNames
|
|||
TaskEth,
|
||||
TaskFtp,
|
||||
TaskModem,
|
||||
TaskRadiolib,
|
||||
TaskNtp,
|
||||
TaskOta,
|
||||
TaskWifi,
|
||||
TaskRouter,
|
||||
TaskSize,
|
||||
TaskMQTT,
|
||||
TaskBeacon,
|
||||
TaskSize
|
||||
};
|
||||
|
||||
#define TASK_APRS_IS "AprsIsTask"
|
||||
#define TASK_ETH "EthTask"
|
||||
#define TASK_FTP "FTPTask"
|
||||
#define TASK_MODEM "ModemTask"
|
||||
#define TASK_NTP "NTPTask"
|
||||
#define TASK_OTA "OTATask"
|
||||
#define TASK_WIFI "WifiTask"
|
||||
#define TASK_ROUTER "RouterTask"
|
||||
#define TASK_APRS_IS "AprsIsTask"
|
||||
#define TASK_ETH "EthTask"
|
||||
#define TASK_FTP "FTPTask"
|
||||
#define TASK_MODEM "ModemTask"
|
||||
#define TASK_RADIOLIB "RadiolibTask"
|
||||
#define TASK_NTP "NTPTask"
|
||||
#define TASK_OTA "OTATask"
|
||||
#define TASK_WIFI "WifiTask"
|
||||
#define TASK_ROUTER "RouterTask"
|
||||
#define TASK_MQTT "MQTTTask"
|
||||
#define TASK_BEACON "BeaconTask"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,7 +16,7 @@ bool AprsIsTask::setup(System &system) {
|
|||
}
|
||||
|
||||
bool AprsIsTask::loop(System &system) {
|
||||
if (!system.isWifiEthConnected()) {
|
||||
if (!system.isWifiOrEthConnected()) {
|
||||
return false;
|
||||
}
|
||||
if (!_aprs_is.connected()) {
|
||||
|
@ -40,15 +40,18 @@ bool AprsIsTask::loop(System &system) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool AprsIsTask::connect(const System &system) {
|
||||
logPrintI("connecting to APRS-IS server: ");
|
||||
logPrintI(system.getUserConfig()->aprs_is.server);
|
||||
logPrintI(" on port: ");
|
||||
logPrintlnI(String(system.getUserConfig()->aprs_is.port));
|
||||
if (!_aprs_is.connect(system.getUserConfig()->aprs_is.server, system.getUserConfig()->aprs_is.port)) {
|
||||
logPrintlnE("Connection failed.");
|
||||
bool AprsIsTask::connect(System &system) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "connecting to APRS-IS server: %s on port: %d", system.getUserConfig()->aprs_is.server.c_str(), system.getUserConfig()->aprs_is.port);
|
||||
APRS_IS::ConnectionStatus status = _aprs_is.connect(system.getUserConfig()->aprs_is.server, system.getUserConfig()->aprs_is.port);
|
||||
if (status == APRS_IS::ERROR_CONNECTION) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "Something went wrong on connecting! Is the server reachable?");
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "Connection failed.");
|
||||
return false;
|
||||
} else if (status == APRS_IS::ERROR_PASSCODE) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "User can not be verified with passcode!");
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "Connection failed.");
|
||||
return false;
|
||||
}
|
||||
logPrintlnI("Connected to APRS-IS server!");
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "Connected to APRS-IS server!");
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ private:
|
|||
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_toAprsIs;
|
||||
|
||||
bool connect(const System &system);
|
||||
bool connect(System &system);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
#include <logger.h>
|
||||
|
||||
#include <OneButton.h>
|
||||
#include <TimeLib.h>
|
||||
|
||||
#include "Task.h"
|
||||
#include "TaskBeacon.h"
|
||||
#include "project_configuration.h"
|
||||
|
||||
BeaconTask::BeaconTask(TaskQueue<std::shared_ptr<APRSMessage>> &toModem, TaskQueue<std::shared_ptr<APRSMessage>> &toAprsIs) : Task(TASK_BEACON, TaskBeacon), _toModem(toModem), _toAprsIs(toAprsIs), _ss(1), _useGps(false) {
|
||||
}
|
||||
|
||||
BeaconTask::~BeaconTask() {
|
||||
}
|
||||
|
||||
OneButton BeaconTask::_userButton;
|
||||
bool BeaconTask::_send_update;
|
||||
uint BeaconTask::_instances;
|
||||
|
||||
void BeaconTask::pushButton() {
|
||||
_send_update = true;
|
||||
}
|
||||
|
||||
bool BeaconTask::setup(System &system) {
|
||||
if (_instances++ == 0 && system.getBoardConfig()->Button > 0) {
|
||||
_userButton = OneButton(system.getBoardConfig()->Button, true, true);
|
||||
_userButton.attachClick(pushButton);
|
||||
_send_update = false;
|
||||
}
|
||||
|
||||
_useGps = system.getUserConfig()->beacon.use_gps;
|
||||
|
||||
if (_useGps) {
|
||||
if (system.getBoardConfig()->GpsRx != 0) {
|
||||
_ss.begin(9600, SERIAL_8N1, system.getBoardConfig()->GpsTx, system.getBoardConfig()->GpsRx);
|
||||
} else {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "NO GPS found.");
|
||||
_useGps = false;
|
||||
}
|
||||
}
|
||||
// setup beacon
|
||||
_beacon_timer.setTimeout(system.getUserConfig()->beacon.timeout * 60 * 1000);
|
||||
|
||||
_beaconMsg = std::shared_ptr<APRSMessage>(new APRSMessage());
|
||||
_beaconMsg->setSource(system.getUserConfig()->callsign);
|
||||
_beaconMsg->setDestination("APLG01");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BeaconTask::loop(System &system) {
|
||||
if (_useGps) {
|
||||
while (_ss.available() > 0) {
|
||||
char c = _ss.read();
|
||||
_gps.encode(c);
|
||||
}
|
||||
}
|
||||
|
||||
_userButton.tick();
|
||||
|
||||
// check for beacon
|
||||
if (_beacon_timer.check() || _send_update) {
|
||||
if (sendBeacon(system)) {
|
||||
_send_update = false;
|
||||
_beacon_timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t diff = _beacon_timer.getTriggerTimeInSec();
|
||||
_stateInfo = "beacon " + String(uint32_t(diff / 600)) + String(uint32_t(diff / 60) % 10) + ":" + String(uint32_t(diff / 10) % 6) + String(uint32_t(diff % 10));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String create_lat_aprs(double lat) {
|
||||
char str[20];
|
||||
char n_s = 'N';
|
||||
if (lat < 0) {
|
||||
n_s = 'S';
|
||||
}
|
||||
lat = std::abs(lat);
|
||||
sprintf(str, "%02d%05.2f%c", (int)lat, (lat - (double)((int)lat)) * 60.0, n_s);
|
||||
String lat_str(str);
|
||||
return lat_str;
|
||||
}
|
||||
|
||||
String create_long_aprs(double lng) {
|
||||
char str[20];
|
||||
char e_w = 'E';
|
||||
if (lng < 0) {
|
||||
e_w = 'W';
|
||||
}
|
||||
lng = std::abs(lng);
|
||||
sprintf(str, "%03d%05.2f%c", (int)lng, (lng - (double)((int)lng)) * 60.0, e_w);
|
||||
String lng_str(str);
|
||||
return lng_str;
|
||||
}
|
||||
|
||||
bool BeaconTask::sendBeacon(System &system) {
|
||||
double lat = system.getUserConfig()->beacon.positionLatitude;
|
||||
double lng = system.getUserConfig()->beacon.positionLongitude;
|
||||
|
||||
if (_useGps) {
|
||||
if (_gps.location.isUpdated()) {
|
||||
lat = _gps.location.lat();
|
||||
lng = _gps.location.lng();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_beaconMsg->getBody()->setData(String("=") + create_lat_aprs(lat) + "L" + create_long_aprs(lng) + "&" + system.getUserConfig()->beacon.message);
|
||||
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "[%s] %s", timeString().c_str(), _beaconMsg->encode().c_str());
|
||||
|
||||
if (system.getUserConfig()->aprs_is.active) {
|
||||
_toAprsIs.addElement(_beaconMsg);
|
||||
}
|
||||
|
||||
if (system.getUserConfig()->digi.beacon) {
|
||||
_toModem.addElement(_beaconMsg);
|
||||
}
|
||||
|
||||
system.getDisplay().addFrame(std::shared_ptr<DisplayFrame>(new TextFrame("BEACON", _beaconMsg->toString())));
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef TASK_BEACON_H_
|
||||
#define TASK_BEACON_H_
|
||||
|
||||
#include <OneButton.h>
|
||||
#include <TinyGPS++.h>
|
||||
|
||||
#include <APRSMessage.h>
|
||||
#include <TaskMQTT.h>
|
||||
#include <TaskManager.h>
|
||||
|
||||
class BeaconTask : public Task {
|
||||
public:
|
||||
BeaconTask(TaskQueue<std::shared_ptr<APRSMessage>> &toModem, TaskQueue<std::shared_ptr<APRSMessage>> &toAprsIs);
|
||||
virtual ~BeaconTask();
|
||||
|
||||
virtual bool setup(System &system) override;
|
||||
virtual bool loop(System &system) override;
|
||||
bool sendBeacon(System &system);
|
||||
|
||||
private:
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_toModem;
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_toAprsIs;
|
||||
|
||||
std::shared_ptr<APRSMessage> _beaconMsg;
|
||||
Timer _beacon_timer;
|
||||
|
||||
HardwareSerial _ss;
|
||||
TinyGPSPlus _gps;
|
||||
bool _useGps;
|
||||
|
||||
static uint _instances;
|
||||
static OneButton _userButton;
|
||||
static bool _send_update;
|
||||
static void pushButton();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -6,66 +6,62 @@
|
|||
#include "TaskEth.h"
|
||||
#include "project_configuration.h"
|
||||
|
||||
volatile bool eth_connected = false;
|
||||
#define WIFI_EVENT "WiFiEvent"
|
||||
|
||||
volatile bool eth_connected = false;
|
||||
logging::Logger *_logger;
|
||||
|
||||
void setWiFiLogger(logging::Logger *logger) {
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event) {
|
||||
switch (event) {
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
logPrintlnI("WiFi Started");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi Started");
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_CONNECTED:
|
||||
logPrintlnI("WiFi Connected");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi Connected");
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
logPrintI("WiFi MAC: ");
|
||||
logPrintI(WiFi.macAddress());
|
||||
logPrintI(", IPv4: ");
|
||||
logPrintI(WiFi.localIP().toString());
|
||||
logPrintI(", Gateway: ");
|
||||
logPrintI(WiFi.gatewayIP().toString());
|
||||
logPrintI(", DNS1: ");
|
||||
logPrintI(WiFi.dnsIP().toString());
|
||||
logPrintI(", DNS2: ");
|
||||
logPrintlnI(WiFi.dnsIP(1).toString());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi MAC: %s", WiFi.macAddress().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi IPv4: %s", WiFi.localIP().toString().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi Gateway: %s", WiFi.gatewayIP().toString().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi DNS1: %s", WiFi.dnsIP().toString().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi DNS2: %s", WiFi.dnsIP(1).toString().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi Hostname: %s", WiFi.getHostname());
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
logPrintlnW("WiFi Disconnected");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi Disconnected");
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_STOP:
|
||||
logPrintlnW("WiFi Stopped");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "WiFi Stopped");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_START:
|
||||
logPrintlnI("ETH Started");
|
||||
ETH.setHostname("esp32-ethernet");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH Started");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_CONNECTED:
|
||||
logPrintlnI("ETH Connected");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH Connected");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||
logPrintI("ETH MAC: ");
|
||||
logPrintI(ETH.macAddress());
|
||||
logPrintI(", IPv4: ");
|
||||
logPrintI(ETH.localIP().toString());
|
||||
logPrintI(", Gateway: ");
|
||||
logPrintI(ETH.gatewayIP().toString());
|
||||
logPrintI(", DNS1: ");
|
||||
logPrintI(ETH.dnsIP().toString());
|
||||
logPrintI(", DNS2: ");
|
||||
logPrintI(ETH.dnsIP(1).toString());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH MAC: %s", ETH.macAddress().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH IPv4: %s", ETH.localIP().toString().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH Gateway: %s", ETH.gatewayIP().toString().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH DNS1: %s", ETH.dnsIP().toString().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH DNS2: %s", ETH.dnsIP(1).toString().c_str());
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH Hostname: %s", ETH.getHostname());
|
||||
if (ETH.fullDuplex()) {
|
||||
logPrintI(", FULL_DUPLEX");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH FULL_DUPLEX");
|
||||
}
|
||||
logPrintI(", ");
|
||||
logPrintI(String(ETH.linkSpeed()));
|
||||
logPrintlnI("Mbps");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_INFO, WIFI_EVENT, "ETH Speed: %dMbps", ETH.linkSpeed());
|
||||
eth_connected = true;
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||
logPrintlnW("ETH Disconnected");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_WARN, WIFI_EVENT, "ETH Disconnected");
|
||||
eth_connected = false;
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_STOP:
|
||||
logPrintlnW("ETH Stopped");
|
||||
_logger->log(logging::LoggerLevel::LOGGER_LEVEL_WARN, WIFI_EVENT, "ETH Stopped");
|
||||
eth_connected = false;
|
||||
break;
|
||||
default:
|
||||
|
@ -100,22 +96,28 @@ bool EthTask::setup(System &system) {
|
|||
delay(200);
|
||||
digitalWrite(ETH_NRST, 1);
|
||||
|
||||
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK);
|
||||
|
||||
if (!system.getUserConfig()->network.DHCP) {
|
||||
ETH.config(system.getUserConfig()->network.staticIP, system.getUserConfig()->network.gateway, system.getUserConfig()->network.subnet, system.getUserConfig()->network.dns1, system.getUserConfig()->network.dns2);
|
||||
ETH.config(system.getUserConfig()->network.static_.ip, system.getUserConfig()->network.static_.gateway, system.getUserConfig()->network.static_.subnet, system.getUserConfig()->network.static_.dns1, system.getUserConfig()->network.static_.dns2);
|
||||
}
|
||||
if (system.getUserConfig()->network.hostname.overwrite) {
|
||||
ETH.setHostname(system.getUserConfig()->network.hostname.name.c_str());
|
||||
} else {
|
||||
ETH.setHostname(system.getUserConfig()->callsign.c_str());
|
||||
}
|
||||
|
||||
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EthTask::loop(System &system) {
|
||||
if (!eth_connected) {
|
||||
system.connectedViaWifiEth(false);
|
||||
system.connectedViaEth(false);
|
||||
_stateInfo = "Ethernet not connected";
|
||||
_state = Error;
|
||||
return false;
|
||||
}
|
||||
system.connectedViaWifiEth(true);
|
||||
system.connectedViaEth(true);
|
||||
_stateInfo = ETH.localIP().toString();
|
||||
_state = Okay;
|
||||
return true;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <TaskManager.h>
|
||||
|
||||
void setWiFiLogger(logging::Logger *logger);
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
|
||||
class EthTask : public Task {
|
||||
|
|
|
@ -14,8 +14,7 @@ FTPTask::~FTPTask() {
|
|||
|
||||
bool FTPTask::setup(System &system) {
|
||||
for (Configuration::Ftp::User user : system.getUserConfig()->ftp.users) {
|
||||
logPrintD("Adding user to FTP Server: ");
|
||||
logPrintlnD(user.name);
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "Adding user to FTP Server: %s", user.name.c_str());
|
||||
_ftpServer.addUser(user.name, user.password);
|
||||
}
|
||||
_ftpServer.addFilesystem("SPIFFS", &SPIFFS);
|
||||
|
@ -31,8 +30,7 @@ bool FTPTask::loop(System &system) {
|
|||
_ftpServer.handle();
|
||||
static bool configWasOpen = false;
|
||||
if (configWasOpen && _ftpServer.countConnections() == 0) {
|
||||
logPrintlnW("Maybe the config has been changed via FTP, lets restart now to get the new config...");
|
||||
logPrintlnW("");
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_WARN, getName(), "Maybe the config has been changed via FTP, lets restart now to get the new config...");
|
||||
ESP.restart();
|
||||
}
|
||||
if (_ftpServer.countConnections() > 0) {
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
#include <logger.h>
|
||||
|
||||
#include "Task.h"
|
||||
#include "TaskMQTT.h"
|
||||
#include "project_configuration.h"
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
MQTTTask::MQTTTask(TaskQueue<std::shared_ptr<APRSMessage>> &toMQTT) : Task(TASK_MQTT, TaskMQTT), _toMQTT(toMQTT), _MQTT(_client) {
|
||||
}
|
||||
|
||||
MQTTTask::~MQTTTask() {
|
||||
}
|
||||
|
||||
bool MQTTTask::setup(System &system) {
|
||||
_MQTT.setServer(system.getUserConfig()->mqtt.server.c_str(), system.getUserConfig()->mqtt.port);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MQTTTask::loop(System &system) {
|
||||
if (!system.isWifiOrEthConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_MQTT.connected()) {
|
||||
connect(system);
|
||||
}
|
||||
|
||||
if (!_toMQTT.empty()) {
|
||||
std::shared_ptr<APRSMessage> msg = _toMQTT.getElement();
|
||||
|
||||
DynamicJsonDocument data(1024);
|
||||
data["source"] = msg->getSource();
|
||||
data["destination"] = msg->getDestination();
|
||||
data["path"] = msg->getPath();
|
||||
data["type"] = msg->getType().toString();
|
||||
String body = msg->getBody()->encode();
|
||||
body.replace("\n", "");
|
||||
data["data"] = body;
|
||||
|
||||
String r;
|
||||
serializeJson(data, r);
|
||||
|
||||
String topic = String(system.getUserConfig()->mqtt.topic);
|
||||
if (!topic.endsWith("/")) {
|
||||
topic = topic + "/";
|
||||
}
|
||||
topic = topic + system.getUserConfig()->callsign;
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "Send MQTT with topic: '%s', data: %s", topic.c_str(), r.c_str());
|
||||
_MQTT.publish(topic.c_str(), r.c_str());
|
||||
}
|
||||
_MQTT.loop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MQTTTask::connect(System &system) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "Connecting to MQTT broker: %s on port %d", system.getUserConfig()->mqtt.server.c_str(), system.getUserConfig()->mqtt.port);
|
||||
if (_MQTT.connect(system.getUserConfig()->callsign.c_str(), system.getUserConfig()->mqtt.name.c_str(), system.getUserConfig()->mqtt.password.c_str())) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "Connected to MQTT broker as: %s", system.getUserConfig()->callsign.c_str());
|
||||
return true;
|
||||
}
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "Connecting to MQTT broker failed. Try again later.");
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef TASK_MQTT_H_
|
||||
#define TASK_MQTT_H_
|
||||
|
||||
#include <APRSMessage.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <TaskManager.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
class MQTTTask : public Task {
|
||||
public:
|
||||
MQTTTask(TaskQueue<std::shared_ptr<APRSMessage>> &toMQTT);
|
||||
virtual ~MQTTTask();
|
||||
|
||||
virtual bool setup(System &system) override;
|
||||
virtual bool loop(System &system) override;
|
||||
|
||||
private:
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_toMQTT;
|
||||
|
||||
WiFiClient _client;
|
||||
PubSubClient _MQTT;
|
||||
|
||||
bool connect(System &system);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,60 +0,0 @@
|
|||
#include <logger.h>
|
||||
|
||||
#include <TimeLib.h>
|
||||
|
||||
#include "Task.h"
|
||||
#include "TaskAprsIs.h"
|
||||
#include "TaskModem.h"
|
||||
#include "project_configuration.h"
|
||||
|
||||
ModemTask::ModemTask(TaskQueue<std::shared_ptr<APRSMessage>> &fromModem, TaskQueue<std::shared_ptr<APRSMessage>> &toModem) : Task(TASK_MODEM, TaskModem), _lora_aprs(), _fromModem(fromModem), _toModem(toModem) {
|
||||
}
|
||||
|
||||
ModemTask::~ModemTask() {
|
||||
}
|
||||
|
||||
bool ModemTask::setup(System &system) {
|
||||
SPI.begin(system.getBoardConfig()->LoraSck, system.getBoardConfig()->LoraMiso, system.getBoardConfig()->LoraMosi, system.getBoardConfig()->LoraCS);
|
||||
_lora_aprs.setPins(system.getBoardConfig()->LoraCS, system.getBoardConfig()->LoraReset, system.getBoardConfig()->LoraIRQ);
|
||||
if (!_lora_aprs.begin(system.getUserConfig()->lora.frequencyRx)) {
|
||||
logPrintlnE("Starting LoRa failed!");
|
||||
_stateInfo = "LoRa-Modem failed";
|
||||
_state = Error;
|
||||
while (true)
|
||||
;
|
||||
}
|
||||
_lora_aprs.setRxFrequency(system.getUserConfig()->lora.frequencyRx);
|
||||
_lora_aprs.setTxFrequency(system.getUserConfig()->lora.frequencyTx);
|
||||
_lora_aprs.setTxPower(system.getUserConfig()->lora.power);
|
||||
_lora_aprs.setSpreadingFactor(system.getUserConfig()->lora.spreadingFactor);
|
||||
_lora_aprs.setSignalBandwidth(system.getUserConfig()->lora.signalBandwidth);
|
||||
_lora_aprs.setCodingRate4(system.getUserConfig()->lora.codingRate4);
|
||||
_lora_aprs.enableCrc();
|
||||
|
||||
_stateInfo = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModemTask::loop(System &system) {
|
||||
if (_lora_aprs.checkMessage()) {
|
||||
std::shared_ptr<APRSMessage> msg = _lora_aprs.getMessage();
|
||||
// msg->getAPRSBody()->setData(msg->getAPRSBody()->getData() + " 123");
|
||||
logPrintD("[" + timeString() + "] ");
|
||||
logPrintD("Received packet '");
|
||||
logPrintD(msg->toString());
|
||||
logPrintD("' with RSSI ");
|
||||
logPrintD(String(_lora_aprs.packetRssi()));
|
||||
logPrintD(" and SNR ");
|
||||
logPrintlnD(String(_lora_aprs.packetSnr()));
|
||||
|
||||
_fromModem.addElement(msg);
|
||||
system.getDisplay().addFrame(std::shared_ptr<DisplayFrame>(new TextFrame("LoRa", msg->toString())));
|
||||
}
|
||||
|
||||
if (!_toModem.empty()) {
|
||||
std::shared_ptr<APRSMessage> msg = _toModem.getElement();
|
||||
_lora_aprs.sendMessage(msg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef TASK_LORA_H_
|
||||
#define TASK_LORA_H_
|
||||
|
||||
#include <BoardFinder.h>
|
||||
#include <LoRa_APRS.h>
|
||||
#include <TaskManager.h>
|
||||
|
||||
class ModemTask : public Task {
|
||||
public:
|
||||
explicit ModemTask(TaskQueue<std::shared_ptr<APRSMessage>> &fromModem, TaskQueue<std::shared_ptr<APRSMessage>> &_toModem);
|
||||
virtual ~ModemTask();
|
||||
|
||||
virtual bool setup(System &system) override;
|
||||
virtual bool loop(System &system) override;
|
||||
|
||||
private:
|
||||
LoRa_APRS _lora_aprs;
|
||||
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_fromModem;
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_toModem;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -18,7 +18,7 @@ bool NTPTask::setup(System &system) {
|
|||
}
|
||||
|
||||
bool NTPTask::loop(System &system) {
|
||||
if (!system.isWifiEthConnected()) {
|
||||
if (!system.isWifiOrEthConnected()) {
|
||||
return false;
|
||||
}
|
||||
if (!_beginCalled) {
|
||||
|
@ -27,8 +27,7 @@ bool NTPTask::loop(System &system) {
|
|||
}
|
||||
if (_ntpClient.update()) {
|
||||
setTime(_ntpClient.getEpochTime());
|
||||
logPrintI("Current time: ");
|
||||
logPrintlnI(_ntpClient.getFormattedTime());
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "Current time: %s", _ntpClient.getFormattedTime().c_str());
|
||||
}
|
||||
_stateInfo = _ntpClient.getFormattedTime();
|
||||
_state = Okay;
|
||||
|
|
|
@ -13,37 +13,36 @@ OTATask::~OTATask() {
|
|||
bool OTATask::setup(System &system) {
|
||||
_ota.onStart([&]() {
|
||||
String type;
|
||||
if (_ota.getCommand() == U_FLASH)
|
||||
if (_ota.getCommand() == U_FLASH) {
|
||||
type = "sketch";
|
||||
else // U_SPIFFS
|
||||
} else { // U_SPIFFS
|
||||
type = "filesystem";
|
||||
logPrintlnI("Start updating " + type);
|
||||
}
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "Start updating %s. please wait, this prozess is taking some time!", type.c_str());
|
||||
})
|
||||
.onEnd([]() {
|
||||
logPrintlnI("");
|
||||
logPrintlnI("OTA End");
|
||||
.onEnd([&]() {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "OTA End");
|
||||
})
|
||||
.onProgress([](unsigned int progress, unsigned int total) {
|
||||
logPrintI("Progress: ");
|
||||
logPrintI(String(progress / (total / 100)));
|
||||
logPrintlnI("%");
|
||||
})
|
||||
.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");
|
||||
.onError([&](ota_error_t error) {
|
||||
String error_str;
|
||||
if (error == OTA_AUTH_ERROR) {
|
||||
error_str = "Auth Failed";
|
||||
} else if (error == OTA_BEGIN_ERROR) {
|
||||
error_str = "Begin Failed";
|
||||
} else if (error == OTA_CONNECT_ERROR) {
|
||||
error_str = "Connect Failed";
|
||||
} else if (error == OTA_RECEIVE_ERROR) {
|
||||
error_str = "Receive Failed";
|
||||
} else if (error == OTA_END_ERROR) {
|
||||
error_str = "End Failed";
|
||||
}
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "Error[%d]: %s", error, error_str.c_str());
|
||||
});
|
||||
_ota.setHostname(system.getUserConfig()->callsign.c_str());
|
||||
if (system.getUserConfig()->network.hostname.overwrite) {
|
||||
_ota.setHostname(system.getUserConfig()->network.hostname.name.c_str());
|
||||
} else {
|
||||
_ota.setHostname(system.getUserConfig()->callsign.c_str());
|
||||
}
|
||||
_stateInfo = "";
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
#include <Task.h>
|
||||
#include <TimeLib.h>
|
||||
#include <logger.h>
|
||||
|
||||
#include "TaskRadiolib.h"
|
||||
|
||||
RadiolibTask::RadiolibTask(TaskQueue<std::shared_ptr<APRSMessage>> &fromModem, TaskQueue<std::shared_ptr<APRSMessage>> &toModem) : Task(TASK_RADIOLIB, TaskRadiolib), _fromModem(fromModem), _toModem(toModem) {
|
||||
}
|
||||
|
||||
RadiolibTask::~RadiolibTask() {
|
||||
radio->clearDio0Action();
|
||||
}
|
||||
|
||||
volatile bool RadiolibTask::enableInterrupt = true; // Need to catch interrupt or not.
|
||||
volatile bool RadiolibTask::operationDone = false; // Caught IRQ or not.
|
||||
|
||||
void RadiolibTask::setFlag(void) {
|
||||
if (!enableInterrupt) {
|
||||
return;
|
||||
}
|
||||
|
||||
operationDone = true;
|
||||
}
|
||||
|
||||
bool RadiolibTask::setup(System &system) {
|
||||
SPI.begin(system.getBoardConfig()->LoraSck, system.getBoardConfig()->LoraMiso, system.getBoardConfig()->LoraMosi, system.getBoardConfig()->LoraCS);
|
||||
module = new Module(system.getBoardConfig()->LoraCS, system.getBoardConfig()->LoraIRQ, system.getBoardConfig()->LoraReset);
|
||||
radio = new SX1278(module);
|
||||
|
||||
config = system.getUserConfig()->lora;
|
||||
|
||||
rxEnable = true;
|
||||
txEnable = config.tx_enable;
|
||||
|
||||
float freqMHz = (float)config.frequencyRx / 1000000;
|
||||
float BWkHz = (float)config.signalBandwidth / 1000;
|
||||
|
||||
const uint16_t preambleLength = 8;
|
||||
|
||||
int16_t state = radio->begin(freqMHz, BWkHz, config.spreadingFactor, config.codingRate4, RADIOLIB_SX127X_SYNC_WORD, config.power, preambleLength, config.gainRx);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
switch (state) {
|
||||
case RADIOLIB_ERR_INVALID_FREQUENCY:
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied frequency value (%fMHz) is invalid for this module.", timeString().c_str(), freqMHz);
|
||||
rxEnable = false;
|
||||
txEnable = false;
|
||||
break;
|
||||
case RADIOLIB_ERR_INVALID_BANDWIDTH:
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied bandwidth value (%fkHz) is invalid for this module. Should be 7800, 10400, 15600, 20800, 31250, 41700 ,62500, 125000, 250000, 500000.", timeString().c_str(), BWkHz);
|
||||
rxEnable = false;
|
||||
txEnable = false;
|
||||
break;
|
||||
case RADIOLIB_ERR_INVALID_SPREADING_FACTOR:
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied spreading factor value (%d) is invalid for this module.", timeString().c_str(), config.spreadingFactor);
|
||||
rxEnable = false;
|
||||
txEnable = false;
|
||||
break;
|
||||
case RADIOLIB_ERR_INVALID_CODING_RATE:
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied coding rate value (%d) is invalid for this module.", timeString().c_str(), config.codingRate4);
|
||||
rxEnable = false;
|
||||
txEnable = false;
|
||||
break;
|
||||
case RADIOLIB_ERR_INVALID_OUTPUT_POWER:
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied output power value (%d) is invalid for this module.", timeString().c_str(), config.power);
|
||||
txEnable = false;
|
||||
break;
|
||||
case RADIOLIB_ERR_INVALID_PREAMBLE_LENGTH:
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied preamble length is invalid.", timeString().c_str());
|
||||
txEnable = false;
|
||||
break;
|
||||
case RADIOLIB_ERR_INVALID_GAIN:
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, The supplied gain value (%d) is invalid.", timeString().c_str(), config.gainRx);
|
||||
rxEnable = false;
|
||||
break;
|
||||
default:
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] SX1278 init failed, code %d", timeString().c_str(), state);
|
||||
rxEnable = false;
|
||||
txEnable = false;
|
||||
}
|
||||
_stateInfo = "LoRa-Modem failed";
|
||||
_state = Error;
|
||||
}
|
||||
|
||||
state = radio->setCRC(true);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] setCRC failed, code %d", timeString().c_str(), state);
|
||||
_stateInfo = "LoRa-Modem failed";
|
||||
_state = Error;
|
||||
}
|
||||
|
||||
radio->setDio0Action(setFlag);
|
||||
|
||||
if (rxEnable) {
|
||||
int state = startRX(RADIOLIB_SX127X_RXCONTINUOUS);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] startRX failed, code %d", timeString().c_str(), state);
|
||||
rxEnable = false;
|
||||
_stateInfo = "LoRa-Modem failed";
|
||||
_state = Error;
|
||||
}
|
||||
}
|
||||
|
||||
preambleDurationMilliSec = ((uint64_t)(preambleLength + 4) << (config.spreadingFactor + 10 /* to milli-sec */)) / config.signalBandwidth;
|
||||
|
||||
_stateInfo = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
int transmissionState = RADIOLIB_ERR_NONE;
|
||||
bool transmitFlag = false; // Transmitting or not.
|
||||
|
||||
bool RadiolibTask::loop(System &system) {
|
||||
if (operationDone) { // occurs interrupt.
|
||||
enableInterrupt = false;
|
||||
|
||||
if (transmitFlag) { // transmitted.
|
||||
if (transmissionState == RADIOLIB_ERR_NONE) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] TX done", timeString().c_str());
|
||||
|
||||
} else {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] transmitFlag failed, code %d", timeString().c_str(), transmissionState);
|
||||
}
|
||||
operationDone = false;
|
||||
transmitFlag = false;
|
||||
|
||||
txWaitTimer.setTimeout(preambleDurationMilliSec * 2);
|
||||
txWaitTimer.start();
|
||||
|
||||
} else { // received.
|
||||
String str;
|
||||
int state = radio->readData(str);
|
||||
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] readData failed, code %d", timeString().c_str(), state);
|
||||
} else {
|
||||
if (str.substring(0, 3) != "<\xff\x01") {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] Unknown packet '%s' with RSSI %.0fdBm, SNR %.2fdB and FreqErr %fHz%s", timeString().c_str(), str.c_str(), radio->getRSSI(), radio->getSNR(), -radio->getFrequencyError());
|
||||
} else {
|
||||
std::shared_ptr<APRSMessage> msg = std::shared_ptr<APRSMessage>(new APRSMessage());
|
||||
msg->decode(str.substring(3));
|
||||
_fromModem.addElement(msg);
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] Received packet '%s' with RSSI %.0fdBm, SNR %.2fdB and FreqErr %fHz", timeString().c_str(), msg->toString().c_str(), radio->getRSSI(), radio->getSNR(), -radio->getFrequencyError());
|
||||
system.getDisplay().addFrame(std::shared_ptr<DisplayFrame>(new TextFrame("LoRa", msg->toString().c_str())));
|
||||
}
|
||||
}
|
||||
operationDone = false;
|
||||
}
|
||||
|
||||
if (rxEnable) {
|
||||
int state = startRX(RADIOLIB_SX127X_RXCONTINUOUS);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] startRX failed, code %d", timeString().c_str(), state);
|
||||
rxEnable = false;
|
||||
}
|
||||
}
|
||||
|
||||
enableInterrupt = true;
|
||||
} else { // not interrupt.
|
||||
if (!txWaitTimer.check()) {
|
||||
} else {
|
||||
if (!txEnable) {
|
||||
// system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] TX is not enabled", timeString().c_str());
|
||||
} else {
|
||||
if (transmitFlag) {
|
||||
// system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] TX signal detected. Waiting TX", timeString().c_str());
|
||||
} else {
|
||||
if (!_toModem.empty()) {
|
||||
if (config.frequencyRx == config.frequencyTx && (radio->getModemStatus() & 0x01) == 0x01) {
|
||||
// system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] RX signal detected. Waiting TX", timeString().c_str());
|
||||
} else {
|
||||
std::shared_ptr<APRSMessage> msg = _toModem.getElement();
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "[%s] Transmitting packet '%s'", timeString().c_str(), msg->toString().c_str());
|
||||
|
||||
int16_t state = startTX("<\xff\x01" + msg->encode());
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "[%s] startTX failed, code %d", timeString().c_str(), state);
|
||||
txEnable = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int16_t RadiolibTask::startRX(uint8_t mode) {
|
||||
if (config.frequencyTx != config.frequencyRx) {
|
||||
int16_t state = radio->setFrequency((float)config.frequencyRx / 1000000);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
return radio->startReceive(0, mode);
|
||||
}
|
||||
|
||||
int16_t RadiolibTask::startTX(String &str) {
|
||||
if (config.frequencyTx != config.frequencyRx) {
|
||||
int16_t state = radio->setFrequency((float)config.frequencyTx / 1000000);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
transmissionState = radio->startTransmit(str);
|
||||
transmitFlag = true;
|
||||
return RADIOLIB_ERR_NONE;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef TASK_LORA_H_
|
||||
#define TASK_LORA_H_
|
||||
|
||||
#include "project_configuration.h"
|
||||
#include <APRS-Decoder.h>
|
||||
#include <BoardFinder.h>
|
||||
#include <RadioLib.h>
|
||||
#include <TaskManager.h>
|
||||
|
||||
class RadiolibTask : public Task {
|
||||
public:
|
||||
explicit RadiolibTask(TaskQueue<std::shared_ptr<APRSMessage>> &fromModem, TaskQueue<std::shared_ptr<APRSMessage>> &_toModem);
|
||||
virtual ~RadiolibTask();
|
||||
|
||||
virtual bool setup(System &system) override;
|
||||
virtual bool loop(System &system) override;
|
||||
|
||||
private:
|
||||
Module *module;
|
||||
SX1278 *radio;
|
||||
|
||||
Configuration::LoRa config;
|
||||
|
||||
bool rxEnable, txEnable;
|
||||
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_fromModem;
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_toModem;
|
||||
|
||||
static volatile bool enableInterrupt; // Need to catch interrupt or not.
|
||||
static volatile bool operationDone; // Caught IRQ or not.
|
||||
|
||||
static void setFlag(void);
|
||||
|
||||
int16_t startRX(uint8_t mode);
|
||||
int16_t startTX(String &str);
|
||||
|
||||
uint32_t preambleDurationMilliSec;
|
||||
Timer txWaitTimer;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -6,34 +6,24 @@
|
|||
#include "TaskRouter.h"
|
||||
#include "project_configuration.h"
|
||||
|
||||
String create_lat_aprs(double lat);
|
||||
String create_long_aprs(double lng);
|
||||
|
||||
RouterTask::RouterTask(TaskQueue<std::shared_ptr<APRSMessage>> &fromModem, TaskQueue<std::shared_ptr<APRSMessage>> &toModem, TaskQueue<std::shared_ptr<APRSMessage>> &toAprsIs) : Task(TASK_ROUTER, TaskRouter), _fromModem(fromModem), _toModem(toModem), _toAprsIs(toAprsIs) {
|
||||
RouterTask::RouterTask(TaskQueue<std::shared_ptr<APRSMessage>> &fromModem, TaskQueue<std::shared_ptr<APRSMessage>> &toModem, TaskQueue<std::shared_ptr<APRSMessage>> &toAprsIs, TaskQueue<std::shared_ptr<APRSMessage>> &toMQTT) : Task(TASK_ROUTER, TaskRouter), _fromModem(fromModem), _toModem(toModem), _toAprsIs(toAprsIs), _toMQTT(toMQTT) {
|
||||
}
|
||||
|
||||
RouterTask::~RouterTask() {
|
||||
}
|
||||
|
||||
bool RouterTask::setup(System &system) {
|
||||
// setup beacon
|
||||
_beacon_timer.setTimeout(system.getUserConfig()->beacon.timeout * 60 * 1000);
|
||||
|
||||
_beaconMsg = std::shared_ptr<APRSMessage>(new APRSMessage());
|
||||
_beaconMsg->setSource(system.getUserConfig()->callsign);
|
||||
_beaconMsg->setDestination("APLG01");
|
||||
String lat = create_lat_aprs(system.getUserConfig()->beacon.positionLatitude);
|
||||
String lng = create_long_aprs(system.getUserConfig()->beacon.positionLongitude);
|
||||
_beaconMsg->getBody()->setData(String("=") + lat + "L" + lng + "&" + system.getUserConfig()->beacon.message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RouterTask::loop(System &system) {
|
||||
// do routing
|
||||
if (!_fromModem.empty()) {
|
||||
std::shared_ptr<APRSMessage> modemMsg = _fromModem.getElement();
|
||||
|
||||
if (system.getUserConfig()->mqtt.active) {
|
||||
_toMQTT.addElement(modemMsg);
|
||||
}
|
||||
|
||||
if (system.getUserConfig()->aprs_is.active && modemMsg->getSource() != system.getUserConfig()->callsign) {
|
||||
std::shared_ptr<APRSMessage> aprsIsMsg = std::make_shared<APRSMessage>(*modemMsg);
|
||||
String path = aprsIsMsg->getPath();
|
||||
|
@ -43,20 +33,21 @@ bool RouterTask::loop(System &system) {
|
|||
path += ",";
|
||||
}
|
||||
|
||||
aprsIsMsg->setPath(path + "qAR," + system.getUserConfig()->callsign);
|
||||
aprsIsMsg->setPath(path + "qAO," + system.getUserConfig()->callsign);
|
||||
|
||||
logPrintD("APRS-IS: ");
|
||||
logPrintlnD(aprsIsMsg->toString());
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "APRS-IS: %s", aprsIsMsg->toString().c_str());
|
||||
_toAprsIs.addElement(aprsIsMsg);
|
||||
} else {
|
||||
logPrintlnD("APRS-IS: no forward => RFonly");
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "APRS-IS: no forward => RFonly");
|
||||
}
|
||||
} else {
|
||||
if (!system.getUserConfig()->aprs_is.active)
|
||||
logPrintlnD("APRS-IS: disabled");
|
||||
if (!system.getUserConfig()->aprs_is.active) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "APRS-IS: disabled");
|
||||
}
|
||||
|
||||
if (modemMsg->getSource() == system.getUserConfig()->callsign)
|
||||
logPrintlnD("APRS-IS: no forward => own packet received");
|
||||
if (modemMsg->getSource() == system.getUserConfig()->callsign) {
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "APRS-IS: no forward => own packet received");
|
||||
}
|
||||
}
|
||||
|
||||
if (system.getUserConfig()->digi.active && modemMsg->getSource() != system.getUserConfig()->callsign) {
|
||||
|
@ -68,33 +59,14 @@ bool RouterTask::loop(System &system) {
|
|||
// fixme
|
||||
digiMsg->setPath(system.getUserConfig()->callsign + "*");
|
||||
|
||||
logPrintD("DIGI: ");
|
||||
logPrintlnD(digiMsg->toString());
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_INFO, getName(), "DIGI: %s", digiMsg->toString().c_str());
|
||||
|
||||
_toModem.addElement(digiMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for beacon
|
||||
if (_beacon_timer.check()) {
|
||||
logPrintD("[" + timeString() + "] ");
|
||||
logPrintlnD(_beaconMsg->encode());
|
||||
|
||||
if (system.getUserConfig()->aprs_is.active)
|
||||
_toAprsIs.addElement(_beaconMsg);
|
||||
|
||||
if (system.getUserConfig()->digi.beacon) {
|
||||
_toModem.addElement(_beaconMsg);
|
||||
}
|
||||
|
||||
system.getDisplay().addFrame(std::shared_ptr<DisplayFrame>(new TextFrame("BEACON", _beaconMsg->toString())));
|
||||
|
||||
_beacon_timer.start();
|
||||
}
|
||||
|
||||
uint32_t diff = _beacon_timer.getTriggerTimeInSec();
|
||||
_stateInfo = "beacon " + String(uint32_t(diff / 600)) + String(uint32_t(diff / 60) % 10) + ":" + String(uint32_t(diff / 10) % 6) + String(uint32_t(diff % 10));
|
||||
_stateInfo = "Router done ";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
#define TASK_ROUTER_H_
|
||||
|
||||
#include <APRSMessage.h>
|
||||
#include <TaskMQTT.h>
|
||||
#include <TaskManager.h>
|
||||
|
||||
class RouterTask : public Task {
|
||||
public:
|
||||
RouterTask(TaskQueue<std::shared_ptr<APRSMessage>> &fromModem, TaskQueue<std::shared_ptr<APRSMessage>> &toModem, TaskQueue<std::shared_ptr<APRSMessage>> &toAprsIs);
|
||||
RouterTask(TaskQueue<std::shared_ptr<APRSMessage>> &fromModem, TaskQueue<std::shared_ptr<APRSMessage>> &toModem, TaskQueue<std::shared_ptr<APRSMessage>> &toAprsIs, TaskQueue<std::shared_ptr<APRSMessage>> &toMQTT);
|
||||
virtual ~RouterTask();
|
||||
|
||||
virtual bool setup(System &system) override;
|
||||
|
@ -16,9 +17,7 @@ private:
|
|||
TaskQueue<std::shared_ptr<APRSMessage>> &_fromModem;
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_toModem;
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_toAprsIs;
|
||||
|
||||
std::shared_ptr<APRSMessage> _beaconMsg;
|
||||
Timer _beacon_timer;
|
||||
TaskQueue<std::shared_ptr<APRSMessage>> &_toMQTT;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,15 +20,18 @@ bool WifiTask::setup(System &system) {
|
|||
WiFi.mode(WIFI_STA);
|
||||
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
WiFi.setHostname(system.getUserConfig()->callsign.c_str());
|
||||
if (system.getUserConfig()->network.hostname.overwrite) {
|
||||
WiFi.setHostname(system.getUserConfig()->network.hostname.name.c_str());
|
||||
} else {
|
||||
WiFi.setHostname(system.getUserConfig()->callsign.c_str());
|
||||
}
|
||||
|
||||
if (!system.getUserConfig()->network.DHCP) {
|
||||
WiFi.config(system.getUserConfig()->network.staticIP, system.getUserConfig()->network.gateway, system.getUserConfig()->network.subnet, system.getUserConfig()->network.dns1, system.getUserConfig()->network.dns2);
|
||||
WiFi.config(system.getUserConfig()->network.static_.ip, system.getUserConfig()->network.static_.gateway, system.getUserConfig()->network.static_.subnet, system.getUserConfig()->network.static_.dns1, system.getUserConfig()->network.static_.dns2);
|
||||
}
|
||||
|
||||
for (Configuration::Wifi::AP ap : system.getUserConfig()->wifi.APs) {
|
||||
logPrintD("Looking for AP: ");
|
||||
logPrintlnD(ap.SSID);
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "Looking for AP: %s", ap.SSID.c_str());
|
||||
_wiFiMulti.addAP(ap.SSID.c_str(), ap.password.c_str());
|
||||
}
|
||||
return true;
|
||||
|
@ -37,20 +40,19 @@ bool WifiTask::setup(System &system) {
|
|||
bool WifiTask::loop(System &system) {
|
||||
const uint8_t wifi_status = _wiFiMulti.run();
|
||||
if (wifi_status != WL_CONNECTED) {
|
||||
system.connectedViaWifiEth(false);
|
||||
logPrintlnE("WiFi not connected!");
|
||||
system.connectedViaWifi(false);
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, getName(), "WiFi not connected!");
|
||||
_oldWifiStatus = wifi_status;
|
||||
_stateInfo = "WiFi not connected";
|
||||
_state = Error;
|
||||
return false;
|
||||
} else if (wifi_status != _oldWifiStatus) {
|
||||
logPrintD("IP address: ");
|
||||
logPrintlnD(WiFi.localIP().toString());
|
||||
system.getLogger().log(logging::LoggerLevel::LOGGER_LEVEL_DEBUG, getName(), "WiFi IP address: %s", WiFi.localIP().toString().c_str());
|
||||
_oldWifiStatus = wifi_status;
|
||||
return false;
|
||||
}
|
||||
system.connectedViaWifiEth(true);
|
||||
_stateInfo = WiFi.localIP().toString();
|
||||
system.connectedViaWifi(true);
|
||||
_stateInfo = String("IP .") + String(WiFi.localIP()[3]) + String(" @ ") + String(WiFi.RSSI()) + String("dBm");
|
||||
_state = Okay;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,42 +8,63 @@ void ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocumen
|
|||
if (data.containsKey("callsign"))
|
||||
conf.callsign = data["callsign"].as<String>();
|
||||
|
||||
if (data.containsKey("network") && data["network"].containsKey("DHCP")) {
|
||||
conf.network.DHCP = data["network"]["DHCP"];
|
||||
conf.network.staticIP.fromString(data["network"]["staticIP"].as<String>());
|
||||
conf.network.subnet.fromString(data["network"]["subnet"].as<String>());
|
||||
conf.network.gateway.fromString(data["network"]["gateway"].as<String>());
|
||||
conf.network.dns1.fromString(data["network"]["dns1"].as<String>());
|
||||
conf.network.dns2.fromString(data["network"]["dns2"].as<String>());
|
||||
if (data.containsKey("network")) {
|
||||
conf.network.DHCP = data["network"]["DHCP"] | false;
|
||||
if (data["network"].containsKey("static")) {
|
||||
if (data["network"]["static"].containsKey("ip"))
|
||||
conf.network.static_.ip.fromString(data["network"]["static"]["ip"].as<String>());
|
||||
if (data["network"]["static"].containsKey("subnet"))
|
||||
conf.network.static_.subnet.fromString(data["network"]["static"]["subnet"].as<String>());
|
||||
if (data["network"]["static"].containsKey("gateway"))
|
||||
conf.network.static_.gateway.fromString(data["network"]["static"]["gateway"].as<String>());
|
||||
if (data["network"]["static"].containsKey("dns1"))
|
||||
conf.network.static_.dns1.fromString(data["network"]["static"]["dns1"].as<String>());
|
||||
if (data["network"]["static"].containsKey("dns2"))
|
||||
conf.network.static_.dns2.fromString(data["network"]["static"]["dns2"].as<String>());
|
||||
}
|
||||
if (data["network"].containsKey("hostname")) {
|
||||
conf.network.hostname.overwrite = data["network"]["hostname"]["overwrite"] | false;
|
||||
if (data["network"]["hostname"].containsKey("name"))
|
||||
conf.network.hostname.name = data["network"]["hostname"]["name"].as<String>();
|
||||
}
|
||||
}
|
||||
|
||||
JsonArray aps = data["wifi"]["AP"].as<JsonArray>();
|
||||
conf.wifi.active = data["wifi"]["active"];
|
||||
JsonArray aps = data["wifi"]["AP"].as<JsonArray>();
|
||||
for (JsonVariant v : aps) {
|
||||
Configuration::Wifi::AP ap;
|
||||
ap.SSID = v["SSID"].as<String>();
|
||||
ap.password = v["password"].as<String>();
|
||||
if (v.containsKey("SSID"))
|
||||
ap.SSID = v["SSID"].as<String>();
|
||||
if (v.containsKey("password"))
|
||||
ap.password = v["password"].as<String>();
|
||||
conf.wifi.APs.push_back(ap);
|
||||
}
|
||||
if (data.containsKey("beacon") && data["beacon"].containsKey("message"))
|
||||
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.beacon.use_gps = data["beacon"]["use_gps"] | false;
|
||||
conf.beacon.timeout = data["beacon"]["timeout"] | 15;
|
||||
conf.aprs_is.active = data["aprs_is"]["active"] | true;
|
||||
|
||||
if (data.containsKey("aprs_is") && data["aprs_is"].containsKey("passcode"))
|
||||
conf.aprs_is.passcode = data["aprs_is"]["passcode"].as<String>();
|
||||
if (data.containsKey("aprs_is") && data["aprs_is"].containsKey("server"))
|
||||
conf.aprs_is.server = data["aprs_is"]["server"].as<String>();
|
||||
conf.aprs_is.port = data["aprs_is"]["port"] | 14580;
|
||||
|
||||
conf.digi.active = data["digi"]["active"] | false;
|
||||
conf.digi.beacon = data["digi"]["beacon"] | false;
|
||||
conf.digi.active = data["digi"]["active"] | false;
|
||||
conf.digi.beacon = data["digi"]["beacon"] | false;
|
||||
|
||||
conf.lora.frequencyRx = data["lora"]["frequency_rx"] | 433775000;
|
||||
conf.lora.gainRx = data["lora"]["gain_rx"] | 0;
|
||||
conf.lora.frequencyTx = data["lora"]["frequency_tx"] | 433775000;
|
||||
conf.lora.power = data["lora"]["power"] | 20;
|
||||
conf.lora.spreadingFactor = data["lora"]["spreading_factor"] | 12;
|
||||
conf.lora.signalBandwidth = data["lora"]["signal_bandwidth"] | 125000;
|
||||
conf.lora.codingRate4 = data["lora"]["coding_rate4"] | 5;
|
||||
conf.lora.tx_enable = data["lora"]["tx_enable"] | true;
|
||||
|
||||
conf.display.alwaysOn = data["display"]["always_on"] | true;
|
||||
conf.display.timeout = data["display"]["timeout"] | 10;
|
||||
conf.display.overwritePin = data["display"]["overwrite_pin"] | 0;
|
||||
|
@ -53,8 +74,10 @@ void ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocumen
|
|||
JsonArray users = data["ftp"]["user"].as<JsonArray>();
|
||||
for (JsonVariant u : users) {
|
||||
Configuration::Ftp::User us;
|
||||
us.name = u["name"].as<String>();
|
||||
us.password = u["password"].as<String>();
|
||||
if (u.containsKey("name"))
|
||||
us.name = u["name"].as<String>();
|
||||
if (u.containsKey("password"))
|
||||
us.password = u["password"].as<String>();
|
||||
conf.ftp.users.push_back(us);
|
||||
}
|
||||
if (conf.ftp.users.empty()) {
|
||||
|
@ -63,6 +86,23 @@ void ProjectConfigurationManagement::readProjectConfiguration(DynamicJsonDocumen
|
|||
us.password = "ftp";
|
||||
conf.ftp.users.push_back(us);
|
||||
}
|
||||
|
||||
conf.mqtt.active = data["mqtt"]["active"] | false;
|
||||
if (data["mqtt"].containsKey("server"))
|
||||
conf.mqtt.server = data["mqtt"]["server"].as<String>();
|
||||
conf.mqtt.port = data["mqtt"]["port"] | 1883;
|
||||
if (data["mqtt"].containsKey("name"))
|
||||
conf.mqtt.name = data["mqtt"]["name"].as<String>();
|
||||
if (data["mqtt"].containsKey("password"))
|
||||
conf.mqtt.password = data["mqtt"]["password"].as<String>();
|
||||
if (data["mqtt"].containsKey("topic"))
|
||||
conf.mqtt.topic = data["mqtt"]["topic"].as<String>();
|
||||
|
||||
conf.syslog.active = data["syslog"]["active"] | true;
|
||||
if (data["syslog"].containsKey("server"))
|
||||
conf.syslog.server = data["syslog"]["server"].as<String>();
|
||||
conf.syslog.port = data["syslog"]["port"] | 514;
|
||||
|
||||
if (data.containsKey("ntp_server"))
|
||||
conf.ntpServer = data["ntp_server"].as<String>();
|
||||
|
||||
|
@ -74,15 +114,18 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration &co
|
|||
data["callsign"] = conf.callsign;
|
||||
|
||||
if (!conf.network.DHCP) {
|
||||
data["network"]["DHCP"] = conf.network.DHCP;
|
||||
data["network"]["staticIP"] = conf.network.staticIP.toString();
|
||||
data["network"]["subnet"] = conf.network.subnet.toString();
|
||||
data["network"]["gateway"] = conf.network.gateway.toString();
|
||||
data["network"]["dns1"] = conf.network.dns1.toString();
|
||||
data["network"]["dns2"] = conf.network.dns2.toString();
|
||||
data["network"]["DHCP"] = conf.network.DHCP;
|
||||
data["network"]["static"]["ip"] = conf.network.static_.ip.toString();
|
||||
data["network"]["static"]["subnet"] = conf.network.static_.subnet.toString();
|
||||
data["network"]["static"]["gateway"] = conf.network.static_.gateway.toString();
|
||||
data["network"]["static"]["dns1"] = conf.network.static_.dns1.toString();
|
||||
data["network"]["static"]["dns2"] = conf.network.static_.dns2.toString();
|
||||
data["network"]["hostname"]["overwrite"] = conf.network.hostname.overwrite;
|
||||
data["network"]["hostname"]["name"] = conf.network.hostname.name;
|
||||
}
|
||||
|
||||
JsonArray aps = data["wifi"].createNestedArray("AP");
|
||||
data["wifi"]["active"] = conf.wifi.active;
|
||||
JsonArray aps = data["wifi"].createNestedArray("AP");
|
||||
for (Configuration::Wifi::AP ap : conf.wifi.APs) {
|
||||
JsonObject v = aps.createNestedObject();
|
||||
v["SSID"] = ap.SSID;
|
||||
|
@ -91,6 +134,7 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration &co
|
|||
data["beacon"]["message"] = conf.beacon.message;
|
||||
data["beacon"]["position"]["latitude"] = conf.beacon.positionLatitude;
|
||||
data["beacon"]["position"]["longitude"] = conf.beacon.positionLongitude;
|
||||
data["beacon"]["use_gps"] = conf.beacon.use_gps;
|
||||
data["beacon"]["timeout"] = conf.beacon.timeout;
|
||||
data["aprs_is"]["active"] = conf.aprs_is.active;
|
||||
data["aprs_is"]["passcode"] = conf.aprs_is.passcode;
|
||||
|
@ -99,11 +143,13 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration &co
|
|||
data["digi"]["active"] = conf.digi.active;
|
||||
data["digi"]["beacon"] = conf.digi.beacon;
|
||||
data["lora"]["frequency_rx"] = conf.lora.frequencyRx;
|
||||
data["lora"]["gain_rx"] = conf.lora.gainRx;
|
||||
data["lora"]["frequency_tx"] = conf.lora.frequencyTx;
|
||||
data["lora"]["power"] = conf.lora.power;
|
||||
data["lora"]["spreading_factor"] = conf.lora.spreadingFactor;
|
||||
data["lora"]["signal_bandwidth"] = conf.lora.signalBandwidth;
|
||||
data["lora"]["coding_rate4"] = conf.lora.codingRate4;
|
||||
data["lora"]["tx_enable"] = conf.lora.tx_enable;
|
||||
data["display"]["always_on"] = conf.display.alwaysOn;
|
||||
data["display"]["timeout"] = conf.display.timeout;
|
||||
data["display"]["overwrite_pin"] = conf.display.overwritePin;
|
||||
|
@ -115,7 +161,16 @@ void ProjectConfigurationManagement::writeProjectConfiguration(Configuration &co
|
|||
v["name"] = u.name;
|
||||
v["password"] = u.password;
|
||||
}
|
||||
data["ntp_server"] = conf.ntpServer;
|
||||
data["mqtt"]["active"] = conf.mqtt.active;
|
||||
data["mqtt"]["server"] = conf.mqtt.server;
|
||||
data["mqtt"]["port"] = conf.mqtt.port;
|
||||
data["mqtt"]["name"] = conf.mqtt.name;
|
||||
data["mqtt"]["password"] = conf.mqtt.password;
|
||||
data["mqtt"]["topic"] = conf.mqtt.topic;
|
||||
data["syslog"]["active"] = conf.syslog.active;
|
||||
data["syslog"]["server"] = conf.syslog.server;
|
||||
data["syslog"]["port"] = conf.syslog.port;
|
||||
data["ntp_server"] = conf.ntpServer;
|
||||
|
||||
data["board"] = conf.board;
|
||||
}
|
||||
|
|
|
@ -6,41 +6,55 @@
|
|||
|
||||
class Configuration {
|
||||
public:
|
||||
class Network {
|
||||
class Static {
|
||||
public:
|
||||
Network() : DHCP(true) {
|
||||
}
|
||||
|
||||
bool DHCP;
|
||||
IPAddress staticIP;
|
||||
IPAddress ip;
|
||||
IPAddress subnet;
|
||||
IPAddress gateway;
|
||||
IPAddress dns1;
|
||||
IPAddress dns2;
|
||||
};
|
||||
|
||||
class Hostname {
|
||||
public:
|
||||
bool overwrite;
|
||||
String name;
|
||||
};
|
||||
|
||||
class Network {
|
||||
public:
|
||||
Network() : DHCP(true) {
|
||||
}
|
||||
|
||||
bool DHCP;
|
||||
Static static_;
|
||||
Hostname hostname;
|
||||
};
|
||||
|
||||
class Wifi {
|
||||
public:
|
||||
Wifi() : active(true) {
|
||||
}
|
||||
|
||||
bool active;
|
||||
class AP {
|
||||
public:
|
||||
String SSID;
|
||||
String password;
|
||||
};
|
||||
|
||||
Wifi() {
|
||||
}
|
||||
|
||||
std::list<AP> APs;
|
||||
};
|
||||
|
||||
class Beacon {
|
||||
public:
|
||||
Beacon() : message("LoRa iGATE & Digi, Info: github.com/peterus/LoRa_APRS_iGate"), positionLatitude(0.0), positionLongitude(0.0), timeout(15) {
|
||||
Beacon() : message("LoRa iGATE & Digi, Info: github.com/peterus/LoRa_APRS_iGate"), positionLatitude(0.0), positionLongitude(0.0), use_gps(false), timeout(15) {
|
||||
}
|
||||
|
||||
String message;
|
||||
double positionLatitude;
|
||||
double positionLongitude;
|
||||
bool use_gps;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
|
@ -66,15 +80,17 @@ public:
|
|||
|
||||
class LoRa {
|
||||
public:
|
||||
LoRa() : frequencyRx(433775000), frequencyTx(433775000), power(20), spreadingFactor(12), signalBandwidth(125000), codingRate4(5) {
|
||||
LoRa() : frequencyRx(433775000), frequencyTx(433775000), power(20), spreadingFactor(12), signalBandwidth(125000), codingRate4(5), tx_enable(true) {
|
||||
}
|
||||
|
||||
long frequencyRx;
|
||||
long frequencyTx;
|
||||
int power;
|
||||
int spreadingFactor;
|
||||
long signalBandwidth;
|
||||
int codingRate4;
|
||||
long frequencyRx;
|
||||
uint8_t gainRx;
|
||||
long frequencyTx;
|
||||
int power;
|
||||
int spreadingFactor;
|
||||
long signalBandwidth;
|
||||
int codingRate4;
|
||||
bool tx_enable;
|
||||
};
|
||||
|
||||
class Display {
|
||||
|
@ -103,7 +119,31 @@ public:
|
|||
std::list<User> users;
|
||||
};
|
||||
|
||||
Configuration() : callsign("NOCALL-10"), board(""), ntpServer("pool.ntp.org"){};
|
||||
class MQTT {
|
||||
public:
|
||||
MQTT() : active(false), server(""), port(1883), name(""), password(""), topic("LoraAPRS/Data") {
|
||||
}
|
||||
|
||||
bool active;
|
||||
String server;
|
||||
int port;
|
||||
String name;
|
||||
String password;
|
||||
String topic;
|
||||
};
|
||||
|
||||
class Syslog {
|
||||
public:
|
||||
Syslog() : active(true), server("syslog.lora-aprs.info"), port(514) {
|
||||
}
|
||||
|
||||
bool active;
|
||||
String server;
|
||||
int port;
|
||||
};
|
||||
|
||||
Configuration() : callsign("NOCALL-10"), ntpServer("pool.ntp.org"), board("") {
|
||||
}
|
||||
|
||||
String callsign;
|
||||
Network network;
|
||||
|
@ -114,13 +154,15 @@ public:
|
|||
LoRa lora;
|
||||
Display display;
|
||||
Ftp ftp;
|
||||
String board;
|
||||
MQTT mqtt;
|
||||
Syslog syslog;
|
||||
String ntpServer;
|
||||
String board;
|
||||
};
|
||||
|
||||
class ProjectConfigurationManagement : public ConfigurationManagement {
|
||||
public:
|
||||
explicit ProjectConfigurationManagement() : ConfigurationManagement("/is-cfg.json") {
|
||||
explicit ProjectConfigurationManagement(logging::Logger &logger) : ConfigurationManagement(logger, "/is-cfg.json") {
|
||||
}
|
||||
virtual ~ProjectConfigurationManagement() {
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue