Portduino work (#3049)

* Move to Portduino's getMacAddr()

* Add ST7735/S screen support

* Push Raspbian support into native target

* Remove latent pigpio references.

* CardKB defensive programming

* Adds configurable spidev

* Fixes to build on Fedora 40

* ENUMs are not #defines. Pull latest portduino

* Add more configuration options for SPI displays

* Add config.yaml option to set DIO3_TCXO_VOLTAGE

* change tft clear() to fillScreen()
Maintains compatability with ESPI driver.

* Adds TXen and RXen pins to portduino

* Add -c --config options to specify config file

* Fail when a specified config file is unavailable

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
Jonathan Bennett
2024-01-12 02:00:31 -06:00
committed by GitHub
parent 7e53a96ee5
commit 4a867c81c0
30 changed files with 279 additions and 250 deletions

View File

@@ -8,10 +8,8 @@
#include <Utility.h>
#include <assert.h>
#ifdef ARCH_RASPBERRY_PI
#include "PortduinoGlue.h"
#include "linux/gpio/LinuxGPIOPin.h"
#include "pigpio.h"
#include "yaml-cpp/yaml.h"
#include <iostream>
#include <map>
@@ -19,10 +17,7 @@
std::map<configNames, int> settingsMap;
std::map<configNames, std::string> settingsStrings;
#else
#include <linux/gpio/LinuxGPIOPin.h>
#endif
char *configPath = nullptr;
// FIXME - move setBluetoothEnable into a HALPlatform class
void setBluetoothEnable(bool on)
@@ -36,34 +31,7 @@ void cpuDeepSleep(uint32_t msecs)
}
void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
#ifndef ARCH_RASPBERRY_PI
/** a simulated pin for busted IRQ hardware
* Porduino helper class to do this i2c based polling:
*/
class PolledIrqPin : public GPIOPin
{
public:
PolledIrqPin() : GPIOPin(LORA_DIO1, "loraIRQ") {}
/// Read the low level hardware for this pin
virtual PinStatus readPinHardware()
{
if (isrPinStatus < 0)
return LOW; // No interrupt handler attached, don't bother polling i2c right now
else {
extern RadioInterface *rIf; // FIXME, temporary hack until we know if we need to keep this
assert(rIf);
RadioLibInterface *rIf95 = static_cast<RadioLibInterface *>(rIf);
bool p = rIf95->isIRQPending();
log(SysGPIO, LogDebug, "PolledIrqPin::readPinHardware(%s, %d, %d)", getName(), getPinNum(), p);
return p ? HIGH : LOW;
}
}
};
static GPIOPin *loraIrq;
#endif
int TCPPort = 4403;
static error_t parse_opt(int key, char *arg, struct argp_state *state)
@@ -73,7 +41,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
if (sscanf(arg, "%d", &TCPPort) < 1)
return ARGP_ERR_UNKNOWN;
else
printf("Using TCP port %d\n", TCPPort);
printf("Using config file %d\n", TCPPort);
break;
case 'c':
configPath = arg;
break;
case ARGP_KEY_ARG:
return 0;
@@ -85,7 +56,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
void portduinoCustomInit()
{
static struct argp_option options[] = {{"port", 'p', "PORT", 0, "The TCP port to use."}, {0}};
static struct argp_option options[] = {{"port", 'p', "PORT", 0, "The TCP port to use."},
{"config", 'c', "CONFIG_PATH", 0, "Full path of the .yaml config file to use."},
{0}};
static void *childArguments;
static char doc[] = "Meshtastic native build.";
static char args_doc[] = "...";
@@ -101,14 +74,20 @@ void portduinoCustomInit()
void portduinoSetup()
{
printf("Setting up Meshtastic on Portduino...\n");
#ifdef ARCH_RASPBERRY_PI
gpioInit();
std::string gpioChipName = "gpiochip";
YAML::Node yamlConfig;
if (access("config.yaml", R_OK) == 0) {
if (configPath != nullptr) {
try {
yamlConfig = YAML::LoadFile(configPath);
} catch (YAML::Exception e) {
std::cout << "Could not open " << configPath << " because of error: " << e.what() << std::endl;
exit(EXIT_FAILURE);
}
} else if (access("config.yaml", R_OK) == 0) {
try {
yamlConfig = YAML::LoadFile("config.yaml");
} catch (YAML::Exception e) {
@@ -123,8 +102,24 @@ void portduinoSetup()
exit(EXIT_FAILURE);
}
} else {
std::cout << "No 'config.yaml' found, exiting." << std::endl;
exit(EXIT_FAILURE);
std::cout << "No 'config.yaml' found, running simulated." << std::endl;
// Set the random seed equal to TCPPort to have a different seed per instance
randomSeed(TCPPort);
/* Aren't all pins defaulted to simulated?
auto fakeBusy = new SimGPIOPin(SX126X_BUSY, "fakeBusy");
fakeBusy->writePin(LOW);
fakeBusy->setSilent(true);
gpioBind(fakeBusy);
auto cs = new SimGPIOPin(SX126X_CS, "fakeLoraCS");
cs->setSilent(true);
gpioBind(cs);
gpioBind(new SimGPIOPin(SX126X_RESET, "fakeLoraReset"));
gpioBind(new SimGPIOPin(LORA_DIO1, "fakeLoraIrq"));
*/
return;
}
try {
@@ -141,12 +136,17 @@ void portduinoSetup()
settingsMap[use_sx1280] = true;
}
settingsMap[dio2_as_rf_switch] = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as<bool>(false);
settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as<bool>(false);
settingsMap[cs] = yamlConfig["Lora"]["CS"].as<int>(RADIOLIB_NC);
settingsMap[irq] = yamlConfig["Lora"]["IRQ"].as<int>(RADIOLIB_NC);
settingsMap[busy] = yamlConfig["Lora"]["Busy"].as<int>(RADIOLIB_NC);
settingsMap[reset] = yamlConfig["Lora"]["Reset"].as<int>(RADIOLIB_NC);
settingsMap[txen] = yamlConfig["Lora"]["TXen"].as<int>(RADIOLIB_NC);
settingsMap[rxen] = yamlConfig["Lora"]["RXen"].as<int>(RADIOLIB_NC);
settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as<int>(0);
gpioChipName += std::to_string(settingsMap[gpiochip]);
settingsStrings[spidev] = "/dev/" + yamlConfig["Lora"]["spidev"].as<std::string>("spidev0.0");
}
if (yamlConfig["GPIO"]) {
settingsMap[user] = yamlConfig["GPIO"]["User"].as<int>(RADIOLIB_NC);
@@ -162,13 +162,20 @@ void portduinoSetup()
if (yamlConfig["Display"]) {
if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7789")
settingsMap[displayPanel] = st7789;
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7735")
settingsMap[displayPanel] = st7735;
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7735S")
settingsMap[displayPanel] = st7735s;
settingsMap[displayHeight] = yamlConfig["Display"]["Height"].as<int>(0);
settingsMap[displayWidth] = yamlConfig["Display"]["Width"].as<int>(0);
settingsMap[displayDC] = yamlConfig["Display"]["DC"].as<int>(-1);
settingsMap[displayCS] = yamlConfig["Display"]["CS"].as<int>(-1);
settingsMap[displayBacklight] = yamlConfig["Display"]["Backlight"].as<int>(-1);
settingsMap[displayReset] = yamlConfig["Display"]["Reset"].as<int>(-1);
settingsMap[displayOffsetX] = yamlConfig["Display"]["OffsetX"].as<int>(0);
settingsMap[displayOffsetY] = yamlConfig["Display"]["OffsetY"].as<int>(0);
settingsMap[displayRotate] = yamlConfig["Display"]["Rotate"].as<bool>(false);
settingsMap[displayInvert] = yamlConfig["Display"]["Invert"].as<bool>(false);
}
settingsMap[touchscreenModule] = no_touchscreen;
if (yamlConfig["Touchscreen"]) {
@@ -185,10 +192,6 @@ void portduinoSetup()
std::cout << "*** Exception " << e.what() << std::endl;
exit(EXIT_FAILURE);
}
if (access("/sys/kernel/debug/bluetooth/hci0/identity", R_OK) != 0) {
std::cout << "Cannot read Bluetooth MAC Address. Please run as root" << std::endl;
exit(EXIT_FAILURE);
}
// Need to bind all the configured GPIO pins so they're not simulated
if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
@@ -216,6 +219,16 @@ void portduinoSetup()
settingsMap[user] = RADIOLIB_NC;
}
}
if (settingsMap.count(rxen) > 0 && settingsMap[rxen] != RADIOLIB_NC) {
if (initGPIOPin(settingsMap[rxen], gpioChipName) != ERRNO_OK) {
settingsMap[rxen] = RADIOLIB_NC;
}
}
if (settingsMap.count(txen) > 0 && settingsMap[txen] != RADIOLIB_NC) {
if (initGPIOPin(settingsMap[txen], gpioChipName) != ERRNO_OK) {
settingsMap[txen] = RADIOLIB_NC;
}
}
if (settingsMap[displayPanel] != no_screen) {
if (settingsMap[displayCS] > 0)
@@ -235,55 +248,8 @@ void portduinoSetup()
}
return;
#endif
#ifdef defined(PORTDUINO_LINUX_HARDWARE)
SPI.begin(); // We need to create SPI
bool usePineLora = !spiChip->isSimulated();
if (usePineLora) {
printf("Connecting to PineLora board...\n");
// FIXME: remove this hack once interrupts are confirmed to work on new pine64 board
// loraIrq = new PolledIrqPin();
loraIrq = new LinuxGPIOPin(LORA_DIO1, "ch341", "int", "loraIrq"); // or "err"?
loraIrq->setSilent();
gpioBind(loraIrq);
// BUSY hw was busted on current board - just use the simulated pin (which will read low)
auto busy = new LinuxGPIOPin(SX126X_BUSY, "ch341", "slct", "loraBusy");
busy->setSilent();
gpioBind(busy);
gpioBind(new LinuxGPIOPin(SX126X_RESET, "ch341", "ini", "loraReset"));
auto loraCs = new LinuxGPIOPin(SX126X_CS, "ch341", "cs0", "loraCs");
loraCs->setSilent();
gpioBind(loraCs);
} else
#endif
#ifndef ARCH_RASPBERRY_PI
{
// Set the random seed equal to TCPPort to have a different seed per instance
randomSeed(TCPPort);
auto fakeBusy = new SimGPIOPin(SX126X_BUSY, "fakeBusy");
fakeBusy->writePin(LOW);
fakeBusy->setSilent(true);
gpioBind(fakeBusy);
auto cs = new SimGPIOPin(SX126X_CS, "fakeLoraCS");
cs->setSilent(true);
gpioBind(cs);
gpioBind(new SimGPIOPin(SX126X_RESET, "fakeLoraReset"));
gpioBind(new SimGPIOPin(LORA_DIO1, "fakeLoraIrq"));
}
// gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET")));
// gpioBind((new SimGPIOPin(LORA_CS, "LORA_CS"))->setSilent());
#endif
}
#ifdef ARCH_RASPBERRY_PI
int initGPIOPin(int pinNum, std::string gpioChipName)
{
std::string gpio_name = "GPIO" + std::to_string(pinNum);
@@ -298,5 +264,4 @@ int initGPIOPin(int pinNum, std::string gpioChipName)
std::cout << "Warning, cannot claim pin " << gpio_name << (p ? p.__cxa_exception_type()->name() : "null") << std::endl;
return ERRNO_DISABLED;
}
}
#endif
}