mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-29 02:51:17 +00:00
Ch341 (#5474)
* Very hacky first attempt at usermod ech341 * Fixes and debug printfs * Move to library version of libpinedio-usb * Add spidev: ch341 option in meshtasticd config.yaml * Only check settingsStrings on native * Use new CH341 code * Bump ch341 lib * Cleanup USBHal * Add ch341 config.d files * Remove ch341quirk * Bump to most recent spi-userspace driver * Add handling for ch341 serial, pid, and vid * Minor fixes from pio check * Trunk * Add include for musl compliance * Point to upstream libch341
This commit is contained in:
parent
658459aaf3
commit
960626e498
@ -26,6 +26,7 @@ lib_deps =
|
|||||||
${radiolib_base.lib_deps}
|
${radiolib_base.lib_deps}
|
||||||
rweather/Crypto@^0.4.0
|
rweather/Crypto@^0.4.0
|
||||||
https://github.com/lovyan03/LovyanGFX.git#1401c28a47646fe00538d487adcb2eb3c72de805
|
https://github.com/lovyan03/LovyanGFX.git#1401c28a47646fe00538d487adcb2eb3c72de805
|
||||||
|
https://github.com/pine64/libch341-spi-userspace#8695637adeabf5abf5601d8e82cb0ba19ce9ec46
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
${arduino_base.build_flags}
|
${arduino_base.build_flags}
|
||||||
|
@ -12,13 +12,6 @@ Lora:
|
|||||||
# IRQ: 17
|
# IRQ: 17
|
||||||
# Reset: 22
|
# Reset: 22
|
||||||
|
|
||||||
# Module: sx1262 # pinedio
|
|
||||||
# CS: 0
|
|
||||||
# IRQ: 10
|
|
||||||
# Busy: 11
|
|
||||||
# DIO2_AS_RF_SWITCH: true
|
|
||||||
# spidev: spidev0.1
|
|
||||||
|
|
||||||
# Module: RF95 # Adafruit RFM9x
|
# Module: RF95 # Adafruit RFM9x
|
||||||
# Reset: 25
|
# Reset: 25
|
||||||
# CS: 7
|
# CS: 7
|
||||||
@ -50,8 +43,6 @@ Lora:
|
|||||||
# TXen: x # TX and RX enable pins
|
# TXen: x # TX and RX enable pins
|
||||||
# RXen: x
|
# RXen: x
|
||||||
|
|
||||||
# ch341_quirk: true # Uncomment this to use the chunked SPI transfer that seems to fix the ch341
|
|
||||||
|
|
||||||
# spiSpeed: 2000000
|
# spiSpeed: 2000000
|
||||||
|
|
||||||
### Set gpio chip to use in /dev/. Defaults to 0.
|
### Set gpio chip to use in /dev/. Defaults to 0.
|
||||||
|
11
bin/config.d/lora-meshstick-1262.yaml
Normal file
11
bin/config.d/lora-meshstick-1262.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
CS: 0
|
||||||
|
IRQ: 6
|
||||||
|
Reset: 2
|
||||||
|
Busy: 4
|
||||||
|
spidev: ch341
|
||||||
|
DIO3_TCXO_VOLTAGE: true
|
||||||
|
# USB_Serialnum: 12345678
|
||||||
|
USB_PID: 0x5512
|
||||||
|
USB_VID: 0x1A86
|
5
bin/config.d/lora-pinedio-usb-sx1262.yaml
Normal file
5
bin/config.d/lora-pinedio-usb-sx1262.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Lora:
|
||||||
|
Module: sx1262
|
||||||
|
CS: 0
|
||||||
|
IRQ: 10
|
||||||
|
spidev: ch341
|
23
src/main.cpp
23
src/main.cpp
@ -90,6 +90,7 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
|
|||||||
#include "linux/LinuxHardwareI2C.h"
|
#include "linux/LinuxHardwareI2C.h"
|
||||||
#include "mesh/raspihttp/PiWebServer.h"
|
#include "mesh/raspihttp/PiWebServer.h"
|
||||||
#include "platform/portduino/PortduinoGlue.h"
|
#include "platform/portduino/PortduinoGlue.h"
|
||||||
|
#include "platform/portduino/USBHal.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -213,6 +214,9 @@ static OSThread *powerFSMthread;
|
|||||||
static OSThread *ambientLightingThread;
|
static OSThread *ambientLightingThread;
|
||||||
|
|
||||||
RadioInterface *rIf = NULL;
|
RadioInterface *rIf = NULL;
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
|
RadioLibHal *RadioLibHAL = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some platforms (nrf52) might provide an alterate version that suppresses calling delay from sleep.
|
* Some platforms (nrf52) might provide an alterate version that suppresses calling delay from sleep.
|
||||||
@ -420,7 +424,6 @@ void setup()
|
|||||||
digitalWrite(AQ_SET_PIN, HIGH);
|
digitalWrite(AQ_SET_PIN, HIGH);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Currently only the tbeam has a PMU
|
// Currently only the tbeam has a PMU
|
||||||
// PMU initialization needs to be placed before i2c scanning
|
// PMU initialization needs to be placed before i2c scanning
|
||||||
power = new Power();
|
power = new Power();
|
||||||
@ -712,6 +715,10 @@ void setup()
|
|||||||
SPI.setRX(LORA_MISO);
|
SPI.setRX(LORA_MISO);
|
||||||
SPI.begin(false);
|
SPI.begin(false);
|
||||||
#endif // HW_SPI1_DEVICE
|
#endif // HW_SPI1_DEVICE
|
||||||
|
#elif ARCH_PORTDUINO
|
||||||
|
if (settingsStrings[spidev] != "ch341") {
|
||||||
|
SPI.begin();
|
||||||
|
}
|
||||||
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
||||||
SPI.begin();
|
SPI.begin();
|
||||||
#else
|
#else
|
||||||
@ -817,8 +824,11 @@ void setup()
|
|||||||
if (settingsMap[use_sx1262]) {
|
if (settingsMap[use_sx1262]) {
|
||||||
if (!rIf) {
|
if (!rIf) {
|
||||||
LOG_DEBUG("Activate sx1262 radio on SPI port %s", settingsStrings[spidev].c_str());
|
LOG_DEBUG("Activate sx1262 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||||
LockingArduinoHal *RadioLibHAL =
|
if (settingsStrings[spidev] == "ch341") {
|
||||||
new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC));
|
RadioLibHAL = ch341Hal;
|
||||||
|
} else {
|
||||||
|
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||||
|
}
|
||||||
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||||
settingsMap[busy]);
|
settingsMap[busy]);
|
||||||
if (!rIf->init()) {
|
if (!rIf->init()) {
|
||||||
@ -832,8 +842,7 @@ void setup()
|
|||||||
} else if (settingsMap[use_rf95]) {
|
} else if (settingsMap[use_rf95]) {
|
||||||
if (!rIf) {
|
if (!rIf) {
|
||||||
LOG_DEBUG("Activate rf95 radio on SPI port %s", settingsStrings[spidev].c_str());
|
LOG_DEBUG("Activate rf95 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||||
LockingArduinoHal *RadioLibHAL =
|
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||||
new LockingArduinoHal(SPI, spiSettings, (settingsMap[ch341Quirk] ? settingsMap[busy] : RADIOLIB_NC));
|
|
||||||
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||||
settingsMap[busy]);
|
settingsMap[busy]);
|
||||||
if (!rIf->init()) {
|
if (!rIf->init()) {
|
||||||
@ -848,7 +857,7 @@ void setup()
|
|||||||
} else if (settingsMap[use_sx1280]) {
|
} else if (settingsMap[use_sx1280]) {
|
||||||
if (!rIf) {
|
if (!rIf) {
|
||||||
LOG_DEBUG("Activate sx1280 radio on SPI port %s", settingsStrings[spidev].c_str());
|
LOG_DEBUG("Activate sx1280 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||||
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||||
settingsMap[busy]);
|
settingsMap[busy]);
|
||||||
if (!rIf->init()) {
|
if (!rIf->init()) {
|
||||||
@ -908,7 +917,7 @@ void setup()
|
|||||||
} else if (settingsMap[use_sx1268]) {
|
} else if (settingsMap[use_sx1268]) {
|
||||||
if (!rIf) {
|
if (!rIf) {
|
||||||
LOG_DEBUG("Activate sx1268 radio on SPI port %s", settingsStrings[spidev].c_str());
|
LOG_DEBUG("Activate sx1268 radio on SPI port %s", settingsStrings[spidev].c_str());
|
||||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||||
rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||||
settingsMap[busy]);
|
settingsMap[busy]);
|
||||||
if (!rIf->init()) {
|
if (!rIf->init()) {
|
||||||
|
@ -31,31 +31,7 @@ void LockingArduinoHal::spiEndTransaction()
|
|||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
void LockingArduinoHal::spiTransfer(uint8_t *out, size_t len, uint8_t *in)
|
void LockingArduinoHal::spiTransfer(uint8_t *out, size_t len, uint8_t *in)
|
||||||
{
|
{
|
||||||
if (busy == RADIOLIB_NC) {
|
|
||||||
spi->transfer(out, in, len);
|
spi->transfer(out, in, len);
|
||||||
} else {
|
|
||||||
uint16_t offset = 0;
|
|
||||||
|
|
||||||
while (len) {
|
|
||||||
uint8_t block_size = (len < 20 ? len : 20);
|
|
||||||
spi->transfer((out != NULL ? out + offset : NULL), (in != NULL ? in + offset : NULL), block_size);
|
|
||||||
if (block_size == len)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// ensure GPIO is low
|
|
||||||
|
|
||||||
uint32_t start = millis();
|
|
||||||
while (digitalRead(busy)) {
|
|
||||||
if (!Throttle::isWithinTimespanMs(start, 2000)) {
|
|
||||||
LOG_ERROR("GPIO mid-transfer timeout, is it connected?");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += block_size;
|
|
||||||
len -= block_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -22,18 +22,11 @@
|
|||||||
class LockingArduinoHal : public ArduinoHal
|
class LockingArduinoHal : public ArduinoHal
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LockingArduinoHal(SPIClass &spi, SPISettings spiSettings, RADIOLIB_PIN_TYPE _busy = RADIOLIB_NC)
|
LockingArduinoHal(SPIClass &spi, SPISettings spiSettings) : ArduinoHal(spi, spiSettings){};
|
||||||
: ArduinoHal(spi, spiSettings)
|
|
||||||
{
|
|
||||||
#if ARCH_PORTDUINO
|
|
||||||
busy = _busy;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
void spiBeginTransaction() override;
|
void spiBeginTransaction() override;
|
||||||
void spiEndTransaction() override;
|
void spiEndTransaction() override;
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
RADIOLIB_PIN_TYPE busy;
|
|
||||||
void spiTransfer(uint8_t *out, size_t len, uint8_t *in) override;
|
void spiTransfer(uint8_t *out, size_t len, uint8_t *in) override;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,9 +21,12 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "platform/portduino/USBHal.h"
|
||||||
|
|
||||||
std::map<configNames, int> settingsMap;
|
std::map<configNames, int> settingsMap;
|
||||||
std::map<configNames, std::string> settingsStrings;
|
std::map<configNames, std::string> settingsStrings;
|
||||||
std::ofstream traceFile;
|
std::ofstream traceFile;
|
||||||
|
Ch341Hal *ch341Hal = nullptr;
|
||||||
char *configPath = nullptr;
|
char *configPath = nullptr;
|
||||||
char *optionMac = nullptr;
|
char *optionMac = nullptr;
|
||||||
|
|
||||||
@ -104,7 +107,6 @@ void getMacAddr(uint8_t *dmac)
|
|||||||
struct hci_dev_info di;
|
struct hci_dev_info di;
|
||||||
di.dev_id = 0;
|
di.dev_id = 0;
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
char addr[18];
|
|
||||||
int btsock;
|
int btsock;
|
||||||
btsock = socket(AF_BLUETOOTH, SOCK_RAW, 1);
|
btsock = socket(AF_BLUETOOTH, SOCK_RAW, 1);
|
||||||
if (btsock < 0) { // If anything fails, just return with the default value
|
if (btsock < 0) { // If anything fails, just return with the default value
|
||||||
@ -201,8 +203,36 @@ void portduinoSetup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if we're using a usermode driver, we need to initialize it here, to get a serial number back for mac address
|
||||||
uint8_t dmac[6] = {0};
|
uint8_t dmac[6] = {0};
|
||||||
|
if (settingsStrings[spidev] == "ch341") {
|
||||||
|
ch341Hal = new Ch341Hal(0);
|
||||||
|
if (settingsStrings[lora_usb_serial_num] != "") {
|
||||||
|
ch341Hal->serial = settingsStrings[lora_usb_serial_num];
|
||||||
|
}
|
||||||
|
ch341Hal->vid = settingsMap[lora_usb_vid];
|
||||||
|
ch341Hal->pid = settingsMap[lora_usb_pid];
|
||||||
|
ch341Hal->init();
|
||||||
|
if (!ch341Hal->isInit()) {
|
||||||
|
std::cout << "Could not initialize CH341 device!" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
char serial[9] = {0};
|
||||||
|
ch341Hal->getSerialString(serial, 8);
|
||||||
|
std::cout << "Serial " << serial << std::endl;
|
||||||
|
if (strlen(serial) == 8 && settingsStrings[mac_address].length() < 12) {
|
||||||
|
uint8_t hash[32] = {0};
|
||||||
|
memcpy(hash, serial, 8);
|
||||||
|
crypto->hash(hash, 8);
|
||||||
|
dmac[0] = (hash[0] << 4) | 2;
|
||||||
|
dmac[1] = hash[1];
|
||||||
|
dmac[2] = hash[2];
|
||||||
|
dmac[3] = hash[3];
|
||||||
|
dmac[4] = hash[4];
|
||||||
|
dmac[5] = hash[5];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getMacAddr(dmac);
|
getMacAddr(dmac);
|
||||||
if (dmac[0] == 0 && dmac[1] == 0 && dmac[2] == 0 && dmac[3] == 0 && dmac[4] == 0 && dmac[5] == 0) {
|
if (dmac[0] == 0 && dmac[1] == 0 && dmac[2] == 0 && dmac[3] == 0 && dmac[4] == 0 && dmac[5] == 0) {
|
||||||
std::cout << "*** Blank MAC Address not allowed!" << std::endl;
|
std::cout << "*** Blank MAC Address not allowed!" << std::endl;
|
||||||
@ -225,6 +255,30 @@ void portduinoSetup()
|
|||||||
// Need to bind all the configured GPIO pins so they're not simulated
|
// Need to bind all the configured GPIO pins so they're not simulated
|
||||||
// TODO: Can we do this in the for loop above?
|
// TODO: Can we do this in the for loop above?
|
||||||
// TODO: If one of these fails, we should log and terminate
|
// TODO: If one of these fails, we should log and terminate
|
||||||
|
if (settingsMap.count(user) > 0 && settingsMap[user] != RADIOLIB_NC) {
|
||||||
|
if (initGPIOPin(settingsMap[user], gpioChipName) != ERRNO_OK) {
|
||||||
|
settingsMap[user] = RADIOLIB_NC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (settingsMap[displayPanel] != no_screen) {
|
||||||
|
if (settingsMap[displayCS] > 0)
|
||||||
|
initGPIOPin(settingsMap[displayCS], gpioChipName);
|
||||||
|
if (settingsMap[displayDC] > 0)
|
||||||
|
initGPIOPin(settingsMap[displayDC], gpioChipName);
|
||||||
|
if (settingsMap[displayBacklight] > 0)
|
||||||
|
initGPIOPin(settingsMap[displayBacklight], gpioChipName);
|
||||||
|
if (settingsMap[displayReset] > 0)
|
||||||
|
initGPIOPin(settingsMap[displayReset], gpioChipName);
|
||||||
|
}
|
||||||
|
if (settingsMap[touchscreenModule] != no_touchscreen) {
|
||||||
|
if (settingsMap[touchscreenCS] > 0)
|
||||||
|
initGPIOPin(settingsMap[touchscreenCS], gpioChipName);
|
||||||
|
if (settingsMap[touchscreenIRQ] > 0)
|
||||||
|
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only initialize the radio pins when dealing with real, kernel controlled SPI hardware
|
||||||
|
if (settingsStrings[spidev] != "" && settingsStrings[spidev] != "ch341") {
|
||||||
if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
|
if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
|
||||||
if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) {
|
if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) {
|
||||||
settingsMap[cs] = RADIOLIB_NC;
|
settingsMap[cs] = RADIOLIB_NC;
|
||||||
@ -250,11 +304,6 @@ void portduinoSetup()
|
|||||||
settingsMap[sx126x_ant_sw] = RADIOLIB_NC;
|
settingsMap[sx126x_ant_sw] = RADIOLIB_NC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (settingsMap.count(user) > 0 && settingsMap[user] != RADIOLIB_NC) {
|
|
||||||
if (initGPIOPin(settingsMap[user], gpioChipName) != ERRNO_OK) {
|
|
||||||
settingsMap[user] = RADIOLIB_NC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (settingsMap.count(rxen) > 0 && settingsMap[rxen] != RADIOLIB_NC) {
|
if (settingsMap.count(rxen) > 0 && settingsMap[rxen] != RADIOLIB_NC) {
|
||||||
if (initGPIOPin(settingsMap[rxen], gpioChipName) != ERRNO_OK) {
|
if (initGPIOPin(settingsMap[rxen], gpioChipName) != ERRNO_OK) {
|
||||||
settingsMap[rxen] = RADIOLIB_NC;
|
settingsMap[rxen] = RADIOLIB_NC;
|
||||||
@ -265,25 +314,6 @@ void portduinoSetup()
|
|||||||
settingsMap[txen] = RADIOLIB_NC;
|
settingsMap[txen] = RADIOLIB_NC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsMap[displayPanel] != no_screen) {
|
|
||||||
if (settingsMap[displayCS] > 0)
|
|
||||||
initGPIOPin(settingsMap[displayCS], gpioChipName);
|
|
||||||
if (settingsMap[displayDC] > 0)
|
|
||||||
initGPIOPin(settingsMap[displayDC], gpioChipName);
|
|
||||||
if (settingsMap[displayBacklight] > 0)
|
|
||||||
initGPIOPin(settingsMap[displayBacklight], gpioChipName);
|
|
||||||
if (settingsMap[displayReset] > 0)
|
|
||||||
initGPIOPin(settingsMap[displayReset], gpioChipName);
|
|
||||||
}
|
|
||||||
if (settingsMap[touchscreenModule] != no_touchscreen) {
|
|
||||||
if (settingsMap[touchscreenCS] > 0)
|
|
||||||
initGPIOPin(settingsMap[touchscreenCS], gpioChipName);
|
|
||||||
if (settingsMap[touchscreenIRQ] > 0)
|
|
||||||
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settingsStrings[spidev] != "") {
|
|
||||||
SPI.begin(settingsStrings[spidev].c_str());
|
SPI.begin(settingsStrings[spidev].c_str());
|
||||||
}
|
}
|
||||||
if (settingsStrings[traceFilename] != "") {
|
if (settingsStrings[traceFilename] != "") {
|
||||||
@ -378,20 +408,27 @@ bool loadConfig(const char *configPath)
|
|||||||
settingsMap[rxen] = yamlConfig["Lora"]["RXen"].as<int>(RADIOLIB_NC);
|
settingsMap[rxen] = yamlConfig["Lora"]["RXen"].as<int>(RADIOLIB_NC);
|
||||||
settingsMap[sx126x_ant_sw] = yamlConfig["Lora"]["SX126X_ANT_SW"].as<int>(RADIOLIB_NC);
|
settingsMap[sx126x_ant_sw] = yamlConfig["Lora"]["SX126X_ANT_SW"].as<int>(RADIOLIB_NC);
|
||||||
settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as<int>(0);
|
settingsMap[gpiochip] = yamlConfig["Lora"]["gpiochip"].as<int>(0);
|
||||||
settingsMap[ch341Quirk] = yamlConfig["Lora"]["ch341_quirk"].as<bool>(false);
|
|
||||||
settingsMap[spiSpeed] = yamlConfig["Lora"]["spiSpeed"].as<int>(2000000);
|
settingsMap[spiSpeed] = yamlConfig["Lora"]["spiSpeed"].as<int>(2000000);
|
||||||
|
settingsStrings[lora_usb_serial_num] = yamlConfig["Lora"]["USB_Serialnum"].as<std::string>("");
|
||||||
|
settingsMap[lora_usb_pid] = yamlConfig["Lora"]["USB_PID"].as<int>(0x5512);
|
||||||
|
settingsMap[lora_usb_vid] = yamlConfig["Lora"]["USB_VID"].as<int>(0x1A86);
|
||||||
|
|
||||||
settingsStrings[spidev] = "/dev/" + yamlConfig["Lora"]["spidev"].as<std::string>("spidev0.0");
|
settingsStrings[spidev] = yamlConfig["Lora"]["spidev"].as<std::string>("spidev0.0");
|
||||||
|
if (settingsStrings[spidev] != "ch341") {
|
||||||
|
settingsStrings[spidev] = "/dev/" + settingsStrings[spidev];
|
||||||
if (settingsStrings[spidev].length() == 14) {
|
if (settingsStrings[spidev].length() == 14) {
|
||||||
int x = settingsStrings[spidev].at(11) - '0';
|
int x = settingsStrings[spidev].at(11) - '0';
|
||||||
int y = settingsStrings[spidev].at(13) - '0';
|
int y = settingsStrings[spidev].at(13) - '0';
|
||||||
|
// Pretty sure this is always true
|
||||||
if (x >= 0 && x < 10 && y >= 0 && y < 10) {
|
if (x >= 0 && x < 10 && y >= 0 && y < 10) {
|
||||||
|
// I believe this bit of weirdness is specifically for the new GUI
|
||||||
settingsMap[spidev] = x + y << 4;
|
settingsMap[spidev] = x + y << 4;
|
||||||
settingsMap[displayspidev] = settingsMap[spidev];
|
settingsMap[displayspidev] = settingsMap[spidev];
|
||||||
settingsMap[touchscreenspidev] = settingsMap[spidev];
|
settingsMap[touchscreenspidev] = settingsMap[spidev];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (yamlConfig["GPIO"]) {
|
if (yamlConfig["GPIO"]) {
|
||||||
settingsMap[user] = yamlConfig["GPIO"]["User"].as<int>(RADIOLIB_NC);
|
settingsMap[user] = yamlConfig["GPIO"]["User"].as<int>(RADIOLIB_NC);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "platform/portduino/USBHal.h"
|
||||||
|
|
||||||
enum configNames {
|
enum configNames {
|
||||||
use_sx1262,
|
use_sx1262,
|
||||||
cs,
|
cs,
|
||||||
@ -13,13 +15,15 @@ enum configNames {
|
|||||||
rxen,
|
rxen,
|
||||||
dio2_as_rf_switch,
|
dio2_as_rf_switch,
|
||||||
dio3_tcxo_voltage,
|
dio3_tcxo_voltage,
|
||||||
ch341Quirk,
|
|
||||||
use_rf95,
|
use_rf95,
|
||||||
use_sx1280,
|
use_sx1280,
|
||||||
use_lr1110,
|
use_lr1110,
|
||||||
use_lr1120,
|
use_lr1120,
|
||||||
use_lr1121,
|
use_lr1121,
|
||||||
use_sx1268,
|
use_sx1268,
|
||||||
|
lora_usb_serial_num,
|
||||||
|
lora_usb_pid,
|
||||||
|
lora_usb_vid,
|
||||||
user,
|
user,
|
||||||
gpiochip,
|
gpiochip,
|
||||||
spidev,
|
spidev,
|
||||||
@ -69,6 +73,7 @@ enum { level_error, level_warn, level_info, level_debug, level_trace };
|
|||||||
extern std::map<configNames, int> settingsMap;
|
extern std::map<configNames, int> settingsMap;
|
||||||
extern std::map<configNames, std::string> settingsStrings;
|
extern std::map<configNames, std::string> settingsStrings;
|
||||||
extern std::ofstream traceFile;
|
extern std::ofstream traceFile;
|
||||||
|
extern Ch341Hal *ch341Hal;
|
||||||
int initGPIOPin(int pinNum, std::string gpioChipname);
|
int initGPIOPin(int pinNum, std::string gpioChipname);
|
||||||
bool loadConfig(const char *configPath);
|
bool loadConfig(const char *configPath);
|
||||||
static bool ends_with(std::string_view str, std::string_view suffix);
|
static bool ends_with(std::string_view str, std::string_view suffix);
|
||||||
|
194
src/platform/portduino/USBHal.h
Normal file
194
src/platform/portduino/USBHal.h
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#ifndef PI_HAL_LGPIO_H
|
||||||
|
#define PI_HAL_LGPIO_H
|
||||||
|
|
||||||
|
// include RadioLib
|
||||||
|
#include "platform/portduino/PortduinoGlue.h"
|
||||||
|
#include <RadioLib.h>
|
||||||
|
#include <csignal>
|
||||||
|
#include <libpinedio-usb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// include the library for Raspberry GPIO pins
|
||||||
|
|
||||||
|
#define PI_RISING (PINEDIO_INT_MODE_RISING)
|
||||||
|
#define PI_FALLING (PINEDIO_INT_MODE_FALLING)
|
||||||
|
#define PI_INPUT (0)
|
||||||
|
#define PI_OUTPUT (1)
|
||||||
|
#define PI_LOW (0)
|
||||||
|
#define PI_HIGH (1)
|
||||||
|
|
||||||
|
#define CH341_PIN_CS (101)
|
||||||
|
#define CH341_PIN_IRQ (0)
|
||||||
|
|
||||||
|
// the HAL must inherit from the base RadioLibHal class
|
||||||
|
// and implement all of its virtual methods
|
||||||
|
class Ch341Hal : public RadioLibHal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// default constructor - initializes the base HAL and any needed private members
|
||||||
|
Ch341Hal(uint8_t spiChannel, uint32_t spiSpeed = 2000000, uint8_t spiDevice = 0, uint8_t gpioDevice = 0)
|
||||||
|
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void getSerialString(char *_serial, size_t len)
|
||||||
|
{
|
||||||
|
if (!pinedio_is_init) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strncpy(_serial, pinedio.serial_number, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() override
|
||||||
|
{
|
||||||
|
// now the SPI
|
||||||
|
spiBegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void term() override
|
||||||
|
{
|
||||||
|
// stop the SPI
|
||||||
|
spiEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GPIO-related methods (pinMode, digitalWrite etc.) should check
|
||||||
|
// RADIOLIB_NC as an alias for non-connected pins
|
||||||
|
void pinMode(uint32_t pin, uint32_t mode) override
|
||||||
|
{
|
||||||
|
if (pin == RADIOLIB_NC) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pinedio_set_pin_mode(&pinedio, pin, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void digitalWrite(uint32_t pin, uint32_t value) override
|
||||||
|
{
|
||||||
|
if (pin == RADIOLIB_NC) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pinedio_digital_write(&pinedio, pin, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t digitalRead(uint32_t pin) override
|
||||||
|
{
|
||||||
|
if (pin == RADIOLIB_NC) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return pinedio_digital_read(&pinedio, pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override
|
||||||
|
{
|
||||||
|
if ((interruptNum == RADIOLIB_NC)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// LOG_DEBUG("Attach interrupt to pin %d", interruptNum);
|
||||||
|
pinedio_attach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum, (pinedio_int_mode)mode, interruptCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void detachInterrupt(uint32_t interruptNum) override
|
||||||
|
{
|
||||||
|
if ((interruptNum == RADIOLIB_NC)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// LOG_DEBUG("Detach interrupt from pin %d", interruptNum);
|
||||||
|
|
||||||
|
pinedio_deattach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void delay(unsigned long ms) override
|
||||||
|
{
|
||||||
|
if (ms == 0) {
|
||||||
|
sched_yield();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(ms * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void delayMicroseconds(unsigned long us) override
|
||||||
|
{
|
||||||
|
if (us == 0) {
|
||||||
|
sched_yield();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usleep(us);
|
||||||
|
}
|
||||||
|
|
||||||
|
void yield() override { sched_yield(); }
|
||||||
|
|
||||||
|
unsigned long millis() override
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000ULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long micros() override
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override
|
||||||
|
{
|
||||||
|
fprintf(stderr, "pulseIn for pin %u is not supported!\n", pin);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spiBegin()
|
||||||
|
{
|
||||||
|
if (!pinedio_is_init) {
|
||||||
|
if (serial != "") {
|
||||||
|
strncpy(pinedio.serial_number, serial.c_str(), 8);
|
||||||
|
pinedio_set_option(&pinedio, PINEDIO_OPTION_SEARCH_SERIAL, 1);
|
||||||
|
}
|
||||||
|
pinedio_set_option(&pinedio, PINEDIO_OPTION_PID, pid);
|
||||||
|
pinedio_set_option(&pinedio, PINEDIO_OPTION_VID, vid);
|
||||||
|
int32_t ret = pinedio_init(&pinedio, NULL);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "Could not open SPI: %d\n", ret);
|
||||||
|
} else {
|
||||||
|
pinedio_is_init = true;
|
||||||
|
// LOG_INFO("USB Serial: %s", pinedio.serial_number);
|
||||||
|
pinedio_set_option(&pinedio, PINEDIO_OPTION_AUTO_CS, 0);
|
||||||
|
pinedio_set_pin_mode(&pinedio, 3, true);
|
||||||
|
pinedio_set_pin_mode(&pinedio, 5, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spiBeginTransaction() {}
|
||||||
|
|
||||||
|
void spiTransfer(uint8_t *out, size_t len, uint8_t *in)
|
||||||
|
{
|
||||||
|
int32_t result = pinedio_transceive(&this->pinedio, out, in, len);
|
||||||
|
if (result < 0) {
|
||||||
|
fprintf(stderr, "Could not perform SPI transfer: %d\n", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spiEndTransaction() {}
|
||||||
|
|
||||||
|
void spiEnd()
|
||||||
|
{
|
||||||
|
if (pinedio_is_init) {
|
||||||
|
pinedio_deinit(&pinedio);
|
||||||
|
pinedio_is_init = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isInit() { return pinedio_is_init; }
|
||||||
|
|
||||||
|
std::string serial = "";
|
||||||
|
uint32_t pid = 0x5512;
|
||||||
|
uint32_t vid = 0x1A86;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// the HAL can contain any additional private members
|
||||||
|
pinedio_inst pinedio = {0};
|
||||||
|
bool pinedio_is_init = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user