mirror of
https://github.com/radio95-rnt/fm95.git
synced 2026-02-26 19:23:51 +01:00
add psk
This commit is contained in:
2
.vscode/.server-controller-port.log
vendored
2
.vscode/.server-controller-port.log
vendored
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"port": 13452,
|
"port": 13452,
|
||||||
"time": 1741524942188,
|
"time": 1741529730555,
|
||||||
"version": "0.0.3"
|
"version": "0.0.3"
|
||||||
}
|
}
|
||||||
102
src/dcf95.c
102
src/dcf95.c
@@ -4,6 +4,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#define buffer_maxlength 2048
|
#define buffer_maxlength 2048
|
||||||
#define buffer_tlength_fragsize 2048
|
#define buffer_tlength_fragsize 2048
|
||||||
@@ -33,6 +34,13 @@
|
|||||||
#define REDUCED_AMPLITUDE 0.15f // Reduced to 15% of normal amplitude during pulses
|
#define REDUCED_AMPLITUDE 0.15f // Reduced to 15% of normal amplitude during pulses
|
||||||
#define BIT_LENGTH 1000 // 1 second per bit
|
#define BIT_LENGTH 1000 // 1 second per bit
|
||||||
|
|
||||||
|
// DSSS Parameters
|
||||||
|
#define DSSS_START_MS 200 // DSSS starts at 200ms into the second
|
||||||
|
#define DSSS_DURATION_MS 793 // DSSS duration is 793ms
|
||||||
|
#define PHASE_SHIFT 15.6 // Phase shift in degrees (±15.6°)
|
||||||
|
#define CHIPS_PER_BIT 512 // Number of chips per bit
|
||||||
|
#define CHIP_CYCLES 120 // Each chip spans 120 cycles
|
||||||
|
|
||||||
volatile sig_atomic_t to_run = 1;
|
volatile sig_atomic_t to_run = 1;
|
||||||
volatile sig_atomic_t transmitting = 0;
|
volatile sig_atomic_t transmitting = 0;
|
||||||
volatile int bit_position = 0;
|
volatile int bit_position = 0;
|
||||||
@@ -41,12 +49,31 @@ volatile int test_mode = 0; // 0 = normal, 1 = test mode
|
|||||||
// DCF77 bits array (59 bits, indexed 0-58)
|
// DCF77 bits array (59 bits, indexed 0-58)
|
||||||
volatile int dcf77_bits[60]; // 60th position is for the 1-second pause
|
volatile int dcf77_bits[60]; // 60th position is for the 1-second pause
|
||||||
|
|
||||||
|
// LFSR state for DSSS
|
||||||
|
unsigned int lfsr = 0;
|
||||||
|
|
||||||
static void stop(int signum) {
|
static void stop(int signum) {
|
||||||
(void)signum;
|
(void)signum;
|
||||||
printf("\nReceived stop signal.\n");
|
printf("\nReceived stop signal.\n");
|
||||||
to_run = 0;
|
to_run = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate next chip from LFSR
|
||||||
|
unsigned int generate_chip() {
|
||||||
|
unsigned int chip = lfsr & 1;
|
||||||
|
|
||||||
|
lfsr >>= 1;
|
||||||
|
if (chip || !lfsr)
|
||||||
|
lfsr ^= 0x110;
|
||||||
|
|
||||||
|
return chip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset LFSR state at the beginning of each second
|
||||||
|
void reset_lfsr() {
|
||||||
|
lfsr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to determine if a given time is in DST for CET
|
// Helper function to determine if a given time is in DST for CET
|
||||||
int is_cet_dst(struct tm *tm_time) {
|
int is_cet_dst(struct tm *tm_time) {
|
||||||
// CET DST rules: starts last Sunday of March at 2:00, ends last Sunday of October at 3:00
|
// CET DST rules: starts last Sunday of March at 2:00, ends last Sunday of October at 3:00
|
||||||
@@ -78,6 +105,7 @@ int is_cet_dst(struct tm *tm_time) {
|
|||||||
|
|
||||||
return 0; // Not in DST
|
return 0; // Not in DST
|
||||||
}
|
}
|
||||||
|
|
||||||
int is_timezone_change_soon() {
|
int is_timezone_change_soon() {
|
||||||
time_t now, in_an_hour;
|
time_t now, in_an_hour;
|
||||||
struct tm cet_now, cet_later;
|
struct tm cet_now, cet_later;
|
||||||
@@ -306,7 +334,7 @@ int main(int argc, char **argv) {
|
|||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
if(test_mode) {
|
if(test_mode) {
|
||||||
time_t now = time(NULL) + offset;
|
time_t now = time(NULL) + offset + 60;
|
||||||
calculate_dcf77_bits(now, (int *)dcf77_bits);
|
calculate_dcf77_bits(now, (int *)dcf77_bits);
|
||||||
print_dcf77_bits((int *)dcf77_bits);
|
print_dcf77_bits((int *)dcf77_bits);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -318,6 +346,7 @@ int main(int argc, char **argv) {
|
|||||||
printf(" Sample rate: %d Hz\n", sample_rate);
|
printf(" Sample rate: %d Hz\n", sample_rate);
|
||||||
printf(" Volume: %.2f\n", master_volume);
|
printf(" Volume: %.2f\n", master_volume);
|
||||||
printf(" Time offset: %d seconds\n", offset);
|
printf(" Time offset: %d seconds\n", offset);
|
||||||
|
printf(" Phase modulation: +/- %.1f degrees\n", PHASE_SHIFT);
|
||||||
|
|
||||||
// #region Setup devices
|
// #region Setup devices
|
||||||
pa_sample_spec mono_format = {
|
pa_sample_spec mono_format = {
|
||||||
@@ -379,6 +408,17 @@ int main(int argc, char **argv) {
|
|||||||
int pulse_0_samples = (int)((PULSE_0_DURATION / 1000.0) * sample_rate);
|
int pulse_0_samples = (int)((PULSE_0_DURATION / 1000.0) * sample_rate);
|
||||||
int pulse_1_samples = (int)((PULSE_1_DURATION / 1000.0) * sample_rate);
|
int pulse_1_samples = (int)((PULSE_1_DURATION / 1000.0) * sample_rate);
|
||||||
|
|
||||||
|
// DSSS parameters
|
||||||
|
int dsss_start_samples = (int)((DSSS_START_MS / 1000.0) * sample_rate);
|
||||||
|
int dsss_duration_samples = (int)((DSSS_DURATION_MS / 1000.0) * sample_rate);
|
||||||
|
int dsss_end_samples = dsss_start_samples + dsss_duration_samples;
|
||||||
|
float phase_shift_rad = (PHASE_SHIFT * M_PI) / 180.0; // Convert degrees to radians
|
||||||
|
|
||||||
|
// For tracking chip generation
|
||||||
|
int current_chip_count = 0;
|
||||||
|
int current_cycle_count = 0;
|
||||||
|
int in_dsss_period = 0;
|
||||||
|
|
||||||
printf("DCF77 encoder ready.\n");
|
printf("DCF77 encoder ready.\n");
|
||||||
printf("Will transmit time signal continuously.\n");
|
printf("Will transmit time signal continuously.\n");
|
||||||
|
|
||||||
@@ -388,7 +428,7 @@ int main(int argc, char **argv) {
|
|||||||
memset(output, 0, sizeof(output));
|
memset(output, 0, sizeof(output));
|
||||||
|
|
||||||
// Get current time
|
// Get current time
|
||||||
time_t now = time(NULL) + offset;
|
time_t now = time(NULL) + offset + 60; // Next minute
|
||||||
struct tm *t = gmtime(&now);
|
struct tm *t = gmtime(&now);
|
||||||
int second = t->tm_sec;
|
int second = t->tm_sec;
|
||||||
|
|
||||||
@@ -415,6 +455,11 @@ int main(int argc, char **argv) {
|
|||||||
if (second != current_second) {
|
if (second != current_second) {
|
||||||
current_second = second;
|
current_second = second;
|
||||||
|
|
||||||
|
// Reset the LFSR at the start of each second for DSSS
|
||||||
|
reset_lfsr();
|
||||||
|
current_chip_count = 0;
|
||||||
|
current_cycle_count = 0;
|
||||||
|
|
||||||
// Update the bit position at the start of each second
|
// Update the bit position at the start of each second
|
||||||
if (transmitting) {
|
if (transmitting) {
|
||||||
if (bit_position < 59) {
|
if (bit_position < 59) {
|
||||||
@@ -436,17 +481,52 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
// Generate the DCF77 signal
|
// Generate the DCF77 signal
|
||||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
// Get base carrier signal
|
// Calculate milliseconds within the current second
|
||||||
float carrier = get_oscillator_sin_sample(&osc);
|
ms_within_second = (int)((elapsed_samples * 1000.0) / sample_rate);
|
||||||
|
|
||||||
|
// Get the current bit (between 0-58)
|
||||||
|
int current_bit = bit_position > 0 ? bit_position - 1 : 59;
|
||||||
|
|
||||||
|
// Determine if we're in the DSSS period (between 200ms and 993ms)
|
||||||
|
in_dsss_period = (elapsed_samples >= dsss_start_samples &&
|
||||||
|
elapsed_samples < dsss_end_samples);
|
||||||
|
|
||||||
|
// Base carrier signal (will be phase-shifted if in DSSS period)
|
||||||
|
float phase_offset = 0.0;
|
||||||
|
|
||||||
|
// Apply DSSS if in the appropriate time window
|
||||||
|
if (in_dsss_period && transmitting) {
|
||||||
|
// Generate a chip every CHIP_CYCLES carrier cycles
|
||||||
|
if (current_cycle_count == 0) {
|
||||||
|
if (current_chip_count < CHIPS_PER_BIT) {
|
||||||
|
// Generate the next chip
|
||||||
|
unsigned int chip = generate_chip();
|
||||||
|
|
||||||
|
// XOR the chip with the current bit value
|
||||||
|
unsigned int modulated_chip = chip ^ dcf77_bits[current_bit];
|
||||||
|
|
||||||
|
// Set phase shift based on the modulated chip
|
||||||
|
if (modulated_chip == 0) {
|
||||||
|
phase_offset = phase_shift_rad; // +15.6 degrees
|
||||||
|
} else {
|
||||||
|
phase_offset = -phase_shift_rad; // -15.6 degrees
|
||||||
|
}
|
||||||
|
|
||||||
|
current_chip_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update cycle counter within each chip
|
||||||
|
current_cycle_count = (current_cycle_count + 1) % CHIP_CYCLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get carrier signal with phase offset if needed
|
||||||
|
float t = osc.phase + phase_offset;
|
||||||
|
float carrier = sin(t);
|
||||||
|
advance_oscillator(&osc);
|
||||||
|
|
||||||
if (transmitting) {
|
if (transmitting) {
|
||||||
// Calculate milliseconds within the current second
|
// Determine amplitude based on AM modulation pattern
|
||||||
ms_within_second = (int)((elapsed_samples * 1000.0) / sample_rate);
|
|
||||||
|
|
||||||
// Get the current bit (between 0-58)
|
|
||||||
int current_bit = bit_position > 0 ? bit_position - 1 : 59;
|
|
||||||
|
|
||||||
// Determine if we should output reduced amplitude
|
|
||||||
if ((dcf77_bits[current_bit] == 0 && ms_within_second < PULSE_0_DURATION) ||
|
if ((dcf77_bits[current_bit] == 0 && ms_within_second < PULSE_0_DURATION) ||
|
||||||
(dcf77_bits[current_bit] == 1 && ms_within_second < PULSE_1_DURATION)) {
|
(dcf77_bits[current_bit] == 1 && ms_within_second < PULSE_1_DURATION)) {
|
||||||
// Reduced amplitude during pulse
|
// Reduced amplitude during pulse
|
||||||
|
|||||||
Reference in New Issue
Block a user