Porównaj commity

...

5 Commity
v.0.51 ... main

Autor SHA1 Wiadomość Data
roman d11ef6b23f build scripts fixed. 2023-12-15 14:44:51 +03:00
Roman Piksaykin 70a86638df
Update README.md 2023-12-10 21:52:35 +03:00
roman 4f3e17e5a1 Major improvement pre-release: up to 10 meter band freq.range. Need to test though. 2023-12-10 21:49:59 +03:00
roman d9bac8da61 Pre-merge commit. 2023-12-10 21:49:59 +03:00
roman d28d20062a Devising auto-maidenhead + new pico-hf-oscillator integration. 2023-12-10 21:49:59 +03:00
12 zmienionych plików z 188 dodań i 30 usunięć

Wyświetl plik

@ -22,7 +22,7 @@ project(pico-wspr-tx C CXX ASM)
pico_sdk_init()
add_executable(pico-wspr-tx)
pico_generate_pio_header(pico-wspr-tx ${CMAKE_CURRENT_LIST_DIR}/pico-hf-oscillator/piodco/dco.pio)
pico_generate_pio_header(pico-wspr-tx ${CMAKE_CURRENT_LIST_DIR}/pico-hf-oscillator/piodco/dco2.pio)
target_sources(pico-wspr-tx PUBLIC
${CMAKE_CURRENT_LIST_DIR}/pico-hf-oscillator/lib/assert.c
@ -31,6 +31,7 @@ target_sources(pico-wspr-tx PUBLIC
${CMAKE_CURRENT_LIST_DIR}/TxChannel/TxChannel.c
${CMAKE_CURRENT_LIST_DIR}/WSPRbeacon/thirdparty/WSPRutility.c
${CMAKE_CURRENT_LIST_DIR}/WSPRbeacon/thirdparty/nhash.c
${CMAKE_CURRENT_LIST_DIR}/WSPRbeacon/thirdparty/maidenhead.c
${CMAKE_CURRENT_LIST_DIR}/WSPRbeacon/WSPRbeacon.c
${CMAKE_CURRENT_LIST_DIR}/debug/logutils.c
${CMAKE_CURRENT_LIST_DIR}/init.c

Wyświetl plik

@ -3,7 +3,7 @@ WSPR beacon for Raspberry Pi Pico, based on pico-hf-oscillator PLL DCO library a
The GPS reference is used to compensate Pico's clock drift. GPS is also used to schedule WSPR transmissions.
![image](https://github.com/RPiks/pico-WSPR-tx/assets/47501785/3f835a9d-fa42-4eb8-ba93-ea72033d9e62)
The example of this WSPR beacon (QRPX power level) reception. Max QRB is ~3400 km.
The example of this WSPR beacon (QRPX power level) reception. Last max QRB is ~3400 km on 40m band.
![image](https://github.com/RPiks/pico-WSPR-tx/assets/47501785/a86280b9-71cb-4bb2-8b3c-0e33d2499aca)
High spectrum quality and less than 1Hz frequency drift.
@ -28,7 +28,7 @@ My QRZ page is https://www.qrz.com/db/R2BDY
6. Load the .uf2 file (2) into the Pico.
7. Initialy the operating HF band is 40 meter (WSPR dial frequency is 7040 kHz).
7. Initialy the operating HF band is 17 meter (WSPR dial frequency is 18106 kHz).
8. Provide the feedback by clicking like on the github page of the project :).

Wyświetl plik

@ -113,7 +113,7 @@ TxChannelContext *TxChannelInit(const uint32_t bit_period_us, uint8_t timer_alar
/// @return A count of bytes.
uint8_t TxChannelPending(TxChannelContext *pctx)
{
return 256 + pctx->_ix_input - pctx->_ix_output;
return 256L + (int)pctx->_ix_input - (int)pctx->_ix_output;
}
/// @brief Push a number of bytes to the output FIFO.
@ -154,14 +154,3 @@ void TxChannelClear(TxChannelContext *pctx)
{
pctx->_ix_input = pctx->_ix_output = 0;
}
/*
void TxChannelStart(TxChannelContext *pctx)
{
pctx->_b_allowtx = YES;
}
void TxChannelStop(TxChannelContext *pctx)
{
pctx->_b_allowtx = NO;
}
*/

Wyświetl plik

@ -51,6 +51,7 @@
///////////////////////////////////////////////////////////////////////////////
#include "WSPRbeacon.h"
#include <WSPRutility.h>
#include <maidenhead.h>
/// @brief Initializes a new WSPR beacon context.
/// @param pcallsign HAM radio callsign, 12 chr max.
@ -112,7 +113,7 @@ int WSPRbeaconSendPacket(const WSPRbeaconContext *pctx)
{
assert_(pctx);
assert_(pctx->_pTX);
assert_(pctx->_pTX->_u32_dialfreqhz > 1100 * kHz);
assert_(pctx->_pTX->_u32_dialfreqhz > 500 * kHz);
TxChannelClear(pctx->_pTX);
@ -214,3 +215,30 @@ void WSPRbeaconDumpContext(const WSPRbeaconContext *pctx)
StampPrintf("pps:%llu", pGPS->_time_data._u64_sysclk_pps_last);
StampPrintf("ppb:%lld", pGPS->_time_data._i32_freq_shift_ppb);
}
/// @brief Extracts maidenhead type QTH locator (such as KO85) using GPS coords.
/// @param pctx Ptr to WSPR beacon context.
/// @return ptr to string of QTH locator (static duration object inside get_mh).
/// @remark It uses third-party project https://github.com/sp6q/maidenhead .
char *WSPRbeaconGetLastQTHLocator(const WSPRbeaconContext *pctx)
{
assert_(pctx);
assert_(pctx->_pTX);
assert_(pctx->_pTX->_p_oscillator);
assert_(pctx->_pTX->_p_oscillator->_pGPStime);
const double lat = 1e-5 * (double)pctx->_pTX->_p_oscillator->_pGPStime->_time_data._i64_lat_100k;
const double lon = 1e-5 * (double)pctx->_pTX->_p_oscillator->_pGPStime->_time_data._i64_lon_100k;
return get_mh(lat, lon, 8);
}
uint8_t WSPRbeaconIsGPSsolutionActive(const WSPRbeaconContext *pctx)
{
assert_(pctx);
assert_(pctx->_pTX);
assert_(pctx->_pTX->_p_oscillator);
assert_(pctx->_pTX->_p_oscillator->_pGPStime);
return YES == pctx->_pTX->_p_oscillator->_pGPStime->_time_data._u8_is_solution_active;
}

Wyświetl plik

@ -92,4 +92,7 @@ int WSPRbeaconTxScheduler(WSPRbeaconContext *pctx, int verbose);
void WSPRbeaconDumpContext(const WSPRbeaconContext *pctx);
char *WSPRbeaconGetLastQTHLocator(const WSPRbeaconContext *pctx);
uint8_t WSPRbeaconIsGPSsolutionActive(const WSPRbeaconContext *pctx);
#endif

Wyświetl plik

@ -0,0 +1,76 @@
#include "maidenhead.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
char letterize(int x) {
return (char) x + 65;
}
char* get_mh(double lat, double lon, int size) {
static char locator[11];
double LON_F[]={20,2.0,0.083333,0.008333,0.0003472083333333333};
double LAT_F[]={10,1.0,0.0416665,0.004166,0.0001735833333333333};
int i;
lon += 180;
lat += 90;
if (size <= 0 || size > 10) size = 6;
size/=2; size*=2;
for (i = 0; i < size/2; i++){
if (i % 2 == 1) {
locator[i*2] = (char) (lon/LON_F[i] + '0');
locator[i*2+1] = (char) (lat/LAT_F[i] + '0');
} else {
locator[i*2] = letterize((int) (lon/LON_F[i]));
locator[i*2+1] = letterize((int) (lat/LAT_F[i]));
}
lon = fmod(lon, LON_F[i]);
lat = fmod(lat, LAT_F[i]);
}
locator[i*2]=0;
return locator;
}
char* complete_mh(char* locator) {
static char locator2[11] = "LL55LL55LL";
int len = strlen(locator);
if (len >= 10) return locator;
memcpy(locator2, locator, strlen(locator));
return locator2;
}
double mh2lon(char* locator) {
double field, square, subsquare, extsquare, precsquare;
int len = strlen(locator);
if (len > 10) return 0;
if (len < 10) locator = complete_mh(locator);
field = (locator[0] - 'A') * 20.0;
square = (locator[2] - '0') * 2.0;
subsquare = (locator[4] - 'A') / 12.0;
extsquare = (locator[6] - '0') / 120.0;
precsquare = (locator[8] - 'A') / 2880.0;
return field + square + subsquare + extsquare + precsquare - 180;
}
double mh2lat(char* locator) {
double field, square, subsquare, extsquare, precsquare;
int len = strlen(locator);
if (len > 10) return 0;
if (len < 10) locator = complete_mh(locator);
field = (locator[1] - 'A') * 10.0;
square = (locator[3] - '0') * 1.0;
subsquare = (locator[5] - 'A') / 24.0;
extsquare = (locator[7] - '0') / 240.0;
precsquare = (locator[9] - 'A') / 5760.0;
return field + square + subsquare + extsquare + precsquare - 90;
}
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,16 @@
#ifndef MAIDENHEAD_H
#define MAIDENHEAD_H
#ifdef __cplusplus
extern "C" {
#endif
char* get_mh(double lat, double lon, int size);
char* complete_mh(char* locator);
double mh2lon(char* locator);
double mh2lat(char* locator);
#ifdef __cplusplus
}
#endif
#endif

Wyświetl plik

@ -1,6 +1,8 @@
#!/bin/bash
mkdir build
git submodule init
git submodule update
git submodule foreach git pull origin main
cd build
cmake ..

Wyświetl plik

@ -65,7 +65,6 @@ void Core1Entry()
assert_(pWSPR);
const uint32_t clkhz = PLL_SYS_MHZ * MHz;
const uint32_t freq_hz = pWSPR->_pTX->_u32_dialfreqhz;
PioDco *p = pWSPR->_pTX->_p_oscillator;
assert_(p);
@ -74,8 +73,8 @@ void Core1Entry()
assert_(0 == PioDCOInit(p, pWSPR->_pTX->_i_tx_gpio, clkhz));
/* Set initial freq. */
assert_(0 == PioDCOSetFreq(p, freq_hz, 0U));
assert_(0 == PioDCOSetFreq(p, pWSPR->_pTX->_u32_dialfreqhz, 0U));
/* Run the main DCO algorithm. It spins forever. */
PioDCOWorker(p);
PioDCOWorker2(p);
}

Wyświetl plik

@ -52,7 +52,7 @@
#ifndef DEFINESWSPR_H
#define DEFINESWSPR_H
//#define DEBUG
#define DEBUG
#ifdef DEBUG
#define DEBUGPRINTF(x) StampPrintf(x);
@ -78,6 +78,9 @@
/* A macro for arithmetic right shifts, with casting of the argument. */
#define iSAR(arg, rcount) (((int32_t)(arg)) >> (rcount))
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
/* A macro of multiplication guarantees of doing so using 1 ASM command. */
#define iMUL32ASM(a,b) __mul_instruction((int32_t)(a), (int32_t)(b))

59
main.c
Wyświetl plik

@ -66,6 +66,13 @@
#include <logutils.h>
#include <protos.h>
#define CONFIG_GPS_SOLUTION_IS_MANDATORY NO
#define CONFIG_GPS_RELY_ON_PAST_SOLUTION NO
#define CONFIG_SCHEDULE_SKIP_SLOT_COUNT 5
#define CONFIG_WSPR_DIAL_FREQUENCY 18106000UL //24926000UL // 28126000UL //7040000UL
#define CONFIG_CALLSIGN "R2BDY"
#define CONFIG_LOCATOR4 "KO85"
WSPRbeaconContext *pWSPR;
int main()
@ -81,21 +88,20 @@ int main()
StampPrintf("WSPR beacon init...");
WSPRbeaconContext *pWB = WSPRbeaconInit(
"R2BDY", /* the Callsign. */
"KO85", /* the QTH locator. */
16, /* Tx power, dbm. */
CONFIG_CALLSIGN,/* the Callsign. */
CONFIG_LOCATOR4,/* the default QTH locator if GPS isn't used. */
12, /* Tx power, dbm. */
&DCO, /* the PioDCO object. */
7040000UL, /* the dial frequency. */
CONFIG_WSPR_DIAL_FREQUENCY,
55UL, /* the carrier freq. shift relative to dial freq. */
RFOUT_PIN /* RF output GPIO pin. */
);
assert_(pWB);
pWSPR = pWB;
pWB->_txSched._u8_tx_GPS_mandatory = YES; /* Send WSPR signals only when GPS solution is active. */
pWB->_txSched._u8_tx_GPS_past_time = YES; /* ?relying on GPS solution in the past. */
pWB->_txSched._u8_tx_slot_skip = 2; /* 1 slot tx, 1 slot idle, etc. */
pWB->_txSched._u8_tx_heating_pause_min = 1; /* Give 1 minute pre-heating ere first transmition. */
pWB->_txSched._u8_tx_GPS_mandatory = CONFIG_GPS_SOLUTION_IS_MANDATORY;
pWB->_txSched._u8_tx_GPS_past_time = CONFIG_GPS_RELY_ON_PAST_SOLUTION;
pWB->_txSched._u8_tx_slot_skip = CONFIG_SCHEDULE_SKIP_SLOT_COUNT;
multicore_launch_core1(Core1Entry);
StampPrintf("RF oscillator started.");
@ -106,7 +112,42 @@ int main()
int tick = 0;
for(;;)
{
WSPRbeaconTxScheduler(pWB, YES);
/*
if(WSPRbeaconIsGPSsolutionActive(pWB))
{
const char *pgps_qth = WSPRbeaconGetLastQTHLocator(pWB);
if(pgps_qth)
{
strncpy(pWB->_pu8_locator, pgps_qth, 4);
pWB->_pu8_locator[5] = 0x00;
}
}
*/
if(pWB->_txSched._u8_tx_GPS_mandatory)
{
WSPRbeaconTxScheduler(pWB, YES);
}
else
{
StampPrintf("Omitting GPS solution, start tx now.");
PioDCOStart(pWB->_pTX->_p_oscillator);
WSPRbeaconCreatePacket(pWB);
sleep_ms(100);
WSPRbeaconSendPacket(pWB);
StampPrintf("The system will be halted when tx is completed.");
for(;;)
{
if(!TxChannelPending(pWB->_pTX))
{
PioDCOStop(pWB->_pTX->_p_oscillator);
StampPrintf("System halted.");
}
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(500);
gpio_put(PICO_DEFAULT_LED_PIN, 0);
}
}
gpio_put(PICO_DEFAULT_LED_PIN, 1);
sleep_ms(100);

@ -1 +1 @@
Subproject commit 01dbdefbaf1964246bfb66383ceeccea63aa6c60
Subproject commit 9fbd9fa407423c89af9c4878340e71446c948f66