kopia lustrzana https://github.com/SQ9MDD/TTGO-T-Beam-LoRa-APRS
Merge pull request #45 from Qyon/master_sq9mdd
Code reformat, GPS NMEA over TCP, fix for TNC not ignoring control framespull/54/head
commit
dc3a9d3db9
|
@ -232,12 +232,17 @@
|
|||
</div>
|
||||
<article>
|
||||
<div class="grid-container quarters">
|
||||
<form action="/reboot" method="post">
|
||||
<form action="/shutdown" method="post" onsubmit="return confirmAction('shutdown');">
|
||||
<div>
|
||||
<input class="button-primary" type="submit" value="Shutdown">
|
||||
</div>
|
||||
</form>
|
||||
<form action="/reboot" method="post" onsubmit="return confirmAction('reboot');">
|
||||
<div>
|
||||
<input class="button-primary" type="submit" value="Reboot">
|
||||
</div>
|
||||
</form>
|
||||
<form action="/restore" method="post">
|
||||
<form action="/restore" method="post" onsubmit="return confirmAction('do factory reset');">
|
||||
<div>
|
||||
<input class="button-primary" type="submit" value="Factory reset">
|
||||
</div>
|
||||
|
|
|
@ -113,4 +113,8 @@ function updateFileUpload(event) {
|
|||
xhr.open('POST', '/update');
|
||||
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
function confirmAction(actionName) {
|
||||
return window.confirm('Are you shure want to ' + actionName);
|
||||
}
|
|
@ -2,4 +2,5 @@
|
|||
#include <TinyGPS++.h>
|
||||
|
||||
extern TinyGPSPlus gps;
|
||||
void taskGPS(void *parameter);
|
||||
|
||||
[[noreturn]] void taskGPS(void *parameter);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#endif
|
||||
#if defined(ENABLE_WIFI)
|
||||
#include "taskWebServer.h"
|
||||
#include "wifi_clients.h"
|
||||
#endif
|
||||
extern QueueHandle_t tncToSendQueue;
|
||||
extern QueueHandle_t tncReceivedQueue;
|
||||
|
|
|
@ -12,6 +12,7 @@ extern BG_RF95 rf95;
|
|||
#ifdef KISS_PROTOCOL
|
||||
extern WiFiServer tncServer;
|
||||
#endif
|
||||
extern WiFiServer gpsServer;
|
||||
typedef struct {
|
||||
String callsign;
|
||||
} tWebServerCfg;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// Created by Admin on 11.06.2021.
|
||||
//
|
||||
|
||||
#ifndef TTGO_T_BEAM_LORA_APRS_WIFI_CLIENTS_H
|
||||
#define TTGO_T_BEAM_LORA_APRS_WIFI_CLIENTS_H
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiServer.h>
|
||||
|
||||
typedef void (*f_connectedClientCallback_t) (WiFiClient *, int, const String *);
|
||||
void iterateWifiClients(f_connectedClientCallback_t callback, const String *data, WiFiClient * wifiClients[], int maxWifiClients);
|
||||
void check_for_new_clients(WiFiServer *wiFiServer, WiFiClient * wifiClients[], int maxWifiClients);
|
||||
#endif //TTGO_T_BEAM_LORA_APRS_WIFI_CLIENTS_H
|
|
@ -7,7 +7,7 @@ String decode_address_ax25(const String &ax25Address, bool &isLast, bool isRelay
|
|||
|
||||
bool validateKISSFrame(const String &kissFormattedFrame);
|
||||
|
||||
String decapsulateKISS(const String& frame);
|
||||
String decapsulateKISS(const String &frame);
|
||||
|
||||
/*
|
||||
* https://ham.zmailer.org/oh2mqk/aprx/PROTOCOLS
|
||||
|
@ -33,100 +33,112 @@ String decapsulateKISS(const String& frame);
|
|||
|
||||
*/
|
||||
|
||||
String encode_kiss(const String& tnc2FormattedFrame) {
|
||||
String ax25Frame = "";
|
||||
String encode_kiss(const String &tnc2FormattedFrame) {
|
||||
String ax25Frame = "";
|
||||
|
||||
if (validateTNC2Frame(tnc2FormattedFrame)){
|
||||
String address = "";
|
||||
bool dst_addres_written = false;
|
||||
for (int p=0;p<=tnc2FormattedFrame.indexOf(':');p++){
|
||||
char currentChar = tnc2FormattedFrame.charAt(p);
|
||||
if (currentChar == ':' || currentChar == '>' || currentChar == ','){
|
||||
if (!dst_addres_written && (currentChar == ',' || currentChar == ':')){
|
||||
// ax25 frame DST SRC
|
||||
// tnc2 frame SRC DST
|
||||
ax25Frame = encode_address_ax25(address) + ax25Frame;
|
||||
dst_addres_written = true;
|
||||
} else {
|
||||
ax25Frame += encode_address_ax25(address);
|
||||
}
|
||||
address = "";
|
||||
} else {
|
||||
address += currentChar;
|
||||
}
|
||||
if (validateTNC2Frame(tnc2FormattedFrame)) {
|
||||
String address = "";
|
||||
bool dst_addres_written = false;
|
||||
for (int p = 0; p <= tnc2FormattedFrame.indexOf(':'); p++) {
|
||||
char currentChar = tnc2FormattedFrame.charAt(p);
|
||||
if (currentChar == ':' || currentChar == '>' || currentChar == ',') {
|
||||
if (!dst_addres_written && (currentChar == ',' || currentChar == ':')) {
|
||||
// ax25 frame DST SRC
|
||||
// tnc2 frame SRC DST
|
||||
ax25Frame = encode_address_ax25(address) + ax25Frame;
|
||||
dst_addres_written = true;
|
||||
} else {
|
||||
ax25Frame += encode_address_ax25(address);
|
||||
}
|
||||
auto lastAddressChar = (uint8_t)ax25Frame.charAt(ax25Frame.length() - 1);
|
||||
ax25Frame.setCharAt(ax25Frame.length() - 1, (char)(lastAddressChar | IS_LAST_ADDRESS_POSITION_MASK));
|
||||
ax25Frame += (char)APRS_CONTROL_FIELD;
|
||||
ax25Frame += (char)APRS_INFORMATION_FIELD;
|
||||
ax25Frame += tnc2FormattedFrame.substring(tnc2FormattedFrame.indexOf(':')+1);
|
||||
address = "";
|
||||
} else {
|
||||
address += currentChar;
|
||||
}
|
||||
}
|
||||
auto lastAddressChar = (uint8_t) ax25Frame.charAt(ax25Frame.length() - 1);
|
||||
ax25Frame.setCharAt(ax25Frame.length() - 1, (char) (lastAddressChar | IS_LAST_ADDRESS_POSITION_MASK));
|
||||
ax25Frame += (char) APRS_CONTROL_FIELD;
|
||||
ax25Frame += (char) APRS_INFORMATION_FIELD;
|
||||
ax25Frame += tnc2FormattedFrame.substring(tnc2FormattedFrame.indexOf(':') + 1);
|
||||
}
|
||||
|
||||
String kissFrame = encapsulateKISS(ax25Frame, CMD_DATA);
|
||||
return kissFrame;
|
||||
String kissFrame = encapsulateKISS(ax25Frame, CMD_DATA);
|
||||
return kissFrame;
|
||||
}
|
||||
|
||||
String encapsulateKISS(const String &ax25Frame, uint8_t TNCCmd) {
|
||||
String kissFrame = "";
|
||||
kissFrame += (char)FEND; // start of frame
|
||||
kissFrame += (char)(0x0f & TNCCmd); // TNC0, cmd
|
||||
for (int i = 0; i < ax25Frame.length(); ++i) {
|
||||
char currentChar = ax25Frame.charAt(i);
|
||||
if (currentChar == (char)FEND){
|
||||
kissFrame += (char)FESC;
|
||||
kissFrame += (char)TFEND;
|
||||
} else if (currentChar == (char)FESC){
|
||||
kissFrame += (char)FESC;
|
||||
kissFrame += (char)TFESC;
|
||||
} else {
|
||||
kissFrame += currentChar;
|
||||
}
|
||||
String kissFrame = "";
|
||||
kissFrame += (char) FEND; // start of frame
|
||||
kissFrame += (char) (0x0f & TNCCmd); // TNC0, cmd
|
||||
for (int i = 0; i < ax25Frame.length(); ++i) {
|
||||
char currentChar = ax25Frame.charAt(i);
|
||||
if (currentChar == (char) FEND) {
|
||||
kissFrame += (char) FESC;
|
||||
kissFrame += (char) TFEND;
|
||||
} else if (currentChar == (char) FESC) {
|
||||
kissFrame += (char) FESC;
|
||||
kissFrame += (char) TFESC;
|
||||
} else {
|
||||
kissFrame += currentChar;
|
||||
}
|
||||
kissFrame += (char)FEND; // end of frame
|
||||
return kissFrame;
|
||||
}
|
||||
kissFrame += (char) FEND; // end of frame
|
||||
return kissFrame;
|
||||
}
|
||||
|
||||
|
||||
String decapsulateKISS(const String& frame) {
|
||||
String ax25Frame = "";
|
||||
for (int i = 2; i < frame.length() - 1; ++i) {
|
||||
char currentChar = frame.charAt(i);
|
||||
if (currentChar == (char)FESC){
|
||||
char nextChar = frame.charAt(i+1);
|
||||
if (nextChar == (char)TFEND){
|
||||
ax25Frame += (char)FEND;
|
||||
} else if (nextChar == (char)TFESC){
|
||||
ax25Frame += (char)FESC;
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
ax25Frame += currentChar;
|
||||
}
|
||||
String decapsulateKISS(const String &frame) {
|
||||
String ax25Frame = "";
|
||||
for (int i = 2; i < frame.length() - 1; ++i) {
|
||||
char currentChar = frame.charAt(i);
|
||||
if (currentChar == (char) FESC) {
|
||||
char nextChar = frame.charAt(i + 1);
|
||||
if (nextChar == (char) TFEND) {
|
||||
ax25Frame += (char) FEND;
|
||||
} else if (nextChar == (char) TFESC) {
|
||||
ax25Frame += (char) FESC;
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
ax25Frame += currentChar;
|
||||
}
|
||||
}
|
||||
|
||||
return ax25Frame;
|
||||
return ax25Frame;
|
||||
}
|
||||
|
||||
String decode_kiss(const String& kissFormattedFrame) {
|
||||
String TNC2Frame = "";
|
||||
/**
|
||||
*
|
||||
* @param inputKISSTNCFrame
|
||||
* @param dataFrame
|
||||
* @return Decapsulated TNC2KISS APRS data frame, or raw command data frame
|
||||
*/
|
||||
String decode_kiss(const String &inputKISSTNCFrame, bool &dataFrame) {
|
||||
String TNC2Frame = "";
|
||||
|
||||
if (validateKISSFrame(kissFormattedFrame)){
|
||||
String ax25Frame = decapsulateKISS(kissFormattedFrame);
|
||||
bool isLast = false;
|
||||
String dst_addr = decode_address_ax25(ax25Frame.substring(0, 7), isLast, false);
|
||||
String src_addr = decode_address_ax25(ax25Frame.substring(7, 14), isLast, false);
|
||||
TNC2Frame = src_addr + ">" + dst_addr;
|
||||
int digi_info_index = 14;
|
||||
while (!isLast && digi_info_index + 7 < ax25Frame.length()){
|
||||
String digi_addr = decode_address_ax25(ax25Frame.substring(digi_info_index, digi_info_index + 7), isLast, true);
|
||||
TNC2Frame += ',' + digi_addr;
|
||||
digi_info_index += 7;
|
||||
}
|
||||
TNC2Frame += ':';
|
||||
TNC2Frame += ax25Frame.substring(digi_info_index + 2);
|
||||
if (validateKISSFrame(inputKISSTNCFrame)) {
|
||||
dataFrame = inputKISSTNCFrame.charAt(1) == CMD_DATA;
|
||||
if (dataFrame){
|
||||
String ax25Frame = decapsulateKISS(inputKISSTNCFrame);
|
||||
bool isLast = false;
|
||||
String dst_addr = decode_address_ax25(ax25Frame.substring(0, 7), isLast, false);
|
||||
String src_addr = decode_address_ax25(ax25Frame.substring(7, 14), isLast, false);
|
||||
TNC2Frame = src_addr + ">" + dst_addr;
|
||||
int digi_info_index = 14;
|
||||
while (!isLast && digi_info_index + 7 < ax25Frame.length()) {
|
||||
String digi_addr = decode_address_ax25(ax25Frame.substring(digi_info_index, digi_info_index + 7), isLast, true);
|
||||
TNC2Frame += ',' + digi_addr;
|
||||
digi_info_index += 7;
|
||||
}
|
||||
TNC2Frame += ':';
|
||||
TNC2Frame += ax25Frame.substring(digi_info_index + 2);
|
||||
} else {
|
||||
// command frame, currently ignored
|
||||
TNC2Frame += inputKISSTNCFrame;
|
||||
}
|
||||
}
|
||||
|
||||
return TNC2Frame;
|
||||
return TNC2Frame;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,32 +147,32 @@ String decode_kiss(const String& kissFormattedFrame) {
|
|||
* @return
|
||||
*/
|
||||
String encode_address_ax25(String tnc2Address) {
|
||||
bool hasBeenDigipited = tnc2Address.indexOf('*') != -1;
|
||||
bool hasBeenDigipited = tnc2Address.indexOf('*') != -1;
|
||||
|
||||
if (tnc2Address.indexOf('-') == -1){
|
||||
if (hasBeenDigipited){
|
||||
// ex. TCPIP* in tnc2Address
|
||||
// so we skip last char
|
||||
tnc2Address = tnc2Address.substring(0, tnc2Address.length()-1);
|
||||
}
|
||||
tnc2Address += "-0";
|
||||
if (tnc2Address.indexOf('-') == -1) {
|
||||
if (hasBeenDigipited) {
|
||||
// ex. TCPIP* in tnc2Address
|
||||
// so we skip last char
|
||||
tnc2Address = tnc2Address.substring(0, tnc2Address.length() - 1);
|
||||
}
|
||||
tnc2Address += "-0";
|
||||
}
|
||||
|
||||
int separatorIndex = tnc2Address.indexOf('-');
|
||||
int ssid = tnc2Address.substring(separatorIndex + 1).toInt();
|
||||
// TODO: SSID should not be > 16
|
||||
String kissAddress = "";
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
char addressChar;
|
||||
if (tnc2Address.length() > i && i < separatorIndex){
|
||||
addressChar = tnc2Address.charAt(i);
|
||||
} else {
|
||||
addressChar = ' ';
|
||||
}
|
||||
kissAddress += (char)(addressChar << 1);
|
||||
int separatorIndex = tnc2Address.indexOf('-');
|
||||
int ssid = tnc2Address.substring(separatorIndex + 1).toInt();
|
||||
// TODO: SSID should not be > 16
|
||||
String kissAddress = "";
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
char addressChar;
|
||||
if (tnc2Address.length() > i && i < separatorIndex) {
|
||||
addressChar = tnc2Address.charAt(i);
|
||||
} else {
|
||||
addressChar = ' ';
|
||||
}
|
||||
kissAddress += (char)((ssid << 1) | 0b01100000 | (hasBeenDigipited ? HAS_BEEN_DIGIPITED_MASK : 0));
|
||||
return kissAddress;
|
||||
kissAddress += (char) (addressChar << 1);
|
||||
}
|
||||
kissAddress += (char) ((ssid << 1) | 0b01100000 | (hasBeenDigipited ? HAS_BEEN_DIGIPITED_MASK : 0));
|
||||
return kissAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,30 +181,35 @@ String encode_address_ax25(String tnc2Address) {
|
|||
* @return
|
||||
*/
|
||||
String decode_address_ax25(const String &ax25Address, bool &isLast, bool isRelay) {
|
||||
String TNCAddress = "";
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
uint8_t currentCharacter = ax25Address.charAt(i);
|
||||
currentCharacter >>= 1;
|
||||
if (currentCharacter != ' '){
|
||||
TNCAddress += (char)currentCharacter;
|
||||
}
|
||||
String TNCAddress = "";
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
uint8_t currentCharacter = ax25Address.charAt(i);
|
||||
currentCharacter >>= 1;
|
||||
if (currentCharacter != ' ') {
|
||||
TNCAddress += (char) currentCharacter;
|
||||
}
|
||||
auto ssid_char = (uint8_t) ax25Address.charAt(6);
|
||||
bool hasBeenDigipited = ssid_char & HAS_BEEN_DIGIPITED_MASK;
|
||||
isLast = ssid_char & IS_LAST_ADDRESS_POSITION_MASK;
|
||||
ssid_char >>= 1;
|
||||
}
|
||||
auto ssid_char = (uint8_t) ax25Address.charAt(6);
|
||||
bool hasBeenDigipited = ssid_char & HAS_BEEN_DIGIPITED_MASK;
|
||||
isLast = ssid_char & IS_LAST_ADDRESS_POSITION_MASK;
|
||||
ssid_char >>= 1;
|
||||
|
||||
int ssid = 0b1111 & ssid_char;
|
||||
if (ssid){
|
||||
TNCAddress += '-';
|
||||
TNCAddress += ssid;
|
||||
}
|
||||
if (isRelay && hasBeenDigipited){
|
||||
TNCAddress += '*';
|
||||
}
|
||||
return TNCAddress;
|
||||
int ssid = 0b1111 & ssid_char;
|
||||
if (ssid) {
|
||||
TNCAddress += '-';
|
||||
TNCAddress += ssid;
|
||||
}
|
||||
if (isRelay && hasBeenDigipited) {
|
||||
TNCAddress += '*';
|
||||
}
|
||||
return TNCAddress;
|
||||
}
|
||||
|
||||
bool validateTNC2Frame(const String &tnc2FormattedFrame) { return (tnc2FormattedFrame.indexOf(':') != -1) && (tnc2FormattedFrame.indexOf('>') != -1); }
|
||||
bool validateTNC2Frame(const String &tnc2FormattedFrame) {
|
||||
return (tnc2FormattedFrame.indexOf(':') != -1) && (tnc2FormattedFrame.indexOf('>') != -1);
|
||||
}
|
||||
|
||||
bool validateKISSFrame(const String &kissFormattedFrame) { return kissFormattedFrame.charAt(0) == (char)FEND && kissFormattedFrame.charAt(kissFormattedFrame.length() - 1) == (char)FEND; }
|
||||
bool validateKISSFrame(const String &kissFormattedFrame) {
|
||||
return kissFormattedFrame.charAt(0) == (char) FEND &&
|
||||
kissFormattedFrame.charAt(kissFormattedFrame.length() - 1) == (char) FEND;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
#define IS_LAST_ADDRESS_POSITION_MASK 0b1
|
||||
|
||||
String encode_kiss(const String& tnc2FormattedFrame);
|
||||
String decode_kiss(const String& kissFormattedFrame);
|
||||
String decode_kiss(const String &inputKISSTNCFrame, bool &dataFrame);
|
||||
|
||||
String encapsulateKISS(const String &ax25Frame, uint8_t TNCCmd);
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Created by Admin on 14.06.2021.
|
||||
//
|
||||
|
||||
#ifndef TTGO_T_BEAM_LORA_APRS_PSRAMJSONDOCUMENT_H
|
||||
#define TTGO_T_BEAM_LORA_APRS_PSRAMJSONDOCUMENT_H
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
struct SpiRamAllocator {
|
||||
void* allocate(size_t size) {
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
void deallocate(void* pointer) {
|
||||
heap_caps_free(pointer);
|
||||
}
|
||||
|
||||
void* reallocate(void* ptr, size_t new_size) {
|
||||
return heap_caps_realloc(ptr, new_size, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
};
|
||||
|
||||
using PSRAMJsonDocument = BasicJsonDocument<SpiRamAllocator>;
|
||||
|
||||
|
||||
#endif //TTGO_T_BEAM_LORA_APRS_PSRAMJSONDOCUMENT_H
|
|
@ -51,6 +51,7 @@ build_flags =
|
|||
-D 'NETWORK_TNC_PORT=8001' ; default KISS TCP port
|
||||
-D 'MAX_TIME_TO_NEXT_TX=120000L' ; can be set from www interfeace
|
||||
-D 'FIX_BEACON_INTERVAL=1800000L' ; can be set from www interfeace
|
||||
-D 'NETWORK_GPS_PORT=10110' ; GPS NMEA Port
|
||||
|
||||
[env:ttgo-t-beam-v1.0]
|
||||
platform = espressif32 @ 3.0.0
|
||||
|
@ -117,9 +118,9 @@ build_flags =
|
|||
-D T_BEAM_V1_0
|
||||
-D ENABLE_WIFI
|
||||
-D ENABLE_BLUETOOTH
|
||||
;-D ENABLE_SYSLOG
|
||||
;-D 'SYSLOG_IP="192.168.0.102"'
|
||||
;-D DEVELOPMENT_DEBUG
|
||||
;lib_deps =
|
||||
; ${env.lib_deps}
|
||||
; arcao/Syslog
|
||||
-D ENABLE_SYSLOG
|
||||
-D 'SYSLOG_IP="192.168.0.102"'
|
||||
-D DEVELOPMENT_DEBUG
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
arcao/Syslog
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
#include <taskGPS.h>
|
||||
#include <SparkFun_Ublox_Arduino_Library.h>
|
||||
#include <taskWebServer.h>
|
||||
|
||||
|
||||
SFE_UBLOX_GPS myGPS;
|
||||
|
||||
#ifdef ENABLE_WIFI
|
||||
#include "wifi_clients.h"
|
||||
#define MAX_GPS_WIFI_CLIENTS 6
|
||||
WiFiClient * gps_clients[MAX_GPS_WIFI_CLIENTS];
|
||||
#endif
|
||||
|
||||
// Pins for GPS
|
||||
#ifdef T_BEAM_V1_0
|
||||
static const int RXPin = 12, TXPin = 34;
|
||||
|
@ -14,7 +22,7 @@ HardwareSerial gpsSerial(1); // TTGO has HW serial
|
|||
TinyGPSPlus gps; // The TinyGPS++ object
|
||||
bool gpsInitialized = false;
|
||||
|
||||
void taskGPS(void *parameter) {
|
||||
[[noreturn]] void taskGPS(void *parameter) {
|
||||
if (!gpsInitialized){
|
||||
gpsSerial.begin(GPSBaud, SERIAL_8N1, TXPin, RXPin); //Startup HW serial for GPS
|
||||
|
||||
|
@ -35,9 +43,29 @@ void taskGPS(void *parameter) {
|
|||
}
|
||||
}
|
||||
|
||||
String gpsDataBuffer = " ";
|
||||
for (;;) {
|
||||
check_for_new_clients(&gpsServer, gps_clients, MAX_GPS_WIFI_CLIENTS);
|
||||
while (gpsSerial.available() > 0) {
|
||||
gps.encode(gpsSerial.read());
|
||||
char gpsChar = (char)gpsSerial.read();
|
||||
gps.encode(gpsChar);
|
||||
#ifdef ENABLE_WIFI
|
||||
if (gpsChar == '$') {
|
||||
gpsDataBuffer = String(gpsChar);
|
||||
} else {
|
||||
gpsDataBuffer += String(gpsChar);
|
||||
|
||||
if (gpsChar == '\n') {
|
||||
iterateWifiClients([](WiFiClient *client, int clientIdx, const String *data){
|
||||
if (client->connected()){
|
||||
client->print(*data);
|
||||
client->flush();
|
||||
}
|
||||
}, &gpsDataBuffer, gps_clients, MAX_GPS_WIFI_CLIENTS);
|
||||
gpsDataBuffer = "";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
|
|
@ -9,25 +9,6 @@ QueueHandle_t tncReceivedQueue = nullptr;
|
|||
#ifdef ENABLE_WIFI
|
||||
#define MAX_WIFI_CLIENTS 6
|
||||
WiFiClient * clients[MAX_WIFI_CLIENTS];
|
||||
|
||||
typedef void (*f_connectedClientCallback_t) (WiFiClient *, int, const String *);
|
||||
|
||||
void iterateWifiClients(f_connectedClientCallback_t callback, const String *data){
|
||||
for (int i=0; i<MAX_WIFI_CLIENTS; i++) {
|
||||
auto client = clients[i];
|
||||
if (client != nullptr) {
|
||||
if (client->connected()) {
|
||||
callback(client, i, data);
|
||||
} else {
|
||||
#ifdef ENABLE_WIFI_CLIENT_DEBUG
|
||||
Serial.println(String("Disconnected client ") + client->remoteIP().toString() + ":" + client->remotePort());
|
||||
#endif
|
||||
delete client;
|
||||
clients[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_WIFI
|
||||
#define IN_TNC_BUFFERS (2+MAX_WIFI_CLIENTS)
|
||||
|
@ -52,28 +33,31 @@ void handleKISSData(char character, int bufferIndex) {
|
|||
}
|
||||
inTNCData->concat(character);
|
||||
if (character == (char) FEND && inTNCData->length() > 3) {
|
||||
const String &TNC2DataFrame = decode_kiss(*inTNCData);
|
||||
bool isDataFrame = false;
|
||||
const String &TNC2DataFrame = decode_kiss(*inTNCData, isDataFrame);
|
||||
|
||||
#ifdef LOCAL_KISS_ECHO
|
||||
if (isDataFrame) {
|
||||
#ifdef LOCAL_KISS_ECHO
|
||||
Serial.print(inTNCData);
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
if (SerialBT.hasClient()) {
|
||||
SerialBT.print(inTNCData);
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_WIFI
|
||||
#endif
|
||||
#ifdef ENABLE_WIFI
|
||||
iterateWifiClients([](WiFiClient *client, const String *data){
|
||||
if (client->connected()){
|
||||
client->print(*data);
|
||||
client->flush();
|
||||
}
|
||||
}, &inTNCData);
|
||||
}, &inTNCData, clients, MAX_WIFI_CLIENTS);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
auto *buffer = new String();
|
||||
buffer->concat(TNC2DataFrame);
|
||||
if (xQueueSend(tncToSendQueue, &buffer, (1000 / portTICK_PERIOD_MS)) != pdPASS){
|
||||
delete buffer;
|
||||
auto *buffer = new String();
|
||||
buffer->concat(TNC2DataFrame);
|
||||
if (xQueueSend(tncToSendQueue, &buffer, (1000 / portTICK_PERIOD_MS)) != pdPASS) {
|
||||
delete buffer;
|
||||
}
|
||||
}
|
||||
inTNCData->clear();
|
||||
}
|
||||
|
@ -103,45 +87,14 @@ void handleKISSData(char character, int bufferIndex) {
|
|||
}
|
||||
#endif
|
||||
#ifdef ENABLE_WIFI
|
||||
WiFiClient new_client = tncServer.available();
|
||||
if (new_client.connected()){
|
||||
bool new_client_handled = false;
|
||||
for (int i=0; i < MAX_WIFI_CLIENTS; i++) {
|
||||
auto client = clients[i];
|
||||
if (client == nullptr) {
|
||||
client = new WiFiClient(new_client);
|
||||
clients[i] = client;
|
||||
new_client_handled = true;
|
||||
#ifdef ENABLE_WIFI_CLIENT_DEBUG
|
||||
Serial.println(String("New client #") +String(i) + ": " + client->remoteIP().toString() + ":" + client->remotePort());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_WIFI_CLIENT_DEBUG
|
||||
for (int i = 0; i < MAX_WIFI_CLIENTS; ++i) {
|
||||
auto client = clients[i];
|
||||
check_for_new_clients(&tncServer, clients, MAX_WIFI_CLIENTS);
|
||||
|
||||
if (client != nullptr){
|
||||
Serial.println(String("Client #") +String(i) + ": " + client->remoteIP().toString() + ":" + client->remotePort());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (!new_client_handled){
|
||||
#ifdef ENABLE_WIFI_CLIENT_DEBUG
|
||||
Serial.println(String("Refusing client "));
|
||||
#endif
|
||||
new_client.stop();
|
||||
}
|
||||
}
|
||||
iterateWifiClients([](WiFiClient * client, int clientIdx, const String * unused){
|
||||
while (client->available() > 0) {
|
||||
char character = client->read();
|
||||
handleKISSData(character, 2+clientIdx);
|
||||
}
|
||||
}, nullptr);
|
||||
}, nullptr, clients, MAX_WIFI_CLIENTS);
|
||||
|
||||
#endif
|
||||
if (xQueueReceive(tncReceivedQueue, &loraReceivedFrameString, (1 / portTICK_PERIOD_MS)) == pdPASS) {
|
||||
|
@ -158,7 +111,7 @@ void handleKISSData(char character, int bufferIndex) {
|
|||
client->print(*data);
|
||||
client->flush();
|
||||
}
|
||||
}, &kissEncoded);
|
||||
}, &kissEncoded, clients, MAX_WIFI_CLIENTS);
|
||||
#endif
|
||||
|
||||
delete loraReceivedFrameString;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "taskWebServer.h"
|
||||
#include "preference_storage.h"
|
||||
#include "syslog_log.h"
|
||||
#include "PSRAMJsonDocument.h"
|
||||
#include <time.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
|
@ -17,7 +18,7 @@ extern const char web_js_js_end[] asm("_binary_data_embed_js_js_out_end");
|
|||
|
||||
QueueHandle_t webListReceivedQueue = nullptr;
|
||||
std::list <tReceivedPacketData*> receivedPackets;
|
||||
const int MAX_RECEIVED_LIST_SIZE = 10;
|
||||
const int MAX_RECEIVED_LIST_SIZE = 50;
|
||||
|
||||
String apSSID = "";
|
||||
String apPassword = "xxxxxxxxxx";
|
||||
|
@ -25,6 +26,7 @@ WebServer server(80);
|
|||
#ifdef KISS_PROTOCOL
|
||||
WiFiServer tncServer(NETWORK_TNC_PORT);
|
||||
#endif
|
||||
WiFiServer gpsServer(NETWORK_GPS_PORT);
|
||||
|
||||
#ifdef ENABLE_SYSLOG
|
||||
// A UDP instance to let us send and receive packets over UDP
|
||||
|
@ -34,6 +36,12 @@ WebServer server(80);
|
|||
Syslog syslog(udpClient, SYSLOG_PROTO_IETF);
|
||||
#endif
|
||||
|
||||
#ifdef T_BEAM_V1_0
|
||||
#include <axp20x.h>
|
||||
extern AXP20X_Class axp;
|
||||
#endif
|
||||
|
||||
|
||||
void sendCacheHeader() { server.sendHeader("Cache-Control", "max-age=3600"); }
|
||||
void sendGzipHeader() { server.sendHeader("Content-Encoding", "gzip"); }
|
||||
|
||||
|
@ -118,9 +126,20 @@ void handle_SaveWifiCfg() {
|
|||
void handle_Reboot() {
|
||||
server.sendHeader("Location", "/");
|
||||
server.send(302,"text/html", "");
|
||||
server.close();
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void handle_Shutdown() {
|
||||
|
||||
#ifdef T_BEAM_V1_0
|
||||
server.send(200,"text/html", "Shutdown");
|
||||
axp.shutdown();
|
||||
#else
|
||||
server.send(404,"text/html", "Not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
void handle_Restore() {
|
||||
server.sendHeader("Location", "/");
|
||||
server.send(302,"text/html", "");
|
||||
|
@ -160,14 +179,16 @@ void handle_Cfg() {
|
|||
jsonData += jsonLineFromPreferenceInt(PREF_DEV_AUTO_SHUT_PRESET);
|
||||
jsonData += jsonLineFromInt("FreeHeap", ESP.getFreeHeap());
|
||||
jsonData += jsonLineFromInt("HeapSize", ESP.getHeapSize());
|
||||
jsonData += jsonLineFromInt("FreeSketchSpace", ESP.getFreeSketchSpace(), true);
|
||||
jsonData += jsonLineFromInt("FreeSketchSpace", ESP.getFreeSketchSpace());
|
||||
jsonData += jsonLineFromInt("PSRAMSize", ESP.getPsramSize());
|
||||
jsonData += jsonLineFromInt("PSRAMFree", ESP.getFreePsram(), true);
|
||||
|
||||
jsonData += "}";
|
||||
server.send(200,"application/json", jsonData);
|
||||
}
|
||||
|
||||
void handle_ReceivedList() {
|
||||
DynamicJsonDocument doc(MAX_RECEIVED_LIST_SIZE * 500);
|
||||
PSRAMJsonDocument doc(MAX_RECEIVED_LIST_SIZE * 1000);
|
||||
JsonObject root = doc.to<JsonObject>();
|
||||
auto received = root.createNestedArray("received");
|
||||
for (auto element: receivedPackets){
|
||||
|
@ -270,13 +291,14 @@ void handle_saveDeviceCfg(){
|
|||
server.on("/scan_wifi", handle_ScanWifi);
|
||||
server.on("/save_wifi_cfg", handle_SaveWifiCfg);
|
||||
server.on("/reboot", handle_Reboot);
|
||||
server.on("/shutdown", handle_Shutdown);
|
||||
server.on("/cfg", handle_Cfg);
|
||||
server.on("/received_list", handle_ReceivedList);
|
||||
server.on("/save_aprs_cfg", handle_SaveAPRSCfg);
|
||||
server.on("/save_device_cfg", handle_saveDeviceCfg);
|
||||
server.on("/restore", handle_Restore);
|
||||
server.on("/update", HTTP_POST, []() {
|
||||
syslog_log(LOG_WARNING, String("Update finished. Status: ") + (Update.hasError() ? "Ok" : "Error"));
|
||||
syslog_log(LOG_WARNING, String("Update finished. Status: ") + (!Update.hasError() ? "Ok" : "Error"));
|
||||
server.sendHeader("Connection", "close");
|
||||
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
|
||||
delay(500);
|
||||
|
@ -360,6 +382,7 @@ void handle_saveDeviceCfg(){
|
|||
#ifdef KISS_PROTOCOL
|
||||
tncServer.begin();
|
||||
#endif
|
||||
gpsServer.begin();
|
||||
if (MDNS.begin(webServerCfg->callsign.c_str())) {
|
||||
MDNS.setInstanceName(webServerCfg->callsign + " TTGO LoRa APRS TNC " + TXFREQ + "MHz");
|
||||
MDNS.addService("http", "tcp", 80);
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Created by Admin on 11.06.2021.
|
||||
//
|
||||
|
||||
#ifdef ENABLE_WIFI
|
||||
|
||||
#include <wifi_clients.h>
|
||||
|
||||
#include "wifi_clients.h"
|
||||
|
||||
void iterateWifiClients(f_connectedClientCallback_t callback, const String *data, WiFiClient * wifiClients[], int maxWifiClients){
|
||||
for (int i=0; i < maxWifiClients; i++) {
|
||||
auto client = wifiClients[i];
|
||||
if (client != nullptr) {
|
||||
if (client->connected()) {
|
||||
callback(client, i, data);
|
||||
} else {
|
||||
#ifdef ENABLE_WIFI_CLIENT_DEBUG
|
||||
Serial.println(String("Disconnected client ") + client->remoteIP().toString() + ":" + client->remotePort());
|
||||
#endif
|
||||
delete client;
|
||||
wifiClients[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_for_new_clients(WiFiServer *wiFiServer, WiFiClient *wifiClients[], int maxWifiClients) {
|
||||
WiFiClient new_client = wiFiServer->available();
|
||||
if (new_client.connected()){
|
||||
bool new_client_handled = false;
|
||||
for (int i=0; i < maxWifiClients; i++) {
|
||||
auto client = wifiClients[i];
|
||||
if (client == nullptr) {
|
||||
client = new WiFiClient(new_client);
|
||||
wifiClients[i] = client;
|
||||
new_client_handled = true;
|
||||
#ifdef ENABLE_WIFI_CLIENT_DEBUG
|
||||
Serial.println(String("New client #") +String(i) + ": " + client->remoteIP().toString() + ":" + client->remotePort());
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_WIFI_CLIENT_DEBUG
|
||||
for (int i = 0; i < maxWifiClients; ++i) {
|
||||
auto client = clients[i];
|
||||
|
||||
if (client != nullptr){
|
||||
Serial.println(String("Client #") +String(i) + ": " + client->remoteIP().toString() + ":" + client->remotePort());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (!new_client_handled){
|
||||
#ifdef ENABLE_WIFI_CLIENT_DEBUG
|
||||
Serial.println(String("Refusing client "));
|
||||
#endif
|
||||
new_client.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Ładowanie…
Reference in New Issue