Porównaj commity

...

10 Commity

Autor SHA1 Wiadomość Data
Mikael Nousiainen 8f3d9cf612 Adjust README 2023-10-14 11:43:55 +03:00
Mikael Nousiainen 9cd9a64a16 Merge branch 'main' into dfm17 2023-10-14 11:41:24 +03:00
Mikael Nousiainen f9d964ab8e Clean up DFM-17 clock calibration implementation and make RS41 compile properly 2023-10-14 11:41:06 +03:00
Mikael Nousiainen 61e428789a
Merge pull request #62 from kd2eat/dfm17
Added a timepulse routine for DFM17 and also a millis() routine.
2023-10-14 11:07:59 +03:00
Mikael Nousiainen 18b6e1ffb4
Remove references to specific ARM GNU toolchain versions 2023-10-14 11:02:55 +03:00
Mikael Nousiainen 6462371a14
Update the ARM GNU compiler toolchain URL 2023-10-14 11:01:47 +03:00
Mike Hojnowski 591749fa98 Added logic to (hopefully) avoid over-calibration if there is an errant timepulse. 2023-10-13 23:48:07 -04:00
Mike Hojnowski a34c9b9e1f Cleaned up clock calibration code and integrated into the main radio loop. Also added APRS telemetry for calibration. 2023-10-11 23:30:21 -04:00
Mike Hojnowski 0901b02de4 More refinements to the HCI calibration 2023-10-11 14:12:26 -04:00
Mike Hojnowski 324c3bf83b Added a timepulse routine for DFM17 and also a millis() routine. Working toward clock calibration. 2023-10-09 00:58:44 -04:00
25 zmienionych plików z 494 dodań i 201 usunięć

Wyświetl plik

