From b2977c66a4554297513b63f8e77a859ace7716f8 Mon Sep 17 00:00:00 2001 From: Rob Riggs Date: Tue, 3 Aug 2021 21:32:40 -0500 Subject: [PATCH] Add support for BER testing. Update version to v2.3.2 --- .../Inc/stm32l4xx_hal_iwdg.h | 255 ++++++++ .../Src/stm32l4xx_hal_iwdg.c | 280 +++++++++ Inc/main.h | 21 + Inc/stm32l4xx_hal_conf.h | 2 +- Src/main.c | 20 +- TNC/AFSKModulator.hpp | 15 +- TNC/AFSKTestTone.cpp | 20 +- TNC/AFSKTestTone.hpp | 8 +- TNC/Afsk1200Demodulator.cpp | 20 +- TNC/AudioInput.cpp | 51 +- TNC/AudioInput.hpp | 4 +- TNC/AudioLevel.cpp | 2 +- TNC/AudioLevel.hpp | 9 +- TNC/Encoder.h | 5 +- TNC/Fsk9600Demodulator.cpp | 20 +- TNC/Fsk9600Modulator.hpp | 15 +- TNC/HdlcFrame.cpp | 2 +- TNC/HdlcFrame.hpp | 14 +- TNC/IOEventTask.cpp | 6 +- TNC/IirFilter.hpp | 15 +- TNC/Kiss.cpp | 20 +- TNC/KissHardware.cpp | 114 ++-- TNC/KissHardware.hpp | 57 +- TNC/LEDIndicator.cpp | 30 +- TNC/LEDIndicator.h | 2 +- TNC/Log.h | 2 - TNC/M17.h | 1 + TNC/M17Demodulator.cpp | 575 ++++++++++-------- TNC/M17Demodulator.h | 21 +- TNC/M17Encoder.cpp | 38 +- TNC/M17Encoder.h | 9 +- TNC/M17FrameDecoder.h | 43 +- TNC/M17Modulator.h | 50 +- TNC/Modulator.hpp | 2 + TNC/ModulatorTask.cpp | 4 +- TNC/NullPort.hpp | 7 +- TNC/SegmentedBuffer.hpp | 7 +- TNC/SerialPort.cpp | 8 +- TNC/SerialPort.hpp | 7 +- TNC/Util.h | 83 ++- TNC/memory.hpp | 9 +- 41 files changed, 1345 insertions(+), 528 deletions(-) create mode 100644 Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_iwdg.h create mode 100644 Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_iwdg.c diff --git a/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_iwdg.h b/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_iwdg.h new file mode 100644 index 0000000..918f671 --- /dev/null +++ b/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal_iwdg.h @@ -0,0 +1,255 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_iwdg.h + * @author MCD Application Team + * @brief Header file of IWDG HAL module. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32L4xx_HAL_IWDG_H +#define __STM32L4xx_HAL_IWDG_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l4xx_hal_def.h" + +/** @addtogroup STM32L4xx_HAL_Driver + * @{ + */ + +/** @defgroup IWDG IWDG + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup IWDG_Exported_Types IWDG Exported Types + * @{ + */ + +/** + * @brief IWDG Init structure definition + */ +typedef struct +{ + uint32_t Prescaler; /*!< Select the prescaler of the IWDG. + This parameter can be a value of @ref IWDG_Prescaler */ + + uint32_t Reload; /*!< Specifies the IWDG down-counter reload value. + This parameter must be a number between Min_Data = 0 and Max_Data = 0x0FFF */ + + uint32_t Window; /*!< Specifies the window value to be compared to the down-counter. + This parameter must be a number between Min_Data = 0 and Max_Data = 0x0FFF */ + +} IWDG_InitTypeDef; + +/** + * @brief IWDG Handle Structure definition + */ +typedef struct +{ + IWDG_TypeDef *Instance; /*!< Register base address */ + + IWDG_InitTypeDef Init; /*!< IWDG required parameters */ + +}IWDG_HandleTypeDef; + +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup IWDG_Exported_Constants IWDG Exported Constants + * @{ + */ + +/** @defgroup IWDG_Prescaler IWDG Prescaler + * @{ + */ +#define IWDG_PRESCALER_4 0x00000000u /*!< IWDG prescaler set to 4 */ +#define IWDG_PRESCALER_8 IWDG_PR_PR_0 /*!< IWDG prescaler set to 8 */ +#define IWDG_PRESCALER_16 IWDG_PR_PR_1 /*!< IWDG prescaler set to 16 */ +#define IWDG_PRESCALER_32 (IWDG_PR_PR_1 | IWDG_PR_PR_0) /*!< IWDG prescaler set to 32 */ +#define IWDG_PRESCALER_64 IWDG_PR_PR_2 /*!< IWDG prescaler set to 64 */ +#define IWDG_PRESCALER_128 (IWDG_PR_PR_2 | IWDG_PR_PR_0) /*!< IWDG prescaler set to 128 */ +#define IWDG_PRESCALER_256 (IWDG_PR_PR_2 | IWDG_PR_PR_1) /*!< IWDG prescaler set to 256 */ +/** + * @} + */ + +/** @defgroup IWDG_Window_option IWDG Window option + * @{ + */ +#define IWDG_WINDOW_DISABLE IWDG_WINR_WIN +/** + * @} + */ + +/** + * @} + */ + +/* Exported macros -----------------------------------------------------------*/ +/** @defgroup IWDG_Exported_Macros IWDG Exported Macros + * @{ + */ + +/** + * @brief Enable the IWDG peripheral. + * @param __HANDLE__ IWDG handle + * @retval None + */ +#define __HAL_IWDG_START(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_ENABLE) + +/** + * @brief Reload IWDG counter with value defined in the reload register + * (write access to IWDG_PR, IWDG_RLR & IWDG_WINR registers disabled). + * @param __HANDLE__ IWDG handle + * @retval None + */ +#define __HAL_IWDG_RELOAD_COUNTER(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_RELOAD) + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup IWDG_Exported_Functions IWDG Exported Functions + * @{ + */ + +/** @defgroup IWDG_Exported_Functions_Group1 Initialization and Start functions + * @{ + */ +/* Initialization/Start functions ********************************************/ +HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg); +/** + * @} + */ + +/** @defgroup IWDG_Exported_Functions_Group2 IO operation functions + * @{ + */ +/* I/O operation functions ****************************************************/ +HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg); +/** + * @} + */ + +/** + * @} + */ + +/* Private constants ---------------------------------------------------------*/ +/** @defgroup IWDG_Private_Constants IWDG Private Constants + * @{ + */ + +/** + * @brief IWDG Key Register BitMask + */ +#define IWDG_KEY_RELOAD 0x0000AAAAu /*!< IWDG Reload Counter Enable */ +#define IWDG_KEY_ENABLE 0x0000CCCCu /*!< IWDG Peripheral Enable */ +#define IWDG_KEY_WRITE_ACCESS_ENABLE 0x00005555u /*!< IWDG KR Write Access Enable */ +#define IWDG_KEY_WRITE_ACCESS_DISABLE 0x00000000u /*!< IWDG KR Write Access Disable */ + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup IWDG_Private_Macros IWDG Private Macros + * @{ + */ + +/** + * @brief Enable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers. + * @param __HANDLE__ IWDG handle + * @retval None + */ +#define IWDG_ENABLE_WRITE_ACCESS(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_WRITE_ACCESS_ENABLE) + +/** + * @brief Disable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers. + * @param __HANDLE__ IWDG handle + * @retval None + */ +#define IWDG_DISABLE_WRITE_ACCESS(__HANDLE__) WRITE_REG((__HANDLE__)->Instance->KR, IWDG_KEY_WRITE_ACCESS_DISABLE) + +/** + * @brief Check IWDG prescaler value. + * @param __PRESCALER__ IWDG prescaler value + * @retval None + */ +#define IS_IWDG_PRESCALER(__PRESCALER__) (((__PRESCALER__) == IWDG_PRESCALER_4) || \ + ((__PRESCALER__) == IWDG_PRESCALER_8) || \ + ((__PRESCALER__) == IWDG_PRESCALER_16) || \ + ((__PRESCALER__) == IWDG_PRESCALER_32) || \ + ((__PRESCALER__) == IWDG_PRESCALER_64) || \ + ((__PRESCALER__) == IWDG_PRESCALER_128)|| \ + ((__PRESCALER__) == IWDG_PRESCALER_256)) + +/** + * @brief Check IWDG reload value. + * @param __RELOAD__ IWDG reload value + * @retval None + */ +#define IS_IWDG_RELOAD(__RELOAD__) ((__RELOAD__) <= IWDG_RLR_RL) + +/** + * @brief Check IWDG window value. + * @param __WINDOW__ IWDG window value + * @retval None + */ +#define IS_IWDG_WINDOW(__WINDOW__) ((__WINDOW__) <= IWDG_WINR_WIN) + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32L4xx_HAL_IWDG_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_iwdg.c b/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_iwdg.c new file mode 100644 index 0000000..2cf5b4a --- /dev/null +++ b/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_iwdg.c @@ -0,0 +1,280 @@ +/** + ****************************************************************************** + * @file stm32l4xx_hal_iwdg.c + * @author MCD Application Team + * @brief IWDG HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Independent Watchdog (IWDG) peripheral: + * + Initialization and Start functions + * + IO operation functions + * + @verbatim + ============================================================================== + ##### IWDG Generic features ##### + ============================================================================== + [..] + (+) The IWDG can be started by either software or hardware (configurable + through option byte). + + (+) The IWDG is clocked by Low-Speed clock (LSI) and thus stays active even + if the main clock fails. + + (+) Once the IWDG is started, the LSI is forced ON and both can not be + disabled. The counter starts counting down from the reset value (0xFFF). + When it reaches the end of count value (0x000) a reset signal is + generated (IWDG reset). + + (+) Whenever the key value 0x0000 AAAA is written in the IWDG_KR register, + the IWDG_RLR value is reloaded in the counter and the watchdog reset is + prevented. + + (+) The IWDG is implemented in the VDD voltage domain that is still functional + in STOP and STANDBY mode (IWDG reset can wake-up from STANDBY). + IWDGRST flag in RCC_CSR register can be used to inform when an IWDG + reset occurs. + + (+) Debug mode : When the microcontroller enters debug mode (core halted), + the IWDG counter either continues to work normally or stops, depending + on DBG_IWDG_STOP configuration bit in DBG module, accessible through + __HAL_DBGMCU_FREEZE_IWDG() and __HAL_DBGMCU_UNFREEZE_IWDG() macros + + [..] Min-max timeout value @32KHz (LSI): ~125us / ~32.7s + The IWDG timeout may vary due to LSI frequency dispersion. STM32L4xx + devices provide the capability to measure the LSI frequency (LSI clock + connected internally to TIM16 CH1 input capture). The measured value + can be used to have an IWDG timeout with an acceptable accuracy. + + ##### How to use this driver ##### + ============================================================================== + [..] + (#) Use IWDG using HAL_IWDG_Init() function to : + (++) Enable instance by writing Start keyword in IWDG_KEY register. LSI + clock is forced ON and IWDG counter starts downcounting. + (++) Enable write access to configuration register: IWDG_PR, IWDG_RLR & + IWDG_WINR. + (++) Configure the IWDG prescaler and counter reload value. This reload + value will be loaded in the IWDG counter each time the watchdog is + reloaded, then the IWDG will start counting down from this value. + (++) Wait for status flags to be reset + (++) Depending on window parameter: + (+++) If Window Init parameter is same as Window register value, + nothing more is done but reload counter value in order to exit + function withy exact time base. + (+++) Else modify Window register. This will automatically reload + watchdog counter. + + (#) Then the application program must refresh the IWDG counter at regular + intervals during normal operation to prevent an MCU reset, using + HAL_IWDG_Refresh() function. + + *** IWDG HAL driver macros list *** + ==================================== + [..] + Below the list of most used macros in IWDG HAL driver: + (+) __HAL_IWDG_START: Enable the IWDG peripheral + (+) __HAL_IWDG_RELOAD_COUNTER: Reloads IWDG counter with value defined in + the reload register + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32l4xx_hal.h" + +/** @addtogroup STM32L4xx_HAL_Driver + * @{ + */ + +#ifdef HAL_IWDG_MODULE_ENABLED +/** @addtogroup IWDG + * @brief IWDG HAL module driver. + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @defgroup IWDG_Private_Defines IWDG Private Defines + * @{ + */ +/* Status register need 5 RC LSI divided by prescaler clock to be updated. With + higher prescaler (256), and according to HSI variation, we need to wait at + least 6 cycles so 48 ms. */ +#define HAL_IWDG_DEFAULT_TIMEOUT 48u +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Exported functions --------------------------------------------------------*/ + +/** @addtogroup IWDG_Exported_Functions + * @{ + */ + +/** @addtogroup IWDG_Exported_Functions_Group1 + * @brief Initialization and Start functions. + * +@verbatim + =============================================================================== + ##### Initialization and Start functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Initialize the IWDG according to the specified parameters in the + IWDG_InitTypeDef of associated handle. + (+) Manage Window option. + (+) Once initialization is performed in HAL_IWDG_Init function, Watchdog + is reloaded in order to exit function with correct time base. + +@endverbatim + * @{ + */ + +/** + * @brief Initialize the IWDG according to the specified parameters in the + * IWDG_InitTypeDef and start watchdog. Before exiting function, + * watchdog is refreshed in order to have correct time base. + * @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains + * the configuration information for the specified IWDG module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg) +{ + uint32_t tickstart; + + /* Check the IWDG handle allocation */ + if(hiwdg == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_IWDG_ALL_INSTANCE(hiwdg->Instance)); + assert_param(IS_IWDG_PRESCALER(hiwdg->Init.Prescaler)); + assert_param(IS_IWDG_RELOAD(hiwdg->Init.Reload)); + assert_param(IS_IWDG_WINDOW(hiwdg->Init.Window)); + + /* Enable IWDG. LSI is turned on automaticaly */ + __HAL_IWDG_START(hiwdg); + + /* Enable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers by writing + 0x5555 in KR */ + IWDG_ENABLE_WRITE_ACCESS(hiwdg); + + /* Write to IWDG registers the Prescaler & Reload values to work with */ + hiwdg->Instance->PR = hiwdg->Init.Prescaler; + hiwdg->Instance->RLR = hiwdg->Init.Reload; + + /* Check pending flag, if previous update not done, return timeout */ + tickstart = HAL_GetTick(); + + /* Wait for register to be updated */ + while (hiwdg->Instance->SR != 0x00u) + { + if((HAL_GetTick() - tickstart ) > HAL_IWDG_DEFAULT_TIMEOUT) + { + return HAL_TIMEOUT; + } + } + + /* If window parameter is different than current value, modify window + register */ + if(hiwdg->Instance->WINR != hiwdg->Init.Window) + { + /* Write to IWDG WINR the IWDG_Window value to compare with. In any case, + even if window feature is disabled, Watchdog will be reloaded by writing + windows register */ + hiwdg->Instance->WINR = hiwdg->Init.Window; + } + else + { + /* Reload IWDG counter with value defined in the reload register */ + __HAL_IWDG_RELOAD_COUNTER(hiwdg); + } + + /* Return function status */ + return HAL_OK; +} + +/** + * @} + */ + + +/** @addtogroup IWDG_Exported_Functions_Group2 + * @brief IO operation functions + * +@verbatim + =============================================================================== + ##### IO operation functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Refresh the IWDG. + +@endverbatim + * @{ + */ + + +/** + * @brief Refresh the IWDG. + * @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains + * the configuration information for the specified IWDG module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg) +{ + /* Reload IWDG counter with value defined in the reload register */ + __HAL_IWDG_RELOAD_COUNTER(hiwdg); + + /* Return function status */ + return HAL_OK; +} + +/** + * @} + */ + +/** + * @} + */ + +#endif /* HAL_IWDG_MODULE_ENABLED */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Inc/main.h b/Inc/main.h index 6391ab2..50dbb8d 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -101,6 +101,27 @@ /* USER CODE BEGIN Private defines */ +// #define TNC_HAS_LSCO -- Not available on NucleoTNC +// #define TNC_HAS_SWO -- Not available on NucleoTNC +#define TNC_HAS_LSE +// #define TNC_HAS_HSE -- Not available on NucleoTNC +// #define TNC_HAS_MCO -- Not available on NucleoTNC +// #define TNC_HAS_BT -- Not available on NucleoTNC +// #define TNC_HAS_BAT -- Not available on NucleoTNC +// #define TNC_HAS_USB -- Not available on NucleoTNC + +// Compatibility defines +// #define BATTERY_ADC_HANDLE hadc2 +// #define BATTERY_ADC_CHANNEL ADC_CHANNEL_16 +#define LED_PWM_TIMER_HANDLE htim1 +#define EEPROM_I2C hi2c3 +#define SERIAL_UART huart2 +#define AUDIO_ADC_HANDLE hadc1 +#define AUDIO_ADC_CHANNEL CHANNEL_8 + +//#define USB_CE_Pin GPIO_PIN_4 +//#define USB_CE_GPIO_Port GPIOB + #define EEPROM_ADDRESS 0xA0 #define EEPROM_CAPACITY 4096 #define EEPROM_PAGE_SIZE 32 diff --git a/Inc/stm32l4xx_hal_conf.h b/Inc/stm32l4xx_hal_conf.h index 31b37cc..079bd4c 100644 --- a/Inc/stm32l4xx_hal_conf.h +++ b/Inc/stm32l4xx_hal_conf.h @@ -67,7 +67,7 @@ /*#define HAL_HASH_MODULE_ENABLED */ /*#define HAL_I2S_MODULE_ENABLED */ /*#define HAL_IRDA_MODULE_ENABLED */ -/*#define HAL_IWDG_MODULE_ENABLED */ +#define HAL_IWDG_MODULE_ENABLED /*#define HAL_LTDC_MODULE_ENABLED */ /*#define HAL_LCD_MODULE_ENABLED */ /*#define HAL_LPTIM_MODULE_ENABLED */ diff --git a/Src/main.c b/Src/main.c index 12591aa..70815fa 100644 --- a/Src/main.c +++ b/Src/main.c @@ -72,6 +72,8 @@ DMA_HandleTypeDef hdma_i2c3_tx; OPAMP_HandleTypeDef hopamp1; +IWDG_HandleTypeDef hiwdg; + RNG_HandleTypeDef hrng; RTC_HandleTypeDef hrtc; @@ -145,6 +147,7 @@ static void MX_USART2_UART_Init(void); static void MX_I2C3_Init(void); static void MX_TIM1_Init(void); static void MX_RNG_Init(void); +static void MX_IWDG_Init(void); void startDefaultTask(void const * argument); extern void startIOEventTask(void const * argument); extern void startAudioInputTask(void const * argument); @@ -636,6 +639,21 @@ static void MX_I2C3_Init(void) } +/* IWDG init function */ +static void MX_IWDG_Init(void) +{ + + hiwdg.Instance = IWDG; + hiwdg.Init.Prescaler = IWDG_PRESCALER_16; + hiwdg.Init.Window = 4095; + hiwdg.Init.Reload = 4095; + if (HAL_IWDG_Init(&hiwdg) != HAL_OK) + { + _Error_Handler(__FILE__, __LINE__); + } + +} + /* OPAMP1 init function */ static void MX_OPAMP1_Init(void) { @@ -1239,7 +1257,7 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) } /* USER CODE BEGIN Callback 1 */ if (htim->Instance == TIM1) { - HTIM1_PeriodElapsedCallback(); + LED_TIMER_PeriodElapsedCallback(); } /* USER CODE END Callback 1 */ diff --git a/TNC/AFSKModulator.hpp b/TNC/AFSKModulator.hpp index 6305885..db28302 100644 --- a/TNC/AFSKModulator.hpp +++ b/TNC/AFSKModulator.hpp @@ -19,6 +19,7 @@ extern osMessageQId hdlcOutputQueueHandle; extern osMessageQId dacOutputQueueHandle; extern TIM_HandleTypeDef htim7; extern DAC_HandleTypeDef hdac1; +extern IWDG_HandleTypeDef hiwdg; namespace mobilinkd { namespace tnc { @@ -114,7 +115,7 @@ struct AFSKModulator : Modulator switch (running_) { case -1: ptt_->on(); -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_DisableLSCO(); #endif @@ -132,8 +133,12 @@ struct AFSKModulator : Modulator } } + void tone(uint16_t freq) override {} + void fill(uint16_t* buffer, bool bit) { + HAL_IWDG_Refresh(&hiwdg); + for (size_t i = 0; i != BIT_LEN; i++) { int s = sin_table[pos_]; @@ -152,7 +157,7 @@ struct AFSKModulator : Modulator } } if (s < 0 or s > 4095) { - DEBUG("DAC inversion (%d)", s); + TNC_DEBUG("DAC inversion (%d)", s); } *buffer = uint16_t(s); ++buffer; @@ -183,6 +188,8 @@ struct AFSKModulator : Modulator void empty() { + HAL_IWDG_Refresh(&hiwdg); + switch (running_) { case 1: running_ = 0; @@ -192,7 +199,7 @@ struct AFSKModulator : Modulator stop_conversion(); ptt_->off(); pos_ = 0; -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_EnableLSCO(RCC_LSCOSOURCE_LSE); #endif break; @@ -207,7 +214,7 @@ struct AFSKModulator : Modulator stop_conversion(); ptt_->off(); pos_ = 0; -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_EnableLSCO(RCC_LSCOSOURCE_LSE); #endif diff --git a/TNC/AFSKTestTone.cpp b/TNC/AFSKTestTone.cpp index 3c4a90b..2b2375c 100644 --- a/TNC/AFSKTestTone.cpp +++ b/TNC/AFSKTestTone.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Rob Riggs +// Copyright 2016-2021 Rob Riggs // All rights reserved. #include "AFSKTestTone.hpp" @@ -85,8 +85,7 @@ void AFSKTestTone::stop() void AFSKTestTone::fill() const { static State current = State::SPACE; - static uint32_t random = 0; - static uint8_t counter = 0; + switch (state_) { case AFSKTestTone::State::NONE: @@ -104,6 +103,7 @@ void AFSKTestTone::fill() const case AFSKTestTone::State::SPACE: if (kiss::settings().modem_type == kiss::Hardware::ModemType::M17) { + getModulator().tone(1); getModulator().send(0x22); } else @@ -114,17 +114,13 @@ void AFSKTestTone::fill() const case AFSKTestTone::State::BOTH: if (kiss::settings().modem_type == kiss::Hardware::ModemType::M17) { - if ((counter & 3) == 0) - { - auto status = HAL_RNG_GenerateRandomNumber(&hrng, &random); - if (status != HAL_OK) - { - WARN("RNG failure code %d", status); + auto frame = getEncoder().create_bert_frame(); + if (frame) { + for (auto c : *frame) { + getModulator().send(c); } + hdlc::release(frame); } - getModulator().send(random & 0xFF); - random >>= 8; - counter += 1; } else { diff --git a/TNC/AFSKTestTone.hpp b/TNC/AFSKTestTone.hpp index f73f971..ec3fbb4 100644 --- a/TNC/AFSKTestTone.hpp +++ b/TNC/AFSKTestTone.hpp @@ -1,8 +1,7 @@ -// Copyright 2016 Rob Riggs +// Copyright 2016-2021 Rob Riggs // All rights reserved. -#ifndef MOBILINKD__TNC__AFSK_TEST_TONE_HPP_ -#define MOBILINKD__TNC__AFSK_TEST_TONE_HPP_ +#pragma once #include "cmsis_os.h" @@ -27,6 +26,3 @@ struct AFSKTestTone }; }} // mobilinkd::tnc - - -#endif // MOBILINKD__TNC__AFSK_TEST_TONE_HPP_ diff --git a/TNC/Afsk1200Demodulator.cpp b/TNC/Afsk1200Demodulator.cpp index 7c92336..b5028fe 100644 --- a/TNC/Afsk1200Demodulator.cpp +++ b/TNC/Afsk1200Demodulator.cpp @@ -85,7 +85,7 @@ hdlc::IoFrame* Afsk1200Demodulator::operator()(const q15_t* samples) */ float Afsk1200Demodulator::readTwist() { - DEBUG("enter Afsk1200Demodulator::readTwist"); + TNC_DEBUG("enter Afsk1200Demodulator::readTwist"); float g1200 = 0.0f; float g2200 = 0.0f; @@ -133,14 +133,14 @@ float Afsk1200Demodulator::readTwist() INFO("Twist = %d / 100 (%d - %d)", int(result * 100), int(g1200), int(g2200)); - DEBUG("exit readTwist"); + TNC_DEBUG("exit readTwist"); return result; } uint32_t Afsk1200Demodulator::readBatteryLevel() { #ifndef NUCLEOTNC - DEBUG("enter Afsk1200Demodulator::readBatteryLevel"); + TNC_DEBUG("enter Afsk1200Demodulator::readBatteryLevel"); ADC_ChannelConfTypeDef sConfig; @@ -171,21 +171,21 @@ uint32_t Afsk1200Demodulator::readBatteryLevel() gpio::BAT_DIVIDER::off(); HAL_Delay(1); - sConfig.Channel = ADC_CHANNEL_15; - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) + sConfig.Channel = BATTERY_ADC_CHANNEL; + if (HAL_ADC_ConfigChannel(&BATTERY_ADC_HANDLE, &sConfig) != HAL_OK) CxxErrorHandler(); uint32_t vbat = 0; - if (HAL_ADC_Start(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_ADC_Start(&BATTERY_ADC_HANDLE) != HAL_OK) CxxErrorHandler(); for (size_t i = 0; i != 8; ++i) { - if (HAL_ADC_PollForConversion(&hadc1, 1) != HAL_OK) CxxErrorHandler(); - vbat += HAL_ADC_GetValue(&hadc1); + if (HAL_ADC_PollForConversion(&BATTERY_ADC_HANDLE, 1) != HAL_OK) CxxErrorHandler(); + vbat += HAL_ADC_GetValue(&BATTERY_ADC_HANDLE); } vbat /= 8; - if (HAL_ADC_Stop(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_ADC_Stop(&BATTERY_ADC_HANDLE) != HAL_OK) CxxErrorHandler(); if (HAL_TIM_Base_Stop(&htim6) != HAL_OK) CxxErrorHandler(); @@ -206,7 +206,7 @@ uint32_t Afsk1200Demodulator::readBatteryLevel() INFO("Vref = %lumV", vref); INFO("Vbat = %lumV", vbat); - DEBUG("exit Afsk1200Demodulator::readBatteryLevel"); + TNC_DEBUG("exit Afsk1200Demodulator::readBatteryLevel"); return vbat; #else return 0; diff --git a/TNC/AudioInput.cpp b/TNC/AudioInput.cpp index c671b25..5a98b54 100644 --- a/TNC/AudioInput.cpp +++ b/TNC/AudioInput.cpp @@ -26,6 +26,7 @@ #include extern osMessageQId ioEventQueueHandle; +extern IWDG_HandleTypeDef hiwdg; extern "C" void SystemClock_Config(void); @@ -61,7 +62,7 @@ extern "C" void HAL_ADC_ErrorCallback(ADC_HandleTypeDef* /* hadc */) { extern "C" void startAudioInputTask(void const*) { using namespace mobilinkd::tnc::audio; - DEBUG("startAudioInputTask"); + TNC_DEBUG("startAudioInputTask"); adcPool.init(); @@ -74,7 +75,7 @@ extern "C" void startAudioInputTask(void const*) { switch (adcState) { case STOPPED: - DEBUG("STOPPED"); + TNC_DEBUG("STOPPED"); // stop(); break; case DEMODULATOR: @@ -82,41 +83,41 @@ extern "C" void startAudioInputTask(void const*) { demodulatorTask(); break; case STREAM_AMPLIFIED_INPUT_LEVEL: - DEBUG("STREAM_AMPLIFIED_INPUT_LEVEL"); + TNC_DEBUG("STREAM_AMPLIFIED_INPUT_LEVEL"); streamAmplifiedInputLevels(); break; case POLL_AMPLIFIED_INPUT_LEVEL: - DEBUG("POLL_AMPLIFIED_INPUT_LEVEL"); + TNC_DEBUG("POLL_AMPLIFIED_INPUT_LEVEL"); pollAmplifiedInputLevel(); break; #ifndef NUCLEOTNC case POLL_BATTERY_LEVEL: - DEBUG("POLL_BATTERY_LEVEL"); + TNC_DEBUG("POLL_BATTERY_LEVEL"); pollBatteryLevel(); break; #endif case POLL_TWIST_LEVEL: - DEBUG("POLL_TWIST_LEVEL"); + TNC_DEBUG("POLL_TWIST_LEVEL"); pollInputTwist(); break; case STREAM_AVERAGE_TWIST_LEVEL: - DEBUG("STREAM_AVERAGE_TWIST_LEVEL"); + TNC_DEBUG("STREAM_AVERAGE_TWIST_LEVEL"); // streamAverageInputTwist(); break; case STREAM_INSTANT_TWIST_LEVEL: - DEBUG("STREAM_INSTANT_TWIST_LEVEL"); + TNC_DEBUG("STREAM_INSTANT_TWIST_LEVEL"); // streamInstantInputTwist(); break; case AUTO_ADJUST_INPUT_LEVEL: - DEBUG("AUTO_ADJUST_INPUT_LEVEL"); + TNC_DEBUG("AUTO_ADJUST_INPUT_LEVEL"); autoAudioInputLevel(); break; case CONFIGURE_INPUT_LEVELS: - DEBUG("CONFIGURE_INPUT_LEVELS"); + TNC_DEBUG("CONFIGURE_INPUT_LEVELS"); setAudioInputLevels(); break; case UPDATE_SETTINGS: - DEBUG("UPDATE_SETTINGS"); + TNC_DEBUG("UPDATE_SETTINGS"); setAudioInputLevels(); updateModulator(); break; @@ -190,7 +191,7 @@ IDemodulator* getDemodulator() void demodulatorTask() { - DEBUG("enter demodulatorTask"); + TNC_DEBUG("enter demodulatorTask"); bool dcd_status{false}; auto demodulator = getDemodulator(); @@ -206,6 +207,8 @@ void demodulatorTask() { continue; } + HAL_IWDG_Refresh(&hiwdg); + auto block = (adc_pool_type::chunk_type*) evt.value.p; auto samples = (int16_t*) block->buffer; @@ -235,7 +238,7 @@ void demodulatorTask() { demodulator->stop(); dcd_off(); - DEBUG("exit demodulatorTask"); + TNC_DEBUG("exit demodulatorTask"); } @@ -294,13 +297,13 @@ void streamLevels(uint8_t cmd) { } demodulator->stop(); - DEBUG("exit streamLevels"); + TNC_DEBUG("exit streamLevels"); } levels_type readLevels(uint32_t) { - DEBUG("enter readLevels"); + TNC_DEBUG("enter readLevels"); // Return Vpp, Vavg, Vmin, Vmax as four 16-bit values, right justified. @@ -382,7 +385,7 @@ float readTwist() */ void pollInputTwist() { - DEBUG("enter pollInputTwist"); + TNC_DEBUG("enter pollInputTwist"); float g1200 = 0.0f; float g2200 = 0.0f; @@ -421,7 +424,7 @@ void pollInputTwist() IDemodulator::stopADC(); - DEBUG("pollInputTwist: MARK=%d, SPACE=%d (x100)", + TNC_DEBUG("pollInputTwist: MARK=%d, SPACE=%d (x100)", int(g1200 * 100.0 / AVG_SAMPLES), int(g2200 * 100.0 / AVG_SAMPLES)); int16_t g1200i = int16_t(g1200 * 256 / AVG_SAMPLES); @@ -436,17 +439,17 @@ void pollInputTwist() ioport->write(buffer, 5, 6, 10); - DEBUG("exit pollInputTwist"); + TNC_DEBUG("exit pollInputTwist"); } void streamAmplifiedInputLevels() { - DEBUG("enter streamAmplifiedInputLevels"); + TNC_DEBUG("enter streamAmplifiedInputLevels"); streamLevels(kiss::hardware::POLL_INPUT_LEVEL); - DEBUG("exit streamAmplifiedInputLevels"); + TNC_DEBUG("exit streamAmplifiedInputLevels"); } void pollAmplifiedInputLevel() { - DEBUG("enter pollAmplifiedInputLevel"); + TNC_DEBUG("enter pollAmplifiedInputLevel"); uint16_t Vpp, Vavg, Vmin, Vmax; std::tie(Vpp, Vavg, Vmin, Vmax) = readLevels(AUDIO_IN); @@ -468,7 +471,7 @@ void pollAmplifiedInputLevel() { data[8] = (Vmax & 0xFF); ioport->write(data, 9, 6, 10); - DEBUG("exit pollAmplifiedInputLevel"); + TNC_DEBUG("exit pollAmplifiedInputLevel"); } #ifndef NUCLEOTNC @@ -493,7 +496,7 @@ void stop() { kiss::settings().input_offset += 6; setAudioInputLevels(); kiss::settings().input_offset -= 6; - DEBUG("Stop"); + TNC_DEBUG("Stop"); // __disable_irq(); vTaskSuspendAll(); SysTick->CTRL = 0; @@ -511,7 +514,7 @@ void stop() { xTaskResumeAll(); setAudioInputLevels(); // adcState = DEMODULATOR; - DEBUG("Wake"); + TNC_DEBUG("Wake"); } #endif diff --git a/TNC/AudioInput.hpp b/TNC/AudioInput.hpp index a070309..15d2903 100644 --- a/TNC/AudioInput.hpp +++ b/TNC/AudioInput.hpp @@ -29,10 +29,10 @@ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef*); * This is the long-running audio input task/thread. The ADC can be * connected to one of 2 inputs: * - * - AUDIO_IN, ADC1, CHANNEL_8 -- this is the input used by the demodulator. + * - AMPLIFIED_AUDIO_IN, ADC1_IN7 -- this is the input used by the demodulator. * - BATTERY_VOLTAGE -- this is 1/2 raw battery voltage (nominal 1.6-2.1V). * This input should not be enabled unless BAT_DIVIDER is enabled and - * pulled low. *** NOT USED on NucleoTNC *** + * pulled low. * * These inputs can be measured in a couple of different ways: * - Vavg -- for the average DC level of the signal diff --git a/TNC/AudioLevel.cpp b/TNC/AudioLevel.cpp index 5c8ad92..4985c55 100644 --- a/TNC/AudioLevel.cpp +++ b/TNC/AudioLevel.cpp @@ -27,7 +27,7 @@ extern DAC_HandleTypeDef hdac1; namespace mobilinkd { namespace tnc { namespace audio { -uint16_t virtual_ground{0}; +int16_t virtual_ground{0}; float i_vgnd{0.0f}; void set_input_gain(int level) diff --git a/TNC/AudioLevel.hpp b/TNC/AudioLevel.hpp index 6f7533d..17f832e 100644 --- a/TNC/AudioLevel.hpp +++ b/TNC/AudioLevel.hpp @@ -1,8 +1,7 @@ -// Copyright 2015 Rob Riggs +// Copyright 2015-2021 Rob Riggs // All rights reserved. -#ifndef MOBILINKD__TNC__AUDIO__AUDIO_LEVEL_H_ -#define MOBILINKD__TNC__AUDIO__AUDIO_LEVEL_H_ +#pragma once #include "arm_math.h" #include "cmsis_os.h" @@ -29,9 +28,7 @@ void setAudioOutputLevel(); extern bool streamInputDCOffset; constexpr const uint16_t vref = 4095; // Must match ADC output (adjust when oversampling) -extern uint16_t virtual_ground; +extern int16_t virtual_ground; extern float i_vgnd; }}} // mobilinkd::tnc::audio - -#endif // MOBILINKD__TNC__AUDIO__AUDIO_LEVEL_H_ diff --git a/TNC/Encoder.h b/TNC/Encoder.h index d78a0d6..396275f 100644 --- a/TNC/Encoder.h +++ b/TNC/Encoder.h @@ -1,8 +1,10 @@ -// Copyright 2015-2020 Mobilinkd LLC +// Copyright 2015-2021 Mobilinkd LLC // All rights reserved. #pragma once +#include "HdlcFrame.hpp" + namespace mobilinkd { @@ -24,6 +26,7 @@ struct Encoder virtual void updateModulator() = 0; virtual void stop() = 0; virtual EncoderType encoder_type() const = 0; + virtual tnc::hdlc::IoFrame* create_bert_frame() { return nullptr; }; }; } // mobilinkd diff --git a/TNC/Fsk9600Demodulator.cpp b/TNC/Fsk9600Demodulator.cpp index c6cd25e..7d36e55 100644 --- a/TNC/Fsk9600Demodulator.cpp +++ b/TNC/Fsk9600Demodulator.cpp @@ -69,7 +69,7 @@ hdlc::IoFrame* Fsk9600Demodulator::operator()(const q15_t* samples) */ float Fsk9600Demodulator::readTwist() { - DEBUG("enter Fsk9600Demodulator::readTwist"); + TNC_DEBUG("enter Fsk9600Demodulator::readTwist"); float g120 = 0.0f; float g4800 = 0.0f; @@ -117,14 +117,14 @@ float Fsk9600Demodulator::readTwist() INFO("9600 Twist = %d / 100 (%d - %d)", int(result * 100), int(g120 * 100), int(g4800 * 100)); - DEBUG("exit Fsk9600Demodulator::readTwist"); + TNC_DEBUG("exit Fsk9600Demodulator::readTwist"); return result; } uint32_t Fsk9600Demodulator::readBatteryLevel() { #ifndef NUCLEOTNC - DEBUG("enter Fsk9600Demodulator::readBatteryLevel"); + TNC_DEBUG("enter Fsk9600Demodulator::readBatteryLevel"); ADC_ChannelConfTypeDef sConfig; @@ -155,21 +155,21 @@ uint32_t Fsk9600Demodulator::readBatteryLevel() gpio::BAT_DIVIDER::off(); HAL_Delay(1); - sConfig.Channel = ADC_CHANNEL_15; - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) + sConfig.Channel = BATTERY_ADC_CHANNEL; + if (HAL_ADC_ConfigChannel(&BATTERY_ADC_HANDLE, &sConfig) != HAL_OK) CxxErrorHandler(); uint32_t vbat = 0; - if (HAL_ADC_Start(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_ADC_Start(&BATTERY_ADC_HANDLE) != HAL_OK) CxxErrorHandler(); for (size_t i = 0; i != 8; ++i) { - if (HAL_ADC_PollForConversion(&hadc1, 1) != HAL_OK) CxxErrorHandler(); - vbat += HAL_ADC_GetValue(&hadc1); + if (HAL_ADC_PollForConversion(&BATTERY_ADC_HANDLE, 1) != HAL_OK) CxxErrorHandler(); + vbat += HAL_ADC_GetValue(&BATTERY_ADC_HANDLE); } vbat /= 8; - if (HAL_ADC_Stop(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_ADC_Stop(&BATTERY_ADC_HANDLE) != HAL_OK) CxxErrorHandler(); if (HAL_TIM_Base_Stop(&htim6) != HAL_OK) CxxErrorHandler(); @@ -190,7 +190,7 @@ uint32_t Fsk9600Demodulator::readBatteryLevel() INFO("Vref = %lumV", vref) INFO("Vbat = %lumV", vbat); - DEBUG("exit Fsk9600Demodulator::readBatteryLevel"); + TNC_DEBUG("exit Fsk9600Demodulator::readBatteryLevel"); return vbat; #else return 0; diff --git a/TNC/Fsk9600Modulator.hpp b/TNC/Fsk9600Modulator.hpp index 26e03d2..59430ff 100644 --- a/TNC/Fsk9600Modulator.hpp +++ b/TNC/Fsk9600Modulator.hpp @@ -5,10 +5,14 @@ #include "Modulator.hpp" +#include "stm32l4xx_hal.h" + #include #include #include +extern IWDG_HandleTypeDef hiwdg; + namespace mobilinkd { namespace tnc { struct Scrambler @@ -86,7 +90,7 @@ struct Fsk9600Modulator : Modulator case State::STOPPING: case State::STOPPED: ptt_->on(); -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_DisableLSCO(); #endif @@ -104,6 +108,8 @@ struct Fsk9600Modulator : Modulator } } + void tone(uint16_t freq) override {} + // DAC DMA interrupt functions. void fill_first(uint8_t bit) override @@ -128,6 +134,8 @@ struct Fsk9600Modulator : Modulator void empty() { + HAL_IWDG_Refresh(&hiwdg); + switch (state) { case State::STARTING: @@ -140,7 +148,7 @@ struct Fsk9600Modulator : Modulator stop_conversion(); ptt_->off(); level = Level::HIGH; -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_EnableLSCO(RCC_LSCOSOURCE_LSE); #endif break; @@ -155,7 +163,7 @@ struct Fsk9600Modulator : Modulator stop_conversion(); ptt_->off(); level = Level::HIGH; -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_EnableLSCO(RCC_LSCOSOURCE_LSE); #endif // Drain the queue. @@ -204,6 +212,7 @@ private: void fill(uint16_t* buffer, bool bit) { + HAL_IWDG_Refresh(&hiwdg); switch (level) { case Level::HIGH: diff --git a/TNC/HdlcFrame.cpp b/TNC/HdlcFrame.cpp index 084aeee..c1c94c8 100644 --- a/TNC/HdlcFrame.cpp +++ b/TNC/HdlcFrame.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Mobilinkd LLC +// Copyright 2015-2021 Mobilinkd LLC // All rights reserved. #include "HdlcFrame.hpp" diff --git a/TNC/HdlcFrame.hpp b/TNC/HdlcFrame.hpp index 92ee303..e43569a 100644 --- a/TNC/HdlcFrame.hpp +++ b/TNC/HdlcFrame.hpp @@ -1,9 +1,7 @@ -// Copyright 2015-2019 Mobilinkd LLC +// Copyright 2015-2021 Mobilinkd LLC // All rights reserved. - -#ifndef MOBILINKD__HDLC_FRAME_HPP_ -#define MOBILINKD__HDLC_FRAME_HPP_ +#pragma once #ifndef EXCLUDE_CRC #include "stm32l4xx_hal.h" @@ -39,7 +37,7 @@ public: DATA = 0, TX_DELAY, P_PERSIST, SLOT_TIME, TX_TAIL, DUPLEX, HARDWARE, TEXT, LOG}; - enum Source { RF_DATA = 0x80 }; + enum Source { RF_DATA = 0x80, BERT = 0x30, STREAM = 0x20, PACKET = 0x10 }; private: data_type data_; @@ -70,7 +68,7 @@ private: checksum <<= 16; // Shift asm volatile("rbit %0, %0" : "+r" (checksum)); // Reverse uint16_t result = checksum & 0xFFFF; - DEBUG("CRC = %hx", result); + TNC_DEBUG("CRC = %hx", result); return result; } #else @@ -132,7 +130,7 @@ public: fcs_ = (*it); ++it; fcs_ |= (*it) << 8; - DEBUG("FCS = %hx", fcs_); + TNC_DEBUG("FCS = %hx", fcs_); crc_ = compute_crc(data_.begin()); complete_ = true; } @@ -207,5 +205,3 @@ IoFrame* acquire(void); IoFrame* acquire_wait(void); }}} // mobilinkd::tnc::hdlc - -#endif // MOBILINKD__HDLC_FRAME_HPP_ diff --git a/TNC/IOEventTask.cpp b/TNC/IOEventTask.cpp index 1828115..e48f9e1 100644 --- a/TNC/IOEventTask.cpp +++ b/TNC/IOEventTask.cpp @@ -76,7 +76,7 @@ void startIOEventTask(void const*) mobilinkd::tnc::audio::DEMODULATOR, osWaitForever); break; case CMD_USER_BUTTON_UP: - DEBUG("Button Up"); + TNC_DEBUG("Button Up"); break; case CMD_SET_PTT_SIMPLEX: getModulator().set_ptt(&simplexPtt); @@ -97,7 +97,7 @@ void startIOEventTask(void const*) if (frame->source() & IoFrame::RF_DATA) { - DEBUG("RF frame"); + TNC_DEBUG("RF frame"); frame->source(frame->source() & 0x70); if (!ioport->write(frame, frame->size() + 100)) { @@ -108,7 +108,7 @@ void startIOEventTask(void const*) } else { - DEBUG("Serial frame"); + TNC_DEBUG("Serial frame"); if ((frame->type() & 0x0F) == IoFrame::DATA) { kiss::getAFSKTestTone().stop(); diff --git a/TNC/IirFilter.hpp b/TNC/IirFilter.hpp index 84394ca..d441147 100644 --- a/TNC/IirFilter.hpp +++ b/TNC/IirFilter.hpp @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Rob Riggs +// Copyright 2015-2021 Rob Riggs // All rights reserved. #pragma once @@ -15,31 +15,32 @@ struct IirFilter { const std::array& numerator_; const std::array& denominator_; std::array history_; - size_t size_; IirFilter(const std::array& b, const std::array& a) : numerator_(b), denominator_(a) - , history_(), size_(N) + , history_() { history_.fill(0.0f); } ~IirFilter() {} + static constexpr size_t size() { return N; } + float operator()(float input) { - for(size_t i = size_ - 1; i != 0; i--) history_[i] = history_[i - 1]; + for (size_t i = N - 1; i != 0; i--) history_[i] = history_[i - 1]; history_[0] = input; - for (size_t i = 1; i != size_; i++) { + for (size_t i = 1; i != N; i++) { history_[0] -= denominator_[i] * history_[i]; } float result = 0; - for (size_t i = 0; i != size_; i++) { + for (size_t i = 0; i != N; i++) { result += numerator_[i] * history_[i]; } @@ -48,5 +49,3 @@ struct IirFilter { }; }} // mobilinkd::tnc - - diff --git a/TNC/Kiss.cpp b/TNC/Kiss.cpp index eb96cd6..56e88be 100644 --- a/TNC/Kiss.cpp +++ b/TNC/Kiss.cpp @@ -20,55 +20,55 @@ void handle_frame(uint8_t frame_type, hdlc::IoFrame* frame) { uint8_t value = *(frame->begin()); switch (frame_type) { case kiss::FRAME_DATA: - DEBUG("FRAME_DATA"); + TNC_DEBUG("FRAME_DATA"); // osMessagePut(hdlcOutputQueueHandle, (uint32_t) frame, 0); break; case kiss::FRAME_TX_DELAY: - DEBUG("FRAME_TX_DELAY"); + TNC_DEBUG("FRAME_TX_DELAY"); kiss::settings().txdelay = value; hdlc::release(frame); updateModulator(); break; case kiss::FRAME_P_PERSIST: - DEBUG("FRAME_P_PERSIST"); + TNC_DEBUG("FRAME_P_PERSIST"); kiss::settings().ppersist = value; hdlc::release(frame); updateModulator(); break; case kiss::FRAME_SLOT_TIME: - DEBUG("FRAME_SLOT_TIME"); + TNC_DEBUG("FRAME_SLOT_TIME"); kiss::settings().slot = value; hdlc::release(frame); updateModulator(); break; case kiss::FRAME_TX_TAIL: - DEBUG("FRAME_TX_TAIL"); + TNC_DEBUG("FRAME_TX_TAIL"); // Ignore. hdlc::release(frame); break; case kiss::FRAME_DUPLEX: - DEBUG("FRAME_DUPLEX"); + TNC_DEBUG("FRAME_DUPLEX"); kiss::settings().duplex = value; hdlc::release(frame); updateModulator(); break; case kiss::FRAME_HARDWARE: - DEBUG("FRAME_HARDWARE"); + TNC_DEBUG("FRAME_HARDWARE"); kiss::settings().handle_request(frame); hdlc::release(frame); break; case kiss::FRAME_LOG: - DEBUG("FRAME_LOG"); + TNC_DEBUG("FRAME_LOG"); hdlc::release(frame); // IGNORE break; case kiss::FRAME_RETURN: - DEBUG("FRAME_RETURN"); + TNC_DEBUG("FRAME_RETURN"); hdlc::release(frame); // Leave KISS mode break; default: - DEBUG("Unknown KISS frame type"); + TNC_DEBUG("Unknown KISS frame type"); hdlc::release(frame); } } diff --git a/TNC/KissHardware.cpp b/TNC/KissHardware.cpp index 3776ff1..bdcc88e 100644 --- a/TNC/KissHardware.cpp +++ b/TNC/KissHardware.cpp @@ -42,14 +42,16 @@ int powerOffViaUSB(void) namespace mobilinkd { namespace tnc { namespace kiss { -#ifdef NUCLEOTNC -const char FIRMWARE_VERSION[] = "2.3.0"; +#if defined(NUCLEOTNC) +const char FIRMWARE_VERSION[] = "2.3.2"; const char HARDWARE_VERSION[] = "Mobilinkd NucleoTNC"; -#else -const char FIRMWARE_VERSION[] = "2.3.0"; +#elif defined(STM32L433xx) +const char FIRMWARE_VERSION[] = "2.3.2"; const char HARDWARE_VERSION[] = "Mobilinkd TNC3 2.1.1"; +#elif defined(STM32L4P5xx) +const char FIRMWARE_VERSION[] = "2.3.2"; +const char HARDWARE_VERSION[] = "Mobilinkd TNC3+ Rev A"; #endif - Hardware& settings() { static Hardware instance __attribute__((section(".bss3"))); @@ -223,7 +225,7 @@ void Hardware::handle_request(hdlc::IoFrame* frame) reply8(hardware::SAVE_EEPROM_SETTINGS, hardware::OK); break; case hardware::POLL_INPUT_LEVEL: - DEBUG("POLL_INPUT_VOLUME"); + TNC_DEBUG("POLL_INPUT_VOLUME"); reply8(hardware::POLL_INPUT_LEVEL, 0); osMessagePut(audioInputQueueHandle, audio::POLL_AMPLIFIED_INPUT_LEVEL, osWaitForever); @@ -231,43 +233,43 @@ void Hardware::handle_request(hdlc::IoFrame* frame) osWaitForever); break; case hardware::STREAM_INPUT_LEVEL: - DEBUG("STREAM_INPUT_VOLUME"); + TNC_DEBUG("STREAM_INPUT_VOLUME"); osMessagePut(audioInputQueueHandle, audio::STREAM_AMPLIFIED_INPUT_LEVEL, osWaitForever); break; case hardware::GET_BATTERY_LEVEL: - DEBUG("GET_BATTERY_LEVEL"); + TNC_DEBUG("GET_BATTERY_LEVEL"); osMessagePut(audioInputQueueHandle, audio::POLL_BATTERY_LEVEL, osWaitForever); osMessagePut(audioInputQueueHandle, audio::DEMODULATOR, osWaitForever); break; case hardware::SEND_MARK: - DEBUG("SEND_MARK"); + TNC_DEBUG("SEND_MARK"); osMessagePut(audioInputQueueHandle, audio::IDLE, osWaitForever); getAFSKTestTone().mark(); break; case hardware::SEND_SPACE: - DEBUG("SEND_SPACE"); + TNC_DEBUG("SEND_SPACE"); osMessagePut(audioInputQueueHandle, audio::IDLE, osWaitForever); getAFSKTestTone().space(); break; case hardware::SEND_BOTH: - DEBUG("SEND_BOTH"); + TNC_DEBUG("SEND_BOTH"); osMessagePut(audioInputQueueHandle, audio::IDLE, osWaitForever); getAFSKTestTone().both(); break; case hardware::STOP_TX: - DEBUG("STOP_TX"); + TNC_DEBUG("STOP_TX"); getAFSKTestTone().stop(); osMessagePut(audioInputQueueHandle, audio::IDLE, osWaitForever); break; case hardware::RESET: - DEBUG("RESET"); + TNC_DEBUG("RESET"); osMessagePut(audioInputQueueHandle, audio::DEMODULATOR, osWaitForever); break; @@ -275,21 +277,21 @@ void Hardware::handle_request(hdlc::IoFrame* frame) output_gain = *it << 8; ++it; output_gain += *it; - DEBUG("SET_OUTPUT_GAIN = %hd", output_gain); + TNC_DEBUG("SET_OUTPUT_GAIN = %hd", output_gain); audio::setAudioOutputLevel(); update_crc(); [[fallthrough]]; case hardware::GET_OUTPUT_GAIN: - DEBUG("GET_OUTPUT_GAIN"); + TNC_DEBUG("GET_OUTPUT_GAIN"); reply16(hardware::GET_OUTPUT_GAIN, output_gain); break; case hardware::STREAM_DCD_VALUE: - DEBUG("STREAM_DCD_VALUE"); + TNC_DEBUG("STREAM_DCD_VALUE"); break; case hardware::POLL_INPUT_TWIST: - DEBUG("POLL_INPUT_TWIST"); + TNC_DEBUG("POLL_INPUT_TWIST"); osMessagePut(audioInputQueueHandle, audio::POLL_TWIST_LEVEL, osWaitForever); osMessagePut(audioInputQueueHandle, audio::DEMODULATOR, @@ -297,19 +299,19 @@ void Hardware::handle_request(hdlc::IoFrame* frame) break; case hardware::STREAM_AVG_INPUT_TWIST: - DEBUG("STREAM_AVG_INPUT_TWIST"); + TNC_DEBUG("STREAM_AVG_INPUT_TWIST"); osMessagePut(audioInputQueueHandle, audio::STREAM_AVERAGE_TWIST_LEVEL, osWaitForever); break; case hardware::STREAM_INPUT_TWIST: - DEBUG("STREAM_INPUT_TWIST"); + TNC_DEBUG("STREAM_INPUT_TWIST"); osMessagePut(audioInputQueueHandle, audio::STREAM_INSTANT_TWIST_LEVEL, osWaitForever); break; case hardware::ADJUST_INPUT_LEVELS: - DEBUG("ADJUST_INPUT_LEVELS"); + TNC_DEBUG("ADJUST_INPUT_LEVELS"); osMessagePut(audioInputQueueHandle, audio::AUTO_ADJUST_INPUT_LEVEL, osWaitForever); osMessagePut(audioInputQueueHandle, audio::STREAM_AMPLIFIED_INPUT_LEVEL, @@ -320,7 +322,7 @@ void Hardware::handle_request(hdlc::IoFrame* frame) input_gain = *it << 8; ++it; input_gain += *it; - DEBUG("SET_INPUT_GAIN = %d", input_gain); + TNC_DEBUG("SET_INPUT_GAIN = %d", input_gain); update_crc(); osMessagePut(audioInputQueueHandle, audio::UPDATE_SETTINGS, osWaitForever); @@ -328,12 +330,12 @@ void Hardware::handle_request(hdlc::IoFrame* frame) osWaitForever); [[fallthrough]]; case hardware::GET_INPUT_GAIN: - DEBUG("GET_INPUT_GAIN"); + TNC_DEBUG("GET_INPUT_GAIN"); reply16(hardware::GET_INPUT_GAIN, input_gain); break; case hardware::SET_INPUT_TWIST: - DEBUG("SET_INPUT_TWIST"); + TNC_DEBUG("SET_INPUT_TWIST"); rx_twist = *it; update_crc(); osMessagePut(audioInputQueueHandle, audio::UPDATE_SETTINGS, @@ -342,7 +344,7 @@ void Hardware::handle_request(hdlc::IoFrame* frame) osWaitForever); [[fallthrough]]; case hardware::GET_INPUT_TWIST: - DEBUG("GET_INPUT_TWIST"); + TNC_DEBUG("GET_INPUT_TWIST"); reply8(hardware::GET_INPUT_TWIST, rx_twist); break; @@ -350,65 +352,65 @@ void Hardware::handle_request(hdlc::IoFrame* frame) tx_twist = *it; if (tx_twist < 0) tx_twist = 0; if (tx_twist > 100) tx_twist = 100; - DEBUG("SET_OUTPUT_TWIST: %d", int(tx_twist)); + TNC_DEBUG("SET_OUTPUT_TWIST: %d", int(tx_twist)); getModulator().init(*this); update_crc(); [[fallthrough]]; case hardware::GET_OUTPUT_TWIST: - DEBUG("GET_OUTPUT_TWIST"); + TNC_DEBUG("GET_OUTPUT_TWIST"); reply8(hardware::GET_OUTPUT_TWIST, tx_twist); break; case hardware::STREAM_AMPLIFIED_INPUT: - DEBUG("STREAM_AMPLIFIED_INPUT"); + TNC_DEBUG("STREAM_AMPLIFIED_INPUT"); osMessagePut(audioInputQueueHandle, audio::STREAM_AMPLIFIED_INPUT_LEVEL, osWaitForever); break; case hardware::GET_TXDELAY: - DEBUG("GET_TXDELAY"); + TNC_DEBUG("GET_TXDELAY"); reply8(hardware::GET_TXDELAY, txdelay); break; case hardware::GET_PERSIST: - DEBUG("GET_PERSIST"); + TNC_DEBUG("GET_PERSIST"); reply8(hardware::GET_PERSIST, ppersist); break; case hardware::GET_TIMESLOT: - DEBUG("GET_TIMESLOT"); + TNC_DEBUG("GET_TIMESLOT"); reply8(hardware::GET_TIMESLOT, slot); break; case hardware::GET_TXTAIL: - DEBUG("GET_TXTAIL"); + TNC_DEBUG("GET_TXTAIL"); reply8(hardware::GET_TXTAIL, txtail); break; case hardware::GET_DUPLEX: - DEBUG("GET_DUPLEX"); + TNC_DEBUG("GET_DUPLEX"); reply8(hardware::GET_DUPLEX, duplex); break; case hardware::GET_FIRMWARE_VERSION: - DEBUG("GET_FIRMWARE_VERSION"); + TNC_DEBUG("GET_FIRMWARE_VERSION"); reply(hardware::GET_FIRMWARE_VERSION, (uint8_t*) FIRMWARE_VERSION, sizeof(FIRMWARE_VERSION) - 1); break; case hardware::GET_HARDWARE_VERSION: - DEBUG("GET_HARDWARE_VERSION"); + TNC_DEBUG("GET_HARDWARE_VERSION"); reply(hardware::GET_HARDWARE_VERSION, (uint8_t*) HARDWARE_VERSION, sizeof(HARDWARE_VERSION) - 1); break; case hardware::GET_SERIAL_NUMBER: - DEBUG("GET_SERIAL_NUMBER"); + TNC_DEBUG("GET_SERIAL_NUMBER"); reply(hardware::GET_SERIAL_NUMBER, (uint8_t*) serial_number_64, sizeof(serial_number_64) - 1); break; case hardware::SET_PTT_CHANNEL: - DEBUG("SET_PTT_CHANNEL"); + TNC_DEBUG("SET_PTT_CHANNEL"); if (*it) { options &= ~KISS_OPTION_PTT_SIMPLEX; osMessagePut(ioEventQueueHandle, CMD_SET_PTT_MULTIPLEX, osWaitForever); @@ -419,13 +421,13 @@ void Hardware::handle_request(hdlc::IoFrame* frame) update_crc(); break; case hardware::GET_PTT_CHANNEL: - DEBUG("GET_PTT_CHANNEL"); + TNC_DEBUG("GET_PTT_CHANNEL"); reply8(hardware::GET_PTT_CHANNEL, options & KISS_OPTION_PTT_SIMPLEX ? 0 : 1); break; case hardware::SET_PASSALL: - DEBUG("SET_PASSALL"); + TNC_DEBUG("SET_PASSALL"); if (*it) { options |= KISS_OPTION_PASSALL; } else { @@ -434,12 +436,12 @@ void Hardware::handle_request(hdlc::IoFrame* frame) update_crc(); [[fallthrough]]; case hardware::GET_PASSALL: - DEBUG("GET_PASSALL"); + TNC_DEBUG("GET_PASSALL"); reply8(hardware::GET_PASSALL, options & KISS_OPTION_PASSALL ? 1 : 0); break; case hardware::SET_RX_REV_POLARITY: - DEBUG("SET_RX_REV_POLARITY"); + TNC_DEBUG("SET_RX_REV_POLARITY"); if (*it) { options |= KISS_OPTION_RX_REV_POLARITY; } else { @@ -448,12 +450,12 @@ void Hardware::handle_request(hdlc::IoFrame* frame) update_crc(); [[fallthrough]]; case hardware::GET_RX_REV_POLARITY: - DEBUG("GET_RX_REV_POLARITY"); + TNC_DEBUG("GET_RX_REV_POLARITY"); reply8(hardware::GET_RX_REV_POLARITY, options & KISS_OPTION_RX_REV_POLARITY ? 1 : 0); break; case hardware::SET_TX_REV_POLARITY: - DEBUG("SET_TX_REV_POLARITY"); + TNC_DEBUG("SET_TX_REV_POLARITY"); if (*it) { options |= KISS_OPTION_TX_REV_POLARITY; } else { @@ -462,13 +464,13 @@ void Hardware::handle_request(hdlc::IoFrame* frame) update_crc(); [[fallthrough]]; case hardware::GET_TX_REV_POLARITY: - DEBUG("GET_TX_REV_POLARITY"); + TNC_DEBUG("GET_TX_REV_POLARITY"); reply8(hardware::GET_TX_REV_POLARITY, options & KISS_OPTION_TX_REV_POLARITY ? 1 : 0); break; #ifndef NUCLEOTNC case hardware::SET_USB_POWER_OFF: - DEBUG("SET_USB_POWER_OFF"); + TNC_DEBUG("SET_USB_POWER_OFF"); if (*it) { options |= KISS_OPTION_VIN_POWER_OFF; } else { @@ -477,13 +479,13 @@ void Hardware::handle_request(hdlc::IoFrame* frame) update_crc(); [[fallthrough]]; case hardware::GET_USB_POWER_OFF: - DEBUG("GET_USB_POWER_OFF"); + TNC_DEBUG("GET_USB_POWER_OFF"); reply8(hardware::GET_USB_POWER_OFF, options & KISS_OPTION_VIN_POWER_OFF ? 1 : 0); break; case hardware::SET_USB_POWER_ON: - DEBUG("SET_USB_POWER_ON"); + TNC_DEBUG("SET_USB_POWER_ON"); if (*it) { options |= KISS_OPTION_VIN_POWER_ON; } else { @@ -492,23 +494,23 @@ void Hardware::handle_request(hdlc::IoFrame* frame) update_crc(); [[fallthrough]]; case hardware::GET_USB_POWER_ON: - DEBUG("GET_USB_POWER_ON"); + TNC_DEBUG("GET_USB_POWER_ON"); reply8(hardware::GET_USB_POWER_ON, options & KISS_OPTION_VIN_POWER_ON ? 1 : 0); break; #endif case hardware::SET_DATETIME: - DEBUG("SET_DATETIME"); + TNC_DEBUG("SET_DATETIME"); set_rtc_datetime(static_cast(&*it)); [[fallthrough]]; case hardware::GET_DATETIME: - DEBUG("GET_DATETIME"); + TNC_DEBUG("GET_DATETIME"); reply(hardware::GET_DATETIME, get_rtc_datetime(), 7); break; case hardware::GET_CAPABILITIES: - DEBUG("GET_CAPABILITIES"); + TNC_DEBUG("GET_CAPABILITIES"); #ifndef NUCLEOTNC reply16(hardware::GET_CAPABILITIES, hardware::CAP_EEPROM_SAVE|hardware::CAP_BATTERY_LEVEL| @@ -522,7 +524,7 @@ void Hardware::handle_request(hdlc::IoFrame* frame) break; case hardware::GET_ALL_VALUES: - DEBUG("GET_ALL_VALUES"); + TNC_DEBUG("GET_ALL_VALUES"); // GET_API_VERSION must always come first. reply16(hardware::GET_API_VERSION, hardware::KISS_API_VERSION); #ifndef NUCLEOTNC @@ -597,13 +599,13 @@ void Hardware::handle_ext_request(hdlc::IoFrame* frame) { switch (ext_command) { case hardware::EXT_SET_MODEM_TYPE[1]: - DEBUG("SET_MODEM_TYPE"); + TNC_DEBUG("SET_MODEM_TYPE"); if ((*it == hardware::MODEM_TYPE_1200) or (*it == hardware::MODEM_TYPE_9600) or (*it == hardware::MODEM_TYPE_M17)) { modem_type = *it; - DEBUG(modem_type_lookup[modem_type]); + TNC_DEBUG(modem_type_lookup[modem_type]); update_crc(); } else @@ -615,11 +617,11 @@ void Hardware::handle_ext_request(hdlc::IoFrame* frame) { osWaitForever); [[fallthrough]]; case hardware::EXT_GET_MODEM_TYPE[1]: - DEBUG("EXT_GET_MODEM_TYPE"); + TNC_DEBUG("EXT_GET_MODEM_TYPE"); ext_reply(hardware::EXT_GET_MODEM_TYPE, modem_type); break; case hardware::EXT_GET_MODEM_TYPES[1]: - DEBUG("EXT_GET_MODEM_TYPES"); + TNC_DEBUG("EXT_GET_MODEM_TYPES"); ext_reply(hardware::EXT_GET_MODEM_TYPES, supported_modem_types); break; default: @@ -667,7 +669,7 @@ bool I2C_Storage::load(void* ptr, size_t len) { if (HAL_I2C_Init(&eeprom_i2c) != HAL_OK) CxxErrorHandler(); - DEBUG("Attempting to read %d bytes from EEPROM...", len); + TNC_DEBUG("Attempting to read %d bytes from EEPROM...", len); uint32_t timeout = 1000; // systicks... milliseconds diff --git a/TNC/KissHardware.hpp b/TNC/KissHardware.hpp index 22b2dbe..a998258 100644 --- a/TNC/KissHardware.hpp +++ b/TNC/KissHardware.hpp @@ -6,6 +6,7 @@ #include "Log.h" #include "HdlcFrame.hpp" #include "AFSKTestTone.hpp" +#include "main.h" #include #include @@ -329,44 +330,44 @@ struct Hardware memset(beacons, 0, sizeof(beacons)); update_crc(); - DEBUG("Settings initialized"); + TNC_DEBUG("Settings initialized"); } void debug() { #ifdef KISS_LOGGING - DEBUG("Hardware Settings (size=%d):", sizeof(Hardware)); - DEBUG("TX Delay: %d", (int)txdelay); - DEBUG("P* Persistence: %d", (int)ppersist); - DEBUG("Slot Time: %d", (int)slot); - DEBUG("TX Tail: %d", (int)txtail); - DEBUG("Duplex: %d", (int)duplex); - DEBUG("Modem Type: %s", modem_type_lookup[modem_type]); - DEBUG("TX Gain: %d", (int)output_gain); - DEBUG("RX Gain: %d", (int)input_gain); - DEBUG("TX Twist: %d", (int)tx_twist); - DEBUG("RX Twist: %d", (int)rx_twist); - DEBUG("Log Level: %d", (int)log_level); - DEBUG("Options: %04hx", options); - DEBUG("MYCALL: %s", mycall.data()); - DEBUG("Dedupe time (secs): %d", (int)dedupe_seconds); - DEBUG("Aliases:"); + TNC_DEBUG("Hardware Settings (size=%d):", sizeof(Hardware)); + TNC_DEBUG("TX Delay: %d", (int)txdelay); + TNC_DEBUG("P* Persistence: %d", (int)ppersist); + TNC_DEBUG("Slot Time: %d", (int)slot); + TNC_DEBUG("TX Tail: %d", (int)txtail); + TNC_DEBUG("Duplex: %d", (int)duplex); + TNC_DEBUG("Modem Type: %s", modem_type_lookup[modem_type]); + TNC_DEBUG("TX Gain: %d", (int)output_gain); + TNC_DEBUG("RX Gain: %d", (int)input_gain); + TNC_DEBUG("TX Twist: %d", (int)tx_twist); + TNC_DEBUG("RX Twist: %d", (int)rx_twist); + TNC_DEBUG("Log Level: %d", (int)log_level); + TNC_DEBUG("Options: %04hx", options); + TNC_DEBUG("MYCALL: %s", mycall.data()); + TNC_DEBUG("Dedupe time (secs): %d", (int)dedupe_seconds); + TNC_DEBUG("Aliases:"); for (auto& a : aliases) { if (!a.set) continue; - DEBUG(" call: %s", a.call.data()); - DEBUG(" use: %d", (int)a.use); - DEBUG(" insert: %d", (int)a.insert_id); - DEBUG(" preempt: %d", (int)a.preempt); - DEBUG(" hops: %d", (int)a.hops); + TNC_DEBUG(" call: %s", a.call.data()); + TNC_DEBUG(" use: %d", (int)a.use); + TNC_DEBUG(" insert: %d", (int)a.insert_id); + TNC_DEBUG(" preempt: %d", (int)a.preempt); + TNC_DEBUG(" hops: %d", (int)a.hops); } - DEBUG("Beacons:"); + TNC_DEBUG("Beacons:"); for (auto& b : this->beacons) { if (b.seconds == 0) continue; - DEBUG(" dest: %s", b.dest.data()); - DEBUG(" path: %s", (char*)b.path); - DEBUG(" text: %s", (char*)b.text); - DEBUG(" frequency (secs): %d", (int)b.seconds); + TNC_DEBUG(" dest: %s", b.dest.data()); + TNC_DEBUG(" path: %s", (char*)b.path); + TNC_DEBUG(" text: %s", (char*)b.text); + TNC_DEBUG(" frequency (secs): %d", (int)b.seconds); } - DEBUG("Checksum: %04hx", checksum); + TNC_DEBUG("Checksum: %04hx", checksum); #endif } diff --git a/TNC/LEDIndicator.cpp b/TNC/LEDIndicator.cpp index 94a06a5..719afaa 100644 --- a/TNC/LEDIndicator.cpp +++ b/TNC/LEDIndicator.cpp @@ -14,7 +14,7 @@ #include -extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef LED_PWM_TIMER_HANDLE; namespace mobilinkd { namespace tnc { @@ -421,7 +421,7 @@ struct Flash if (counter == 0) { state = STATE::OFF; - HAL_TIM_PWM_Stop(&htim1, channel); + HAL_TIM_PWM_Stop(&LED_PWM_TIMER_HANDLE, channel); } else { @@ -451,7 +451,7 @@ struct Flash auto expected = STATE::OFF; if (gr_state.compare_exchange_strong(expected, STATE::RAMP_UP)) { - HAL_TIM_PWM_Start(&htim1, GREEN_CHANNEL); + HAL_TIM_PWM_Start(&LED_PWM_TIMER_HANDLE, GREEN_CHANNEL); } else { @@ -473,7 +473,7 @@ struct Flash if (rd_state.compare_exchange_strong(expected, STATE::RAMP_UP)) { // PWM Channel must match - HAL_TIM_PWM_Start(&htim1, RED_CHANNEL); + HAL_TIM_PWM_Start(&LED_PWM_TIMER_HANDLE, RED_CHANNEL); } else { @@ -492,19 +492,19 @@ struct Flash void disconnect() { blue_func = noConnection; - HAL_TIM_PWM_Start(&htim1, BLUE_CHANNEL); + HAL_TIM_PWM_Start(&LED_PWM_TIMER_HANDLE, BLUE_CHANNEL); } void usb() { blue_func = usbConnection; - HAL_TIM_PWM_Start(&htim1, BLUE_CHANNEL); + HAL_TIM_PWM_Start(&LED_PWM_TIMER_HANDLE, BLUE_CHANNEL); } void bt() { blue_func = btConnection; - HAL_TIM_PWM_Start(&htim1, BLUE_CHANNEL); + HAL_TIM_PWM_Start(&LED_PWM_TIMER_HANDLE, BLUE_CHANNEL); } }; @@ -518,25 +518,25 @@ Flash& flash() } } // mobilinkd::tnc -void HTIM1_PeriodElapsedCallback() +void LED_TIMER_PeriodElapsedCallback() { using mobilinkd::tnc::flash; // CCR registers must match the TIM_CHANNEL used for each LED in Flash. #ifndef NUCLEOTNC - htim1.Instance->CCR1 = flash().blue(); - htim1.Instance->CCR2 = flash().green(); - htim1.Instance->CCR3 = flash().red(); + LED_PWM_TIMER_HANDLE.Instance->CCR1 = flash().blue(); + LED_PWM_TIMER_HANDLE.Instance->CCR2 = flash().green(); + LED_PWM_TIMER_HANDLE.Instance->CCR3 = flash().red(); #else - htim1.Instance->CCR1 = flash().red(); - htim1.Instance->CCR2 = flash().green(); - htim1.Instance->CCR3 = flash().blue(); // YELLOW + LED_PWM_TIMER_HANDLE.Instance->CCR1 = flash().red(); + LED_PWM_TIMER_HANDLE.Instance->CCR2 = flash().green(); + LED_PWM_TIMER_HANDLE.Instance->CCR3 = flash().blue(); // YELLOW #endif } void indicate_turning_on(void) { - HAL_TIM_Base_Start_IT(&htim1); + HAL_TIM_Base_Start_IT(&LED_PWM_TIMER_HANDLE); tx_on(); rx_on(); } diff --git a/TNC/LEDIndicator.h b/TNC/LEDIndicator.h index d94b768..624c917 100644 --- a/TNC/LEDIndicator.h +++ b/TNC/LEDIndicator.h @@ -19,7 +19,7 @@ void tx_off(void); void rx_on(void); void rx_off(void); -void HTIM1_PeriodElapsedCallback(void); +void LED_TIMER_PeriodElapsedCallback(void); #ifdef __cplusplus } diff --git a/TNC/Log.h b/TNC/Log.h index 85e8ca2..12dcb6b 100644 --- a/TNC/Log.h +++ b/TNC/Log.h @@ -28,14 +28,12 @@ void log_(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3))) #define LOG(level, ...) if(level >= KISS_LOG_LEVEL) log_(level, __VA_ARGS__); -#define DEBUG(...) LOG(0, __VA_ARGS__) #define TNC_DEBUG(...) LOG(0, __VA_ARGS__) #define INFO(...) LOG(1, __VA_ARGS__) #define WARN(...) LOG(2, __VA_ARGS__) #define ERROR(...) LOG(3, __VA_ARGS__) #define SEVERE(...) LOG(4, __VA_ARGS__) #else -#define DEBUG(...) #define TNC_DEBUG(...) #define INFO(...) #define WARN(...) diff --git a/TNC/M17.h b/TNC/M17.h index ae8450a..a903a29 100644 --- a/TNC/M17.h +++ b/TNC/M17.h @@ -27,6 +27,7 @@ extern const std::array rrc_taps_f15; constexpr std::array LSF_SYNC = { 0x55, 0xF7 }; constexpr std::array STREAM_SYNC = { 0xFF, 0x5D }; constexpr std::array PACKET_SYNC = { 0x75, 0xFF }; +constexpr std::array BERT_SYNC = { 0xDF, 0x55 }; inline constexpr uint16_t sync_word(std::array sw) { diff --git a/TNC/M17Demodulator.cpp b/TNC/M17Demodulator.cpp index 2a3b21c..c60f86f 100644 --- a/TNC/M17Demodulator.cpp +++ b/TNC/M17Demodulator.cpp @@ -16,13 +16,15 @@ namespace mobilinkd { namespace tnc { //m17::Indicator lsf_indicator{GPIOB, GPIO_PIN_0}; -//m17::Indicator dcd_indicator{GPIOA, GPIO_PIN_7}; -//m17::Indicator str_indicator{GPIOA, GPIO_PIN_2}; +//m17::Indicator dcd_indicator{GPIOA, GPIO_PIN_2}; +//m17::Indicator str_indicator{GPIOA, GPIO_PIN_7}; void M17Demodulator::start() { SysClock72(); +#if defined(HAVE_LSCO) HAL_RCCEx_DisableLSCO(); +#endif demod_filter.init(m17::rrc_taps_f15); passall(kiss::settings().options & KISS_OPTION_PASSALL); @@ -53,31 +55,31 @@ void M17Demodulator::start() void M17Demodulator::update_values(uint8_t index) { - correlator.apply([this,index](float t){dev.sample(t);}, index); - dev.update(); - idev = dev.idev() * polarity; - sync_sample_index = index; + correlator.apply([this,index](float t){dev.sample(t);}, index); + dev.update(); + idev = dev.idev() * polarity; + sync_sample_index = index; } void M17Demodulator::dcd_on() { - // Data carrier newly detected. - INFO("dcd = %d", int(dcd.level() * 100)); - dcd_ = true; - sync_count = 0; - dev.reset(); + // Data carrier newly detected. + INFO("dcd = %d", int(dcd.level() * 100)); + dcd_ = true; + sync_count = 0; + dev.reset(); framer.reset(); decoder.reset(); - missing_sync_count = 0; + missing_sync_count = 0; // dcd_indicator.off(); } void M17Demodulator::dcd_off() { - // Just lost data carrier. - INFO("dcd = %d", int(dcd.level() * 100)); - dcd_ = false; - demodState = DemodState::UNLOCKED; + // Just lost data carrier. + INFO("dcd = %d", int(dcd.level() * 100)); + dcd_ = false; + demodState = DemodState::UNLOCKED; // dcd_indicator.on(); adc_timing_adjust = 0; prev_clock_estimate = 1.; @@ -95,8 +97,8 @@ void M17Demodulator::initialize(const q15_t* input) auto filtered = demod_filter(demod_buffer.data()); for (size_t i = 0; i != ADC_BLOCK_SIZE; ++i) { - auto filtered_sample = filtered[i]; - correlator.sample(filtered_sample); + auto filtered_sample = filtered[i]; + correlator.sample(filtered_sample); } } @@ -106,66 +108,79 @@ void M17Demodulator::update_dcd(const q15_t* input) if (!dcd_ && dcd.dcd()) { - dcd_on(); - need_clock_reset_ = true; + dcd_on(); + need_clock_reset_ = true; } else if (dcd_ && !dcd.dcd()) { - dcd_off(); + dcd_off(); } for (size_t i = 0; i != ADC_BLOCK_SIZE; ++i) { - dcd(input[i] * inv); + dcd(input[i] * inv); } } [[gnu::noinline]] void M17Demodulator::do_unlocked() { - // We expect to find the preamble immediately after DCD. + // We expect to find the preamble immediately after DCD. if (missing_sync_count < 1920) - { - missing_sync_count += 1; - auto sync_index = preamble_sync(correlator); - auto sync_updated = preamble_sync.updated(); - if (sync_updated) - { - sync_count = 0; - missing_sync_count = 0; - need_clock_reset_ = true; - dev.reset(); - update_values(sync_index); - sample_index = sync_index; - demodState = DemodState::LSF_SYNC; - INFO("P sync %d", sync_index); - } - } - else // Otherwise we start searching for a sync word. - { - auto sync_index = lsf_sync(correlator); - auto sync_updated = lsf_sync.updated(); - if (sync_updated) - { - sync_count = 0; - missing_sync_count = 0; - need_clock_reset_ = true; - dev.reset(); - update_values(sync_index); - sample_index = sync_index; - demodState = DemodState::FRAME; - if (sync_updated < 0) - { - sync_word_type = M17FrameDecoder::SyncWordType::STREAM; - INFO("S sync %d", int(sync_index)); - } - else - { - sync_word_type = M17FrameDecoder::SyncWordType::LSF; - INFO("L sync %d", int(sync_index)); - } - } - } + { + missing_sync_count += 1; + auto sync_index = preamble_sync(correlator); + auto sync_updated = preamble_sync.updated(); + if (sync_updated) + { + sync_count = 0; + missing_sync_count = 0; + need_clock_reset_ = true; + dev.reset(); + update_values(sync_index); + sample_index = sync_index; + demodState = DemodState::LSF_SYNC; + INFO("P sync %d", sync_index); + } + return; + } + // Otherwise we start searching for a sync word. + auto sync_index = lsf_sync(correlator); + auto sync_updated = lsf_sync.updated(); + if (sync_updated) + { + sync_count = 0; + missing_sync_count = 0; + need_clock_reset_ = true; + dev.reset(); + update_values(sync_index); + sample_index = sync_index; + demodState = DemodState::FRAME; + if (sync_updated < 0) + { + sync_word_type = M17FrameDecoder::SyncWordType::STREAM; + INFO("S sync %d", int(sync_index)); + } + else + { + sync_word_type = M17FrameDecoder::SyncWordType::LSF; + INFO("L sync %d", int(sync_index)); + } + } + sync_index = packet_sync(correlator); + sync_updated = packet_sync.updated(); + if (sync_updated < 0) + { + sync_count = 0; + missing_sync_count = 0; + need_clock_reset_ = true; + dev.reset(); + update_values(sync_index); + sample_index = sync_index; + demodState = DemodState::FRAME; + sync_word_type = M17FrameDecoder::SyncWordType::BERT; + INFO("B sync %d", int(sync_index)); + } } /** @@ -176,48 +191,59 @@ void M17Demodulator::do_unlocked() [[gnu::noinline]] void M17Demodulator::do_lsf_sync() { - float sync_triggered = 0.; + float sync_triggered = 0.; + float bert_triggered = 0.; - if (correlator.index() == sample_index) - { - sync_triggered = preamble_sync.triggered(correlator); + if (correlator.index() == sample_index) + { + sync_triggered = preamble_sync.triggered(correlator); // INFO("PSync = %d", int(sync_triggered)); - if (sync_triggered > 0.1) - { - ITM_SendChar('.'); - return; - } - sync_triggered = lsf_sync.triggered(correlator); - if (std::abs(sync_triggered) > 0.1) - { - missing_sync_count = 0; - need_clock_update_ = true; - update_values(sample_index); - INFO("LSync = %d", int(sync_triggered)); - if (sync_triggered > 0) - { - demodState = DemodState::FRAME; - sync_word_type = M17FrameDecoder::SyncWordType::LSF; - INFO("+l sync %d", int(sample_index)); - } - else - { - demodState = DemodState::FRAME; - sync_word_type = M17FrameDecoder::SyncWordType::STREAM; - INFO("+s sync %d", int(sample_index)); - } - } - else if (++missing_sync_count > 192) - { - demodState = DemodState::UNLOCKED; - INFO("l unlock %d", int(missing_sync_count)); - missing_sync_count = 0; - } - else - { - update_values(sample_index); - } - } + if (sync_triggered > 0.1) + { + ITM_SendChar('.'); + return; + } + sync_triggered = lsf_sync.triggered(correlator); + bert_triggered = packet_sync.triggered(correlator); + if (bert_triggered < 0) + { + missing_sync_count = 0; + need_clock_update_ = true; + update_values(sample_index); + demodState = DemodState::FRAME; + sync_word_type = M17FrameDecoder::SyncWordType::BERT; + INFO("+b sync"); + } + else if (std::abs(sync_triggered) > 0.1) + { + missing_sync_count = 0; + need_clock_update_ = true; + update_values(sample_index); + INFO("LSync = %d", int(sync_triggered)); + if (sync_triggered > 0) + { + demodState = DemodState::FRAME; + sync_word_type = M17FrameDecoder::SyncWordType::LSF; + INFO("+l sync %d", int(sample_index)); + } + else + { + demodState = DemodState::FRAME; + sync_word_type = M17FrameDecoder::SyncWordType::STREAM; + INFO("+s sync %d", int(sample_index)); + } + } + else if (++missing_sync_count > 192) + { + demodState = DemodState::UNLOCKED; + INFO("l unlock %d", int(missing_sync_count)); + missing_sync_count = 0; + } + else + { + update_values(sample_index); + } + } } /** @@ -229,43 +255,36 @@ void M17Demodulator::do_lsf_sync() [[gnu::noinline]] void M17Demodulator::do_stream_sync() { - uint8_t sync_index = lsf_sync(correlator); - int8_t sync_updated = lsf_sync.updated(); - sync_count += 1; - if (sync_updated < 0) - { - missing_sync_count = 0; - if (sync_count <= 70) - { - update_values(sync_index); - sync_word_type = M17FrameDecoder::SyncWordType::STREAM; - demodState = DemodState::FRAME; - INFO("s early"); - } - else if (sync_count > 70) - { - update_values(sync_index); - sync_word_type = M17FrameDecoder::SyncWordType::STREAM; - demodState = DemodState::FRAME; - INFO("s sync %d", int(sync_index)); - } - return; - } + uint8_t sync_index = lsf_sync(correlator); + int8_t sync_updated = lsf_sync.updated(); + sync_count += 1; + if (sync_updated < 0) + { + missing_sync_count = 0; + if (sync_count > 70) + { + update_values(sync_index); + sync_word_type = M17FrameDecoder::SyncWordType::STREAM; + demodState = DemodState::FRAME; + INFO("s sync %d", int(sync_index)); + } + return; + } else if (sync_count > 87) { - update_values(sync_index); - missing_sync_count += 1; - if (missing_sync_count < MAX_MISSING_SYNC) - { - sync_word_type = M17FrameDecoder::SyncWordType::STREAM; - demodState = DemodState::FRAME; - INFO("s unsync %d", int(missing_sync_count)); - } - else - { - demodState = DemodState::LSF_SYNC; - INFO("s unlock"); - } + update_values(sync_index); + missing_sync_count += 1; + if (missing_sync_count < MAX_MISSING_SYNC) + { + sync_word_type = M17FrameDecoder::SyncWordType::STREAM; + demodState = DemodState::FRAME; + INFO("s unsync %d", int(missing_sync_count)); + } + else + { + demodState = DemodState::LSF_SYNC; + INFO("s unlock"); + } } } @@ -276,100 +295,137 @@ void M17Demodulator::do_stream_sync() [[gnu::noinline]] void M17Demodulator::do_packet_sync() { - auto sync_index = packet_sync(correlator); - auto sync_updated = packet_sync.updated(); - sync_count += 1; - if (sync_count > 70 && sync_updated) - { - missing_sync_count = 0; - update_values(sync_index); - sync_word_type = M17FrameDecoder::SyncWordType::PACKET; - demodState = DemodState::FRAME; - INFO("k sync"); - return; - } - else if (sync_count > 87) - { - missing_sync_count += 1; - if (missing_sync_count < MAX_MISSING_SYNC) - { - sync_word_type = M17FrameDecoder::SyncWordType::PACKET; - demodState = DemodState::FRAME; - INFO("k unsync"); - } - else - { - demodState = DemodState::UNLOCKED; - INFO("k unlock"); - } - } + auto sync_index = packet_sync(correlator); + auto sync_updated = packet_sync.updated(); + sync_count += 1; + if (sync_count > 70 && sync_updated) + { + missing_sync_count = 0; + update_values(sync_index); + sync_word_type = M17FrameDecoder::SyncWordType::PACKET; + demodState = DemodState::FRAME; + INFO("k sync"); + return; + } + else if (sync_count > 87) + { + missing_sync_count += 1; + if (missing_sync_count < MAX_MISSING_SYNC) + { + sync_word_type = M17FrameDecoder::SyncWordType::PACKET; + demodState = DemodState::FRAME; + INFO("k unsync"); + } + else + { + demodState = DemodState::UNLOCKED; + INFO("k unlock"); + } + } +} + +/** + * Check for a bert sync word. + */ +[[gnu::noinline]] +void M17Demodulator::do_bert_sync() +{ + auto sync_index = packet_sync(correlator); + auto sync_updated = packet_sync.updated(); + sync_count += 1; + if (sync_count > 70 && sync_updated < 0) + { + missing_sync_count = 0; + update_values(sync_index); + sync_word_type = M17FrameDecoder::SyncWordType::BERT; + INFO("b sync"); + demodState = DemodState::FRAME; + } + else if (sync_count > 87) + { + missing_sync_count += 1; + if (missing_sync_count < MAX_MISSING_SYNC) + { + sync_word_type = M17FrameDecoder::SyncWordType::BERT; + demodState = DemodState::FRAME; + INFO("b unsync"); + } + else + { + demodState = DemodState::UNLOCKED; + INFO("b unlock"); + } + } } [[gnu::noinline]] void M17Demodulator::do_frame(float filtered_sample, hdlc::IoFrame*& frame_result) { - if (correlator.index() != sample_index) return; + if (correlator.index() != sample_index) return; - float sample = filtered_sample - dev.offset(); - sample *= idev; + float sample = filtered_sample - dev.offset(); + sample *= idev; - auto n = mobilinkd::llr(sample); - int8_t* tmp; - auto len = framer(n, &tmp); - if (len != 0) - { - need_clock_update_ = true; + auto n = mobilinkd::llr(sample); + int8_t* tmp; + auto len = framer(n, &tmp); + if (len != 0) + { + need_clock_update_ = true; - std::copy(tmp, tmp + len, buffer.begin()); - auto valid = decoder(sync_word_type, buffer, frame_result, ber); - INFO("demod: %d, dt: %7d, evma: %5d, dev: %5d, freq: %5d, index: %d, %d, %d ber: %d", - int(decoder.state()), int(clock_recovery.clock_estimate() * 1000000), - int(dev.error() * 1000), int(dev.deviation() * 1000), - int(dev.offset() * 1000), - int(sample_index), int(clock_recovery.sample_index()), int(sync_sample_index), - ber); + std::copy(tmp, tmp + len, buffer.begin()); + auto valid = decoder(sync_word_type, buffer, frame_result, ber); + INFO("demod: %d, dt: %7d, evma: %5d, dev: %5d, freq: %5d, index: %d, %d, %d ber: %d", + int(decoder.state()), int(clock_recovery.clock_estimate() * 1000000), + int(dev.error() * 1000), int(dev.deviation() * 1000), + int(dev.offset() * 1000), + int(sample_index), int(clock_recovery.sample_index()), int(sync_sample_index), + ber); - switch (decoder.state()) - { - case M17FrameDecoder::State::STREAM: - demodState = DemodState::STREAM_SYNC; - break; - case M17FrameDecoder::State::LSF: - // If state == LSF, we need to recover LSF from LICH. - demodState = DemodState::STREAM_SYNC; - break; - default: - demodState = DemodState::PACKET_SYNC; - break; - } + switch (decoder.state()) + { + case M17FrameDecoder::State::STREAM: + demodState = DemodState::STREAM_SYNC; + break; + case M17FrameDecoder::State::LSF: + // If state == LSF, we need to recover LSF from LICH. + demodState = DemodState::STREAM_SYNC; + break; + case M17FrameDecoder::State::BERT: + demodState = DemodState::BERT_SYNC; + break; + default: + demodState = DemodState::PACKET_SYNC; + break; + } - sync_count = 0; + sync_count = 0; - switch (valid) - { - case M17FrameDecoder::DecodeResult::FAIL: - WARN("decode invalid"); - if (frame_result && !passall_) - { - hdlc::release(frame_result); - frame_result = nullptr; - } - break; - case M17FrameDecoder::DecodeResult::EOS: - demodState = DemodState::LSF_SYNC; - INFO("EOS"); - break; - case M17FrameDecoder::DecodeResult::OK: - break; - case M17FrameDecoder::DecodeResult::INCOMPLETE: - break; - } - } + switch (valid) + { + case M17FrameDecoder::DecodeResult::FAIL: + WARN("decode invalid"); + if (frame_result && !passall_) + { + hdlc::release(frame_result); + frame_result = nullptr; + } + break; + case M17FrameDecoder::DecodeResult::EOS: + demodState = DemodState::LSF_SYNC; + INFO("EOS"); + break; + case M17FrameDecoder::DecodeResult::OK: + break; + case M17FrameDecoder::DecodeResult::INCOMPLETE: + break; + } + } } hdlc::IoFrame* M17Demodulator::operator()(const q15_t* input) { - static int16_t initializing = 10; + static int16_t initializing = 10; hdlc::IoFrame* frame_result = nullptr; @@ -377,12 +433,12 @@ hdlc::IoFrame* M17Demodulator::operator()(const q15_t* input) // the demodulator. if (__builtin_expect((initializing), 0)) { - --initializing; - initialize(input); - return frame_result; + --initializing; + initialize(input); + return frame_result; } -// str_indicator.on(); +// str_indicator.on(); update_dcd(input); if (!dcd_) @@ -411,55 +467,58 @@ hdlc::IoFrame* M17Demodulator::operator()(const q15_t* input) if (correlator.index() == 0) { - if (need_clock_reset_) - { - clock_recovery.reset(); - need_clock_reset_ = false; - sample_index = sync_sample_index; - adc_timing_adjust = 0; - } - else if (need_clock_update_) // must avoid update immediately after reset. - { - clock_recovery.update(); - uint8_t clock_index = clock_recovery.sample_index(); - uint8_t clock_diff = std::abs(sample_index - clock_index); - uint8_t sync_diff = std::abs(sample_index - sync_sample_index); - bool clock_diff_ok = clock_diff <= 1 || clock_diff == 9; - bool sync_diff_ok = sync_diff <= 1 || sync_diff == 9; - if (clock_diff_ok) sample_index = clock_index; - else if (sync_diff_ok) sample_index = sync_sample_index; - // else unchanged. - need_clock_update_ = false; - } + if (need_clock_reset_) + { + clock_recovery.reset(); + need_clock_reset_ = false; + sample_index = sync_sample_index; + adc_timing_adjust = 0; + } + else if (need_clock_update_) // must avoid update immediately after reset. + { + clock_recovery.update(); + uint8_t clock_index = clock_recovery.sample_index(); + uint8_t clock_diff = std::abs(sample_index - clock_index); + uint8_t sync_diff = std::abs(sample_index - sync_sample_index); + bool clock_diff_ok = clock_diff <= 1 || clock_diff == 9; + bool sync_diff_ok = sync_diff <= 1 || sync_diff == 9; + if (clock_diff_ok) sample_index = clock_index; + else if (sync_diff_ok) sample_index = sync_sample_index; + // else unchanged. + need_clock_update_ = false; + } } - clock_recovery(filtered_sample); + clock_recovery(filtered_sample); - if (demodState != DemodState::UNLOCKED && correlator.index() == sample_index) - { - dev.sample(filtered_sample); - } + if (demodState != DemodState::UNLOCKED && correlator.index() == sample_index) + { + dev.sample(filtered_sample); + } switch (demodState) { case DemodState::UNLOCKED: - // In this state, the sample_index is unknown. We need to find - // a sync word to find the proper sample_index. We only leave - // this state if we believe that we have a valid sample_index. - do_unlocked(); - break; + // In this state, the sample_index is unknown. We need to find + // a sync word to find the proper sample_index. We only leave + // this state if we believe that we have a valid sample_index. + do_unlocked(); + break; case DemodState::LSF_SYNC: - do_lsf_sync(); + do_lsf_sync(); break; case DemodState::STREAM_SYNC: - do_stream_sync(); + do_stream_sync(); break; case DemodState::PACKET_SYNC: - do_packet_sync(); - break; + do_packet_sync(); + break; + case DemodState::BERT_SYNC: + do_bert_sync(); + break; case DemodState::FRAME: - do_frame(filtered_sample,frame_result); - break; + do_frame(filtered_sample,frame_result); + break; } } dcd.update(); diff --git a/TNC/M17Demodulator.h b/TNC/M17Demodulator.h index 70a6800..41d614c 100644 --- a/TNC/M17Demodulator.h +++ b/TNC/M17Demodulator.h @@ -49,7 +49,7 @@ struct M17Demodulator : IDemodulator using audio_filter_t = FirFilter; using sync_word_t = m17::SyncWord; - enum class DemodState { UNLOCKED, LSF_SYNC, STREAM_SYNC, PACKET_SYNC, FRAME }; + enum class DemodState { UNLOCKED, LSF_SYNC, STREAM_SYNC, PACKET_SYNC, BERT_SYNC, FRAME }; audio_filter_t demod_filter; std::array demod_buffer; @@ -59,7 +59,7 @@ struct M17Demodulator : IDemodulator m17::Correlator correlator; sync_word_t preamble_sync{{+3,-3,+3,-3,+3,-3,+3,-3}, 29.f}; sync_word_t lsf_sync{{+3,+3,+3,+3,-3,-3,+3,-3}, 31.f, -31.f}; - sync_word_t packet_sync{{3,-3,3,3,-3,-3,-3,-3}, 32.f}; + sync_word_t packet_sync{{3,-3,3,3,-3,-3,-3,-3}, 31.f, -31.f}; m17::FreqDevEstimator dev; @@ -97,6 +97,7 @@ struct M17Demodulator : IDemodulator void do_lsf_sync(); void do_packet_sync(); void do_stream_sync(); + void do_bert_sync(); void do_frame(float filtered_sample, hdlc::IoFrame*& frame_result); void stop() override @@ -139,7 +140,7 @@ struct M17Demodulator : IDemodulator uint32_t readBatteryLevel() override { #ifndef NUCLEOTNC - DEBUG("enter M17Demodulator::readBatteryLevel"); + TNC_DEBUG("enter M17Demodulator::readBatteryLevel"); ADC_ChannelConfTypeDef sConfig; @@ -170,21 +171,21 @@ struct M17Demodulator : IDemodulator gpio::BAT_DIVIDER::off(); HAL_Delay(1); - sConfig.Channel = ADC_CHANNEL_15; - if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) + sConfig.Channel = BATTERY_ADC_CHANNEL; + if (HAL_ADC_ConfigChannel(&BATTERY_ADC_HANDLE, &sConfig) != HAL_OK) CxxErrorHandler(); uint32_t vbat = 0; - if (HAL_ADC_Start(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_ADC_Start(&BATTERY_ADC_HANDLE) != HAL_OK) CxxErrorHandler(); for (size_t i = 0; i != 8; ++i) { - if (HAL_ADC_PollForConversion(&hadc1, 1) != HAL_OK) CxxErrorHandler(); - vbat += HAL_ADC_GetValue(&hadc1); + if (HAL_ADC_PollForConversion(&BATTERY_ADC_HANDLE, 1) != HAL_OK) CxxErrorHandler(); + vbat += HAL_ADC_GetValue(&BATTERY_ADC_HANDLE); } vbat /= 8; - if (HAL_ADC_Stop(&hadc1) != HAL_OK) CxxErrorHandler(); + if (HAL_ADC_Stop(&BATTERY_ADC_HANDLE) != HAL_OK) CxxErrorHandler(); if (HAL_TIM_Base_Stop(&htim6) != HAL_OK) CxxErrorHandler(); @@ -205,7 +206,7 @@ struct M17Demodulator : IDemodulator INFO("Vref = %lumV", vref) INFO("Vbat = %lumV", vbat); - DEBUG("exit M17Demodulator::readBatteryLevel"); + TNC_DEBUG("exit M17Demodulator::readBatteryLevel"); return vbat; #else return 0; diff --git a/TNC/M17Encoder.cpp b/TNC/M17Encoder.cpp index ca9852d..e77700e 100644 --- a/TNC/M17Encoder.cpp +++ b/TNC/M17Encoder.cpp @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Mobilinkd LLC +// Copyright 2015-2021 Mobilinkd LLC // All rights reserved. #include "M17Encoder.h" @@ -29,6 +29,7 @@ static osMessageQId m17EncoderInputQueueHandle; static osMessageQId m17EncoderOutputQueueHandle; extern RNG_HandleTypeDef hrng; +extern IWDG_HandleTypeDef hiwdg; namespace mobilinkd { @@ -518,6 +519,39 @@ bool M17Encoder::do_csma() { return false; } +tnc::hdlc::IoFrame* M17Encoder::create_bert_frame() { + static PRBS9 prbs; + + std::array bert_frame; + + uint8_t byte = 0; + size_t j = 0; + for (size_t i = 0; i != 197; ++i) { + byte <<= 1; + byte |= prbs.generate(); + if ((i & 7) == 7) { + bert_frame[j] = byte; + j += 1; + byte = 0; + } + } + byte <<= 3; + bert_frame[j] = byte; + + // Encoder, puncture, interleave & randomize. + auto encoded = conv_encode(bert_frame, 197); + puncture_bytes(encoded, m17_frame, P2); + interleaver.interleave(m17_frame); + randomizer(m17_frame); + + auto frame = tnc::hdlc::acquire_wait(); + + for (auto c : m17::BERT_SYNC) frame->push_back(c); + for (auto c : m17_frame) frame->push_back(c); + + return frame; +} + /* * The encoder task is responsible for feeding symbols to the M17 modulator. */ @@ -533,6 +567,8 @@ void M17Encoder::encoderTask(void const*) osEvent evt = osMessageGet(m17EncoderInputQueueHandle, osWaitForever); if (evt.status != osEventMessage) continue; + HAL_IWDG_Refresh(&hiwdg); + auto frame = static_cast(evt.value.p); if (frame->size() != 48) { diff --git a/TNC/M17Encoder.h b/TNC/M17Encoder.h index 9b750a1..2e95e42 100644 --- a/TNC/M17Encoder.h +++ b/TNC/M17Encoder.h @@ -1,4 +1,4 @@ -// Copyright 2015-2020 Mobilinkd LLC +// Copyright 2015-2021 Mobilinkd LLC // All rights reserved. #pragma once @@ -64,6 +64,7 @@ struct M17Encoder : public Encoder static const std::array LSF_SYNC; static const std::array STREAM_SYNC; static const std::array PACKET_SYNC; + static const std::array BERT_SYNC; enum class State {INACTIVE, IDLE, ACTIVE}; enum class FrameType {BASIC_PACKET, FULL_PACKET, VOICE_STREAM}; @@ -75,6 +76,8 @@ struct M17Encoder : public Encoder void updateModulator() override; void stop() override; EncoderType encoder_type() const override { return EncoderType::M17; } + tnc::hdlc::IoFrame* create_bert_frame() override; + private: @@ -123,7 +126,9 @@ private: /** * Convolutional encode N bytes of data, returning N*2 + 1 bytes * of encoded data (4 zero flush bits are added). If total bits - * are not an even byte boundary, the + * are not an even byte boundary, the high bits of the last byte + * are used. + * * @param data * @param total_bits * @return diff --git a/TNC/M17FrameDecoder.h b/TNC/M17FrameDecoder.h index c7fc578..42616a5 100644 --- a/TNC/M17FrameDecoder.h +++ b/TNC/M17FrameDecoder.h @@ -40,6 +40,12 @@ tnc::hdlc::IoFrame* to_frame(std::array in) } } + if (b) // Not a full byte boundary. + { + while (b++ != 8) out <<= 1; + frame->push_back(out); + } + return frame; } @@ -153,8 +159,8 @@ struct M17FrameDecoder CRC16<0x5935, 0xFFFF> crc_; - enum class State {LSF, STREAM, BASIC_PACKET, FULL_PACKET}; - enum class SyncWordType { LSF, STREAM, PACKET, RESERVED }; + enum class State {LSF, STREAM, BASIC_PACKET, FULL_PACKET, BERT}; + enum class SyncWordType { LSF, STREAM, PACKET, BERT }; enum class DecodeResult { FAIL, OK, EOS, INCOMPLETE }; State state_ = State::LSF; @@ -164,6 +170,8 @@ struct M17FrameDecoder using lsf_conv_buffer_t = std::array; using lsf_buffer_t = std::array; + using bert_buffer_t = std::array; + using audio_conv_buffer_t = std::array; using audio_buffer_t = std::array; @@ -172,18 +180,21 @@ struct M17FrameDecoder link_setup_callback_t link_setup_callback_; audio_callback_t audio_callback_; + union { std::array lich; std::array lsf; std::array packet; std::array stream; + std::array bert; } output; union { std::array lsf; std::array packet; std::array stream; + std::array bert; std::array lich; } tmp; @@ -290,7 +301,7 @@ struct M17FrameDecoder for (auto c : current_lsf) lsf->push_back(c); lsf->push_back(0); lsf->push_back(0); - lsf->source(0x20); + lsf->source(tnc::hdlc::IoFrame::STREAM); return DecodeResult::OK; } lsf = nullptr; @@ -364,13 +375,13 @@ struct M17FrameDecoder INFO("LICH crc = %04x", checksum); if (checksum == 0) { - lich_segments = 0; + lich_segments = 0; state_ = State::STREAM; lsf = tnc::hdlc::acquire_wait(); for (auto c : output.lich) lsf->push_back(c); lsf->push_back(0); lsf->push_back(0); - lsf->source(0x20); + lsf->source(tnc::hdlc::IoFrame::STREAM); ber = 0; dump(output.lich); return DecodeResult::OK; @@ -385,6 +396,18 @@ struct M17FrameDecoder return DecodeResult::INCOMPLETE; } + [[gnu::noinline]] + DecodeResult decode_bert(buffer_t& buffer, tnc::hdlc::IoFrame*& bert, int& ber) + { + depuncture(buffer, tmp.bert, P2); + ber = viterbi_.decode(tmp.bert, output.bert); + bert = detail::to_frame(output.bert); + bert->push_back(0); + bert->push_back(0); + bert->source(tnc::hdlc::IoFrame::BERT); + return DecodeResult::OK; + } + [[gnu::noinline]] DecodeResult decode_stream(buffer_t& buffer, tnc::hdlc::IoFrame*& stream, int& ber) { @@ -410,7 +433,7 @@ struct M17FrameDecoder } stream->push_back(0); stream->push_back(0); - stream->source(0x20); + stream->source(tnc::hdlc::IoFrame::STREAM); return result; } @@ -524,7 +547,7 @@ struct M17FrameDecoder } current_packet->push_back(0); current_packet->push_back(0); - current_packet->source(0x10); + current_packet->source(tnc::hdlc::IoFrame::PACKET); packet = current_packet; current_packet = nullptr; packet_frame_counter = 0; @@ -618,9 +641,9 @@ struct M17FrameDecoder state_ = State::LSF; } break; - case SyncWordType::RESERVED: - state_ = State::LSF; - break; + case SyncWordType::BERT: + state_ = State::BERT; + return decode_bert(buffer, result, ber); } return DecodeResult::FAIL; diff --git a/TNC/M17Modulator.h b/TNC/M17Modulator.h index 3ab6df5..d105ca9 100644 --- a/TNC/M17Modulator.h +++ b/TNC/M17Modulator.h @@ -26,7 +26,7 @@ struct M17Modulator : Modulator // Six buffers per M17 frame, or 12 half-buffer interrupts. static constexpr uint8_t UPSAMPLE = 10; static constexpr uint32_t BLOCKSIZE = 4; - static constexpr uint32_t STATE_SIZE = (m17::FILTER_TAP_NUM_9 / UPSAMPLE) + BLOCKSIZE - 1; + static constexpr uint32_t STATE_SIZE = (m17::FILTER_TAP_NUM_15 / UPSAMPLE) + BLOCKSIZE - 1; static constexpr int16_t DAC_BUFFER_LEN = 80; // 8 symbols, 16 bits, 2 bytes. static constexpr int16_t TRANSFER_LEN = DAC_BUFFER_LEN / 2; // 4 symbols, 8 bits, 1 byte. static constexpr uint16_t VREF = 4095; @@ -43,13 +43,14 @@ struct M17Modulator : Modulator volatile uint16_t stop_count = 0; // Flush the RRC matched filter. State state{State::STOPPED}; float tmp[TRANSFER_LEN]; + bool send_tone = false; M17Modulator(osMessageQId queue, PTT* ptt) : dacOutputQueueHandle_(queue), ptt_(ptt) { arm_fir_interpolate_init_f32( - &fir_interpolator, UPSAMPLE, m17::FILTER_TAP_NUM_9, - (float32_t*) m17::rrc_taps_f9.data(), fir_state.data(), BLOCKSIZE); + &fir_interpolator, UPSAMPLE, m17::FILTER_TAP_NUM_15, + (float32_t*) m17::rrc_taps_f15.data(), fir_state.data(), BLOCKSIZE); } ~M17Modulator() override {} @@ -102,7 +103,7 @@ struct M17Modulator : Modulator { case State::STOPPING: case State::STOPPED: -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_DisableLSCO(); #endif delay_count = 0; @@ -127,6 +128,20 @@ struct M17Modulator : Modulator } } + constexpr std::array make_1000hz_tone() + { + std::array result; + for (size_t i = 0; i != result.size(); ++i) { + result[i] = std::sin(M_PI * i * 2.0 / result.size()) * 3; + } + return result; + } + + void tone(uint16_t) override + { + send_tone = true; + } + // DAC DMA interrupt functions. [[gnu::noinline]] void fill_first(uint8_t bits) override @@ -168,7 +183,7 @@ struct M17Modulator : Modulator case State::STOPPED: stop_conversion(); ptt_->off(); -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_EnableLSCO(RCC_LSCOSOURCE_LSE); #endif osMessagePut(audioInputQueueHandle, tnc::audio::DEMODULATOR, @@ -206,7 +221,7 @@ struct M17Modulator : Modulator case State::STOPPED: stop_conversion(); ptt_->off(); -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_EnableLSCO(RCC_LSCOSOURCE_LSE); #endif osMessagePut(audioInputQueueHandle, tnc::audio::DEMODULATOR, @@ -218,9 +233,10 @@ struct M17Modulator : Modulator void abort() override { state = State::STOPPED; + send_tone = false; stop_conversion(); ptt_->off(); -#if defined(KISS_LOGGING) && !defined(NUCLEOTNC) +#if defined(KISS_LOGGING) && defined(HAVE_LSCO) HAL_RCCEx_EnableLSCO(RCC_LSCOSOURCE_LSE); #endif // Drain the queue. @@ -295,9 +311,28 @@ private: } } + void fill_tone(int16_t* buffer) + { + static uint8_t pos = 0; + static const auto Hz1000 = make_1000hz_tone(); + + int16_t polarity = kiss::settings().tx_rev_polarity() ? -1 : 1; + + for (size_t i = 0; i != TRANSFER_LEN; ++i) { + buffer[i] = adjust_level(Hz1000[pos++] * polarity); + if (pos == Hz1000.size()) pos = 0; + } + } + [[gnu::noinline]] void fill(int16_t* buffer, uint8_t bits) { + if (send_tone) + { + fill_tone(buffer); + return; + } + int16_t polarity = kiss::settings().tx_rev_polarity() ? -1 : 1; for (size_t i = 0; i != 4; ++i) @@ -333,6 +368,7 @@ private: [[gnu::noinline]] void fill_empty(int16_t* buffer) { + send_tone = false; for (size_t i = 0; i != TRANSFER_LEN; ++i) { buffer[i] = 2048; diff --git a/TNC/Modulator.hpp b/TNC/Modulator.hpp index ab7555b..183ea67 100644 --- a/TNC/Modulator.hpp +++ b/TNC/Modulator.hpp @@ -59,6 +59,8 @@ struct Modulator */ virtual void send(uint8_t symbol) = 0; + virtual void tone(uint16_t freq) = 0; + /// The next three functions are called by the DAC DMA interrupt handler. /** diff --git a/TNC/ModulatorTask.cpp b/TNC/ModulatorTask.cpp index 6dfd050..87aab2d 100644 --- a/TNC/ModulatorTask.cpp +++ b/TNC/ModulatorTask.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Mobilinkd LLC +// Copyright 2015-2021 Mobilinkd LLC // All rights reserved. #include "ModulatorTask.hpp" @@ -10,6 +10,7 @@ #include "AFSKModulator.hpp" #include "KissHardware.hpp" #include "main.h" +#include "Log.h" mobilinkd::tnc::SimplexPTT simplexPtt; mobilinkd::tnc::MultiplexPTT multiplexPtt; @@ -77,6 +78,7 @@ mobilinkd::Encoder& getEncoder() case kiss::Hardware::ModemType::M17: return m17Encoder; default: + ERROR("Invalid modem type %d", int(kiss::settings().modem_type)); CxxErrorHandler(); } } diff --git a/TNC/NullPort.hpp b/TNC/NullPort.hpp index 48941b6..0a1830d 100644 --- a/TNC/NullPort.hpp +++ b/TNC/NullPort.hpp @@ -1,8 +1,7 @@ -// Copyright 2016 Rob Riggs +// Copyright 2016-2021 Rob Riggs // All rights reserved. -#ifndef MOBILINKD__TNC__NULL_PORT_HPP_ -#define MOBILINKD__TNC__NULL_PORT_HPP_ +#pragma once #include "PortInterface.hpp" @@ -52,5 +51,3 @@ struct NullPort : PortInterface NullPort* getNullPort(); }} // mobilinkd::tnc - -#endif // MOBILINKD__TNC__NULL_PORT_HPP_ diff --git a/TNC/SegmentedBuffer.hpp b/TNC/SegmentedBuffer.hpp index 3e0620c..66e86ec 100644 --- a/TNC/SegmentedBuffer.hpp +++ b/TNC/SegmentedBuffer.hpp @@ -1,8 +1,7 @@ -// Copyright 2015 Mobilinkd LLC +// Copyright 2015-2021 Mobilinkd LLC // All rights reserved. -#ifndef MOBILINKD__SEGMENTED_BUFFER_HPP_ -#define MOBILINKD__SEGMENTED_BUFFER_HPP_ +#pragma once #include "memory.hpp" @@ -157,5 +156,3 @@ struct SegmentedBufferIterator : public boost::iterator_facade< }; }}} // mobilinkd::tnc::buffer - -#endif // MOBILINKD__SEGMENTED_BUFFER_HPP_ diff --git a/TNC/SerialPort.cpp b/TNC/SerialPort.cpp index b668459..3e185cc 100644 --- a/TNC/SerialPort.cpp +++ b/TNC/SerialPort.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Rob Riggs +// Copyright 2016-2021 Rob Riggs // All rights reserved. #ifndef NUCLEOTNC @@ -52,11 +52,11 @@ void log_frame(mobilinkd::tnc::hdlc::IoFrame* frame) if (isprint(int(c))) pos += sprintf((char*)tmpBuffer2 + pos, " %c ", c); else pos += sprintf((char*)tmpBuffer2 + pos, "/%02x", c); if (pos > 80) { - DEBUG((char*)tmpBuffer2); + TNC_DEBUG((char*)tmpBuffer2); pos = 0; } } - DEBUG((char*)tmpBuffer2); + TNC_DEBUG((char*)tmpBuffer2); } #endif @@ -569,7 +569,7 @@ bool SerialPort::write(hdlc::IoFrame* frame, uint32_t timeout) osMutexRelease(mutex_); hdlc::release(frame); - DEBUG("SerialPort::write COMPLETE"); + TNC_DEBUG("SerialPort::write COMPLETE"); return true; } diff --git a/TNC/SerialPort.hpp b/TNC/SerialPort.hpp index 5374c53..7dcbded 100644 --- a/TNC/SerialPort.hpp +++ b/TNC/SerialPort.hpp @@ -1,8 +1,7 @@ -// Copyright 2016 Rob Riggs +// Copyright 2016-2021 Rob Riggs // All rights reserved. -#ifndef MOBILINKD__TNC__SERIAL_PORT_HPP_ -#define MOBILINKD__TNC__SERIAL_PORT_HPP_ +#pragma once #include "PortInterface.hpp" @@ -38,5 +37,3 @@ private: SerialPort* getSerialPort(); }} // mobilinkd::tnc - -#endif // MOBILINKD__TNC__SERIAL_PORT_HPP_ diff --git a/TNC/Util.h b/TNC/Util.h index 50379cd..21a1baa 100644 --- a/TNC/Util.h +++ b/TNC/Util.h @@ -1,4 +1,4 @@ -// Copyright 2020 Mobilinkd LLC. +// Copyright 2020-2021 Mobilinkd LLC. #pragma once @@ -314,4 +314,85 @@ constexpr void to_byte_array(std::array in, std::array history; + size_t hist_count = 0; + size_t hist_pos = 0; + + // PRBS generator. + bool generate() + { + bool result = ((state >> TAP_1) ^ (state >> TAP_2)) & 1; + state = ((state << 1) | result) & MASK; + return result; + } + + // PRBS validator. + bool validate(bool bit) + { + bool result; + bit_count += 1; + if (!synced) { + // Need to sync the PRBS with the incoming data. + result = (bit ^ (state >> TAP_1) ^ (state >> TAP_2)) & 1; + state = ((state << 1) | bit) & MASK; + if (result) { + err_count += 1; + sync_count = 0; // error + } else { + if (++sync_count == LOCK_COUNT) { + synced = true; + history.fill(0); + hist_count = 0; + hist_pos = 0; + sync_count = 0; + } + } + } else { + // PRBS is now free-running. + result = generate(); + + hist_count -= (history[hist_pos >> 3] & (1 << (hist_pos & 7))) != 0; + if (result != bit) { + err_count += 1; + hist_count += 1; + history[hist_pos >> 3] |= (1 << (hist_pos & 7)); + } else { + history[hist_pos >> 3] &= ~(1 << (hist_pos & 7)); + } + if (++hist_pos == 128) hist_pos = 0; + } + return result; + } + + bool sync() const { return synced; } + + uint32_t errors() const { assert(synced); return err_count; } + uint32_t bits() const { assert(synced); return bit_count; } + + // Reset the state. + void reset() + { + state = 1; + synced = false; + sync_count = 0; + bit_count = 0; + err_count = 0; + history.fill(0); + hist_count = 0; + hist_pos = 0; + } +}; + } // mobilinkd diff --git a/TNC/memory.hpp b/TNC/memory.hpp index e3ae05f..ae1789a 100644 --- a/TNC/memory.hpp +++ b/TNC/memory.hpp @@ -1,8 +1,7 @@ -// Copyright 2015 Mobilinkd LLC +// Copyright 2015-2021 Mobilinkd LLC // All rights reserved. -#ifndef MOBILINKD__MEMORY_HPP_ -#define MOBILINKD__MEMORY_HPP_ +#pragma once #include "cmsis_os.h" @@ -66,9 +65,9 @@ struct Pool { free_list.push_back(*item); taskEXIT_CRITICAL_FROM_ISR(x); } + + size_t free() const { return free_list.size(); } }; }}} // mobilinkd::tnc::memory - -#endif // MOBILINKD__MEMORY_HPP_