kopia lustrzana https://github.com/RPiks/pico-hf-oscillator
Debugging almost finished. It decodes NMEA and calculates freq shift & ready to make timewindowed WSPR.
rodzic
f0e79b50bc
commit
735698ec94
|
@ -34,6 +34,8 @@ pico_generate_pio_header(pico-hf-oscillator-test ${CMAKE_CURRENT_LIST_DIR}/piodc
|
||||||
target_sources(pico-hf-oscillator-test PUBLIC
|
target_sources(pico-hf-oscillator-test PUBLIC
|
||||||
${CMAKE_CURRENT_LIST_DIR}/lib/assert.c
|
${CMAKE_CURRENT_LIST_DIR}/lib/assert.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/lib/thirdparty/strnstr.c
|
${CMAKE_CURRENT_LIST_DIR}/lib/thirdparty/strnstr.c
|
||||||
|
# ${CMAKE_CURRENT_LIST_DIR}/lib/thirdparty/strptime.c
|
||||||
|
# ${CMAKE_CURRENT_LIST_DIR}/lib/thirdparty/timegm.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/piodco/piodco.c
|
${CMAKE_CURRENT_LIST_DIR}/piodco/piodco.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/gpstime/GPStime.c
|
${CMAKE_CURRENT_LIST_DIR}/gpstime/GPStime.c
|
||||||
${CMAKE_CURRENT_LIST_DIR}/test.c
|
${CMAKE_CURRENT_LIST_DIR}/test.c
|
||||||
|
|
|
@ -78,4 +78,8 @@
|
||||||
|
|
||||||
#define ABS(x) ((x) > 0 ? (x) : -(x))
|
#define ABS(x) ((x) > 0 ? (x) : -(x))
|
||||||
|
|
||||||
|
#define INVERSE(x) ((x) = -(x))
|
||||||
|
|
||||||
|
#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// gpstime.h - GPS time reference utilities for digital controlled radio freq
|
// gpstime.c - GPS time reference utilities for digital controlled radio freq
|
||||||
// oscillator based on Raspberry Pi Pico.
|
// oscillator based on Raspberry Pi Pico.
|
||||||
//
|
//
|
||||||
// DESCRIPTION
|
// DESCRIPTION
|
||||||
//
|
//
|
||||||
// GPS time utilities for PioDco oscillator calculates a precise frequency
|
// GPS time utilities for PioDco oscillator calculates a precise frequency
|
||||||
// between the local Pico oscillator and reference oscillator of GPS system.
|
// shift between the local Pico oscillator and reference oscill. of GPS system.
|
||||||
// The value of the shift is used to correct PioDco generated frequency. The
|
// The value of the shift is used to correct PioDco generated frequency. The
|
||||||
// practical precision of this solution within tenths millihertz range.
|
// practical precision of this solution within tenths millihertz range.
|
||||||
// The value of this accuracy depends on quality of navigation solution of GPS
|
// The value of this accuracy depends on quality of navigation solution of GPS
|
||||||
|
@ -89,6 +89,12 @@ GPStimeContext *GPStimeInit(int uart_id, int uart_baud, int pps_gpio)
|
||||||
gpio_init(pps_gpio);
|
gpio_init(pps_gpio);
|
||||||
gpio_set_dir(pps_gpio, GPIO_IN);
|
gpio_set_dir(pps_gpio, GPIO_IN);
|
||||||
gpio_set_irq_enabled_with_callback(pps_gpio, GPIO_IRQ_EDGE_RISE, true, &GPStimePPScallback);
|
gpio_set_irq_enabled_with_callback(pps_gpio, GPIO_IRQ_EDGE_RISE, true, &GPStimePPScallback);
|
||||||
|
|
||||||
|
irq_set_exclusive_handler(UART0_IRQ, GPStimeUartRxIsr);
|
||||||
|
irq_set_enabled(UART0_IRQ, true);
|
||||||
|
uart_set_irq_enables(uart0, true, false);
|
||||||
|
|
||||||
|
return pgt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPStimeDestroy(GPStimeContext **pp)
|
void GPStimeDestroy(GPStimeContext **pp)
|
||||||
|
@ -129,7 +135,7 @@ void __not_in_flash_func (GPStimePPScallback)(uint gpio, uint32_t events)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUGLOG
|
#ifdef NOP
|
||||||
const int64_t dt_1M = (dt_per_window + (eSlidingLen >> 1)) / eSlidingLen;
|
const int64_t dt_1M = (dt_per_window + (eSlidingLen >> 1)) / eSlidingLen;
|
||||||
const uint64_t tmp = (spGPStimeData->_u64_pps_period_1M + (eSlidingLen >> 1)) / eSlidingLen;
|
const uint64_t tmp = (spGPStimeData->_u64_pps_period_1M + (eSlidingLen >> 1)) / eSlidingLen;
|
||||||
printf("%llu %lld %llu %lld\n", spGPStimeData->_u64_sysclk_pps_last, dt_1M, tmp,
|
printf("%llu %lld %llu %lld\n", spGPStimeData->_u64_sysclk_pps_last, dt_1M, tmp,
|
||||||
|
@ -186,7 +192,9 @@ void __not_in_flash_func (GPStimeUartRxIsr)()
|
||||||
|
|
||||||
if(spGPStimeContext->_is_sentence_ready)
|
if(spGPStimeContext->_is_sentence_ready)
|
||||||
{
|
{
|
||||||
|
spGPStimeContext->_u8_ixw = 0;
|
||||||
spGPStimeContext->_i32_error_count -= GPStimeProcNMEAsentence(spGPStimeContext);
|
spGPStimeContext->_i32_error_count -= GPStimeProcNMEAsentence(spGPStimeContext);
|
||||||
|
//printf("err: %ld\n", spGPStimeContext->_i32_error_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,28 +203,105 @@ int GPStimeProcNMEAsentence(GPStimeContext *pg)
|
||||||
{
|
{
|
||||||
assert_(pg);
|
assert_(pg);
|
||||||
|
|
||||||
uint8_t *prmc = strnstr(pg->_pbytebuff, "$GPRMC", sizeof(pg->_pbytebuff));
|
uint8_t *prmc = (uint8_t *)strnstr((char *)pg->_pbytebuff, "$GPRMC,", sizeof(pg->_pbytebuff));
|
||||||
if(prmc)
|
if(prmc)
|
||||||
{
|
{
|
||||||
uint8_t u8ixcollector[16], chksum = '$'^'G'^'P'^'R'^'M'^'C'^',';
|
uint64_t tm_fix = GetUptime64();
|
||||||
for(uint8_t u8ix = prmc - pg->_pbytebuff + 7, i = 0;
|
|
||||||
u8ix != prmc - pg->_pbytebuff; ++u8ix)
|
uint8_t u8ixcollector[16] = {0};
|
||||||
|
uint8_t chksum = 0;
|
||||||
|
for(uint8_t u8ix = 0, i = 0; u8ix != sizeof(pg->_pbytebuff); ++u8ix)
|
||||||
{
|
{
|
||||||
chksum ^= pg->_pbytebuff[u8ix];
|
uint8_t *p = pg->_pbytebuff + u8ix;
|
||||||
if(',' == pg->_pbytebuff[u8ix])
|
chksum ^= *p;
|
||||||
|
if(',' == *p)
|
||||||
{
|
{
|
||||||
pg->_pbytebuff[u8ix] = 0;
|
*p = 0;
|
||||||
u8ixcollector[i++] = u8ix;
|
u8ixcollector[i++] = u8ix + 1;
|
||||||
if(12 == i)
|
if('*' == *p || 12 == i)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pg->_time_data._u8_is_solution_active = 'A' == prmc[u8ixcollector[1]];
|
||||||
|
|
||||||
|
if(pg->_time_data._u8_is_solution_active)
|
||||||
|
{
|
||||||
|
pg->_time_data._i64_lat_100k = (int64_t)(.5f + 1e5 * atof((const char *)prmc + u8ixcollector[2]));
|
||||||
|
if('N' == prmc[u8ixcollector[3]]) { }
|
||||||
|
else if('S' == prmc[u8ixcollector[3]])
|
||||||
|
{
|
||||||
|
INVERSE(pg->_time_data._i64_lat_100k);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg->_time_data._i64_lon_100k = (int64_t)(.5f + 1e5 * atof((const char *)prmc + u8ixcollector[4]));
|
||||||
|
if('E' == prmc[u8ixcollector[5]]) { }
|
||||||
|
else if('W' == prmc[u8ixcollector[5]])
|
||||||
|
{
|
||||||
|
INVERSE(pg->_time_data._i64_lon_100k);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if('*' != prmc[u8ixcollector[11] + 1])
|
||||||
|
{
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pg->_time_data._u32_utime_nmea_last = GPStime2UNIX(prmc + u8ixcollector[8], prmc + u8ixcollector[0]);
|
||||||
|
pg->_time_data._u64_sysclk_nmea_last = tm_fix;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
"$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
|
"$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GPStime2UNIX(const char *pdate, const char *ptime)
|
||||||
|
{
|
||||||
|
assert_(pdate);
|
||||||
|
assert_(ptime);
|
||||||
|
|
||||||
|
if(strlen(pdate) == 6 && strlen(ptime) > 5)
|
||||||
|
{
|
||||||
|
struct tm ltm = {0};
|
||||||
|
|
||||||
|
ltm.tm_year = 100 + DecimalStr2ToNumber(pdate + 4);
|
||||||
|
ltm.tm_mon = DecimalStr2ToNumber(pdate + 2) - 1;
|
||||||
|
ltm.tm_mday = DecimalStr2ToNumber(pdate);
|
||||||
|
|
||||||
|
ltm.tm_hour = DecimalStr2ToNumber(ptime);
|
||||||
|
ltm.tm_min = DecimalStr2ToNumber(ptime + 2);
|
||||||
|
ltm.tm_sec = DecimalStr2ToNumber(ptime + 4);
|
||||||
|
|
||||||
|
return mktime(<m);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPStimeDump(const GPStimeData *pd)
|
||||||
|
{
|
||||||
|
assert_(pd);
|
||||||
|
|
||||||
|
static int tick = 0;
|
||||||
|
|
||||||
|
printf("%u\nActive:%u\n", tick++, pd->_u8_is_solution_active);
|
||||||
|
printf("NMEA utime last:%lu\n", pd->_u32_utime_nmea_last);
|
||||||
|
printf("SYSCKL NMEA last:%llu\n", pd->_u64_sysclk_nmea_last);
|
||||||
|
printf("Lat:%lld Lon:%lld\n", pd->_i64_lat_100k, pd->_i64_lon_100k);
|
||||||
|
printf("SYSCKL PPS last:%llu\n", pd->_u64_sysclk_pps_last);
|
||||||
|
printf("PPS period e6:%llu\n", (pd->_u64_pps_period_1M + (eSlidingLen>>1)) / eSlidingLen);
|
||||||
|
printf("FRQ corr ppb:%lld\n\n", pd->_i32_freq_shift_ppb);
|
||||||
|
}
|
||||||
|
|
|
@ -11,27 +11,22 @@
|
||||||
//
|
//
|
||||||
// DESCRIPTION
|
// DESCRIPTION
|
||||||
//
|
//
|
||||||
// GPS time utilities for PioDco oscillator provides a precise reference
|
// GPS time utilities for PioDco oscillator calculates a precise frequency
|
||||||
// frequency in order to obtain an absolute accuracy of PioDco. The value of
|
// shift between the local Pico oscillator and reference oscill. of GPS system.
|
||||||
// this accuracy depends on quality of navigation solution of GPS receiver.
|
// The value of the shift is used to correct PioDco generated frequency. The
|
||||||
// This quality can be estimated by GDOP (geometric dilution of precision) and
|
// practical precision of this solution within tenths millihertz range.
|
||||||
// TDOP (time dilution of precision) received in NMEA-0183 message packet from
|
// The value of this accuracy depends on quality of navigation solution of GPS
|
||||||
// GPS receiver.
|
// receiver. This quality can be estimated by GDOP and TDOP parameters received
|
||||||
// The Pico's frequency error due to drift of its CLK oscillator is
|
// in NMEA-0183 message packet from GPS receiver.
|
||||||
// calculated by that utilities and is used to shift PioDco frequency to
|
|
||||||
// compensate the drift. So, the absolute frequency value which we possess
|
|
||||||
// on the GPIO pin is supposed to be much more accurate when using GPS time
|
|
||||||
// utilities.
|
|
||||||
// Owing to the meager PioDco frequency step in millihertz range, we obtain
|
// Owing to the meager PioDco frequency step in millihertz range, we obtain
|
||||||
// a quasi-analog precision frequency source.
|
// a quasi-analog precision frequency source (if the GPS navigation works ok).
|
||||||
// This is an experimental project of amateur radio class and it is devised
|
// This is an experimental project of amateur radio class and it is devised
|
||||||
// by me on the free will base in order to experiment with QRP narrowband
|
// by me on the free will base in order to experiment with QRP narrowband
|
||||||
// digital modes including extremely ones such as QRSS.
|
// digital modes including extremely ones such as QRSS.
|
||||||
// I gracefully appreciate any thoughts or comments on this matter.
|
// I gracefully appreciate any thoughts or comments on that matter.
|
||||||
//
|
//
|
||||||
// PLATFORM
|
// PLATFORM
|
||||||
// Raspberry Pi pico.
|
// Raspberry Pi pico.
|
||||||
// A GPS receiver module which supports PPS (pulse per second) output.
|
|
||||||
//
|
//
|
||||||
// REVISION HISTORY
|
// REVISION HISTORY
|
||||||
//
|
//
|
||||||
|
@ -70,6 +65,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "hardware/uart.h"
|
#include "hardware/uart.h"
|
||||||
#include "../defines.h"
|
#include "../defines.h"
|
||||||
|
@ -122,12 +118,14 @@ typedef struct
|
||||||
GPStimeContext *GPStimeInit(int uart_id, int uart_baud, int pps_gpio);
|
GPStimeContext *GPStimeInit(int uart_id, int uart_baud, int pps_gpio);
|
||||||
void GPStimeDestroy(GPStimeContext **pp);
|
void GPStimeDestroy(GPStimeContext **pp);
|
||||||
|
|
||||||
//void GPStimeProcessingTick(GPStimeContext *pg);
|
|
||||||
int GPStimeProcNMEAsentence(GPStimeContext *pg);
|
int GPStimeProcNMEAsentence(GPStimeContext *pg);
|
||||||
|
|
||||||
void __not_in_flash_func (GPStimePPScallback)(uint gpio, uint32_t events);
|
void __not_in_flash_func (GPStimePPScallback)(uint gpio, uint32_t events);
|
||||||
void __not_in_flash_func (GPStimeUartRxIsr)();
|
void __not_in_flash_func (GPStimeUartRxIsr)();
|
||||||
|
|
||||||
int GPStimeGetTime(const GPStimeContext *pg, uint32_t *u32_tmdst);
|
int GPStimeGetTime(const GPStimeContext *pg, uint32_t *u32_tmdst);
|
||||||
|
uint32_t GPStime2UNIX(const char *pdate, const char *ptime);
|
||||||
|
|
||||||
|
void GPStimeDump(const GPStimeData *pd);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
|
||||||
|
* Copyright (c) 1990, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to Berkeley by
|
||||||
|
* Chris Torek.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(LIBC_SCCS) && !defined(lint)
|
||||||
|
static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93";
|
||||||
|
#endif /* LIBC_SCCS and not lint */
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD: src/lib/libc/string/strnstr.c,v 1.5 2009/02/03 17:58:20 danger Exp $");
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the first occurrence of find in s, where the search is limited to the
|
||||||
|
* first slen characters of s.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
strnstr(const char *s, const char *find, size_t slen)
|
||||||
|
{
|
||||||
|
char c, sc;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if ((c = *find++) != '\0') {
|
||||||
|
len = strlen(find);
|
||||||
|
do {
|
||||||
|
do {
|
||||||
|
if (slen-- < 1 || (sc = *s++) == '\0')
|
||||||
|
return (NULL);
|
||||||
|
} while (sc != c);
|
||||||
|
if (len > slen)
|
||||||
|
return (NULL);
|
||||||
|
} while (strncmp(s, find, len) != 0);
|
||||||
|
s--;
|
||||||
|
}
|
||||||
|
return ((char *)s);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef STRNSTR_H_
|
||||||
|
#define STRNSTR_H_
|
||||||
|
|
||||||
|
char *
|
||||||
|
strnstr(const char *s, const char *find, size_t slen);
|
||||||
|
|
||||||
|
#endif
|
|
@ -22,4 +22,9 @@ inline uint32_t PicoU64timeToSeconds(uint64_t u64tm)
|
||||||
return u64tm / 1000000U; // No rounding deliberately!
|
return u64tm / 1000000U; // No rounding deliberately!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint32_t DecimalStr2ToNumber(const char *p)
|
||||||
|
{
|
||||||
|
return 10U * (p[0] - '0') + (p[1] - '0');
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
12
test.c
12
test.c
|
@ -216,13 +216,15 @@ int main()
|
||||||
set_sys_clock_khz(clkhz / 1000L, true);
|
set_sys_clock_khz(clkhz / 1000L, true);
|
||||||
|
|
||||||
stdio_init_all();
|
stdio_init_all();
|
||||||
|
sleep_ms(1000);
|
||||||
//uart_init(uart0, 9600);
|
printf("Start\n");
|
||||||
//gpio_set_function(0, GPIO_FUNC_UART);
|
|
||||||
//gpio_set_function(1, GPIO_FUNC_UART);
|
|
||||||
|
|
||||||
GPStimeContext *pGPS = GPStimeInit(0, 9600, 2);
|
GPStimeContext *pGPS = GPStimeInit(0, 9600, 2);
|
||||||
for(;;) {}
|
for(;;)
|
||||||
|
{
|
||||||
|
GPStimeDump(&(pGPS->_time_data));
|
||||||
|
sleep_ms(1000);
|
||||||
|
}
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
|
|
Ładowanie…
Reference in New Issue