Add support for BER testing. Update version to v2.3.2

master v2.3.2
Rob Riggs 2021-08-03 21:32:40 -05:00
rodzic f68001529b
commit b2977c66a4
41 zmienionych plików z 1345 dodań i 528 usunięć

Wyświetl plik

@ -0,0 +1,255 @@
/**
******************************************************************************
* @file stm32l4xx_hal_iwdg.h
* @author MCD Application Team
* @brief Header file of IWDG HAL module.
******************************************************************************
* @attention
*
* <h2><center>&copy; 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****/

Wyświetl plik

@ -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>&copy; 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****/

Wyświetl plik

@ -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

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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 */

Wyświetl plik

@ -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

Wyświetl plik

@ -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
{

Wyświetl plik

@ -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_

Wyświetl plik

@ -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;

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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_

Wyświetl plik

@ -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

Wyświetl plik

@ -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;

Wyświetl plik

@ -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:

Wyświetl plik

@ -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"

Wyświetl plik

@ -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_

Wyświetl plik

@ -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();

Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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
}

Wyświetl plik

@ -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();
}

Wyświetl plik

@ -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
}

Wyświetl plik

@ -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(...)

Wyświetl plik

@ -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)
{

Wyświetl plik

@ -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();

Wyświetl plik

@ -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;

Wyświetl plik

@ -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)
{

Wyświetl plik

@ -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

Wyświetl plik

@ -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;

Wyświetl plik

@ -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;

Wyświetl plik

@ -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.
/**

Wyświetl plik

@ -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();
}
}

Wyświetl plik

@ -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_

Wyświetl plik

@ -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_

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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_

Wyświetl plik

@ -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

Wyświetl plik

@ -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_