feat(ACCESS): Configure AUX serial port as "External module" (#2562)
* Enable RX DMA on external module USART * feat(ACCESS): configure AUX serial port as "External module" (#2562) This allows configuring the external access mod on runtime rather than by compilation option. * fix: fetch external module driver
This commit is contained in:
@@ -238,6 +238,7 @@ enum UartModes {
|
||||
UART_MODE_GPS,
|
||||
UART_MODE_DEBUG,
|
||||
UART_MODE_SPACEMOUSE,
|
||||
UART_MODE_EXT_MODULE,
|
||||
UART_MODE_COUNT SKIP,
|
||||
UART_MODE_MAX SKIP = UART_MODE_COUNT-1
|
||||
};
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#if defined(PXX2)
|
||||
#include "extmodule_serial_driver.h"
|
||||
#endif
|
||||
|
||||
#if defined(PCBFRSKY) || defined(PCBFLYSKY)
|
||||
uint8_t switchToMix(uint8_t source)
|
||||
{
|
||||
@@ -431,6 +435,15 @@ bool isSerialModeAvailable(uint8_t port_nr, int mode)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if !defined(AUX_SERIAL_DMA_TX) || defined(EXTMODULE_USART)
|
||||
if (mode == UART_MODE_EXT_MODULE)
|
||||
return false;
|
||||
#else // defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART)
|
||||
// UART_MODE_EXT_MODULE is only supported on AUX1, as AUX2 has no TX DMA
|
||||
if (mode == UART_MODE_EXT_MODULE && port_nr != SP_AUX1)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if !defined(LUA)
|
||||
if (mode == UART_MODE_LUA)
|
||||
return false;
|
||||
@@ -802,6 +815,7 @@ bool isInternalModuleAvailable(int moduleType)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_EXTERNAL_MODULE)
|
||||
bool isExternalModuleAvailable(int moduleType)
|
||||
{
|
||||
|
||||
@@ -834,11 +848,17 @@ bool isExternalModuleAvailable(int moduleType)
|
||||
return false; // doesn't exist for now
|
||||
|
||||
|
||||
#if !defined(PXX2) || !defined(EXTMODULE_USART)
|
||||
if (moduleType == MODULE_TYPE_XJT_LITE_PXX2 || moduleType == MODULE_TYPE_R9M_PXX2 || moduleType == MODULE_TYPE_R9M_LITE_PXX2 || moduleType == MODULE_TYPE_R9M_LITE_PRO_PXX2) {
|
||||
if (moduleType == MODULE_TYPE_XJT_LITE_PXX2 ||
|
||||
moduleType == MODULE_TYPE_R9M_PXX2 ||
|
||||
moduleType == MODULE_TYPE_R9M_LITE_PXX2 ||
|
||||
moduleType == MODULE_TYPE_R9M_LITE_PRO_PXX2) {
|
||||
|
||||
#if defined(PXX2)
|
||||
return extmoduleGetSerialPort() != nullptr;
|
||||
#else
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(CROSSFIRE)
|
||||
if (moduleType == MODULE_TYPE_CROSSFIRE)
|
||||
@@ -886,6 +906,14 @@ bool isExternalModuleAvailable(int moduleType)
|
||||
return true;
|
||||
}
|
||||
|
||||
#else // !defined(HARDWARE_EXTERNAL_MODULE)
|
||||
|
||||
bool isExternalModuleAvailable(int moduleType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool isRfProtocolAvailable(int protocol)
|
||||
{
|
||||
#if defined(CROSSFIRE)
|
||||
|
||||
@@ -864,7 +864,9 @@ void applyModelConfig(uint8_t module)
|
||||
static void* initExternal(uint8_t module)
|
||||
{
|
||||
#if defined(AFHDS3_EXT_UART)
|
||||
const etx_serial_driver_t* drv = &ExtmoduleSerialDriver;
|
||||
auto drv = extmoduleGetSerialPort();
|
||||
if (!drv) return nullptr;
|
||||
|
||||
uint16_t period = AFHDS3_UART_COMMAND_TIMEOUT * 1000 /* us */;
|
||||
#else
|
||||
const etx_serial_driver_t* drv = nullptr;
|
||||
|
||||
@@ -207,9 +207,11 @@ uint8_t getModuleType(uint8_t module)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_EXTERNAL_MODULE)
|
||||
if (module == EXTERNAL_MODULE && isExternalModuleAvailable(type)) {
|
||||
return type;
|
||||
}
|
||||
#endif
|
||||
|
||||
return MODULE_TYPE_NONE;
|
||||
}
|
||||
@@ -579,7 +581,7 @@ void enablePulsesExternalModule(uint8_t protocol)
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(PXX2) && defined(EXTMODULE_USART)
|
||||
#if defined(PXX2)
|
||||
case PROTOCOL_CHANNELS_PXX2_HIGHSPEED:
|
||||
externalModuleContext = Pxx2ExternalDriver.init(EXTERNAL_MODULE);
|
||||
externalModuleDriver = &Pxx2ExternalDriver;
|
||||
|
||||
@@ -295,7 +295,10 @@ static const etx_serial_init pxx1ExtSerialInit = {
|
||||
|
||||
static void* pxx1InitExternal(uint8_t module)
|
||||
{
|
||||
void* uart_ctx = ExtmoduleSerialDriver.init(&pxx1ExtSerialInit);
|
||||
auto drv = extmoduleGetSerialPort();
|
||||
if (!drv) return nullptr;
|
||||
|
||||
void* uart_ctx = drv->init(&pxx1ExtSerialInit);
|
||||
|
||||
mixerSchedulerSetPeriod(EXTERNAL_MODULE, EXTMODULE_PXX1_SERIAL_PERIOD);
|
||||
EXTERNAL_MODULE_ON();
|
||||
@@ -307,7 +310,9 @@ static void pxx1DeInitExternal(void* context)
|
||||
{
|
||||
EXTERNAL_MODULE_OFF();
|
||||
mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0);
|
||||
ExtmoduleSerialDriver.deinit(context);
|
||||
|
||||
auto drv = extmoduleGetSerialPort();
|
||||
if (drv) drv->deinit(context);
|
||||
}
|
||||
|
||||
static void pxx1SetupPulsesExternal(void* context, int16_t* channels, uint8_t nChannels)
|
||||
@@ -323,8 +328,11 @@ static void pxx1SetupPulsesExternal(void* context, int16_t* channels, uint8_t nC
|
||||
|
||||
static void pxx1SendPulsesExternal(void* context)
|
||||
{
|
||||
ExtmoduleSerialDriver.sendBuffer(context, extmodulePulsesData.pxx_uart.getData(),
|
||||
extmodulePulsesData.pxx_uart.getSize());
|
||||
auto drv = extmoduleGetSerialPort();
|
||||
if (!drv) return;
|
||||
|
||||
drv->sendBuffer(context, extmodulePulsesData.pxx_uart.getData(),
|
||||
extmodulePulsesData.pxx_uart.getSize());
|
||||
}
|
||||
|
||||
const etx_module_driver_t Pxx1ExternalSerialDriver = {
|
||||
|
||||
@@ -812,6 +812,7 @@ static void pxx2ProcessData(void* context, uint8_t data, uint8_t* buffer, uint8_
|
||||
|
||||
|
||||
#include "hal/module_driver.h"
|
||||
#include "extmodule_serial_driver.h"
|
||||
|
||||
const etx_module_driver_t Pxx2InternalDriver = {
|
||||
.protocol = PROTOCOL_CHANNELS_PXX2_HIGHSPEED,
|
||||
@@ -823,9 +824,6 @@ const etx_module_driver_t Pxx2InternalDriver = {
|
||||
.processData = pxx2ProcessData,
|
||||
};
|
||||
|
||||
#if defined(EXTMODULE_USART)
|
||||
#include "extmodule_serial_driver.h"
|
||||
|
||||
static void* pxx2InitExternal(uint8_t module, uint32_t baudrate)
|
||||
{
|
||||
etx_serial_init params(pxx2SerialInitParams);
|
||||
@@ -837,9 +835,10 @@ static void* pxx2InitExternal(uint8_t module, uint32_t baudrate)
|
||||
telemetryProtocol = PROTOCOL_TELEMETRY_FRSKY_SPORT;
|
||||
|
||||
auto state = &pxx2State[module];
|
||||
state->init(module, &extmodulePulsesData.pxx2, &ExtmoduleSerialDriver,
|
||||
ExtmoduleSerialDriver.init(¶ms));
|
||||
|
||||
auto drv = extmoduleGetSerialPort();
|
||||
if (!drv) return nullptr;
|
||||
|
||||
state->init(module, &extmodulePulsesData.pxx2, drv, drv->init(¶ms));
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -855,9 +854,11 @@ static void* pxx2InitExtHighSpeed(uint8_t module)
|
||||
|
||||
static void pxx2DeInitExternal(void* context)
|
||||
{
|
||||
auto state = (PXX2State*)context;
|
||||
if (state) state->deinit();
|
||||
|
||||
EXTERNAL_MODULE_OFF();
|
||||
mixerSchedulerSetPeriod(EXTERNAL_MODULE, 0);
|
||||
ExtmoduleSerialDriver.deinit(context);
|
||||
telemetryProtocol = 0xFF;
|
||||
}
|
||||
|
||||
@@ -897,4 +898,3 @@ const etx_module_driver_t Pxx2LowSpeedExternalDriver = {
|
||||
.getByte = pxx2GetByte,
|
||||
.processData = pxx2ProcessData,
|
||||
};
|
||||
#endif
|
||||
|
||||
+24
-5
@@ -41,6 +41,10 @@
|
||||
#include "telemetry/crossfire.h"
|
||||
#endif
|
||||
|
||||
#if defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART)
|
||||
#include "extmodule_serial_driver.h"
|
||||
#endif
|
||||
|
||||
#define PRINTF_BUFFER_SIZE 128
|
||||
|
||||
static void (*dbg_serial_putc)(void*, uint8_t) = nullptr;
|
||||
@@ -212,11 +216,19 @@ static void serialSetCallBacks(int mode, void* ctx, const etx_serial_port_t* por
|
||||
gpsSetSerialDriver(ctx, drv);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(SPACEMOUSE)
|
||||
case UART_MODE_SPACEMOUSE:
|
||||
spacemouseSetSerialDriver(ctx, drv);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART)
|
||||
case UART_MODE_EXT_MODULE:
|
||||
extmoduleSetSerialPort(drv);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -279,6 +291,12 @@ static void serialSetupPort(int mode, etx_serial_init& params)
|
||||
params.rx_enable = true;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(AUX_SERIAL_DMA_TX) && !defined(EXTMODULE_USART)
|
||||
case UART_MODE_EXT_MODULE:
|
||||
params.rx_enable = true;
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -330,10 +348,10 @@ void serialInit(uint8_t port_nr, int mode)
|
||||
|
||||
if (state->port) {
|
||||
auto drv = state->port->uart;
|
||||
if (drv && drv->deinit) {
|
||||
if (drv && drv->deinit && state->usart_ctx) {
|
||||
drv->deinit(state->usart_ctx);
|
||||
}
|
||||
if (state->mode != 0) {
|
||||
if (state->mode != UART_MODE_NONE) {
|
||||
// Clear callbacks
|
||||
serialSetCallBacks(state->mode, nullptr, nullptr);
|
||||
}
|
||||
@@ -356,11 +374,12 @@ void serialInit(uint8_t port_nr, int mode)
|
||||
serialSetPowerState(port_nr);
|
||||
#endif
|
||||
|
||||
if (params.baudrate != 0) {
|
||||
state->mode = mode;
|
||||
state->mode = mode;
|
||||
|
||||
if (mode != UART_MODE_NONE) {
|
||||
state->port = port;
|
||||
|
||||
if (port) {
|
||||
if (port && params.baudrate != 0) {
|
||||
if (port->uart && port->uart->init)
|
||||
state->usart_ctx = port->uart->init(¶ms);
|
||||
}
|
||||
|
||||
@@ -114,15 +114,6 @@ void postModelLoad(bool alarms)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
if (!isInternalModuleAvailable(g_model.moduleData[INTERNAL_MODULE].type)) {
|
||||
memclear(&g_model.moduleData[INTERNAL_MODULE], sizeof(ModuleData));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!isExternalModuleAvailable(g_model.moduleData[EXTERNAL_MODULE].type)) {
|
||||
memclear(&g_model.moduleData[EXTERNAL_MODULE], sizeof(ModuleData));
|
||||
}
|
||||
#if defined(MULTIMODULE) && defined(MULTI_PROTOLIST)
|
||||
MultiRfProtocols::removeInstance(EXTERNAL_MODULE);
|
||||
#endif
|
||||
|
||||
@@ -1881,6 +1881,7 @@ static const struct YamlIdStr enum_UartModes[] = {
|
||||
{ UART_MODE_GPS, "GPS" },
|
||||
{ UART_MODE_DEBUG, "DEBUG" },
|
||||
{ UART_MODE_SPACEMOUSE, "SPACEMOUSE" },
|
||||
{ UART_MODE_EXT_MODULE, "EXT_MODULE" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#define AUX_SERIAL_TX_BUFFER 512
|
||||
|
||||
#if defined(SDRAM)
|
||||
#define AUX_SERIAL_RX_BUFFER 128
|
||||
#define AUX_SERIAL_RX_BUFFER 512
|
||||
#else
|
||||
#define AUX_SERIAL_RX_BUFFER 32
|
||||
#endif
|
||||
@@ -53,8 +53,8 @@ static void* aux_serial_init(const SerialState* st, const etx_serial_init* param
|
||||
stm32_usart_init(st->usart, params);
|
||||
|
||||
if (params->rx_enable && st->usart->rxDMA) {
|
||||
st->rxFifo->clear();
|
||||
stm32_usart_init_rx_dma(st->usart, st->rxFifo->buffer(), st->rxFifo->size());
|
||||
st->rxFifo->clear();
|
||||
}
|
||||
|
||||
return (void*)st;
|
||||
@@ -62,17 +62,25 @@ static void* aux_serial_init(const SerialState* st, const etx_serial_init* param
|
||||
|
||||
static void aux_serial_putc(void* ctx, uint8_t c)
|
||||
{
|
||||
// When sending single bytes,
|
||||
// send is based on IRQ, so that this
|
||||
// only enables the corresponding IRQ
|
||||
|
||||
auto st = (const SerialState*)ctx;
|
||||
if (st->txFifo->isFull()) return;
|
||||
st->txFifo->push(c);
|
||||
|
||||
// Send is based on IRQ, so that this
|
||||
// only enables the corresponding IRQ
|
||||
stm32_usart_send_buffer(st->usart, &c, 1);
|
||||
stm32_usart_enable_tx_irq(st->usart);
|
||||
}
|
||||
|
||||
static void aux_serial_send_buffer(void* ctx, const uint8_t* data, uint8_t size)
|
||||
{
|
||||
auto st = (const SerialState*)ctx;
|
||||
if (st->usart->txDMA) {
|
||||
stm32_usart_send_buffer(st->usart, data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
while(size > 0) {
|
||||
aux_serial_putc(ctx, *data++);
|
||||
size--;
|
||||
@@ -112,15 +120,22 @@ static const LL_GPIO_InitTypeDef auxUSARTPinInit = {
|
||||
.Alternate = AUX_SERIAL_GPIO_AF_LL,
|
||||
};
|
||||
|
||||
#if !defined(AUX_SERIAL_DMA_TX)
|
||||
#define AUX_SERIAL_DMA_TX nullptr
|
||||
#define AUX_SERIAL_DMA_Stream_TX nullptr
|
||||
#define AUX_SERIAL_DMA_Stream_TX_LL 0
|
||||
#define AUX_SERIAL_DMA_Channel_TX 0
|
||||
#endif
|
||||
|
||||
static const stm32_usart_t auxUSART = {
|
||||
.USARTx = AUX_SERIAL_USART,
|
||||
.GPIOx = AUX_SERIAL_GPIO,
|
||||
.pinInit = &auxUSARTPinInit,
|
||||
.IRQn = AUX_SERIAL_USART_IRQn,
|
||||
.IRQ_Prio = 7, // TODO: define constant
|
||||
.txDMA = nullptr,
|
||||
.txDMA_Stream = 0,
|
||||
.txDMA_Channel = 0,
|
||||
.txDMA = AUX_SERIAL_DMA_TX,
|
||||
.txDMA_Stream = AUX_SERIAL_DMA_Stream_TX_LL,
|
||||
.txDMA_Channel = AUX_SERIAL_DMA_Channel_TX,
|
||||
.rxDMA = AUX_SERIAL_DMA_RX,
|
||||
.rxDMA_Stream = AUX_SERIAL_DMA_Stream_RX_LL,
|
||||
.rxDMA_Channel = AUX_SERIAL_DMA_Channel_RX,
|
||||
|
||||
@@ -20,38 +20,60 @@
|
||||
*/
|
||||
|
||||
#include "stm32_hal_ll.h"
|
||||
#include "stm32_usart_driver.h"
|
||||
#include "extmodule_serial_driver.h"
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#if defined(EXTMODULE_USART)
|
||||
#include "stm32_usart_driver.h"
|
||||
#include "fifo.h"
|
||||
|
||||
typedef Fifo<uint8_t, INTMODULE_FIFO_SIZE> RxFifo;
|
||||
static RxFifo extmoduleFifo;
|
||||
struct RxFifo {
|
||||
uint8_t* buf;
|
||||
uint16_t size;
|
||||
uint16_t widx;
|
||||
uint16_t ridx;
|
||||
};
|
||||
|
||||
struct ExtmoduleCtx
|
||||
{
|
||||
RxFifo* rxFifo;
|
||||
struct ExtmoduleCtx {
|
||||
RxFifo rxFifo;
|
||||
const stm32_usart_t* usart;
|
||||
};
|
||||
|
||||
static etx_serial_callbacks_t extmodule_driver = {
|
||||
static etx_serial_callbacks_t extmodule_callbacks = {
|
||||
nullptr, nullptr, nullptr
|
||||
};
|
||||
|
||||
void extmoduleFifoReceive(uint8_t data)
|
||||
static void _fifo_clear(const stm32_usart_t* usart, RxFifo& fifo)
|
||||
{
|
||||
extmoduleFifo.push(data);
|
||||
if (usart->rxDMA) {
|
||||
auto dma_len = LL_DMA_GetDataLength(usart->rxDMA, usart->rxDMA_Stream);
|
||||
fifo.ridx = fifo.size - dma_len;
|
||||
} else {
|
||||
fifo.widx = fifo.ridx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const etx_serial_init extmoduleSerialParams = {
|
||||
.baudrate = 0,
|
||||
.parity = ETX_Parity_None,
|
||||
.stop_bits = ETX_StopBits_One,
|
||||
.word_length = ETX_WordLength_8,
|
||||
.rx_enable = true,
|
||||
};
|
||||
static int _fifo_get_byte(const stm32_usart_t* usart, RxFifo& fifo, uint8_t* data)
|
||||
{
|
||||
if (usart->rxDMA) {
|
||||
auto DMAx = usart->rxDMA;
|
||||
auto stream = usart->rxDMA_Stream;
|
||||
|
||||
// DMA stream enabled?
|
||||
if (!LL_DMA_IsEnabledStream(DMAx, stream)) return 0;
|
||||
|
||||
// Anything to read?
|
||||
auto dma_len = LL_DMA_GetDataLength(DMAx, stream);
|
||||
if (fifo.size - dma_len == fifo.ridx) return 0;
|
||||
} else {
|
||||
if (fifo.ridx == fifo.widx) return 0;
|
||||
}
|
||||
|
||||
*data = fifo.buf[fifo.ridx];
|
||||
fifo.ridx = (fifo.ridx + 1) & (fifo.size - 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const LL_GPIO_InitTypeDef extmoduleUSART_PinDef = {
|
||||
.Pin = EXTMODULE_TX_GPIO_PIN | EXTMODULE_RX_GPIO_PIN,
|
||||
@@ -71,96 +93,118 @@ static const stm32_usart_t extmoduleUSART = {
|
||||
.txDMA = EXTMODULE_USART_TX_DMA,
|
||||
.txDMA_Stream = EXTMODULE_USART_TX_DMA_STREAM_LL,
|
||||
.txDMA_Channel = EXTMODULE_USART_TX_DMA_CHANNEL,
|
||||
.rxDMA = nullptr,
|
||||
.rxDMA_Stream = 0,
|
||||
.rxDMA_Channel = 0,
|
||||
.rxDMA = EXTMODULE_USART_TX_DMA,
|
||||
.rxDMA_Stream = EXTMODULE_USART_RX_DMA_STREAM_LL,
|
||||
.rxDMA_Channel = EXTMODULE_USART_RX_DMA_CHANNEL,
|
||||
};
|
||||
|
||||
static const ExtmoduleCtx extmoduleCtx = {
|
||||
.rxFifo = &extmoduleFifo,
|
||||
static uint8_t _rx_buffer[INTMODULE_FIFO_SIZE] __DMA;
|
||||
|
||||
static ExtmoduleCtx extmoduleCtx = {
|
||||
.rxFifo = { _rx_buffer, sizeof(_rx_buffer), 0, 0 },
|
||||
.usart = &extmoduleUSART,
|
||||
};
|
||||
|
||||
static void* extmoduleSerialStart(const etx_serial_init* params)
|
||||
static void* extmoduleSerialInit(const etx_serial_init* params)
|
||||
{
|
||||
if (!params) return nullptr;
|
||||
|
||||
extmodule_driver.on_receive = extmoduleFifoReceive;
|
||||
extmodule_driver.on_error = nullptr;
|
||||
extmodule_callbacks.on_receive = nullptr;
|
||||
extmodule_callbacks.on_error = nullptr;
|
||||
|
||||
// UART config
|
||||
stm32_usart_init(&extmoduleUSART, params);
|
||||
extmoduleCtx.rxFifo->clear();
|
||||
auto usart = extmoduleCtx.usart;
|
||||
stm32_usart_init(usart, params);
|
||||
|
||||
auto& fifo = extmoduleCtx.rxFifo;
|
||||
if (params->rx_enable && usart->rxDMA) {
|
||||
stm32_usart_init_rx_dma(usart, fifo.buf, fifo.size);
|
||||
}
|
||||
_fifo_clear(usart, fifo);
|
||||
|
||||
return (void*)&extmoduleCtx;
|
||||
}
|
||||
|
||||
void extmoduleInvertedSerialStart(uint32_t baudrate)
|
||||
void extmoduleSerialStop(void* ctx)
|
||||
{
|
||||
EXTERNAL_MODULE_ON();
|
||||
etx_serial_init params(extmoduleSerialParams);
|
||||
params.baudrate = baudrate;
|
||||
extmoduleSerialStart(¶ms);
|
||||
}
|
||||
|
||||
void extmoduleSerialStop(void*)
|
||||
{
|
||||
stm32_usart_deinit(&extmoduleUSART);
|
||||
auto modCtx = (ExtmoduleCtx*)ctx;
|
||||
stm32_usart_deinit(modCtx->usart);
|
||||
|
||||
// reset callbacks
|
||||
extmodule_driver.on_receive = nullptr;
|
||||
extmodule_driver.on_error = nullptr;
|
||||
extmodule_callbacks.on_receive = nullptr;
|
||||
extmodule_callbacks.on_error = nullptr;
|
||||
}
|
||||
|
||||
static void extmoduleSendByte(void* ctx, uint8_t byte)
|
||||
static void extmoduleSerialSendByte(void* ctx, uint8_t byte)
|
||||
{
|
||||
auto modCtx = (ExtmoduleCtx*)ctx;
|
||||
stm32_usart_send_byte(modCtx->usart, byte);
|
||||
}
|
||||
|
||||
static void extmoduleSendBuffer(void* ctx, const uint8_t * data, uint8_t size)
|
||||
static void extmoduleSerialSendBuffer(void* ctx, const uint8_t * data, uint8_t size)
|
||||
{
|
||||
auto modCtx = (ExtmoduleCtx*)ctx;
|
||||
if (size == 0) return;
|
||||
stm32_usart_send_buffer(modCtx->usart, data, size);
|
||||
}
|
||||
|
||||
static void extmoduleWaitForTxCompleted(void* ctx)
|
||||
static void extmoduleSerialWaitForTxCompleted(void* ctx)
|
||||
{
|
||||
auto modCtx = (ExtmoduleCtx*)ctx;
|
||||
stm32_usart_wait_for_tx_dma(modCtx->usart);
|
||||
}
|
||||
|
||||
static int extmoduleGetByte(void* ctx, uint8_t* data)
|
||||
static int extmoduleSerialGetByte(void* ctx, uint8_t* data)
|
||||
{
|
||||
auto modCtx = (ExtmoduleCtx*)ctx;
|
||||
if (!modCtx->rxFifo) return -1;
|
||||
return modCtx->rxFifo->pop(*data);
|
||||
return _fifo_get_byte(modCtx->usart, modCtx->rxFifo, data);
|
||||
}
|
||||
|
||||
static void extmoduleClearRxBuffer(void* ctx)
|
||||
static void extmoduleSerialClearRxBuffer(void* ctx)
|
||||
{
|
||||
auto modCtx = (ExtmoduleCtx*)ctx;
|
||||
if (!modCtx->rxFifo) return;
|
||||
modCtx->rxFifo->clear();
|
||||
_fifo_clear(modCtx->usart, modCtx->rxFifo);
|
||||
}
|
||||
|
||||
const etx_serial_driver_t ExtmoduleSerialDriver = {
|
||||
.init = extmoduleSerialStart,
|
||||
static const etx_serial_driver_t extmoduleSerialDriver = {
|
||||
.init = extmoduleSerialInit,
|
||||
.deinit = extmoduleSerialStop,
|
||||
.sendByte = extmoduleSendByte,
|
||||
.sendBuffer = extmoduleSendBuffer,
|
||||
.waitForTxCompleted = extmoduleWaitForTxCompleted,
|
||||
.getByte = extmoduleGetByte,
|
||||
.clearRxBuffer = extmoduleClearRxBuffer,
|
||||
.sendByte = extmoduleSerialSendByte,
|
||||
.sendBuffer = extmoduleSerialSendBuffer,
|
||||
.waitForTxCompleted = extmoduleSerialWaitForTxCompleted,
|
||||
.getByte = extmoduleSerialGetByte,
|
||||
.clearRxBuffer = extmoduleSerialClearRxBuffer,
|
||||
.getBaudrate = nullptr,
|
||||
.setReceiveCb = nullptr,
|
||||
.setBaudrateCb = nullptr,
|
||||
};
|
||||
|
||||
constexpr const etx_serial_driver_t* _default_driver = &extmoduleSerialDriver;
|
||||
|
||||
// IRQ based RX/TX: probably obsolete now
|
||||
extern "C" void EXTMODULE_USART_IRQHandler(void)
|
||||
{
|
||||
stm32_usart_isr(&extmoduleUSART, &extmodule_driver);
|
||||
stm32_usart_isr(extmoduleCtx.usart, &extmodule_callbacks);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
constexpr const etx_serial_driver_t* _default_driver = nullptr;
|
||||
|
||||
#endif // defined(EXTMODULE_USART)
|
||||
|
||||
const etx_serial_driver_t* _extmodule_driver = _default_driver;
|
||||
|
||||
void extmoduleSetSerialPort(const etx_serial_driver_t* drv)
|
||||
{
|
||||
if (drv) {
|
||||
_extmodule_driver = drv;
|
||||
} else {
|
||||
_extmodule_driver = _default_driver;
|
||||
}
|
||||
}
|
||||
|
||||
const etx_serial_driver_t* extmoduleGetSerialPort()
|
||||
{
|
||||
return _extmodule_driver;
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
|
||||
#define EXTMODULE_USART_IRQ_PRIORITY 6
|
||||
|
||||
// Callbacks using intmoduleFifo
|
||||
void extmoduleFifoReceive(uint8_t data);
|
||||
void extmoduleFifoError();
|
||||
// Use an alternative USART as external module
|
||||
void extmoduleSetSerialPort(const etx_serial_driver_t* port);
|
||||
|
||||
extern const etx_serial_driver_t ExtmoduleSerialDriver;
|
||||
// Return the serial driver to be used as external module
|
||||
const etx_serial_driver_t* extmoduleGetSerialPort();
|
||||
|
||||
@@ -19,9 +19,52 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "stm32_hal_ll.h"
|
||||
#include "stm32_usart_driver.h"
|
||||
#include <string.h>
|
||||
|
||||
// WARNING:
|
||||
//
|
||||
// NVIC_GetEnableIRQ is stolen from "${THIRDPARTY_DIR}/CMSIS/Include/core_cm4.h".
|
||||
//
|
||||
// Until we can include the new CMSIS everywhere, this
|
||||
// needs to be defined here, as the old CMSIS does not define it.
|
||||
//
|
||||
// The new CMSIS can be used when StdPeriph is gone, as it mandates
|
||||
// the old version located in "${STM32LIB_DIR}/CMSIS/Include"
|
||||
//
|
||||
static inline uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn)
|
||||
{
|
||||
if ((int32_t)(IRQn) >= 0) {
|
||||
return ((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] &
|
||||
(1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL)
|
||||
? 1UL
|
||||
: 0UL));
|
||||
} else {
|
||||
return (0U);
|
||||
}
|
||||
}
|
||||
|
||||
static void _enable_usart_irq(const stm32_usart_t* usart)
|
||||
{
|
||||
NVIC_SetPriority(usart->IRQn, usart->IRQ_Prio);
|
||||
NVIC_EnableIRQ(usart->IRQn);
|
||||
}
|
||||
|
||||
void stm32_usart_enable_tx_irq(const stm32_usart_t* usart)
|
||||
{
|
||||
if (LL_USART_IsEnabledDMAReq_TX(usart->USARTx)) {
|
||||
stm32_usart_wait_for_tx_dma(usart);
|
||||
LL_USART_DisableDMAReq_TX(usart->USARTx);
|
||||
}
|
||||
|
||||
if (!NVIC_GetEnableIRQ(usart->IRQn)) {
|
||||
_enable_usart_irq(usart);
|
||||
}
|
||||
|
||||
LL_USART_EnableIT_TXE(usart->USARTx);
|
||||
}
|
||||
|
||||
static void enable_usart_clock(USART_TypeDef* USARTx)
|
||||
{
|
||||
if (USARTx == USART1) {
|
||||
@@ -60,6 +103,7 @@ static void disable_usart_clock(USART_TypeDef* USARTx)
|
||||
LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_UART7);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void stm32_usart_init_rx_dma(const stm32_usart_t* usart, void* buffer, uint32_t length)
|
||||
@@ -103,9 +147,7 @@ void stm32_usart_deinit_rx_dma(const stm32_usart_t* usart)
|
||||
|
||||
// Enable IRQ based RX
|
||||
LL_USART_EnableIT_RXNE(usart->USARTx);
|
||||
|
||||
NVIC_SetPriority(usart->IRQn, usart->IRQ_Prio);
|
||||
NVIC_EnableIRQ(usart->IRQn);
|
||||
_enable_usart_irq(usart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,8 +214,7 @@ void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params)
|
||||
}
|
||||
|
||||
if (!usart->txDMA || (params->rx_enable && !usart->rxDMA)) {
|
||||
NVIC_SetPriority(usart->IRQn, usart->IRQ_Prio);
|
||||
NVIC_EnableIRQ(usart->IRQn);
|
||||
_enable_usart_irq(usart);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ struct stm32_usart_t {
|
||||
|
||||
void stm32_usart_init(const stm32_usart_t* usart, const etx_serial_init* params);
|
||||
void stm32_usart_init_rx_dma(const stm32_usart_t* usart, void* buffer, uint32_t length);
|
||||
void stm32_usart_enable_tx_irq(const stm32_usart_t* usart);
|
||||
void stm32_usart_deinit(const stm32_usart_t* usart);
|
||||
void stm32_usart_deinit_rx_dma(const stm32_usart_t* usart);
|
||||
void stm32_usart_send_byte(const stm32_usart_t* usart, uint8_t byte);
|
||||
|
||||
@@ -358,23 +358,26 @@ static void* sbus_trainer_ctx = nullptr;
|
||||
|
||||
void init_trainer_module_sbus()
|
||||
{
|
||||
sbus_trainer_ctx = ExtmoduleSerialDriver.init(&sbusTrainerParams);
|
||||
auto serial_driver = extmoduleGetSerialPort();
|
||||
sbus_trainer_ctx = serial_driver->init(&sbusTrainerParams);
|
||||
}
|
||||
|
||||
void stop_trainer_module_sbus()
|
||||
{
|
||||
auto serial_driver = extmoduleGetSerialPort();
|
||||
auto ctx = sbus_trainer_ctx;
|
||||
if (ctx) {
|
||||
sbus_trainer_ctx = nullptr;
|
||||
ExtmoduleSerialDriver.deinit(ctx);
|
||||
serial_driver->deinit(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
int trainerModuleSbusGetByte(uint8_t* data)
|
||||
{
|
||||
auto serial_driver = extmoduleGetSerialPort();
|
||||
auto ctx = sbus_trainer_ctx;
|
||||
if (ctx) {
|
||||
return ExtmoduleSerialDriver.getByte(ctx, data);
|
||||
return serial_driver->getByte(ctx, data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -434,10 +434,14 @@
|
||||
#define AUX_SERIAL_USART USART3
|
||||
#define AUX_SERIAL_USART_IRQHandler USART3_IRQHandler
|
||||
#define AUX_SERIAL_USART_IRQn USART3_IRQn
|
||||
#define AUX_SERIAL_DMA_TX DMA1
|
||||
#define AUX_SERIAL_DMA_Stream_TX DMA1_Stream3
|
||||
#define AUX_SERIAL_DMA_Stream_TX_LL LL_DMA_STREAM_3
|
||||
#define AUX_SERIAL_DMA_Channel_TX LL_DMA_CHANNEL_4
|
||||
#define AUX_SERIAL_DMA_RX DMA1
|
||||
#define AUX_SERIAL_DMA_Stream_RX DMA1_Stream1
|
||||
#define AUX_SERIAL_DMA_Stream_RX_LL LL_DMA_STREAM_1
|
||||
#define AUX_SERIAL_DMA_Channel_RX DMA_Channel_4
|
||||
#define AUX_SERIAL_DMA_Channel_RX LL_DMA_CHANNEL_4
|
||||
#if defined(RADIO_TX16S)
|
||||
#define AUX_SERIAL_PWR_GPIO GPIOA
|
||||
#define AUX_SERIAL_PWR_GPIO_PIN GPIO_Pin_15 // PA.15
|
||||
@@ -876,9 +880,9 @@
|
||||
#define EXTMODULE_USART_TX_DMA_CHANNEL LL_DMA_CHANNEL_4
|
||||
#define EXTMODULE_USART_TX_DMA_STREAM DMA1_Stream3
|
||||
#define EXTMODULE_USART_TX_DMA_STREAM_LL LL_DMA_STREAM_3
|
||||
#define EXTMODULE_USART_TX_DMA_FLAG_TC DMA_FLAG_TCIF3
|
||||
#define EXTMODULE_USART_RX_DMA_CHANNEL LL_DMA_CHANNEL_4
|
||||
#define EXTMODULE_USART_RX_DMA_STREAM DMA1_Stream1
|
||||
#define EXTMODULE_USART_RX_DMA_STREAM_LL LL_DMA_STREAM_1
|
||||
#elif defined(PCBX10) || PCBREV >= 13
|
||||
#define EXTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_DMA2)
|
||||
#define EXTMODULE_TX_GPIO GPIOA
|
||||
|
||||
@@ -462,20 +462,14 @@
|
||||
#define EXTMODULE_USART_TX_DMA_CHANNEL LL_DMA_CHANNEL_5
|
||||
#define EXTMODULE_USART_TX_DMA_STREAM DMA2_Stream7
|
||||
#define EXTMODULE_USART_TX_DMA_STREAM_LL LL_DMA_STREAM_7
|
||||
#define EXTMODULE_USART_TX_DMA_IRQn DMA2_Stream7_IRQn
|
||||
#define EXTMODULE_USART_TX_DMA_IRQHandler DMA2_Stream7_IRQHandler
|
||||
#define EXTMODULE_USART_TX_DMA_FLAG_TC DMA_IT_TCIF7
|
||||
|
||||
#define EXTMODULE_USART_RX_DMA_CHANNEL LL_DMA_CHANNEL_5
|
||||
#define EXTMODULE_USART_RX_DMA_STREAM DMA2_Stream2
|
||||
#define EXTMODULE_USART_RX_DMA_IRQn DMA2_Stream2_IRQn
|
||||
#define EXTMODULE_USART_RX_DMA_IRQHandler DMA2_Stream2_IRQHandler
|
||||
#define EXTMODULE_USART_RX_DMA_FLAG_TC DMA_IT_TCIF2
|
||||
#define EXTMODULE_USART_RX_DMA_STREAM_LL LL_DMA_STREAM_2
|
||||
|
||||
#define EXTMODULE_USART_IRQHandler USART6_IRQHandler
|
||||
#define EXTMODULE_USART_IRQn USART6_IRQn
|
||||
|
||||
#define EXTMODULE_TIMER_DMA_SIZE (DMA_SxCR_PSIZE_0 | DMA_SxCR_MSIZE_0)
|
||||
//TIMER
|
||||
#define EXTMODULE_TIMER_DMA_CHANNEL LL_DMA_CHANNEL_7
|
||||
#define EXTMODULE_TIMER_DMA_STREAM DMA2_Stream1
|
||||
@@ -483,7 +477,6 @@
|
||||
#define EXTMODULE_TIMER_DMA_STREAM_LL LL_DMA_STREAM_1
|
||||
#define EXTMODULE_TIMER_DMA_STREAM_IRQn DMA2_Stream1_IRQn
|
||||
#define EXTMODULE_TIMER_DMA_IRQHandler DMA2_Stream1_IRQHandler
|
||||
#define EXTMODULE_TIMER_DMA_FLAG_TC DMA_IT_TCIF1
|
||||
|
||||
#define EXTMODULE_TX_INVERT_GPIO GPIOE
|
||||
#define EXTMODULE_TX_INVERT_GPIO_PIN GPIO_Pin_3 // PE.03
|
||||
|
||||
@@ -80,7 +80,8 @@ const etx_serial_driver_t IntmoduleSerialDriver = {
|
||||
.setBaudrateCb = nullptr,
|
||||
};
|
||||
|
||||
const etx_serial_driver_t ExtmoduleSerialDriver = {
|
||||
#if defined(EXTMODULE_USART)
|
||||
static const etx_serial_driver_t _extmoduleSerialDriver = {
|
||||
.init = init,
|
||||
.deinit = deinit,
|
||||
.sendByte = sendByte,
|
||||
@@ -92,3 +93,21 @@ const etx_serial_driver_t ExtmoduleSerialDriver = {
|
||||
.setReceiveCb = nullptr,
|
||||
.setBaudrateCb = nullptr,
|
||||
};
|
||||
|
||||
constexpr const etx_serial_driver_t* _ext_default_drv = &_extmoduleSerialDriver;
|
||||
#else
|
||||
constexpr const etx_serial_driver_t* _ext_default_drv = nullptr;
|
||||
#endif
|
||||
|
||||
const etx_serial_driver_t* _ext_drv = _ext_default_drv;
|
||||
|
||||
void extmoduleSetSerialPort(const etx_serial_driver_t* drv)
|
||||
{
|
||||
if (drv) _ext_drv = drv;
|
||||
else _ext_drv = _ext_default_drv;
|
||||
}
|
||||
|
||||
const etx_serial_driver_t* extmoduleGetSerialPort()
|
||||
{
|
||||
return _ext_drv;
|
||||
}
|
||||
|
||||
@@ -743,6 +743,26 @@ void rtcSetTime(const struct gtm * t)
|
||||
const etx_serial_port_t UsbSerialPort = { "USB-VCP", nullptr, nullptr };
|
||||
#endif
|
||||
|
||||
#if defined(AUX_SERIAL) || defined(AUX2_SERIAL)
|
||||
static void* _fake_drv_init(const etx_serial_init*) { return nullptr; }
|
||||
static void _fake_drv_fct1(void*) {}
|
||||
static void _fake_drv_send_byte(void*, uint8_t) {}
|
||||
static void _fake_drv_send_buffer(void*, const uint8_t*, uint8_t) {}
|
||||
static int _fake_drv_get_byte(void*, uint8_t*) { return 0; }
|
||||
static const etx_serial_driver_t _fake_drv = {
|
||||
.init = _fake_drv_init,
|
||||
.deinit = _fake_drv_fct1,
|
||||
.sendByte = _fake_drv_send_byte,
|
||||
.sendBuffer = _fake_drv_send_buffer,
|
||||
.waitForTxCompleted = _fake_drv_fct1,
|
||||
.getByte = _fake_drv_get_byte,
|
||||
.clearRxBuffer = nullptr,
|
||||
.getBaudrate = nullptr,
|
||||
.setReceiveCb = nullptr,
|
||||
.setBaudrateCb = nullptr,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(AUX_SERIAL)
|
||||
#if defined(AUX_SERIAL_PWR_GPIO)
|
||||
static void _fake_pwr_aux(uint8_t) {}
|
||||
@@ -750,7 +770,7 @@ const etx_serial_port_t UsbSerialPort = { "USB-VCP", nullptr, nullptr };
|
||||
#else
|
||||
#define AUX_SERIAL_PWR nullptr
|
||||
#endif
|
||||
const etx_serial_port_t auxSerialPort = { "AUX1", nullptr, AUX_SERIAL_PWR };
|
||||
static const etx_serial_port_t auxSerialPort = {"AUX1", &_fake_drv, AUX_SERIAL_PWR};
|
||||
#define AUX_SERIAL_PORT &auxSerialPort
|
||||
#else
|
||||
#define AUX_SERIAL_PORT nullptr
|
||||
@@ -763,7 +783,7 @@ const etx_serial_port_t auxSerialPort = { "AUX1", nullptr, AUX_SERIAL_PWR };
|
||||
#else
|
||||
#define AUX2_SERIAL_PWR nullptr
|
||||
#endif
|
||||
const etx_serial_port_t aux2SerialPort = { "AUX2", nullptr, AUX2_SERIAL_PWR };
|
||||
static const etx_serial_port_t aux2SerialPort = {"AUX2", &_fake_drv, AUX2_SERIAL_PWR};
|
||||
#define AUX2_SERIAL_PORT &aux2SerialPort
|
||||
#else
|
||||
#define AUX2_SERIAL_PORT nullptr
|
||||
|
||||
@@ -1783,12 +1783,12 @@
|
||||
#define EXTMODULE_USART_IRQn USART6_IRQn
|
||||
#define EXTMODULE_USART_IRQHandler USART6_IRQHandler
|
||||
#define EXTMODULE_USART_TX_DMA DMA2
|
||||
#define EXTMODULE_USART_TX_DMA_CHANNEL DMA_Channel_5
|
||||
#define EXTMODULE_USART_TX_DMA_CHANNEL LL_DMA_CHANNEL_5
|
||||
#define EXTMODULE_USART_TX_DMA_STREAM DMA2_Stream6
|
||||
#define EXTMODULE_USART_TX_DMA_STREAM_LL LL_DMA_STREAM_6
|
||||
#define EXTMODULE_USART_TX_DMA_FLAG_TC DMA_FLAG_TCIF6
|
||||
#define EXTMODULE_USART_RX_DMA_CHANNEL DMA_Channel_5
|
||||
#define EXTMODULE_USART_RX_DMA_CHANNEL LL_DMA_CHANNEL_5
|
||||
#define EXTMODULE_USART_RX_DMA_STREAM DMA2_Stream1
|
||||
#define EXTMODULE_USART_RX_DMA_STREAM_LL LL_DMA_STREAM_1
|
||||
#else
|
||||
#define EXTMODULE_RCC_AHB1Periph (RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_DMA2)
|
||||
#if defined(RADIO_COMMANDO8)
|
||||
|
||||
@@ -95,12 +95,15 @@ TEST(Conversions, ConversionX9DPFrom23)
|
||||
EXPECT_STRNEQ("Tes", g_model.gvars[0].name); // ZSTREQ
|
||||
EXPECT_STRNEQ("Test", g_model.flightModeData[0].name); // ZSTREQ
|
||||
|
||||
#if defined(INTERNAL_MODULE_PXX2)
|
||||
// Please note: we don't wipe the model's module settings
|
||||
// in case the module is not supported anymore.
|
||||
//
|
||||
// #if defined(INTERNAL_MODULE_PXX2)
|
||||
EXPECT_EQ(MODULE_TYPE_ISRM_PXX2, g_model.moduleData[INTERNAL_MODULE].type);
|
||||
EXPECT_EQ(MODULE_SUBTYPE_ISRM_PXX2_ACCST_D16, g_model.moduleData[INTERNAL_MODULE].subType);
|
||||
#else
|
||||
EXPECT_EQ(MODULE_TYPE_NONE, g_model.moduleData[INTERNAL_MODULE].type);
|
||||
#endif
|
||||
// #else
|
||||
// EXPECT_EQ(MODULE_TYPE_NONE, g_model.moduleData[INTERNAL_MODULE].type);
|
||||
// #endif
|
||||
|
||||
EXPECT_EQ(MODULE_TYPE_R9M_PXX1, g_model.moduleData[EXTERNAL_MODULE].type);
|
||||
EXPECT_EQ(MODULE_SUBTYPE_R9M_FCC, g_model.moduleData[EXTERNAL_MODULE].subType);
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#define TR_TRNMODE "OFF","+=",":="
|
||||
#define TR_TRNCHN "CH1","CH2","CH3","CH4"
|
||||
|
||||
#define TR_AUX_SERIAL_MODES "OFF","Telem Mirror","Telemetry In","SBUS Trainer","LUA","CLI","GPS","Debug","SpaceMouse"
|
||||
#define TR_AUX_SERIAL_MODES "OFF","Telem Mirror","Telemetry In","SBUS Trainer","LUA","CLI","GPS","Debug","SpaceMouse","External module"
|
||||
#define TR_SWTYPES "None","Toggle","2POS","3POS"
|
||||
#define TR_POTTYPES "None",TR("Pot w. det","Pot with detent"),TR("Multipos","Multipos Switch"),"Pot"
|
||||
#define TR_SLIDERTYPES "None","Slider"
|
||||
|
||||
Reference in New Issue
Block a user