@ -329,8 +329,9 @@ Now you can flash the firmware using instructions below (skip the build instruct
Software requirements: Software requirements:
* [GNU GCC toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads/9-2-2019-12) * [GNU GCC toolchain](https://developer.arm.com/downloads/-/gnu-rm)
version 8.3.0 or higher for cross-compiling the firmware for the ARM Cortex-M3 architecture (`arm-none-eabi-gcc`) for cross-compiling the firmware for the ARM Cortex-M3 architecture (`arm-none-eabi-gcc`)
* Pick the latest toolchain version available for your operating system.
* [CMake](https://cmake.org/) version 3.6 or higher for building the firmware * [CMake](https://cmake.org/) version 3.6 or higher for building the firmware
* [OpenOCD](http://openocd.org/) version 0.10.0 or higher for flashing the firmware * [OpenOCD](http://openocd.org/) version 0.10.0 or higher for flashing the firmware
@ -475,7 +476,8 @@ _____
It is possible to receive log messages from the firmware program and to perform debugging of the firmware using GNU GDB. It is possible to receive log messages from the firmware program and to perform debugging of the firmware using GNU GDB.
Also, please note that Red Hat/Fedora do not provide GDB for ARM architectures, so you will need to manually download Also, please note that Red Hat/Fedora do not provide GDB for ARM architectures, so you will need to manually download
and install GDB from [ARM GNU GCC toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-a/downloads/9-2-2019-12). and install GDB from [ARM GNU GCC toolchain](https://developer.arm.com/downloads/-/gnu-rm).
Pick the latest version available for your operating system.
Semihosting allows the firmware to send log messages via special system calls to OpenOCD, so that you Semihosting allows the firmware to send log messages via special system calls to OpenOCD, so that you
can get real-time feedback and debug output from the application. can get real-time feedback and debug output from the application.
@ -514,7 +516,9 @@ otherwise the firmware will not run.**
To load debugging symbols for settings breakpoints and to perform more detailed inspection, To load debugging symbols for settings breakpoints and to perform more detailed inspection,
use command `file src/RS41ng.elf`. use command `file src/RS41ng.elf`.
## Si4032 Bell FSK modulation hack for APRS (notes by Mikael OH3BHX) ## Si4032 Bell FSK modulation hack for APRS
Notes by Mikael OH3BHX:
The idea behind the APRS / Bell 202 modulation implementation is based on RS41HUP project and its "ancestors" The idea behind the APRS / Bell 202 modulation implementation is based on RS41HUP project and its "ancestors"
and I'm describing it here, since it has not been documented elsewhere. and I'm describing it here, since it has not been documented elsewhere.
@ -598,6 +602,7 @@ rtl_fm -f 432500000 -M fm -s 250k -r 48000 -g 22 - | ./aprs -
* http://happysat.nl/RS-41/RS41.html - Vaisala RS-41 SGP Modification and info about the original firmware settings * http://happysat.nl/RS-41/RS41.html - Vaisala RS-41 SGP Modification and info about the original firmware settings
* https://destevez.net/2018/06/flashing-a-vaisala-rs41-radiosonde/ * https://destevez.net/2018/06/flashing-a-vaisala-rs41-radiosonde/
* https://destevez.net/2017/11/tracking-an-rs41-sgp-radiosonde-and-reporting-to-aprs/ * https://destevez.net/2017/11/tracking-an-rs41-sgp-radiosonde-and-reporting-to-aprs/
* https://github.com/digiampietro/esp8266-rs41 - A tool for reconfiguring RS41s via its serial port
## Graw DFM-17 hardware documentation ## Graw DFM-17 hardware documentation

Wyświetl plik

@ -27,6 +27,8 @@
* $he - Heading in degrees (up to 3 chars) * $he - Heading in degrees (up to 3 chars)
* $pc - Pulse counter value (wraps to zero at 65535, 16-bit unsigned value) * $pc - Pulse counter value (wraps to zero at 65535, 16-bit unsigned value)
* $ri - Radiation intensity in µR/h (up to 5 chars) * $ri - Radiation intensity in µR/h (up to 5 chars)
* $ct - Clock calibration trim value (0-31, only for DFM-17)
* $cc - Clock calibration change count (only for DFM-17)
* *
* Allowed message lengths: * Allowed message lengths:
* *

Wyświetl plik

@ -8,6 +8,9 @@
#if !defined(RS41) && !defined(DFM17) #if !defined(RS41) && !defined(DFM17)
#error "No hardware type specified. Please define RS41 or DFM17." #error "No hardware type specified. Please define RS41 or DFM17."
#endif #endif
#if defined(RS41) && defined(DFM17)
#error "Please define either RS41 or DFM17."
#endif
// Enable semihosting to receive debug logs during development // Enable semihosting to receive debug logs during development

Wyświetl plik

@ -13,6 +13,9 @@
// PARIS: 50 dot durations, 20 WPM -> 60ms per unit // PARIS: 50 dot durations, 20 WPM -> 60ms per unit
#define MORSE_WPM_TO_SYMBOL_RATE(wpm) (1000 / (60 * 20 / wpm)) #define MORSE_WPM_TO_SYMBOL_RATE(wpm) (1000 / (60 * 20 / wpm))
// Experimental fast frequency change routine for Si5351, not tested
#define SI5351_FAST_ENABLE false
#include <stdbool.h> #include <stdbool.h>
extern bool leds_enabled; extern bool leds_enabled;

Wyświetl plik

@ -499,7 +499,7 @@ void si4063_configure()
si4063_send_command(SI4063_COMMAND_SET_PROPERTY, sizeof(data), data); si4063_send_command(SI4063_COMMAND_SET_PROPERTY, sizeof(data), data);
} }
// HERE
{ {
// Used only in synchronous mode (for GFSK modulation/filtering) // Used only in synchronous mode (for GFSK modulation/filtering)
uint8_t data[] = { uint8_t data[] = {

Wyświetl plik

@ -69,6 +69,9 @@
#define BANK_GREEN_LED GPIOC #define BANK_GREEN_LED GPIOC
#define PIN_GREEN_LED GPIO_Pin_6 #define PIN_GREEN_LED GPIO_Pin_6
#define BANK_YELLOW_LED GPIOC
#define PIN_YELLOW_LED GPIO_Pin_7
#define BANK_MOSI GPIOA #define BANK_MOSI GPIOA
#define PIN_MOSI GPIO_Pin_7 #define PIN_MOSI GPIO_Pin_7
#define BANK_SCK GPIOA #define BANK_SCK GPIOA

Wyświetl plik

@ -0,0 +1,144 @@
#include "config.h"
#ifdef DFM17
#include "stm32f10x_exti.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#include "system.h"
#include "millis.h"
#include "clock_calibration.h"
// The HSI (internal oscillator) trim register mask, copied from stm_lib/src/stm32f10x_rcc.c
#define CR_HSITRIM_Mask ((uint32_t)0xFFFFFF07)
// Register definition for reading the HSI current trim out of the Calibration Register (CR).
// Resulting value will be between 0-31.
#define CURRENT_TRIM ((RCC->CR & ~CR_HSITRIM_Mask) >>3)
/**
* On the DFM-17, GPIO PB8 is wired to the GPS Timepulse. We take advantage of this to do a
* processor speed calibration. HSITRIM[4:0] allows for 32 values to adjust the HSI clock
* speed. The center (16) value is "neutral". Each trim value above or below 16 adjusts
* the clock by approximately 40kHZ (0.5% of the 8MHZ clock speed) (per AN2868).
* 0.5% is about 5ms per second, so if we detect that we're off by more than 5 milliseconds between time pulses,
* we will suggest a recalibration. The "trim_suggestion" variable is a static that will be maintained
* by the time pulse IRQ and can be used at any time it's convenient to adjust the clock speed.
*/
// Defaults, will be set it in the init routine below.
int trim_suggestion = 16;
int trim_current = 16;
uint32_t old_millis = 0;
uint16_t calibration_change_count = 0;
bool calibration_indicator_state = true;
uint8_t clock_calibration_get_trim()
{
return CURRENT_TRIM;
}
uint16_t clock_calibration_get_change_count()
{
return calibration_change_count;
}
void clock_calibration_adjust()
{
if (trim_suggestion == trim_current) {
return;
}
RCC_AdjustHSICalibrationValue(trim_suggestion);
trim_current = trim_suggestion;
calibration_change_count++;
calibration_indicator_state = !calibration_indicator_state;
system_set_yellow_led(calibration_indicator_state);
}
void timepulse_init()
{
// Initialize pin PB8 as floating input
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Pin = GPIO_Pin_8;
gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_init.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &gpio_init);
// PB8 is connected to interrupt line 8, set trigger on the configured edge and enable the interrupt
EXTI_InitTypeDef exti_init;
exti_init.EXTI_Line = EXTI_Line8;
exti_init.EXTI_Mode = EXTI_Mode_Interrupt;
exti_init.EXTI_Trigger = EXTI_Trigger_Rising;
exti_init.EXTI_LineCmd = ENABLE;
EXTI_Init(&exti_init);
// Attach interrupt line to port B
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8);
// PB8 is connected to EXTI_Line8, which has EXTI9_5_IRQn vector. Use priority 0 for now.
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// Pull the current calibration to start
trim_current = CURRENT_TRIM;
trim_suggestion = trim_current;
// Set the yellow LED to help identify calibration changes
system_set_yellow_led(calibration_indicator_state);
}
// This handler is (at present) only being used for the GPS time pulse interrupt,
// so we shouldn't need to do additional testing for the cause of the interrupt.
void EXTI9_5_IRQHandler(void)
{
uint32_t current_millis = millis();
EXTI_ClearITPendingBit(EXTI_Line8);
if (old_millis == 0) {
// First timepulse. Just store millis.
old_millis = current_millis;
return;
}
if (current_millis < old_millis) {
// Milliseconds value wrapped to zero. Wait for the next interrupt.
return;
}
// Calculate milliseconds since last timepulse. Ideally there were 1000.
uint32_t millis_delta = current_millis - old_millis;
old_millis = current_millis;
// If too few clicks, speed up clock. If too many, slow down.
int delta = (int) (1000 - millis_delta) / 5;
// Take one step at a time in case we had a bad clock tick
if (delta > 1) {
delta = 1;
}
if (delta < -1) {
delta = -1;
}
// Don't allow calibration suggestion to go out of range
if (((delta + trim_current) >= 0) &&
((delta + trim_current <= 31))) {
// If the delta makes sense, apply to the suggestion. Otherwise, skip.
trim_suggestion = trim_current + delta;
}
}
#endif

Wyświetl plik

@ -0,0 +1,15 @@
#ifndef __CLOCK_CALIBRATION_H
#define __CLOCK_CALIBRATION_H
#include "config.h"
#ifdef DFM17
extern void timepulse_init();
extern uint8_t clock_calibration_get_trim();
extern uint16_t clock_calibration_get_change_count();
extern void clock_calibration_adjust();
#endif
#endif

Wyświetl plik

@ -34,8 +34,8 @@ void data_timer_init(uint32_t baud_rate)
NVIC_InitTypeDef nvic_init; NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = TIM2_IRQn; nvic_init.NVIC_IRQChannel = TIM2_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 0; nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
nvic_init.NVIC_IRQChannelSubPriority = 1; nvic_init.NVIC_IRQChannelSubPriority = 2;
nvic_init.NVIC_IRQChannelCmd = ENABLE; nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init); NVIC_Init(&nvic_init);
@ -48,8 +48,8 @@ void data_timer_uninit()
NVIC_InitTypeDef nvic_init; NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = TIM2_IRQn; nvic_init.NVIC_IRQChannel = TIM2_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 0; nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
nvic_init.NVIC_IRQChannelSubPriority = 1; nvic_init.NVIC_IRQChannelSubPriority = 2;
nvic_init.NVIC_IRQChannelCmd = DISABLE; nvic_init.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&nvic_init); NVIC_Init(&nvic_init);
@ -61,8 +61,6 @@ void TIM2_IRQHandler(void)
{ {
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
system_handle_data_timer_tick(); system_handle_data_timer_tick();
} }
} }

Wyświetl plik

@ -31,7 +31,7 @@ void delay_init()
NVIC_InitTypeDef nvic_init; NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = TIM3_IRQn; nvic_init.NVIC_IRQChannel = TIM3_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 0; nvic_init.NVIC_IRQChannelPreemptionPriority = 1;
nvic_init.NVIC_IRQChannelSubPriority = 1; nvic_init.NVIC_IRQChannelSubPriority = 1;
nvic_init.NVIC_IRQChannelCmd = ENABLE; nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init); NVIC_Init(&nvic_init);

