Skip to content

long annoying tone before sendiq #342

@elapt1c

Description

@elapt1c

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.

Image

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.```

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions