Debugging almost finished. It decodes NMEA and calculates freq shift & ready to make timewindowed WSPR.

gpstest
roman 2023-11-26 02:59:05 +03:00
rodzic f0e79b50bc
commit 735698ec94
8 zmienionych plików z 200 dodań i 32 usunięć

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

65
lib/thirdparty/strnstr.c vendored 100644
Wyświetl plik

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

7
lib/thirdparty/strnstr.h vendored 100644
Wyświetl plik

@ -0,0 +1,7 @@
#ifndef STRNSTR_H_
#define STRNSTR_H_
char *
strnstr(const char *s, const char *find, size_t slen);
#endif

Wyświetl plik

@ -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
Wyświetl plik

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