65
src/hal/millis.c 100644
Wyświetl plik

@ -0,0 +1,65 @@
#include <stm32f10x_rcc.h>
#include <stm32f10x_tim.h>
#include <misc.h>
#include "src/hal/millis.h"
static uint32_t millis_counter;
void millis_timer_init(void)
{
TIM_DeInit(TIM7);
TIM_TimeBaseInitTypeDef tim_init;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB1Periph_TIM7, DISABLE);
// The data timer assumes a 24 MHz clock source
tim_init.TIM_Prescaler = 24 - 1; // tick every 1/1000000 s
tim_init.TIM_CounterMode = TIM_CounterMode_Up;
tim_init.TIM_Period = (uint16_t) (1000 - 1); // set up period of 1 millisecond
tim_init.TIM_ClockDivision = TIM_CKD_DIV1;
tim_init.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM7, &tim_init);
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);
NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = TIM7_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
nvic_init.NVIC_IRQChannelSubPriority = 1;
nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init);
TIM_Cmd(TIM7, ENABLE);
}
void millis_timer_uninit()
{
TIM_Cmd(TIM7, DISABLE);
NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = TIM7_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
nvic_init.NVIC_IRQChannelSubPriority = 1;
nvic_init.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&nvic_init);
TIM_ITConfig(TIM7, TIM_IT_Update, DISABLE);
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
}
void TIM7_IRQHandler(void)
{
if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET) {
TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
millis_counter++;
}
}
uint32_t millis(void)
{
return millis_counter;
}

12
src/hal/millis.h 100644
Wyświetl plik

@ -0,0 +1,12 @@
#ifndef __MILLIS_H
#define __MILLIS_H
#include <stdint.h>
extern void millis_timer_init(void);
extern void millis_timer_uninit();
extern uint32_t millis();
#endif

Wyświetl plik

