commit
735e2af3d4
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,347 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
|
||||||
|
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2017 by Danilo DB4PLE
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* Some of the code is based on work of Guus Van Dooren PE1PLM:
|
||||||
|
* https://github.com/ki6zum/gmsk-dstar/blob/master/firmware/dvmega/dvmega.ino
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__ADF7021_H__)
|
||||||
|
#define __ADF7021_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "IO.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define LOW 0
|
||||||
|
#define HIGH 1
|
||||||
|
|
||||||
|
/** Band Tables */
|
||||||
|
/** 136 - 174 mhz */
|
||||||
|
#define VHF_MIN 136000000
|
||||||
|
#define VHF_MAX 174000000
|
||||||
|
|
||||||
|
/** 216 - 225 mhz */
|
||||||
|
#define VHF_220_MIN 216000000
|
||||||
|
#define VHF_220_MAX 225000000
|
||||||
|
|
||||||
|
/** 380 - 431mhz */
|
||||||
|
#define UHF_380_MIN 380000000
|
||||||
|
#define UHF_380_MAX 431000000
|
||||||
|
|
||||||
|
/** 431 - 450mhz */
|
||||||
|
#define UHF_1_MIN 431000000
|
||||||
|
#define UHF_1_MAX 470000000
|
||||||
|
|
||||||
|
/** 450 - 470mhz */
|
||||||
|
#define UHF_2_MIN 450000000
|
||||||
|
#define UHF_2_MAX 470000000
|
||||||
|
|
||||||
|
/** 470 - 520mhz (T-band) */
|
||||||
|
#define UHF_T_MIN 470000000
|
||||||
|
#define UHF_T_MAX 520000000
|
||||||
|
|
||||||
|
/** 842 - 900mhz */
|
||||||
|
#define UHF_800_MIN 842000000
|
||||||
|
#define UHF_800_MAX 900000000
|
||||||
|
|
||||||
|
/** 900 - 950mhz */
|
||||||
|
#define UHF_900_MIN 900000000
|
||||||
|
#define UHF_900_MAX 950000000
|
||||||
|
|
||||||
|
#if defined(ENABLE_ADF7021)
|
||||||
|
|
||||||
|
#define ADF_BIT_READ(value, bit) (((value) >> (bit)) & 0x01)
|
||||||
|
|
||||||
|
#if defined(ADF7021_DISABLE_RC_4FSK)
|
||||||
|
#define ADF7021_EVEN_BIT true
|
||||||
|
#else
|
||||||
|
#define ADF7021_EVEN_BIT false
|
||||||
|
#endif // ADF7021_DISABLE_RC_4FSK
|
||||||
|
|
||||||
|
/*
|
||||||
|
- Most of the registers values are obteined from ADI eval software:
|
||||||
|
http://www.analog.com/en/products/rf-microwave/integrated-transceivers-transmitters-receivers/low-power-rf-transceivers/adf7021.html
|
||||||
|
- or ADF7021 datasheet formulas:
|
||||||
|
www.analog.com/media/en/technical-documentation/data-sheets/ADF7021.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Test modes */
|
||||||
|
|
||||||
|
// Enable SWD pin to access the demodulator output signal:
|
||||||
|
// (See application note AN-852 and ADF7021 datasheet, page 60)
|
||||||
|
// #define TEST_DAC
|
||||||
|
|
||||||
|
// Transmit the carrier frequency:
|
||||||
|
// #define TEST_TX
|
||||||
|
|
||||||
|
/*********************/
|
||||||
|
|
||||||
|
// Disable TX Raised Cosine filter for 4FSK modulation in ADF7021:
|
||||||
|
// #define ADF7021_DISABLE_RC_4FSK
|
||||||
|
|
||||||
|
// Support for ADF7021-N version:
|
||||||
|
// #define ADF7021_N_VER
|
||||||
|
|
||||||
|
// Enable AFC support for DMR, YSF, P25, and M17 (experimental):
|
||||||
|
// (AFC is already enabled by default in D-Star)
|
||||||
|
// #define ADF7021_ENABLE_4FSK_AFC
|
||||||
|
|
||||||
|
// Configure AFC with positive initial frequency offset:
|
||||||
|
// #define ADF7021_AFC_POS
|
||||||
|
|
||||||
|
/** Support for 14.7456 MHz TCXO (modified RF7021SE boards) */
|
||||||
|
#if defined(ADF7021_14_7456)
|
||||||
|
|
||||||
|
// R = 4
|
||||||
|
// DEMOD_CLK = 2.4576 MHz (DEFAULT
|
||||||
|
// DEMOD_CLK = 4.9152 MHz (DMR, P25)
|
||||||
|
#define ADF7021_PFD 3686400.0
|
||||||
|
|
||||||
|
/*
|
||||||
|
** VCO/Oscillator (Register 1)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG1_VHF 0x02175041 /** 136 - 174mhz */
|
||||||
|
#define ADF7021_REG1_VHF_220 0x021B5041 /** 219 - 225mhz */
|
||||||
|
#define ADF7021_REG1_UHF_380 0x021B5041 /** 380 - 431mhz */ // this could be problematic due to
|
||||||
|
// the external VCO control
|
||||||
|
#define ADF7021_REG1_UHF_1 0x00575041 /** 431 - 450mhz */
|
||||||
|
#define ADF7021_REG1_UHF_2 0x01D75041 /** 450 - 470mhz */
|
||||||
|
#define ADF7021_REG1_UHF_T 0x02235041 /** 470 - 520mhz */ // this could be problematic due to
|
||||||
|
// the external VCO control
|
||||||
|
#define ADF7021_REG1_800 0x00535041 /** 842 - 900mhz */
|
||||||
|
#define ADF7021_REG1_900 0x01D35041 /** 900 - 950mhz */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Transmit Modulation (Register 2)
|
||||||
|
*/
|
||||||
|
#define ADF7021_DEV_DEFAULT 43U
|
||||||
|
#define ADF7021_DEV_DMR 23U
|
||||||
|
|
||||||
|
#if defined(ENABLE_P25_WIDE)
|
||||||
|
#define ADF7021_DEV_P25 32U
|
||||||
|
#else
|
||||||
|
#define ADF7021_DEV_P25 22U
|
||||||
|
#endif // ENABLE_P25_WIDE
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Tx/Rx Clock (Register 3)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG3_DEFAULT 0x2A4C4193
|
||||||
|
#if defined(TEST_DAC)
|
||||||
|
#define ADF7021_REG3_DMR 0x2A4C04D3
|
||||||
|
#define ADF7021_REG3_P25 0x2A4C04D3
|
||||||
|
#else
|
||||||
|
#define ADF7021_REG3_DMR 0x2A4C80D3
|
||||||
|
#define ADF7021_REG3_P25 0x2A4C80D3
|
||||||
|
#endif // TEST_DAC
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Demodulator Setup (Register 4)
|
||||||
|
*/
|
||||||
|
// Discriminator bandwith, demodulator
|
||||||
|
// Bug in ADI evaluation software, use datasheet formula (4FSK)
|
||||||
|
#define ADF7021_DISC_BW_DEFAULT 522U // K=85
|
||||||
|
#define ADF7021_DISC_BW_DMR 393U // K=32
|
||||||
|
#define ADF7021_DISC_BW_P25 394U // K=32
|
||||||
|
|
||||||
|
// Post demodulator bandwith
|
||||||
|
#define ADF7021_POST_BW_DEFAULT 10U
|
||||||
|
#define ADF7021_POST_BW_DMR 80U
|
||||||
|
#define ADF7021_POST_BW_P25 6U
|
||||||
|
|
||||||
|
/*
|
||||||
|
** IF Coarse Cal Setup (Register 5)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG5 0x000024F5
|
||||||
|
|
||||||
|
/*
|
||||||
|
** IF Fine Cal Setup (Register 6)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG6 0x05070E16
|
||||||
|
|
||||||
|
/*
|
||||||
|
** AFC (Register 10)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG10_DEFAULT 0x0C96473A
|
||||||
|
|
||||||
|
#if defined(ADF7021_ENABLE_4FSK_AFC)
|
||||||
|
|
||||||
|
#define ADF7021_REG10_DMR 0x01FE473A
|
||||||
|
#define ADF7021_REG10_P25 0x01FE473A
|
||||||
|
|
||||||
|
#if defined(ADF7021_AFC_POS)
|
||||||
|
|
||||||
|
#define AFC_OFFSET_DMR -250
|
||||||
|
#define AFC_OFFSET_P25 -250
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define AFC_OFFSET_DMR 250
|
||||||
|
#define AFC_OFFSET_P25 250
|
||||||
|
|
||||||
|
#endif // ADF7021_AFC_POS
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ADF7021_REG10_DMR 0x049E472A
|
||||||
|
#define ADF7021_REG10_P25 0x049E472A
|
||||||
|
#define AFC_OFFSET_DMR 0
|
||||||
|
#define AFC_OFFSET_P25 0
|
||||||
|
|
||||||
|
#endif // ADF7021_ENABLE_4FSK_AFC
|
||||||
|
|
||||||
|
/** Support for 12.2880 MHz TCXO */
|
||||||
|
#elif defined(ADF7021_12_2880)
|
||||||
|
|
||||||
|
// R = 2
|
||||||
|
// DEMOD_CLK = 2.4576 MHz (DEFAULT)
|
||||||
|
// DEMOD_CLK = 6.1440 MHz (DMR, P25)
|
||||||
|
#define ADF7021_PFD 6144000.0
|
||||||
|
|
||||||
|
/*
|
||||||
|
** VCO/Oscillator (Register 1)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG1_VHF 0x02175021 /** 136 - 174mhz */
|
||||||
|
#define ADF7021_REG1_VHF_220 0x021B5021 /** 219 - 225mhz */
|
||||||
|
#define ADF7021_REG1_UHF_380 0x021B5021 /** 380 - 431mhz */ // this could be problematic due to
|
||||||
|
// the external VCO control
|
||||||
|
#define ADF7021_REG1_UHF_1 0x00575021 /** 431 - 450mhz */
|
||||||
|
#define ADF7021_REG1_UHF_2 0x01D75021 /** 450 - 470mhz */
|
||||||
|
#define ADF7021_REG1_UHF_T 0x02235021 /** 470 - 520mhz */ // this could be problematic due to
|
||||||
|
// the external VCO control
|
||||||
|
#define ADF7021_REG1_800 0x00535021 /** 842 - 900mhz */
|
||||||
|
#define ADF7021_REG1_900 0x01D35021 /** 900 - 950mhz */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Transmit Modulation (Register 2)
|
||||||
|
*/
|
||||||
|
#define ADF7021_DEV_DEFAULT 26U
|
||||||
|
#define ADF7021_DEV_DMR 14U
|
||||||
|
|
||||||
|
#if defined(ENABLE_P25_WIDE)
|
||||||
|
#define ADF7021_DEV_P25 19U
|
||||||
|
#else
|
||||||
|
#define ADF7021_DEV_P25 13U
|
||||||
|
#endif // ENABLE_P25_WIDE
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Tx/Rx Clock (Register 3)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG3_DEFAULT 0x29EC4153
|
||||||
|
#if defined(TEST_DAC)
|
||||||
|
#define ADF7021_REG3_DMR 0x29EC0493
|
||||||
|
#define ADF7021_REG3_P25 0x29EC0493
|
||||||
|
#else
|
||||||
|
#define ADF7021_REG3_DMR 0x29ECA093
|
||||||
|
#define ADF7021_REG3_P25 0x29ECA093
|
||||||
|
#endif // TEST_DAC
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Demodulator Setup (Register 4)
|
||||||
|
*/
|
||||||
|
// Discriminator bandwith, demodulator
|
||||||
|
// Bug in ADI evaluation software, use datasheet formula (4FSK)
|
||||||
|
#define ADF7021_DISC_BW_DEFAULT 522U // K=85
|
||||||
|
#define ADF7021_DISC_BW_DMR 491U // K=32
|
||||||
|
#define ADF7021_DISC_BW_P25 493U // K=32
|
||||||
|
|
||||||
|
// Post demodulator bandwith
|
||||||
|
#define ADF7021_POST_BW_DEFAULT 10U
|
||||||
|
#define ADF7021_POST_BW_DMR 80U
|
||||||
|
#define ADF7021_POST_BW_P25 6U
|
||||||
|
|
||||||
|
/*
|
||||||
|
** IF Coarse Cal Setup (Register 5)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG5 0x00001ED5
|
||||||
|
|
||||||
|
/*
|
||||||
|
** IF Fine Cal Setup (Register 6)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG6 0x0505EBB6
|
||||||
|
|
||||||
|
/*
|
||||||
|
** AFC (Register 10)
|
||||||
|
*/
|
||||||
|
#define ADF7021_REG10_DEFAULT 0x0C96557A
|
||||||
|
|
||||||
|
#if defined(ADF7021_ENABLE_4FSK_AFC)
|
||||||
|
|
||||||
|
#define ADF7021_REG10_DMR 0x01FE557A
|
||||||
|
#define ADF7021_REG10_P25 0x01FE557A
|
||||||
|
|
||||||
|
#if defined(ADF7021_AFC_POS)
|
||||||
|
|
||||||
|
#define AFC_OFFSET_DMR -250
|
||||||
|
#define AFC_OFFSET_P25 -250
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define AFC_OFFSET_DMR 250
|
||||||
|
#define AFC_OFFSET_P25 250
|
||||||
|
|
||||||
|
#endif // ADF7021_AFC_POS
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ADF7021_REG10_DMR 0x049E556A
|
||||||
|
#define ADF7021_REG10_P25 0x049E556A
|
||||||
|
#define AFC_OFFSET_DMR 0
|
||||||
|
#define AFC_OFFSET_P25 0
|
||||||
|
|
||||||
|
#endif // ADF7021_ENABLE_4FSK_AFC
|
||||||
|
|
||||||
|
#endif // ADF7021_12_2880
|
||||||
|
|
||||||
|
/*
|
||||||
|
** 3FSK/4FSK Demod (Register 13)
|
||||||
|
*/
|
||||||
|
// Slicer threshold for 4FSK demodulator
|
||||||
|
#define ADF7021_SLICER_TH_DEFAULT 0U
|
||||||
|
|
||||||
|
#if defined(ADF7021_N_VER)
|
||||||
|
|
||||||
|
#define ADF7021_SLICER_TH_DMR 51U
|
||||||
|
#define ADF7021_SLICER_TH_P25 43U
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ADF7021_SLICER_TH_DMR 57U
|
||||||
|
#define ADF7021_SLICER_TH_P25 47U
|
||||||
|
|
||||||
|
#endif // ADF7021_N_VER
|
||||||
|
|
||||||
|
#endif // ENABLE_ADF7021
|
||||||
|
#endif // __ADF7021_H__
|
||||||
@ -0,0 +1,739 @@
|
|||||||
|
# Building instructions
|
||||||
|
|
||||||
|
This is a detailed guide for building the firmware of MMDVM_HS from the source code. For quick instructions, please see [README.md](README.md). This software runs on STM32F103 microcontroller. Also, Arduino with 3.3 V I/O (Arduino Due and Zero) and Teensy (3.1, 3.2, 3.5 or 3.6) are supported. You can build this code using Arduino IDE with Roger Clark's [STM32duino](https://github.com/rogerclarkmelbourne/Arduino_STM32/tree/ZUMspot) package, or using command line tools with ARM GCC tools. The preferred method under Windows is using STM32duino, and under Linux or macOS (command line) is using [STM32F10X_Lib](https://github.com/juribeparada/STM32F10X_Lib).
|
||||||
|
|
||||||
|
# Index
|
||||||
|
|
||||||
|
- ZUMspot RPi
|
||||||
|
- ZUMspot Libre Kit
|
||||||
|
- ZUMspot USB
|
||||||
|
- MMDVM_HS_Hat
|
||||||
|
- Makefile options
|
||||||
|
- Config.h options
|
||||||
|
- Pinout definitions
|
||||||
|
- Hidden options
|
||||||
|
|
||||||
|
# ZUMspot RPi
|
||||||
|
|
||||||
|
Download latest Raspbian image and install to a micro SD
|
||||||
|
|
||||||
|
* See: https://www.raspberrypi.org/documentation/installation/installing-images/
|
||||||
|
* Configure your SD before booting. Useful article: https://styxit.com/2017/03/14/headless-raspberry-setup.html
|
||||||
|
|
||||||
|
Boot your Raspberry Pi. Run raspi-config and configure according to your preferences:
|
||||||
|
|
||||||
|
sudo raspi-config
|
||||||
|
|
||||||
|
Select at least:
|
||||||
|
|
||||||
|
* Expand filesystem
|
||||||
|
* Change default password
|
||||||
|
* Enable "Wait for Network at Boot"
|
||||||
|
* Disable Desktop GUI if you don't plan to use it
|
||||||
|
|
||||||
|
### Enable serial port in Raspberry Pi 3 or Pi Zero W
|
||||||
|
|
||||||
|
Edit /boot/cmdline.txt:
|
||||||
|
|
||||||
|
sudo nano /boot/cmdline.txt
|
||||||
|
(remove the text: console=serial0,115200)
|
||||||
|
|
||||||
|
Disable services:
|
||||||
|
|
||||||
|
sudo systemctl disable serial-getty@ttyAMA0.service
|
||||||
|
sudo systemctl disable bluetooth.service
|
||||||
|
|
||||||
|
Edit /boot/config.txt
|
||||||
|
|
||||||
|
sudo nano /boot/config.txt
|
||||||
|
|
||||||
|
and add the following lines at the end of /boot/config.txt:
|
||||||
|
|
||||||
|
enable_uart=1
|
||||||
|
dtoverlay=pi3-disable-bt
|
||||||
|
|
||||||
|
Reboot your RPi:
|
||||||
|
|
||||||
|
sudo reboot
|
||||||
|
|
||||||
|
### Enable serial port in Raspberry Pi 2
|
||||||
|
|
||||||
|
Edit /boot/cmdline.txt:
|
||||||
|
|
||||||
|
sudo nano /boot/cmdline.txt
|
||||||
|
(remove the text: console=serial0,115200)
|
||||||
|
|
||||||
|
Disable the service:
|
||||||
|
|
||||||
|
sudo systemctl disable serial-getty@ttyAMA0.service
|
||||||
|
|
||||||
|
Reboot your RPi:
|
||||||
|
|
||||||
|
sudo reboot
|
||||||
|
|
||||||
|
### Build the firmware and upload to ZUMspot RPi
|
||||||
|
|
||||||
|
If you are using Pi-Star, expand filesystem (if you haven't done before):
|
||||||
|
|
||||||
|
sudo pistar-expand
|
||||||
|
sudo reboot
|
||||||
|
|
||||||
|
Enable RW filesystem if you are using Pi-Star:
|
||||||
|
|
||||||
|
rpi-rw
|
||||||
|
|
||||||
|
Install the necessary software tools:
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install gcc-arm-none-eabi gdb-arm-none-eabi libstdc++-arm-none-eabi-newlib libnewlib-arm-none-eabi
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
git clone https://git.code.sf.net/p/stm32flash/code stm32flash
|
||||||
|
cd stm32flash
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
Download the firmware sources:
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
git clone https://github.com/juribeparada/MMDVM_HS
|
||||||
|
cd MMDVM_HS/
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
(Please do not download any different code inside MMDVM_HS folder)
|
||||||
|
|
||||||
|
Edit Config.h
|
||||||
|
|
||||||
|
nano Config.h
|
||||||
|
|
||||||
|
and enable:
|
||||||
|
|
||||||
|
#define ZUMSPOT_ADF7021
|
||||||
|
#define ENABLE_ADF7021
|
||||||
|
#define ADF7021_14_7456
|
||||||
|
#define STM32_USART1_HOST
|
||||||
|
#define ENABLE_SCAN_MODE
|
||||||
|
|
||||||
|
Build the firmware:
|
||||||
|
|
||||||
|
make
|
||||||
|
|
||||||
|
If you are using Pi-Star, stop services:
|
||||||
|
|
||||||
|
sudo pistar-watchdog.service stop
|
||||||
|
sudo systemctl stop mmdvmhost.timer
|
||||||
|
sudo systemctl stop mmdvmhost.service
|
||||||
|
|
||||||
|
Upload the firmware to ZUMspot RPi board:
|
||||||
|
|
||||||
|
sudo make zumspot-pi
|
||||||
|
|
||||||
|
Install MMDVMHost:
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
git clone https://github.com/g4klx/MMDVMHost/
|
||||||
|
cd MMDVMHost/
|
||||||
|
make
|
||||||
|
|
||||||
|
Edit MMDVM.ini according your preferences
|
||||||
|
|
||||||
|
nano MMDVM.ini
|
||||||
|
(use Port=/dev/ttyAMA0 in [Modem])
|
||||||
|
|
||||||
|
Execute MMDVMHost:
|
||||||
|
|
||||||
|
./MMDVMHost MMDVM.ini
|
||||||
|
|
||||||
|
# ZUMspot Libre Kit
|
||||||
|
|
||||||
|
## Windows with Arduino IDE
|
||||||
|
|
||||||
|
Download and install the Arduino IDE:
|
||||||
|
|
||||||
|
https://www.arduino.cc/en/Main/Software
|
||||||
|
|
||||||
|
Run Arduino IDE. On the Tools menu, select the Boards manager, and install the "Arduino SAM" from the list of available boards.
|
||||||
|
|
||||||
|
Download STM32duino (Arduino for STM32) from this URL:
|
||||||
|
|
||||||
|
https://github.com/rogerclarkmelbourne/Arduino_STM32/tree/ZUMspot
|
||||||
|
|
||||||
|
Unzip and change the extracted folder name "Arduino_STM32-ZUMspot" to "Arduino_STM32"
|
||||||
|
|
||||||
|
Copy Arduino_STM32 folder in:
|
||||||
|
|
||||||
|
My Documents/Arduino/hardware
|
||||||
|
|
||||||
|
Install the USB bootloader to STM32F103. Follow the instructions:
|
||||||
|
|
||||||
|
https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki/stm32duino-bootloader
|
||||||
|
|
||||||
|
Connect the ZUMspot Libre Kit to your PC. Install the USB Mapple driver using the bat file (you may also check http://wiki.stm32duino.com/index.php?title=Windows_driver_installation):
|
||||||
|
|
||||||
|
My Documents/Arduino/hardware/Arduino_STM32/drivers/win/install_drivers.bat
|
||||||
|
|
||||||
|
You have to be sure that Windows detect your ZUMspot as an USB serial device COMx (please see Windows Device Manager).
|
||||||
|
|
||||||
|
Download the source (zip file) of MMDVM_HS from:
|
||||||
|
|
||||||
|
https://github.com/juribeparada/MMDVM_HS
|
||||||
|
|
||||||
|
Do not download or install the STM32F103 library (STM32F10X_Lib) this is not necessary under STM32duino.
|
||||||
|
|
||||||
|
Unzip MMDVM_HS-master.zip and change the folder name to "MMDVM_HS". The path name to this folder can't have spaces.
|
||||||
|
|
||||||
|
Start the Arduino IDE. Open the MMDVM_HS.ino file in the MMDVM_HS folder.
|
||||||
|
|
||||||
|
Under the menu "Tools" select "Board" and then select:
|
||||||
|
|
||||||
|
Board: Generic STM32F103C Series
|
||||||
|
Variant: STM32F103C8 (20k RAM, 64k Flash)
|
||||||
|
CPU Speed: 72 MHz (Normal)
|
||||||
|
Upload method: STM32duino bootloader (you have transfered the USB bootloader before)
|
||||||
|
Serial port: COMx (Maple Mini)
|
||||||
|
|
||||||
|
Edit Config.h:
|
||||||
|
|
||||||
|
#define LIBRE_KIT_ADF7021
|
||||||
|
#define ENABLE_ADF7021
|
||||||
|
#define ADF7021_14_7456
|
||||||
|
#define STM32_USB_HOST
|
||||||
|
#define ENABLE_SCAN_MODE
|
||||||
|
|
||||||
|
Click the Upload button in the IDE and wait for the transfer.
|
||||||
|
|
||||||
|
Once the transfer is completed, press the RESET button of the board or disconnect and connect the USB cable. You will see the LED (PC13) of the blue pill blinking. Once you connect with MMDVMHost, the LED will blink fast.
|
||||||
|
|
||||||
|
For further help with STM32duino and STM32F103 blue pill boards, please see the STM32duino [forum](http://www.stm32duino.com).
|
||||||
|
|
||||||
|
## Windows with command line
|
||||||
|
|
||||||
|
Download the source code (zip file) of MMDVM_HS from:
|
||||||
|
|
||||||
|
https://github.com/juribeparada/MMDVM_HS
|
||||||
|
|
||||||
|
Unzip MMDVM_HS-master.zip and change the folder name to "MMDVM_HS". The path name to this folder can't have spaces.
|
||||||
|
|
||||||
|
Download the ST libraries STM32F10X_Lib-master.zip from:
|
||||||
|
|
||||||
|
https://github.com/juribeparada/STM32F10X_Lib/
|
||||||
|
|
||||||
|
Extract the STM32F10X_Lib-master folder into the same folder as the MMDVM_HS. Change the folder name to "STM32F10X_Lib".
|
||||||
|
|
||||||
|
Download the GNU make utility:
|
||||||
|
|
||||||
|
http://gnuwin32.sourceforge.net/packages/make.htm
|
||||||
|
|
||||||
|
Download the binaries zip file and extract make.exe and put it in the same directory MMDVM_HS. Download the dependencies zip file and extract libintl3.dll and libiconv2.dll and put them in the same directory MMDVM_HS.
|
||||||
|
|
||||||
|
Download the GNU ARM embedded toolchain from here:
|
||||||
|
|
||||||
|
https://launchpad.net/gcc-arm-embedded/+download
|
||||||
|
|
||||||
|
Currently the direct link to the installer is here:
|
||||||
|
https://launchpad.net/gcc-arm-embedded/5.0/5-2016-q3-update/+download/gcc-arm-none-eabi-5_4-2016q3-20160926-win32.exe
|
||||||
|
|
||||||
|
Download STM32duino (Arduino for STM32) from this URL (only for USB drivers):
|
||||||
|
|
||||||
|
https://github.com/rogerclarkmelbourne/Arduino_STM32/tree/ZUMspot
|
||||||
|
|
||||||
|
Unzip and copy Arduino_STM32-ZUMspot folder in (for example):
|
||||||
|
|
||||||
|
C:\Arduino_STM32-ZUMspot
|
||||||
|
|
||||||
|
Connect the ZUMspot Libre Kit to your PC. Install the USB Mapple driver using the bat file (you may also check http://wiki.stm32duino.com/index.php?title=Windows_driver_installation):
|
||||||
|
|
||||||
|
C:\Arduino_STM32-ZUMspot\drivers\win\install_drivers.bat
|
||||||
|
|
||||||
|
Once the USB driver is installed, you may delete "C:\Arduino_STM32-ZUMspot" folder.
|
||||||
|
|
||||||
|
Launch the "GCC Command Prompt" from "GNU Tools for ARM Embedded Processors" (Start Menu) and
|
||||||
|
cd to the folder where you put the MMDVM_HS folder.
|
||||||
|
|
||||||
|
Edit Config.h according your preferences. The default Config.h is OK for ZUMSpot Libre Kit.
|
||||||
|
|
||||||
|
Build the firmware:
|
||||||
|
|
||||||
|
make clean
|
||||||
|
make bl
|
||||||
|
|
||||||
|
Press the reset button of ZUMspot and upload the firmware:
|
||||||
|
|
||||||
|
make dfu
|
||||||
|
|
||||||
|
## Linux Raspbian
|
||||||
|
|
||||||
|
If you are using Pi-Star, expand filesystem (if you haven't done before):
|
||||||
|
|
||||||
|
sudo pistar-expand
|
||||||
|
sudo reboot
|
||||||
|
|
||||||
|
Enable RW filesystem if you are using Pi-Star:
|
||||||
|
|
||||||
|
rpi-rw
|
||||||
|
|
||||||
|
Install the necessary software tools:
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install gcc-arm-none-eabi gdb-arm-none-eabi libstdc++-arm-none-eabi-newlib libnewlib-arm-none-eabi
|
||||||
|
|
||||||
|
Download the sources:
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
git clone https://github.com/juribeparada/MMDVM_HS
|
||||||
|
cd MMDVM_HS/
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
(Please do not download any different code inside MMDVM_HS folder)
|
||||||
|
|
||||||
|
Edit Config.h:
|
||||||
|
|
||||||
|
nano Config.h
|
||||||
|
|
||||||
|
and enable:
|
||||||
|
|
||||||
|
#define LIBRE_KIT_ADF7021
|
||||||
|
#define ENABLE_ADF7021
|
||||||
|
#define ADF7021_14_7456
|
||||||
|
#define STM32_USB_HOST
|
||||||
|
#define ENABLE_SCAN_MODE
|
||||||
|
|
||||||
|
Build the firmware with bootloader support:
|
||||||
|
|
||||||
|
make bl
|
||||||
|
|
||||||
|
If you are using Pi-Star, stop services:
|
||||||
|
|
||||||
|
sudo pistar-watchdog.service stop
|
||||||
|
sudo systemctl stop mmdvmhost.timer
|
||||||
|
sudo systemctl stop mmdvmhost.service
|
||||||
|
|
||||||
|
Upload bootloader and firmware to ZUMspot Libre Kit, using serial port first (you are using an USB-serial converter with device name /dev/ttyUSB0). Move BOOT0 jumper to 1, next press and release RESET and execute:
|
||||||
|
|
||||||
|
sudo make serial-bl devser=/dev/ttyUSB0
|
||||||
|
|
||||||
|
Move BOOT0 jumper to 0.
|
||||||
|
|
||||||
|
For following firmware updates, you could use the USB port directly:
|
||||||
|
|
||||||
|
sudo make dfu devser=/dev/ttyACM0
|
||||||
|
|
||||||
|
Install MMDVMHost:
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
git clone https://github.com/g4klx/MMDVMHost/
|
||||||
|
cd MMDVMHost/
|
||||||
|
make
|
||||||
|
|
||||||
|
Edit MMDVM.ini according your preferences
|
||||||
|
|
||||||
|
nano MMDVM.ini
|
||||||
|
(use Port=/dev/ttyACM0 in [Modem])
|
||||||
|
|
||||||
|
Execute MMDVMHost:
|
||||||
|
|
||||||
|
./MMDVMHost MMDVM.ini
|
||||||
|
|
||||||
|
# ZUMspot USB
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
|
||||||
|
Download and install the Arduino IDE:
|
||||||
|
|
||||||
|
https://www.arduino.cc/en/Main/Software
|
||||||
|
|
||||||
|
Run Arduino IDE. On the Tools menu, select the Boards manager, and install the "Arduino SAM" from the list of available boards.
|
||||||
|
|
||||||
|
Download STM32duino (Arduino for STM32) from this URL:
|
||||||
|
|
||||||
|
https://github.com/rogerclarkmelbourne/Arduino_STM32/tree/ZUMspot
|
||||||
|
|
||||||
|
Unzip and change the extracted folder name "Arduino_STM32-ZUMspot" to "Arduino_STM32"
|
||||||
|
|
||||||
|
Copy Arduino_STM32 folder in:
|
||||||
|
|
||||||
|
My Documents/Arduino/hardware
|
||||||
|
|
||||||
|
Connect the ZUMspot USB to your PC. Install the USB Mapple driver using the bat file:
|
||||||
|
|
||||||
|
My Documents/Arduino/hardware/Arduino_STM32/drivers/win/install_drivers.bat
|
||||||
|
(you may also check: http://wiki.stm32duino.com/index.php?title=Windows_driver_installation)
|
||||||
|
|
||||||
|
You have to be sure that Windows detect your ZUMspot as an USB serial device COMx (please
|
||||||
|
see Windows Device Manager)
|
||||||
|
|
||||||
|
Download the source (zip file) of MMDVM_HS from:
|
||||||
|
|
||||||
|
https://github.com/juribeparada/MMDVM_HS
|
||||||
|
|
||||||
|
Do not download or install the STM32F103 library, STM32F10X_Lib, this is not necessary
|
||||||
|
under STM32duino.
|
||||||
|
|
||||||
|
Unzip MMDVM_HS-master.zip and change the folder name to "MMDVM_HS". The path name to this
|
||||||
|
folder can't have spaces.
|
||||||
|
|
||||||
|
Start the Arduino IDE. Open the MMDVM_HS.ino file in the MMDVM_HS folder.
|
||||||
|
|
||||||
|
Under the menu "Tools" select "Board" and then select:
|
||||||
|
|
||||||
|
Board: Generic STM32F103C Series
|
||||||
|
Variant: STM32F103C8 (20k RAM, 64k Flash)
|
||||||
|
CPU Speed: 72 MHz (Normal)
|
||||||
|
Upload method: STM32duino bootloader (you have transfered the USB bootloader before)
|
||||||
|
Serial port: COMx (Maple Mini)
|
||||||
|
|
||||||
|
Edit Config.h:
|
||||||
|
|
||||||
|
#define ZUMSPOT_ADF7021
|
||||||
|
#define ENABLE_ADF7021
|
||||||
|
#define ADF7021_14_7456
|
||||||
|
#define STM32_USB_HOST
|
||||||
|
#define ENABLE_SCAN_MODE
|
||||||
|
|
||||||
|
Click the Upload button in the IDE and wait for the transfer.
|
||||||
|
|
||||||
|
Once the transfer is completed, press the RESET button of the board or disconnect and
|
||||||
|
connect the USB cable.
|
||||||
|
|
||||||
|
## Linux Raspbian
|
||||||
|
|
||||||
|
If you are using Pi-Star, expand filesystem (if you haven't done before):
|
||||||
|
|
||||||
|
sudo pistar-expand
|
||||||
|
sudo reboot
|
||||||
|
|
||||||
|
Enable RW filesystem if you are using Pi-Star:
|
||||||
|
|
||||||
|
rpi-rw
|
||||||
|
|
||||||
|
Install the necessary software tools:
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install gcc-arm-none-eabi gdb-arm-none-eabi libstdc++-arm-none-eabi-newlib libnewlib-arm-none-eabi
|
||||||
|
|
||||||
|
Download the sources:
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
git clone https://github.com/juribeparada/MMDVM_HS
|
||||||
|
cd MMDVM_HS/
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
|
||||||
|
(Please do not download any different code inside MMDVM_HS folder)
|
||||||
|
|
||||||
|
Edit Config.h
|
||||||
|
|
||||||
|
nano Config.h
|
||||||
|
|
||||||
|
and enable:
|
||||||
|
|
||||||
|
#define ZUMSPOT_ADF7021
|
||||||
|
#define ENABLE_ADF7021
|
||||||
|
#define ADF7021_14_7456
|
||||||
|
#define STM32_USB_HOST
|
||||||
|
#define ENABLE_SCAN_MODE
|
||||||
|
|
||||||
|
Build the firmware with bootloader support:
|
||||||
|
|
||||||
|
make bl
|
||||||
|
|
||||||
|
If you are using Pi-Star, stop services:
|
||||||
|
|
||||||
|
sudo pistar-watchdog.service stop
|
||||||
|
sudo systemctl stop mmdvmhost.timer
|
||||||
|
sudo systemctl stop mmdvmhost.service
|
||||||
|
|
||||||
|
Upload the firmware to ZUMspot USB:
|
||||||
|
|
||||||
|
sudo make dfu devser=/dev/ttyACM0
|
||||||
|
|
||||||
|
Install MMDVMHost:
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
git clone https://github.com/g4klx/MMDVMHost/
|
||||||
|
cd MMDVMHost/
|
||||||
|
make
|
||||||
|
|
||||||
|
Edit MMDVM.ini according your preferences
|
||||||
|
|
||||||
|
nano MMDVM.ini
|
||||||
|
(use Port=/dev/ttyACM0 in [Modem])
|
||||||
|
|
||||||
|
Execute MMDVMHost:
|
||||||
|
|
||||||
|
./MMDVMHost MMDVM.ini
|
||||||
|
|
||||||
|
# MMDVM_HS_Hat
|
||||||
|
|
||||||
|
Please check here for detailed instructions:
|
||||||
|
|
||||||
|
https://github.com/mathisschmieder/MMDVM_HS_Hat/blob/master/README.md
|
||||||
|
|
||||||
|
# Makefile options
|
||||||
|
|
||||||
|
- make clean: delete all objects files *.o, for starting a new firmware building.
|
||||||
|
|
||||||
|
- make: it builds a standard firmware (without USB bootloader support).
|
||||||
|
|
||||||
|
- make bl: it builds a firmware with USB bootloader support.
|
||||||
|
|
||||||
|
- make zumspot-pi: upload the firmware to a ZUMspot RPi version (using internal RPi serial port)
|
||||||
|
|
||||||
|
- make mmdvm_hs_hat: upload the firmware to MMDVM_HS_Hat board (using internal RPi serial port)
|
||||||
|
|
||||||
|
- make nano-hotspot: upload the firmware to Nano hotSPOT board (using internal serial port)
|
||||||
|
|
||||||
|
- make nano-dv: upload the firmware to NanoDV board (using internal serial port)
|
||||||
|
|
||||||
|
- make d2rg_mmdvm_hs: upload the firmware to D2RG MMDVM_HS board (using internal serial port)
|
||||||
|
|
||||||
|
- make skybridge: upload the firmware to SkyBridge HotSpot board (using internal serial port)
|
||||||
|
|
||||||
|
- make dfu [devser=/dev/ttyXXX]: upload firmware using USB bootloader. "devser" is optional, and it corresponds to the USB serial port device name. This option permits to perform a reset to enter to booloader mode (DFU). If you don't use "devser", you have to press the reset button of the ZUMspot just before using this command.
|
||||||
|
|
||||||
|
- make serial devser=/dev/ttyXXX: upload standard firmware using serial port bootloader method.
|
||||||
|
|
||||||
|
- make serial-bl devser=/dev/ttyXXX: upload firmware with USB bootloader support using serial port bootloader method.
|
||||||
|
|
||||||
|
- make serial-nobl devser=/dev/ttyXXX: upload firmware with USB support using serial port bootloader method, but without USB bootloader installation.
|
||||||
|
|
||||||
|
- make serial-bl-old devser=/dev/ttyXXX: same as "make serial-bl" but using bootloader with short reset pulse.
|
||||||
|
|
||||||
|
- make stlink: upload standard firmware using ST-Link interface.
|
||||||
|
|
||||||
|
- make stlink-bl: upload firmware with USB bootloader support using ST-Link interface.
|
||||||
|
|
||||||
|
- make stlink-nobl: upload firmware with USB support using ST-Link interface, but without USB bootloader.
|
||||||
|
|
||||||
|
- make stlink-bl-old: same as "make stlink-bl" but using bootloader with short reset pulse.
|
||||||
|
|
||||||
|
- make ocd: upload standard firmware using ST-Link interface. This method uses a local openocd installation.
|
||||||
|
|
||||||
|
- make ocd-nobl: upload firmware with USB support using ST-Link interface, but without USB bootloader. This method uses a local openocd installation.
|
||||||
|
|
||||||
|
- make ocd-bl: upload firmware with USB bootloader support using ST-Link interface. This method uses a local openocd installation.
|
||||||
|
|
||||||
|
- make ocd-bl-old: same as "make ocd-bl" but using bootloader with short reset pulse.
|
||||||
|
|
||||||
|
## Common Makefile commands
|
||||||
|
|
||||||
|
Serial programming (first programming, transfer the USB bootloader):
|
||||||
|
|
||||||
|
make clean
|
||||||
|
make bl
|
||||||
|
sudo make serial-bl devser=/dev/ttyUSB0
|
||||||
|
|
||||||
|
USB programming (you have already transfered the USB bootloader):
|
||||||
|
|
||||||
|
make clean
|
||||||
|
make bl
|
||||||
|
sudo make dfu (reset ZUMspot before) or
|
||||||
|
sudo make dfu devser=/dev/ttyACM0 (/dev/ttyACM0 is the device name of ZUMspot USB under Raspbian)
|
||||||
|
|
||||||
|
ZUMspot RPi (no USB support needed):
|
||||||
|
|
||||||
|
make clean
|
||||||
|
make
|
||||||
|
sudo make zumspot-pi
|
||||||
|
|
||||||
|
# Config.h options
|
||||||
|
|
||||||
|
- #define ZUMSPOT_ADF7021: enable pinouts support for ZUMspot RPi or ZUMspot USB. You have to enable this option if you have one of these products.
|
||||||
|
|
||||||
|
- #define LIBRE_KIT_ADF7021: enable this option if you have a ZUMspot Libre Kit (Board with modified RF7021SE and Blue Pill STM32F103).
|
||||||
|
|
||||||
|
- #define MMDVM_HS_HAT_REV12: enable this option if you have a MMDVM_HS_Hat board for RPi.
|
||||||
|
|
||||||
|
- #define MMDVM_HS_DUAL_HAT_REV10: enable this option if you have a MMDVM_HS_Dual_Hat board for RPi/USB.
|
||||||
|
|
||||||
|
- #define NANO_HOTSPOT: enable this option if you have a Nano hotSPOT (BI7JTA).
|
||||||
|
|
||||||
|
- #define NANO_DV_REV10: enable this option if you have a Nano DV (BG4TGO & BG5HHP).
|
||||||
|
|
||||||
|
- #define ENABLE_ADF7021: add support for ADF7021 (all boards, enabled by default).
|
||||||
|
|
||||||
|
- #define DUPLEX: enable duplex mode with dual ADF7021. It is still under development.
|
||||||
|
|
||||||
|
- #define ADF7021_14_7456: select this option if your board uses a 14.7456 MHz (enabled by default).
|
||||||
|
|
||||||
|
- #define ADF7021_12_2880: select this option if your board uses a 12.2880 MHz.
|
||||||
|
|
||||||
|
- #define STM32_USART1_HOST: enable direct serial host communication with ZUMspot (using USART1 PA9 and PA10 pins). Disable STM32_USB_HOST if you enable this option. Enable this if you have a ZUMspot RPi. You don't need to enable this option if you will transfer the bootloader.
|
||||||
|
|
||||||
|
- #define STM32_USB_HOST: enable USB host communication with ZUMspot (using STM32F103 USB interface). Disable STM32_USART1_HOST if you enable this option. Enable this if you have a ZUMspot USB or ZUMspot Libre Kit.
|
||||||
|
|
||||||
|
- #define ENABLE_SCAN_MODE: enable automatic mode detection in ZUMspot. This is based on scanning over all enabled modes, and you could have some detection delay. Enabled by default.
|
||||||
|
|
||||||
|
- #define SEND_RSSI_DATA: enable RSSI reports to MMDVMHost. It is already converted to dBm.
|
||||||
|
|
||||||
|
- #define SERIAL_REPEATER: enable a second serial port (USART2, pins PA2 and PA3) for Nextion LCD display.
|
||||||
|
|
||||||
|
- #define SERIAL_REPEATER_USART1: enable USART1 (pins PA9 and PA10) for Nextion LCD display. Do not use with STM32_USART1_HOST enabled, only with USB host communication.
|
||||||
|
|
||||||
|
- #define ENABLE_P25_WIDE: enable support for Motorola Wide P25 mod/demod in XTS3000 radios. Using this mode improves RX BER. You need to enable this mode in your radio for each conventional personalities.
|
||||||
|
|
||||||
|
- #define QUIET_MODE_LEDS: disable mode LEDs blink during scan mode.
|
||||||
|
|
||||||
|
# Pinout definitions
|
||||||
|
|
||||||
|
## Pinout definitions for ZUMspot Libre Kit
|
||||||
|
|
||||||
|
This is the carrier board or any board with RF7021SE + STM32F103.
|
||||||
|
|
||||||
|
Main RF7021SE board:
|
||||||
|
|
||||||
|
CE PC14
|
||||||
|
SLE PB8
|
||||||
|
SREAD PB7
|
||||||
|
SDATA PB6
|
||||||
|
SCLK PB5
|
||||||
|
DATA PB4 (TxRxData)*
|
||||||
|
DCLK PB3 (TxRxCLK)*
|
||||||
|
CLKOUT PA15 (jumper wire in RF7021SE, not needed with BIDIR_DATA_PIN enabled)
|
||||||
|
PAC PB14 (PTT LED)
|
||||||
|
VCC 3.3 V
|
||||||
|
GND Ground
|
||||||
|
|
||||||
|
Second RF7021SE board (duplex mode, experimental):
|
||||||
|
|
||||||
|
SLE PA6
|
||||||
|
DATA PA4 (TxRxData)*
|
||||||
|
DCLK PA5 (TxRxCLK)*
|
||||||
|
PAC NC
|
||||||
|
CLKOUT NC
|
||||||
|
VCC 3.3 V
|
||||||
|
GND Ground
|
||||||
|
|
||||||
|
SDATA, SREAD, SCLK and CE are shared with the main ADF7021.
|
||||||
|
|
||||||
|
Serial ports:
|
||||||
|
|
||||||
|
TXD PA9 (serial port host communication)
|
||||||
|
RXD PA10 (serial port host communication)
|
||||||
|
DISP_TXD PA2 (Nextion LCD serial repeater)
|
||||||
|
DISP_RXD PA3 (Nextion LCD serial repeater)
|
||||||
|
|
||||||
|
Status LEDs:
|
||||||
|
|
||||||
|
COS_LED PB15
|
||||||
|
PTT_LED PB14
|
||||||
|
NXDN_LED PA8
|
||||||
|
P25_LED PB0
|
||||||
|
YSF_LED PB1
|
||||||
|
DMR_LED PB13
|
||||||
|
DSTAR_LED PB12
|
||||||
|
|
||||||
|
Misc pins:
|
||||||
|
|
||||||
|
PIN_LED PC13 (status led)
|
||||||
|
PIN_DEB PB9 (debugging pin)
|
||||||
|
|
||||||
|
You could install a serie resistor (10 - 100 ohms) in each TxRxData and TxRxCLK lines, for reducing EMI.
|
||||||
|
|
||||||
|
## Pinout definitions for Arduino Due/Zero + RF7021SE
|
||||||
|
|
||||||
|
Use Arduino IDE with SAM support for building the code.
|
||||||
|
|
||||||
|
Main RF7021SE board:
|
||||||
|
|
||||||
|
CE 12
|
||||||
|
SLE 6
|
||||||
|
SREAD 5
|
||||||
|
SDATA 4 // 2 in Arduino Zero Pro
|
||||||
|
SCLK 3
|
||||||
|
DATA 7 (TxRxData)*
|
||||||
|
DCLK 8 (TxRxCLK)*
|
||||||
|
CLKOUT 2 // 4 in Arduino Zero Pro (jumper wire in RF7021SE, not needed with BIDIR_DATA_PIN enabled)
|
||||||
|
PAC 9 (PTT LED)
|
||||||
|
VCC 3.3 V
|
||||||
|
GND Ground
|
||||||
|
|
||||||
|
Serial ports:
|
||||||
|
|
||||||
|
USB Arduino Programming Port (host communication)
|
||||||
|
|
||||||
|
Status LEDs:
|
||||||
|
|
||||||
|
COS_LED 10
|
||||||
|
PTT_LED 9
|
||||||
|
NXDN_LED 18
|
||||||
|
P25_LED 17
|
||||||
|
YSF_LED 16
|
||||||
|
DMR_LED 15
|
||||||
|
DSTAR_LED 14
|
||||||
|
|
||||||
|
Misc pins:
|
||||||
|
|
||||||
|
PIN_LED 13
|
||||||
|
PIN_DEB 11
|
||||||
|
|
||||||
|
You could install a serie resistor (10 - 100 ohms) in each TxRxData and TxRxCLK lines, for reducing EMI.
|
||||||
|
|
||||||
|
## Pinout definitions for Teensy (3.1, 3.2, 3.5 or 3.6) + RF7021SE:
|
||||||
|
|
||||||
|
Use Teensyduino + Arduino IDE for building the code.
|
||||||
|
|
||||||
|
Main RF7021SE board:
|
||||||
|
|
||||||
|
CE 6
|
||||||
|
SLE 5
|
||||||
|
SREAD 4
|
||||||
|
SDATA 3
|
||||||
|
SCLK 2
|
||||||
|
DATA 7 (TxRxData)*
|
||||||
|
DCLK 8 (TxRxCLK)*
|
||||||
|
CLKOUT 22 (jumper wire in RF7021SE, not needed with BIDIR_DATA_PIN enabled)
|
||||||
|
PAC 14 (PTT LED)
|
||||||
|
VCC 3.3 V
|
||||||
|
GND Ground
|
||||||
|
|
||||||
|
Serial ports:
|
||||||
|
|
||||||
|
Teensy USB Port (host communication)
|
||||||
|
DISP_TXD 1 (Nextion LCD serial repeater)
|
||||||
|
DISP_RXD 0 (Nextion LCD serial repeater)
|
||||||
|
|
||||||
|
Status LEDs:
|
||||||
|
|
||||||
|
COS_LED 15
|
||||||
|
PTT_LED 14
|
||||||
|
NXDN_LED 20
|
||||||
|
P25_LED 19
|
||||||
|
YSF_LED 18
|
||||||
|
DMR_LED 17
|
||||||
|
DSTAR_LED 16
|
||||||
|
|
||||||
|
Misc pins:
|
||||||
|
|
||||||
|
PIN_LED 13
|
||||||
|
PIN_DEB 23
|
||||||
|
|
||||||
|
You could install a serie resistor (10 - 100 ohms) in each TxRxData and TxRxCLK lines, for reducing EMI.
|
||||||
|
|
||||||
|
# Hidden functions
|
||||||
|
|
||||||
|
You could enable two test modes, if you edit ADF7021.h file before compilation. Please always comment these two #defines for normal operation.
|
||||||
|
|
||||||
|
- #define TEST_DAC: Enable SWD pin to access the demodulator output signal. See application note AN-852 and ADF7021 datasheet, page 60.
|
||||||
|
|
||||||
|
- #define TEST_TX: Transmit the carrier frequency. This works only with D-Star mode enabled in MMDVM.ini. This test mode will transmit the carrier frequency defined with TXFrequency in MMDVM.ini. This could be useful to determine the frequency offset of your ZUMspot (with test equipment).
|
||||||
|
|
||||||
|
Also in ADF7021.h:
|
||||||
|
|
||||||
|
- #define ADF7021_N_VER: enable support for narrow band version of ADF7021 (ADF7021N). Disabled by default, in general all boards will have just ADF7021.
|
||||||
|
|
||||||
|
- #define ADF7021_ENABLE_4FSK_AFC: enable AFC support for DMR, YSF and P25. This is experimental, depending on your frequency offset this option will improve or not your BER reception.
|
||||||
|
|
||||||
|
- #define ADF7021_AFC_POS: enable this option if you can not receive any signal after enable the ADF7021_ENABLE_4FSK_AFC option.
|
||||||
|
|
||||||
|
- #define ADF7021_DISABLE_RC_4FSK: disable TX Raised Cosine filter for 4FSK modulation in ADF7021. Default TX pulse shaping filter for 4FSK is not optimum for DMR, YSF and P25. Activating this option might improve audio in 4FSK digital modes.
|
||||||
|
|
||||||
|
In Globals.h:
|
||||||
|
|
||||||
|
- #define BIDIR_DATA_PIN: enable Standard TX/RX Data Interface of ADF7021 (enabled by default, needed for scanning mode detection feature).
|
||||||
|
|
||||||
|
In IOSTM.cpp:
|
||||||
|
|
||||||
|
- #define PI_HAT_7021_REV_02: enable pinouts for first revision of ZUMspot RPi. In general is not used.
|
||||||
@ -0,0 +1,145 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin KI6ZUM
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "BitBuffer.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the BitBuffer class.
|
||||||
|
/// </summary>
|
||||||
|
BitBuffer::BitBuffer(uint16_t length) :
|
||||||
|
m_length(length),
|
||||||
|
m_bits(NULL),
|
||||||
|
m_control(NULL),
|
||||||
|
m_head(0U),
|
||||||
|
m_tail(0U),
|
||||||
|
m_full(false),
|
||||||
|
m_overflow(false)
|
||||||
|
{
|
||||||
|
m_bits = new uint8_t[length / 8U];
|
||||||
|
m_control = new uint8_t[length / 8U];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to get how much space the ring buffer has for samples.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint16_t BitBuffer::getSpace() const
|
||||||
|
{
|
||||||
|
uint16_t n = 0U;
|
||||||
|
|
||||||
|
if (m_tail == m_head)
|
||||||
|
n = m_full ? 0U : m_length;
|
||||||
|
else if (m_tail < m_head)
|
||||||
|
n = m_length - m_head + m_tail;
|
||||||
|
else
|
||||||
|
n = m_tail - m_head;
|
||||||
|
|
||||||
|
if (n > m_length)
|
||||||
|
n = 0U;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint16_t BitBuffer::getData() const
|
||||||
|
{
|
||||||
|
if (m_tail == m_head)
|
||||||
|
return m_full ? m_length : 0U;
|
||||||
|
else if (m_tail < m_head)
|
||||||
|
return m_head - m_tail;
|
||||||
|
else
|
||||||
|
return m_length - m_tail + m_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool BitBuffer::put(uint8_t bit, uint8_t control)
|
||||||
|
{
|
||||||
|
if (m_full) {
|
||||||
|
m_overflow = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_BIT(m_bits, m_head, bit);
|
||||||
|
WRITE_BIT(m_control, m_head, control);
|
||||||
|
|
||||||
|
m_head++;
|
||||||
|
if (m_head >= m_length)
|
||||||
|
m_head = 0U;
|
||||||
|
|
||||||
|
if (m_head == m_tail)
|
||||||
|
m_full = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool BitBuffer::get(uint8_t& bit, uint8_t& control)
|
||||||
|
{
|
||||||
|
if (m_head == m_tail && !m_full)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bit = READ_BIT(m_bits, m_tail);
|
||||||
|
control = READ_BIT(m_control, m_tail);
|
||||||
|
|
||||||
|
m_full = false;
|
||||||
|
|
||||||
|
m_tail++;
|
||||||
|
if (m_tail >= m_length)
|
||||||
|
m_tail = 0U;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool BitBuffer::hasOverflowed()
|
||||||
|
{
|
||||||
|
bool overflow = m_overflow;
|
||||||
|
m_overflow = false;
|
||||||
|
|
||||||
|
return overflow;
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin KI6ZUM
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#if !defined(__BIT_RB_H__)
|
||||||
|
#define __BIT_RB_H__
|
||||||
|
|
||||||
|
#if defined(STM32F10X_MD)
|
||||||
|
#include "stm32f10x.h"
|
||||||
|
#elif defined(STM32F4XX)
|
||||||
|
#include "stm32f4xx.h"
|
||||||
|
#include <cstddef>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements a circular buffer for bit data.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API BitBuffer {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the BitBuffer class.</summary>
|
||||||
|
BitBuffer(uint16_t length);
|
||||||
|
|
||||||
|
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
|
||||||
|
uint16_t getSpace() const;
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
uint16_t getData() const;
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
bool put(uint8_t bit, uint8_t control);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
bool get(uint8_t& bit, uint8_t& control);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
bool hasOverflowed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t m_length;
|
||||||
|
volatile uint8_t* m_bits;
|
||||||
|
volatile uint8_t* m_control;
|
||||||
|
|
||||||
|
volatile uint16_t m_head;
|
||||||
|
volatile uint16_t m_tail;
|
||||||
|
|
||||||
|
volatile bool m_full;
|
||||||
|
|
||||||
|
bool m_overflow;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __BIT_RB_H__
|
||||||
@ -0,0 +1,202 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "CWIdTX.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// 4FSK symbol sequence (800 Hz "tone" at 4800 baud): +1 +3 +1 -1 -3 -1
|
||||||
|
// Bit sequence: 00 01 00 10 11 10
|
||||||
|
uint8_t TONE[] = { 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0 };
|
||||||
|
|
||||||
|
uint8_t SILENCE[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
const uint8_t CYCLE_LENGTH = 12U;
|
||||||
|
|
||||||
|
const uint8_t DOT_LENGTH = 40U;
|
||||||
|
|
||||||
|
const struct {
|
||||||
|
uint8_t c;
|
||||||
|
uint32_t pattern;
|
||||||
|
uint8_t length;
|
||||||
|
} SYMBOL_LIST[] = {
|
||||||
|
{ 'A', 0xB8000000U, 8U },
|
||||||
|
{ 'B', 0xEA800000U, 12U },
|
||||||
|
{ 'C', 0xEBA00000U, 14U },
|
||||||
|
{ 'D', 0xEA000000U, 10U },
|
||||||
|
{ 'E', 0x80000000U, 4U },
|
||||||
|
{ 'F', 0xAE800000U, 12U },
|
||||||
|
{ 'G', 0xEE800000U, 12U },
|
||||||
|
{ 'H', 0xAA000000U, 10U },
|
||||||
|
{ 'I', 0xA0000000U, 6U },
|
||||||
|
{ 'J', 0xBBB80000U, 16U },
|
||||||
|
{ 'K', 0xEB800000U, 12U },
|
||||||
|
{ 'L', 0xBA800000U, 12U },
|
||||||
|
{ 'M', 0xEE000000U, 10U },
|
||||||
|
{ 'N', 0xE8000000U, 8U },
|
||||||
|
{ 'O', 0xEEE00000U, 14U },
|
||||||
|
{ 'P', 0xBBA00000U, 14U },
|
||||||
|
{ 'Q', 0xEEB80000U, 16U },
|
||||||
|
{ 'R', 0xBA000000U, 10U },
|
||||||
|
{ 'S', 0xA8000000U, 8U },
|
||||||
|
{ 'T', 0xE0000000U, 6U },
|
||||||
|
{ 'U', 0xAE000000U, 10U },
|
||||||
|
{ 'V', 0xAB800000U, 12U },
|
||||||
|
{ 'W', 0xBB800000U, 12U },
|
||||||
|
{ 'X', 0xEAE00000U, 14U },
|
||||||
|
{ 'Y', 0xEBB80000U, 16U },
|
||||||
|
{ 'Z', 0xEEA00000U, 14U },
|
||||||
|
{ '1', 0xBBBB8000U, 20U },
|
||||||
|
{ '2', 0xAEEE0000U, 18U },
|
||||||
|
{ '3', 0xABB80000U, 16U },
|
||||||
|
{ '4', 0xAAE00000U, 14U },
|
||||||
|
{ '5', 0xAA800000U, 12U },
|
||||||
|
{ '6', 0xEAA00000U, 14U },
|
||||||
|
{ '7', 0xEEA80000U, 16U },
|
||||||
|
{ '8', 0xEEEA0000U, 18U },
|
||||||
|
{ '9', 0xEEEE8000U, 20U },
|
||||||
|
{ '0', 0xEEEEE000U, 22U },
|
||||||
|
{ '/', 0xEAE80000U, 16U },
|
||||||
|
{ '?', 0xAEEA0000U, 18U },
|
||||||
|
{ ',', 0xEEAEE000U, 22U },
|
||||||
|
{ '-', 0xEAAE0000U, 18U },
|
||||||
|
{ '=', 0xEAB80000U, 16U },
|
||||||
|
{ '.', 0xBAEB8000U, 20U },
|
||||||
|
{ ' ', 0x00000000U, 4U },
|
||||||
|
{ 0U, 0x00000000U, 0U }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the CWIdTX class.
|
||||||
|
/// </summary>
|
||||||
|
CWIdTX::CWIdTX() :
|
||||||
|
m_poBuffer(),
|
||||||
|
m_poLen(0U),
|
||||||
|
m_poPtr(0U),
|
||||||
|
m_n(0U)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process local buffer and transmit on the air interface.
|
||||||
|
/// </summary>
|
||||||
|
void CWIdTX::process()
|
||||||
|
{
|
||||||
|
if (m_poLen == 0U)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > CYCLE_LENGTH) {
|
||||||
|
bool b = _READ_BIT(m_poBuffer, m_poPtr);
|
||||||
|
if (b)
|
||||||
|
io.write(TONE, CYCLE_LENGTH);
|
||||||
|
else
|
||||||
|
io.write(SILENCE, CYCLE_LENGTH);
|
||||||
|
|
||||||
|
space -= CYCLE_LENGTH;
|
||||||
|
|
||||||
|
m_n++;
|
||||||
|
if (m_n >= DOT_LENGTH) {
|
||||||
|
m_poPtr++;
|
||||||
|
m_n = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_poPtr >= m_poLen) {
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_poLen = 0U;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write CW ID data to the local buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t CWIdTX::write(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
::memset(m_poBuffer, 0x00U, 300U * sizeof(uint8_t));
|
||||||
|
|
||||||
|
m_poLen = 8U;
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_n = 0U;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < length; i++) {
|
||||||
|
for (uint8_t j = 0U; SYMBOL_LIST[j].c != 0U; j++) {
|
||||||
|
if (SYMBOL_LIST[j].c == data[i]) {
|
||||||
|
uint32_t MASK = 0x80000000U;
|
||||||
|
for (uint8_t k = 0U; k < SYMBOL_LIST[j].length; k++, m_poLen++, MASK >>= 1) {
|
||||||
|
bool b = (SYMBOL_LIST[j].pattern & MASK) == MASK;
|
||||||
|
_WRITE_BIT(m_poBuffer, m_poLen, b);
|
||||||
|
|
||||||
|
if (m_poLen >= 295U) {
|
||||||
|
m_poLen = 0U;
|
||||||
|
return 4U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// An empty message
|
||||||
|
if (m_poLen == 8U) {
|
||||||
|
m_poLen = 0U;
|
||||||
|
return RSN_ILLEGAL_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poLen += 5U;
|
||||||
|
|
||||||
|
DEBUG2("CWIdTx: write(): message created with length", m_poLen);
|
||||||
|
|
||||||
|
return RSN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to reset data values to defaults.
|
||||||
|
/// </summary>
|
||||||
|
void CWIdTX::reset()
|
||||||
|
{
|
||||||
|
m_poLen = 0U;
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_n = 0U;
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__CWID_TX_H__)
|
||||||
|
#define __CWID_TX_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements logic to transmit a CW ID.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API CWIdTX {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the CWIdTX class.</summary>
|
||||||
|
CWIdTX();
|
||||||
|
|
||||||
|
/// <summary>Process local buffer and transmit on the air interface.</summary>
|
||||||
|
void process();
|
||||||
|
|
||||||
|
/// <summary>Write CW ID data to the local buffer.</summary>
|
||||||
|
uint8_t write(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
/// <summary>Helper to reset data values to defaults.</summary>
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t m_poBuffer[300U];
|
||||||
|
uint16_t m_poLen;
|
||||||
|
uint16_t m_poPtr;
|
||||||
|
|
||||||
|
uint8_t m_n;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __CWID_TX_H__
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "CalRSSI.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the CalRSSI class.
|
||||||
|
/// </summary>
|
||||||
|
CalRSSI::CalRSSI() :
|
||||||
|
m_count(0U),
|
||||||
|
m_navg(0U),
|
||||||
|
m_accum(0U),
|
||||||
|
m_min(0xFFFFU),
|
||||||
|
m_max(0x0000U)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sample RSSI values from the air interface.
|
||||||
|
/// </summary>
|
||||||
|
void CalRSSI::process()
|
||||||
|
{
|
||||||
|
m_count++;
|
||||||
|
|
||||||
|
if (m_count >= 32000U) {
|
||||||
|
uint16_t rssi = io.readRSSI();
|
||||||
|
m_count = 0U;
|
||||||
|
m_navg++;
|
||||||
|
|
||||||
|
m_accum += rssi;
|
||||||
|
|
||||||
|
if (rssi > m_max)
|
||||||
|
m_max = rssi;
|
||||||
|
if (rssi < m_min)
|
||||||
|
m_min = rssi;
|
||||||
|
|
||||||
|
if (m_navg >= 6U) {
|
||||||
|
uint16_t ave = m_accum / 6U;
|
||||||
|
|
||||||
|
uint8_t buffer[6U];
|
||||||
|
buffer[0U] = (m_max >> 8) & 0xFFU;
|
||||||
|
buffer[1U] = (m_max >> 0) & 0xFFU;
|
||||||
|
buffer[2U] = (m_min >> 8) & 0xFFU;
|
||||||
|
buffer[3U] = (m_min >> 0) & 0xFFU;
|
||||||
|
buffer[4U] = (ave >> 8) & 0xFFU;
|
||||||
|
buffer[5U] = (ave >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
serial.writeRSSIData(buffer, 6U);
|
||||||
|
|
||||||
|
m_navg = 0U;
|
||||||
|
m_accum = 0U;
|
||||||
|
m_min = 0xFFFFU;
|
||||||
|
m_max = 0x0000U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__CAL_RSSI_H__)
|
||||||
|
#define __CAL_RSSI_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements logic for RSSI calibration mode.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API CalRSSI {
|
||||||
|
/// <summary>Initializes a new instance of the CalRSSI class.</summary>
|
||||||
|
CalRSSI();
|
||||||
|
|
||||||
|
/// <summary>Sample RSSI values from the air interface.</summary>
|
||||||
|
void process();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t m_count;
|
||||||
|
uint8_t m_navg;
|
||||||
|
uint32_t m_accum;
|
||||||
|
uint16_t m_min;
|
||||||
|
uint16_t m_max;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __CAL_RSSI_H__
|
||||||
@ -0,0 +1,148 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017,2018,2019,2020 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__DEFINES_H__)
|
||||||
|
#define __DEFINES_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <arm_math.h>
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Types
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _INT8_T_DECLARED
|
||||||
|
#ifndef __INT8_TYPE__
|
||||||
|
typedef signed char int8_t;
|
||||||
|
#endif // __INT8_TYPE__
|
||||||
|
#endif // _INT8_T_DECLARED
|
||||||
|
#ifndef _INT16_T_DECLARED
|
||||||
|
#ifndef __INT16_TYPE__
|
||||||
|
typedef short int16_t;
|
||||||
|
#endif // __INT16_TYPE__
|
||||||
|
#endif // _INT16_T_DECLARED
|
||||||
|
#ifndef _INT32_T_DECLARED
|
||||||
|
#ifndef __INT32_TYPE__
|
||||||
|
typedef int int32_t;
|
||||||
|
#endif // __INT32_TYPE__
|
||||||
|
#endif // _INT32_T_DECLARED
|
||||||
|
#ifndef _INT64_T_DECLARED
|
||||||
|
#ifndef __INT64_TYPE__
|
||||||
|
typedef long long int64_t;
|
||||||
|
#endif // __INT64_TYPE__
|
||||||
|
#endif // _INT64_T_DECLARED
|
||||||
|
#ifndef _UINT8_T_DECLARED
|
||||||
|
#ifndef __UINT8_TYPE__
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
#endif // __UINT8_TYPE__
|
||||||
|
#endif // _UINT8_T_DECLARED
|
||||||
|
#ifndef _UINT16_T_DECLARED
|
||||||
|
#ifndef __UINT16_TYPE__
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
#endif // __UINT16_TYPE__
|
||||||
|
#endif // _UINT16_T_DECLARED
|
||||||
|
#ifndef _UINT32_T_DECLARED
|
||||||
|
#ifndef __UINT32_TYPE__
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
#endif // __UINT32_TYPE__
|
||||||
|
#endif // _UINT32_T_DECLARED
|
||||||
|
#ifndef _UINT64_T_DECLARED
|
||||||
|
#ifndef __UINT64_TYPE__
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
#endif // __UINT64_TYPE__
|
||||||
|
#endif // _UINT64_T_DECLARED
|
||||||
|
|
||||||
|
#ifndef __LONG64_TYPE__
|
||||||
|
typedef long long long64_t;
|
||||||
|
#endif // __LONG64_TYPE__
|
||||||
|
#ifndef __ULONG64_TYPE__
|
||||||
|
typedef unsigned long long ulong64_t;
|
||||||
|
#endif // __ULONG64_TYPE__
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define DSP_FW_API
|
||||||
|
|
||||||
|
// Allow the DMR protocol
|
||||||
|
#define ENABLE_DMR
|
||||||
|
|
||||||
|
// Allow the P25 protocol
|
||||||
|
#define ENABLE_P25
|
||||||
|
|
||||||
|
// Enable P25 Wide modulation
|
||||||
|
// #define ENABLE_P25_WIDE
|
||||||
|
|
||||||
|
// Enable ADF7021 support
|
||||||
|
#define ENABLE_ADF7021
|
||||||
|
|
||||||
|
// Bidirectional Data pin (Enable Standard TX/RX Data Interface of ADF7021)
|
||||||
|
#define BIDIR_DATA_PIN
|
||||||
|
|
||||||
|
// Enable full duplex support with dual ADF7021 (valid for homebrew hotspots only)
|
||||||
|
#define DUPLEX
|
||||||
|
|
||||||
|
// TCXO of the ADF7021
|
||||||
|
// For 14.7456 MHz:
|
||||||
|
#define ADF7021_14_7456
|
||||||
|
// For 12.2880 MHz:
|
||||||
|
// #define ADF7021_12_2880
|
||||||
|
|
||||||
|
// Configure receiver gain for ADF7021
|
||||||
|
// AGC automatic, default settings
|
||||||
|
#define AD7021_GAIN_AUTO
|
||||||
|
// AGC automatic with high LNA linearity
|
||||||
|
// #define AD7021_GAIN_AUTO_LIN
|
||||||
|
// AGC OFF, lowest gain
|
||||||
|
// #define AD7021_GAIN_LOW
|
||||||
|
// AGC OFF, highest gain
|
||||||
|
// #define AD7021_GAIN_HIGH
|
||||||
|
|
||||||
|
// Enable mode detection
|
||||||
|
#define ENABLE_SCAN_MODE
|
||||||
|
|
||||||
|
// Pass RSSI information to the host
|
||||||
|
// #define SEND_RSSI_DATA
|
||||||
|
|
||||||
|
// Enable for RPi 3B+, USB mode
|
||||||
|
// #define LONG_USB_RESET
|
||||||
|
|
||||||
|
const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Macros
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define _WRITE_BIT(p, i, b) p[(i) >> 3] = (b) ? (p[(i) >> 3] | BIT_MASK_TABLE[(i) & 7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i) & 7])
|
||||||
|
#define _READ_BIT(p, i) (p[(i) >> 3] & BIT_MASK_TABLE[(i) & 7])
|
||||||
|
|
||||||
|
#endif // __DEFINES_H__
|
||||||
@ -0,0 +1,150 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Mathis Schmieder DB9MAT
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2016,2017,2018,2019 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2019 by Florian Wolters DF2ET
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Globals
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DVM_STATE m_modemState = STATE_IDLE;
|
||||||
|
DVM_STATE m_calState = STATE_IDLE;
|
||||||
|
DVM_STATE m_modemStatePrev = STATE_IDLE;
|
||||||
|
|
||||||
|
bool m_cwIdState = false;
|
||||||
|
uint8_t m_cwIdTXLevel = 30;
|
||||||
|
|
||||||
|
uint32_t m_modeTimerCnt;
|
||||||
|
|
||||||
|
#ifdef ENABLE_DMR
|
||||||
|
bool m_dmrEnable = true;
|
||||||
|
#else
|
||||||
|
bool m_dmrEnable = false;
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_P25
|
||||||
|
bool m_p25Enable = true;
|
||||||
|
#else
|
||||||
|
bool m_p25Enable = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool m_duplex = false;
|
||||||
|
|
||||||
|
bool m_tx = false;
|
||||||
|
bool m_dcd = false;
|
||||||
|
|
||||||
|
uint8_t m_control;
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
/** DMR BS */
|
||||||
|
dmr::DMRIdleRX dmrIdleRX;
|
||||||
|
dmr::DMRRX dmrRX;
|
||||||
|
dmr::DMRTX dmrTX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** DMR MS-DMO */
|
||||||
|
dmr::DMRDMORX dmrDMORX;
|
||||||
|
dmr::DMRDMOTX dmrDMOTX;
|
||||||
|
|
||||||
|
/** P25 */
|
||||||
|
p25::P25RX p25RX;
|
||||||
|
p25::P25TX p25TX;
|
||||||
|
|
||||||
|
/** Calibration */
|
||||||
|
dmr::CalDMR calDMR;
|
||||||
|
p25::CalP25 calP25;
|
||||||
|
CalRSSI calRSSI;
|
||||||
|
|
||||||
|
/** CW */
|
||||||
|
CWIdTX cwIdTX;
|
||||||
|
|
||||||
|
/** RS232 and Air Interface I/O */
|
||||||
|
SerialPort serial;
|
||||||
|
IO io;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Global Functions
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
serial.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
io.process();
|
||||||
|
|
||||||
|
serial.process();
|
||||||
|
|
||||||
|
// The following is for transmitting
|
||||||
|
if (m_dmrEnable && m_modemState == STATE_DMR && m_calState == STATE_IDLE) {
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
if (m_duplex)
|
||||||
|
dmrTX.process();
|
||||||
|
else
|
||||||
|
dmrDMOTX.process();
|
||||||
|
#else
|
||||||
|
dmrDMOTX.process();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_p25Enable && m_modemState == STATE_P25)
|
||||||
|
p25TX.process();
|
||||||
|
|
||||||
|
if (m_modemState == STATE_DMR_DMO_CAL_1K || m_modemState == STATE_DMR_CAL_1K ||
|
||||||
|
m_modemState == STATE_DMR_LF_CAL || m_modemState == STATE_DMR_CAL)
|
||||||
|
calDMR.process();
|
||||||
|
|
||||||
|
if (m_modemState == STATE_P25_CAL_1K || m_modemState == STATE_P25_LF_CAL || m_modemState == STATE_P25_CAL)
|
||||||
|
calP25.process();
|
||||||
|
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
if (m_calState == STATE_RSSI_CAL)
|
||||||
|
calRSSI.process();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_modemState == STATE_CW || m_modemState == STATE_IDLE)
|
||||||
|
cwIdTX.process();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Firmware Entry Point
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
setup();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
loop();
|
||||||
|
}
|
||||||
@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016,2017,2018,2019 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2019 by Florian Wolters DF2ET
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__GLOBALS_H__)
|
||||||
|
#define __GLOBALS_H__
|
||||||
|
|
||||||
|
#if defined(STM32F10X_MD)
|
||||||
|
#include <stm32f10x.h>
|
||||||
|
#include "string.h"
|
||||||
|
#elif defined(STM32F4XX)
|
||||||
|
#include "stm32f4xx.h"
|
||||||
|
#include "string.h"
|
||||||
|
#elif defined(STM32F7XX)
|
||||||
|
#include "stm32f7xx.h"
|
||||||
|
#include "string.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "SerialPort.h"
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
#include "dmr/DMRIdleRX.h"
|
||||||
|
#include "dmr/DMRRX.h"
|
||||||
|
#include "dmr/DMRTX.h"
|
||||||
|
#endif
|
||||||
|
#include "dmr/DMRDMORX.h"
|
||||||
|
#include "dmr/DMRDMOTX.h"
|
||||||
|
#include "dmr/CalDMR.h"
|
||||||
|
#include "p25/P25RX.h"
|
||||||
|
#include "p25/P25TX.h"
|
||||||
|
#include "p25/CalP25.h"
|
||||||
|
#include "CalRSSI.h"
|
||||||
|
#include "CWIdTX.h"
|
||||||
|
#include "IO.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint8_t MARK_SLOT1 = 0x08U;
|
||||||
|
const uint8_t MARK_SLOT2 = 0x04U;
|
||||||
|
const uint8_t MARK_NONE = 0x00U;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Macros
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define DEBUG1(a) serial.writeDebug((a))
|
||||||
|
#define DEBUG2(a,b) serial.writeDebug((a),(b))
|
||||||
|
#define DEBUG3(a,b,c) serial.writeDebug((a),(b),(c))
|
||||||
|
#define DEBUG4(a,b,c,d) serial.writeDebug((a),(b),(c),(d))
|
||||||
|
#define DEBUG5(a,b,c,d,e) serial.writeDebug((a),(b),(c),(d),(e))
|
||||||
|
#define DEBUG_DUMP(a,b) serial.writeDump((a),(b))
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Global Externs
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern DVM_STATE m_modemState;
|
||||||
|
extern DVM_STATE m_calState;
|
||||||
|
extern DVM_STATE m_modemStatePrev;
|
||||||
|
|
||||||
|
extern bool m_cwIdState;
|
||||||
|
extern uint8_t m_cwIdTXLevel;
|
||||||
|
|
||||||
|
extern uint32_t m_modeTimerCnt;
|
||||||
|
|
||||||
|
extern bool m_dmrEnable;
|
||||||
|
extern bool m_p25Enable;
|
||||||
|
|
||||||
|
extern bool m_duplex;
|
||||||
|
|
||||||
|
extern bool m_tx;
|
||||||
|
extern bool m_dcd;
|
||||||
|
|
||||||
|
extern uint8_t m_control;
|
||||||
|
|
||||||
|
extern SerialPort serial;
|
||||||
|
extern IO io;
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
/** DMR BS */
|
||||||
|
extern dmr::DMRIdleRX dmrIdleRX;
|
||||||
|
extern dmr::DMRRX dmrRX;
|
||||||
|
extern dmr::DMRTX dmrTX;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** DMR MS-DMO */
|
||||||
|
extern dmr::DMRDMORX dmrDMORX;
|
||||||
|
extern dmr::DMRDMOTX dmrDMOTX;
|
||||||
|
|
||||||
|
/** P25 BS */
|
||||||
|
extern p25::P25RX p25RX;
|
||||||
|
extern p25::P25TX p25TX;
|
||||||
|
|
||||||
|
/** Calibration */
|
||||||
|
extern dmr::CalDMR calDMR;
|
||||||
|
extern p25::CalP25 calP25;
|
||||||
|
extern CalRSSI calRSSI;
|
||||||
|
|
||||||
|
/** CW */
|
||||||
|
extern CWIdTX cwIdTX;
|
||||||
|
|
||||||
|
#endif // __GLOBALS_H__
|
||||||
@ -0,0 +1,444 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016,2017,2018,2019,2020 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2017 by Danilo DB4PLE
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "IO.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Globals
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
uint32_t m_rxFrequency;
|
||||||
|
uint32_t m_txFrequency;
|
||||||
|
uint8_t m_rfPower;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the IO class.
|
||||||
|
/// </summary>
|
||||||
|
IO::IO():
|
||||||
|
m_started(false),
|
||||||
|
m_rxBuffer(1024U),
|
||||||
|
m_txBuffer(1024U),
|
||||||
|
m_ledCount(0U),
|
||||||
|
m_scanEnable(false),
|
||||||
|
m_scanPauseCnt(0U),
|
||||||
|
m_scanPos(0U),
|
||||||
|
m_ledValue(true),
|
||||||
|
m_watchdog(0U),
|
||||||
|
m_int1Counter(0U),
|
||||||
|
m_int2Counter(0U)
|
||||||
|
{
|
||||||
|
initInt();
|
||||||
|
|
||||||
|
CE(HIGH);
|
||||||
|
|
||||||
|
setLEDInt(HIGH);
|
||||||
|
setPTTInt(LOW);
|
||||||
|
setDMRInt(LOW);
|
||||||
|
setP25Int(LOW);
|
||||||
|
setCOSInt(LOW);
|
||||||
|
|
||||||
|
#if !defined(BIDIR_DATA_PIN)
|
||||||
|
setTXDInt(LOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SCLK(LOW);
|
||||||
|
SDATA(LOW);
|
||||||
|
SLE1(LOW);
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
SLE2(LOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
selfTest();
|
||||||
|
m_modeTimerCnt = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts air interface sampler.
|
||||||
|
/// </summary>
|
||||||
|
void IO::start()
|
||||||
|
{
|
||||||
|
m_totalModes = 0U;
|
||||||
|
|
||||||
|
if (m_dmrEnable) {
|
||||||
|
m_modes[m_totalModes] = STATE_DMR;
|
||||||
|
m_totalModes++;
|
||||||
|
}
|
||||||
|
if (m_p25Enable) {
|
||||||
|
m_modes[m_totalModes] = STATE_P25;
|
||||||
|
m_totalModes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(ENABLE_SCAN_MODE)
|
||||||
|
if (m_totalModes > 1U) {
|
||||||
|
m_scanEnable = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_scanEnable = false;
|
||||||
|
setMode(m_modemState);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
m_scanEnable = false;
|
||||||
|
setMode(m_modemState);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_started)
|
||||||
|
return;
|
||||||
|
|
||||||
|
startInt();
|
||||||
|
|
||||||
|
m_started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process samples from air interface.
|
||||||
|
/// </summary>
|
||||||
|
void IO::process()
|
||||||
|
{
|
||||||
|
uint8_t bit;
|
||||||
|
uint32_t scantime;
|
||||||
|
uint8_t control;
|
||||||
|
|
||||||
|
m_ledCount++;
|
||||||
|
if (m_started) {
|
||||||
|
// Two seconds timeout
|
||||||
|
if (m_watchdog >= 19200U) {
|
||||||
|
if (m_modemState == STATE_DMR || m_modemState == STATE_P25) {
|
||||||
|
m_modemState = STATE_IDLE;
|
||||||
|
setMode(m_modemState);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_watchdog = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ledCount >= 48000U) {
|
||||||
|
m_ledCount = 0U;
|
||||||
|
m_ledValue = !m_ledValue;
|
||||||
|
setLEDInt(m_ledValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_ledCount >= 480000U) {
|
||||||
|
m_ledCount = 0U;
|
||||||
|
m_ledValue = !m_ledValue;
|
||||||
|
setLEDInt(m_ledValue);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch off the transmitter if needed
|
||||||
|
if (m_txBuffer.getData() == 0U && m_tx) {
|
||||||
|
if (m_cwIdState) {
|
||||||
|
// check for CW ID end of transmission
|
||||||
|
m_cwIdState = false;
|
||||||
|
|
||||||
|
// restoring previous mode
|
||||||
|
if (m_totalModes) {
|
||||||
|
io.rf1Conf(m_modemStatePrev, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setRX(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_modemStatePrev == STATE_DMR)
|
||||||
|
scantime = SCAN_TIME * 2U;
|
||||||
|
else if (m_modemStatePrev == STATE_P25)
|
||||||
|
scantime = SCAN_TIME;
|
||||||
|
else
|
||||||
|
scantime = SCAN_TIME;
|
||||||
|
|
||||||
|
if (m_modeTimerCnt >= scantime) {
|
||||||
|
m_modeTimerCnt = 0U;
|
||||||
|
if ((m_modemState == STATE_IDLE) && (m_scanPauseCnt == 0U) && m_scanEnable && !m_cwIdState) {
|
||||||
|
m_scanPos = (m_scanPos + 1U) % m_totalModes;
|
||||||
|
|
||||||
|
setMode(m_modes[m_scanPos]);
|
||||||
|
io.rf1Conf(m_modes[m_scanPos], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_rxBuffer.getData() >= 1U) {
|
||||||
|
m_rxBuffer.get(bit, control);
|
||||||
|
|
||||||
|
if (m_modemStatePrev == STATE_DMR) {
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
if (m_duplex) {
|
||||||
|
if (m_tx)
|
||||||
|
dmrRX.databit(bit, control);
|
||||||
|
else
|
||||||
|
dmrIdleRX.databit(bit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dmrDMORX.databit(bit);
|
||||||
|
#else
|
||||||
|
dmrDMORX.databit(bit);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (m_modemStatePrev == STATE_P25) {
|
||||||
|
p25RX.databit(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write bits to air interface.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mode"></param>
|
||||||
|
/// <param name="samples"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <param name="control"></param>
|
||||||
|
void IO::write(uint8_t* data, uint16_t length, const uint8_t* control)
|
||||||
|
{
|
||||||
|
if (!m_started)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (uint16_t i = 0U; i < length; i++) {
|
||||||
|
if (control == NULL)
|
||||||
|
m_txBuffer.put(data[i], MARK_NONE);
|
||||||
|
else
|
||||||
|
m_txBuffer.put(data[i], control[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch the transmitter on if needed
|
||||||
|
if (!m_tx) {
|
||||||
|
setTX();
|
||||||
|
m_tx = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to get how much space the transmit ring buffer has for samples.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint16_t IO::getSpace() const
|
||||||
|
{
|
||||||
|
return m_txBuffer.getSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dcd"></param>
|
||||||
|
void IO::setDecode(bool dcd)
|
||||||
|
{
|
||||||
|
if (dcd != m_dcd) {
|
||||||
|
m_scanPauseCnt = 1U;
|
||||||
|
setCOSInt(dcd ? true : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dcd = dcd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to set the modem air interface state.
|
||||||
|
/// </summary>
|
||||||
|
void IO::setMode(DVM_STATE modemState)
|
||||||
|
{
|
||||||
|
setDMRInt(modemState == STATE_DMR);
|
||||||
|
setP25Int(modemState == STATE_P25);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the RF parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rxFreq"></param>
|
||||||
|
/// <param name="txFreq"></param>
|
||||||
|
/// <param name="rfPower"></param>
|
||||||
|
uint8_t IO::setRFParams(uint32_t rxFreq, uint32_t txFreq, uint8_t rfPower)
|
||||||
|
{
|
||||||
|
m_rfPower = rfPower >> 2;
|
||||||
|
|
||||||
|
// check frequency ranges
|
||||||
|
if (!(
|
||||||
|
/** 136 - 174 mhz */
|
||||||
|
((rxFreq >= VHF_MIN) && (rxFreq < VHF_MAX)) || ((txFreq >= VHF_MIN) && (txFreq < VHF_MAX)) ||
|
||||||
|
/** 216 - 225 mhz */
|
||||||
|
((rxFreq >= VHF_220_MIN) && (rxFreq < VHF_220_MAX)) || ((txFreq >= VHF_220_MIN) && (txFreq < VHF_220_MAX)) ||
|
||||||
|
/** 380 - 431 mhz */
|
||||||
|
((rxFreq >= UHF_380_MIN) && (rxFreq < UHF_380_MAX)) || ((txFreq >= UHF_380_MIN) && (txFreq < UHF_380_MAX)) ||
|
||||||
|
/** 431 - 450 mhz */
|
||||||
|
((rxFreq >= UHF_1_MIN) && (rxFreq < UHF_1_MAX)) || ((txFreq >= UHF_1_MIN) && (txFreq < UHF_1_MAX)) ||
|
||||||
|
/** 450 - 470 mhz */
|
||||||
|
((rxFreq >= UHF_2_MIN) && (rxFreq < UHF_2_MAX)) || ((txFreq >= UHF_2_MIN) && (txFreq < UHF_2_MAX)) ||
|
||||||
|
/** 470 - 520 mhz */
|
||||||
|
((rxFreq >= UHF_T_MIN) && (rxFreq < UHF_T_MAX)) || ((txFreq >= UHF_T_MIN) && (txFreq < UHF_T_MAX)) ||
|
||||||
|
/** 842 - 900 mhz */
|
||||||
|
((rxFreq >= UHF_800_MIN) && (rxFreq < UHF_800_MAX)) || ((txFreq >= UHF_800_MIN) && (txFreq < UHF_800_MAX)) ||
|
||||||
|
/** 900 - 950 mhz */
|
||||||
|
((rxFreq >= UHF_900_MIN) && (rxFreq < UHF_900_MAX)) || ((txFreq >= UHF_900_MIN) && (txFreq < UHF_900_MAX))
|
||||||
|
))
|
||||||
|
return RSN_INVALID_REQUEST;
|
||||||
|
|
||||||
|
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
|
||||||
|
// check hotspot configuration for single or dual ADF7021
|
||||||
|
if (!(io.hasSingleADF7021())) {
|
||||||
|
// there are two ADF7021s on the board -- are they dual-band?
|
||||||
|
if (io.isDualBand()) {
|
||||||
|
// dual band
|
||||||
|
if ((txFreq <= VHF_220_MAX) && (rxFreq <= VHF_220_MAX)) {
|
||||||
|
// turn on VHF side
|
||||||
|
io.setBandVHF(true);
|
||||||
|
}
|
||||||
|
else if ((txFreq >= UHF_1_MIN) && (rxFreq >= UHF_1_MIN)) {
|
||||||
|
// turn on UHF side
|
||||||
|
io.setBandVHF(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!io.isDualBand()) {
|
||||||
|
// duplex board
|
||||||
|
if ((txFreq < UHF_1_MIN) || (rxFreq < UHF_1_MIN)) {
|
||||||
|
// Reject VHF frequencies
|
||||||
|
return RSN_INVALID_REQUEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_rxFrequency = rxFreq;
|
||||||
|
m_txFrequency = txFreq;
|
||||||
|
|
||||||
|
return RSN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag indicating the TX ring buffer has overflowed.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IO::hasTXOverflow()
|
||||||
|
{
|
||||||
|
return m_txBuffer.hasOverflowed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag indicating the RX ring buffer has overflowed.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IO::hasRXOverflow()
|
||||||
|
{
|
||||||
|
return m_rxBuffer.hasOverflowed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void IO::resetWatchdog()
|
||||||
|
{
|
||||||
|
m_watchdog = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint32_t IO::getWatchdog()
|
||||||
|
{
|
||||||
|
return m_watchdog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void IO::selfTest()
|
||||||
|
{
|
||||||
|
bool ledValue = false;
|
||||||
|
uint32_t ledCount = 0U;
|
||||||
|
uint32_t blinks = 0U;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
ledCount++;
|
||||||
|
delayUS(1000U);
|
||||||
|
|
||||||
|
if (ledCount >= 125U) {
|
||||||
|
ledCount = 0U;
|
||||||
|
ledValue = !ledValue;
|
||||||
|
|
||||||
|
setLEDInt(!ledValue);
|
||||||
|
setPTTInt(ledValue);
|
||||||
|
setDMRInt(ledValue);
|
||||||
|
setP25Int(ledValue);
|
||||||
|
setCOSInt(ledValue);
|
||||||
|
|
||||||
|
blinks++;
|
||||||
|
|
||||||
|
if (blinks > 5U)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="int1"></param>
|
||||||
|
/// <param name="int2"></param>
|
||||||
|
void IO::getIntCounter(uint16_t& int1, uint16_t& int2)
|
||||||
|
{
|
||||||
|
int1 = m_int1Counter;
|
||||||
|
int2 = m_int2Counter;
|
||||||
|
m_int1Counter = 0U;
|
||||||
|
m_int2Counter = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rxFreq"></param>
|
||||||
|
/// <param name="txFreq"></param>
|
||||||
|
void IO::checkBand(uint32_t rxFreq, uint32_t txFreq)
|
||||||
|
{
|
||||||
|
// check hotspot configuration for single or dual ADF7021
|
||||||
|
if (!(io.hasSingleADF7021())) {
|
||||||
|
// there are two ADF7021s on the board -- are they dual-band?
|
||||||
|
if (io.isDualBand()) {
|
||||||
|
// dual band
|
||||||
|
if ((txFreq <= VHF_220_MAX) && (rxFreq <= VHF_220_MAX)) {
|
||||||
|
// turn on VHF side
|
||||||
|
io.setBandVHF(true);
|
||||||
|
}
|
||||||
|
else if ((txFreq >= UHF_1_MIN) && (rxFreq >= UHF_1_MIN)) {
|
||||||
|
// turn on UHF side
|
||||||
|
io.setBandVHF(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -0,0 +1,244 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016,2017,2018,2019,2020 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2017 by Danilo DB4PLE
|
||||||
|
* Copyright (C) 2017-2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__IO_H__)
|
||||||
|
#define __IO_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "BitBuffer.h"
|
||||||
|
#include "ADF7021.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define SCAN_TIME 1920
|
||||||
|
#define SCAN_PAUSE 20000
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
#if defined(STM32_USB_HOST)
|
||||||
|
#define CAL_DLY_LOOP 98950U
|
||||||
|
#else
|
||||||
|
#define CAL_DLY_LOOP 96100U
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if defined(STM32_USB_HOST)
|
||||||
|
#define CAL_DLY_LOOP 110850U
|
||||||
|
#else
|
||||||
|
#define CAL_DLY_LOOP 104600U
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Global Externs
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern uint32_t m_rxFrequency;
|
||||||
|
extern uint32_t m_txFrequency;
|
||||||
|
extern uint8_t m_rfPower;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements the input/output data path with the radio air interface.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API IO {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the IO class.</summary>
|
||||||
|
IO();
|
||||||
|
|
||||||
|
/// <summary>Starts air interface sampler.</summary>
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/// <summary>Process bits from air interface.</summary>
|
||||||
|
void process();
|
||||||
|
|
||||||
|
/// <summary>Write bits to air interface.</summary>
|
||||||
|
void write(uint8_t* data, uint16_t length, const uint8_t* control = NULL);
|
||||||
|
|
||||||
|
/// <summary>Helper to get how much space the transmit ring buffer has for samples.</summary>
|
||||||
|
uint16_t getSpace(void) const;
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void setDecode(bool dcd);
|
||||||
|
|
||||||
|
/// <summary>Set modem mode.</summary>
|
||||||
|
void setMode(DVM_STATE modemState);
|
||||||
|
|
||||||
|
/// <summary>Hardware interrupt handler.</summary>
|
||||||
|
void interrupt1();
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
/// <summary>Hardware interrupt handler.</summary>
|
||||||
|
void interrupt2();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>Sets the ADF7021 RF configuration.</summary>
|
||||||
|
void rf1Conf(DVM_STATE modemState, bool reset);
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
/// <summary>Sets the ADF7021 RF configuration.</summary>
|
||||||
|
void rf2Conf(DVM_STATE modemState);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void setDeviations(uint8_t dmrTXLevel, uint8_t p25TXLevel);
|
||||||
|
/// <summary>Sets the RF parameters.</summary>
|
||||||
|
uint8_t setRFParams(uint32_t rxFreq, uint32_t txFreq, uint8_t rfPower);
|
||||||
|
|
||||||
|
/// <summary>Flag indicating the TX ring buffer has overflowed.</summary>
|
||||||
|
bool hasTXOverflow(void);
|
||||||
|
/// <summary>Flag indicating the RX ring buffer has overflowed.</summary>
|
||||||
|
bool hasRXOverflow(void);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void resetWatchdog(void);
|
||||||
|
/// <summary></summary>
|
||||||
|
uint32_t getWatchdog(void);
|
||||||
|
|
||||||
|
/// <summary>Gets the CPU type the firmware is running on.</summary>
|
||||||
|
uint8_t getCPU() const;
|
||||||
|
|
||||||
|
/// <summary>Gets the unique identifier for the air interface.</summary>
|
||||||
|
void getUDID(uint8_t* buffer);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void updateCal();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void delayBit(void);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
uint16_t readRSSI(void);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void selfTest();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void getIntCounter(uint16_t& int1, uint16_t& int2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_started;
|
||||||
|
|
||||||
|
BitBuffer m_rxBuffer;
|
||||||
|
BitBuffer m_txBuffer;
|
||||||
|
|
||||||
|
uint32_t m_ledCount;
|
||||||
|
|
||||||
|
bool m_scanEnable;
|
||||||
|
uint32_t m_scanPauseCnt;
|
||||||
|
uint8_t m_scanPos;
|
||||||
|
|
||||||
|
uint8_t m_totalModes;
|
||||||
|
DVM_STATE m_modes[6];
|
||||||
|
bool m_ledValue;
|
||||||
|
|
||||||
|
volatile uint32_t m_watchdog;
|
||||||
|
|
||||||
|
volatile uint16_t m_int1Counter;
|
||||||
|
volatile uint16_t m_int2Counter;
|
||||||
|
|
||||||
|
/// <summary>Helper to check the frequencies are within band ranges of the ADF7021.</summary>
|
||||||
|
void checkBand(uint32_t rxFreq, uint32_t txFreq);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void setBandVHF(bool enable);
|
||||||
|
/// <summary></summary>
|
||||||
|
bool hasSingleADF7021();
|
||||||
|
/// <summary></summary>
|
||||||
|
bool isDualBand();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void configureBand();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void setTX();
|
||||||
|
/// <summary></summary>
|
||||||
|
void setRX(bool doSle = true);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void delayIfCal();
|
||||||
|
/// <summary></summary>
|
||||||
|
void delayReset();
|
||||||
|
/// <summary></summary>
|
||||||
|
void delayUS(uint32_t us);
|
||||||
|
|
||||||
|
// Hardware specific routines
|
||||||
|
/// <summary>Initializes hardware interrupts.</summary>
|
||||||
|
void initInt();
|
||||||
|
/// <summary>Starts hardware interrupts.</summary>
|
||||||
|
void startInt();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void SCLK(bool on);
|
||||||
|
/// <summary></summary>
|
||||||
|
void SDATA(bool on);
|
||||||
|
/// <summary></summary>
|
||||||
|
bool SREAD();
|
||||||
|
/// <summary></summary>
|
||||||
|
void SLE1(bool on);
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
/// <summary></summary>
|
||||||
|
void SLE2(bool on);
|
||||||
|
/// <summary></summary>
|
||||||
|
bool RXD2();
|
||||||
|
#endif
|
||||||
|
/// <summary></summary>
|
||||||
|
void CE(bool on);
|
||||||
|
/// <summary></summary>
|
||||||
|
bool RXD1();
|
||||||
|
/// <summary></summary>
|
||||||
|
bool CLK();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void setTXDInt(bool on);
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
/// <summary></summary>
|
||||||
|
void setDataDirOut(bool dir);
|
||||||
|
/// <summary></summary>
|
||||||
|
void setRXDInt(bool on);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void setLEDInt(bool on);
|
||||||
|
/// <summary></summary>
|
||||||
|
void setPTTInt(bool on);
|
||||||
|
/// <summary></summary>
|
||||||
|
void setCOSInt(bool on);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void setDMRInt(bool on);
|
||||||
|
/// <summary></summary>
|
||||||
|
void setP25Int(bool on);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,856 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
|
||||||
|
* Copyright (C) 2016,2017,2018,2019,2020 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2017 by Danilo DB4PLE
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "IO.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(STM32F10X_MD)
|
||||||
|
/**
|
||||||
|
* The STM32 factory-programmed UUID memory.
|
||||||
|
* Three values of 32 bits each starting at this address
|
||||||
|
* Use like this: STM32_UUID[0], STM32_UUID[1], STM32_UUID[2]
|
||||||
|
*/
|
||||||
|
#define STM32_UUID ((uint32_t *)0x1FFFF7E8)
|
||||||
|
|
||||||
|
#if defined(PI_HAT_7021_REV_02)
|
||||||
|
|
||||||
|
#define PIN_SCLK GPIO_Pin_4
|
||||||
|
#define PORT_SCLK GPIOB
|
||||||
|
|
||||||
|
#define PIN_SREAD GPIO_Pin_5
|
||||||
|
#define PORT_SREAD GPIOB
|
||||||
|
|
||||||
|
#define PIN_SDATA GPIO_Pin_6
|
||||||
|
#define PORT_SDATA GPIOB
|
||||||
|
|
||||||
|
#define PIN_SLE GPIO_Pin_7
|
||||||
|
#define PORT_SLE GPIOB
|
||||||
|
|
||||||
|
#define PIN_CE GPIO_Pin_14
|
||||||
|
#define PORT_CE GPIOC
|
||||||
|
|
||||||
|
#define PIN_RXD GPIO_Pin_3
|
||||||
|
#define PORT_RXD GPIOB
|
||||||
|
|
||||||
|
// TXD used in SPI Data mode of ADF7021
|
||||||
|
// TXD is TxRxCLK of ADF7021, standard TX/RX data interface
|
||||||
|
#define PIN_TXD GPIO_Pin_15
|
||||||
|
#define PORT_TXD GPIOA
|
||||||
|
#define PIN_TXD_INT GPIO_PinSource15
|
||||||
|
#define PORT_TXD_INT GPIO_PortSourceGPIOA
|
||||||
|
|
||||||
|
// CLKOUT used in SPI Data mode of ADF7021
|
||||||
|
#define PIN_CLKOUT GPIO_Pin_14
|
||||||
|
#define PORT_CLKOUT GPIOA
|
||||||
|
#define PIN_CLKOUT_INT GPIO_PinSource14
|
||||||
|
#define PORT_CLKOUT_INT GPIO_PortSourceGPIOA
|
||||||
|
|
||||||
|
#define PIN_LED GPIO_Pin_13
|
||||||
|
#define PORT_LED GPIOC
|
||||||
|
|
||||||
|
#define PIN_DEB GPIO_Pin_11
|
||||||
|
#define PORT_DEB GPIOA
|
||||||
|
|
||||||
|
#define PIN_DMR_LED GPIO_Pin_15
|
||||||
|
#define PORT_DMR_LED GPIOB
|
||||||
|
|
||||||
|
#define PIN_P25_LED GPIO_Pin_12
|
||||||
|
#define PORT_P25_LED GPIOA
|
||||||
|
|
||||||
|
#define PIN_PTT_LED GPIO_Pin_12
|
||||||
|
#define PORT_PTT_LED GPIOB
|
||||||
|
|
||||||
|
#define PIN_COS_LED GPIO_Pin_13
|
||||||
|
#define PORT_COS_LED GPIOB
|
||||||
|
|
||||||
|
#elif defined(ZUMSPOT_ADF7021) || defined(SKYBRIDGE_HS) || defined(LONESTAR_USB)
|
||||||
|
|
||||||
|
#define PIN_SCLK GPIO_Pin_5
|
||||||
|
#define PORT_SCLK GPIOB
|
||||||
|
|
||||||
|
#define PIN_SREAD GPIO_Pin_6
|
||||||
|
#define PORT_SREAD GPIOB
|
||||||
|
|
||||||
|
#define PIN_SDATA GPIO_Pin_7
|
||||||
|
#define PORT_SDATA GPIOB
|
||||||
|
|
||||||
|
#define PIN_SLE GPIO_Pin_8
|
||||||
|
#define PORT_SLE GPIOB
|
||||||
|
|
||||||
|
#define PIN_SLE2 GPIO_Pin_6
|
||||||
|
#define PORT_SLE2 GPIOA
|
||||||
|
|
||||||
|
#define PIN_CE GPIO_Pin_14
|
||||||
|
#define PORT_CE GPIOC
|
||||||
|
|
||||||
|
#define PIN_RXD GPIO_Pin_4
|
||||||
|
#define PORT_RXD GPIOB
|
||||||
|
|
||||||
|
#define PIN_SGL_DBL GPIO_Pin_12
|
||||||
|
#define PORT_SGL_DBL GPIOA
|
||||||
|
|
||||||
|
#define PIN_DL_DPX GPIO_Pin_15
|
||||||
|
#define PORT_DL_DPX GPIOC
|
||||||
|
|
||||||
|
#define PIN_SET_BAND GPIO_Pin_15
|
||||||
|
#define PORT_SET_BAND GPIOA
|
||||||
|
|
||||||
|
// TXD used in SPI Data mode of ADF7021
|
||||||
|
// TXD is TxRxCLK of ADF7021, standard TX/RX data interface
|
||||||
|
#define PIN_TXD GPIO_Pin_3
|
||||||
|
#define PORT_TXD GPIOB
|
||||||
|
#define PIN_TXD_INT GPIO_PinSource3
|
||||||
|
#define PORT_TXD_INT GPIO_PortSourceGPIOB
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
#define PIN_RXD2 GPIO_Pin_11
|
||||||
|
#define PORT_RXD2 GPIOA
|
||||||
|
|
||||||
|
// TXD2 is TxRxCLK of the second ADF7021, standard TX/RX data interface
|
||||||
|
#define PIN_TXD2 GPIO_Pin_8
|
||||||
|
#define PORT_TXD2 GPIOA
|
||||||
|
#define PIN_TXD2_INT GPIO_PinSource8
|
||||||
|
#define PORT_TXD2_INT GPIO_PortSourceGPIOA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CLKOUT used in SPI Data mode of ADF7021
|
||||||
|
#define PIN_CLKOUT GPIO_Pin_15
|
||||||
|
#define PORT_CLKOUT GPIOA
|
||||||
|
#define PIN_CLKOUT_INT GPIO_PinSource15
|
||||||
|
#define PORT_CLKOUT_INT GPIO_PortSourceGPIOA
|
||||||
|
|
||||||
|
#define PIN_LED GPIO_Pin_13
|
||||||
|
#define PORT_LED GPIOC
|
||||||
|
|
||||||
|
#define PIN_DEB GPIO_Pin_9
|
||||||
|
#define PORT_DEB GPIOB
|
||||||
|
|
||||||
|
#define PIN_DMR_LED GPIO_Pin_13
|
||||||
|
#define PORT_DMR_LED GPIOB
|
||||||
|
|
||||||
|
#define PIN_P25_LED GPIO_Pin_0
|
||||||
|
#define PORT_P25_LED GPIOB
|
||||||
|
|
||||||
|
#define PIN_PTT_LED GPIO_Pin_14
|
||||||
|
#define PORT_PTT_LED GPIOB
|
||||||
|
|
||||||
|
#define PIN_COS_LED GPIO_Pin_15
|
||||||
|
#define PORT_COS_LED GPIOB
|
||||||
|
|
||||||
|
#elif defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11)
|
||||||
|
|
||||||
|
#define PIN_SCLK GPIO_Pin_5
|
||||||
|
#define PORT_SCLK GPIOB
|
||||||
|
|
||||||
|
#define PIN_SREAD GPIO_Pin_7
|
||||||
|
#define PORT_SREAD GPIOB
|
||||||
|
|
||||||
|
#define PIN_SDATA GPIO_Pin_6
|
||||||
|
#define PORT_SDATA GPIOB
|
||||||
|
|
||||||
|
#define PIN_SLE GPIO_Pin_8
|
||||||
|
#define PORT_SLE GPIOB
|
||||||
|
|
||||||
|
#define PIN_SLE2 GPIO_Pin_6
|
||||||
|
#define PORT_SLE2 GPIOA
|
||||||
|
|
||||||
|
#define PIN_CE GPIO_Pin_14
|
||||||
|
#define PORT_CE GPIOC
|
||||||
|
|
||||||
|
#define PIN_RXD GPIO_Pin_4
|
||||||
|
#define PORT_RXD GPIOB
|
||||||
|
|
||||||
|
#define PIN_RXD2 GPIO_Pin_4
|
||||||
|
#define PORT_RXD2 GPIOA
|
||||||
|
|
||||||
|
// TXD used in SPI Data mode of ADF7021
|
||||||
|
// TXD is TxRxCLK of ADF7021, standard TX/RX data interface
|
||||||
|
#define PIN_TXD GPIO_Pin_3
|
||||||
|
#define PORT_TXD GPIOB
|
||||||
|
#define PIN_TXD_INT GPIO_PinSource3
|
||||||
|
#define PORT_TXD_INT GPIO_PortSourceGPIOB
|
||||||
|
|
||||||
|
// TXD2 is TxRxCLK of the second ADF7021, standard TX/RX data interface
|
||||||
|
#define PIN_TXD2 GPIO_Pin_5
|
||||||
|
#define PORT_TXD2 GPIOA
|
||||||
|
#define PIN_TXD2_INT GPIO_PinSource5
|
||||||
|
#define PORT_TXD2_INT GPIO_PortSourceGPIOA
|
||||||
|
|
||||||
|
// CLKOUT used in SPI Data mode of ADF7021
|
||||||
|
#define PIN_CLKOUT GPIO_Pin_15
|
||||||
|
#define PORT_CLKOUT GPIOA
|
||||||
|
#define PIN_CLKOUT_INT GPIO_PinSource15
|
||||||
|
#define PORT_CLKOUT_INT GPIO_PortSourceGPIOA
|
||||||
|
|
||||||
|
#define PIN_LED GPIO_Pin_13
|
||||||
|
#define PORT_LED GPIOC
|
||||||
|
|
||||||
|
#define PIN_DEB GPIO_Pin_9
|
||||||
|
#define PORT_DEB GPIOB
|
||||||
|
|
||||||
|
#define PIN_DMR_LED GPIO_Pin_13
|
||||||
|
#define PORT_DMR_LED GPIOB
|
||||||
|
|
||||||
|
#define PIN_P25_LED GPIO_Pin_0
|
||||||
|
#define PORT_P25_LED GPIOB
|
||||||
|
|
||||||
|
#define PIN_PTT_LED GPIO_Pin_14
|
||||||
|
#define PORT_PTT_LED GPIOB
|
||||||
|
|
||||||
|
#define PIN_COS_LED GPIO_Pin_15
|
||||||
|
#define PORT_COS_LED GPIOB
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Either PI_HAT_7021_REV_02, ZUMSPOT_ADF7021, LONESTAR_USB, MMDVM_HS_HAT_REV12, MMDVM_HS_DUAL_HAT_REV10, NANO_HOTSPOT, NANO_DV_REV11, or SKYBRIDGE_HS need to be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Global Functions
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#if defined(PI_HAT_7021_REV_02)
|
||||||
|
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
void EXTI15_10_IRQHandler(void)
|
||||||
|
{
|
||||||
|
if (EXTI_GetITStatus(EXTI_Line15) != RESET) {
|
||||||
|
io.interrupt1();
|
||||||
|
EXTI_ClearITPendingBit(EXTI_Line15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void EXTI15_10_IRQHandler(void)
|
||||||
|
{
|
||||||
|
if (EXTI_GetITStatus(EXTI_Line14) != RESET) {
|
||||||
|
io.interrupt1();
|
||||||
|
EXTI_ClearITPendingBit(EXTI_Line14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // BIDIR_DATA_PIN
|
||||||
|
|
||||||
|
#elif defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
|
||||||
|
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
void EXTI3_IRQHandler(void) {
|
||||||
|
if (EXTI_GetITStatus(EXTI_Line3) != RESET) {
|
||||||
|
io.interrupt1();
|
||||||
|
EXTI_ClearITPendingBit(EXTI_Line3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void EXTI15_10_IRQHandler(void) {
|
||||||
|
if (EXTI_GetITStatus(EXTI_Line15) != RESET) {
|
||||||
|
io.interrupt1();
|
||||||
|
EXTI_ClearITPendingBit(EXTI_Line15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // BIDIR_DATA_PIN
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
void EXTI9_5_IRQHandler(void) {
|
||||||
|
#if defined(ZUMSPOT_ADF7021) || defined(SKYBRIDGE_HS)
|
||||||
|
if (EXTI_GetITStatus(EXTI_Line8) != RESET) {
|
||||||
|
io.interrupt2();
|
||||||
|
EXTI_ClearITPendingBit(EXTI_Line8);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (EXTI_GetITStatus(EXTI_Line5) != RESET) {
|
||||||
|
io.interrupt2();
|
||||||
|
EXTI_ClearITPendingBit(EXTI_Line5);
|
||||||
|
}
|
||||||
|
#endif // ZUMSPOT_ADF7021 || SKYBRIDGE_HS
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Function delay_us() from stm32duino project
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="us">Number of microseconds to delay.</param>
|
||||||
|
static inline void delay_us(uint32_t us)
|
||||||
|
{
|
||||||
|
us *= 12;
|
||||||
|
|
||||||
|
/* fudge for function call overhead */
|
||||||
|
us--;
|
||||||
|
asm volatile(
|
||||||
|
" mov r0, %[us] \n\t"
|
||||||
|
"1: subs r0, #1 \n\t"
|
||||||
|
" bhi 1b \n\t"
|
||||||
|
:
|
||||||
|
: [us] "r" (us)
|
||||||
|
: "r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
static inline void delay_ns()
|
||||||
|
{
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
"nop \n\t"
|
||||||
|
"nop \n\t"
|
||||||
|
"nop \n\t"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void IO::delayBit()
|
||||||
|
{
|
||||||
|
delay_ns();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable"></param>
|
||||||
|
void IO::setBandVHF(bool enable)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_SET_BAND, PIN_SET_BAND, vhf_on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IO::hasSingleADF7021()
|
||||||
|
{
|
||||||
|
return GPIO_ReadInputDataBit(PORT_SGL_DBL, PIN_SGL_DBL) == Bit_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IO::isDualBand()
|
||||||
|
{
|
||||||
|
return GPIO_ReadInputDataBit(PORT_DL_DPX, PIN_DL_DPX) == Bit_SET;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void IO::delayIfCal()
|
||||||
|
{
|
||||||
|
delayUS(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void IO::delayReset()
|
||||||
|
{
|
||||||
|
delayUS(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="us"></param>
|
||||||
|
void IO::delayUS(uint32_t us)
|
||||||
|
{
|
||||||
|
::delay_us(us);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes hardware interrupts.
|
||||||
|
/// </summary>
|
||||||
|
void IO::initInt()
|
||||||
|
{
|
||||||
|
GPIO_InitTypeDef GPIO_InitStruct;
|
||||||
|
GPIO_StructInit(&GPIO_InitStruct);
|
||||||
|
|
||||||
|
EXTI_InitTypeDef EXTI_InitStructure;
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
EXTI_InitTypeDef EXTI_InitStructure2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
|
||||||
|
|
||||||
|
#if defined(PI_HAT_7021_REV_02)
|
||||||
|
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);
|
||||||
|
#elif defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
|
||||||
|
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
|
||||||
|
// Pin defines if the board has a single ADF7021 or double
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_SGL_DBL;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
|
||||||
|
GPIO_Init(PORT_SGL_DBL, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// Pin defines if the board is dual band or duplex
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_DL_DPX;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
|
||||||
|
GPIO_Init(PORT_DL_DPX, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// Pin will set UHF or VHF
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_SET_BAND;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_SET_BAND, &GPIO_InitStruct);
|
||||||
|
// TODO: Remove this line
|
||||||
|
// GPIO_WriteBit(PORT_SET_BAND, PIN_SET_BAND, Bit_RESET);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(STM32_USB_HOST)
|
||||||
|
// Pin PA11,PA12 = LOW, USB Reset
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||||
|
GPIO_WriteBit(GPIOA, GPIO_Pin_11, Bit_RESET);
|
||||||
|
GPIO_WriteBit(GPIOA, GPIO_Pin_12, Bit_RESET);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(LONG_USB_RESET)
|
||||||
|
// 10 ms delay
|
||||||
|
delayUS(10000U);
|
||||||
|
#else
|
||||||
|
volatile unsigned int delay;
|
||||||
|
for (delay = 0; delay < 512; delay++);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
|
||||||
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);
|
||||||
|
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
|
||||||
|
|
||||||
|
// Pin SCLK
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_SCLK;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_SCLK, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// Pin SDATA
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_SDATA;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_SDATA, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// Pin SREAD
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_SREAD;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
GPIO_Init(PORT_SREAD, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// Pin SLE
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_SLE;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_SLE, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
// Pin SLE2
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_SLE2;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_SLE2, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// Pin RXD2
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_RXD2;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
GPIO_Init(PORT_RXD2, &GPIO_InitStruct);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin CE
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_CE;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_CE, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// Pin RXD
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_RXD;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
GPIO_Init(PORT_RXD, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// Pin TXD
|
||||||
|
// TXD is TxRxCLK of ADF7021, standard TX/RX data interface
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_TXD;
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
#else
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
#endif
|
||||||
|
GPIO_Init(PORT_TXD, &GPIO_InitStruct);
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_TXD2;
|
||||||
|
GPIO_Init(PORT_TXD2, &GPIO_InitStruct);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin TXRX_CLK
|
||||||
|
#if !defined(BIDIR_DATA_PIN)
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_CLKOUT;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
GPIO_Init(PORT_CLKOUT, &GPIO_InitStruct);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Pin LED
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_LED;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_LED, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// Pin Debug
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_DEB;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_DEB, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// DMR LED
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_DMR_LED;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_DMR_LED, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// P25 LED
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_P25_LED;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_P25_LED, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// PTT LED
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_PTT_LED;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_PTT_LED, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
// COS LED
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_COS_LED;
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_Init(PORT_COS_LED, &GPIO_InitStruct);
|
||||||
|
|
||||||
|
#if defined(PI_HAT_7021_REV_02)
|
||||||
|
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
// Connect EXTI15 Line
|
||||||
|
GPIO_EXTILineConfig(PORT_TXD_INT, PIN_TXD_INT);
|
||||||
|
// Configure EXTI15 line
|
||||||
|
EXTI_InitStructure.EXTI_Line = EXTI_Line15;
|
||||||
|
#else
|
||||||
|
// Connect EXTI14 Line
|
||||||
|
GPIO_EXTILineConfig(PORT_CLKOUT_INT, PIN_CLKOUT_INT);
|
||||||
|
// Configure EXTI14 line
|
||||||
|
EXTI_InitStructure.EXTI_Line = EXTI_Line14;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
|
||||||
|
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
// Connect EXTI3 Line
|
||||||
|
GPIO_EXTILineConfig(PORT_TXD_INT, PIN_TXD_INT);
|
||||||
|
// Configure EXTI3 line
|
||||||
|
EXTI_InitStructure.EXTI_Line = EXTI_Line3;
|
||||||
|
#else
|
||||||
|
// Connect EXTI15 Line
|
||||||
|
GPIO_EXTILineConfig(PORT_CLKOUT_INT, PIN_CLKOUT_INT);
|
||||||
|
// Configure EXTI15 line
|
||||||
|
EXTI_InitStructure.EXTI_Line = EXTI_Line15;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
// Connect EXTI5 Line
|
||||||
|
GPIO_EXTILineConfig(PORT_TXD2_INT, PIN_TXD2_INT);
|
||||||
|
// Configure EXT5 line
|
||||||
|
#if defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(SKYBRIDGE_HS)
|
||||||
|
EXTI_InitStructure2.EXTI_Line = EXTI_Line8;
|
||||||
|
#else
|
||||||
|
EXTI_InitStructure2.EXTI_Line = EXTI_Line5;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||||
|
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
|
||||||
|
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
|
||||||
|
EXTI_Init(&EXTI_InitStructure);
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
EXTI_InitStructure2.EXTI_Mode = EXTI_Mode_Interrupt;
|
||||||
|
EXTI_InitStructure2.EXTI_Trigger = EXTI_Trigger_Rising;
|
||||||
|
EXTI_InitStructure2.EXTI_LineCmd = ENABLE;
|
||||||
|
EXTI_Init(&EXTI_InitStructure2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts hardware interrupts.
|
||||||
|
/// </summary>
|
||||||
|
void IO::startInt()
|
||||||
|
{
|
||||||
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
NVIC_InitTypeDef NVIC_InitStructure2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PI_HAT_7021_REV_02)
|
||||||
|
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
|
||||||
|
|
||||||
|
#elif defined(ZUMSPOT_ADF7021) || defined(LONESTAR_USB) || defined(LIBRE_KIT_ADF7021) || defined(MMDVM_HS_HAT_REV12) || defined(MMDVM_HS_DUAL_HAT_REV10) || defined(NANO_HOTSPOT) || defined(NANO_DV_REV11) || defined(D2RG_MMDVM_HS) || defined(SKYBRIDGE_HS)
|
||||||
|
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
// Enable and set EXTI3 Interrupt
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
|
||||||
|
#else
|
||||||
|
// Enable and set EXTI15 Interrupt
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
NVIC_InitStructure2.NVIC_IRQChannel = EXTI9_5_IRQn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 15;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||||
|
NVIC_Init(&NVIC_InitStructure);
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
NVIC_InitStructure2.NVIC_IRQChannelPreemptionPriority = 1;
|
||||||
|
NVIC_InitStructure2.NVIC_IRQChannelSubPriority = 15;
|
||||||
|
NVIC_InitStructure2.NVIC_IRQChannelCmd = ENABLE;
|
||||||
|
NVIC_Init(&NVIC_InitStructure2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>RXD pin is bidirectional in standard interfaces</remarks>
|
||||||
|
/// <param name="dir"></param>
|
||||||
|
void IO::setDataDirOut(bool dir)
|
||||||
|
{
|
||||||
|
GPIO_InitTypeDef GPIO_InitStruct;
|
||||||
|
|
||||||
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStruct.GPIO_Pin = PIN_RXD;
|
||||||
|
|
||||||
|
if (dir)
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
else
|
||||||
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
|
||||||
|
GPIO_Init(PORT_RXD, &GPIO_InitStruct);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::SCLK(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_SCLK, PIN_SCLK, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::SDATA(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_SDATA, PIN_SDATA, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IO::SREAD()
|
||||||
|
{
|
||||||
|
return GPIO_ReadInputDataBit(PORT_SREAD, PIN_SREAD) == Bit_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::SLE1(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_SLE, PIN_SLE, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::SLE2(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_SLE2, PIN_SLE2, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IO::RXD2()
|
||||||
|
{
|
||||||
|
return GPIO_ReadInputDataBit(PORT_RXD2, PIN_RXD2) == Bit_SET;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::CE(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_CE, PIN_CE, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IO::RXD1()
|
||||||
|
{
|
||||||
|
return GPIO_ReadInputDataBit(PORT_RXD, PIN_RXD) == Bit_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool IO::CLK()
|
||||||
|
{
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
return GPIO_ReadInputDataBit(PORT_TXD, PIN_TXD) == Bit_SET;
|
||||||
|
#else
|
||||||
|
return GPIO_ReadInputDataBit(PORT_CLKOUT, PIN_CLKOUT) == Bit_SET;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BIDIR_DATA_PIN)
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::setRXDInt(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_RXD, PIN_RXD, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::setTXDInt(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_TXD, PIN_TXD, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::setLEDInt(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_LED, PIN_LED, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::setPTTInt(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_PTT_LED, PIN_PTT_LED, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::setCOSInt(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_COS_LED, PIN_COS_LED, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::setDMRInt(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_DMR_LED, PIN_DMR_LED, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="on"></param>
|
||||||
|
void IO::setP25Int(bool on)
|
||||||
|
{
|
||||||
|
GPIO_WriteBit(PORT_P25_LED, PIN_P25_LED, on ? Bit_SET : Bit_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // STM32F10X_MD
|
||||||
@ -0,0 +1,264 @@
|
|||||||
|
The GNU General Public License, Version 2, June 1991 (GPLv2)
|
||||||
|
============================================================
|
||||||
|
|
||||||
|
> Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
> 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this license
|
||||||
|
document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
--------
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your freedom to share
|
||||||
|
and change it. By contrast, the GNU General Public License is intended to
|
||||||
|
guarantee your freedom to share and change free software--to make sure the
|
||||||
|
software is free for all its users. This General Public License applies to most
|
||||||
|
of the Free Software Foundation's software and to any other program whose
|
||||||
|
authors commit to using it. (Some other Free Software Foundation software is
|
||||||
|
covered by the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not price. Our
|
||||||
|
General Public Licenses are designed to make sure that you have the freedom to
|
||||||
|
distribute copies of free software (and charge for this service if you wish),
|
||||||
|
that you receive source code or can get it if you want it, that you can change
|
||||||
|
the software or use pieces of it in new free programs; and that you know you can
|
||||||
|
do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid anyone to deny
|
||||||
|
you these rights or to ask you to surrender the rights. These restrictions
|
||||||
|
translate to certain responsibilities for you if you distribute copies of the
|
||||||
|
software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether gratis or for a
|
||||||
|
fee, you must give the recipients all the rights that you have. You must make
|
||||||
|
sure that they, too, receive or can get the source code. And you must show them
|
||||||
|
these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and (2) offer
|
||||||
|
you this license which gives you legal permission to copy, distribute and/or
|
||||||
|
modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain that
|
||||||
|
everyone understands that there is no warranty for this free software. If the
|
||||||
|
software is modified by someone else and passed on, we want its recipients to
|
||||||
|
know that what they have is not the original, so that any problems introduced by
|
||||||
|
others will not reflect on the original authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software patents. We wish
|
||||||
|
to avoid the danger that redistributors of a free program will individually
|
||||||
|
obtain patent licenses, in effect making the program proprietary. To prevent
|
||||||
|
this, we have made it clear that any patent must be licensed for everyone's free
|
||||||
|
use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and modification
|
||||||
|
follow.
|
||||||
|
|
||||||
|
|
||||||
|
Terms And Conditions For Copying, Distribution And Modification
|
||||||
|
---------------------------------------------------------------
|
||||||
|
|
||||||
|
**0.** This License applies to any program or other work which contains a notice
|
||||||
|
placed by the copyright holder saying it may be distributed under the terms of
|
||||||
|
this General Public License. The "Program", below, refers to any such program or
|
||||||
|
work, and a "work based on the Program" means either the Program or any
|
||||||
|
derivative work under copyright law: that is to say, a work containing the
|
||||||
|
Program or a portion of it, either verbatim or with modifications and/or
|
||||||
|
translated into another language. (Hereinafter, translation is included without
|
||||||
|
limitation in the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not covered by
|
||||||
|
this License; they are outside its scope. The act of running the Program is not
|
||||||
|
restricted, and the output from the Program is covered only if its contents
|
||||||
|
constitute a work based on the Program (independent of having been made by
|
||||||
|
running the Program). Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
**1.** You may copy and distribute verbatim copies of the Program's source code
|
||||||
|
as you receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice and
|
||||||
|
disclaimer of warranty; keep intact all the notices that refer to this License
|
||||||
|
and to the absence of any warranty; and give any other recipients of the Program
|
||||||
|
a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and you may at
|
||||||
|
your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
**2.** You may modify your copy or copies of the Program or any portion of it,
|
||||||
|
thus forming a work based on the Program, and copy and distribute such
|
||||||
|
modifications or work under the terms of Section 1 above, provided that you also
|
||||||
|
meet all of these conditions:
|
||||||
|
|
||||||
|
* **a)** You must cause the modified files to carry prominent notices stating
|
||||||
|
that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
* **b)** You must cause any work that you distribute or publish, that in whole
|
||||||
|
or in part contains or is derived from the Program or any part thereof, to
|
||||||
|
be licensed as a whole at no charge to all third parties under the terms of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
* **c)** If the modified program normally reads commands interactively when
|
||||||
|
run, you must cause it, when started running for such interactive use in the
|
||||||
|
most ordinary way, to print or display an announcement including an
|
||||||
|
appropriate copyright notice and a notice that there is no warranty (or
|
||||||
|
else, saying that you provide a warranty) and that users may redistribute
|
||||||
|
the program under these conditions, and telling the user how to view a copy
|
||||||
|
of this License. (Exception: if the Program itself is interactive but does
|
||||||
|
not normally print such an announcement, your work based on the Program is
|
||||||
|
not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If identifiable
|
||||||
|
sections of that work are not derived from the Program, and can be reasonably
|
||||||
|
considered independent and separate works in themselves, then this License, and
|
||||||
|
its terms, do not apply to those sections when you distribute them as separate
|
||||||
|
works. But when you distribute the same sections as part of a whole which is a
|
||||||
|
work based on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the entire whole,
|
||||||
|
and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest your
|
||||||
|
rights to work written entirely by you; rather, the intent is to exercise the
|
||||||
|
right to control the distribution of derivative or collective works based on the
|
||||||
|
Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program with the
|
||||||
|
Program (or with a work based on the Program) on a volume of a storage or
|
||||||
|
distribution medium does not bring the other work under the scope of this
|
||||||
|
License.
|
||||||
|
|
||||||
|
**3.** You may copy and distribute the Program (or a work based on it, under
|
||||||
|
Section 2) in object code or executable form under the terms of Sections 1 and 2
|
||||||
|
above provided that you also do one of the following:
|
||||||
|
|
||||||
|
* **a)** Accompany it with the complete corresponding machine-readable source
|
||||||
|
code, which must be distributed under the terms of Sections 1 and 2 above on
|
||||||
|
a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
* **b)** Accompany it with a written offer, valid for at least three years, to
|
||||||
|
give any third party, for a charge no more than your cost of physically
|
||||||
|
performing source distribution, a complete machine-readable copy of the
|
||||||
|
corresponding source code, to be distributed under the terms of Sections 1
|
||||||
|
and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
* **c)** Accompany it with the information you received as to the offer to
|
||||||
|
distribute corresponding source code. (This alternative is allowed only for
|
||||||
|
noncommercial distribution and only if you received the program in object
|
||||||
|
code or executable form with such an offer, in accord with Subsection b
|
||||||
|
above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for making
|
||||||
|
modifications to it. For an executable work, complete source code means all the
|
||||||
|
source code for all modules it contains, plus any associated interface
|
||||||
|
definition files, plus the scripts used to control compilation and installation
|
||||||
|
of the executable. However, as a special exception, the source code distributed
|
||||||
|
need not include anything that is normally distributed (in either source or
|
||||||
|
binary form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component itself
|
||||||
|
accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the source code
|
||||||
|
from the same place counts as distribution of the source code, even though third
|
||||||
|
parties are not compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
**4.** You may not copy, modify, sublicense, or distribute the Program except as
|
||||||
|
expressly provided under this License. Any attempt otherwise to copy, modify,
|
||||||
|
sublicense or distribute the Program is void, and will automatically terminate
|
||||||
|
your rights under this License. However, parties who have received copies, or
|
||||||
|
rights, from you under this License will not have their licenses terminated so
|
||||||
|
long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
**5.** You are not required to accept this License, since you have not signed
|
||||||
|
it. However, nothing else grants you permission to modify or distribute the
|
||||||
|
Program or its derivative works. These actions are prohibited by law if you do
|
||||||
|
not accept this License. Therefore, by modifying or distributing the Program (or
|
||||||
|
any work based on the Program), you indicate your acceptance of this License to
|
||||||
|
do so, and all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
**6.** Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the original
|
||||||
|
licensor to copy, distribute or modify the Program subject to these terms and
|
||||||
|
conditions. You may not impose any further restrictions on the recipients'
|
||||||
|
exercise of the rights granted herein. You are not responsible for enforcing
|
||||||
|
compliance by third parties to this License.
|
||||||
|
|
||||||
|
**7.** If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues), conditions
|
||||||
|
are imposed on you (whether by court order, agreement or otherwise) that
|
||||||
|
contradict the conditions of this License, they do not excuse you from the
|
||||||
|
conditions of this License. If you cannot distribute so as to satisfy
|
||||||
|
simultaneously your obligations under this License and any other pertinent
|
||||||
|
obligations, then as a consequence you may not distribute the Program at all.
|
||||||
|
For example, if a patent license would not permit royalty-free redistribution of
|
||||||
|
the Program by all those who receive copies directly or indirectly through you,
|
||||||
|
then the only way you could satisfy both it and this License would be to refrain
|
||||||
|
entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply and the
|
||||||
|
section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any patents or
|
||||||
|
other property right claims or to contest validity of any such claims; this
|
||||||
|
section has the sole purpose of protecting the integrity of the free software
|
||||||
|
distribution system, which is implemented by public license practices. Many
|
||||||
|
people have made generous contributions to the wide range of software
|
||||||
|
distributed through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing to
|
||||||
|
distribute software through any other system and a licensee cannot impose that
|
||||||
|
choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to be a
|
||||||
|
consequence of the rest of this License.
|
||||||
|
|
||||||
|
**8.** If the distribution and/or use of the Program is restricted in certain
|
||||||
|
countries either by patents or by copyrighted interfaces, the original copyright
|
||||||
|
holder who places the Program under this License may add an explicit
|
||||||
|
geographical distribution limitation excluding those countries, so that
|
||||||
|
distribution is permitted only in or among countries not thus excluded. In such
|
||||||
|
case, this License incorporates the limitation as if written in the body of this
|
||||||
|
License.
|
||||||
|
|
||||||
|
**9.** The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the General Public License from time to time. Such new versions will be similar
|
||||||
|
in spirit to the present version, but may differ in detail to address new
|
||||||
|
problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program specifies
|
||||||
|
a version number of this License which applies to it and "any later version",
|
||||||
|
you have the option of following the terms and conditions either of that version
|
||||||
|
or of any later version published by the Free Software Foundation. If the
|
||||||
|
Program does not specify a version number of this License, you may choose any
|
||||||
|
version ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
**10.** If you wish to incorporate parts of the Program into other free programs
|
||||||
|
whose distribution conditions are different, write to the author to ask for
|
||||||
|
permission. For software which is copyrighted by the Free Software Foundation,
|
||||||
|
write to the Free Software Foundation; we sometimes make exceptions for this.
|
||||||
|
Our decision will be guided by the two goals of preserving the free status of
|
||||||
|
all derivatives of our free software and of promoting the sharing and reuse of
|
||||||
|
software generally.
|
||||||
|
|
||||||
|
|
||||||
|
No Warranty
|
||||||
|
-----------
|
||||||
|
|
||||||
|
**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
|
||||||
|
THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
|
||||||
|
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
|
||||||
|
"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
|
||||||
|
INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
|
||||||
|
BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER
|
||||||
|
OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
# Digital Voice Modem Firmware (Hotspot)
|
||||||
|
|
||||||
|
The DVM firmware provides the embedded microcontroller implementation of a mixed-mode DMR/P25 or dedicated-mode DMR or P25 repeater system. The firmware; is the portion of a complete Over-The-Air modem implementation that uses an ADF7021 to provide a raw RF interface.
|
||||||
|
|
||||||
|
This project is a direct fork of the MMDVM (https://github.com/jelimoore/MMDVM_HS) project.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
Please see the various Makefile's included in the project for more information. This project includes a few Makefiles to target different hardware. (All following information assumes familiarity with the standard Linux make system.)
|
||||||
|
|
||||||
|
* Makefile - This makefile is used for targeting a generic STM32F103/ADF7021 device.
|
||||||
|
|
||||||
|
* For STM32F103 using Ubuntu OS install the standard ARM embedded toolchain (typically arm-gcc-none-eabi).
|
||||||
|
1. Create a directory under "/opt" called "tools" and change to the directory:
|
||||||
|
```
|
||||||
|
mkdir -p /opt/tools
|
||||||
|
cd /opt/tools
|
||||||
|
```
|
||||||
|
2. Checkout ```https://github.com/juribeparada/STM32F10X_Lib``` to /opt/tools:
|
||||||
|
```git clone https://github.com/juribeparada/STM32F10X_Lib```
|
||||||
|
|
||||||
|
Use the ```make``` command to build the firmware, choosing the appropriate makefile with the -F switch.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the GPLv2 License - see the [LICENSE.md](LICENSE.md) file for details. Use of this project is intended, strictly for amateur and educational use ONLY. Any other use is at the risk of user and all commercial purposes are strictly forbidden.
|
||||||
|
|
||||||
@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (c) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(STM32F10X_MD) || defined(STM32F4XX)
|
||||||
|
|
||||||
|
#include "STM_UART.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the STM_UART class.
|
||||||
|
/// </summary>
|
||||||
|
STM_UART::STM_UART() :
|
||||||
|
m_usart(NULL)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
/// <param name="usart"></param>
|
||||||
|
void STM_UART::init(USART_TypeDef* usart)
|
||||||
|
{
|
||||||
|
m_usart = usart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
void STM_UART::write(const uint8_t* data, uint16_t length)
|
||||||
|
{
|
||||||
|
if (length == 0U || m_usart == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
m_txFifo.put(data[0]);
|
||||||
|
USART_ITConfig(m_usart, USART_IT_TXE, ENABLE);//switch TX IRQ is on
|
||||||
|
|
||||||
|
for (uint16_t i = 1U; i < length; i++) {
|
||||||
|
m_txFifo.put(data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
USART_ITConfig(m_usart, USART_IT_TXE, ENABLE);//make sure TX IRQ is on
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t STM_UART::read()
|
||||||
|
{
|
||||||
|
return m_rxFifo.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void STM_UART::handleIRQ()
|
||||||
|
{
|
||||||
|
if (m_usart == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (USART_GetITStatus(m_usart, USART_IT_RXNE)) {
|
||||||
|
if (!m_rxFifo.isFull())
|
||||||
|
m_rxFifo.put((uint8_t)USART_ReceiveData(m_usart));
|
||||||
|
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (USART_GetITStatus(m_usart, USART_IT_TXE)) {
|
||||||
|
if (!m_txFifo.isEmpty())
|
||||||
|
USART_SendData(m_usart, m_txFifo.get());
|
||||||
|
|
||||||
|
USART_ClearITPendingBit(m_usart, USART_IT_TXE);
|
||||||
|
|
||||||
|
if (m_txFifo.isEmpty()) // if there's no more data to transmit then turn off TX interrupts
|
||||||
|
USART_ITConfig(m_usart, USART_IT_TXE, DISABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes the transmit shift register.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This call is blocking!
|
||||||
|
/// </remarks>
|
||||||
|
void STM_UART::flush()
|
||||||
|
{
|
||||||
|
if (m_usart == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// wait until the TXE shows the shift register is empty
|
||||||
|
while (USART_GetITStatus(m_usart, USART_FLAG_TXE))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint16_t STM_UART::available()
|
||||||
|
{
|
||||||
|
return m_rxFifo.isEmpty() ? 0U : 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint16_t STM_UART::availableForWrite()
|
||||||
|
{
|
||||||
|
return m_txFifo.isFull() ? 0U : 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,137 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (c) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(STM32F10X_MD) || defined(STM32F4XX)
|
||||||
|
#if !defined(__STM_UART_H__)
|
||||||
|
#define __STM_UART_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
#if defined(STM32F10X_MD)
|
||||||
|
#include <stm32f10x.h>
|
||||||
|
#elif defined(STM32F4XX)
|
||||||
|
#include "stm32f4xx.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const uint16_t BUFFER_SIZE = 2048U; //needs to be a power of 2 !
|
||||||
|
const uint16_t BUFFER_MASK = BUFFER_SIZE - 1;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// This class represents a FIFO buffer on a STM32 UART.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API STM_UARTFIFO {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the STM_UARTFIFO class.</summary>
|
||||||
|
STM_UARTFIFO() :
|
||||||
|
m_head(0U),
|
||||||
|
m_tail(0U)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
uint8_t get()
|
||||||
|
{
|
||||||
|
return m_buffer[BUFFER_MASK & (m_tail++)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void put(uint8_t data)
|
||||||
|
{
|
||||||
|
m_buffer[BUFFER_MASK & (m_head++)] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Helper to reset data values to defaults.</summary>
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
m_tail = 0U;
|
||||||
|
m_head = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
bool isEmpty()
|
||||||
|
{
|
||||||
|
return m_tail == m_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
bool isFull()
|
||||||
|
{
|
||||||
|
return ((m_head + 1U) & BUFFER_MASK) == (m_tail & BUFFER_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
volatile uint8_t m_buffer[BUFFER_SIZE];
|
||||||
|
volatile uint16_t m_head;
|
||||||
|
volatile uint16_t m_tail;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// This class represents an STM32 UART.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class STM_UART {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the STM_UART class.</summary>
|
||||||
|
STM_UART();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void init(USART_TypeDef* usart);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
uint8_t read();
|
||||||
|
/// <summary></summary>
|
||||||
|
void write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void handleIRQ();
|
||||||
|
|
||||||
|
/// <summary>Flushes the transmit shift register.</summary>
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
uint16_t available();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
uint16_t availableForWrite();
|
||||||
|
|
||||||
|
private:
|
||||||
|
USART_TypeDef* m_usart;
|
||||||
|
|
||||||
|
STM_UARTFIFO m_rxFifo;
|
||||||
|
STM_UARTFIFO m_txFifo;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SERIAL_PORT_H__
|
||||||
|
#endif
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin KI6ZUM
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "SerialBuffer.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the SerialBuffer class.
|
||||||
|
/// </summary>
|
||||||
|
SerialBuffer::SerialBuffer(uint16_t length) :
|
||||||
|
m_length(length),
|
||||||
|
m_buffer(NULL),
|
||||||
|
m_head(0U),
|
||||||
|
m_tail(0U),
|
||||||
|
m_full(false)
|
||||||
|
{
|
||||||
|
m_buffer = new uint8_t[length];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to get how much space the ring buffer has for samples.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint16_t SerialBuffer::getSpace() const
|
||||||
|
{
|
||||||
|
uint16_t n = 0U;
|
||||||
|
|
||||||
|
if (m_tail == m_head)
|
||||||
|
n = m_full ? 0U : m_length;
|
||||||
|
else if (m_tail < m_head)
|
||||||
|
n = m_length - m_head + m_tail;
|
||||||
|
else
|
||||||
|
n = m_tail - m_head;
|
||||||
|
|
||||||
|
if (n > m_length)
|
||||||
|
n = 0U;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint16_t SerialBuffer::getData() const
|
||||||
|
{
|
||||||
|
if (m_tail == m_head)
|
||||||
|
return m_full ? m_length : 0U;
|
||||||
|
else if (m_tail < m_head)
|
||||||
|
return m_head - m_tail;
|
||||||
|
else
|
||||||
|
return m_length - m_tail + m_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to reset data values to defaults.
|
||||||
|
/// </summary>
|
||||||
|
void SerialBuffer::reset()
|
||||||
|
{
|
||||||
|
m_head = 0U;
|
||||||
|
m_tail = 0U;
|
||||||
|
m_full = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool SerialBuffer::put(uint8_t c)
|
||||||
|
{
|
||||||
|
if (m_full)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_buffer[m_head] = c;
|
||||||
|
|
||||||
|
m_head++;
|
||||||
|
if (m_head >= m_length)
|
||||||
|
m_head = 0U;
|
||||||
|
|
||||||
|
if (m_head == m_tail)
|
||||||
|
m_full = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t SerialBuffer::peek() const
|
||||||
|
{
|
||||||
|
return m_buffer[m_tail];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t SerialBuffer::get()
|
||||||
|
{
|
||||||
|
uint8_t value = m_buffer[m_tail];
|
||||||
|
|
||||||
|
m_full = false;
|
||||||
|
|
||||||
|
m_tail++;
|
||||||
|
if (m_tail >= m_length)
|
||||||
|
m_tail = 0U;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
* Serial FIFO Control Copyright (C) 2015 by James McLaughlin KI6ZUM
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#if !defined(__SERIAL_RB_H__)
|
||||||
|
#define __SERIAL_RB_H__
|
||||||
|
|
||||||
|
#if defined(STM32F10X_MD)
|
||||||
|
#include "stm32f10x.h"
|
||||||
|
#elif defined(STM32F4XX)
|
||||||
|
#include "stm32f4xx.h"
|
||||||
|
#include <cstddef>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint16_t SERIAL_RINGBUFFER_SIZE = 1000U;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements a circular buffer for serial data.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API SerialBuffer {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the SerialBuffer class.</summary>
|
||||||
|
SerialBuffer(uint16_t length = SERIAL_RINGBUFFER_SIZE);
|
||||||
|
|
||||||
|
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
|
||||||
|
uint16_t getSpace() const;
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
uint16_t getData() const;
|
||||||
|
|
||||||
|
/// <summary>Helper to reset data values to defaults.</summary>
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
bool put(uint8_t c);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
uint8_t peek() const;
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
uint8_t get();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t m_length;
|
||||||
|
volatile uint8_t* m_buffer;
|
||||||
|
|
||||||
|
volatile uint16_t m_head;
|
||||||
|
volatile uint16_t m_tail;
|
||||||
|
|
||||||
|
volatile bool m_full;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SERIAL_RB_H__
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,218 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2018,2020,2021 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2018,2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__SERIAL_PORT_H__)
|
||||||
|
#define __SERIAL_PORT_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "SerialBuffer.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum DVM_STATE {
|
||||||
|
STATE_IDLE = 0U,
|
||||||
|
// DMR
|
||||||
|
STATE_DMR = 1U,
|
||||||
|
// Project 25
|
||||||
|
STATE_P25 = 2U,
|
||||||
|
|
||||||
|
// CW
|
||||||
|
STATE_CW = 10U,
|
||||||
|
|
||||||
|
// Calibration States
|
||||||
|
STATE_P25_LF_CAL = 91U,
|
||||||
|
STATE_P25_CAL_1K = 92U,
|
||||||
|
|
||||||
|
STATE_DMR_DMO_CAL_1K = 93U,
|
||||||
|
STATE_DMR_CAL_1K = 94U,
|
||||||
|
STATE_DMR_LF_CAL = 95U,
|
||||||
|
|
||||||
|
STATE_RSSI_CAL = 96U,
|
||||||
|
|
||||||
|
STATE_P25_CAL = 97U,
|
||||||
|
STATE_DMR_CAL = 98U,
|
||||||
|
STATE_INT_CAL = 99U
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DVM_COMMANDS {
|
||||||
|
CMD_GET_VERSION = 0x00U,
|
||||||
|
CMD_GET_STATUS = 0x01U,
|
||||||
|
CMD_SET_CONFIG = 0x02U,
|
||||||
|
CMD_SET_MODE = 0x03U,
|
||||||
|
|
||||||
|
CMD_SET_SYMLVLADJ = 0x04U,
|
||||||
|
CMD_SET_RXLEVEL = 0x05U,
|
||||||
|
CMD_SET_RFPARAMS = 0x06U,
|
||||||
|
|
||||||
|
CMD_CAL_DATA = 0x08U,
|
||||||
|
CMD_RSSI_DATA = 0x09U,
|
||||||
|
|
||||||
|
CMD_SEND_CWID = 0x0AU,
|
||||||
|
|
||||||
|
CMD_DMR_DATA1 = 0x18U,
|
||||||
|
CMD_DMR_LOST1 = 0x19U,
|
||||||
|
CMD_DMR_DATA2 = 0x1AU,
|
||||||
|
CMD_DMR_LOST2 = 0x1BU,
|
||||||
|
CMD_DMR_SHORTLC = 0x1CU,
|
||||||
|
CMD_DMR_START = 0x1DU,
|
||||||
|
CMD_DMR_ABORT = 0x1EU,
|
||||||
|
|
||||||
|
CMD_P25_DATA = 0x31U,
|
||||||
|
CMD_P25_LOST = 0x32U,
|
||||||
|
CMD_P25_CLEAR = 0x33U,
|
||||||
|
|
||||||
|
CMD_ACK = 0x70U,
|
||||||
|
CMD_NAK = 0x7FU,
|
||||||
|
|
||||||
|
CMD_DEBUG1 = 0xF1U,
|
||||||
|
CMD_DEBUG2 = 0xF2U,
|
||||||
|
CMD_DEBUG3 = 0xF3U,
|
||||||
|
CMD_DEBUG4 = 0xF4U,
|
||||||
|
CMD_DEBUG5 = 0xF5U,
|
||||||
|
CMD_DEBUG_DUMP = 0xFAU,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CMD_REASON_CODE {
|
||||||
|
RSN_OK = 0U,
|
||||||
|
RSN_NAK = 1U,
|
||||||
|
|
||||||
|
RSN_ILLEGAL_LENGTH = 2U,
|
||||||
|
RSN_INVALID_REQUEST = 4U,
|
||||||
|
RSN_RINGBUFF_FULL = 8U,
|
||||||
|
|
||||||
|
RSN_INVALID_FDMA_PREAMBLE = 10U,
|
||||||
|
RSN_INVALID_MODE = 11U,
|
||||||
|
|
||||||
|
RSN_INVALID_DMR_CC = 12U,
|
||||||
|
RSN_INVALID_DMR_SLOT = 13U,
|
||||||
|
RSN_INVALID_DMR_START = 14U,
|
||||||
|
RSN_INVALID_DMR_RX_DELAY = 15U,
|
||||||
|
|
||||||
|
RSN_INVALID_P25_CORR_COUNT = 16U,
|
||||||
|
|
||||||
|
RSN_DMR_DISABLED = 63U,
|
||||||
|
RSN_P25_DISABLED = 64U,
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t DVM_FRAME_START = 0xFEU;
|
||||||
|
|
||||||
|
#define SERIAL_SPEED 115200
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements the RS232 serial bus to communicate with the HOST S/W.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API SerialPort {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the SerialPort class.</summary>
|
||||||
|
SerialPort();
|
||||||
|
|
||||||
|
/// <summary>Starts serial port communications.</summary>
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/// <summary>Process data from serial port.</summary>
|
||||||
|
void process();
|
||||||
|
|
||||||
|
/// <summary>Write DMR frame data to serial port.</summary>
|
||||||
|
void writeDMRData(bool slot, const uint8_t* data, uint8_t length);
|
||||||
|
/// <summary>Write lost DMR frame data to serial port.</summary>
|
||||||
|
void writeDMRLost(bool slot);
|
||||||
|
|
||||||
|
/// <summary>Write P25 frame data to serial port.</summary>
|
||||||
|
void writeP25Data(const uint8_t* data, uint8_t length);
|
||||||
|
/// <summary>Write lost P25 frame data to serial port.</summary>
|
||||||
|
void writeP25Lost();
|
||||||
|
|
||||||
|
/// <summary>Write calibration frame data to serial port.</summary>
|
||||||
|
void writeCalData(const uint8_t* data, uint8_t length);
|
||||||
|
/// <summary>Write RSSI frame data to serial port.</summary>
|
||||||
|
void writeRSSIData(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeDebug(const char* text);
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeDebug(const char* text, int16_t n1);
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeDebug(const char* text, int16_t n1, int16_t n2);
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3);
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeDebug(const char* text, int16_t n1, int16_t n2, int16_t n3, int16_t n4);
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeDump(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t m_buffer[256U];
|
||||||
|
uint8_t m_ptr;
|
||||||
|
uint8_t m_len;
|
||||||
|
|
||||||
|
bool m_debug;
|
||||||
|
bool m_firstCal;
|
||||||
|
|
||||||
|
/// <summary>Write acknowlegement.</summary>
|
||||||
|
void sendACK();
|
||||||
|
/// <summary>Write negative acknowlegement.</summary>
|
||||||
|
void sendNAK(uint8_t err);
|
||||||
|
/// <summary>Write modem DSP status.</summary>
|
||||||
|
void getStatus();
|
||||||
|
/// <summary>Write modem DSP version.</summary>
|
||||||
|
void getVersion();
|
||||||
|
/// <summary>Helper to validate the passed modem state is valid.</summary>
|
||||||
|
uint8_t modemStateCheck(DVM_STATE state);
|
||||||
|
/// <summary>Set modem DSP configuration from serial port data.</summary>
|
||||||
|
uint8_t setConfig(const uint8_t* data, uint8_t length);
|
||||||
|
/// <summary>Set modem DSP mode from serial port data.</summary>
|
||||||
|
uint8_t setMode(const uint8_t* data, uint8_t length);
|
||||||
|
/// <summary>Sets the modem state.</summary>
|
||||||
|
void setMode(DVM_STATE modemState);
|
||||||
|
/// <summary>Sets the fine-tune symbol levels.</summary>
|
||||||
|
uint8_t setSymbolLvlAdj(const uint8_t* data, uint8_t length);
|
||||||
|
/// <summary>Sets the RF parameters.</summary>
|
||||||
|
uint8_t setRFParams(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
// Hardware specific routines
|
||||||
|
/// <summary></summary>
|
||||||
|
void beginInt(uint8_t n, int speed);
|
||||||
|
/// <summary></summary>
|
||||||
|
int availableInt(uint8_t n);
|
||||||
|
/// <summary></summary>
|
||||||
|
int availableForWriteInt(uint8_t n);
|
||||||
|
/// <summary></summary>
|
||||||
|
uint8_t readInt(uint8_t n);
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush = false);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __SERIAL_PORT_H__
|
||||||
@ -0,0 +1,316 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
|
||||||
|
* Copyright (C) 2016,2017,2018,2019 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "SerialPort.h"
|
||||||
|
#include "STM_UART.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Pin definitions:
|
||||||
|
|
||||||
|
- Host communication:
|
||||||
|
1) USART1 - TXD PA9 - RXD PA10
|
||||||
|
2) USB VCOM
|
||||||
|
|
||||||
|
- Serial repeater
|
||||||
|
USART2 - TXD PA2 - RXD PA3
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(STM32F10X_MD)
|
||||||
|
|
||||||
|
#if defined(STM32_USB_HOST)
|
||||||
|
#include <usb_serial.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(STM32_USART1_HOST) && defined(STM32_USB_HOST)
|
||||||
|
#error "You have to select STM32_USART1_HOST or STM32_USB_HOST, but not both"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(STM32_USART1_HOST) || defined(SERIAL_REPEATER_USART1)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Global Functions and Variables
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void USART1_IRQHandler();
|
||||||
|
void USART2_IRQHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// UART1
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static STM_UART m_USART1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void USART1_IRQHandler()
|
||||||
|
{
|
||||||
|
m_USART1.handleIRQ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="speed"></param>
|
||||||
|
void InitUSART1(int speed)
|
||||||
|
{
|
||||||
|
// USART1 - TXD PA9 - RXD PA10
|
||||||
|
GPIO_InitTypeDef GPIO_InitStructure;
|
||||||
|
USART_InitTypeDef USART_InitStructure;
|
||||||
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
|
||||||
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
|
||||||
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
||||||
|
|
||||||
|
// USART IRQ init
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 15;
|
||||||
|
NVIC_Init(&NVIC_InitStructure);
|
||||||
|
|
||||||
|
// Configure USART as alternate function
|
||||||
|
GPIO_StructInit(&GPIO_InitStructure);
|
||||||
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||||
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // Tx
|
||||||
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||||
|
|
||||||
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // Rx
|
||||||
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||||
|
|
||||||
|
// Configure USART baud rate
|
||||||
|
USART_StructInit(&USART_InitStructure);
|
||||||
|
USART_InitStructure.USART_BaudRate = speed;
|
||||||
|
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
||||||
|
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
||||||
|
USART_InitStructure.USART_Parity = USART_Parity_No;
|
||||||
|
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
||||||
|
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
|
||||||
|
USART_Init(USART1, &USART_InitStructure);
|
||||||
|
|
||||||
|
USART_Cmd(USART1, ENABLE);
|
||||||
|
|
||||||
|
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
|
||||||
|
|
||||||
|
m_USART1.init(USART1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// UART2
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static STM_UART m_USART2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void USART2_IRQHandler()
|
||||||
|
{
|
||||||
|
m_USART2.handleIRQ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="speed"></param>
|
||||||
|
void InitUSART2(int speed)
|
||||||
|
{
|
||||||
|
// USART2 - TXD PA2 - RXD PA3
|
||||||
|
GPIO_InitTypeDef GPIO_InitStructure;
|
||||||
|
USART_InitTypeDef USART_InitStructure;
|
||||||
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
|
||||||
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
|
||||||
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
|
||||||
|
|
||||||
|
// USART IRQ init
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 15;
|
||||||
|
NVIC_Init(&NVIC_InitStructure);
|
||||||
|
|
||||||
|
// Configure USART as alternate function
|
||||||
|
GPIO_StructInit(&GPIO_InitStructure);
|
||||||
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||||
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; // Tx
|
||||||
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||||
|
|
||||||
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // Rx
|
||||||
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||||
|
|
||||||
|
// Configure USART baud rate
|
||||||
|
USART_StructInit(&USART_InitStructure);
|
||||||
|
USART_InitStructure.USART_BaudRate = speed;
|
||||||
|
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
||||||
|
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
||||||
|
USART_InitStructure.USART_Parity = USART_Parity_No;
|
||||||
|
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
||||||
|
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
|
||||||
|
USART_Init(USART2, &USART_InitStructure);
|
||||||
|
|
||||||
|
USART_Cmd(USART2, ENABLE);
|
||||||
|
|
||||||
|
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
|
||||||
|
|
||||||
|
m_USART2.init(USART2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n"></param>
|
||||||
|
/// <param name="speed"></param>
|
||||||
|
void SerialPort::beginInt(uint8_t n, int speed)
|
||||||
|
{
|
||||||
|
switch (n) {
|
||||||
|
case 1U:
|
||||||
|
#if defined(STM32_USART1_HOST)
|
||||||
|
InitUSART1(speed);
|
||||||
|
#elif defined(STM32_USB_HOST)
|
||||||
|
usbserial.begin();
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case 3U:
|
||||||
|
InitUSART2(speed);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int SerialPort::availableInt(uint8_t n)
|
||||||
|
{
|
||||||
|
switch (n) {
|
||||||
|
case 1U:
|
||||||
|
#if defined(STM32_USART1_HOST)
|
||||||
|
return m_USART1.available();
|
||||||
|
#elif defined(STM32_USB_HOST)
|
||||||
|
return usbserial.available();
|
||||||
|
#endif
|
||||||
|
case 3U:
|
||||||
|
m_USART2.available();
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int SerialPort::availableForWriteInt(uint8_t n)
|
||||||
|
{
|
||||||
|
switch (n) {
|
||||||
|
case 1U:
|
||||||
|
#if defined(STM32_USART1_HOST)
|
||||||
|
return m_USART1.availableForWrite();
|
||||||
|
#elif defined(STM32_USB_HOST)
|
||||||
|
return usbserial.availableForWrite();
|
||||||
|
#endif
|
||||||
|
case 3U:
|
||||||
|
return m_USART2.availableForWrite();
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t SerialPort::readInt(uint8_t n)
|
||||||
|
{
|
||||||
|
switch (n) {
|
||||||
|
case 1U:
|
||||||
|
#if defined(STM32_USART1_HOST)
|
||||||
|
return m_USART1.read();
|
||||||
|
#elif defined(STM32_USB_HOST)
|
||||||
|
return usbserial.read();
|
||||||
|
#endif
|
||||||
|
case 3U:
|
||||||
|
return m_USART2.read();
|
||||||
|
default:
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <param name="flush"></param>
|
||||||
|
void SerialPort::writeInt(uint8_t n, const uint8_t* data, uint16_t length, bool flush)
|
||||||
|
{
|
||||||
|
switch (n) {
|
||||||
|
case 1U:
|
||||||
|
#if defined(STM32_USART1_HOST)
|
||||||
|
m_USART1.write(data, length);
|
||||||
|
if (flush)
|
||||||
|
m_USART1.flush();
|
||||||
|
#elif defined(STM32_USB_HOST)
|
||||||
|
usbserial.write(data, length);
|
||||||
|
if (flush)
|
||||||
|
usbserial.flush();
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case 3U:
|
||||||
|
m_USART2.write(data, length);
|
||||||
|
if (flush)
|
||||||
|
m_USART2.flush();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants/Macros
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint8_t BITS_TABLE[] = {
|
||||||
|
# define B2(n) n, n+1, n+1, n+2
|
||||||
|
# define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
|
||||||
|
# define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
|
||||||
|
B6(0), B6(1), B6(1), B6(2)
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Global Functions
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
uint8_t countBits8(uint8_t bits)
|
||||||
|
{
|
||||||
|
return BITS_TABLE[bits];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t countBits16(uint16_t bits)
|
||||||
|
{
|
||||||
|
uint8_t* p = (uint8_t*)&bits;
|
||||||
|
uint8_t n = 0U;
|
||||||
|
n += BITS_TABLE[p[0U]];
|
||||||
|
n += BITS_TABLE[p[1U]];
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t countBits32(uint32_t bits)
|
||||||
|
{
|
||||||
|
uint8_t* p = (uint8_t*)&bits;
|
||||||
|
uint8_t n = 0U;
|
||||||
|
n += BITS_TABLE[p[0U]];
|
||||||
|
n += BITS_TABLE[p[1U]];
|
||||||
|
n += BITS_TABLE[p[2U]];
|
||||||
|
n += BITS_TABLE[p[3U]];
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t countBits64(uint64_t bits)
|
||||||
|
{
|
||||||
|
uint8_t* p = (uint8_t*)&bits;
|
||||||
|
uint8_t n = 0U;
|
||||||
|
n += BITS_TABLE[p[0U]];
|
||||||
|
n += BITS_TABLE[p[1U]];
|
||||||
|
n += BITS_TABLE[p[2U]];
|
||||||
|
n += BITS_TABLE[p[3U]];
|
||||||
|
n += BITS_TABLE[p[4U]];
|
||||||
|
n += BITS_TABLE[p[5U]];
|
||||||
|
n += BITS_TABLE[p[6U]];
|
||||||
|
n += BITS_TABLE[p[7U]];
|
||||||
|
return n;
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__UTILS_H__)
|
||||||
|
#define __UTILS_H__
|
||||||
|
|
||||||
|
#if defined(STM32F10X_MD)
|
||||||
|
#include "stm32f10x.h"
|
||||||
|
#elif defined(STM32F4XX)
|
||||||
|
#include "stm32f4xx.h"
|
||||||
|
#elif defined(STM32F7XX)
|
||||||
|
#include "stm32f7xx.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Global Functions
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DSP_FW_API uint8_t countBits8(uint8_t bits);
|
||||||
|
DSP_FW_API uint8_t countBits16(uint16_t bits);
|
||||||
|
DSP_FW_API uint8_t countBits32(uint32_t bits);
|
||||||
|
DSP_FW_API uint8_t countBits64(ulong64_t bits);
|
||||||
|
|
||||||
|
#endif // __UTILS_H__
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Memory areas */
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ROM (rx) : ORIGIN = 0x08002000, LENGTH = 120K /* FLASH */
|
||||||
|
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K /* Main RAM */
|
||||||
|
}
|
||||||
|
|
||||||
|
INCLUDE stm32f10x_link.ld
|
||||||
@ -0,0 +1,286 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2018,2019 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "dmr/CalDMR.h"
|
||||||
|
|
||||||
|
using namespace dmr;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Voice LC Header, CC: 1, srcID: 1, dstID: TG9
|
||||||
|
const uint8_t VH_1K[] = { 0x00U,
|
||||||
|
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
|
||||||
|
0x60U, 0x84U, 0x6DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xDEU, 0x30U, 0x30U,
|
||||||
|
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU };
|
||||||
|
|
||||||
|
// Voice Term with LC, CC: 1, srcID: 1, dstID: TG9
|
||||||
|
const uint8_t VT_1K[] = { 0x00U,
|
||||||
|
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
|
||||||
|
0xC0U, 0x84U, 0xADU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD9U, 0x65U, 0x24U,
|
||||||
|
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU };
|
||||||
|
|
||||||
|
// Voice LC MS Header, CC: 1, srcID: 1, dstID: TG9
|
||||||
|
const uint8_t VH_DMO1K[] = { 0x00U,
|
||||||
|
0x00U, 0x20U, 0x08U, 0x08U, 0x02U, 0x38U, 0x15U, 0x00U, 0x2CU, 0xA0U, 0x14U,
|
||||||
|
0x60U, 0x84U, 0x6DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x7EU, 0x30U, 0x30U,
|
||||||
|
0x01U, 0x10U, 0x01U, 0x40U, 0x03U, 0xC0U, 0x13U, 0xC1U, 0x1EU, 0x80U, 0x6FU };
|
||||||
|
|
||||||
|
// Voice Term MS with LC, CC: 1, srcID: 1, dstID: TG9
|
||||||
|
const uint8_t VT_DMO1K[] = { 0x00U,
|
||||||
|
0x00U, 0x4FU, 0x08U, 0xDCU, 0x02U, 0x88U, 0x15U, 0x78U, 0x2CU, 0xD0U, 0x14U,
|
||||||
|
0xC0U, 0x84U, 0xADU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x79U, 0x65U, 0x24U,
|
||||||
|
0x02U, 0x28U, 0x06U, 0x20U, 0x0FU, 0x80U, 0x1BU, 0xC1U, 0x07U, 0x80U, 0x5CU };
|
||||||
|
|
||||||
|
// Voice coding data + FEC, 1031 Hz Test Pattern
|
||||||
|
const uint8_t VOICE_1K[] = { 0x00U,
|
||||||
|
0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU, 0xCEU, 0xA8U,
|
||||||
|
0xFEU, 0x83U, 0xA0U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x0CU, 0xC4U, 0x58U,
|
||||||
|
0x20U, 0x0AU, 0xCEU, 0xA8U, 0xFEU, 0x83U, 0xACU, 0xC4U, 0x58U, 0x20U, 0x0AU };
|
||||||
|
|
||||||
|
// Embedded LC: CC: 1, srcID: 1, dstID: TG9
|
||||||
|
const uint8_t SYNCEMB_1K[6][7] = {
|
||||||
|
{ 0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U }, // BS VOICE SYNC (audio seq 0)
|
||||||
|
{ 0x01U, 0x30U, 0x00U, 0x00U, 0x90U, 0x09U, 0x10U }, // EMB + Embedded LC1 (audio seq 1)
|
||||||
|
{ 0x01U, 0x70U, 0x00U, 0x90U, 0x00U, 0x07U, 0x40U }, // EMB + Embedded LC2 (audio seq 2)
|
||||||
|
{ 0x01U, 0x70U, 0x00U, 0x31U, 0x40U, 0x07U, 0x40U }, // EMB + Embedded LC3 (audio seq 3)
|
||||||
|
{ 0x01U, 0x50U, 0xA1U, 0x71U, 0xD1U, 0x70U, 0x70U }, // EMB + Embedded LC4 (audio seq 4)
|
||||||
|
{ 0x01U, 0x10U, 0x00U, 0x00U, 0x00U, 0x0EU, 0x20U } }; // EMB (audio seq 5)
|
||||||
|
|
||||||
|
// Embedded LC MS: CC: 1, srcID: 1, dstID: TG9
|
||||||
|
const uint8_t SYNCEMB_DMO1K[6][7] = {
|
||||||
|
{ 0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U }, // MS VOICE SYNC (audio seq 0)
|
||||||
|
{ 0x01U, 0x30U, 0x00U, 0x00U, 0x90U, 0x09U, 0x10U }, // EMB + Embedded LC1 (audio seq 1)
|
||||||
|
{ 0x01U, 0x70U, 0x00U, 0x90U, 0x00U, 0x07U, 0x40U }, // EMB + Embedded LC2 (audio seq 2)
|
||||||
|
{ 0x01U, 0x70U, 0x00U, 0x31U, 0x40U, 0x07U, 0x40U }, // EMB + Embedded LC3 (audio seq 3)
|
||||||
|
{ 0x01U, 0x50U, 0xA1U, 0x71U, 0xD1U, 0x70U, 0x70U }, // EMB + Embedded LC4 (audio seq 4)
|
||||||
|
{ 0x01U, 0x10U, 0x00U, 0x00U, 0x00U, 0x0EU, 0x20U } }; // EMB (audio seq 5)
|
||||||
|
|
||||||
|
// Short LC:
|
||||||
|
// TS1: dstID: 0, ACTIVITY_NONE
|
||||||
|
// TS2: dstID: TG9, ACTIVITY_VOICE
|
||||||
|
const uint8_t SHORTLC_1K[] = { 0x33U, 0x3AU, 0xA0U, 0x30U, 0x00U, 0x55U, 0xA6U, 0x5FU, 0x50U };
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the CalDMR class.
|
||||||
|
/// </summary>
|
||||||
|
CalDMR::CalDMR() :
|
||||||
|
m_transmit(false),
|
||||||
|
m_state(DMRCAL1K_IDLE),
|
||||||
|
m_frameStart(0U),
|
||||||
|
m_dmr1k(),
|
||||||
|
m_audioSeq(0),
|
||||||
|
m_count(0)
|
||||||
|
{
|
||||||
|
::memcpy(m_dmr1k, VOICE_1K, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process local state and transmit on the air interface.
|
||||||
|
/// </summary>
|
||||||
|
void CalDMR::process()
|
||||||
|
{
|
||||||
|
switch (m_calState) {
|
||||||
|
case STATE_DMR_CAL:
|
||||||
|
case STATE_DMR_LF_CAL:
|
||||||
|
if (m_transmit) {
|
||||||
|
dmrDMOTX.setCal(true);
|
||||||
|
dmrDMOTX.process();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dmrDMOTX.setCal(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STATE_DMR_CAL_1K:
|
||||||
|
dmr1kcal();
|
||||||
|
break;
|
||||||
|
case STATE_DMR_DMO_CAL_1K:
|
||||||
|
dmrDMO1kcal();
|
||||||
|
break;
|
||||||
|
case STATE_INT_CAL:
|
||||||
|
// Simple interrupt counter for board diagnostics (TCXO, connections, etc)
|
||||||
|
// Not intended for precise interrupt frequency measurements
|
||||||
|
m_count++;
|
||||||
|
if (m_count >= CAL_DLY_LOOP) {
|
||||||
|
m_count = 0U;
|
||||||
|
uint16_t int1, int2;
|
||||||
|
io.getIntCounter(int1, int2);
|
||||||
|
DEBUG3("Counter INT1/INT2:", int1 >> 1U, int2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n"></param>
|
||||||
|
void CalDMR::createData1k(uint8_t n)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 5U; i++)
|
||||||
|
m_dmr1k[i + 15U] = SYNCEMB_1K[n][i + 1U];
|
||||||
|
|
||||||
|
m_dmr1k[14U] &= 0xF0U;
|
||||||
|
m_dmr1k[20U] &= 0x0FU;
|
||||||
|
m_dmr1k[14U] |= SYNCEMB_1K[n][0] & 0x0FU;
|
||||||
|
m_dmr1k[20U] |= SYNCEMB_1K[n][6] & 0xF0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="n"></param>
|
||||||
|
void CalDMR::createDataDMO1k(uint8_t n)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < 5U; i++)
|
||||||
|
m_dmr1k[i + 15U] = SYNCEMB_DMO1K[n][i + 1U];
|
||||||
|
|
||||||
|
m_dmr1k[14U] &= 0xF0U;
|
||||||
|
m_dmr1k[20U] &= 0x0FU;
|
||||||
|
m_dmr1k[14U] |= SYNCEMB_DMO1K[n][0] & 0x0FU;
|
||||||
|
m_dmr1k[20U] |= SYNCEMB_DMO1K[n][6] & 0xF0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void CalDMR::dmr1kcal()
|
||||||
|
{
|
||||||
|
dmrTX.process();
|
||||||
|
|
||||||
|
uint16_t space = dmrTX.getSpace2();
|
||||||
|
if (space < 1U)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (m_state) {
|
||||||
|
case DMRCAL1K_VH:
|
||||||
|
dmrTX.setColorCode(1U);
|
||||||
|
dmrTX.writeShortLC(SHORTLC_1K, 9U);
|
||||||
|
dmrTX.writeData2(VH_1K, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
dmrTX.setStart(true);
|
||||||
|
m_state = DMRCAL1K_VOICE;
|
||||||
|
break;
|
||||||
|
case DMRCAL1K_VOICE:
|
||||||
|
createData1k(m_audioSeq);
|
||||||
|
dmrTX.writeData2(m_dmr1k, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
if (m_audioSeq == 5U) {
|
||||||
|
m_audioSeq = 0U;
|
||||||
|
if (!m_transmit)
|
||||||
|
m_state = DMRCAL1K_VT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_audioSeq++;
|
||||||
|
break;
|
||||||
|
case DMRCAL1K_VT:
|
||||||
|
dmrTX.writeData2(VT_1K, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
m_frameStart = dmrTX.getFrameCount();
|
||||||
|
m_state = DMRCAL1K_WAIT;
|
||||||
|
break;
|
||||||
|
case DMRCAL1K_WAIT:
|
||||||
|
if (dmrTX.getFrameCount() > (m_frameStart + 30U)) {
|
||||||
|
dmrTX.setStart(false);
|
||||||
|
dmrTX.resetFifo2();
|
||||||
|
m_audioSeq = 0U;
|
||||||
|
m_state = DMRCAL1K_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_state = DMRCAL1K_IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void CalDMR::dmrDMO1kcal()
|
||||||
|
{
|
||||||
|
dmrDMOTX.process();
|
||||||
|
|
||||||
|
uint16_t space = dmrDMOTX.getSpace();
|
||||||
|
if (space < 1U)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (m_state) {
|
||||||
|
case DMRCAL1K_VH:
|
||||||
|
dmrDMOTX.writeData(VH_DMO1K, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
m_state = DMRCAL1K_VOICE;
|
||||||
|
break;
|
||||||
|
case DMRCAL1K_VOICE:
|
||||||
|
createDataDMO1k(m_audioSeq);
|
||||||
|
dmrDMOTX.writeData(m_dmr1k, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
if (m_audioSeq == 5U) {
|
||||||
|
m_audioSeq = 0U;
|
||||||
|
if (!m_transmit)
|
||||||
|
m_state = DMRCAL1K_VT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_audioSeq++;
|
||||||
|
break;
|
||||||
|
case DMRCAL1K_VT:
|
||||||
|
dmrDMOTX.writeData(VT_DMO1K, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
m_state = DMRCAL1K_IDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_state = DMRCAL1K_IDLE;
|
||||||
|
m_audioSeq = 0U;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write DMR calibration state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t CalDMR::write(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (length != 1U)
|
||||||
|
return RSN_ILLEGAL_LENGTH;
|
||||||
|
|
||||||
|
m_transmit = data[0U] == 1U;
|
||||||
|
|
||||||
|
if (m_transmit && m_state == DMRCAL1K_IDLE && (m_modemState == STATE_DMR_CAL_1K || m_modemState == STATE_DMR_DMO_CAL_1K))
|
||||||
|
m_state = DMRCAL1K_VH;
|
||||||
|
|
||||||
|
if (m_transmit)
|
||||||
|
io.rf1Conf(STATE_DMR, true);
|
||||||
|
|
||||||
|
return RSN_OK;
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__CAL_DMR_H__)
|
||||||
|
#define __CAL_DMR_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "dmr/DMRDefines.h"
|
||||||
|
|
||||||
|
namespace dmr
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum DMRCAL1K {
|
||||||
|
DMRCAL1K_IDLE,
|
||||||
|
DMRCAL1K_VH,
|
||||||
|
DMRCAL1K_VOICE,
|
||||||
|
DMRCAL1K_VT,
|
||||||
|
DMRCAL1K_WAIT
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements logic for DMR calibration mode.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API CalDMR {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the CalDMR class.</summary>
|
||||||
|
CalDMR();
|
||||||
|
|
||||||
|
/// <summary>Process local state and transmit on the air interface.</summary>
|
||||||
|
void process();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void createData1k(uint8_t n);
|
||||||
|
/// <summary></summary>
|
||||||
|
void createDataDMO1k(uint8_t n);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void dmr1kcal();
|
||||||
|
/// <summary></summary>
|
||||||
|
void dmrDMO1kcal();
|
||||||
|
|
||||||
|
/// <summary>Write DMR calibration state.</summary>
|
||||||
|
uint8_t write(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_transmit;
|
||||||
|
DMRCAL1K m_state;
|
||||||
|
uint32_t m_frameStart;
|
||||||
|
|
||||||
|
uint8_t m_dmr1k[DMR_FRAME_LENGTH_BYTES + 1U];
|
||||||
|
|
||||||
|
uint8_t m_audioSeq;
|
||||||
|
uint32_t m_count;
|
||||||
|
};
|
||||||
|
} // namespace dmr
|
||||||
|
|
||||||
|
#endif // __CAL_DMR_H__
|
||||||
@ -0,0 +1,354 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "dmr/DMRDMORX.h"
|
||||||
|
#include "dmr/DMRSlotType.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
using namespace dmr;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint8_t MAX_SYNC_BYTES_ERRS = 3U;
|
||||||
|
|
||||||
|
const uint8_t MAX_SYNC_LOST_FRAMES = 13U;
|
||||||
|
|
||||||
|
const uint16_t NOENDPTR = 9999U;
|
||||||
|
|
||||||
|
const uint8_t CONTROL_NONE = 0x00U;
|
||||||
|
const uint8_t CONTROL_VOICE = 0x20U;
|
||||||
|
const uint8_t CONTROL_DATA = 0x40U;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DMRDMORX class.
|
||||||
|
/// </summary>
|
||||||
|
DMRDMORX::DMRDMORX() :
|
||||||
|
m_bitBuffer(0x00U),
|
||||||
|
m_buffer(),
|
||||||
|
m_dataPtr(0U),
|
||||||
|
m_syncPtr(0U),
|
||||||
|
m_startPtr(0U),
|
||||||
|
m_endPtr(NOENDPTR),
|
||||||
|
m_control(CONTROL_NONE),
|
||||||
|
m_syncCount(0U),
|
||||||
|
m_colorCode(0U),
|
||||||
|
m_state(DMORXS_NONE),
|
||||||
|
m_n(0U),
|
||||||
|
m_type(0U)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to reset data values to defaults.
|
||||||
|
/// </summary>
|
||||||
|
void DMRDMORX::reset()
|
||||||
|
{
|
||||||
|
m_syncPtr = 0U;
|
||||||
|
m_control = CONTROL_NONE;
|
||||||
|
m_syncCount = 0U;
|
||||||
|
m_state = DMORXS_NONE;
|
||||||
|
m_startPtr = 0U;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sample DMR bits from the air interface.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit"></param>
|
||||||
|
void DMRDMORX::databit(bool bit)
|
||||||
|
{
|
||||||
|
_WRITE_BIT(m_buffer, m_dataPtr, bit);
|
||||||
|
|
||||||
|
m_bitBuffer <<= 1;
|
||||||
|
if (bit)
|
||||||
|
m_bitBuffer |= 0x01U;
|
||||||
|
|
||||||
|
if (m_state == DMORXS_NONE) {
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint16_t min = m_syncPtr + DMO_BUFFER_LENGTH_BITS - 2;
|
||||||
|
uint16_t max = m_syncPtr + 2;
|
||||||
|
|
||||||
|
if (min >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
min -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
if (max >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
max -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
if (min < max) {
|
||||||
|
if (m_dataPtr >= min && m_dataPtr <= max)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_dataPtr >= min || m_dataPtr <= max)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dataPtr == m_endPtr) {
|
||||||
|
frame[0U] = m_control;
|
||||||
|
|
||||||
|
bitsToBytes(m_startPtr, DMR_FRAME_LENGTH_BYTES, frame + 1U);
|
||||||
|
|
||||||
|
if (m_control == CONTROL_DATA) {
|
||||||
|
// Data sync
|
||||||
|
uint8_t colorCode;
|
||||||
|
uint8_t dataType;
|
||||||
|
CDMRSlotType slotType;
|
||||||
|
slotType.decode(frame + 1U, colorCode, dataType);
|
||||||
|
|
||||||
|
if (colorCode == m_colorCode) {
|
||||||
|
m_syncCount = 0U;
|
||||||
|
m_n = 0U;
|
||||||
|
|
||||||
|
frame[0U] |= dataType;
|
||||||
|
|
||||||
|
switch (dataType) {
|
||||||
|
case DT_DATA_HEADER:
|
||||||
|
DEBUG2("DMRDMORX: databit(): data header found pos", m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
m_state = DMORXS_DATA;
|
||||||
|
m_type = 0x00U;
|
||||||
|
break;
|
||||||
|
case DT_RATE_12_DATA:
|
||||||
|
case DT_RATE_34_DATA:
|
||||||
|
case DT_RATE_1_DATA:
|
||||||
|
if (m_state == DMORXS_DATA) {
|
||||||
|
DEBUG2("DMRDMORX: databit(): data payload found pos", m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
m_type = dataType;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DT_VOICE_LC_HEADER:
|
||||||
|
DEBUG2("DMRDMORX: databit(): voice header found pos", m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
m_state = DMORXS_VOICE;
|
||||||
|
break;
|
||||||
|
case DT_VOICE_PI_HEADER:
|
||||||
|
if (m_state == DMORXS_VOICE) {
|
||||||
|
DEBUG2("DMRDMORX: databit(): voice pi header found pos", m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
}
|
||||||
|
m_state = DMORXS_VOICE;
|
||||||
|
break;
|
||||||
|
case DT_TERMINATOR_WITH_LC:
|
||||||
|
if (m_state == DMORXS_VOICE) {
|
||||||
|
DEBUG2("DMRDMORX: databit(): voice terminator found pos", m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: // DT_CSBK
|
||||||
|
DEBUG2("DMRDMORX: databit(): csbk found pos", m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_control == CONTROL_VOICE) {
|
||||||
|
// Voice sync
|
||||||
|
DEBUG2("DMRDMORX: databit(): voice sync found pos", m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
|
||||||
|
m_state = DMORXS_VOICE;
|
||||||
|
m_syncCount = 0U;
|
||||||
|
m_n = 0U;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_state != DMORXS_NONE) {
|
||||||
|
m_syncCount++;
|
||||||
|
if (m_syncCount >= MAX_SYNC_LOST_FRAMES) {
|
||||||
|
DEBUG1("DMRDMORX: databit(): sync timeout, lost lock");
|
||||||
|
serial.writeDMRLost(true);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == DMORXS_VOICE) {
|
||||||
|
if (m_n >= 5U) {
|
||||||
|
frame[0U] = CONTROL_VOICE;
|
||||||
|
m_n = 0U;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frame[0U] = ++m_n;
|
||||||
|
}
|
||||||
|
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
}
|
||||||
|
else if (m_state == DMORXS_DATA) {
|
||||||
|
if (m_type != 0x00U) {
|
||||||
|
frame[0U] = CONTROL_DATA | m_type;
|
||||||
|
writeRSSIData(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of this slot, reset some items for the next slot.
|
||||||
|
m_control = CONTROL_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dataPtr++;
|
||||||
|
|
||||||
|
if (m_dataPtr >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
|
||||||
|
io.setDecode(m_state != DMORXS_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the DMR color code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="colorCode">Color code.</param>
|
||||||
|
void DMRDMORX::setColorCode(uint8_t colorCode)
|
||||||
|
{
|
||||||
|
m_colorCode = colorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Frame synchronization correlator.
|
||||||
|
/// </summary>
|
||||||
|
void DMRDMORX::correlateSync()
|
||||||
|
{
|
||||||
|
if ((countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_DATA_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) || \
|
||||||
|
(countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_S2_DATA_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS)) {
|
||||||
|
m_control = CONTROL_DATA;
|
||||||
|
m_syncPtr = m_dataPtr;
|
||||||
|
|
||||||
|
m_startPtr = m_dataPtr + DMO_BUFFER_LENGTH_BITS - DMR_SLOT_TYPE_LENGTH_BITS / 2U - DMR_INFO_LENGTH_BITS / 2U - DMR_SYNC_LENGTH_BITS + 1;
|
||||||
|
if (m_startPtr >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
m_startPtr -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U;
|
||||||
|
if (m_endPtr >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
m_endPtr -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_modeTimerCnt = 0;
|
||||||
|
|
||||||
|
DEBUG4("DMRDMORX: correlateSync(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
|
||||||
|
}
|
||||||
|
else if ((countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_VOICE_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) || \
|
||||||
|
(countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_S2_VOICE_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS)) {
|
||||||
|
m_control = CONTROL_VOICE;
|
||||||
|
m_syncPtr = m_dataPtr;
|
||||||
|
|
||||||
|
m_startPtr = m_dataPtr + DMO_BUFFER_LENGTH_BITS - DMR_SLOT_TYPE_LENGTH_BITS / 2U - DMR_INFO_LENGTH_BITS / 2U - DMR_SYNC_LENGTH_BITS + 1;
|
||||||
|
if (m_startPtr >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
m_startPtr -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U;
|
||||||
|
if (m_endPtr >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
m_endPtr -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_modeTimerCnt = 0;
|
||||||
|
|
||||||
|
DEBUG4("DMRDMORX: correlateSync(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
/// <param name="buffer"></param>
|
||||||
|
void DMRDMORX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0U; i < count; i++) {
|
||||||
|
buffer[i] = 0U;
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 7;
|
||||||
|
start++;
|
||||||
|
if (start >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 6;
|
||||||
|
start++;
|
||||||
|
if (start >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 5;
|
||||||
|
start++;
|
||||||
|
if (start >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 4;
|
||||||
|
start++;
|
||||||
|
if (start >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 3;
|
||||||
|
start++;
|
||||||
|
if (start >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 2;
|
||||||
|
start++;
|
||||||
|
if (start >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 1;
|
||||||
|
start++;
|
||||||
|
if (start >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 0;
|
||||||
|
start++;
|
||||||
|
if (start >= DMO_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMO_BUFFER_LENGTH_BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frame"></param>
|
||||||
|
void DMRDMORX::writeRSSIData(uint8_t* frame)
|
||||||
|
{
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
uint16_t rssi = io.readRSSI();
|
||||||
|
|
||||||
|
frame[34U] = (rssi >> 8) & 0xFFU;
|
||||||
|
frame[35U] = (rssi >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 3U);
|
||||||
|
#else
|
||||||
|
serial.writeDMRData(true, frame, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__DMR_DMO_RX_H__)
|
||||||
|
#define __DMR_DMO_RX_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "dmr/DMRDefines.h"
|
||||||
|
|
||||||
|
namespace dmr
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint16_t DMO_BUFFER_LENGTH_BITS = 576U;
|
||||||
|
|
||||||
|
enum DMORX_STATE {
|
||||||
|
DMORXS_NONE,
|
||||||
|
DMORXS_VOICE,
|
||||||
|
DMORXS_DATA
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements receiver logic for DMR DMO mode operation.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API DMRDMORX {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the DMRDMORX class.</summary>
|
||||||
|
DMRDMORX();
|
||||||
|
|
||||||
|
/// <summary>Helper to reset data values to defaults.</summary>
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/// <summary>Sample DMR bits from the air interface.</summary>
|
||||||
|
void databit(bool bit);
|
||||||
|
|
||||||
|
/// <summary>Sets the DMR color code.</summary>
|
||||||
|
void setColorCode(uint8_t colorCode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t m_bitBuffer;
|
||||||
|
uint8_t m_buffer[DMO_BUFFER_LENGTH_BITS / 8U]; // 72 bytes
|
||||||
|
|
||||||
|
uint8_t frame[DMR_FRAME_LENGTH_BYTES + 3U];
|
||||||
|
|
||||||
|
uint16_t m_dataPtr;
|
||||||
|
uint16_t m_syncPtr;
|
||||||
|
uint16_t m_startPtr;
|
||||||
|
uint16_t m_endPtr;
|
||||||
|
|
||||||
|
uint8_t m_control;
|
||||||
|
uint8_t m_syncCount;
|
||||||
|
|
||||||
|
uint8_t m_colorCode;
|
||||||
|
|
||||||
|
DMORX_STATE m_state;
|
||||||
|
|
||||||
|
uint8_t m_n;
|
||||||
|
|
||||||
|
uint8_t m_type;
|
||||||
|
|
||||||
|
/// <summary>Frame synchronization correlator.</summary>
|
||||||
|
void correlateSync();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer);
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeRSSIData(uint8_t* frame);
|
||||||
|
};
|
||||||
|
} // namespace dmr
|
||||||
|
|
||||||
|
#endif // __DMR_DMO_RX_H__
|
||||||
@ -0,0 +1,228 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM project. (https://github.com/g4klx/MMDVM)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "dmr/DMRSlotType.h"
|
||||||
|
|
||||||
|
using namespace dmr;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// PR FILL pattern
|
||||||
|
const uint8_t PR_FILL[] =
|
||||||
|
{ 0x63U, 0xEAU, 0x00U, 0x76U, 0x6CU, 0x76U, 0xC4U, 0x52U, 0xC8U, 0x78U,
|
||||||
|
0x09U, 0x2DU, 0xB8U, 0x79U, 0x27U, 0x57U, 0x9BU, 0x31U, 0xBCU, 0x3EU,
|
||||||
|
0xEAU, 0x45U, 0xC3U, 0x30U, 0x49U, 0x17U, 0x93U, 0xAEU, 0x8BU, 0x6DU,
|
||||||
|
0xA4U, 0xA5U, 0xADU, 0xA2U, 0xF1U, 0x35U, 0xB5U, 0x3CU, 0x1EU };
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DMRDMOTX class.
|
||||||
|
/// </summary>
|
||||||
|
DMRDMOTX::DMRDMOTX() :
|
||||||
|
m_fifo(875U),
|
||||||
|
m_poBuffer(),
|
||||||
|
m_poLen(0U),
|
||||||
|
m_poPtr(0U),
|
||||||
|
m_preambleCnt(DMRDMO_FIXED_DELAY),
|
||||||
|
m_cal(false)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process local buffer and transmit on the air interface.
|
||||||
|
/// </summary>
|
||||||
|
void DMRDMOTX::process()
|
||||||
|
{
|
||||||
|
if (m_poLen == 0U && m_fifo.getData() > 0U) {
|
||||||
|
if (!m_tx) {
|
||||||
|
for (uint16_t i = 0U; i < m_preambleCnt; i++)
|
||||||
|
m_poBuffer[i] = DMR_START_SYNC;
|
||||||
|
|
||||||
|
m_poLen = m_preambleCnt;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (unsigned int i = 0U; i < 72U; i++)
|
||||||
|
m_poBuffer[i] = DMR_START_SYNC;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++)
|
||||||
|
m_poBuffer[i + 39U] = m_fifo.get();
|
||||||
|
|
||||||
|
m_poLen = 72U;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG2("DMRDMOTX: process(): poLen", m_poLen);
|
||||||
|
m_poPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_poLen > 0U) {
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > 8U) {
|
||||||
|
uint8_t c = m_poBuffer[m_poPtr++];
|
||||||
|
|
||||||
|
writeByte(c);
|
||||||
|
|
||||||
|
space -= 8U;
|
||||||
|
|
||||||
|
if (m_poPtr >= m_poLen) {
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_poLen = 0U;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write data to the local buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t DMRDMOTX::writeData(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
||||||
|
return RSN_ILLEGAL_LENGTH;
|
||||||
|
|
||||||
|
uint16_t space = m_fifo.getSpace();
|
||||||
|
DEBUG3("DMRDMOTX: writeData(): dataLength/fifoLength", length, space);
|
||||||
|
if (space < DMR_FRAME_LENGTH_BYTES)
|
||||||
|
return RSN_RINGBUFF_FULL;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++)
|
||||||
|
m_fifo.put(data[i + 1U]);
|
||||||
|
|
||||||
|
return RSN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
void DMRDMOTX::setCal(bool start)
|
||||||
|
{
|
||||||
|
m_cal = start ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the FDMA preamble count.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="preambleCnt">Count of preambles.</param>
|
||||||
|
void DMRDMOTX::setPreambleCount(uint8_t preambleCnt)
|
||||||
|
{
|
||||||
|
uint32_t preambles = (uint32_t)((float)preambleCnt / 0.2083F);
|
||||||
|
m_preambleCnt = DMRDMO_FIXED_DELAY + preambles;
|
||||||
|
|
||||||
|
// clamp preamble count to 250ms maximum
|
||||||
|
if (m_preambleCnt > 1200U)
|
||||||
|
m_preambleCnt = 1200U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the fine adjust 4FSK symbol levels.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level3Adj">+3/-3 symbol adjust.</param>
|
||||||
|
/// <param name="level1Adj">+1/-1 symbol adjust.</param>
|
||||||
|
void DMRDMOTX::setSymbolLvlAdj(int8_t level3Adj, int8_t level1Adj)
|
||||||
|
{
|
||||||
|
/* ignored ADF7021 doesn't allow direct symbol level adjustments */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to get how much space the ring buffer has for samples.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint16_t DMRDMOTX::getSpace() const
|
||||||
|
{
|
||||||
|
return m_fifo.getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void DMRDMOTX::createCal()
|
||||||
|
{
|
||||||
|
// 1.2 kHz sine wave generation
|
||||||
|
if (m_calState == STATE_DMR_CAL) {
|
||||||
|
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
|
||||||
|
m_poBuffer[i] = 0x5FU; // +3, +3, -3, -3 pattern for deviation cal.
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poLen = DMR_FRAME_LENGTH_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 80 Hz square wave generation
|
||||||
|
if (m_modemState == STATE_DMR_LF_CAL) {
|
||||||
|
for (unsigned int i = 0U; i < 7U; i++) {
|
||||||
|
m_poBuffer[i] = 0x55U; // +3, +3, ... pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poBuffer[7U] = 0x5FU; // +3, +3, -3, -3 pattern
|
||||||
|
|
||||||
|
for (unsigned int i = 8U; i < 15U; i++) {
|
||||||
|
m_poBuffer[i] = 0xFFU; // -3, -3, ... pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poLen = 15U;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poLen = DMR_FRAME_LENGTH_BYTES;
|
||||||
|
m_poPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c"></param>
|
||||||
|
void DMRDMOTX::writeByte(uint8_t c)
|
||||||
|
{
|
||||||
|
uint8_t bit;
|
||||||
|
uint8_t mask = 0x80U;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < 8U; i++, c <<= 1) {
|
||||||
|
if ((c & mask) == mask)
|
||||||
|
bit = 1U;
|
||||||
|
else
|
||||||
|
bit = 0U;
|
||||||
|
|
||||||
|
io.write(&bit, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__DMR_DMO_TX_H__)
|
||||||
|
#define __DMR_DMO_TX_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "dmr/DMRDefines.h"
|
||||||
|
#include "SerialBuffer.h"
|
||||||
|
|
||||||
|
namespace dmr
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define DMRDMO_FIXED_DELAY 300 // 300 = 62.49ms
|
||||||
|
// Delay Value * 0.2083 = Preamble Length (ms)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements transmitter logic for DMR DMO mode operation.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API DMRDMOTX {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the DMRDMOTX class.</summary>
|
||||||
|
DMRDMOTX();
|
||||||
|
|
||||||
|
/// <summary>Process local buffer and transmit on the air interface.</summary>
|
||||||
|
void process();
|
||||||
|
|
||||||
|
/// <summary>Write data to the local buffer.</summary>
|
||||||
|
uint8_t writeData(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
/// <summary>Helper to set the calibration state for Tx.</summary>
|
||||||
|
void setCal(bool start);
|
||||||
|
|
||||||
|
/// <summary>Sets the FDMA preamble count.</summary>
|
||||||
|
void setPreambleCount(uint8_t preambleCnt);
|
||||||
|
/// <summary>Sets the fine adjust 4FSK symbol levels.</summary>
|
||||||
|
void setSymbolLvlAdj(int8_t level3Adj, int8_t level1Adj);
|
||||||
|
|
||||||
|
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
|
||||||
|
uint16_t getSpace() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SerialBuffer m_fifo;
|
||||||
|
|
||||||
|
uint8_t m_poBuffer[80U];
|
||||||
|
uint16_t m_poLen;
|
||||||
|
uint16_t m_poPtr;
|
||||||
|
|
||||||
|
uint32_t m_preambleCnt;
|
||||||
|
|
||||||
|
bool m_cal;
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void createCal();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeByte(uint8_t c);
|
||||||
|
};
|
||||||
|
} // namespace dmr
|
||||||
|
|
||||||
|
#endif // __DMR_DMO_TX_H__
|
||||||
@ -0,0 +1,135 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__DMR_DEFINES_H__)
|
||||||
|
#define __DMR_DEFINES_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
namespace dmr
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint32_t DMR_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
|
||||||
|
|
||||||
|
const uint32_t DMR_FRAME_LENGTH_BYTES = 33U;
|
||||||
|
const uint32_t DMR_FRAME_LENGTH_BITS = DMR_FRAME_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t DMR_FRAME_LENGTH_SYMBOLS = DMR_FRAME_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t DMR_FRAME_LENGTH_SAMPLES = DMR_FRAME_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t DMR_SYNC_LENGTH_BYTES = 6U;
|
||||||
|
const uint32_t DMR_SYNC_LENGTH_BITS = DMR_SYNC_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t DMR_SYNC_LENGTH_SYMBOLS = DMR_SYNC_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t DMR_SYNC_LENGTH_SAMPLES = DMR_SYNC_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t DMR_EMB_LENGTH_BITS = 16U;
|
||||||
|
const uint32_t DMR_EMB_LENGTH_SYMBOLS = 8U;
|
||||||
|
const uint32_t DMR_EMB_LENGTH_SAMPLES = DMR_EMB_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t DMR_EMBSIG_LENGTH_BITS = 32U;
|
||||||
|
const uint32_t DMR_EMBSIG_LENGTH_SYMBOLS = 16U;
|
||||||
|
const uint32_t DMR_EMBSIG_LENGTH_SAMPLES = DMR_EMBSIG_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t DMR_SLOT_TYPE_LENGTH_BITS = 20U;
|
||||||
|
const uint32_t DMR_SLOT_TYPE_LENGTH_SYMBOLS = 10U;
|
||||||
|
const uint32_t DMR_SLOT_TYPE_LENGTH_SAMPLES = DMR_SLOT_TYPE_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t DMR_INFO_LENGTH_BITS = 196U;
|
||||||
|
const uint32_t DMR_INFO_LENGTH_SYMBOLS = 98U;
|
||||||
|
const uint32_t DMR_INFO_LENGTH_SAMPLES = DMR_INFO_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t DMR_AUDIO_LENGTH_BITS = 216U;
|
||||||
|
const uint32_t DMR_AUDIO_LENGTH_SYMBOLS = 108U;
|
||||||
|
const uint32_t DMR_AUDIO_LENGTH_SAMPLES = DMR_AUDIO_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t DMR_CACH_LENGTH_BYTES = 3U;
|
||||||
|
const uint32_t DMR_CACH_LENGTH_BITS = DMR_CACH_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t DMR_CACH_LENGTH_SYMBOLS = DMR_CACH_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t DMR_CACH_LENGTH_SAMPLES = DMR_CACH_LENGTH_SYMBOLS * DMR_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint8_t DMR_SYNC_BYTES_LENGTH = 7U;
|
||||||
|
const uint8_t DMR_MS_DATA_SYNC_BYTES[] = { 0x0DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x70U };
|
||||||
|
const uint8_t DMR_MS_VOICE_SYNC_BYTES[] = { 0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U };
|
||||||
|
const uint8_t DMR_BS_DATA_SYNC_BYTES[] = { 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U };
|
||||||
|
const uint8_t DMR_BS_VOICE_SYNC_BYTES[] = { 0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U };
|
||||||
|
const uint8_t DMR_S1_DATA_SYNC_BYTES[] = { 0x0FU, 0x7FU, 0xDDU, 0x5DU, 0xDFU, 0xD5U, 0x50U };
|
||||||
|
const uint8_t DMR_S1_VOICE_SYNC_BYTES[] = { 0x05U, 0xD5U, 0x77U, 0xF7U, 0x75U, 0x7FU, 0xF0U };
|
||||||
|
const uint8_t DMR_S2_DATA_SYNC_BYTES[] = { 0x0DU, 0x75U, 0x57U, 0xF5U, 0xFFU, 0x7FU, 0x50U };
|
||||||
|
const uint8_t DMR_S2_VOICE_SYNC_BYTES[] = { 0x07U, 0xDFU, 0xFDU, 0x5FU, 0x55U, 0xD5U, 0xF0U };
|
||||||
|
const uint8_t DMR_SYNC_BYTES_MASK[] = { 0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U };
|
||||||
|
|
||||||
|
const uint8_t DMR_START_SYNC = 0x5FU;
|
||||||
|
|
||||||
|
const uint64_t DMR_MS_DATA_SYNC_BITS = 0x0000D5D7F77FD757U;
|
||||||
|
const uint64_t DMR_MS_VOICE_SYNC_BITS = 0x00007F7D5DD57DFDU;
|
||||||
|
const uint64_t DMR_BS_DATA_SYNC_BITS = 0x0000DFF57D75DF5DU;
|
||||||
|
const uint64_t DMR_BS_VOICE_SYNC_BITS = 0x0000755FD7DF75F7U;
|
||||||
|
const uint64_t DMR_S1_DATA_SYNC_BITS = 0x0000F7FDD5DDFD55U;
|
||||||
|
const uint64_t DMR_S1_VOICE_SYNC_BITS = 0x00005D577F7757FFU;
|
||||||
|
const uint64_t DMR_S2_DATA_SYNC_BITS = 0x0000D7557F5FF7F5U;
|
||||||
|
const uint64_t DMR_S2_VOICE_SYNC_BITS = 0x00007DFFD5F55D5FU;
|
||||||
|
const uint64_t DMR_SYNC_BITS_MASK = 0x0000FFFFFFFFFFFFU;
|
||||||
|
|
||||||
|
const uint32_t DMR_MS_DATA_SYNC_SYMBOLS = 0x0076286EU;
|
||||||
|
const uint32_t DMR_MS_VOICE_SYNC_SYMBOLS = 0x0089D791U;
|
||||||
|
const uint32_t DMR_BS_DATA_SYNC_SYMBOLS = 0x00439B4DU;
|
||||||
|
const uint32_t DMR_BS_VOICE_SYNC_SYMBOLS = 0x00BC64B2U;
|
||||||
|
const uint32_t DMR_S1_DATA_SYNC_SYMBOLS = 0x0021751FU;
|
||||||
|
const uint32_t DMR_S1_VOICE_SYNC_SYMBOLS = 0x00DE8AE0U;
|
||||||
|
const uint32_t DMR_S2_DATA_SYNC_SYMBOLS = 0x006F8C23U;
|
||||||
|
const uint32_t DMR_S2_VOICE_SYNC_SYMBOLS = 0x009073DCU;
|
||||||
|
const uint32_t DMR_SYNC_SYMBOLS_MASK = 0x00FFFFFFU;
|
||||||
|
|
||||||
|
// D 5 D 7 F 7 7 F D 7 5 7
|
||||||
|
// 11 01 01 01 11 01 01 11 11 11 01 11 01 11 11 11 11 01 01 11 01 01 01 11
|
||||||
|
// -3 +3 +3 +3 -3 +3 +3 -3 -3 -3 +3 -3 +3 -3 -3 -3 -3 +3 +3 -3 +3 +3 +3 -3
|
||||||
|
|
||||||
|
const int8_t DMR_MS_DATA_SYNC_SYMBOLS_VALUES[] = { -3, +3, +3, +3, -3, +3, +3, -3, -3, -3, +3, -3, +3, -3, -3, -3, -3, +3, +3, -3, +3, +3, +3, -3 };
|
||||||
|
|
||||||
|
// 7 F 7 D 5 D D 5 7 D F D
|
||||||
|
// 01 11 11 11 01 11 11 01 01 01 11 01 11 01 01 01 01 11 11 01 11 11 11 01
|
||||||
|
// +3 -3 -3 -3 +3 -3 -3 +3 +3 +3 -3 +3 -3 +3 +3 +3 +3 -3 -3 +3 -3 -3 -3 +3
|
||||||
|
|
||||||
|
const int8_t DMR_MS_VOICE_SYNC_SYMBOLS_VALUES[] = { +3, -3, -3, -3, +3, -3, -3, +3, +3, +3, -3, +3, -3, +3, +3, +3, +3, -3, -3, +3, -3, -3, -3, +3 };
|
||||||
|
|
||||||
|
// Data Type(s)
|
||||||
|
const uint8_t DT_VOICE_PI_HEADER = 0U;
|
||||||
|
const uint8_t DT_VOICE_LC_HEADER = 1U;
|
||||||
|
const uint8_t DT_TERMINATOR_WITH_LC = 2U;
|
||||||
|
const uint8_t DT_CSBK = 3U;
|
||||||
|
const uint8_t DT_DATA_HEADER = 6U;
|
||||||
|
const uint8_t DT_RATE_12_DATA = 7U;
|
||||||
|
const uint8_t DT_RATE_34_DATA = 8U;
|
||||||
|
const uint8_t DT_IDLE = 9U;
|
||||||
|
const uint8_t DT_RATE_1_DATA = 10U;
|
||||||
|
} // namespace dmr
|
||||||
|
|
||||||
|
#endif // __DMR_DEFINES_H__
|
||||||
@ -0,0 +1,186 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "dmr/DMRIdleRX.h"
|
||||||
|
#include "dmr/DMRSlotType.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
using namespace dmr;
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint8_t MAX_SYNC_BYTES_ERRS = 2U;
|
||||||
|
|
||||||
|
const uint16_t NOENDPTR = 9999U;
|
||||||
|
|
||||||
|
const uint8_t CONTROL_IDLE = 0x80U;
|
||||||
|
const uint8_t CONTROL_DATA = 0x40U;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DMRIdleRX class.
|
||||||
|
/// </summary>
|
||||||
|
DMRIdleRX::DMRIdleRX() :
|
||||||
|
m_bitBuffer(0U),
|
||||||
|
m_buffer(),
|
||||||
|
m_dataPtr(0U),
|
||||||
|
m_endPtr(NOENDPTR),
|
||||||
|
m_colorCode(0U)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to reset data values to defaults.
|
||||||
|
/// </summary>
|
||||||
|
void DMRIdleRX::reset()
|
||||||
|
{
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sample DMR bits from the air interface.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit"></param>
|
||||||
|
void DMRIdleRX::databit(bool bit)
|
||||||
|
{
|
||||||
|
_WRITE_BIT(m_buffer, m_dataPtr, bit);
|
||||||
|
|
||||||
|
m_bitBuffer <<= 1;
|
||||||
|
if (bit)
|
||||||
|
m_bitBuffer |= 0x01U;
|
||||||
|
|
||||||
|
if (countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_DATA_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) {
|
||||||
|
m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U;
|
||||||
|
if (m_endPtr >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
m_endPtr -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
|
||||||
|
DEBUG3("DMRIdleRx: databit(): dataPtr/endPtr", m_dataPtr, m_endPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dataPtr == m_endPtr) {
|
||||||
|
uint16_t ptr = m_endPtr + DMR_IDLE_LENGTH_BITS - DMR_FRAME_LENGTH_BITS + 1;
|
||||||
|
if (ptr >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
ptr -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
|
||||||
|
uint8_t frame[DMR_FRAME_LENGTH_BYTES + 1U];
|
||||||
|
bitsToBytes(ptr, DMR_FRAME_LENGTH_BYTES, frame + 1U);
|
||||||
|
|
||||||
|
uint8_t colorCode;
|
||||||
|
uint8_t dataType;
|
||||||
|
DMRSlotType slotType;
|
||||||
|
slotType.decode(frame + 1U, colorCode, dataType);
|
||||||
|
|
||||||
|
if (colorCode == m_colorCode && dataType == DT_CSBK) {
|
||||||
|
frame[0U] = CONTROL_IDLE | CONTROL_DATA | DT_CSBK;
|
||||||
|
serial.writeDMRData(false, frame, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dataPtr++;
|
||||||
|
if (m_dataPtr >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the DMR color code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="colorCode">Color code.</param>
|
||||||
|
void DMRIdleRX::setColorCode(uint8_t colorCode)
|
||||||
|
{
|
||||||
|
m_colorCode = colorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
/// <param name="buffer"></param>
|
||||||
|
void DMRIdleRX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0U; i < count; i++) {
|
||||||
|
buffer[i] = 0U;
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 7;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
start -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 6;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
start -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 5;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
start -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 4;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
start -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 3;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
start -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 2;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
start -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 1;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
start -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 0;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_IDLE_LENGTH_BITS)
|
||||||
|
start -= DMR_IDLE_LENGTH_BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DUPLEX
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__DMR_IDLE_RX_H__)
|
||||||
|
#define __DMR_IDLE_RX_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "dmr/DMRDefines.h"
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
|
||||||
|
namespace dmr
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint16_t DMR_IDLE_LENGTH_BITS = 320U;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements receiver logic for idle DMR mode operation.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API DMRIdleRX {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the DMRIdleRX class.</summary>
|
||||||
|
DMRIdleRX();
|
||||||
|
|
||||||
|
/// <summary>Helper to reset data values to defaults.</summary>
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/// <summary>Sample DMR bits from the air interface.</summary>
|
||||||
|
void databit(bool bit);
|
||||||
|
|
||||||
|
/// <summary>Sets the DMR color code.</summary>
|
||||||
|
void setColorCode(uint8_t colorCode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t m_bitBuffer;
|
||||||
|
uint8_t m_buffer[DMR_IDLE_LENGTH_BITS / 8U];
|
||||||
|
|
||||||
|
uint16_t m_dataPtr;
|
||||||
|
uint16_t m_endPtr;
|
||||||
|
|
||||||
|
uint8_t m_colorCode;
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer);
|
||||||
|
};
|
||||||
|
} // namespace dmr
|
||||||
|
|
||||||
|
#endif // DUPLEX
|
||||||
|
|
||||||
|
#endif // __DMR_IDLE_RX_H__
|
||||||
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "dmr/DMRRX.h"
|
||||||
|
|
||||||
|
using namespace dmr;
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DMRRX class.
|
||||||
|
/// </summary>
|
||||||
|
DMRRX::DMRRX() :
|
||||||
|
m_slot1RX(false),
|
||||||
|
m_slot2RX(true)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to reset data values to defaults.
|
||||||
|
/// </summary>
|
||||||
|
void DMRRX::reset()
|
||||||
|
{
|
||||||
|
m_slot1RX.reset();
|
||||||
|
m_slot2RX.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sample DMR bits from the air interface.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit"></param>
|
||||||
|
void DMRRX::databit(bool bit, const uint8_t control)
|
||||||
|
{
|
||||||
|
bool dcd1 = false;
|
||||||
|
bool dcd2 = false;
|
||||||
|
|
||||||
|
switch (control) {
|
||||||
|
case MARK_SLOT1:
|
||||||
|
m_slot1RX.start();
|
||||||
|
break;
|
||||||
|
case MARK_SLOT2:
|
||||||
|
m_slot2RX.start();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dcd1 = m_slot1RX.databit(bit);
|
||||||
|
dcd2 = m_slot2RX.databit(bit);
|
||||||
|
|
||||||
|
io.setDecode(dcd1 || dcd2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the DMR color code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="colorCode">Color code.</param>
|
||||||
|
void DMRRX::setColorCode(uint8_t colorCode)
|
||||||
|
{
|
||||||
|
m_slot1RX.setColorCode(colorCode);
|
||||||
|
m_slot2RX.setColorCode(colorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the number of samples to delay before processing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="delay">Number of samples to delay.</param>
|
||||||
|
void DMRRX::setRxDelay(uint8_t delay)
|
||||||
|
{
|
||||||
|
m_slot1RX.setRxDelay(delay);
|
||||||
|
m_slot2RX.setRxDelay(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DUPLEX
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__DMR_RX_H__)
|
||||||
|
#define __DMR_RX_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "dmr/DMRSlotRX.h"
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
|
||||||
|
namespace dmr
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements receiver logic for duplex DMR mode operation.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API DMRRX {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the DMRRX class.</summary>
|
||||||
|
DMRRX();
|
||||||
|
|
||||||
|
/// <summary>Helper to reset data values to defaults.</summary>
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/// <summary>Sample DMR bits from the air interface.</summary>
|
||||||
|
void databit(bool bit, const uint8_t control);
|
||||||
|
|
||||||
|
/// <summary>Sets the DMR color code.</summary>
|
||||||
|
void setColorCode(uint8_t colorCode);
|
||||||
|
/// <summary>Sets the number of samples to delay before processing.</summary>
|
||||||
|
void setRxDelay(uint8_t delay);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DMRSlotRX m_slot1RX;
|
||||||
|
DMRSlotRX m_slot2RX;
|
||||||
|
};
|
||||||
|
} // namespace dmr
|
||||||
|
|
||||||
|
#endif // DUPLEX
|
||||||
|
|
||||||
|
#endif // __DMR_RX_H__
|
||||||
@ -0,0 +1,391 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "dmr/DMRSlotRX.h"
|
||||||
|
#include "dmr/DMRSlotType.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
using namespace dmr;
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint16_t SCAN_START = 390U;
|
||||||
|
const uint16_t SCAN_END = 500U;
|
||||||
|
|
||||||
|
const uint8_t MAX_SYNC_BYTES_ERRS = 3U;
|
||||||
|
|
||||||
|
const uint8_t MAX_SYNC_LOST_FRAMES = 13U;
|
||||||
|
|
||||||
|
const uint16_t NOENDPTR = 9999U;
|
||||||
|
|
||||||
|
const uint8_t CONTROL_NONE = 0x00U;
|
||||||
|
const uint8_t CONTROL_VOICE = 0x20U;
|
||||||
|
const uint8_t CONTROL_DATA = 0x40U;
|
||||||
|
|
||||||
|
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DMRSlotRX class.
|
||||||
|
/// </summary>
|
||||||
|
DMRSlotRX::DMRSlotRX(bool slot) :
|
||||||
|
m_slot(false),
|
||||||
|
m_bitBuffer(0x00U),
|
||||||
|
m_buffer(),
|
||||||
|
m_dataPtr(0U),
|
||||||
|
m_syncPtr(0U),
|
||||||
|
m_startPtr(0U),
|
||||||
|
m_endPtr(NOENDPTR),
|
||||||
|
m_delayPtr(0U),
|
||||||
|
m_control(CONTROL_NONE),
|
||||||
|
m_syncCount(0U),
|
||||||
|
m_colorCode(0U),
|
||||||
|
m_delay(0U),
|
||||||
|
m_state(DMRRXS_NONE),
|
||||||
|
m_n(0U),
|
||||||
|
m_type(0U)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to set data values for start of Rx.
|
||||||
|
/// </summary>
|
||||||
|
void DMRSlotRX::start()
|
||||||
|
{
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
m_delayPtr = 0U;
|
||||||
|
m_control = CONTROL_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to reset data values to defaults.
|
||||||
|
/// </summary>
|
||||||
|
void DMRSlotRX::reset()
|
||||||
|
{
|
||||||
|
m_syncPtr = 0U;
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
m_delayPtr = 0U;
|
||||||
|
|
||||||
|
m_bitBuffer = 0U;
|
||||||
|
|
||||||
|
m_control = CONTROL_NONE;
|
||||||
|
m_syncCount = 0U;
|
||||||
|
m_state = DMRRXS_NONE;
|
||||||
|
m_startPtr = 0U;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sample DMR bits from the air interface.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit"></param>
|
||||||
|
bool DMRSlotRX::databit(bool bit)
|
||||||
|
{
|
||||||
|
uint16_t min, max;
|
||||||
|
|
||||||
|
m_delayPtr++;
|
||||||
|
if (m_delayPtr < m_delay)
|
||||||
|
return m_state != DMRRXS_NONE;
|
||||||
|
|
||||||
|
_WRITE_BIT(m_buffer, m_dataPtr, bit);
|
||||||
|
|
||||||
|
m_bitBuffer <<= 1;
|
||||||
|
if (bit)
|
||||||
|
m_bitBuffer |= 0x01U;
|
||||||
|
|
||||||
|
// Ensure that the buffer doesn't overflow
|
||||||
|
if (m_dataPtr > m_endPtr || m_dataPtr >= 576U)
|
||||||
|
return m_state != DMRRXS_NONE;
|
||||||
|
|
||||||
|
if (m_state == DMRRXS_NONE) {
|
||||||
|
if (m_dataPtr >= SCAN_START && m_dataPtr <= SCAN_END)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
uint16_t min = m_syncPtr - 1U;
|
||||||
|
uint16_t max = m_syncPtr + 1U;
|
||||||
|
if (m_dataPtr >= min && m_dataPtr <= max)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dataPtr == m_endPtr) {
|
||||||
|
uint8_t frame[DMR_FRAME_LENGTH_BYTES + 3U];
|
||||||
|
frame[0U] = m_control;
|
||||||
|
|
||||||
|
bitsToBytes(m_startPtr, DMR_FRAME_LENGTH_BYTES, frame + 1U);
|
||||||
|
|
||||||
|
if (m_control == CONTROL_DATA) {
|
||||||
|
// Data sync
|
||||||
|
uint8_t colorCode;
|
||||||
|
uint8_t dataType;
|
||||||
|
DMRSlotType slotType;
|
||||||
|
slotType.decode(frame + 1U, colorCode, dataType);
|
||||||
|
|
||||||
|
if (colorCode == m_colorCode) {
|
||||||
|
m_syncCount = 0U;
|
||||||
|
m_n = 0U;
|
||||||
|
|
||||||
|
frame[0U] |= dataType;
|
||||||
|
|
||||||
|
switch (dataType) {
|
||||||
|
case DT_DATA_HEADER:
|
||||||
|
DEBUG3("DMRSlotRX: databit(): data header found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
m_state = DMRRXS_DATA;
|
||||||
|
m_type = 0x00U;
|
||||||
|
break;
|
||||||
|
case DT_RATE_12_DATA:
|
||||||
|
case DT_RATE_34_DATA:
|
||||||
|
case DT_RATE_1_DATA:
|
||||||
|
if (m_state == DMRRXS_DATA) {
|
||||||
|
DEBUG3("DMRSlotRX: databit(): data payload found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
m_type = dataType;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DT_VOICE_LC_HEADER:
|
||||||
|
DEBUG3("DMRSlotRX: databit(): voice header found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
m_state = DMRRXS_VOICE;
|
||||||
|
break;
|
||||||
|
case DT_VOICE_PI_HEADER:
|
||||||
|
if (m_state == DMRRXS_VOICE) {
|
||||||
|
DEBUG3("DMRSlotRX: databit(): voice pi header found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
}
|
||||||
|
m_state = DMRRXS_VOICE;
|
||||||
|
break;
|
||||||
|
case DT_TERMINATOR_WITH_LC:
|
||||||
|
if (m_state == DMRRXS_VOICE) {
|
||||||
|
DEBUG3("DMRSlotRX: databit(): voice terminator found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
m_state = DMRRXS_NONE;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: // DT_CSBK
|
||||||
|
DEBUG3("DMRSlotRX: databit(): csbk found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
m_state = DMRRXS_NONE;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_control == CONTROL_VOICE) {
|
||||||
|
// Voice sync
|
||||||
|
DEBUG3("DMRSlotRX: databit(): voice sync found slot/pos", m_slot ? 2U : 1U, m_syncPtr);
|
||||||
|
writeRSSIData(frame);
|
||||||
|
m_state = DMRRXS_VOICE;
|
||||||
|
m_syncCount = 0U;
|
||||||
|
m_n = 0U;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_state != DMRRXS_NONE) {
|
||||||
|
m_syncCount++;
|
||||||
|
if (m_syncCount >= MAX_SYNC_LOST_FRAMES) {
|
||||||
|
DEBUG1("DMRSlotRX: databit(): sync timeout, lost lock");
|
||||||
|
serial.writeDMRLost(m_slot);
|
||||||
|
m_state = DMRRXS_NONE;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == DMRRXS_VOICE) {
|
||||||
|
if (m_n >= 5U) {
|
||||||
|
frame[0U] = CONTROL_VOICE;
|
||||||
|
m_n = 0U;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frame[0U] = ++m_n;
|
||||||
|
}
|
||||||
|
|
||||||
|
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
}
|
||||||
|
else if (m_state == DMRRXS_DATA) {
|
||||||
|
if (m_type != 0x00U) {
|
||||||
|
frame[0U] = CONTROL_DATA | m_type;
|
||||||
|
writeRSSIData(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dataPtr++;
|
||||||
|
if (m_dataPtr >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
|
||||||
|
return m_state != DMRRXS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the DMR color code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="colorCode">Color code.</param>
|
||||||
|
void DMRSlotRX::setColorCode(uint8_t colorCode)
|
||||||
|
{
|
||||||
|
m_colorCode = colorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the number of samples to delay before processing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="delay">Number of samples to delay.</param>
|
||||||
|
void DMRSlotRX::setRxDelay(uint8_t delay)
|
||||||
|
{
|
||||||
|
m_delay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Frame synchronization correlator.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="first"></param>
|
||||||
|
void DMRSlotRX::correlateSync()
|
||||||
|
{
|
||||||
|
if (countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_DATA_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) {
|
||||||
|
m_control = CONTROL_DATA;
|
||||||
|
m_syncPtr = m_dataPtr;
|
||||||
|
|
||||||
|
m_startPtr = m_dataPtr + DMR_BUFFER_LENGTH_BITS - DMR_SLOT_TYPE_LENGTH_BITS / 2U - DMR_INFO_LENGTH_BITS / 2U - DMR_SYNC_LENGTH_BITS + 1;
|
||||||
|
if (m_startPtr >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
m_startPtr -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U;
|
||||||
|
if (m_endPtr >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
m_endPtr -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
DEBUG4("DMRSlotRX: correlateSync(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
|
||||||
|
}
|
||||||
|
else if (countBits64((m_bitBuffer & DMR_SYNC_BITS_MASK) ^ DMR_MS_VOICE_SYNC_BITS) <= MAX_SYNC_BYTES_ERRS) {
|
||||||
|
m_control = CONTROL_VOICE;
|
||||||
|
m_syncPtr = m_dataPtr;
|
||||||
|
|
||||||
|
m_startPtr = m_dataPtr + DMR_BUFFER_LENGTH_BITS - DMR_SLOT_TYPE_LENGTH_BITS / 2U - DMR_INFO_LENGTH_BITS / 2U - DMR_SYNC_LENGTH_BITS + 1;
|
||||||
|
if (m_startPtr >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
m_startPtr -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_endPtr = m_dataPtr + DMR_SLOT_TYPE_LENGTH_BITS / 2U + DMR_INFO_LENGTH_BITS / 2U;
|
||||||
|
if (m_endPtr >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
m_endPtr -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
DEBUG4("DMRSlotRX: correlateSync(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
/// <param name="buffer"></param>
|
||||||
|
void DMRSlotRX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0U; i < count; i++) {
|
||||||
|
buffer[i] = 0U;
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 7;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 6;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 5;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 4;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 3;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 2;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 1;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 0;
|
||||||
|
start++;
|
||||||
|
if (start >= DMR_BUFFER_LENGTH_BITS)
|
||||||
|
start -= DMR_BUFFER_LENGTH_BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frame"></param>
|
||||||
|
void DMRSlotRX::writeRSSIData(uint8_t* frame)
|
||||||
|
{
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
// Calculate RSSI average over a burst period. We don't take into account 2.5 ms at the beginning and 2.5 ms at the end
|
||||||
|
uint16_t start = m_startPtr + DMR_SYNC_LENGTH_SAMPLES / 2U;
|
||||||
|
|
||||||
|
uint32_t accum = 0U;
|
||||||
|
for (uint16_t i = 0U; i < (DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES); i++)
|
||||||
|
accum += m_rssi[start++];
|
||||||
|
|
||||||
|
uint16_t avg = accum / (DMR_FRAME_LENGTH_SAMPLES - DMR_SYNC_LENGTH_SAMPLES);
|
||||||
|
frame[34U] = (avg >> 8) & 0xFFU;
|
||||||
|
frame[35U] = (avg >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 3U);
|
||||||
|
#else
|
||||||
|
serial.writeDMRData(m_slot, frame, DMR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DUPLEX
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__DMR_SLOT_RX_H__)
|
||||||
|
#define __DMR_SLOT_RX_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "dmr/DMRDefines.h"
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
|
||||||
|
namespace dmr
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint16_t DMR_BUFFER_LENGTH_BITS = 576U;
|
||||||
|
|
||||||
|
enum DMRRX_STATE {
|
||||||
|
DMRRXS_NONE,
|
||||||
|
DMRRXS_VOICE,
|
||||||
|
DMRRXS_DATA
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements receiver logic for DMR slots.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API DMRSlotRX {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the DMRSlotRX class.</summary>
|
||||||
|
DMRSlotRX(bool slot);
|
||||||
|
|
||||||
|
/// <summary>Helper to set data values for start of Rx.</summary>
|
||||||
|
void start();
|
||||||
|
/// <summary>Helper to reset data values to defaults.</summary>
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/// <summary>Sample DMR bits from the air interface.</summary>
|
||||||
|
bool databit(bool bit);
|
||||||
|
|
||||||
|
/// <summary>Sets the DMR color code.</summary>
|
||||||
|
void setColorCode(uint8_t colorCode);
|
||||||
|
/// <summary>Sets the number of samples to delay before processing.</summary>
|
||||||
|
void setRxDelay(uint8_t delay);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_slot;
|
||||||
|
|
||||||
|
uint64_t m_bitBuffer;
|
||||||
|
uint8_t m_buffer[DMR_BUFFER_LENGTH_BITS / 8U]; // 72 bytes
|
||||||
|
|
||||||
|
uint16_t m_dataPtr;
|
||||||
|
uint16_t m_syncPtr;
|
||||||
|
uint16_t m_startPtr;
|
||||||
|
uint16_t m_endPtr;
|
||||||
|
uint16_t m_delayPtr;
|
||||||
|
|
||||||
|
uint8_t m_control;
|
||||||
|
uint8_t m_syncCount;
|
||||||
|
|
||||||
|
uint8_t m_colorCode;
|
||||||
|
|
||||||
|
uint16_t m_delay;
|
||||||
|
|
||||||
|
DMRRX_STATE m_state;
|
||||||
|
|
||||||
|
uint8_t m_n;
|
||||||
|
|
||||||
|
uint8_t m_type;
|
||||||
|
|
||||||
|
/// <summary>Frame synchronization correlator.</summary>
|
||||||
|
void correlateSync();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer);
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeRSSIData(uint8_t* frame);
|
||||||
|
};
|
||||||
|
} // namespace dmr
|
||||||
|
|
||||||
|
#endif // DUPLEX
|
||||||
|
|
||||||
|
#endif // __DMR_SLOT_RX_H__
|
||||||
@ -0,0 +1,334 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "dmr/DMRSlotType.h"
|
||||||
|
|
||||||
|
using namespace dmr;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint16_t ENCODING_TABLE_2087[] = {
|
||||||
|
0x0000U, 0xB08EU, 0xE093U, 0x501DU, 0x70A9U, 0xC027U, 0x903AU, 0x20B4U, 0x60DCU, 0xD052U, 0x804FU, 0x30C1U,
|
||||||
|
0x1075U, 0xA0FBU, 0xF0E6U, 0x4068U, 0x7036U, 0xC0B8U, 0x90A5U, 0x202BU, 0x009FU, 0xB011U, 0xE00CU, 0x5082U,
|
||||||
|
0x10EAU, 0xA064U, 0xF079U, 0x40F7U, 0x6043U, 0xD0CDU, 0x80D0U, 0x305EU, 0xD06CU, 0x60E2U, 0x30FFU, 0x8071U,
|
||||||
|
0xA0C5U, 0x104BU, 0x4056U, 0xF0D8U, 0xB0B0U, 0x003EU, 0x5023U, 0xE0ADU, 0xC019U, 0x7097U, 0x208AU, 0x9004U,
|
||||||
|
0xA05AU, 0x10D4U, 0x40C9U, 0xF047U, 0xD0F3U, 0x607DU, 0x3060U, 0x80EEU, 0xC086U, 0x7008U, 0x2015U, 0x909BU,
|
||||||
|
0xB02FU, 0x00A1U, 0x50BCU, 0xE032U, 0x90D9U, 0x2057U, 0x704AU, 0xC0C4U, 0xE070U, 0x50FEU, 0x00E3U, 0xB06DU,
|
||||||
|
0xF005U, 0x408BU, 0x1096U, 0xA018U, 0x80ACU, 0x3022U, 0x603FU, 0xD0B1U, 0xE0EFU, 0x5061U, 0x007CU, 0xB0F2U,
|
||||||
|
0x9046U, 0x20C8U, 0x70D5U, 0xC05BU, 0x8033U, 0x30BDU, 0x60A0U, 0xD02EU, 0xF09AU, 0x4014U, 0x1009U, 0xA087U,
|
||||||
|
0x40B5U, 0xF03BU, 0xA026U, 0x10A8U, 0x301CU, 0x8092U, 0xD08FU, 0x6001U, 0x2069U, 0x90E7U, 0xC0FAU, 0x7074U,
|
||||||
|
0x50C0U, 0xE04EU, 0xB053U, 0x00DDU, 0x3083U, 0x800DU, 0xD010U, 0x609EU, 0x402AU, 0xF0A4U, 0xA0B9U, 0x1037U,
|
||||||
|
0x505FU, 0xE0D1U, 0xB0CCU, 0x0042U, 0x20F6U, 0x9078U, 0xC065U, 0x70EBU, 0xA03DU, 0x10B3U, 0x40AEU, 0xF020U,
|
||||||
|
0xD094U, 0x601AU, 0x3007U, 0x8089U, 0xC0E1U, 0x706FU, 0x2072U, 0x90FCU, 0xB048U, 0x00C6U, 0x50DBU, 0xE055U,
|
||||||
|
0xD00BU, 0x6085U, 0x3098U, 0x8016U, 0xA0A2U, 0x102CU, 0x4031U, 0xF0BFU, 0xB0D7U, 0x0059U, 0x5044U, 0xE0CAU,
|
||||||
|
0xC07EU, 0x70F0U, 0x20EDU, 0x9063U, 0x7051U, 0xC0DFU, 0x90C2U, 0x204CU, 0x00F8U, 0xB076U, 0xE06BU, 0x50E5U,
|
||||||
|
0x108DU, 0xA003U, 0xF01EU, 0x4090U, 0x6024U, 0xD0AAU, 0x80B7U, 0x3039U, 0x0067U, 0xB0E9U, 0xE0F4U, 0x507AU,
|
||||||
|
0x70CEU, 0xC040U, 0x905DU, 0x20D3U, 0x60BBU, 0xD035U, 0x8028U, 0x30A6U, 0x1012U, 0xA09CU, 0xF081U, 0x400FU,
|
||||||
|
0x30E4U, 0x806AU, 0xD077U, 0x60F9U, 0x404DU, 0xF0C3U, 0xA0DEU, 0x1050U, 0x5038U, 0xE0B6U, 0xB0ABU, 0x0025U,
|
||||||
|
0x2091U, 0x901FU, 0xC002U, 0x708CU, 0x40D2U, 0xF05CU, 0xA041U, 0x10CFU, 0x307BU, 0x80F5U, 0xD0E8U, 0x6066U,
|
||||||
|
0x200EU, 0x9080U, 0xC09DU, 0x7013U, 0x50A7U, 0xE029U, 0xB034U, 0x00BAU, 0xE088U, 0x5006U, 0x001BU, 0xB095U,
|
||||||
|
0x9021U, 0x20AFU, 0x70B2U, 0xC03CU, 0x8054U, 0x30DAU, 0x60C7U, 0xD049U, 0xF0FDU, 0x4073U, 0x106EU, 0xA0E0U,
|
||||||
|
0x90BEU, 0x2030U, 0x702DU, 0xC0A3U, 0xE017U, 0x5099U, 0x0084U, 0xB00AU, 0xF062U, 0x40ECU, 0x10F1U, 0xA07FU,
|
||||||
|
0x80CBU, 0x3045U, 0x6058U, 0xD0D6U };
|
||||||
|
|
||||||
|
const uint32_t DECODING_TABLE_1987[] = {
|
||||||
|
0x00000U, 0x00001U, 0x00002U, 0x00003U, 0x00004U, 0x00005U, 0x00006U, 0x00007U, 0x00008U, 0x00009U, 0x0000AU, 0x0000BU, 0x0000CU,
|
||||||
|
0x0000DU, 0x0000EU, 0x24020U, 0x00010U, 0x00011U, 0x00012U, 0x00013U, 0x00014U, 0x00015U, 0x00016U, 0x00017U, 0x00018U, 0x00019U,
|
||||||
|
0x0001AU, 0x0001BU, 0x0001CU, 0x0001DU, 0x48040U, 0x01480U, 0x00020U, 0x00021U, 0x00022U, 0x00023U, 0x00024U, 0x00025U, 0x00026U,
|
||||||
|
0x24008U, 0x00028U, 0x00029U, 0x0002AU, 0x24004U, 0x0002CU, 0x24002U, 0x24001U, 0x24000U, 0x00030U, 0x00031U, 0x00032U, 0x08180U,
|
||||||
|
0x00034U, 0x00C40U, 0x00036U, 0x00C42U, 0x00038U, 0x43000U, 0x0003AU, 0x43002U, 0x02902U, 0x24012U, 0x02900U, 0x24010U, 0x00040U,
|
||||||
|
0x00041U, 0x00042U, 0x00043U, 0x00044U, 0x00045U, 0x00046U, 0x00047U, 0x00048U, 0x00049U, 0x0004AU, 0x02500U, 0x0004CU, 0x0004DU,
|
||||||
|
0x48010U, 0x48011U, 0x00050U, 0x00051U, 0x00052U, 0x21200U, 0x00054U, 0x00C20U, 0x48008U, 0x48009U, 0x00058U, 0x00059U, 0x48004U,
|
||||||
|
0x48005U, 0x48002U, 0x48003U, 0x48000U, 0x48001U, 0x00060U, 0x00061U, 0x00062U, 0x00063U, 0x00064U, 0x00C10U, 0x10300U, 0x0B000U,
|
||||||
|
0x00068U, 0x00069U, 0x01880U, 0x01881U, 0x40181U, 0x40180U, 0x24041U, 0x24040U, 0x00070U, 0x00C04U, 0x00072U, 0x00C06U, 0x00C01U,
|
||||||
|
0x00C00U, 0x00C03U, 0x00C02U, 0x05204U, 0x00C0CU, 0x48024U, 0x48025U, 0x05200U, 0x00C08U, 0x48020U, 0x48021U, 0x00080U, 0x00081U,
|
||||||
|
0x00082U, 0x00083U, 0x00084U, 0x00085U, 0x00086U, 0x00087U, 0x00088U, 0x00089U, 0x0008AU, 0x50200U, 0x0008CU, 0x0A800U, 0x01411U,
|
||||||
|
0x01410U, 0x00090U, 0x00091U, 0x00092U, 0x08120U, 0x00094U, 0x00095U, 0x04A00U, 0x01408U, 0x00098U, 0x00099U, 0x01405U, 0x01404U,
|
||||||
|
0x01403U, 0x01402U, 0x01401U, 0x01400U, 0x000A0U, 0x000A1U, 0x000A2U, 0x08110U, 0x000A4U, 0x000A5U, 0x42400U, 0x42401U, 0x000A8U,
|
||||||
|
0x000A9U, 0x01840U, 0x01841U, 0x40141U, 0x40140U, 0x24081U, 0x24080U, 0x000B0U, 0x08102U, 0x08101U, 0x08100U, 0x000B4U, 0x08106U,
|
||||||
|
0x08105U, 0x08104U, 0x20A01U, 0x20A00U, 0x08109U, 0x08108U, 0x01423U, 0x01422U, 0x01421U, 0x01420U, 0x000C0U, 0x000C1U, 0x000C2U,
|
||||||
|
0x000C3U, 0x000C4U, 0x000C5U, 0x000C6U, 0x000C7U, 0x000C8U, 0x000C9U, 0x01820U, 0x01821U, 0x20600U, 0x40120U, 0x16000U, 0x16001U,
|
||||||
|
0x000D0U, 0x000D1U, 0x42801U, 0x42800U, 0x03100U, 0x18200U, 0x03102U, 0x18202U, 0x000D8U, 0x000D9U, 0x48084U, 0x01444U, 0x48082U,
|
||||||
|
0x01442U, 0x48080U, 0x01440U, 0x000E0U, 0x32000U, 0x01808U, 0x04600U, 0x40109U, 0x40108U, 0x0180CU, 0x4010AU, 0x01802U, 0x40104U,
|
||||||
|
0x01800U, 0x01801U, 0x40101U, 0x40100U, 0x01804U, 0x40102U, 0x0A408U, 0x08142U, 0x08141U, 0x08140U, 0x00C81U, 0x00C80U, 0x00C83U,
|
||||||
|
0x00C82U, 0x0A400U, 0x0A401U, 0x01810U, 0x01811U, 0x40111U, 0x40110U, 0x01814U, 0x40112U, 0x00100U, 0x00101U, 0x00102U, 0x00103U,
|
||||||
|
0x00104U, 0x00105U, 0x00106U, 0x41800U, 0x00108U, 0x00109U, 0x0010AU, 0x02440U, 0x0010CU, 0x0010DU, 0x0010EU, 0x02444U, 0x00110U,
|
||||||
|
0x00111U, 0x00112U, 0x080A0U, 0x00114U, 0x00115U, 0x00116U, 0x080A4U, 0x00118U, 0x00119U, 0x15000U, 0x15001U, 0x02822U, 0x02823U,
|
||||||
|
0x02820U, 0x02821U, 0x00120U, 0x00121U, 0x00122U, 0x08090U, 0x00124U, 0x00125U, 0x10240U, 0x10241U, 0x00128U, 0x00129U, 0x0012AU,
|
||||||
|
0x24104U, 0x09400U, 0x400C0U, 0x02810U, 0x24100U, 0x00130U, 0x08082U, 0x08081U, 0x08080U, 0x31001U, 0x31000U, 0x02808U, 0x08084U,
|
||||||
|
0x02806U, 0x0808AU, 0x02804U, 0x08088U, 0x02802U, 0x02803U, 0x02800U, 0x02801U, 0x00140U, 0x00141U, 0x00142U, 0x02408U, 0x00144U,
|
||||||
|
0x00145U, 0x10220U, 0x10221U, 0x00148U, 0x02402U, 0x02401U, 0x02400U, 0x400A1U, 0x400A0U, 0x02405U, 0x02404U, 0x00150U, 0x00151U,
|
||||||
|
0x00152U, 0x02418U, 0x03080U, 0x03081U, 0x03082U, 0x03083U, 0x09801U, 0x09800U, 0x02411U, 0x02410U, 0x48102U, 0x09804U, 0x48100U,
|
||||||
|
0x48101U, 0x00160U, 0x00161U, 0x10204U, 0x10205U, 0x10202U, 0x40088U, 0x10200U, 0x10201U, 0x40085U, 0x40084U, 0x02421U, 0x02420U,
|
||||||
|
0x40081U, 0x40080U, 0x10208U, 0x40082U, 0x41402U, 0x080C2U, 0x41400U, 0x080C0U, 0x00D01U, 0x00D00U, 0x10210U, 0x10211U, 0x40095U,
|
||||||
|
0x40094U, 0x02844U, 0x080C8U, 0x40091U, 0x40090U, 0x02840U, 0x02841U, 0x00180U, 0x00181U, 0x00182U, 0x08030U, 0x00184U, 0x14400U,
|
||||||
|
0x22201U, 0x22200U, 0x00188U, 0x00189U, 0x0018AU, 0x08038U, 0x40061U, 0x40060U, 0x40063U, 0x40062U, 0x00190U, 0x08022U, 0x08021U,
|
||||||
|
0x08020U, 0x03040U, 0x03041U, 0x08025U, 0x08024U, 0x40C00U, 0x40C01U, 0x08029U, 0x08028U, 0x2C000U, 0x2C001U, 0x01501U, 0x01500U,
|
||||||
|
0x001A0U, 0x08012U, 0x08011U, 0x08010U, 0x40049U, 0x40048U, 0x08015U, 0x08014U, 0x06200U, 0x40044U, 0x30400U, 0x08018U, 0x40041U,
|
||||||
|
0x40040U, 0x40043U, 0x40042U, 0x08003U, 0x08002U, 0x08001U, 0x08000U, 0x08007U, 0x08006U, 0x08005U, 0x08004U, 0x0800BU, 0x0800AU,
|
||||||
|
0x08009U, 0x08008U, 0x40051U, 0x40050U, 0x02880U, 0x0800CU, 0x001C0U, 0x001C1U, 0x64000U, 0x64001U, 0x03010U, 0x40028U, 0x08C00U,
|
||||||
|
0x08C01U, 0x40025U, 0x40024U, 0x02481U, 0x02480U, 0x40021U, 0x40020U, 0x40023U, 0x40022U, 0x03004U, 0x03005U, 0x08061U, 0x08060U,
|
||||||
|
0x03000U, 0x03001U, 0x03002U, 0x03003U, 0x0300CU, 0x40034U, 0x30805U, 0x30804U, 0x03008U, 0x40030U, 0x30801U, 0x30800U, 0x4000DU,
|
||||||
|
0x4000CU, 0x08051U, 0x08050U, 0x40009U, 0x40008U, 0x10280U, 0x4000AU, 0x40005U, 0x40004U, 0x01900U, 0x40006U, 0x40001U, 0x40000U,
|
||||||
|
0x40003U, 0x40002U, 0x14800U, 0x08042U, 0x08041U, 0x08040U, 0x03020U, 0x40018U, 0x08045U, 0x08044U, 0x40015U, 0x40014U, 0x08049U,
|
||||||
|
0x08048U, 0x40011U, 0x40010U, 0x40013U, 0x40012U, 0x00200U, 0x00201U, 0x00202U, 0x00203U, 0x00204U, 0x00205U, 0x00206U, 0x00207U,
|
||||||
|
0x00208U, 0x00209U, 0x0020AU, 0x50080U, 0x0020CU, 0x0020DU, 0x0020EU, 0x50084U, 0x00210U, 0x00211U, 0x00212U, 0x21040U, 0x00214U,
|
||||||
|
0x00215U, 0x04880U, 0x04881U, 0x00218U, 0x00219U, 0x0E001U, 0x0E000U, 0x0021CU, 0x0021DU, 0x04888U, 0x0E004U, 0x00220U, 0x00221U,
|
||||||
|
0x00222U, 0x00223U, 0x00224U, 0x00225U, 0x10140U, 0x10141U, 0x00228U, 0x00229U, 0x0022AU, 0x24204U, 0x12401U, 0x12400U, 0x24201U,
|
||||||
|
0x24200U, 0x00230U, 0x00231U, 0x00232U, 0x21060U, 0x2A000U, 0x2A001U, 0x2A002U, 0x2A003U, 0x20881U, 0x20880U, 0x20883U, 0x20882U,
|
||||||
|
0x05040U, 0x05041U, 0x05042U, 0x24210U, 0x00240U, 0x00241U, 0x00242U, 0x21010U, 0x00244U, 0x46000U, 0x10120U, 0x10121U, 0x00248U,
|
||||||
|
0x00249U, 0x0024AU, 0x21018U, 0x20480U, 0x20481U, 0x20482U, 0x20483U, 0x00250U, 0x21002U, 0x21001U, 0x21000U, 0x18081U, 0x18080U,
|
||||||
|
0x21005U, 0x21004U, 0x12800U, 0x12801U, 0x21009U, 0x21008U, 0x05020U, 0x05021U, 0x48200U, 0x48201U, 0x00260U, 0x00261U, 0x10104U,
|
||||||
|
0x04480U, 0x10102U, 0x10103U, 0x10100U, 0x10101U, 0x62002U, 0x62003U, 0x62000U, 0x62001U, 0x05010U, 0x05011U, 0x10108U, 0x10109U,
|
||||||
|
0x0500CU, 0x21022U, 0x21021U, 0x21020U, 0x05008U, 0x00E00U, 0x10110U, 0x10111U, 0x05004U, 0x05005U, 0x05006U, 0x21028U, 0x05000U,
|
||||||
|
0x05001U, 0x05002U, 0x05003U, 0x00280U, 0x00281U, 0x00282U, 0x50008U, 0x00284U, 0x00285U, 0x04810U, 0x22100U, 0x00288U, 0x50002U,
|
||||||
|
0x50001U, 0x50000U, 0x20440U, 0x20441U, 0x50005U, 0x50004U, 0x00290U, 0x00291U, 0x04804U, 0x04805U, 0x04802U, 0x18040U, 0x04800U,
|
||||||
|
0x04801U, 0x20821U, 0x20820U, 0x50011U, 0x50010U, 0x0480AU, 0x01602U, 0x04808U, 0x01600U, 0x002A0U, 0x002A1U, 0x04441U, 0x04440U,
|
||||||
|
0x002A4U, 0x002A5U, 0x04830U, 0x04444U, 0x06100U, 0x20810U, 0x50021U, 0x50020U, 0x06104U, 0x20814U, 0x50025U, 0x50024U, 0x20809U,
|
||||||
|
0x20808U, 0x13000U, 0x08300U, 0x04822U, 0x2080CU, 0x04820U, 0x04821U, 0x20801U, 0x20800U, 0x20803U, 0x20802U, 0x20805U, 0x20804U,
|
||||||
|
0x04828U, 0x20806U, 0x002C0U, 0x002C1U, 0x04421U, 0x04420U, 0x20408U, 0x18010U, 0x2040AU, 0x18012U, 0x20404U, 0x20405U, 0x50041U,
|
||||||
|
0x50040U, 0x20400U, 0x20401U, 0x20402U, 0x20403U, 0x18005U, 0x18004U, 0x21081U, 0x21080U, 0x18001U, 0x18000U, 0x04840U, 0x18002U,
|
||||||
|
0x20414U, 0x1800CU, 0x21089U, 0x21088U, 0x20410U, 0x18008U, 0x20412U, 0x1800AU, 0x04403U, 0x04402U, 0x04401U, 0x04400U, 0x10182U,
|
||||||
|
0x04406U, 0x10180U, 0x04404U, 0x01A02U, 0x0440AU, 0x01A00U, 0x04408U, 0x20420U, 0x40300U, 0x20422U, 0x40302U, 0x04413U, 0x04412U,
|
||||||
|
0x04411U, 0x04410U, 0x18021U, 0x18020U, 0x10190U, 0x18022U, 0x20841U, 0x20840U, 0x01A10U, 0x20842U, 0x05080U, 0x05081U, 0x05082U,
|
||||||
|
0x05083U, 0x00300U, 0x00301U, 0x00302U, 0x00303U, 0x00304U, 0x00305U, 0x10060U, 0x22080U, 0x00308U, 0x00309U, 0x28800U, 0x28801U,
|
||||||
|
0x44402U, 0x44403U, 0x44400U, 0x44401U, 0x00310U, 0x00311U, 0x10C01U, 0x10C00U, 0x00314U, 0x00315U, 0x10070U, 0x10C04U, 0x00318U,
|
||||||
|
0x00319U, 0x28810U, 0x10C08U, 0x44412U, 0x00000U, 0x44410U, 0x44411U, 0x00320U, 0x60400U, 0x10044U, 0x10045U, 0x10042U, 0x0C800U,
|
||||||
|
0x10040U, 0x10041U, 0x06080U, 0x06081U, 0x06082U, 0x06083U, 0x1004AU, 0x0C808U, 0x10048U, 0x10049U, 0x58008U, 0x08282U, 0x08281U,
|
||||||
|
0x08280U, 0x10052U, 0x0C810U, 0x10050U, 0x10051U, 0x58000U, 0x58001U, 0x58002U, 0x08288U, 0x02A02U, 0x02A03U, 0x02A00U, 0x02A01U,
|
||||||
|
0x00340U, 0x00341U, 0x10024U, 0x10025U, 0x10022U, 0x10023U, 0x10020U, 0x10021U, 0x34001U, 0x34000U, 0x02601U, 0x02600U, 0x1002AU,
|
||||||
|
0x34004U, 0x10028U, 0x10029U, 0x0C400U, 0x0C401U, 0x21101U, 0x21100U, 0x60800U, 0x60801U, 0x10030U, 0x10031U, 0x0C408U, 0x34010U,
|
||||||
|
0x21109U, 0x21108U, 0x60808U, 0x60809U, 0x10038U, 0x28420U, 0x10006U, 0x10007U, 0x10004U, 0x10005U, 0x10002U, 0x10003U, 0x10000U,
|
||||||
|
0x10001U, 0x1000EU, 0x40284U, 0x1000CU, 0x1000DU, 0x1000AU, 0x40280U, 0x10008U, 0x10009U, 0x10016U, 0x10017U, 0x10014U, 0x10015U,
|
||||||
|
0x10012U, 0x10013U, 0x10010U, 0x10011U, 0x05104U, 0x44802U, 0x44801U, 0x44800U, 0x05100U, 0x05101U, 0x10018U, 0x28400U, 0x00380U,
|
||||||
|
0x00381U, 0x22005U, 0x22004U, 0x22003U, 0x22002U, 0x22001U, 0x22000U, 0x06020U, 0x06021U, 0x50101U, 0x50100U, 0x11800U, 0x11801U,
|
||||||
|
0x22009U, 0x22008U, 0x45001U, 0x45000U, 0x08221U, 0x08220U, 0x04902U, 0x22012U, 0x04900U, 0x22010U, 0x06030U, 0x45008U, 0x08229U,
|
||||||
|
0x08228U, 0x11810U, 0x11811U, 0x04908U, 0x22018U, 0x06008U, 0x06009U, 0x08211U, 0x08210U, 0x100C2U, 0x22022U, 0x100C0U, 0x22020U,
|
||||||
|
0x06000U, 0x06001U, 0x06002U, 0x06003U, 0x06004U, 0x40240U, 0x06006U, 0x40242U, 0x08203U, 0x08202U, 0x08201U, 0x08200U, 0x08207U,
|
||||||
|
0x08206U, 0x08205U, 0x08204U, 0x06010U, 0x20900U, 0x08209U, 0x08208U, 0x61002U, 0x20904U, 0x61000U, 0x61001U, 0x29020U, 0x29021U,
|
||||||
|
0x100A4U, 0x22044U, 0x100A2U, 0x22042U, 0x100A0U, 0x22040U, 0x20504U, 0x40224U, 0x0D005U, 0x0D004U, 0x20500U, 0x40220U, 0x0D001U,
|
||||||
|
0x0D000U, 0x03204U, 0x18104U, 0x08261U, 0x08260U, 0x03200U, 0x18100U, 0x03202U, 0x18102U, 0x11421U, 0x11420U, 0x00000U, 0x11422U,
|
||||||
|
0x03208U, 0x18108U, 0x0D011U, 0x0D010U, 0x29000U, 0x29001U, 0x10084U, 0x04500U, 0x10082U, 0x40208U, 0x10080U, 0x10081U, 0x06040U,
|
||||||
|
0x40204U, 0x06042U, 0x40206U, 0x40201U, 0x40200U, 0x10088U, 0x40202U, 0x29010U, 0x08242U, 0x08241U, 0x08240U, 0x10092U, 0x40218U,
|
||||||
|
0x10090U, 0x10091U, 0x11401U, 0x11400U, 0x11403U, 0x11402U, 0x40211U, 0x40210U, 0x10098U, 0x40212U, 0x00400U, 0x00401U, 0x00402U,
|
||||||
|
0x00403U, 0x00404U, 0x00405U, 0x00406U, 0x00407U, 0x00408U, 0x00409U, 0x0040AU, 0x02140U, 0x0040CU, 0x0040DU, 0x01091U, 0x01090U,
|
||||||
|
0x00410U, 0x00411U, 0x00412U, 0x00413U, 0x00414U, 0x00860U, 0x01089U, 0x01088U, 0x00418U, 0x38000U, 0x01085U, 0x01084U, 0x01083U,
|
||||||
|
0x01082U, 0x01081U, 0x01080U, 0x00420U, 0x00421U, 0x00422U, 0x00423U, 0x00424U, 0x00850U, 0x42080U, 0x42081U, 0x00428U, 0x00429U,
|
||||||
|
0x48801U, 0x48800U, 0x09100U, 0x12200U, 0x24401U, 0x24400U, 0x00430U, 0x00844U, 0x00432U, 0x00846U, 0x00841U, 0x00840U, 0x1C000U,
|
||||||
|
0x00842U, 0x00438U, 0x0084CU, 0x010A5U, 0x010A4U, 0x00849U, 0x00848U, 0x010A1U, 0x010A0U, 0x00440U, 0x00441U, 0x00442U, 0x02108U,
|
||||||
|
0x00444U, 0x00830U, 0x70001U, 0x70000U, 0x00448U, 0x02102U, 0x02101U, 0x02100U, 0x20280U, 0x20281U, 0x02105U, 0x02104U, 0x00450U,
|
||||||
|
0x00824U, 0x00452U, 0x00826U, 0x00821U, 0x00820U, 0x00823U, 0x00822U, 0x24802U, 0x02112U, 0x24800U, 0x02110U, 0x00829U, 0x00828U,
|
||||||
|
0x48400U, 0x010C0U, 0x00460U, 0x00814U, 0x04281U, 0x04280U, 0x00811U, 0x00810U, 0x00813U, 0x00812U, 0x54000U, 0x54001U, 0x02121U,
|
||||||
|
0x02120U, 0x00819U, 0x00818U, 0x0081BU, 0x0081AU, 0x00805U, 0x00804U, 0x41100U, 0x00806U, 0x00801U, 0x00800U, 0x00803U, 0x00802U,
|
||||||
|
0x0A080U, 0x0080CU, 0x0A082U, 0x0080EU, 0x00809U, 0x00808U, 0x0080BU, 0x0080AU, 0x00480U, 0x00481U, 0x00482U, 0x00483U, 0x00484U,
|
||||||
|
0x14100U, 0x42020U, 0x01018U, 0x00488U, 0x00489U, 0x01015U, 0x01014U, 0x20240U, 0x01012U, 0x01011U, 0x01010U, 0x00490U, 0x00491U,
|
||||||
|
0x0100DU, 0x0100CU, 0x0100BU, 0x0100AU, 0x01009U, 0x01008U, 0x40900U, 0x01006U, 0x01005U, 0x01004U, 0x01003U, 0x01002U, 0x01001U,
|
||||||
|
0x01000U, 0x004A0U, 0x004A1U, 0x42004U, 0x04240U, 0x42002U, 0x42003U, 0x42000U, 0x42001U, 0x30102U, 0x30103U, 0x30100U, 0x30101U,
|
||||||
|
0x4200AU, 0x01032U, 0x42008U, 0x01030U, 0x25000U, 0x25001U, 0x08501U, 0x08500U, 0x008C1U, 0x008C0U, 0x42010U, 0x01028U, 0x0A040U,
|
||||||
|
0x0A041U, 0x01025U, 0x01024U, 0x01023U, 0x01022U, 0x01021U, 0x01020U, 0x004C0U, 0x49000U, 0x04221U, 0x04220U, 0x20208U, 0x20209U,
|
||||||
|
0x08900U, 0x08901U, 0x20204U, 0x20205U, 0x02181U, 0x02180U, 0x20200U, 0x20201U, 0x20202U, 0x01050U, 0x0A028U, 0x008A4U, 0x0104DU,
|
||||||
|
0x0104CU, 0x008A1U, 0x008A0U, 0x01049U, 0x01048U, 0x0A020U, 0x0A021U, 0x01045U, 0x01044U, 0x20210U, 0x01042U, 0x01041U, 0x01040U,
|
||||||
|
0x04203U, 0x04202U, 0x04201U, 0x04200U, 0x00891U, 0x00890U, 0x42040U, 0x04204U, 0x0A010U, 0x0A011U, 0x01C00U, 0x04208U, 0x20220U,
|
||||||
|
0x40500U, 0x20222U, 0x40502U, 0x0A008U, 0x00884U, 0x04211U, 0x04210U, 0x00881U, 0x00880U, 0x00883U, 0x00882U, 0x0A000U, 0x0A001U,
|
||||||
|
0x0A002U, 0x0A003U, 0x0A004U, 0x00888U, 0x01061U, 0x01060U, 0x00500U, 0x00501U, 0x00502U, 0x02048U, 0x00504U, 0x14080U, 0x00506U,
|
||||||
|
0x14082U, 0x00508U, 0x02042U, 0x02041U, 0x02040U, 0x09020U, 0x09021U, 0x44200U, 0x02044U, 0x00510U, 0x00511U, 0x10A01U, 0x10A00U,
|
||||||
|
0x4A001U, 0x4A000U, 0x4A003U, 0x4A002U, 0x40880U, 0x40881U, 0x02051U, 0x02050U, 0x40884U, 0x01182U, 0x01181U, 0x01180U, 0x00520U,
|
||||||
|
0x60200U, 0x00522U, 0x60202U, 0x09008U, 0x09009U, 0x0900AU, 0x0900BU, 0x09004U, 0x09005U, 0x30080U, 0x02060U, 0x09000U, 0x09001U,
|
||||||
|
0x09002U, 0x09003U, 0x41042U, 0x08482U, 0x41040U, 0x08480U, 0x00941U, 0x00940U, 0x41044U, 0x00942U, 0x09014U, 0x09015U, 0x02C04U,
|
||||||
|
0x08488U, 0x09010U, 0x09011U, 0x02C00U, 0x02C01U, 0x00540U, 0x0200AU, 0x02009U, 0x02008U, 0x08882U, 0x0200EU, 0x08880U, 0x0200CU,
|
||||||
|
0x02003U, 0x02002U, 0x02001U, 0x02000U, 0x02007U, 0x02006U, 0x02005U, 0x02004U, 0x0C200U, 0x0C201U, 0x41020U, 0x02018U, 0x00921U,
|
||||||
|
0x00920U, 0x41024U, 0x00922U, 0x02013U, 0x02012U, 0x02011U, 0x02010U, 0x02017U, 0x02016U, 0x02015U, 0x02014U, 0x41012U, 0x0202AU,
|
||||||
|
0x41010U, 0x02028U, 0x26000U, 0x00910U, 0x10600U, 0x10601U, 0x02023U, 0x02022U, 0x02021U, 0x02020U, 0x09040U, 0x40480U, 0x02025U,
|
||||||
|
0x02024U, 0x41002U, 0x00904U, 0x41000U, 0x41001U, 0x00901U, 0x00900U, 0x41004U, 0x00902U, 0x4100AU, 0x02032U, 0x41008U, 0x02030U,
|
||||||
|
0x00909U, 0x00908U, 0x28201U, 0x28200U, 0x00580U, 0x14004U, 0x00582U, 0x14006U, 0x14001U, 0x14000U, 0x08840U, 0x14002U, 0x40810U,
|
||||||
|
0x40811U, 0x30020U, 0x020C0U, 0x14009U, 0x14008U, 0x01111U, 0x01110U, 0x40808U, 0x40809U, 0x08421U, 0x08420U, 0x14011U, 0x14010U,
|
||||||
|
0x01109U, 0x01108U, 0x40800U, 0x40801U, 0x40802U, 0x01104U, 0x40804U, 0x01102U, 0x01101U, 0x01100U, 0x03801U, 0x03800U, 0x30008U,
|
||||||
|
0x08410U, 0x14021U, 0x14020U, 0x42100U, 0x42101U, 0x30002U, 0x30003U, 0x30000U, 0x30001U, 0x09080U, 0x40440U, 0x30004U, 0x30005U,
|
||||||
|
0x08403U, 0x08402U, 0x08401U, 0x08400U, 0x08407U, 0x08406U, 0x08405U, 0x08404U, 0x40820U, 0x40821U, 0x30010U, 0x08408U, 0x40824U,
|
||||||
|
0x01122U, 0x01121U, 0x01120U, 0x08806U, 0x0208AU, 0x08804U, 0x02088U, 0x08802U, 0x14040U, 0x08800U, 0x08801U, 0x02083U, 0x02082U,
|
||||||
|
0x02081U, 0x02080U, 0x20300U, 0x40420U, 0x08808U, 0x02084U, 0x03404U, 0x03405U, 0x08814U, 0x02098U, 0x03400U, 0x03401U, 0x08810U,
|
||||||
|
0x08811U, 0x40840U, 0x40841U, 0x02091U, 0x02090U, 0x40844U, 0x01142U, 0x01141U, 0x01140U, 0x04303U, 0x04302U, 0x04301U, 0x04300U,
|
||||||
|
0x40409U, 0x40408U, 0x08820U, 0x08821U, 0x40405U, 0x40404U, 0x30040U, 0x020A0U, 0x40401U, 0x40400U, 0x40403U, 0x40402U, 0x41082U,
|
||||||
|
0x08442U, 0x41080U, 0x08440U, 0x00981U, 0x00980U, 0x41084U, 0x00982U, 0x0A100U, 0x11200U, 0x0A102U, 0x11202U, 0x40411U, 0x40410U,
|
||||||
|
0x40413U, 0x40412U, 0x00600U, 0x00601U, 0x00602U, 0x00603U, 0x00604U, 0x00605U, 0x00606U, 0x00607U, 0x00608U, 0x05800U, 0x0060AU,
|
||||||
|
0x05802U, 0x200C0U, 0x12020U, 0x44100U, 0x44101U, 0x00610U, 0x00611U, 0x10901U, 0x10900U, 0x51000U, 0x51001U, 0x51002U, 0x10904U,
|
||||||
|
0x00618U, 0x05810U, 0x01285U, 0x01284U, 0x51008U, 0x01282U, 0x01281U, 0x01280U, 0x00620U, 0x60100U, 0x040C1U, 0x040C0U, 0x12009U,
|
||||||
|
0x12008U, 0x21800U, 0x21801U, 0x12005U, 0x12004U, 0x12007U, 0x12006U, 0x12001U, 0x12000U, 0x12003U, 0x12002U, 0x00630U, 0x00A44U,
|
||||||
|
0x040D1U, 0x040D0U, 0x00A41U, 0x00A40U, 0x21810U, 0x00A42U, 0x12015U, 0x12014U, 0x00000U, 0x12016U, 0x12011U, 0x12010U, 0x12013U,
|
||||||
|
0x12012U, 0x00640U, 0x00641U, 0x040A1U, 0x040A0U, 0x20088U, 0x20089U, 0x2008AU, 0x040A4U, 0x20084U, 0x20085U, 0x19000U, 0x02300U,
|
||||||
|
0x20080U, 0x20081U, 0x20082U, 0x20083U, 0x0C100U, 0x0C101U, 0x21401U, 0x21400U, 0x00A21U, 0x00A20U, 0x00A23U, 0x00A22U, 0x20094U,
|
||||||
|
0x20095U, 0x19010U, 0x21408U, 0x20090U, 0x20091U, 0x20092U, 0x28120U, 0x04083U, 0x04082U, 0x04081U, 0x04080U, 0x00A11U, 0x00A10U,
|
||||||
|
0x10500U, 0x04084U, 0x200A4U, 0x0408AU, 0x04089U, 0x04088U, 0x200A0U, 0x12040U, 0x200A2U, 0x12042U, 0x00A05U, 0x00A04U, 0x04091U,
|
||||||
|
0x04090U, 0x00A01U, 0x00A00U, 0x00A03U, 0x00A02U, 0x05404U, 0x00A0CU, 0x28105U, 0x28104U, 0x05400U, 0x00A08U, 0x28101U, 0x28100U,
|
||||||
|
0x00680U, 0x00681U, 0x04061U, 0x04060U, 0x20048U, 0x20049U, 0x2004AU, 0x04064U, 0x20044U, 0x20045U, 0x50401U, 0x50400U, 0x20040U,
|
||||||
|
0x20041U, 0x20042U, 0x01210U, 0x68002U, 0x68003U, 0x68000U, 0x68001U, 0x04C02U, 0x0120AU, 0x04C00U, 0x01208U, 0x20054U, 0x01206U,
|
||||||
|
0x01205U, 0x01204U, 0x20050U, 0x01202U, 0x01201U, 0x01200U, 0x18800U, 0x04042U, 0x04041U, 0x04040U, 0x42202U, 0x04046U, 0x42200U,
|
||||||
|
0x04044U, 0x20064U, 0x0404AU, 0x04049U, 0x04048U, 0x20060U, 0x12080U, 0x20062U, 0x12082U, 0x18810U, 0x04052U, 0x04051U, 0x04050U,
|
||||||
|
0x4C009U, 0x4C008U, 0x42210U, 0x04054U, 0x20C01U, 0x20C00U, 0x20C03U, 0x20C02U, 0x4C001U, 0x4C000U, 0x01221U, 0x01220U, 0x2000CU,
|
||||||
|
0x04022U, 0x04021U, 0x04020U, 0x20008U, 0x20009U, 0x2000AU, 0x04024U, 0x20004U, 0x20005U, 0x20006U, 0x04028U, 0x20000U, 0x20001U,
|
||||||
|
0x20002U, 0x20003U, 0x2001CU, 0x04032U, 0x04031U, 0x04030U, 0x20018U, 0x18400U, 0x2001AU, 0x18402U, 0x20014U, 0x20015U, 0x20016U,
|
||||||
|
0x01244U, 0x20010U, 0x20011U, 0x20012U, 0x01240U, 0x04003U, 0x04002U, 0x04001U, 0x04000U, 0x20028U, 0x04006U, 0x04005U, 0x04004U,
|
||||||
|
0x20024U, 0x0400AU, 0x04009U, 0x04008U, 0x20020U, 0x20021U, 0x20022U, 0x0400CU, 0x04013U, 0x04012U, 0x04011U, 0x04010U, 0x00A81U,
|
||||||
|
0x00A80U, 0x04015U, 0x04014U, 0x0A200U, 0x11100U, 0x04019U, 0x04018U, 0x20030U, 0x20031U, 0x50800U, 0x50801U, 0x00700U, 0x60020U,
|
||||||
|
0x10811U, 0x10810U, 0x4400AU, 0x60024U, 0x44008U, 0x44009U, 0x44006U, 0x02242U, 0x44004U, 0x02240U, 0x44002U, 0x44003U, 0x44000U,
|
||||||
|
0x44001U, 0x0C040U, 0x10802U, 0x10801U, 0x10800U, 0x0C044U, 0x10806U, 0x10805U, 0x10804U, 0x23000U, 0x23001U, 0x10809U, 0x10808U,
|
||||||
|
0x44012U, 0x44013U, 0x44010U, 0x44011U, 0x60001U, 0x60000U, 0x60003U, 0x60002U, 0x60005U, 0x60004U, 0x10440U, 0x10441U, 0x60009U,
|
||||||
|
0x60008U, 0x44024U, 0x6000AU, 0x09200U, 0x12100U, 0x44020U, 0x44021U, 0x60011U, 0x60010U, 0x10821U, 0x10820U, 0x07003U, 0x07002U,
|
||||||
|
0x07001U, 0x07000U, 0x23020U, 0x60018U, 0x28045U, 0x28044U, 0x09210U, 0x28042U, 0x28041U, 0x28040U, 0x0C010U, 0x0C011U, 0x02209U,
|
||||||
|
0x02208U, 0x10422U, 0x10423U, 0x10420U, 0x10421U, 0x02203U, 0x02202U, 0x02201U, 0x02200U, 0x20180U, 0x20181U, 0x44040U, 0x02204U,
|
||||||
|
0x0C000U, 0x0C001U, 0x0C002U, 0x10840U, 0x0C004U, 0x0C005U, 0x0C006U, 0x10844U, 0x0C008U, 0x0C009U, 0x02211U, 0x02210U, 0x0C00CU,
|
||||||
|
0x28022U, 0x28021U, 0x28020U, 0x60041U, 0x60040U, 0x10404U, 0x04180U, 0x10402U, 0x10403U, 0x10400U, 0x10401U, 0x02223U, 0x02222U,
|
||||||
|
0x02221U, 0x02220U, 0x1040AU, 0x28012U, 0x10408U, 0x28010U, 0x0C020U, 0x0C021U, 0x41200U, 0x41201U, 0x00B01U, 0x00B00U, 0x10410U,
|
||||||
|
0x28008U, 0x11081U, 0x11080U, 0x28005U, 0x28004U, 0x28003U, 0x28002U, 0x28001U, 0x28000U, 0x52040U, 0x14204U, 0x22405U, 0x22404U,
|
||||||
|
0x14201U, 0x14200U, 0x22401U, 0x22400U, 0x20144U, 0x20145U, 0x44084U, 0x022C0U, 0x20140U, 0x20141U, 0x44080U, 0x44081U, 0x40A08U,
|
||||||
|
0x10882U, 0x10881U, 0x10880U, 0x14211U, 0x14210U, 0x1A008U, 0x10884U, 0x40A00U, 0x40A01U, 0x40A02U, 0x01304U, 0x1A002U, 0x01302U,
|
||||||
|
0x1A000U, 0x01300U, 0x60081U, 0x60080U, 0x04141U, 0x04140U, 0x60085U, 0x60084U, 0x104C0U, 0x04144U, 0x06400U, 0x06401U, 0x30200U,
|
||||||
|
0x30201U, 0x06404U, 0x40640U, 0x30204U, 0x30205U, 0x08603U, 0x08602U, 0x08601U, 0x08600U, 0x00000U, 0x08606U, 0x08605U, 0x08604U,
|
||||||
|
0x11041U, 0x11040U, 0x30210U, 0x11042U, 0x11045U, 0x11044U, 0x1A020U, 0x01320U, 0x52000U, 0x52001U, 0x04121U, 0x04120U, 0x20108U,
|
||||||
|
0x20109U, 0x08A00U, 0x08A01U, 0x20104U, 0x20105U, 0x02281U, 0x02280U, 0x20100U, 0x20101U, 0x20102U, 0x20103U, 0x0C080U, 0x0C081U,
|
||||||
|
0x0C082U, 0x04130U, 0x0C084U, 0x06808U, 0x08A10U, 0x08A11U, 0x11021U, 0x11020U, 0x11023U, 0x11022U, 0x20110U, 0x06800U, 0x20112U,
|
||||||
|
0x06802U, 0x04103U, 0x04102U, 0x04101U, 0x04100U, 0x10482U, 0x04106U, 0x10480U, 0x04104U, 0x11011U, 0x11010U, 0x04109U, 0x04108U,
|
||||||
|
0x20120U, 0x40600U, 0x20122U, 0x40602U, 0x11009U, 0x11008U, 0x22800U, 0x04110U, 0x1100DU, 0x1100CU, 0x22804U, 0x04114U, 0x11001U,
|
||||||
|
0x11000U, 0x11003U, 0x11002U, 0x11005U, 0x11004U, 0x28081U, 0x28080U };
|
||||||
|
|
||||||
|
#define X18 0x00040000 /* vector representation of X^{18} */
|
||||||
|
#define X11 0x00000800 /* vector representation of X^{11} */
|
||||||
|
#define MASK8 0xfffff800 /* auxiliary vector for testing */
|
||||||
|
#define GENPOL 0x00000c75 /* generator polinomial, g(x) */
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DMRSlotType class.
|
||||||
|
/// </summary>
|
||||||
|
DMRSlotType::DMRSlotType()
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes DMR slot type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frame"></param>
|
||||||
|
/// <param name="colorCode"></param>
|
||||||
|
/// <param name="dataType"></param>
|
||||||
|
void DMRSlotType::decode(const uint8_t* frame, uint8_t& colorCode, uint8_t& dataType) const
|
||||||
|
{
|
||||||
|
uint8_t slotType[3U];
|
||||||
|
slotType[0U] = (frame[12U] << 2) & 0xFCU;
|
||||||
|
slotType[0U] |= (frame[13U] >> 6) & 0x03U;
|
||||||
|
|
||||||
|
slotType[1U] = (frame[13U] << 2) & 0xC0U;
|
||||||
|
slotType[1U] |= (frame[19U] << 2) & 0x3CU;
|
||||||
|
slotType[1U] |= (frame[20U] >> 6) & 0x03U;
|
||||||
|
|
||||||
|
slotType[2U] = (frame[20U] << 2) & 0xF0U;
|
||||||
|
|
||||||
|
uint8_t code = decode2087(slotType);
|
||||||
|
|
||||||
|
colorCode = (code >> 4) & 0x0FU;
|
||||||
|
dataType = (code >> 0) & 0x0FU;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encodes DMR slot type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="colorCode"></param>
|
||||||
|
/// <param name="dataType"></param>
|
||||||
|
/// <param name="frame"></param>
|
||||||
|
void DMRSlotType::encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) const
|
||||||
|
{
|
||||||
|
uint8_t slotType[3U];
|
||||||
|
slotType[0U] = (colorCode << 4) & 0xF0U;
|
||||||
|
slotType[0U] |= (dataType << 0) & 0x0FU;
|
||||||
|
|
||||||
|
uint16_t cksum = ENCODING_TABLE_2087[slotType[0U]];
|
||||||
|
|
||||||
|
slotType[1U] = (cksum >> 0) & 0xFFU;
|
||||||
|
slotType[2U] = (cksum >> 8) & 0xFFU;
|
||||||
|
|
||||||
|
frame[12U] = (frame[12U] & 0xC0U) | ((slotType[0U] >> 2) & 0x3FU);
|
||||||
|
frame[13U] = (frame[13U] & 0x0FU) | ((slotType[0U] << 6) & 0xC0U) | ((slotType[1U] >> 2) & 0x30U);
|
||||||
|
frame[19U] = (frame[19U] & 0xF0U) | ((slotType[1U] >> 2) & 0x0FU);
|
||||||
|
frame[20U] = (frame[20U] & 0x03U) | ((slotType[1U] << 6) & 0xC0U) | ((slotType[2U] >> 2) & 0x3CU);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t DMRSlotType::decode2087(const uint8_t* data) const
|
||||||
|
{
|
||||||
|
uint32_t code = (data[0U] << 11) + (data[1U] << 3) + (data[2U] >> 5);
|
||||||
|
uint32_t syndrome = getSyndrome1987(code);
|
||||||
|
uint32_t error_pattern = DECODING_TABLE_1987[syndrome];
|
||||||
|
|
||||||
|
if (error_pattern != 0x00U)
|
||||||
|
code ^= error_pattern;
|
||||||
|
|
||||||
|
return code >> 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Compute the syndrome corresponding to the given pattern, i.e., the
|
||||||
|
/// remainder after dividing the pattern (when considering it as the vector
|
||||||
|
/// representation of a polynomial) by the generator polynomial, GENPOL.
|
||||||
|
/// In the program this pattern has several meanings: (1) pattern = infomation
|
||||||
|
/// bits, when constructing the encoding table; (2) pattern = error pattern,
|
||||||
|
/// when constructing the decoding table; and (3) pattern = received vector, to
|
||||||
|
/// obtain its syndrome in decoding.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="pattern"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint32_t DMRSlotType::getSyndrome1987(uint32_t pattern) const
|
||||||
|
{
|
||||||
|
unsigned int aux = X18;
|
||||||
|
|
||||||
|
if (pattern >= X11) {
|
||||||
|
while (pattern & MASK8) {
|
||||||
|
while (!(aux & pattern))
|
||||||
|
aux = aux >> 1;
|
||||||
|
|
||||||
|
pattern ^= (aux / X11) * GENPOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__DMR_SLOT_TYPE_H__)
|
||||||
|
#define __DMR_SLOT_TYPE_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
namespace dmr
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
//
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API DMRSlotType {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the DMRSlotType class.</summary>
|
||||||
|
DMRSlotType();
|
||||||
|
|
||||||
|
/// <summary>Decodes DMR slot type.</summary>
|
||||||
|
void decode(const uint8_t* frame, uint8_t& colorCode, uint8_t& dataType) const;
|
||||||
|
/// <summary>Encodes DMR slot type.</summary>
|
||||||
|
void encode(uint8_t colorCode, uint8_t dataType, uint8_t* frame) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// <summary></summary>
|
||||||
|
uint8_t decode2087(const uint8_t* data) const;
|
||||||
|
/// <summary></summary>
|
||||||
|
uint32_t getSyndrome1987(uint32_t pattern) const;
|
||||||
|
};
|
||||||
|
} // namespace dmr
|
||||||
|
|
||||||
|
#endif // __DMR_SLOT_TYPE_H__
|
||||||
@ -0,0 +1,466 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "dmr/DMRSlotType.h"
|
||||||
|
|
||||||
|
using namespace dmr;
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// The PR FILL and BS Data Sync pattern.
|
||||||
|
const uint8_t IDLE_DATA[] = {
|
||||||
|
0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U,
|
||||||
|
0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U,
|
||||||
|
0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t CACH_INTERLEAVE[] = {
|
||||||
|
1U, 2U, 3U, 5U, 6U, 7U, 9U, 10U, 11U, 13U, 15U, 16U, 17U, 19U, 20U, 21U, 23U,
|
||||||
|
25U, 26U, 27U, 29U, 30U, 31U, 33U, 34U, 35U, 37U, 39U, 40U, 41U, 43U, 44U, 45U, 47U,
|
||||||
|
49U, 50U, 51U, 53U, 54U, 55U, 57U, 58U, 59U, 61U, 63U, 64U, 65U, 67U, 68U, 69U, 71U,
|
||||||
|
73U, 74U, 75U, 77U, 78U, 79U, 81U, 82U, 83U, 85U, 87U, 88U, 89U, 91U, 92U, 93U, 95U
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t EMPTY_SHORT_LC[] = {
|
||||||
|
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t STARTUP_COUNT = 20U;
|
||||||
|
const uint32_t ABORT_COUNT = 6U;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DMRTX class.
|
||||||
|
/// </summary>
|
||||||
|
DMRTX::DMRTX() :
|
||||||
|
m_fifo(),
|
||||||
|
m_state(DMRTXSTATE_IDLE),
|
||||||
|
m_idle(),
|
||||||
|
m_cachPtr(0U),
|
||||||
|
m_shortLC(),
|
||||||
|
m_newShortLC(),
|
||||||
|
m_markBuffer(),
|
||||||
|
m_poBuffer(),
|
||||||
|
m_poLen(0U),
|
||||||
|
m_poPtr(0U),
|
||||||
|
m_frameCount(0U),
|
||||||
|
m_abortCount(),
|
||||||
|
m_abort(),
|
||||||
|
m_control_old(0U)
|
||||||
|
{
|
||||||
|
::memcpy(m_newShortLC, EMPTY_SHORT_LC, 12U);
|
||||||
|
::memcpy(m_shortLC, EMPTY_SHORT_LC, 12U);
|
||||||
|
|
||||||
|
m_abort[0U] = false;
|
||||||
|
m_abort[1U] = false;
|
||||||
|
|
||||||
|
m_abortCount[0U] = 0U;
|
||||||
|
m_abortCount[1U] = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process local buffer and transmit on the air interface.
|
||||||
|
/// </summary>
|
||||||
|
void DMRTX::process()
|
||||||
|
{
|
||||||
|
if (m_state == DMRTXSTATE_IDLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_poLen == 0U) {
|
||||||
|
switch (m_state) {
|
||||||
|
case DMRTXSTATE_SLOT1:
|
||||||
|
createData(0U);
|
||||||
|
m_state = DMRTXSTATE_CACH2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DMRTXSTATE_CACH2:
|
||||||
|
createCACH(1U, 0U);
|
||||||
|
m_state = DMRTXSTATE_SLOT2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DMRTXSTATE_SLOT2:
|
||||||
|
createData(1U);
|
||||||
|
m_state = DMRTXSTATE_CACH1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DMRTXSTATE_CAL:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
createCACH(0U, 1U);
|
||||||
|
m_state = DMRTXSTATE_SLOT1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG2("DMRTX: process(): poLen", m_poLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_poLen > 0U) {
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > 8U) {
|
||||||
|
uint8_t c = m_poBuffer[m_poPtr];
|
||||||
|
uint8_t m = m_markBuffer[m_poPtr];
|
||||||
|
m_poPtr++;
|
||||||
|
|
||||||
|
writeByte(c, m);
|
||||||
|
|
||||||
|
space -= 8U;
|
||||||
|
|
||||||
|
if (m_poPtr >= m_poLen) {
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_poLen = 0U;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write slot 1 data to the local buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t DMRTX::writeData1(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
||||||
|
return RSN_ILLEGAL_LENGTH;
|
||||||
|
|
||||||
|
uint16_t space = m_fifo[0U].getSpace();
|
||||||
|
DEBUG3("DMRTX: writeData1(): dataLength/fifoLength", length, space);
|
||||||
|
if (space < DMR_FRAME_LENGTH_BYTES)
|
||||||
|
return RSN_RINGBUFF_FULL;
|
||||||
|
|
||||||
|
if (m_abort[0U]) {
|
||||||
|
m_fifo[0U].reset();
|
||||||
|
m_abort[0U] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++)
|
||||||
|
m_fifo[0U].put(data[i + 1U]);
|
||||||
|
|
||||||
|
// Start the TX if it isn't already on
|
||||||
|
if (!m_tx)
|
||||||
|
m_state = DMRTXSTATE_SLOT1;
|
||||||
|
|
||||||
|
return RSN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write slot 2 data to the local buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t DMRTX::writeData2(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
||||||
|
return RSN_ILLEGAL_LENGTH;
|
||||||
|
|
||||||
|
uint16_t space = m_fifo[1U].getSpace();
|
||||||
|
DEBUG3("DMRTX: writeData2(): dataLength/fifoLength", length, space);
|
||||||
|
if (space < DMR_FRAME_LENGTH_BYTES)
|
||||||
|
return RSN_RINGBUFF_FULL;
|
||||||
|
|
||||||
|
if (m_abort[1U]) {
|
||||||
|
m_fifo[1U].reset();
|
||||||
|
m_abort[1U] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++)
|
||||||
|
m_fifo[1U].put(data[i + 1U]);
|
||||||
|
|
||||||
|
// Start the TX if it isn't already on
|
||||||
|
if (!m_tx)
|
||||||
|
m_state = DMRTXSTATE_SLOT1;
|
||||||
|
|
||||||
|
return RSN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write short LC data to the local buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t DMRTX::writeShortLC(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (length != 9U)
|
||||||
|
return RSN_ILLEGAL_LENGTH;
|
||||||
|
|
||||||
|
::memset(m_newShortLC, 0x00U, 12U);
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < 68U; i++) {
|
||||||
|
bool b = _READ_BIT(data, i);
|
||||||
|
uint8_t n = CACH_INTERLEAVE[i];
|
||||||
|
_WRITE_BIT(m_newShortLC, n, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RSN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write abort data to the local buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t DMRTX::writeAbort(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (length != 1U)
|
||||||
|
return RSN_ILLEGAL_LENGTH;
|
||||||
|
|
||||||
|
switch (data[0U]) {
|
||||||
|
case 1U:
|
||||||
|
m_abort[0U] = true;
|
||||||
|
m_abortCount[0U] = 0U;
|
||||||
|
return RSN_OK;
|
||||||
|
|
||||||
|
case 2U:
|
||||||
|
m_abort[1U] = true;
|
||||||
|
m_abortCount[1U] = 0U;
|
||||||
|
return RSN_OK;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return RSN_INVALID_DMR_SLOT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to set the start state for Tx.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
void DMRTX::setStart(bool start)
|
||||||
|
{
|
||||||
|
m_state = start ? DMRTXSTATE_SLOT1 : DMRTXSTATE_IDLE;
|
||||||
|
|
||||||
|
m_frameCount = 0U;
|
||||||
|
m_abortCount[0U] = 0U;
|
||||||
|
m_abortCount[1U] = 1U;
|
||||||
|
|
||||||
|
m_abort[0U] = false;
|
||||||
|
m_abort[1U] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to get how much space the slot 1 ring buffer has for samples.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t DMRTX::getSpace1() const
|
||||||
|
{
|
||||||
|
return m_fifo[0U].getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to get how much space the slot 2 ring buffer has for samples.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t DMRTX::getSpace2() const
|
||||||
|
{
|
||||||
|
return m_fifo[1U].getSpace() / (DMR_FRAME_LENGTH_BYTES + 2U);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the DMR color code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="colorCode">Color code.</param>
|
||||||
|
void DMRTX::setColorCode(uint8_t colorCode)
|
||||||
|
{
|
||||||
|
::memcpy(m_idle, IDLE_DATA, DMR_FRAME_LENGTH_BYTES);
|
||||||
|
|
||||||
|
DMRSlotType slotType;
|
||||||
|
slotType.encode(colorCode, DT_IDLE, m_idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the fine adjust 4FSK symbol levels.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level3Adj">+3/-3 symbol adjust.</param>
|
||||||
|
/// <param name="level1Adj">+1/-1 symbol adjust.</param>
|
||||||
|
void DMRTX::setSymbolLvlAdj(int8_t level3Adj, int8_t level1Adj)
|
||||||
|
{
|
||||||
|
/* ignored ADF7021 doesn't allow direct symbol level adjustments */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to reset data values to defaults for slot 1 FIFO.
|
||||||
|
/// </summary>
|
||||||
|
void DMRTX::resetFifo1()
|
||||||
|
{
|
||||||
|
m_fifo[0U].reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to reset data values to defaults for slot 2 FIFO.
|
||||||
|
/// </summary>
|
||||||
|
void DMRTX::resetFifo2()
|
||||||
|
{
|
||||||
|
m_fifo[1U].reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint32_t DMRTX::getFrameCount()
|
||||||
|
{
|
||||||
|
return m_frameCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slotIndex"></param>
|
||||||
|
void DMRTX::createData(uint8_t slotIndex)
|
||||||
|
{
|
||||||
|
if (m_fifo[slotIndex].getData() > 0U && m_frameCount >= STARTUP_COUNT) {
|
||||||
|
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
|
||||||
|
m_poBuffer[i] = m_fifo[slotIndex].get();
|
||||||
|
if (i == 8U)
|
||||||
|
m_markBuffer[i] = slotIndex == 0U ? MARK_SLOT1 : MARK_SLOT2;
|
||||||
|
else
|
||||||
|
m_markBuffer[i] = MARK_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_abort[slotIndex] = false;
|
||||||
|
// Transmit an idle message
|
||||||
|
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
|
||||||
|
m_poBuffer[i] = m_idle[i];
|
||||||
|
if (i == 8U)
|
||||||
|
m_markBuffer[i] = slotIndex == 0U ? MARK_SLOT1 : MARK_SLOT2;
|
||||||
|
else
|
||||||
|
m_markBuffer[i] = MARK_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poLen = DMR_FRAME_LENGTH_BYTES;
|
||||||
|
m_poPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="txSlotIndex"></param>
|
||||||
|
/// <param name="rxSlotIndex"></param>
|
||||||
|
void DMRTX::createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex)
|
||||||
|
{
|
||||||
|
m_frameCount++;
|
||||||
|
m_abortCount[0U]++;
|
||||||
|
m_abortCount[1U]++;
|
||||||
|
|
||||||
|
if (m_cachPtr >= 12U)
|
||||||
|
m_cachPtr = 0U;
|
||||||
|
|
||||||
|
if (m_cachPtr == 0U) {
|
||||||
|
if (m_fifo[0U].getData() == 0U && m_fifo[1U].getData() == 0U)
|
||||||
|
::memcpy(m_shortLC, EMPTY_SHORT_LC, 12U);
|
||||||
|
else
|
||||||
|
::memcpy(m_shortLC, m_newShortLC, 12U);
|
||||||
|
}
|
||||||
|
|
||||||
|
::memcpy(m_poBuffer, m_shortLC + m_cachPtr, 3U);
|
||||||
|
m_markBuffer[0U] = MARK_NONE;
|
||||||
|
m_markBuffer[1U] = MARK_NONE;
|
||||||
|
m_markBuffer[2U] = rxSlotIndex == 1U ? MARK_SLOT1 : MARK_SLOT2;
|
||||||
|
|
||||||
|
bool at = false;
|
||||||
|
if (m_frameCount >= STARTUP_COUNT)
|
||||||
|
at = m_fifo[rxSlotIndex].getData() > 0U;
|
||||||
|
bool tc = txSlotIndex == 1U;
|
||||||
|
bool ls0 = true; // For 1 and 2
|
||||||
|
bool ls1 = true;
|
||||||
|
|
||||||
|
if (m_cachPtr == 0U) // For 0
|
||||||
|
ls1 = false;
|
||||||
|
else if (m_cachPtr == 9U) // For 3
|
||||||
|
ls0 = false;
|
||||||
|
|
||||||
|
bool h0 = at ^ tc ^ ls1;
|
||||||
|
bool h1 = tc ^ ls1 ^ ls0;
|
||||||
|
bool h2 = at ^ tc ^ ls0;
|
||||||
|
|
||||||
|
m_poBuffer[0U] |= at ? 0x80U : 0x00U;
|
||||||
|
m_poBuffer[0U] |= tc ? 0x08U : 0x00U;
|
||||||
|
m_poBuffer[1U] |= ls1 ? 0x80U : 0x00U;
|
||||||
|
m_poBuffer[1U] |= ls0 ? 0x08U : 0x00U;
|
||||||
|
m_poBuffer[1U] |= h0 ? 0x02U : 0x00U;
|
||||||
|
m_poBuffer[2U] |= h1 ? 0x20U : 0x00U;
|
||||||
|
m_poBuffer[2U] |= h2 ? 0x02U : 0x00U;
|
||||||
|
|
||||||
|
m_poLen = DMR_CACH_LENGTH_BYTES;
|
||||||
|
m_poPtr = 0U;
|
||||||
|
|
||||||
|
m_cachPtr += 3U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c"></param>
|
||||||
|
/// <param name="control"></param>
|
||||||
|
void DMRTX::writeByte(uint8_t c, uint8_t control)
|
||||||
|
{
|
||||||
|
uint8_t bit;
|
||||||
|
uint8_t mask = 0x80U;
|
||||||
|
uint8_t control_tmp = m_control_old;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < 8U; i++, c <<= 1) {
|
||||||
|
if ((c & mask) == mask)
|
||||||
|
bit = 1U;
|
||||||
|
else
|
||||||
|
bit = 0U;
|
||||||
|
|
||||||
|
if (i == 7U) {
|
||||||
|
if (control == MARK_SLOT2)
|
||||||
|
control_tmp = true;
|
||||||
|
else if (control == MARK_SLOT1)
|
||||||
|
control_tmp = false;
|
||||||
|
|
||||||
|
m_control_old = control_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
io.write(&bit, 1, &control_tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DUPLEX
|
||||||
@ -0,0 +1,135 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__DMR_TX_H__)
|
||||||
|
#define __DMR_TX_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "dmr/DMRDefines.h"
|
||||||
|
#include "SerialBuffer.h"
|
||||||
|
|
||||||
|
#if defined(DUPLEX)
|
||||||
|
|
||||||
|
namespace dmr
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum DMRTXSTATE {
|
||||||
|
DMRTXSTATE_IDLE,
|
||||||
|
DMRTXSTATE_SLOT1,
|
||||||
|
DMRTXSTATE_CACH1,
|
||||||
|
DMRTXSTATE_SLOT2,
|
||||||
|
DMRTXSTATE_CACH2,
|
||||||
|
DMRTXSTATE_CAL
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements receiver logic for duplex DMR mode operation.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API DMRTX {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the DMRTX class.</summary>
|
||||||
|
DMRTX();
|
||||||
|
|
||||||
|
/// <summary>Process local buffer and transmit on the air interface.</summary>
|
||||||
|
void process();
|
||||||
|
|
||||||
|
/// <summary>Write slot 1 data to the local buffer.</summary>
|
||||||
|
uint8_t writeData1(const uint8_t* data, uint8_t length);
|
||||||
|
/// <summary>Write slot 2 data to the local buffer.</summary>
|
||||||
|
uint8_t writeData2(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
/// <summary>Write short LC data to the local buffer.</summary>
|
||||||
|
uint8_t writeShortLC(const uint8_t* data, uint8_t length);
|
||||||
|
/// <summary>Write abort data to the local buffer.</summary>
|
||||||
|
uint8_t writeAbort(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
/// <summary>Helper to set the start state for Tx.</summary>
|
||||||
|
void setStart(bool start);
|
||||||
|
|
||||||
|
/// <summary>Helper to get how much space the slot 1 ring buffer has for samples.</summary>
|
||||||
|
uint8_t getSpace1() const;
|
||||||
|
/// <summary>Helper to get how much space the slot 2 ring buffer has for samples.</summary>
|
||||||
|
uint8_t getSpace2() const;
|
||||||
|
|
||||||
|
/// <summary>Sets the DMR color code.</summary>
|
||||||
|
void setColorCode(uint8_t colorCode);
|
||||||
|
/// <summary>Sets the fine adjust 4FSK symbol levels.</summary>
|
||||||
|
void setSymbolLvlAdj(int8_t level3Adj, int8_t level1Adj);
|
||||||
|
|
||||||
|
/// <summary>Helper to reset data values to defaults for slot 1 FIFO.</summary>
|
||||||
|
void resetFifo1();
|
||||||
|
/// <summary>Helper to reset data values to defaults for slot 2 FIFO.</summary>
|
||||||
|
void resetFifo2();
|
||||||
|
/// <summary></summary>
|
||||||
|
uint32_t getFrameCount();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SerialBuffer m_fifo[2U];
|
||||||
|
|
||||||
|
DMRTXSTATE m_state;
|
||||||
|
|
||||||
|
uint8_t m_idle[DMR_FRAME_LENGTH_BYTES];
|
||||||
|
uint8_t m_cachPtr;
|
||||||
|
|
||||||
|
uint8_t m_shortLC[12U];
|
||||||
|
uint8_t m_newShortLC[12U];
|
||||||
|
|
||||||
|
uint8_t m_markBuffer[40U];
|
||||||
|
|
||||||
|
uint8_t m_poBuffer[40U];
|
||||||
|
uint16_t m_poLen;
|
||||||
|
uint16_t m_poPtr;
|
||||||
|
|
||||||
|
uint32_t m_frameCount;
|
||||||
|
|
||||||
|
uint32_t m_abortCount[2U];
|
||||||
|
bool m_abort[2U];
|
||||||
|
|
||||||
|
uint8_t m_control_old;
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void createData(uint8_t slotIndex);
|
||||||
|
/// <summary></summary>
|
||||||
|
void createCACH(uint8_t txSlotIndex, uint8_t rxSlotIndex);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeByte(uint8_t c, uint8_t control);
|
||||||
|
};
|
||||||
|
} // namespace dmr
|
||||||
|
|
||||||
|
#endif // DUPLEX
|
||||||
|
|
||||||
|
#endif // __DMR_TX_H__
|
||||||
@ -0,0 +1,197 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{3733f055-083f-4bf4-9233-25d471de58d9}</ProjectGuid>
|
||||||
|
<RootNamespace>dvmfirmwarehs</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
<ProjectName>firmware-hs</ProjectName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="ADF7021.h" />
|
||||||
|
<ClInclude Include="BitBuffer.h" />
|
||||||
|
<ClInclude Include="CalRSSI.h" />
|
||||||
|
<ClInclude Include="CWIdTX.h" />
|
||||||
|
<ClInclude Include="Defines.h" />
|
||||||
|
<ClInclude Include="dmr\CalDMR.h" />
|
||||||
|
<ClInclude Include="dmr\DMRDefines.h" />
|
||||||
|
<ClInclude Include="dmr\DMRDMORX.h" />
|
||||||
|
<ClInclude Include="dmr\DMRDMOTX.h" />
|
||||||
|
<ClInclude Include="dmr\DMRIdleRX.h" />
|
||||||
|
<ClInclude Include="dmr\DMRRX.h" />
|
||||||
|
<ClInclude Include="dmr\DMRSlotRX.h" />
|
||||||
|
<ClInclude Include="dmr\DMRSlotType.h" />
|
||||||
|
<ClInclude Include="dmr\DMRTX.h" />
|
||||||
|
<ClInclude Include="Globals.h" />
|
||||||
|
<ClInclude Include="IO.h" />
|
||||||
|
<ClInclude Include="p25\CalP25.h" />
|
||||||
|
<ClInclude Include="p25\P25Defines.h" />
|
||||||
|
<ClInclude Include="p25\P25RX.h" />
|
||||||
|
<ClInclude Include="p25\P25TX.h" />
|
||||||
|
<ClInclude Include="SerialPort.h" />
|
||||||
|
<ClInclude Include="SerialBuffer.h" />
|
||||||
|
<ClInclude Include="STM_UART.h" />
|
||||||
|
<ClInclude Include="Utils.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="ADF7021.cpp" />
|
||||||
|
<ClCompile Include="BitBuffer.cpp" />
|
||||||
|
<ClCompile Include="CalRSSI.cpp" />
|
||||||
|
<ClCompile Include="CWIdTX.cpp" />
|
||||||
|
<ClCompile Include="dmr\CalDMR.cpp" />
|
||||||
|
<ClCompile Include="dmr\DMRDMORX.cpp" />
|
||||||
|
<ClCompile Include="dmr\DMRDMOTX.cpp" />
|
||||||
|
<ClCompile Include="dmr\DMRIdleRX.cpp" />
|
||||||
|
<ClCompile Include="dmr\DMRRX.cpp" />
|
||||||
|
<ClCompile Include="dmr\DMRSlotRX.cpp" />
|
||||||
|
<ClCompile Include="dmr\DMRSlotType.cpp" />
|
||||||
|
<ClCompile Include="dmr\DMRTX.cpp" />
|
||||||
|
<ClCompile Include="FirmwareMain.cpp" />
|
||||||
|
<ClCompile Include="IO.cpp" />
|
||||||
|
<ClCompile Include="IOSTM.cpp" />
|
||||||
|
<ClCompile Include="p25\CalP25.cpp" />
|
||||||
|
<ClCompile Include="p25\P25RX.cpp" />
|
||||||
|
<ClCompile Include="p25\P25TX.cpp" />
|
||||||
|
<ClCompile Include="SerialPort.cpp" />
|
||||||
|
<ClCompile Include="SerialBuffer.cpp" />
|
||||||
|
<ClCompile Include="SerialSTM.cpp" />
|
||||||
|
<ClCompile Include="STM_UART.cpp" />
|
||||||
|
<ClCompile Include="Utils.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,174 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\dmr">
|
||||||
|
<UniqueIdentifier>{03e2c302-d472-4e33-8ab9-53296423a641}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Source Files\p25">
|
||||||
|
<UniqueIdentifier>{19296f3e-bc16-4bc8-9faf-158ab22b8dc0}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\dmr">
|
||||||
|
<UniqueIdentifier>{493de3cc-83da-49f4-ab01-a199ac989d23}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\p25">
|
||||||
|
<UniqueIdentifier>{ce2a5db1-59c6-4fdc-8774-f1d85651cd34}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="dmr\CalDMR.h">
|
||||||
|
<Filter>Header Files\dmr</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="dmr\DMRDefines.h">
|
||||||
|
<Filter>Header Files\dmr</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="dmr\DMRDMORX.h">
|
||||||
|
<Filter>Header Files\dmr</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="dmr\DMRDMOTX.h">
|
||||||
|
<Filter>Header Files\dmr</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="dmr\DMRIdleRX.h">
|
||||||
|
<Filter>Header Files\dmr</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="dmr\DMRRX.h">
|
||||||
|
<Filter>Header Files\dmr</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="dmr\DMRSlotRX.h">
|
||||||
|
<Filter>Header Files\dmr</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="dmr\DMRSlotType.h">
|
||||||
|
<Filter>Header Files\dmr</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="dmr\DMRTX.h">
|
||||||
|
<Filter>Header Files\dmr</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="p25\P25Defines.h">
|
||||||
|
<Filter>Header Files\p25</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="p25\P25RX.h">
|
||||||
|
<Filter>Header Files\p25</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="p25\P25TX.h">
|
||||||
|
<Filter>Header Files\p25</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ADF7021.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="BitBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CalRSSI.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="CWIdTX.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Globals.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="IO.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SerialPort.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SerialBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Utils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Defines.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="STM_UART.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="p25\CalP25.h">
|
||||||
|
<Filter>Header Files\p25</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dmr\CalDMR.cpp">
|
||||||
|
<Filter>Source Files\dmr</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dmr\DMRDMORX.cpp">
|
||||||
|
<Filter>Source Files\dmr</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dmr\DMRDMOTX.cpp">
|
||||||
|
<Filter>Source Files\dmr</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dmr\DMRIdleRX.cpp">
|
||||||
|
<Filter>Source Files\dmr</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dmr\DMRRX.cpp">
|
||||||
|
<Filter>Source Files\dmr</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dmr\DMRSlotRX.cpp">
|
||||||
|
<Filter>Source Files\dmr</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dmr\DMRSlotType.cpp">
|
||||||
|
<Filter>Source Files\dmr</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dmr\DMRTX.cpp">
|
||||||
|
<Filter>Source Files\dmr</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="p25\P25RX.cpp">
|
||||||
|
<Filter>Source Files\p25</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="p25\P25TX.cpp">
|
||||||
|
<Filter>Source Files\p25</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ADF7021.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="BitBuffer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CalRSSI.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="CWIdTX.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="FirmwareMain.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="IO.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="IOSTM.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SerialPort.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SerialBuffer.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SerialSTM.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Utils.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="STM_UART.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="p25\CalP25.cpp">
|
||||||
|
<Filter>Source Files\p25</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Memory areas */
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ROM (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* FLASH */
|
||||||
|
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K /* Main RAM */
|
||||||
|
}
|
||||||
|
|
||||||
|
INCLUDE stm32f10x_link.ld
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "p25/CalP25.h"
|
||||||
|
|
||||||
|
using namespace p25;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Recommended 1011 Hz test pattern for P25 Phase 1 (ANSI/TIA-102.CAAA)
|
||||||
|
// NAC: 0x293, srcID: 1, dstID: TG1
|
||||||
|
unsigned char LDU1_1K[] = { 0x00,
|
||||||
|
0x55, 0x75, 0xF5, 0xFF, 0x77, 0xFF, 0x29, 0x35, 0x54, 0x7B, 0xCB, 0x19, 0x4D, 0x0D, 0xCE, 0x24, 0xA1, 0x24,
|
||||||
|
0x0D, 0x43, 0x3C, 0x0B, 0xE1, 0xB9, 0x18, 0x44, 0xFC, 0xC1, 0x62, 0x96, 0x27, 0x60, 0xE4, 0xE2, 0x4A, 0x10,
|
||||||
|
0x90, 0xD4, 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4C, 0xFC, 0x16, 0x29, 0x62, 0x76, 0x0E, 0xC0, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x03, 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x02, 0xF8, 0x6E, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x94,
|
||||||
|
0x89, 0xD8, 0x39, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x38, 0x24, 0xA1, 0x24, 0x35, 0x0C, 0xF0, 0x2F, 0x86, 0xE4,
|
||||||
|
0x18, 0x44, 0xFF, 0x05, 0x8A, 0x58, 0x9D, 0x83, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x70, 0xE2, 0x4A, 0x12, 0x40,
|
||||||
|
0xD4, 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4F, 0xF0, 0x16, 0x29, 0x62, 0x76, 0x0E, 0x6D, 0xE5, 0xD5, 0x48,
|
||||||
|
0xAD, 0xE3, 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x08, 0xF8, 0x6E, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x96, 0x24,
|
||||||
|
0xD8, 0x3B, 0xA1, 0x41, 0xC2, 0xD2, 0xBA, 0x38, 0x90, 0xA1, 0x24, 0x35, 0x0C, 0xF0, 0x2F, 0x86, 0xE4, 0x60,
|
||||||
|
0x44, 0xFF, 0x05, 0x8A, 0x58, 0x9D, 0x83, 0x94, 0xC8, 0xFB, 0x02, 0x35, 0xA4, 0xE2, 0x4A, 0x12, 0x43, 0x50,
|
||||||
|
0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4F, 0xF0, 0x58, 0x29, 0x62, 0x76, 0x0E, 0xC0, 0x00, 0x00, 0x00, 0x0C,
|
||||||
|
0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x0B, 0xE1, 0xB8, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x96, 0x27, 0x60, 0xE4 };
|
||||||
|
|
||||||
|
unsigned char LDU2_1K[] = { 0x00,
|
||||||
|
0x55, 0x75, 0xF5, 0xFF, 0x77, 0xFF, 0x29, 0x3A, 0xB8, 0xA4, 0xEF, 0xB0, 0x9A, 0x8A, 0xCE, 0x24, 0xA1, 0x24,
|
||||||
|
0x0D, 0x43, 0x3C, 0x0B, 0xE1, 0xB9, 0x18, 0x44, 0xFC, 0xC1, 0x62, 0x96, 0x27, 0x60, 0xEC, 0xE2, 0x4A, 0x10,
|
||||||
|
0x90, 0xD4, 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4C, 0xFC, 0x16, 0x29, 0x62, 0x76, 0x0E, 0x40, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x03, 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x02, 0xF8, 0x6E, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x94,
|
||||||
|
0x89, 0xD8, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x24, 0xA1, 0x24, 0x35, 0x0C, 0xF0, 0x2F, 0x86, 0xE4,
|
||||||
|
0x18, 0x44, 0xFF, 0x05, 0x8A, 0x58, 0x9D, 0x83, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x4A, 0x12, 0x40,
|
||||||
|
0xD4, 0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4F, 0xF0, 0x16, 0x29, 0x62, 0x76, 0x0E, 0xE0, 0xE0, 0x00, 0x00,
|
||||||
|
0x00, 0x03, 0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x08, 0xF8, 0x6E, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x96, 0x24,
|
||||||
|
0xD8, 0x39, 0xAE, 0x8B, 0x48, 0xB6, 0x49, 0x38, 0x90, 0xA1, 0x24, 0x35, 0x0C, 0xF0, 0x2F, 0x86, 0xE4, 0x60,
|
||||||
|
0x44, 0xFF, 0x05, 0x8A, 0x58, 0x9D, 0x83, 0xB9, 0xA8, 0xF4, 0xF1, 0xFD, 0x60, 0xE2, 0x4A, 0x12, 0x43, 0x50,
|
||||||
|
0x33, 0xC0, 0xBE, 0x1B, 0x91, 0x84, 0x4F, 0xF0, 0x58, 0x29, 0x62, 0x76, 0x0E, 0x40, 0x00, 0x00, 0x00, 0x0C,
|
||||||
|
0x89, 0x28, 0x49, 0x0D, 0x43, 0x3C, 0x0B, 0xE1, 0xB8, 0x46, 0x11, 0x3F, 0xC1, 0x62, 0x96, 0x27, 0x60, 0xEC };
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the CalP25 class.
|
||||||
|
/// </summary>
|
||||||
|
CalP25::CalP25() :
|
||||||
|
m_transmit(false),
|
||||||
|
m_state(P25CAL1K_IDLE)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process local state and transmit on the air interface.
|
||||||
|
/// </summary>
|
||||||
|
void CalP25::process()
|
||||||
|
{
|
||||||
|
if (m_modemState == STATE_P25_CAL || m_modemState == STATE_P25_LF_CAL) {
|
||||||
|
m_state = P25CAL1K_IDLE;
|
||||||
|
|
||||||
|
if (m_transmit) {
|
||||||
|
p25TX.setCal(true);
|
||||||
|
p25TX.process();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p25TX.setCal(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p25TX.process();
|
||||||
|
|
||||||
|
uint16_t space = p25TX.getSpace();
|
||||||
|
if (space < 1U)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (m_state) {
|
||||||
|
case P25CAL1K_LDU1:
|
||||||
|
p25TX.writeData(LDU1_1K, P25_LDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
m_state = P25CAL1K_LDU2;
|
||||||
|
break;
|
||||||
|
case P25CAL1K_LDU2:
|
||||||
|
p25TX.writeData(LDU2_1K, P25_LDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
if (!m_transmit)
|
||||||
|
m_state = P25CAL1K_IDLE;
|
||||||
|
else
|
||||||
|
m_state = P25CAL1K_LDU1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_state = P25CAL1K_IDLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write P25 calibration data to the local buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t CalP25::write(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (length != 1U)
|
||||||
|
return RSN_ILLEGAL_LENGTH;
|
||||||
|
|
||||||
|
m_transmit = data[0U] == 1U;
|
||||||
|
|
||||||
|
if (m_transmit && m_state == P25CAL1K_IDLE)
|
||||||
|
m_state = P25CAL1K_LDU1;
|
||||||
|
|
||||||
|
if (m_transmit)
|
||||||
|
io.rf1Conf(STATE_P25, true);
|
||||||
|
|
||||||
|
return RSN_OK;
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__CAL_P25_H__)
|
||||||
|
#define __CAL_P25_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "p25/P25Defines.h"
|
||||||
|
|
||||||
|
namespace p25
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum P25CAL1K {
|
||||||
|
P25CAL1K_IDLE,
|
||||||
|
P25CAL1K_LDU1,
|
||||||
|
P25CAL1K_LDU2
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements logic for P25 calibration mode.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API CalP25 {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the CalP25 class.</summary>
|
||||||
|
CalP25();
|
||||||
|
|
||||||
|
/// <summary>Process local state and transmit on the air interface.</summary>
|
||||||
|
void process();
|
||||||
|
|
||||||
|
/// <summary>Write P25 calibration state.</summary>
|
||||||
|
uint8_t write(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_transmit;
|
||||||
|
P25CAL1K m_state;
|
||||||
|
};
|
||||||
|
} // namespace p25
|
||||||
|
|
||||||
|
#endif // __CAL_P25_H__
|
||||||
@ -0,0 +1,135 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2017-2018 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__P25_DEFINES_H__)
|
||||||
|
#define __P25_DEFINES_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
|
namespace p25
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint32_t P25_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
|
||||||
|
|
||||||
|
const uint32_t P25_HDU_FRAME_LENGTH_BYTES = 99U;
|
||||||
|
const uint32_t P25_HDU_FRAME_LENGTH_BITS = P25_HDU_FRAME_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t P25_HDU_FRAME_LENGTH_SYMBOLS = P25_HDU_FRAME_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t P25_HDU_FRAME_LENGTH_SAMPLES = P25_HDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t P25_TDU_FRAME_LENGTH_BYTES = 18U;
|
||||||
|
const uint32_t P25_TDU_FRAME_LENGTH_BITS = P25_TDU_FRAME_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t P25_TDU_FRAME_LENGTH_SYMBOLS = P25_TDU_FRAME_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t P25_TDU_FRAME_LENGTH_SAMPLES = P25_TDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t P25_LDU_FRAME_LENGTH_BYTES = 216U;
|
||||||
|
const uint32_t P25_LDU_FRAME_LENGTH_BITS = P25_LDU_FRAME_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t P25_LDU_FRAME_LENGTH_SYMBOLS = P25_LDU_FRAME_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t P25_LDU_FRAME_LENGTH_SAMPLES = P25_LDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t P25_TSDU_FRAME_LENGTH_BYTES = 45U;
|
||||||
|
const uint32_t P25_TSDU_FRAME_LENGTH_BITS = P25_TSDU_FRAME_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t P25_TSDU_FRAME_LENGTH_SYMBOLS = P25_TSDU_FRAME_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t P25_TSDU_FRAME_LENGTH_SAMPLES = P25_TSDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t P25_TDULC_FRAME_LENGTH_BYTES = 54U;
|
||||||
|
const uint32_t P25_TDULC_FRAME_LENGTH_BITS = P25_TDULC_FRAME_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t P25_TDULC_FRAME_LENGTH_SYMBOLS = P25_TDULC_FRAME_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t P25_TDULC_FRAME_LENGTH_SAMPLES = P25_TDULC_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t P25_SYNC_LENGTH_BYTES = 6U;
|
||||||
|
const uint32_t P25_SYNC_LENGTH_BITS = P25_SYNC_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t P25_SYNC_LENGTH_SYMBOLS = P25_SYNC_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t P25_SYNC_LENGTH_SAMPLES = P25_SYNC_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t P25_NID_LENGTH_BYTES = 2U;
|
||||||
|
const uint32_t P25_NID_LENGTH_BITS = P25_NID_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t P25_NID_LENGTH_SYMBOLS = P25_NID_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t P25_NID_LENGTH_SAMPLES = P25_NID_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint32_t P25_PDU_HDU_FRAME_LENGTH_BYTES = 39U;
|
||||||
|
const uint32_t P25_PDU_HDU_FRAME_LENGTH_BITS = P25_PDU_HDU_FRAME_LENGTH_BYTES * 8U;
|
||||||
|
const uint32_t P25_PDU_HDU_FRAME_LENGTH_SYMBOLS = P25_PDU_HDU_FRAME_LENGTH_BYTES * 4U;
|
||||||
|
const uint32_t P25_PDU_HDU_FRAME_LENGTH_SAMPLES = P25_PDU_HDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const uint8_t P25_SYNC_BYTES[] = { 0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU };
|
||||||
|
const uint8_t P25_SYNC_BYTES_LENGTH = 6U;
|
||||||
|
const uint8_t P25_START_SYNC = 0x5FU;
|
||||||
|
const uint8_t P25_NULL = 0x00U;
|
||||||
|
|
||||||
|
const uint8_t P25_TEST_PATTERN[] = { 0x55, 0xFF };
|
||||||
|
const uint8_t P25_TEST_PATTERN_LENGTH = 2U;
|
||||||
|
|
||||||
|
const ulong64_t P25_SYNC_BITS = 0x00005575F5FF77FFU;
|
||||||
|
const ulong64_t P25_SYNC_BITS_MASK = 0x0000FFFFFFFFFFFFU;
|
||||||
|
|
||||||
|
// 5 5 7 5 F 5 F F 7 7 F F
|
||||||
|
// 01 01 01 01 01 11 01 01 11 11 01 01 11 11 11 11 01 11 01 11 11 11 11 11
|
||||||
|
// +3 +3 +3 +3 +3 -3 +3 +3 -3 -3 +3 +3 -3 -3 -3 -3 +3 -3 +3 -3 -3 -3 -3 -3
|
||||||
|
|
||||||
|
const int8_t P25_SYNC_SYMBOLS_VALUES[] = { +3, +3, +3, +3, +3, -3, +3, +3, -3, -3, +3, +3, -3, -3, -3, -3, +3, -3, +3, -3, -3, -3, -3, -3 };
|
||||||
|
|
||||||
|
const uint32_t P25_SYNC_SYMBOLS = 0x00FB30A0U;
|
||||||
|
const uint32_t P25_SYNC_SYMBOLS_MASK = 0x00FFFFFFU;
|
||||||
|
|
||||||
|
const uint32_t P25_TX_BUFFER_LEN = 2000U;
|
||||||
|
|
||||||
|
// Data Unit ID(s)
|
||||||
|
const uint8_t P25_DUID_HDU = 0x00U; // Header Data Unit
|
||||||
|
const uint8_t P25_DUID_TDU = 0x03U; // Simple Terminator Data Unit
|
||||||
|
const uint8_t P25_DUID_LDU1 = 0x05U; // Logical Link Data Unit 1
|
||||||
|
const uint8_t P25_DUID_TSDU = 0x07U; // Trunking System Data Unit
|
||||||
|
const uint8_t P25_DUID_LDU2 = 0x0AU; // Logical Link Data Unit 2
|
||||||
|
const uint8_t P25_DUID_PDU = 0x0CU; // Packet Data Unit
|
||||||
|
const uint8_t P25_DUID_TDULC = 0x0FU; // Terminator Data Unit with Link Control
|
||||||
|
} // namespace p25
|
||||||
|
|
||||||
|
#endif // __P25_DEFINES_H__
|
||||||
@ -0,0 +1,572 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "p25/P25RX.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
using namespace p25;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint8_t MAX_SYNC_BYTES_START_ERRS = 2U;
|
||||||
|
const uint8_t MAX_SYNC_BYTES_ERRS = 4U;
|
||||||
|
|
||||||
|
const uint16_t MAX_SYNC_FRAMES = 7U;
|
||||||
|
|
||||||
|
const uint8_t CORRELATION_COUNTDOWN = 6U;
|
||||||
|
|
||||||
|
const uint16_t NOENDPTR = 9999U;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the P25RX class.
|
||||||
|
/// </summary>
|
||||||
|
P25RX::P25RX() :
|
||||||
|
m_bitBuffer(0x00U),
|
||||||
|
m_buffer(),
|
||||||
|
m_dataPtr(0U),
|
||||||
|
m_minSyncPtr(0U),
|
||||||
|
m_maxSyncPtr(NOENDPTR),
|
||||||
|
m_startPtr(0U),
|
||||||
|
m_endPtr(NOENDPTR),
|
||||||
|
m_syncPtr(0U),
|
||||||
|
m_lostCount(0U),
|
||||||
|
m_countdown(0U),
|
||||||
|
m_nac(0xF7EU),
|
||||||
|
m_corrCountdown(CORRELATION_COUNTDOWN),
|
||||||
|
m_state(P25RXS_NONE),
|
||||||
|
m_duid(0xFFU)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to reset data values to defaults.
|
||||||
|
/// </summary>
|
||||||
|
void P25RX::reset()
|
||||||
|
{
|
||||||
|
m_bitBuffer = 0x00U;
|
||||||
|
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
|
||||||
|
m_minSyncPtr = 0U;
|
||||||
|
m_maxSyncPtr = NOENDPTR;
|
||||||
|
|
||||||
|
m_startPtr = 0U;
|
||||||
|
m_endPtr = NOENDPTR;
|
||||||
|
m_syncPtr = 0U;
|
||||||
|
|
||||||
|
m_lostCount = 0U;
|
||||||
|
m_countdown = 0U;
|
||||||
|
|
||||||
|
m_state = P25RXS_NONE;
|
||||||
|
|
||||||
|
m_duid = 0xFFU;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sample P25 bits from the air interface.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit"></param>
|
||||||
|
void P25RX::databit(bool bit)
|
||||||
|
{
|
||||||
|
_WRITE_BIT(m_buffer, m_dataPtr, bit);
|
||||||
|
|
||||||
|
m_bitBuffer <<= 1;
|
||||||
|
if (bit)
|
||||||
|
m_bitBuffer |= 0x01U;
|
||||||
|
|
||||||
|
if (m_state == P25RXS_SYNC) {
|
||||||
|
processBit(bit);
|
||||||
|
}
|
||||||
|
else if (m_state == P25RXS_VOICE) {
|
||||||
|
processVoice(bit);
|
||||||
|
}
|
||||||
|
else if (m_state == P25RXS_DATA) {
|
||||||
|
processData(bit);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bool ret = correlateSync();
|
||||||
|
if (ret) {
|
||||||
|
// on the first sync, start the countdown to the state change
|
||||||
|
if (m_countdown == 0U) {
|
||||||
|
io.setDecode(true);
|
||||||
|
|
||||||
|
m_countdown = m_corrCountdown;
|
||||||
|
DEBUG2("P25RX: databit(): correlation countdown", m_countdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_countdown > 0U)
|
||||||
|
m_countdown--;
|
||||||
|
|
||||||
|
if (m_countdown == 1U) {
|
||||||
|
m_minSyncPtr = m_syncPtr + P25_HDU_FRAME_LENGTH_BITS - 1U;
|
||||||
|
if (m_minSyncPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_minSyncPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_maxSyncPtr = m_syncPtr + P25_HDU_FRAME_LENGTH_BITS + 1U;
|
||||||
|
if (m_maxSyncPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_maxSyncPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_state = P25RXS_SYNC;
|
||||||
|
m_countdown = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dataPtr++;
|
||||||
|
if (m_dataPtr >= P25_LDU_FRAME_LENGTH_BITS) {
|
||||||
|
m_duid = 0xFFU;
|
||||||
|
m_dataPtr = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the P25 NAC.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nac">NAC.</param>
|
||||||
|
void P25RX::setNAC(uint16_t nac)
|
||||||
|
{
|
||||||
|
m_nac = nac;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the P25 sync correlation countdown.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">Correlation Countdown Count.</param>
|
||||||
|
void P25RX::setCorrCount(uint8_t count)
|
||||||
|
{
|
||||||
|
m_corrCountdown = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to process P25 samples.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit"></param>
|
||||||
|
void P25RX::processBit(bool bit)
|
||||||
|
{
|
||||||
|
if (m_minSyncPtr < m_maxSyncPtr) {
|
||||||
|
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// initial sample processing does not have an end pointer -- we simply wait till we've read
|
||||||
|
// the bits up to the maximum sync pointer
|
||||||
|
if (m_dataPtr == m_maxSyncPtr) {
|
||||||
|
DEBUG4("P25RX: processBit(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_maxSyncPtr);
|
||||||
|
DEBUG4("P25RX: processBit(): lostCount/maxSyncPtr/minSyncPtr", m_lostCount, m_maxSyncPtr, m_minSyncPtr);
|
||||||
|
|
||||||
|
if (!decodeNid(m_startPtr)) {
|
||||||
|
io.setDecode(false);
|
||||||
|
|
||||||
|
serial.writeP25Lost();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (m_duid) {
|
||||||
|
case P25_DUID_HDU:
|
||||||
|
{
|
||||||
|
DEBUG1("P25RX: processBit(): sync found in HDU pos", m_syncPtr);
|
||||||
|
|
||||||
|
uint8_t frame[P25_HDU_FRAME_LENGTH_BYTES + 1U];
|
||||||
|
bitsToBytes(m_startPtr + P25_NID_LENGTH_BITS, P25_HDU_FRAME_LENGTH_BITS, frame);
|
||||||
|
|
||||||
|
frame[0U] = 0x01U;
|
||||||
|
serial.writeP25Data(frame, P25_HDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case P25_DUID_TDU:
|
||||||
|
{
|
||||||
|
DEBUG1("P25RX: processBit(): sync found in TDU pos", m_syncPtr);
|
||||||
|
|
||||||
|
uint8_t frame[P25_TDU_FRAME_LENGTH_BYTES + 1U];
|
||||||
|
bitsToBytes(m_startPtr + P25_NID_LENGTH_BITS, P25_TDU_FRAME_LENGTH_BITS, frame);
|
||||||
|
|
||||||
|
frame[0U] = 0x01U;
|
||||||
|
serial.writeP25Data(frame, P25_TDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case P25_DUID_LDU1:
|
||||||
|
m_state = P25RXS_VOICE;
|
||||||
|
return;
|
||||||
|
case P25_DUID_TSDU:
|
||||||
|
{
|
||||||
|
DEBUG1("P25RX: processBit(): sync found in TSDU pos", m_syncPtr);
|
||||||
|
|
||||||
|
uint8_t frame[P25_TSDU_FRAME_LENGTH_BYTES + 1U];
|
||||||
|
bitsToBytes(m_startPtr + P25_NID_LENGTH_BITS, P25_TSDU_FRAME_LENGTH_BITS, frame);
|
||||||
|
|
||||||
|
frame[0U] = 0x01U;
|
||||||
|
serial.writeP25Data(frame, P25_TSDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case P25_DUID_LDU2:
|
||||||
|
m_state = P25RXS_VOICE;
|
||||||
|
return;
|
||||||
|
case P25_DUID_PDU:
|
||||||
|
m_state = P25RXS_DATA;
|
||||||
|
return;
|
||||||
|
case P25_DUID_TDULC:
|
||||||
|
{
|
||||||
|
DEBUG1("P25RX: processBit(): sync found in TDULC pos", m_syncPtr);
|
||||||
|
|
||||||
|
uint8_t frame[P25_TDULC_FRAME_LENGTH_BYTES + 1U];
|
||||||
|
bitsToBytes(m_startPtr + P25_NID_LENGTH_BITS, P25_TDULC_FRAME_LENGTH_BITS, frame);
|
||||||
|
|
||||||
|
frame[0U] = 0x01U;
|
||||||
|
serial.writeP25Data(frame, P25_TDULC_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
DEBUG3("P25RX: processBit(): illegal DUID in NID", m_nac, m_duid);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_minSyncPtr = m_syncPtr + P25_LDU_FRAME_LENGTH_BITS - 1U;
|
||||||
|
if (m_minSyncPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_minSyncPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_maxSyncPtr = m_syncPtr + 1U;
|
||||||
|
if (m_maxSyncPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_maxSyncPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_lostCount = MAX_SYNC_FRAMES;
|
||||||
|
|
||||||
|
if (m_state == P25RXS_VOICE) {
|
||||||
|
processVoice(bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == P25RXS_DATA) {
|
||||||
|
processData(bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to process LDU P25 bits.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit"></param>
|
||||||
|
void P25RX::processVoice(bool bit)
|
||||||
|
{
|
||||||
|
if (m_minSyncPtr < m_maxSyncPtr) {
|
||||||
|
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dataPtr == m_endPtr) {
|
||||||
|
if (m_lostCount == MAX_SYNC_FRAMES) {
|
||||||
|
m_minSyncPtr = m_syncPtr + P25_LDU_FRAME_LENGTH_BITS - 1U;
|
||||||
|
if (m_minSyncPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_minSyncPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_maxSyncPtr = m_syncPtr + 1U;
|
||||||
|
if (m_maxSyncPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_maxSyncPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lostCount--;
|
||||||
|
|
||||||
|
DEBUG4("P25RX: processVoice(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
|
||||||
|
DEBUG4("P25RX: processVoice(): lostCount/maxSyncPtr/minSyncPtr", m_lostCount, m_maxSyncPtr, m_minSyncPtr);
|
||||||
|
|
||||||
|
// we've not seen a data sync for too long, signal sync lost and change to P25RXS_NONE
|
||||||
|
if (m_lostCount == 0U) {
|
||||||
|
DEBUG1("P25RX: processVoice(): sync timeout in LDU, lost lock");
|
||||||
|
|
||||||
|
io.setDecode(false);
|
||||||
|
|
||||||
|
serial.writeP25Lost();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!decodeNid(m_startPtr)) {
|
||||||
|
io.setDecode(false);
|
||||||
|
|
||||||
|
serial.writeP25Lost();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_duid == P25_DUID_TDU) {
|
||||||
|
DEBUG1("P25RX: processBit(): sync found in TDU pos", m_syncPtr);
|
||||||
|
|
||||||
|
uint8_t frame[P25_TDU_FRAME_LENGTH_BYTES + 1U];
|
||||||
|
bitsToBytes(m_startPtr + P25_NID_LENGTH_BITS, P25_TDU_FRAME_LENGTH_BITS, frame);
|
||||||
|
|
||||||
|
frame[0U] = 0x01U;
|
||||||
|
serial.writeP25Data(frame, P25_TDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
|
||||||
|
io.setDecode(false);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG1("P25RX: processVoice(): sync found in LDU pos", m_syncPtr);
|
||||||
|
|
||||||
|
uint8_t frame[P25_LDU_FRAME_LENGTH_BYTES + 3U];
|
||||||
|
bitsToBytes(m_startPtr + P25_NID_LENGTH_BITS, P25_LDU_FRAME_LENGTH_BITS, frame);
|
||||||
|
|
||||||
|
frame[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U;
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
if (m_rssiCount > 0U) {
|
||||||
|
uint16_t rssi = m_rssiAccum / m_rssiCount;
|
||||||
|
frame[217U] = (rssi >> 8) & 0xFFU;
|
||||||
|
frame[218U] = (rssi >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
serial.writeP25Data(false, frame, P25_LDU_FRAME_LENGTH_BYTES + 3U);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
serial.writeP25Data(false, frame, P25_LDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
serial.writeP25Data(frame, P25_LDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to process PDU P25 bits.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bit"></param>
|
||||||
|
void P25RX::processData(bool bit)
|
||||||
|
{
|
||||||
|
if (m_minSyncPtr < m_maxSyncPtr) {
|
||||||
|
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr)
|
||||||
|
correlateSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dataPtr == m_endPtr) {
|
||||||
|
if (m_lostCount == MAX_SYNC_FRAMES) {
|
||||||
|
m_minSyncPtr = m_syncPtr + P25_LDU_FRAME_LENGTH_BITS - 1U;
|
||||||
|
if (m_minSyncPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_minSyncPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_maxSyncPtr = m_syncPtr + 1U;
|
||||||
|
if (m_maxSyncPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_maxSyncPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lostCount--;
|
||||||
|
|
||||||
|
DEBUG4("P25RX: processData(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
|
||||||
|
DEBUG4("P25RX: processData(): lostCount/maxSyncPtr/minSyncPtr", m_lostCount, m_maxSyncPtr, m_minSyncPtr);
|
||||||
|
|
||||||
|
// we've not seen a data sync for too long, signal sync lost and change to P25RXS_NONE
|
||||||
|
if (m_lostCount == 0U) {
|
||||||
|
DEBUG1("P25RX: processData(): sync timeout in PDU, lost lock");
|
||||||
|
|
||||||
|
io.setDecode(false);
|
||||||
|
|
||||||
|
serial.writeP25Lost();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!decodeNid(m_startPtr)) {
|
||||||
|
io.setDecode(false);
|
||||||
|
|
||||||
|
serial.writeP25Lost();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG1("P25RX: processVoice(): sync found in PDU pos", m_syncPtr);
|
||||||
|
|
||||||
|
uint8_t frame[P25_LDU_FRAME_LENGTH_BYTES + 3U];
|
||||||
|
bitsToBytes(m_startPtr + P25_NID_LENGTH_BITS, P25_LDU_FRAME_LENGTH_BITS, frame);
|
||||||
|
|
||||||
|
frame[0U] = m_lostCount == (MAX_SYNC_FRAMES - 1U) ? 0x01U : 0x00U;
|
||||||
|
#if defined(SEND_RSSI_DATA)
|
||||||
|
if (m_rssiCount > 0U) {
|
||||||
|
uint16_t rssi = m_rssiAccum / m_rssiCount;
|
||||||
|
frame[217U] = (rssi >> 8) & 0xFFU;
|
||||||
|
frame[218U] = (rssi >> 0) & 0xFFU;
|
||||||
|
|
||||||
|
serial.writeP25Data(false, frame, P25_LDU_FRAME_LENGTH_BYTES + 3U);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
serial.writeP25Data(false, frame, P25_LDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
serial.writeP25Data(frame, P25_LDU_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Frame synchronization correlator.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool P25RX::correlateSync()
|
||||||
|
{
|
||||||
|
uint8_t maxErrs;
|
||||||
|
if (m_state == P25RXS_NONE)
|
||||||
|
maxErrs = MAX_SYNC_BYTES_START_ERRS;
|
||||||
|
else
|
||||||
|
maxErrs = MAX_SYNC_BYTES_ERRS;
|
||||||
|
|
||||||
|
uint8_t errs = countBits64((m_bitBuffer & P25_SYNC_BITS_MASK) ^ P25_SYNC_BITS);
|
||||||
|
if (errs <= maxErrs) {
|
||||||
|
DEBUG2("P25RX: correlateSync(): correlateSync errs", errs);
|
||||||
|
|
||||||
|
m_syncPtr = m_dataPtr;
|
||||||
|
|
||||||
|
m_startPtr = m_dataPtr + P25_LDU_FRAME_LENGTH_BITS - P25_SYNC_LENGTH_BITS + 1;
|
||||||
|
if (m_startPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_startPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_endPtr = m_dataPtr + P25_LDU_FRAME_LENGTH_BITS - P25_SYNC_LENGTH_BITS - 1U;
|
||||||
|
if (m_endPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
m_endPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
m_lostCount = MAX_SYNC_FRAMES;
|
||||||
|
|
||||||
|
DEBUG4("P25RX: correlateSync(): dataPtr/startPtr/endPtr", m_dataPtr, m_startPtr, m_endPtr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to decode the P25 NID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
bool P25RX::decodeNid(uint16_t start)
|
||||||
|
{
|
||||||
|
uint16_t nidStartPtr = start + P25_SYNC_LENGTH_BITS;
|
||||||
|
if (nidStartPtr >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
nidStartPtr -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
uint8_t nid[P25_NID_LENGTH_BYTES];
|
||||||
|
bitsToBytes(m_startPtr, P25_NID_LENGTH_BITS, nid);
|
||||||
|
|
||||||
|
if (m_nac == 0xF7EU) {
|
||||||
|
m_duid = nid[1U] & 0x0FU;
|
||||||
|
DEBUG2("P25RX: decodeNid(): DUID for xDU", m_duid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t nac = (nid[0U] << 4) | ((nid[1U] & 0xF0U) >> 4);
|
||||||
|
if (nac == m_nac) {
|
||||||
|
m_duid = nid[1U] & 0x0FU;
|
||||||
|
DEBUG2("P25RX: decodeNid(): DUID for xDU", m_duid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG3("P25RX: decodeNid(): invalid NAC found; nac != m_nac", nac, m_nac);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
/// <param name="count"></param>
|
||||||
|
/// <param name="buffer"></param>
|
||||||
|
void P25RX::bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0U; i < count; i++) {
|
||||||
|
buffer[i] = 0U;
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 7;
|
||||||
|
start++;
|
||||||
|
if (start >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
start -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 6;
|
||||||
|
start++;
|
||||||
|
if (start >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
start -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 5;
|
||||||
|
start++;
|
||||||
|
if (start >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
start -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 4;
|
||||||
|
start++;
|
||||||
|
if (start >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
start -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 3;
|
||||||
|
start++;
|
||||||
|
if (start >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
start -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 2;
|
||||||
|
start++;
|
||||||
|
if (start >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
start -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 1;
|
||||||
|
start++;
|
||||||
|
if (start >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
start -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
buffer[i] |= _READ_BIT(m_buffer, start) << 0;
|
||||||
|
start++;
|
||||||
|
if (start >= P25_LDU_FRAME_LENGTH_BITS)
|
||||||
|
start -= P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016,2017,2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__P25_RX_H__)
|
||||||
|
#define __P25_RX_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "p25/P25Defines.h"
|
||||||
|
|
||||||
|
namespace p25
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum P25RX_STATE {
|
||||||
|
P25RXS_NONE,
|
||||||
|
P25RXS_SYNC,
|
||||||
|
P25RXS_VOICE,
|
||||||
|
P25RXS_DATA
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements receiver logic for P25 mode operation.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API P25RX {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the P25RX class.</summary>
|
||||||
|
P25RX();
|
||||||
|
|
||||||
|
/// <summary>Helper to reset data values to defaults.</summary>
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/// <summary>Sample P25 bits from the air interface.</summary>
|
||||||
|
void databit(bool bit);
|
||||||
|
|
||||||
|
/// <summary>Sets the P25 NAC.</summary>
|
||||||
|
void setNAC(uint16_t nac);
|
||||||
|
/// <summary>Sets the P25 sync correlation countdown.</summary>
|
||||||
|
void setCorrCount(uint8_t count);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t m_bitBuffer;
|
||||||
|
uint8_t m_buffer[P25_LDU_FRAME_LENGTH_BITS / 8U + 3U];
|
||||||
|
|
||||||
|
uint16_t m_dataPtr;
|
||||||
|
|
||||||
|
uint16_t m_minSyncPtr;
|
||||||
|
uint16_t m_maxSyncPtr;
|
||||||
|
|
||||||
|
uint16_t m_startPtr;
|
||||||
|
uint16_t m_endPtr;
|
||||||
|
uint16_t m_syncPtr;
|
||||||
|
|
||||||
|
uint16_t m_lostCount;
|
||||||
|
uint8_t m_countdown;
|
||||||
|
|
||||||
|
uint16_t m_nac;
|
||||||
|
|
||||||
|
uint8_t m_corrCountdown;
|
||||||
|
|
||||||
|
P25RX_STATE m_state;
|
||||||
|
|
||||||
|
uint8_t m_duid;
|
||||||
|
|
||||||
|
/// <summary>Helper to process P25 bits.</summary>
|
||||||
|
void processBit(bool bit);
|
||||||
|
/// <summary>Helper to process LDU P25 bits.</summary>
|
||||||
|
void processVoice(bool bit);
|
||||||
|
/// <summary>Helper to process PDU P25 bits.</summary>
|
||||||
|
void processData(bool bit);
|
||||||
|
|
||||||
|
/// <summary>Frame synchronization correlator.</summary>
|
||||||
|
bool correlateSync();
|
||||||
|
|
||||||
|
/// <summary>Helper to decode the P25 NID.</summary>
|
||||||
|
bool decodeNid(uint16_t start);
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void bitsToBytes(uint16_t start, uint8_t count, uint8_t* buffer);
|
||||||
|
};
|
||||||
|
} // namespace p25
|
||||||
|
|
||||||
|
#endif // __P25_RX_H__
|
||||||
@ -0,0 +1,279 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016,2017 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "p25/P25TX.h"
|
||||||
|
#include "p25/P25Defines.h"
|
||||||
|
|
||||||
|
using namespace p25;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Public Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the P25TX class.
|
||||||
|
/// </summary>
|
||||||
|
P25TX::P25TX() :
|
||||||
|
m_fifo(P25_TX_BUFFER_LEN),
|
||||||
|
m_state(P25TXSTATE_NORMAL),
|
||||||
|
m_poBuffer(),
|
||||||
|
m_poLen(0U),
|
||||||
|
m_poPtr(0U),
|
||||||
|
m_preambleCnt(P25_FIXED_DELAY),
|
||||||
|
m_tailCnt(0U)
|
||||||
|
{
|
||||||
|
/* stub */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process local buffer and transmit on the air interface.
|
||||||
|
/// </summary>
|
||||||
|
void P25TX::process()
|
||||||
|
{
|
||||||
|
if (m_fifo.getData() == 0U && m_poLen == 0U && m_tailCnt > 0U &&
|
||||||
|
m_state != P25TXSTATE_CAL) {
|
||||||
|
// transmit silence until the hang timer has expired
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > 8U) {
|
||||||
|
writeByte(P25_START_SYNC);
|
||||||
|
|
||||||
|
space -= 8U;
|
||||||
|
m_tailCnt--;
|
||||||
|
|
||||||
|
if (m_tailCnt == 0U)
|
||||||
|
return;
|
||||||
|
if (m_fifo.getData() > 0U) {
|
||||||
|
m_tailCnt = 0U;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_fifo.getData() == 0U && m_poLen == 0U)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_poLen == 0U) {
|
||||||
|
if (m_state == P25TXSTATE_CAL) {
|
||||||
|
m_tailCnt = 0U;
|
||||||
|
createCal();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_fifo.getData() == 0U)
|
||||||
|
return;
|
||||||
|
|
||||||
|
createData();
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG2("P25TX: process(): poLen", m_poLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_poLen > 0U) {
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > 8U) {
|
||||||
|
uint8_t c = m_poBuffer[m_poPtr++];
|
||||||
|
|
||||||
|
writeByte(c);
|
||||||
|
|
||||||
|
space -= 8U;
|
||||||
|
m_tailCnt = P25_FIXED_TAIL;
|
||||||
|
|
||||||
|
if (m_poPtr >= m_poLen) {
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_poLen = 0U;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write data to the local buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t P25TX::writeData(const uint8_t* data, uint8_t length)
|
||||||
|
{
|
||||||
|
if (length < (P25_TDU_FRAME_LENGTH_BYTES + 1U))
|
||||||
|
return RSN_ILLEGAL_LENGTH;
|
||||||
|
|
||||||
|
uint16_t space = m_fifo.getSpace();
|
||||||
|
DEBUG3("P25TX: writeData(): dataLength/fifoLength", length, space);
|
||||||
|
if (space < length) {
|
||||||
|
m_fifo.reset();
|
||||||
|
return RSN_RINGBUFF_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fifo.put(length - 1U);
|
||||||
|
for (uint8_t i = 0U; i < (length - 1U); i++)
|
||||||
|
m_fifo.put(data[i + 1U]);
|
||||||
|
|
||||||
|
return RSN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the local buffer.
|
||||||
|
/// </summary>
|
||||||
|
void P25TX::clear()
|
||||||
|
{
|
||||||
|
m_fifo.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the FDMA preamble count.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="preambleCnt">Count of preambles.</param>
|
||||||
|
void P25TX::setPreambleCount(uint8_t preambleCnt)
|
||||||
|
{
|
||||||
|
uint32_t preambles = (uint32_t)((float)preambleCnt / 0.2083F);
|
||||||
|
m_preambleCnt = P25_FIXED_DELAY + preambles;
|
||||||
|
|
||||||
|
// clamp preamble count to 250ms maximum
|
||||||
|
if (m_preambleCnt > 1200U)
|
||||||
|
m_preambleCnt = 1200U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the fine adjust 4FSK symbol levels.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level3Adj">+3/-3 symbol adjust.</param>
|
||||||
|
/// <param name="level1Adj">+1/-1 symbol adjust.</param>
|
||||||
|
void P25TX::setSymbolLvlAdj(int8_t level3Adj, int8_t level1Adj)
|
||||||
|
{
|
||||||
|
/* ignored ADF7021 doesn't allow direct symbol level adjustments */
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to set the calibration state for Tx.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="start"></param>
|
||||||
|
void P25TX::setCal(bool start)
|
||||||
|
{
|
||||||
|
m_state = start ? P25TXSTATE_CAL : P25TXSTATE_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper to get how much space the ring buffer has for samples.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
uint8_t P25TX::getSpace() const
|
||||||
|
{
|
||||||
|
return m_fifo.getSpace() / P25_LDU_FRAME_LENGTH_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private Class Members
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void P25TX::createData()
|
||||||
|
{
|
||||||
|
if (!m_tx) {
|
||||||
|
for (uint16_t i = 0U; i < m_preambleCnt; i++)
|
||||||
|
m_poBuffer[m_poLen++] = P25_START_SYNC;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint8_t length = m_fifo.get();
|
||||||
|
DEBUG3("P25TX: createData(): dataLength/fifoSpace", length, m_fifo.getSpace());
|
||||||
|
for (uint8_t i = 0U; i < length; i++) {
|
||||||
|
m_poBuffer[m_poLen++] = m_fifo.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void P25TX::createCal()
|
||||||
|
{
|
||||||
|
// 1.2 kHz sine wave generation
|
||||||
|
if (m_modemState == STATE_P25_CAL) {
|
||||||
|
for (unsigned int i = 0U; i < P25_LDU_FRAME_LENGTH_BYTES; i++) {
|
||||||
|
m_poBuffer[i] = P25_START_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poLen = P25_LDU_FRAME_LENGTH_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 80 Hz square wave generation
|
||||||
|
if (m_modemState == STATE_P25_LF_CAL) {
|
||||||
|
for (unsigned int i = 0U; i < 108U; i++) {
|
||||||
|
m_poBuffer[i] = 0x55U; // +3, +3, ... pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poBuffer[109U] = 0x5FU; // +3, +3, -3, -3 pattern
|
||||||
|
|
||||||
|
for (unsigned int i = 110U; i < 216U; i++) {
|
||||||
|
m_poBuffer[i] = 0xFFU; // -3, -3, ... pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poLen = P25_LDU_FRAME_LENGTH_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_poLen = P25_LDU_FRAME_LENGTH_BYTES;
|
||||||
|
m_poPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c"></param>
|
||||||
|
void P25TX::writeByte(uint8_t c)
|
||||||
|
{
|
||||||
|
uint8_t bit;
|
||||||
|
uint8_t mask = 0x80U;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < 8U; i++, c <<= 1) {
|
||||||
|
if ((c & mask) == mask)
|
||||||
|
bit = 1U;
|
||||||
|
else
|
||||||
|
bit = 0U;
|
||||||
|
|
||||||
|
io.write(&bit, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
void P25TX::writeSilence()
|
||||||
|
{
|
||||||
|
uint8_t bit;
|
||||||
|
for (uint8_t i = 0U; i < 4U; i++) {
|
||||||
|
bit = 0U;
|
||||||
|
io.write(&bit, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* Digital Voice Modem - DSP Firmware (Hotspot)
|
||||||
|
* GPLv2 Open Source. Use is subject to license terms.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* @package DVM / DSP Firmware (Hotspot)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//
|
||||||
|
// Based on code from the MMDVM_HS project. (https://github.com/juribeparada/MMDVM_HS)
|
||||||
|
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016,2017 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2021 by Bryan Biedenkapp N2PLL
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#if !defined(__P25_TX_H__)
|
||||||
|
#define __P25_TX_H__
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "SerialBuffer.h"
|
||||||
|
|
||||||
|
namespace p25
|
||||||
|
{
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define P25_FIXED_DELAY 300 // 300 = 62.49ms
|
||||||
|
// Delay Value * 0.2083 = Preamble Length (ms)
|
||||||
|
#define P25_FIXED_TAIL 600 // 600 = 500ms
|
||||||
|
|
||||||
|
enum P25TXSTATE {
|
||||||
|
P25TXSTATE_NORMAL,
|
||||||
|
P25TXSTATE_CAL
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Class Declaration
|
||||||
|
// Implements transmitter logic for P25 mode operation.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DSP_FW_API P25TX {
|
||||||
|
public:
|
||||||
|
/// <summary>Initializes a new instance of the P25TX class.</summary>
|
||||||
|
P25TX();
|
||||||
|
|
||||||
|
/// <summary>Process local buffer and transmit on the air interface.</summary>
|
||||||
|
void process();
|
||||||
|
|
||||||
|
/// <summary>Write data to the local buffer.</summary>
|
||||||
|
uint8_t writeData(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
/// <summary>Clears the local buffer.</summary>
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/// <summary>Sets the FDMA preamble count.</summary>
|
||||||
|
void setPreambleCount(uint8_t preambleCnt);
|
||||||
|
/// <summary>Sets the fine adjust 4FSK symbol levels.</summary>
|
||||||
|
void setSymbolLvlAdj(int8_t level3Adj, int8_t level1Adj);
|
||||||
|
/// <summary>Helper to set the calibration state for Tx.</summary>
|
||||||
|
void setCal(bool start);
|
||||||
|
|
||||||
|
/// <summary>Helper to get how much space the ring buffer has for samples.</summary>
|
||||||
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SerialBuffer m_fifo;
|
||||||
|
|
||||||
|
P25TXSTATE m_state;
|
||||||
|
|
||||||
|
uint8_t m_poBuffer[1200U];
|
||||||
|
uint16_t m_poLen;
|
||||||
|
uint16_t m_poPtr;
|
||||||
|
|
||||||
|
uint16_t m_preambleCnt;
|
||||||
|
uint16_t m_tailCnt;
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void createData();
|
||||||
|
/// <summary></summary>
|
||||||
|
void createCal();
|
||||||
|
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeByte(uint8_t c);
|
||||||
|
/// <summary></summary>
|
||||||
|
void writeSilence();
|
||||||
|
};
|
||||||
|
} // namespace p25
|
||||||
|
|
||||||
|
#endif // __P25_TX_H__
|
||||||
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Required amount of heap and stack */
|
||||||
|
_min_heap_size = 0x1000;
|
||||||
|
_min_stack_size = 0x0800;
|
||||||
|
|
||||||
|
/* The entry point in the interrupt vector table */
|
||||||
|
ENTRY(Reset_Handler)
|
||||||
|
|
||||||
|
/* Stack start address (end of 20K RAM) */
|
||||||
|
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
/* The interrupt vector table */
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.isr_vector .isr_vector.*))
|
||||||
|
|
||||||
|
/* The program code */
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.text .text*)
|
||||||
|
*(.rodata .rodata*)
|
||||||
|
|
||||||
|
/* ARM-Thumb code */
|
||||||
|
*(.glue_7) *(.glue_7t)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.init))
|
||||||
|
KEEP(*(.fini))
|
||||||
|
|
||||||
|
/* EABI C++ global constructors support */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__preinit_array_start = .;
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
__preinit_array_end = .;
|
||||||
|
|
||||||
|
/* EABI C++ global constructors support */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__init_array_start = .;
|
||||||
|
KEEP (*(SORT(.init_array.*)))
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
__init_array_end = .;
|
||||||
|
|
||||||
|
/* EABI C++ global constructors support */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__fini_array_start = .;
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
KEEP (*(SORT(.fini_array.*)))
|
||||||
|
__fini_array_end = .;
|
||||||
|
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
/* ARM sections containing exception unwinding information */
|
||||||
|
.ARM.extab : {
|
||||||
|
__extab_start = .;
|
||||||
|
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||||
|
__extab_end = .;
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
/* ARM index entries for section unwinding */
|
||||||
|
.ARM.exidx : {
|
||||||
|
__exidx_start = .;
|
||||||
|
*(.ARM.exidx*)
|
||||||
|
__exidx_end = .;
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
/* Start address for the initialization values of the .data section */
|
||||||
|
_sidata = .;
|
||||||
|
|
||||||
|
/* The .data section (initialized data) */
|
||||||
|
.data : AT ( _sidata )
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sdata = . ; /* Start address for the .data section */
|
||||||
|
*(.data .data*)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
_edata = . ; /* End address for the .data section */
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* The .bss section (uninitialized data) */
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sbss = .; /* Start address for the .bss section */
|
||||||
|
__bss_start__ = _sbss;
|
||||||
|
*(.bss)
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = . ; /* End address for the .bss section */
|
||||||
|
__bss_end__ = _ebss;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* Space for heap and stack */
|
||||||
|
.heap_stack :
|
||||||
|
{
|
||||||
|
end = . ; /* 'end' symbol defines heap location */
|
||||||
|
_end = end ;
|
||||||
|
. = . + _min_heap_size; /* Additional space for heap and stack */
|
||||||
|
. = . + _min_stack_size;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* Remove information from the standard libraries */
|
||||||
|
/DISCARD/ :
|
||||||
|
{
|
||||||
|
libc.a ( * )
|
||||||
|
libm.a ( * )
|
||||||
|
libgcc.a ( * )
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Required amount of heap and stack */
|
||||||
|
_min_heap_size = 0x1000;
|
||||||
|
_min_stack_size = 0x0800;
|
||||||
|
|
||||||
|
/* The entry point in the interrupt vector table */
|
||||||
|
ENTRY(Reset_Handler)
|
||||||
|
|
||||||
|
/* Memory areas */
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ROM (rx) : ORIGIN = 0x08000000, LENGTH = 1024K /* FLASH */
|
||||||
|
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K /* Core Coupled Memory (CPU only access) */
|
||||||
|
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* Main RAM (bus matrix)*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stack start address (end of 128K RAM) */
|
||||||
|
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
/* The interrupt vector table */
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.isr_vector .isr_vector.*))
|
||||||
|
|
||||||
|
/* The program code */
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.text .text*)
|
||||||
|
*(.rodata .rodata*)
|
||||||
|
|
||||||
|
/* ARM-Thumb code */
|
||||||
|
*(.glue_7) *(.glue_7t)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.init))
|
||||||
|
KEEP(*(.fini))
|
||||||
|
|
||||||
|
/* EABI C++ global constructors support */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__preinit_array_start = .;
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
__preinit_array_end = .;
|
||||||
|
|
||||||
|
/* EABI C++ global constructors support */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__init_array_start = .;
|
||||||
|
KEEP (*(SORT(.init_array.*)))
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
__init_array_end = .;
|
||||||
|
|
||||||
|
/* EABI C++ global constructors support */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__fini_array_start = .;
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
KEEP (*(SORT(.fini_array.*)))
|
||||||
|
__fini_array_end = .;
|
||||||
|
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
/* ARM sections containing exception unwinding information */
|
||||||
|
.ARM.extab : {
|
||||||
|
__extab_start = .;
|
||||||
|
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||||
|
__extab_end = .;
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
/* ARM index entries for section unwinding */
|
||||||
|
.ARM.exidx : {
|
||||||
|
__exidx_start = .;
|
||||||
|
*(.ARM.exidx*)
|
||||||
|
__exidx_end = .;
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
/* Start address for the initialization values of the .data section */
|
||||||
|
_sidata = .;
|
||||||
|
|
||||||
|
/* The .data section (initialized data) */
|
||||||
|
.data : AT ( _sidata )
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sdata = . ; /* Start address for the .data section */
|
||||||
|
*(.data .data*)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
_edata = . ; /* End address for the .data section */
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* The .bss section (uninitialized data) */
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sbss = .; /* Start address for the .bss section */
|
||||||
|
__bss_start__ = _sbss;
|
||||||
|
*(.bss)
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = . ; /* End address for the .bss section */
|
||||||
|
__bss_end__ = _ebss;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* Space for heap and stack */
|
||||||
|
.heap_stack :
|
||||||
|
{
|
||||||
|
end = . ; /* 'end' symbol defines heap location */
|
||||||
|
_end = end ;
|
||||||
|
. = . + _min_heap_size; /* Additional space for heap and stack */
|
||||||
|
. = . + _min_stack_size;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* Remove information from the standard libraries */
|
||||||
|
/DISCARD/ :
|
||||||
|
{
|
||||||
|
libc.a ( * )
|
||||||
|
libm.a ( * )
|
||||||
|
libgcc.a ( * )
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Required amount of heap and stack */
|
||||||
|
_min_heap_size = 0x1000;
|
||||||
|
_min_stack_size = 0x0800;
|
||||||
|
|
||||||
|
/* The entry point in the interrupt vector table */
|
||||||
|
ENTRY(Reset_Handler)
|
||||||
|
|
||||||
|
/* Memory areas */
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ROM (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* FLASH */
|
||||||
|
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K /* Main RAM */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stack start address (end of 512K RAM) */
|
||||||
|
_estack = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
/* The interrupt vector table */
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.isr_vector .isr_vector.*))
|
||||||
|
|
||||||
|
/* The program code */
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.text .text*)
|
||||||
|
*(.rodata .rodata*)
|
||||||
|
|
||||||
|
/* ARM-Thumb code */
|
||||||
|
*(.glue_7) *(.glue_7t)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
KEEP(*(.init))
|
||||||
|
KEEP(*(.fini))
|
||||||
|
|
||||||
|
/* EABI C++ global constructors support */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__preinit_array_start = .;
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
__preinit_array_end = .;
|
||||||
|
|
||||||
|
/* EABI C++ global constructors support */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__init_array_start = .;
|
||||||
|
KEEP (*(SORT(.init_array.*)))
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
__init_array_end = .;
|
||||||
|
|
||||||
|
/* EABI C++ global constructors support */
|
||||||
|
. = ALIGN(4);
|
||||||
|
__fini_array_start = .;
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
KEEP (*(SORT(.fini_array.*)))
|
||||||
|
__fini_array_end = .;
|
||||||
|
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
/* ARM sections containing exception unwinding information */
|
||||||
|
.ARM.extab : {
|
||||||
|
__extab_start = .;
|
||||||
|
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||||
|
__extab_end = .;
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
/* ARM index entries for section unwinding */
|
||||||
|
.ARM.exidx : {
|
||||||
|
__exidx_start = .;
|
||||||
|
*(.ARM.exidx*)
|
||||||
|
__exidx_end = .;
|
||||||
|
} > ROM
|
||||||
|
|
||||||
|
/* Start address for the initialization values of the .data section */
|
||||||
|
_sidata = .;
|
||||||
|
|
||||||
|
/* The .data section (initialized data) */
|
||||||
|
.data : AT ( _sidata )
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sdata = . ; /* Start address for the .data section */
|
||||||
|
*(.data .data*)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
_edata = . ; /* End address for the .data section */
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* The .bss section (uninitialized data) */
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sbss = .; /* Start address for the .bss section */
|
||||||
|
__bss_start__ = _sbss;
|
||||||
|
*(.bss)
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = . ; /* End address for the .bss section */
|
||||||
|
__bss_end__ = _ebss;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* Space for heap and stack */
|
||||||
|
.heap_stack :
|
||||||
|
{
|
||||||
|
end = . ; /* 'end' symbol defines heap location */
|
||||||
|
_end = end ;
|
||||||
|
. = . + _min_heap_size; /* Additional space for heap and stack */
|
||||||
|
. = . + _min_stack_size;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* Remove information from the standard libraries */
|
||||||
|
/DISCARD/ :
|
||||||
|
{
|
||||||
|
libc.a ( * )
|
||||||
|
libm.a ( * )
|
||||||
|
libgcc.a ( * )
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in new issue