From c8a4a80ffdebbcf57d63c3713ce2ca68b5e6f11d Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sun, 14 Nov 2021 11:13:47 +0100 Subject: [PATCH] Serial pass-through --- radio/src/cli.cpp | 121 +++++++++++++++++- radio/src/targets/common/arm/CMakeLists.txt | 5 + .../arm/stm32/intmodule_serial_driver.cpp | 12 ++ radio/src/targets/horus/CMakeLists.txt | 1 + radio/src/targets/horus/board.h | 1 + radio/src/targets/horus/hal.h | 2 +- 6 files changed, 138 insertions(+), 4 deletions(-) diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index 8c263b536..efb3c3472 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -808,12 +808,13 @@ int cliSet(const char **argv) t.tm_hour = hour; t.tm_min = minute; t.tm_sec = second; - g_rtcTime = - gmktime(&t); // update local timestamp and get wday calculated + // update local timestamp and get wday calculated + g_rtcTime = gmktime(&t); rtcSetTime(&t); } else { serialPrint("%s: Invalid arguments \"%s\" \"%s\"", argv[0], argv[1], argv[2]); + return -1; } } #if !defined(SOFTWARE_VOLUME) @@ -824,13 +825,123 @@ int cliSet(const char **argv) } else { serialPrint("%s: Invalid argument \"%s\" \"%s\"", argv[0], argv[1], argv[2]); + return -1; } - return 0; } #endif +#if defined(INTMODULE_BOOTCMD_GPIO) + else if (!strcmp(argv[1], "bootpin")) { + int level = 0; + if (toInt(argv, 2, &level) < 0) { + serialPrint("%s: invalid level argument '%s'", argv[0], argv[2]); + return -1; + } + + if (level) + GPIO_SetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); + else + GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN); + } +#endif + return 0; } +#if defined(ENABLE_SERIAL_PASSTHROUGH) +int cliSerialPassthrough(const char **argv) +{ + const char* port_type = argv[1]; + const char* port_num = argv[2]; + const char* rate_str = argv[3]; + + if (!port_type || !port_num || !rate_str) { + serialPrint("%s: missing argument", argv[0]); + return -1; + } + + int port_n = 0; + int err = toInt(argv, 2, &port_n); + if (err == -1) return err; + if (err == 0) { + serialPrint("%s: missing port #", argv[0]); + return -1; + } + + int baudrate = 0; + err = toInt(argv, 2, &baudrate); + if (err == -1) return err; + if (err == 0) { + serialPrint("%s: missing baudrate", argv[0]); + return -1; + } + + if (!strcmp("rfmod", port_type)) { + + if (port_n >= NUM_MODULES + // only internal module supported for now + && port_n != INTERNAL_MODULE) { + serialPrint("%s: invalid port # '%s'", port_num); + return -1; + } + + // stop pulses + watchdogSuspend(200/*2s*/); + pausePulses(); +#if defined(HARDWARE_INTERNAL_MODULE) + stopPulsesInternalModule(); +#endif +#if defined(HARDWARE_EXTERNAL_MODULE) + stopPulsesExternalModule(); +#endif + +#if defined(HARDWARE_INTERNAL_MODULE) + if (port_n == INTERNAL_MODULE) { + + // TODO: check the stack level so we don't crash it + uint8_t tmpBuf[256]; + + // setup serial com + // TODO: + // - '8n1' param + intmoduleSerialStart(baudrate, true, USART_Parity_No, USART_StopBits_1, + USART_WordLength_8b); + for (;;) { + /* Block for max 10ms. */ + const TickType_t xTimeout = 10 / RTOS_MS_PER_TICK; + size_t xReceivedBytes = + xStreamBufferReceive(cliRxBuffer, tmpBuf, sizeof(tmpBuf), xTimeout); + + // keep us up & running + WDG_RESET(); + + if (xReceivedBytes) { + // TODO: wait for previous buffer flushed + intmoduleWaitForTxCompleted(); + intmoduleSendBuffer(tmpBuf, xReceivedBytes); + } + + // Let's hope this does not starve the other side + uint8_t inData; + while(intmoduleFifo.pop(inData)) { + serialPutc(inData); + } + } + } +#endif + + // TODO: + // - external module (S.PORT?) + // - how to exit this mode ??? USB exit ? + + } else { + serialPrint("%s: invalid port type '%s'", port_type); + return -1; + } + + return 0; +} +#endif + #if defined(DEBUG_INTERRUPTS) void printInterrupts() { @@ -1268,6 +1379,9 @@ const CliCommand cliCommands[] = { { "play", cliPlay, "" }, { "reboot", cliReboot, "[wdt]" }, { "set", cliSet, " " }, +#if defined(ENABLE_SERIAL_PASSTHROUGH) + { "serialpassthrough", cliSerialPassthrough, " "}, +#endif #if defined(DEBUG) { "print", cliDisplay, "
[] | " }, { "p", cliDisplay, "
[] | " }, @@ -1395,6 +1509,7 @@ void cliTask(void * pdata) // save new command strcpy(cliLastLine, line); } + // TODO: check return value cliExecLine(line); pos = 0; cliPrompt(); diff --git a/radio/src/targets/common/arm/CMakeLists.txt b/radio/src/targets/common/arm/CMakeLists.txt index 929c56b36..bd780c5d5 100644 --- a/radio/src/targets/common/arm/CMakeLists.txt +++ b/radio/src/targets/common/arm/CMakeLists.txt @@ -1,6 +1,7 @@ set(TIMERS 3 CACHE STRING "Timers count (2 or 3)") set_property(CACHE TIMERS PROPERTY STRINGS 2 3) option(CLI "Command Line Interface" OFF) +option(ENABLE_SERIAL_PASSTHROUGH "Enable serial passthrough" OFF) option(DEBUG "Debug mode" OFF) option(LOG_TELEMETRY "Telemetry Logs on SD card" OFF) option(LOG_BLUETOOTH "Bluetooth Logs on SD card" OFF) @@ -101,6 +102,10 @@ if(CLI OR DEBUG) set(SRC ${SRC} dump.cpp) endif() +if(ENABLE_SERIAL_PASSTHROUGH) + add_definitions(-DENABLE_SERIAL_PASSTHROUGH) +endif() + if(DEBUG) add_definitions(-DDEBUG) endif() diff --git a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp index 2d8c7a2da..cdaaff4c6 100755 --- a/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp +++ b/radio/src/targets/common/arm/stm32/intmodule_serial_driver.cpp @@ -205,3 +205,15 @@ void intmoduleSendNextFrame() #endif } } + +void intmoduleWaitForTxCompleted() +{ +#if defined(INTMODULE_DMA_STREAM) + if (DMA_GetCmdStatus(INTMODULE_DMA_STREAM) == ENABLE) { + while(DMA_GetFlagStatus(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC) == RESET); + DMA_ClearFlag(INTMODULE_DMA_STREAM, INTMODULE_DMA_FLAG_TC); + } +#else + #error "intmoduleWaitForTC() not implemented for IRQ based transfer" +#endif +} diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 85a51f568..37cdc2be5 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -106,6 +106,7 @@ if (PCB STREQUAL X10) set(AUX2_SERIAL ON) endif() set(INTERNAL_GPS_BAUDRATE "9600" CACHE STRING "Baud rate for internal GPS") + set(ENABLE_SERIAL_PASSTHROUGH ON CACHE BOOL "Enable serial passthrough") set(CLI ON CACHE BOOL "Enable CLI") elseif (PCBREV STREQUAL T18) set(FLAVOUR t18) diff --git a/radio/src/targets/horus/board.h b/radio/src/targets/horus/board.h index ed61357e1..4e8a1fb6e 100644 --- a/radio/src/targets/horus/board.h +++ b/radio/src/targets/horus/board.h @@ -202,6 +202,7 @@ void intmoduleSerialStart(uint32_t baudrate, uint8_t rxEnable, uint16_t parity, void intmoduleSendByte(uint8_t byte); void intmoduleSendBuffer(const uint8_t * data, uint8_t size); void intmoduleSendNextFrame(); +void intmoduleWaitForTxCompleted(); void extmoduleSerialStart(); void extmoduleInvertedSerialStart(uint32_t baudrate); diff --git a/radio/src/targets/horus/hal.h b/radio/src/targets/horus/hal.h index 829482d90..2ad32f759 100644 --- a/radio/src/targets/horus/hal.h +++ b/radio/src/targets/horus/hal.h @@ -817,7 +817,7 @@ #define INTMODULE_DMA_STREAM DMA2_Stream7 #define INTMODULE_DMA_STREAM_IRQ DMA2_Stream7_IRQn #define INTMODULE_DMA_STREAM_IRQHandler DMA2_Stream7_IRQHandler -#define INTMODULE_DMA_FLAG_TC DMA_IT_TCIF7 +#define INTMODULE_DMA_FLAG_TC DMA_FLAG_TCIF7 #define INTMODULE_DMA_CHANNEL DMA_Channel_4 #if defined(PCBX12S) #define INTMODULE_BOOTCMD_GPIO GPIOC