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
|
||||
${CMAKE_CURRENT_LIST_DIR}/lib/assert.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}/gpstime/GPStime.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/test.c
|
||||
|
|
|
@ -78,4 +78,8 @@
|
|||
|
||||
#define ABS(x) ((x) > 0 ? (x) : -(x))
|
||||
|
||||
#define INVERSE(x) ((x) = -(x))
|
||||
|
||||
#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
|
||||
|
||||
#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.
|
||||
//
|
||||
// DESCRIPTION
|
||||
//
|
||||
// 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
|
||||
// practical precision of this solution within tenths millihertz range.
|
||||
// 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_set_dir(pps_gpio, GPIO_IN);
|
||||
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)
|
||||
|
@ -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 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,
|
||||
|
@ -186,7 +192,9 @@ void __not_in_flash_func (GPStimeUartRxIsr)()
|
|||
|
||||
if(spGPStimeContext->_is_sentence_ready)
|
||||
{
|
||||
spGPStimeContext->_u8_ixw = 0;
|
||||
spGPStimeContext->_i32_error_count -= GPStimeProcNMEAsentence(spGPStimeContext);
|
||||
//printf("err: %ld\n", spGPStimeContext->_i32_error_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,28 +203,105 @@ int GPStimeProcNMEAsentence(GPStimeContext *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)
|
||||
{
|
||||
uint8_t u8ixcollector[16], chksum = '$'^'G'^'P'^'R'^'M'^'C'^',';
|
||||
for(uint8_t u8ix = prmc - pg->_pbytebuff + 7, i = 0;
|
||||
u8ix != prmc - pg->_pbytebuff; ++u8ix)
|
||||
uint64_t tm_fix = GetUptime64();
|
||||
|
||||
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];
|
||||
if(',' == pg->_pbytebuff[u8ix])
|
||||
uint8_t *p = pg->_pbytebuff + u8ix;
|
||||
chksum ^= *p;
|
||||
if(',' == *p)
|
||||
{
|
||||
pg->_pbytebuff[u8ix] = 0;
|
||||
u8ixcollector[i++] = u8ix;
|
||||
if(12 == i)
|
||||
*p = 0;
|
||||
u8ixcollector[i++] = u8ix + 1;
|
||||
if('*' == *p || 12 == i)
|
||||
{
|
||||
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";
|
||||
*/
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
//
|
||||
// GPS time utilities for PioDco oscillator provides a precise reference
|
||||
// frequency in order to obtain an absolute accuracy of PioDco. The value of
|
||||
// this accuracy depends on quality of navigation solution of GPS receiver.
|
||||
// This quality can be estimated by GDOP (geometric dilution of precision) and
|
||||
// TDOP (time dilution of precision) received in NMEA-0183 message packet from
|
||||
// GPS receiver.
|
||||
// The Pico's frequency error due to drift of its CLK oscillator is
|
||||
// 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.
|
||||
// GPS time utilities for PioDco oscillator calculates a precise frequency
|
||||
// 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
|
||||
// practical precision of this solution within tenths millihertz range.
|
||||
// The value of this accuracy depends on quality of navigation solution of GPS
|
||||
// receiver. This quality can be estimated by GDOP and TDOP parameters received
|
||||
// in NMEA-0183 message packet from GPS receiver.
|
||||
// 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
|
||||
// by me on the free will base in order to experiment with QRP narrowband
|
||||
// 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
|
||||
// Raspberry Pi pico.
|
||||
// A GPS receiver module which supports PPS (pulse per second) output.
|
||||
//
|
||||
// REVISION HISTORY
|
||||
//
|
||||
|
@ -70,6 +65,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/uart.h"
|
||||
#include "../defines.h"
|
||||
|
@ -122,12 +118,14 @@ typedef struct
|
|||
GPStimeContext *GPStimeInit(int uart_id, int uart_baud, int pps_gpio);
|
||||
void GPStimeDestroy(GPStimeContext **pp);
|
||||
|
||||
//void GPStimeProcessingTick(GPStimeContext *pg);
|
||||
int GPStimeProcNMEAsentence(GPStimeContext *pg);
|
||||
|
||||
void __not_in_flash_func (GPStimePPScallback)(uint gpio, uint32_t events);
|
||||
void __not_in_flash_func (GPStimeUartRxIsr)();
|
||||
|
||||
int GPStimeGetTime(const GPStimeContext *pg, uint32_t *u32_tmdst);
|
||||
uint32_t GPStime2UNIX(const char *pdate, const char *ptime);
|
||||
|
||||
void GPStimeDump(const GPStimeData *pd);
|
||||
|
||||
#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!
|
||||
}
|
||||
|
||||
inline uint32_t DecimalStr2ToNumber(const char *p)
|
||||
{
|
||||
return 10U * (p[0] - '0') + (p[1] - '0');
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
12
test.c
12
test.c
|
@ -216,13 +216,15 @@ int main()
|
|||
set_sys_clock_khz(clkhz / 1000L, true);
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
//uart_init(uart0, 9600);
|
||||
//gpio_set_function(0, GPIO_FUNC_UART);
|
||||
//gpio_set_function(1, GPIO_FUNC_UART);
|
||||
sleep_ms(1000);
|
||||
printf("Start\n");
|
||||
|
||||
GPStimeContext *pGPS = GPStimeInit(0, 9600, 2);
|
||||
for(;;) {}
|
||||
for(;;)
|
||||
{
|
||||
GPStimeDump(&(pGPS->_time_data));
|
||||
sleep_ms(1000);
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
|
Ładowanie…
Reference in New Issue