@ -14,7 +14,6 @@ uint16_t (*pwm_handle_dma_transfer_full)(uint16_t buffer_size, uint16_t *buffer)
DMA_Channel_TypeDef *pwm_dma_channel = DMA1_Channel2; DMA_Channel_TypeDef *pwm_dma_channel = DMA1_Channel2;
void pwm_data_timer_init() void pwm_data_timer_init()
{ {
// Timer frequency = TIM_CLK/(TIM_PSC+1)/(TIM_ARR + 1) // Timer frequency = TIM_CLK/(TIM_PSC+1)/(TIM_ARR + 1)
@ -43,8 +42,8 @@ void pwm_data_timer_init()
NVIC_InitTypeDef nvic_init; NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = TIM2_IRQn; nvic_init.NVIC_IRQChannel = TIM2_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 0; nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
nvic_init.NVIC_IRQChannelSubPriority = 1; nvic_init.NVIC_IRQChannelSubPriority = 2;
nvic_init.NVIC_IRQChannelCmd = ENABLE; nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init); NVIC_Init(&nvic_init);
*/ */
@ -52,12 +51,6 @@ void pwm_data_timer_init()
TIM_Cmd(TIM2, ENABLE); TIM_Cmd(TIM2, ENABLE);
} }
void pwm_data_timer_dma_request_enable(bool enabled)
{
// TIM2 Update DMA requests are routed to DMA1 Channel2
TIM_DMACmd(TIM2, TIM_DMA_Update, enabled ? ENABLE : DISABLE);
}
void pwm_data_timer_uninit() void pwm_data_timer_uninit()
{ {
TIM_Cmd(TIM2, DISABLE); TIM_Cmd(TIM2, DISABLE);
@ -117,7 +110,7 @@ void pwm_timer_init(uint32_t frequency_hz_100)
NVIC_InitTypeDef nvic_init; NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = TIM1_BRK_TIM15_IRQn; nvic_init.NVIC_IRQChannel = TIM1_BRK_TIM15_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 0; nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
nvic_init.NVIC_IRQChannelSubPriority = 1; nvic_init.NVIC_IRQChannelSubPriority = 1;
nvic_init.NVIC_IRQChannelCmd = ENABLE; nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init); NVIC_Init(&nvic_init);
@ -126,86 +119,6 @@ void pwm_timer_init(uint32_t frequency_hz_100)
TIM_Cmd(TIM15, ENABLE); TIM_Cmd(TIM15, ENABLE);
} }
static void pwm_dma_init_channel()
{
DMA_InitTypeDef dma_init;
dma_init.DMA_BufferSize = PWM_TIMER_DMA_BUFFER_SIZE;
dma_init.DMA_DIR = DMA_DIR_PeripheralDST;
dma_init.DMA_M2M = DMA_M2M_Disable;
dma_init.DMA_MemoryBaseAddr = (uint32_t) pwm_timer_dma_buffer;
dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma_init.DMA_Mode = DMA_Mode_Circular;
dma_init.DMA_PeripheralBaseAddr = (uint32_t) &TIM15->ARR;
dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // DMA_PeripheralDataSize_Word ?
dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma_init.DMA_Priority = DMA_Priority_VeryHigh;
DMA_Init(pwm_dma_channel, &dma_init);
}
inline void pwm_dma_interrupt_enable(bool enabled)
{
DMA_ClearITPendingBit(DMA1_IT_HT2);
DMA_ClearITPendingBit(DMA1_IT_TC2);
DMA_ITConfig(pwm_dma_channel, DMA_IT_HT | DMA_IT_TC | DMA_IT_TE, enabled ? ENABLE : DISABLE);
}
void pwm_dma_init()
{
DMA_DeInit(pwm_dma_channel);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
pwm_dma_init_channel();
pwm_dma_interrupt_enable(true);
DMA_Cmd(pwm_dma_channel, ENABLE);
NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = DMA1_Channel2_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
nvic_init.NVIC_IRQChannelSubPriority = 1;
nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init);
}
void pwm_dma_start()
{
//pwm_dma_init_channel();
//pwm_dma_interrupt_enable(true);
// TODO: Why doesn't timer DMA request restart without reinitializing the timer?
pwm_timer_init(100 * 100);
pwm_timer_pwm_enable(true);
pwm_timer_use(true);
DMA_SetCurrDataCounter(pwm_dma_channel, PWM_TIMER_DMA_BUFFER_SIZE);
DMA_Cmd(pwm_dma_channel, ENABLE);
pwm_data_timer_dma_request_enable(true);
}
void pwm_dma_stop()
{
pwm_data_timer_dma_request_enable(false);
DMA_Cmd(pwm_dma_channel, DISABLE);
//pwm_dma_interrupt_enable(false);
}
void DMA1_Channel2_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_TE2)) {
DMA_ClearITPendingBit(DMA1_IT_TE2);
log_info("DMA Transfer Error\n");
}
if (DMA_GetITStatus(DMA1_IT_HT2)) {
DMA_ClearITPendingBit(DMA1_IT_HT2);
pwm_handle_dma_transfer_half(PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
}
if (DMA_GetITStatus(DMA1_IT_TC2)) {
DMA_ClearITPendingBit(DMA1_IT_TC2);
pwm_handle_dma_transfer_full(PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
}
}
void pwm_timer_pwm_enable(bool enabled) void pwm_timer_pwm_enable(bool enabled)
{ {
#ifdef RS41 #ifdef RS41
@ -243,12 +156,96 @@ inline uint16_t pwm_calculate_period(uint32_t frequency_hz_100)
inline void pwm_timer_set_frequency(uint32_t pwm_period) inline void pwm_timer_set_frequency(uint32_t pwm_period)
{ {
// TIM_CtrlPWMOutputs(TIM15, DISABLE);
// TIM_Cmd(TIM15, DISABLE);
TIM_SetAutoreload(TIM15, pwm_period); TIM_SetAutoreload(TIM15, pwm_period);
// TIM_SetCompare2(TIM15, pwm_period / 2); }
// TIM_Cmd(TIM15, ENABLE); /**
// TIM_CtrlPWMOutputs(TIM15, ENABLE); * Below are experimental DMA routines for supplying PWM data for APRS modulation.
* This does not work correctly, but is left for future reference.
*/
static void pwm_dma_init_channel()
{
DMA_InitTypeDef dma_init;
dma_init.DMA_BufferSize = PWM_TIMER_DMA_BUFFER_SIZE;
dma_init.DMA_DIR = DMA_DIR_PeripheralDST;
dma_init.DMA_M2M = DMA_M2M_Disable;
dma_init.DMA_MemoryBaseAddr = (uint32_t) pwm_timer_dma_buffer;
dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
dma_init.DMA_Mode = DMA_Mode_Circular;
dma_init.DMA_PeripheralBaseAddr = (uint32_t) &TIM15->ARR;
dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // DMA_PeripheralDataSize_Word ?
dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
dma_init.DMA_Priority = DMA_Priority_VeryHigh;
DMA_Init(pwm_dma_channel, &dma_init);
}
inline void pwm_dma_interrupt_enable(bool enabled)
{
DMA_ClearITPendingBit(DMA1_IT_HT2);
DMA_ClearITPendingBit(DMA1_IT_TC2);
DMA_ITConfig(pwm_dma_channel, DMA_IT_HT | DMA_IT_TC | DMA_IT_TE, enabled ? ENABLE : DISABLE);
}
void pwm_dma_init()
{
DMA_DeInit(pwm_dma_channel);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
pwm_dma_init_channel();
pwm_dma_interrupt_enable(true);
DMA_Cmd(pwm_dma_channel, ENABLE);
NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = DMA1_Channel2_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 2;
nvic_init.NVIC_IRQChannelSubPriority = 0;
nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init);
}
void pwm_dma_start()
{
//pwm_dma_init_channel();
//pwm_dma_interrupt_enable(true);
// TODO: Why doesn't timer DMA request restart without reinitializing the timer?
pwm_timer_init(100 * 100);
pwm_timer_pwm_enable(true);
pwm_timer_use(true);
DMA_SetCurrDataCounter(pwm_dma_channel, PWM_TIMER_DMA_BUFFER_SIZE);
DMA_Cmd(pwm_dma_channel, ENABLE);
pwm_data_timer_dma_request_enable(true);
}
void pwm_dma_stop()
{
pwm_data_timer_dma_request_enable(false);
DMA_Cmd(pwm_dma_channel, DISABLE);
//pwm_dma_interrupt_enable(false);
}
void pwm_data_timer_dma_request_enable(bool enabled)
{
// TIM2 Update DMA requests are routed to DMA1 Channel2
TIM_DMACmd(TIM2, TIM_DMA_Update, enabled ? ENABLE : DISABLE);
}
void DMA1_Channel2_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_TE2)) {
DMA_ClearITPendingBit(DMA1_IT_TE2);
log_info("DMA Transfer Error\n");
}
if (DMA_GetITStatus(DMA1_IT_HT2)) {
DMA_ClearITPendingBit(DMA1_IT_HT2);
pwm_handle_dma_transfer_half(PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
}
if (DMA_GetITStatus(DMA1_IT_TC2)) {
DMA_ClearITPendingBit(DMA1_IT_TC2);
pwm_handle_dma_transfer_full(PWM_TIMER_DMA_BUFFER_SIZE, pwm_timer_dma_buffer);
}
} }

Wyświetl plik

@ -12,6 +12,7 @@
#include "delay.h" #include "delay.h"
#include "log.h" #include "log.h"
#include "gpio.h" #include "gpio.h"
#include "millis.h"
#define BUTTON_PRESS_LONG_COUNT SYSTEM_SCHEDULER_TIMER_TICKS_PER_SECOND #define BUTTON_PRESS_LONG_COUNT SYSTEM_SCHEDULER_TIMER_TICKS_PER_SECOND
@ -126,6 +127,14 @@ static void gpio_init()
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP; gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz; gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BANK_RED_LED, &gpio_init); GPIO_Init(BANK_RED_LED, &gpio_init);
#ifdef DFM17
// Yellow LED (only in DFM-17)
gpio_init.GPIO_Pin = PIN_YELLOW_LED;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BANK_YELLOW_LED, &gpio_init);
#endif
} }
/** /**
@ -343,6 +352,18 @@ void system_set_red_led(bool enabled)
#endif #endif
} }
void system_set_yellow_led(bool enabled)
{
#ifdef DFM17
// Only DFM-17 has a yellow LED
if (enabled) {
GPIO_SetBits(BANK_YELLOW_LED, PIN_YELLOW_LED);
} else {
GPIO_ResetBits(BANK_YELLOW_LED, PIN_YELLOW_LED);
}
#endif
}
void system_disable_irq() void system_disable_irq()
{ {
__disable_irq(); __disable_irq();
@ -360,7 +381,10 @@ void system_init()
gpio_init(); gpio_init();
dma_adc_init(); dma_adc_init();
delay_init(); delay_init();
#ifdef DFM17
// The millis timer is used for clock calibration on DFM-17 only
millis_timer_init();
#endif
system_scheduler_timer_init(); system_scheduler_timer_init();
RCC_ClocksTypeDef RCC_Clocks; RCC_ClocksTypeDef RCC_Clocks;

Wyświetl plik

@ -1,11 +1,9 @@
#ifndef __HAL_SYSTEM_H #ifndef __HAL_SYSTEM_H
#define __HAL_SYSTEM_H #define __HAL_SYSTEM_H
#include "config.h"
#include "hal.h" #include "hal.h"
#define GPIO_PIN_LED_GREEN GPIO_Pin_7
#define GPIO_PIN_LED_RED GPIO_Pin_8
#define SYSTEM_SCHEDULER_TIMER_TICKS_PER_SECOND 10000 #define SYSTEM_SCHEDULER_TIMER_TICKS_PER_SECOND 10000
void system_init(); void system_init();
@ -17,6 +15,9 @@ void system_disable_irq();
void system_enable_irq(); void system_enable_irq();
void system_set_green_led(bool enabled); void system_set_green_led(bool enabled);
void system_set_red_led(bool enabled); void system_set_red_led(bool enabled);
#ifdef DFM17
void system_set_yellow_led(bool enabled);
#endif
uint16_t system_get_battery_voltage_millivolts(); uint16_t system_get_battery_voltage_millivolts();
uint16_t system_get_button_adc_value(); uint16_t system_get_button_adc_value();

Wyświetl plik

@ -49,7 +49,7 @@ void usart_gps_init(uint32_t baud_rate, bool enable_irq)
NVIC_InitTypeDef nvic_init; NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = USART_IRQ; nvic_init.NVIC_IRQChannel = USART_IRQ;
nvic_init.NVIC_IRQChannelPreemptionPriority = 15; nvic_init.NVIC_IRQChannelPreemptionPriority = 3;
nvic_init.NVIC_IRQChannelSubPriority = 2; nvic_init.NVIC_IRQChannelSubPriority = 2;
nvic_init.NVIC_IRQChannelCmd = ENABLE; nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init); NVIC_Init(&nvic_init);

Wyświetl plik

@ -19,6 +19,7 @@
#endif #endif
#ifdef DFM17 #ifdef DFM17
#include "hal/clock_calibration.h"
#include "drivers/si4063/si4063.h" #include "drivers/si4063/si4063.h"
#endif #endif
@ -74,6 +75,17 @@ void set_red_led(bool enabled)
system_set_red_led(enabled); system_set_red_led(enabled);
} }
#ifdef DFM17
void set_yellow_led(bool enabled)
{
if ((LEDS_DISABLE_ALTITUDE_METERS > 0) && (current_gps_data.altitude_mm / 1000 > LEDS_DISABLE_ALTITUDE_METERS)) {
enabled = false;
}
system_set_yellow_led(enabled);
}
#endif
int main(void) int main(void)
{ {
bool success; bool success;
@ -115,6 +127,11 @@ int main(void)
goto gps_init; goto gps_init;
} }
#ifdef DFM17
log_info("Timepulse init\n");
timepulse_init();
#endif
#if defined(RS41) #if defined(RS41)
log_info("Si4032 init\n"); log_info("Si4032 init\n");
si4032_init(); si4032_init();
@ -175,6 +192,9 @@ int main(void)
while (true) { while (true) {
radio_handle_main_loop(); radio_handle_main_loop();
#ifdef DFM17
clock_calibration_adjust();
#endif
//NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, DISABLE); //NVIC_SystemLPConfig(NVIC_LP_SEVONPEND, DISABLE);
//__WFI(); //__WFI();
} }

Wyświetl plik

@ -1,7 +1,6 @@
#include "config.h" #include "config.h"
#ifdef RS41 #ifdef RS41
#include <stdint.h>
#include <string.h> #include <string.h>
#include "hal/system.h" #include "hal/system.h"
@ -260,7 +259,7 @@ inline void radio_handle_data_timer_si4032()
tone_index = fsk_encoder_api->next_tone(fsk_enc); tone_index = fsk_encoder_api->next_tone(fsk_enc);
if (tone_index < 0) { if (tone_index < 0) {
log_info("Horus V1 TX finished\n"); log_info("Horus TX finished\n");
radio_shared_state.radio_interrupt_transmit_active = false; radio_shared_state.radio_interrupt_transmit_active = false;
radio_shared_state.radio_transmission_finished = true; radio_shared_state.radio_transmission_finished = true;
system_enable_tick(); system_enable_tick();

Wyświetl plik

@ -19,7 +19,7 @@
// TODO: Add support for multiple APRS baud rates // TODO: Add support for multiple APRS baud rates
// This delay is for DFM-17 radiosondes // This delay is for DFM-17 radiosondes
#define symbol_delay_bell_202_1200bps_us 820 #define symbol_delay_bell_202_1200bps_us 821
static volatile bool radio_si4063_state_change = false; static volatile bool radio_si4063_state_change = false;
static volatile uint32_t radio_si4063_freq = 0; static volatile uint32_t radio_si4063_freq = 0;

Wyświetl plik

@ -8,8 +8,6 @@
#define CW_SYMBOL_RATE_MULTIPLIER 4 #define CW_SYMBOL_RATE_MULTIPLIER 4
static bool use_fast_si5351 = false;
static volatile bool radio_si5351_state_change = false; static volatile bool radio_si5351_state_change = false;
static volatile uint64_t radio_si5351_freq = 0; static volatile uint64_t radio_si5351_freq = 0;
static volatile bool radio_si5351_frequency_not_set = false; static volatile bool radio_si5351_frequency_not_set = false;
@ -27,27 +25,19 @@ bool radio_start_transmit_si5351(radio_transmit_entry *entry, radio_module_state
set_frequency_early = false; set_frequency_early = false;
break; break;
case RADIO_DATA_MODE_HORUS_V1: case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
data_timer_init(entry->fsk_encoder_api->get_symbol_rate(&entry->fsk_encoder)); data_timer_init(entry->fsk_encoder_api->get_symbol_rate(&entry->fsk_encoder));
//use_fast_si5351 = true;
break; break;
default: default:
break; break;
} }
// TODO: handle Si5351 errors // TODO: handle Si5351 errors
if (use_fast_si5351) {
si5351_set_drive_strength_fast(SI5351_CLOCK_CLK0, entry->tx_power);
if (set_frequency_early) {
si5351_set_frequency_fast(SI5351_CLOCK_CLK0, ((uint64_t) entry->frequency) * 100ULL);
si5351_output_enable_fast(SI5351_CLOCK_CLK0, true);
}
} else {
si5351_set_drive_strength(SI5351_CLOCK_CLK0, entry->tx_power); si5351_set_drive_strength(SI5351_CLOCK_CLK0, entry->tx_power);
if (set_frequency_early) { if (set_frequency_early) {
si5351_set_frequency(SI5351_CLOCK_CLK0, ((uint64_t) entry->frequency) * 100ULL); si5351_set_frequency(SI5351_CLOCK_CLK0, ((uint64_t) entry->frequency) * 100ULL);
si5351_output_enable(SI5351_CLOCK_CLK0, true); si5351_output_enable(SI5351_CLOCK_CLK0, true);
} }
}
switch (entry->data_mode) { switch (entry->data_mode) {
case RADIO_DATA_MODE_CW: case RADIO_DATA_MODE_CW:
@ -58,6 +48,7 @@ bool radio_start_transmit_si5351(radio_transmit_entry *entry, radio_module_state
radio_si5351_frequency_not_set = true; radio_si5351_frequency_not_set = true;
break; break;
case RADIO_DATA_MODE_HORUS_V1: case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
system_disable_tick(); system_disable_tick();
shared_state->radio_interrupt_transmit_active = true; shared_state->radio_interrupt_transmit_active = true;
break; break;
@ -73,8 +64,8 @@ bool radio_transmit_symbol_si5351(radio_transmit_entry *entry, radio_module_stat
switch (entry->data_mode) { switch (entry->data_mode) {
case RADIO_DATA_MODE_CW: case RADIO_DATA_MODE_CW:
case RADIO_DATA_MODE_PIP: case RADIO_DATA_MODE_PIP:
return false;
case RADIO_DATA_MODE_HORUS_V1: case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
return false; return false;
default: { default: {
int8_t next_tone_index = entry->fsk_encoder_api->next_tone(&entry->fsk_encoder); int8_t next_tone_index = entry->fsk_encoder_api->next_tone(&entry->fsk_encoder);
@ -152,14 +143,15 @@ inline void radio_handle_data_timer_si5351()
radio_shared_state.radio_symbol_count_interrupt++; radio_shared_state.radio_symbol_count_interrupt++;
break; break;
} }
case RADIO_DATA_MODE_HORUS_V1: { case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2: {
fsk_encoder_api *fsk_encoder_api = radio_current_transmit_entry->fsk_encoder_api; fsk_encoder_api *fsk_encoder_api = radio_current_transmit_entry->fsk_encoder_api;
fsk_encoder *fsk_enc = &radio_current_transmit_entry->fsk_encoder; fsk_encoder *fsk_enc = &radio_current_transmit_entry->fsk_encoder;
int8_t tone_index; int8_t tone_index;
tone_index = fsk_encoder_api->next_tone(fsk_enc); tone_index = fsk_encoder_api->next_tone(fsk_enc);
if (tone_index < 0) { if (tone_index < 0) {
log_info("Horus V1 TX finished\n"); log_info("Horus TX finished\n");
radio_shared_state.radio_interrupt_transmit_active = false; radio_shared_state.radio_interrupt_transmit_active = false;
radio_shared_state.radio_transmission_finished = true; radio_shared_state.radio_transmission_finished = true;
system_enable_tick(); system_enable_tick();
@ -181,30 +173,13 @@ inline void radio_handle_data_timer_si5351()
bool radio_stop_transmit_si5351(radio_transmit_entry *entry, radio_module_state *shared_state) bool radio_stop_transmit_si5351(radio_transmit_entry *entry, radio_module_state *shared_state)
{ {
switch (entry->data_mode) {
case RADIO_DATA_MODE_CW:
case RADIO_DATA_MODE_PIP:
break;
case RADIO_DATA_MODE_HORUS_V1:
// use_fast_si5351 = true;
break;
default:
break;
}
if (use_fast_si5351) {
si5351_output_enable_fast(SI5351_CLOCK_CLK0, false);
} else {
si5351_output_enable(SI5351_CLOCK_CLK0, false); si5351_output_enable(SI5351_CLOCK_CLK0, false);
}
switch (entry->data_mode) { switch (entry->data_mode) {
case RADIO_DATA_MODE_CW: case RADIO_DATA_MODE_CW:
case RADIO_DATA_MODE_PIP: case RADIO_DATA_MODE_PIP:
data_timer_uninit();
system_enable_tick();
break;
case RADIO_DATA_MODE_HORUS_V1: case RADIO_DATA_MODE_HORUS_V1:
case RADIO_DATA_MODE_HORUS_V2:
data_timer_uninit(); data_timer_uninit();
system_enable_tick(); system_enable_tick();
break; break;

Wyświetl plik

@ -1,10 +1,64 @@
#include "drivers/si5351/si5351.h" #include "config.h"
#if SI5351_FAST_ENABLE
#include "drivers/si5351fast/si5351mcu.h" #include "drivers/si5351fast/si5351mcu.h"
#else
#include "drivers/si5351/si5351.h"
#endif
#include "si5351_handler.h" #include "si5351_handler.h"
Si5351 *si5351; #if SI5351_FAST_ENABLE
Si5351mcu si5351_fast; Si5351mcu si5351_fast;
#else
Si5351 *si5351;
#endif
#if SI5351_FAST_ENABLE
bool si5351_handler_init()
{
si5351_fast.init(&DEFAULT_I2C_PORT, SIADDR);
return true;
}
bool si5351_set_frequency(si5351_clock_id clock, uint64_t frequency_hz_100)
{
si5351_fast.setFreq((uint8_t) clock, frequency_hz_100 / 100L);
return true;
}
void si5351_output_enable(si5351_clock_id clock, bool enabled)
{
if (enabled) {
si5351_fast.enable((uint8_t) clock);
} else {
si5351_fast.disable((uint8_t) clock);
}
}
void si5351_set_drive_strength(si5351_clock_id clock, uint8_t drive)
{
int si5351_drive;
switch (drive) {
case 0:
si5351_drive = SIOUT_2mA;
break;
case 1:
si5351_drive = SIOUT_4mA;
break;
case 2:
si5351_drive = SIOUT_6mA;
break;
case 3:
si5351_drive = SIOUT_8mA;
break;
default:
si5351_drive = SIOUT_2mA;
}
si5351_fast.setPower(si5351_drive, (uint8_t) clock);
}
#else
bool si5351_handler_init() bool si5351_handler_init()
{ {
si5351 = new Si5351(&DEFAULT_I2C_PORT); si5351 = new Si5351(&DEFAULT_I2C_PORT);
@ -14,9 +68,6 @@ bool si5351_handler_init()
if (!si5351_found) { if (!si5351_found) {
return si5351_found; return si5351_found;
} }
// si5351_fast.init(&DEFAULT_I2C_PORT, SIADDR);
return si5351_found; return si5351_found;
} }
@ -53,42 +104,4 @@ void si5351_set_drive_strength(si5351_clock_id clock, uint8_t drive)
si5351->drive_strength((enum si5351_clock) clock, si5351_drive); si5351->drive_strength((enum si5351_clock) clock, si5351_drive);
} }
#endif
bool si5351_set_frequency_fast(si5351_clock_id clock, uint64_t frequency_hz_100)
{
si5351_fast.setFreq((uint8_t) clock, frequency_hz_100 / 100L);
return true;
}
void si5351_output_enable_fast(si5351_clock_id clock, bool enabled)
{
if (enabled) {
si5351_fast.enable((uint8_t) clock);
} else {
si5351_fast.disable((uint8_t) clock);
}
}
void si5351_set_drive_strength_fast(si5351_clock_id clock, uint8_t drive)
{
int si5351_drive;
switch (drive) {
case 0:
si5351_drive = SIOUT_2mA;
break;
case 1:
si5351_drive = SIOUT_4mA;
break;
case 2:
si5351_drive = SIOUT_6mA;
break;
case 3:
si5351_drive = SIOUT_8mA;
break;
default:
si5351_drive = SIOUT_2mA;
}
si5351_fast.setPower(si5351_drive, (uint8_t) clock);
}

Wyświetl plik

@ -23,9 +23,6 @@ bool si5351_handler_init();
bool si5351_set_frequency(si5351_clock_id clock, uint64_t frequency_hz_100); bool si5351_set_frequency(si5351_clock_id clock, uint64_t frequency_hz_100);
void si5351_output_enable(si5351_clock_id clock, bool enabled); void si5351_output_enable(si5351_clock_id clock, bool enabled);
void si5351_set_drive_strength(si5351_clock_id clock, uint8_t drive); void si5351_set_drive_strength(si5351_clock_id clock, uint8_t drive);
bool si5351_set_frequency_fast(si5351_clock_id clock, uint64_t frequency_hz_100);
void si5351_output_enable_fast(si5351_clock_id clock, bool enabled);
void si5351_set_drive_strength_fast(si5351_clock_id clock, uint8_t drive);
#ifdef __cplusplus #ifdef __cplusplus
} }

Wyświetl plik

@ -12,6 +12,7 @@
#include "drivers/si4032/si4032.h" #include "drivers/si4032/si4032.h"
#endif #endif
#ifdef DFM17 #ifdef DFM17
#include "hal/clock_calibration.h"
#include "drivers/si4063/si4063.h" #include "drivers/si4063/si4063.h"
#endif #endif
@ -71,6 +72,11 @@ void telemetry_collect(telemetry_data *data)
data->gps.climb_cm_per_second = 0; data->gps.climb_cm_per_second = 0;
} }
#ifdef DFM17
data->clock_calibration_trim = clock_calibration_get_trim();
data->clock_calibration_count = clock_calibration_get_change_count();
#endif
locator_from_lonlat(data->gps.longitude_degrees_1000000, data->gps.latitude_degrees_1000000, locator_from_lonlat(data->gps.longitude_degrees_1000000, data->gps.latitude_degrees_1000000,
LOCATOR_PAIR_COUNT_FULL, data->locator); LOCATOR_PAIR_COUNT_FULL, data->locator);

Wyświetl plik

@ -21,6 +21,9 @@ typedef struct _telemetry_data {
gps_data gps; gps_data gps;
char locator[LOCATOR_PAIR_COUNT_FULL * 2 + 1]; char locator[LOCATOR_PAIR_COUNT_FULL * 2 + 1];
int clock_calibration_trim;
uint16_t clock_calibration_count;
} telemetry_data; } telemetry_data;
void telemetry_collect(telemetry_data *data); void telemetry_collect(telemetry_data *data);

Wyświetl plik

@ -111,6 +111,14 @@ size_t template_replace(char *dest, size_t dest_len, char *src, telemetry_data *
strlcpy(temp, dest, dest_len); strlcpy(temp, dest, dest_len);
str_replace(dest, dest_len, temp, "$ri", replacement); str_replace(dest, dest_len, temp, "$ri", replacement);
snprintf(replacement, sizeof(replacement), "%d", (int) data->clock_calibration_trim);
strlcpy(temp, dest, dest_len);
str_replace(dest, dest_len, temp, "$ct", replacement);
snprintf(replacement, sizeof(replacement), "%d", (int) data->clock_calibration_count);
strlcpy(temp, dest, dest_len);
str_replace(dest, dest_len, temp, "$cc", replacement);
free(temp); free(temp);
return len; return len;