-
Notifications
You must be signed in to change notification settings - Fork 573
Open
Description
i'm trying to impliment my custom digital protocol (BPFSK https://github.com/elapt1c/BPFSK) and when doing sendiq, it makes a really long tone and i dont know why or how to remove it.
import struct
import numpy as np
import scipy.io.wavfile as wavfile
import subprocess
import os
from flask import Flask, request
# Configuration (Adjust as needed)
CARRIER_FREQUENCY = 13553000
CHANNEL_FREQUENCIES = {
1: 440, 2: 523, 3: 587, 4: 659, 5: 784,
6: 880, 7: 988, 8: 1047, 9: 1175, 10: 1319
}
SAMPLE_RATE = 48000
CHANNEL_DURATION = 0.01
PREAMBLE_DURATION = 1
WAV_FILE = "bpfsk.wav"
CSDR_PATH = "/usr/bin/csdr"
SENDIQ_PATH = "./sendiq"
SILENCE_DURATION = 1 # Initial silence duration
LOOP_SILENCE_DURATION = 1 # Silence duration during the loop
app = Flask(__name__)
# Functions
def generate_tone_data(frequency, duration):
"""Generates sine wave data for a given frequency and duration."""
t = np.linspace(0, duration, int(SAMPLE_RATE * duration), endpoint=False)
data = np.sin(2 * np.pi * frequency * t)
data = (data * 32767).astype(np.int16)
return data
def get_channel_sequence(message):
"""Encodes the message using BPFSK and returns the channel sequence."""
channel_sequence = [1] # Preamble
channel_sequence.extend([2, 3, 4, 5, 6, 7, 8, 9, 10]) # Training
for char in message:
byte_val = ord(char)
for i in range(8):
if (byte_val >> i) & 1:
channel_sequence.append(i + 3)
channel_sequence.append(2) # Byte separator
channel_sequence.append(1) # Postamble
return channel_sequence
def generate_silence(duration):
"""Generates silence data for a given duration."""
num_samples = int(SAMPLE_RATE * duration)
return np.zeros(num_samples, dtype=np.int16)
def encode_bpfsk_to_wav(message, channel_duration, preamble_duration):
"""Encodes BPFSK into a WAV file."""
channel_sequence = get_channel_sequence(message)
audio_data = np.array([]) # Start with an empty array
for channel in channel_sequence:
duration = channel_duration if channel != 1 else preamble_duration
frequency = CHANNEL_FREQUENCIES.get(channel)
if frequency:
audio_data = np.concatenate((audio_data, generate_tone_data(frequency, duration)))
try:
wavfile.write(WAV_FILE, SAMPLE_RATE, audio_data.astype(np.int16))
print(f"WAV data written to {WAV_FILE}")
return True
except Exception as e:
print(f"Error writing WAV data: {e}")
return False
def transmit_bpfsk_wav(wav_file):
"""Transmits the given WAV file using csdr and sendiq."""
command = f"cat {wav_file} | {CSDR_PATH} convert_i16_f | {CSDR_PATH} fir_interpolate_cc 2 | {CSDR_PATH} dsb_fc | {CSDR_PATH} bandpass_fir_fft_cc 0.002 0.06 0.01 | {CSDR_PATH} fastagc_ff | sudo {SENDIQ_PATH} -i /dev/stdin -s 96000 -f {CARRIER_FREQUENCY} -t float"
print(f"Executing command: {command}")
try:
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
if process.returncode != 0:
print(f"Error: Transmission pipeline returned code {process.returncode}")
if stderr:
print(f"Pipeline error output: {stderr.decode()}")
else:
print("Pipeline: No error output available.")
if stdout:
print(f"Pipeline standard output: {stdout.decode()}")
except FileNotFoundError as e:
print(f"Error: Executable not found: {e.filename}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
# Initial silence transmission
def transmit_silence():
"""Transmits silence indefinitely."""
silence_data = generate_silence(LOOP_SILENCE_DURATION)
silence_file = "silence.wav"
wavfile.write(silence_file, SAMPLE_RATE, silence_data)
#Build code
command = f"cat {silence_file} | {CSDR_PATH} convert_i16_f | {CSDR_PATH} fir_interpolate_cc 2 | {CSDR_PATH} dsb_fc | {CSDR_PATH} bandpass_fir_fft_cc 0.002 0.06 0.01 | {CSDR_PATH} fastagc_ff | sudo {SENDIQ_PATH} -i /dev/stdin -s 96000 -f {CARRIER_FREQUENCY} -t float"
print(f"Transmitting Initial Silence")
process = subprocess.Popen(command, shell=True) #Keep the process running
return process
# REST APIs
initial_process = transmit_silence()
@app.route('/transmit', methods=['POST'])
def transmit_message():
message = request.form['message']
print(f"Received message: {message}")
# Kill previous process to clean start
global initial_process # Global variable to prevent multiple transmission instances.
initial_process.kill()
time.sleep(0.1) #Wait for kill to run
if encode_bpfsk_to_wav(message, CHANNEL_DURATION, PREAMBLE_DURATION):
transmit_bpfsk_wav(WAV_FILE)
print("Transmission Complete.")
else:
print("Encoding failed. Transmission aborted.")
#Restart
initial_process = transmit_silence()
return "Message transmitted!", 200
if __name__ == "__main__":
print("BPFSK Transmitter Starting...")
app.run(host='0.0.0.0', port=5051, debug=False) #Enable access on all IP addresses for ease.```
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
