Merge branch 'master' into tft-gui-work

This commit is contained in:
Manuel 2024-06-15 11:56:23 +02:00 committed by GitHub
commit 8a2e29d45a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 226 additions and 21 deletions

View File

@ -73,6 +73,7 @@ build_flags = -Wno-missing-field-initializers
-DRADIOLIB_EXCLUDE_FSK4 -DRADIOLIB_EXCLUDE_FSK4
-DRADIOLIB_EXCLUDE_APRS -DRADIOLIB_EXCLUDE_APRS
-DRADIOLIB_EXCLUDE_LORAWAN -DRADIOLIB_EXCLUDE_LORAWAN
-DMESHTASTIC_EXCLUDE_DROPZONE=1
monitor_speed = 115200 monitor_speed = 115200

View File

@ -117,8 +117,16 @@ class LGFX : public lgfx::LGFX_Device
static LGFX *tft = nullptr; static LGFX *tft = nullptr;
#elif defined(RAK14014) #elif defined(RAK14014)
#include <RAK14014_FT6336U.h>
#include <TFT_eSPI.h> #include <TFT_eSPI.h>
TFT_eSPI *tft = nullptr; TFT_eSPI *tft = nullptr;
FT6336U ft6336u;
static uint8_t _rak14014_touch_int = false; // TP interrupt generation flag.
static void rak14014_tpIntHandle(void)
{
_rak14014_touch_int = true;
}
#elif defined(ST7789_CS) #elif defined(ST7789_CS)
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip #include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
@ -653,8 +661,12 @@ void TFTDisplay::sendCommand(uint8_t com)
void TFTDisplay::setDisplayBrightness(uint8_t _brightness) void TFTDisplay::setDisplayBrightness(uint8_t _brightness)
{ {
#ifdef RAK14014
// todo
#else
tft->setBrightness(_brightness); tft->setBrightness(_brightness);
LOG_DEBUG("Brightness is set to value: %i \n", _brightness); LOG_DEBUG("Brightness is set to value: %i \n", _brightness);
#endif
} }
void TFTDisplay::flipScreenVertically() void TFTDisplay::flipScreenVertically()
@ -668,6 +680,7 @@ void TFTDisplay::flipScreenVertically()
bool TFTDisplay::hasTouch(void) bool TFTDisplay::hasTouch(void)
{ {
#ifdef RAK14014 #ifdef RAK14014
return true;
#elif !defined(M5STACK) #elif !defined(M5STACK)
return tft->touch() != nullptr; return tft->touch() != nullptr;
#else #else
@ -678,6 +691,15 @@ bool TFTDisplay::hasTouch(void)
bool TFTDisplay::getTouch(int16_t *x, int16_t *y) bool TFTDisplay::getTouch(int16_t *x, int16_t *y)
{ {
#ifdef RAK14014 #ifdef RAK14014
if (_rak14014_touch_int) {
_rak14014_touch_int = false;
/* The X and Y axes have to be switched */
*y = ft6336u.read_touch1_x();
*x = TFT_HEIGHT - ft6336u.read_touch1_y();
return true;
} else {
return false;
}
#elif !defined(M5STACK) #elif !defined(M5STACK)
return tft->getTouch(x, y); return tft->getTouch(x, y);
#else #else
@ -727,7 +749,10 @@ bool TFTDisplay::connect()
#elif defined(RAK14014) #elif defined(RAK14014)
tft->setRotation(1); tft->setRotation(1);
tft->setSwapBytes(true); tft->setSwapBytes(true);
// tft->fillScreen(TFT_BLACK); // tft->fillScreen(TFT_BLACK);
ft6336u.begin();
pinMode(SCREEN_TOUCH_INT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(SCREEN_TOUCH_INT), rak14014_tpIntHandle, FALLING);
#elif defined(T_DECK) || defined(PICOMPUTER_S3) || defined(CHATTER_2) #elif defined(T_DECK) || defined(PICOMPUTER_S3) || defined(CHATTER_2)
tft->setRotation(1); // T-Deck has the TFT in landscape tft->setRotation(1); // T-Deck has the TFT in landscape
#elif defined(T_WATCH_S3) #elif defined(T_WATCH_S3)

View File

@ -49,7 +49,7 @@ CannedMessageModule::CannedMessageModule()
LOG_INFO("CannedMessageModule is enabled\n"); LOG_INFO("CannedMessageModule is enabled\n");
// T-Watch interface currently has no way to select destination type, so default to 'node' // T-Watch interface currently has no way to select destination type, so default to 'node'
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE;
#endif #endif
@ -75,7 +75,7 @@ int CannedMessageModule::splitConfiguredMessages()
String messages = cannedMessageModuleConfig.messages; String messages = cannedMessageModuleConfig.messages;
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
String separator = messages.length() ? "|" : ""; String separator = messages.length() ? "|" : "";
messages = "[---- Free Text ----]" + separator + messages; messages = "[---- Free Text ----]" + separator + messages;
@ -144,7 +144,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
} }
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) { if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) {
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
if (this->currentMessageIndex == 0) { if (this->currentMessageIndex == 0) {
this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT; this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT;
@ -170,7 +170,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
e.frameChanged = true; e.frameChanged = true;
this->currentMessageIndex = -1; this->currentMessageIndex = -1;
#ifndef T_WATCH_S3 #if !defined(T_WATCH_S3) && !defined(RAK14014)
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
@ -183,7 +183,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) || (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) ||
(event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) { (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) {
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) { if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) {
this->payload = 0xb4; this->payload = 0xb4;
} else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) { } else if (event->inputEvent == static_cast<char>(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) {
@ -283,7 +283,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event)
} }
} }
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
String keyTapped = keyForCoordinates(event->touchX, event->touchY); String keyTapped = keyForCoordinates(event->touchX, event->touchY);
@ -404,7 +404,7 @@ int32_t CannedMessageModule::runOnce()
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
#ifndef T_WATCH_S3 #if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
#endif #endif
@ -417,7 +417,7 @@ int32_t CannedMessageModule::runOnce()
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
#ifndef T_WATCH_S3 #if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
#endif #endif
@ -437,7 +437,7 @@ int32_t CannedMessageModule::runOnce()
powerFSM.trigger(EVENT_PRESS); powerFSM.trigger(EVENT_PRESS);
return INT32_MAX; return INT32_MAX;
} else { } else {
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
sendText(this->dest, indexChannels[this->channel], this->messages[this->currentMessageIndex], true); sendText(this->dest, indexChannels[this->channel], this->messages[this->currentMessageIndex], true);
#else #else
sendText(NODENUM_BROADCAST, channels.getPrimaryIndex(), this->messages[this->currentMessageIndex], true); sendText(NODENUM_BROADCAST, channels.getPrimaryIndex(), this->messages[this->currentMessageIndex], true);
@ -454,7 +454,7 @@ int32_t CannedMessageModule::runOnce()
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
#ifndef T_WATCH_S3 #if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
#endif #endif
@ -471,7 +471,7 @@ int32_t CannedMessageModule::runOnce()
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
#ifndef T_WATCH_S3 #if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
#endif #endif
@ -484,7 +484,7 @@ int32_t CannedMessageModule::runOnce()
this->freetext = ""; // clear freetext this->freetext = ""; // clear freetext
this->cursor = 0; this->cursor = 0;
#ifndef T_WATCH_S3 #if !defined(T_WATCH_S3) && !defined(RAK14014)
this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE;
#endif #endif
@ -714,7 +714,7 @@ void CannedMessageModule::showTemporaryMessage(const String &message)
setIntervalFromNow(2000); setIntervalFromNow(2000);
} }
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
String CannedMessageModule::keyForCoordinates(uint x, uint y) String CannedMessageModule::keyForCoordinates(uint x, uint y)
{ {
@ -950,7 +950,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled."); display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled.");
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) {
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
drawKeyboard(display, state, 0, 0); drawKeyboard(display, state, 0, 0);
#else #else

View File

@ -98,7 +98,7 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
int getNextIndex(); int getNextIndex();
int getPrevIndex(); int getPrevIndex();
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
void drawKeyboard(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); void drawKeyboard(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
String keyForCoordinates(uint x, uint y); String keyForCoordinates(uint x, uint y);
bool shift = false; bool shift = false;
@ -152,7 +152,7 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
unsigned long lastTouchMillis = 0; unsigned long lastTouchMillis = 0;
String temporaryMessage; String temporaryMessage;
#ifdef T_WATCH_S3 #if defined(T_WATCH_S3) || defined(RAK14014)
Letter keyboard[2][4][10] = {{{{"Q", 20, 0, 0, 0, 0}, Letter keyboard[2][4][10] = {{{{"Q", 20, 0, 0, 0, 0},
{"W", 22, 0, 0, 0, 0}, {"W", 22, 0, 0, 0, 0},
{"E", 17, 0, 0, 0, 0}, {"E", 17, 0, 0, 0, 0},

View File

@ -0,0 +1,95 @@
#if !MESHTASTIC_EXCLUDE_DROPZONE
#include "DropzoneModule.h"
#include "MeshService.h"
#include "configuration.h"
#include "gps/GeoCoord.h"
#include "gps/RTC.h"
#include "main.h"
#include <assert.h>
#include "modules/Telemetry/Sensor/DFRobotLarkSensor.h"
#include "modules/Telemetry/UnitConversions.h"
#include <string>
DropzoneModule *dropzoneModule;
int32_t DropzoneModule::runOnce()
{
// Send on a 5 second delay from receiving the matching request
if (startSendConditions != 0 && (startSendConditions + 5000U) < millis()) {
service.sendToMesh(sendConditions(), RX_SRC_LOCAL);
startSendConditions = 0;
}
// Run every second to check if we need to send conditions
return 1000;
}
ProcessMessage DropzoneModule::handleReceived(const meshtastic_MeshPacket &mp)
{
auto &p = mp.decoded;
char matchCompare[54];
auto incomingMessage = reinterpret_cast<const char *>(p.payload.bytes);
sprintf(matchCompare, "%s conditions", owner.short_name);
if (strncasecmp(incomingMessage, matchCompare, strlen(matchCompare)) == 0) {
LOG_DEBUG("Received dropzone conditions request\n");
startSendConditions = millis();
}
sprintf(matchCompare, "%s conditions", owner.long_name);
if (strncasecmp(incomingMessage, matchCompare, strlen(matchCompare)) == 0) {
LOG_DEBUG("Received dropzone conditions request\n");
startSendConditions = millis();
}
return ProcessMessage::CONTINUE;
}
meshtastic_MeshPacket *DropzoneModule::sendConditions()
{
char replyStr[200];
/*
CLOSED @ {HH:MM:SS}z
Wind 2 kts @ 125°
29.25 inHg 72°C
*/
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
int hour = 0, min = 0, sec = 0;
if (rtc_sec > 0) {
long hms = rtc_sec % SEC_PER_DAY;
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
hour = hms / SEC_PER_HOUR;
min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN;
}
// Check if the dropzone is open or closed by reading the analog pin
// If pin is connected to GND (below 100 should be lower than floating voltage),
// the dropzone is open
auto dropzoneStatus = analogRead(A1) < 100 ? "OPEN" : "CLOSED";
auto reply = allocDataPacket();
auto node = nodeDB->getMeshNode(nodeDB->getNodeNum());
if (sensor.hasSensor()) {
meshtastic_Telemetry telemetry = meshtastic_Telemetry_init_zero;
sensor.getMetrics(&telemetry);
auto windSpeed = UnitConversions::MetersPerSecondToKnots(telemetry.variant.environment_metrics.wind_speed);
auto windDirection = telemetry.variant.environment_metrics.wind_direction;
auto temp = telemetry.variant.environment_metrics.temperature;
auto baro = UnitConversions::HectoPascalToInchesOfMercury(telemetry.variant.environment_metrics.barometric_pressure);
sprintf(replyStr, "%s @ %02d:%02d:%02dz\nWind %.2f kts @ %d°\nBaro %.2f inHg %.2f°C", dropzoneStatus, hour, min, sec,
windSpeed, windDirection, baro, temp);
} else {
LOG_ERROR("No sensor found\n");
sprintf(replyStr, "%s @ %02d:%02d:%02d\nNo sensor found", dropzoneStatus, hour, min, sec);
}
LOG_DEBUG("Conditions reply: %s\n", replyStr);
reply->decoded.payload.size = strlen(replyStr); // You must specify how many bytes are in the reply
memcpy(reply->decoded.payload.bytes, replyStr, reply->decoded.payload.size);
return reply;
}
#endif

View File

@ -0,0 +1,37 @@
#pragma once
#if !MESHTASTIC_EXCLUDE_DROPZONE
#include "SinglePortModule.h"
#include "modules/Telemetry/Sensor/DFRobotLarkSensor.h"
/**
* An example module that replies to a message with the current conditions
* and status at the dropzone when it receives a text message mentioning it's name followed by "conditions"
*/
class DropzoneModule : public SinglePortModule, private concurrency::OSThread
{
DFRobotLarkSensor sensor;
public:
/** Constructor
* name is for debugging output
*/
DropzoneModule() : SinglePortModule("dropzone", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("DropzoneModule")
{
// Set up the analog pin for reading the dropzone status
pinMode(PIN_A1, INPUT);
}
virtual int32_t runOnce() override;
protected:
/** Called to handle a particular incoming message
*/
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
private:
meshtastic_MeshPacket *sendConditions();
uint32_t startSendConditions = 0;
};
extern DropzoneModule *dropzoneModule;
#endif

View File

@ -70,6 +70,11 @@
#include "modules/SerialModule.h" #include "modules/SerialModule.h"
#endif #endif
#endif #endif
#if !MESHTASTIC_EXCLUDE_DROPZONE
#include "modules/DropzoneModule.h"
#endif
/** /**
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else) * Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
*/ */
@ -100,6 +105,10 @@ void setupModules()
#if !MESHTASTIC_EXCLUDE_ATAK #if !MESHTASTIC_EXCLUDE_ATAK
atakPluginModule = new AtakPluginModule(); atakPluginModule = new AtakPluginModule();
#endif #endif
#if !MESHTASTIC_EXCLUDE_DROPZONE
dropzoneModule = new DropzoneModule();
#endif
// Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance
// to a global variable. // to a global variable.

View File

@ -1,3 +1,7 @@
#pragma once
#ifndef _MT_DFROBOTLARKSENSOR_H
#define _MT_DFROBOTLARKSENSOR_H
#include "configuration.h" #include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR #if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
@ -22,3 +26,4 @@ class DFRobotLarkSensor : public TelemetrySensor
}; };
#endif #endif
#endif

View File

@ -0,0 +1,21 @@
#include "UnitConversions.h"
float UnitConversions::CelsiusToFahrenheit(float celcius)
{
return (celcius * 9) / 5 + 32;
}
float UnitConversions::MetersPerSecondToKnots(float metersPerSecond)
{
return metersPerSecond * 1.94384;
}
float UnitConversions::MetersPerSecondToMilesPerHour(float metersPerSecond)
{
return metersPerSecond * 2.23694;
}
float UnitConversions::HectoPascalToInchesOfMercury(float hectoPascal)
{
return hectoPascal * 0.029529983071445;
}

View File

@ -0,0 +1,10 @@
#pragma once
class UnitConversions
{
public:
static float CelsiusToFahrenheit(float celcius);
static float MetersPerSecondToKnots(float metersPerSecond);
static float MetersPerSecondToMilesPerHour(float metersPerSecond);
static float HectoPascalToInchesOfMercury(float hectoPascal);
};

View File

@ -17,6 +17,8 @@ lib_deps =
https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2 https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
bodmer/TFT_eSPI bodmer/TFT_eSPI
beegee-tokyo/RAKwireless RAK12034@^1.0.0
beegee-tokyo/RAK14014-FT6336U @ 1.0.1
debug_tool = jlink debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
;upload_protocol = jlink ;upload_protocol = jlink

View File

@ -307,10 +307,10 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
#define SCREEN_ROTATE #define SCREEN_ROTATE
#define SCREEN_TRANSITION_FRAMERATE 5 #define SCREEN_TRANSITION_FRAMERATE 5
#define HAS_TOUCHSCREEN 0 #define HAS_TOUCHSCREEN 1
#define SCREEN_TOUCH_INT 10 // From tp.h on the tracker open source code. #define SCREEN_TOUCH_INT WB_IO6
#define TOUCH_I2C_PORT 0
#define TOUCH_SLAVE_ADDRESS 0x5D // GT911 #define CANNED_MESSAGE_MODULE_ENABLE 1
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Arduino objects - C++ only * Arduino objects - C++ only