kopia lustrzana https://github.com/mobilinkd/NucleoTNC
rodzic
f68001529b
commit
b2977c66a4
|
@ -0,0 +1,255 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* @file stm32l4xx_hal_iwdg.h
|
||||
* @author MCD Application Team
|
||||
* @brief Header file of IWDG HAL module.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
|
||||
*
|
||||
* 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****/
|
|
@ -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
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
|
||||
*
|
||||
* 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****/
|
21
Inc/main.h
21
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
|
||||
|
|
|
@ -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 */
|
||||
|
|
20
Src/main.c
20
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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 Rob Riggs <rob@mobilinkd.com>
|
||||
// Copyright 2016-2021 Rob Riggs <rob@mobilinkd.com>
|
||||
// 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
|
||||
{
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright 2016 Rob Riggs <rob@mobilinkd.com>
|
||||
// Copyright 2016-2021 Rob Riggs <rob@mobilinkd.com>
|
||||
// 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_
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <type_traits>
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright 2015 Rob Riggs <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Rob Riggs <rob@mobilinkd.com>
|
||||
// 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_
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// Copyright 2015-2020 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// 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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -5,10 +5,14 @@
|
|||
|
||||
#include "Modulator.hpp"
|
||||
|
||||
#include "stm32l4xx_hal.h"
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
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:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2015 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// All rights reserved.
|
||||
|
||||
#include "HdlcFrame.hpp"
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
// Copyright 2015-2019 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// 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_
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2015-2020 Rob Riggs <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Rob Riggs <rob@mobilinkd.com>
|
||||
// All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
@ -15,31 +15,32 @@ struct IirFilter {
|
|||
const std::array<float, N>& numerator_;
|
||||
const std::array<float, N>& denominator_;
|
||||
std::array<float, N> history_;
|
||||
size_t size_;
|
||||
|
||||
IirFilter(const std::array<float, N>& b,
|
||||
const std::array<float, N>& 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
|
||||
|
||||
|
||||
|
|
20
TNC/Kiss.cpp
20
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<const uint8_t*>(&*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
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Log.h"
|
||||
#include "HdlcFrame.hpp"
|
||||
#include "AFSKTestTone.hpp"
|
||||
#include "main.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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(...)
|
||||
|
|
|
@ -27,6 +27,7 @@ extern const std::array<float, FILTER_TAP_NUM_15> rrc_taps_f15;
|
|||
constexpr std::array<uint8_t, 2> LSF_SYNC = { 0x55, 0xF7 };
|
||||
constexpr std::array<uint8_t, 2> STREAM_SYNC = { 0xFF, 0x5D };
|
||||
constexpr std::array<uint8_t, 2> PACKET_SYNC = { 0x75, 0xFF };
|
||||
constexpr std::array<uint8_t, 2> BERT_SYNC = { 0xDF, 0x55 };
|
||||
|
||||
inline constexpr uint16_t sync_word(std::array<uint8_t, 2> sw)
|
||||
{
|
||||
|
|
|
@ -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<float, 4>(sample);
|
||||
int8_t* tmp;
|
||||
auto len = framer(n, &tmp);
|
||||
if (len != 0)
|
||||
{
|
||||
need_clock_update_ = true;
|
||||
auto n = mobilinkd::llr<float, 4>(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();
|
||||
|
|
|
@ -49,7 +49,7 @@ struct M17Demodulator : IDemodulator
|
|||
using audio_filter_t = FirFilter<ADC_BLOCK_SIZE, m17::FILTER_TAP_NUM_15>;
|
||||
using sync_word_t = m17::SyncWord<m17::Correlator>;
|
||||
|
||||
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<float, ADC_BLOCK_SIZE> 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<float> 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;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2015-2020 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// 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<uint8_t, 25> 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<IoFrame*>(evt.value.p);
|
||||
if (frame->size() != 48)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2015-2020 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
@ -64,6 +64,7 @@ struct M17Encoder : public Encoder
|
|||
static const std::array<uint8_t, 2> LSF_SYNC;
|
||||
static const std::array<uint8_t, 2> STREAM_SYNC;
|
||||
static const std::array<uint8_t, 2> PACKET_SYNC;
|
||||
static const std::array<uint8_t, 2> 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
|
||||
|
|
|
@ -40,6 +40,12 @@ tnc::hdlc::IoFrame* to_frame(std::array<T, N> 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<uint8_t, 46>;
|
||||
using lsf_buffer_t = std::array<uint8_t, 30>;
|
||||
|
||||
using bert_buffer_t = std::array<uint8_t, 25>;
|
||||
|
||||
using audio_conv_buffer_t = std::array<uint8_t, 34>;
|
||||
using audio_buffer_t = std::array<uint8_t, 18>;
|
||||
|
||||
|
@ -172,18 +180,21 @@ struct M17FrameDecoder
|
|||
|
||||
link_setup_callback_t link_setup_callback_;
|
||||
audio_callback_t audio_callback_;
|
||||
|
||||
union
|
||||
{
|
||||
std::array<uint8_t, 30> lich;
|
||||
std::array<uint8_t, 240> lsf;
|
||||
std::array<uint8_t, 206> packet;
|
||||
std::array<uint8_t, 144> stream;
|
||||
std::array<uint8_t, 197> bert;
|
||||
} output;
|
||||
|
||||
union {
|
||||
std::array<int8_t, 488> lsf;
|
||||
std::array<int8_t, 420> packet;
|
||||
std::array<int8_t, 272> stream;
|
||||
std::array<int8_t, 402> bert;
|
||||
std::array<uint8_t, 6> 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;
|
||||
|
|
|
@ -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<float, 48> make_1000hz_tone()
|
||||
{
|
||||
std::array<float, 48> 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;
|
||||
|
|
|
@ -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.
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2015 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright 2016 Rob Riggs <rob@mobilinkd.com>
|
||||
// Copyright 2016-2021 Rob Riggs <rob@mobilinkd.com>
|
||||
// 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_
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright 2015 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// 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_
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2016 Rob Riggs <rob@mobilinkd.com>
|
||||
// Copyright 2016-2021 Rob Riggs <rob@mobilinkd.com>
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright 2016 Rob Riggs <rob@mobilinkd.com>
|
||||
// Copyright 2016-2021 Rob Riggs <rob@mobilinkd.com>
|
||||
// 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_
|
||||
|
|
83
TNC/Util.h
83
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<T, N> in, std::array<uint8_t, (N + 7) /
|
|||
if (i < out.size()) out[i] = tmp;
|
||||
}
|
||||
|
||||
struct PRBS9
|
||||
{
|
||||
static constexpr uint16_t MASK = 0x1FF;
|
||||
static constexpr uint8_t TAP_1 = 8; // Bit 9
|
||||
static constexpr uint8_t TAP_2 = 4; // Bit 5
|
||||
static constexpr uint8_t LOCK_COUNT = 18; // 18 consecutive good bits.
|
||||
|
||||
uint16_t state = 1;
|
||||
bool synced = false;
|
||||
uint8_t sync_count = 0;
|
||||
uint32_t bit_count = 0;
|
||||
uint32_t err_count = 0;
|
||||
std::array<uint8_t, 16> 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
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
// Copyright 2015 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// Copyright 2015-2021 Mobilinkd LLC <rob@mobilinkd.com>
|
||||
// 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_
|
||||
|
|
Ładowanie…
Reference in New Issue