RPiks / pico-hf-oscillator

Digital controlled radio frequency oscillator based on Raspberry Pi Pico (1 Hz to ~32.333 MHz band). RTTY, MFSK, freq sweep examples are included.
MIT License
36 stars 12 forks source link

programming challenge: impliment my data transmission protocol into a pico #5

Open elapt1c opened 2 hours ago

elapt1c commented 2 hours ago

an explanation of how the protocol works

it has a bunch of "channels" which are set frequency offsets. you split a byte into a list of channel numbers. so like 0101 would be channels 2 and 4, then you go through and put a tone through on that frequency (its usually better to just have a continuous tone and change the tone to each channel though) and you would actually have every binary position channel offset so we can fit some extra data in. so you can think of it like: (preamble/postamble) | (byte seperator) | (other channels that can show byte position) the preamble plays for 1 whole second, then it sends a byte (goes through and puts a tone on the first set channel, then the next, until all the byte places are sent), then play a byte seperator to show that the byte is done, then go on to the next and do that until all the bytes are done, play 1 second postamble and then the transmission is finished. so an example of a transmission would be as follows (each number is the channel currently being transmitted) |1|4578(2)567(2)468(2)|1| the (2) is a byte seperator and the |1| is the pre/postamble and the rest is the position of bits the byte 4578 is 01101100 for example we can skip the 0's places which makes this decently efficient. it also can have variable transmission speed so bytes with small amounts of 1's go really fast I want to see this implimented on a pi pico using pico-hf-oscilator also a way to communicate to it with serial connection such as commands to change bandwith or frequency or change transmission speed and send messages would be really nice too

I dont know anything other than python myself but im hoping somebody will be bored enough or nice enough to help out :)

I have code that successfully impliments my protocol with python and plays the frequencies on speakers, though the code is a little messy and the channel numbers are shifted to unneeded numbers, it still works as an example of how it functions.

elapt1c commented 2 hours ago

import sounddevice as sd
from scipy.io.wavfile import write

# Global variables
stream = None
current_frequency = 0
audio_buffer = []  # Buffer to store audio data

# Define the frequency channels (22 channels from 200 Hz to 2200 Hz)
base_frequency = 200
checksum_freq = 8
frequencies = [base_frequency * (i + 1) for i in range(22)]

def audio_callback(outdata, frames, time, status):
    """Callback function to generate audio."""
    global current_frequency, audio_buffer
    if status:
        print(status)

    t = np.linspace(0, frames / 44100, frames, False)  # Create time array for the frames
    tone = 0.5 * np.sin(2 * np.pi * current_frequency * t)  # Generate sine wave
    outdata[:] = tone.reshape(-1, 1)  # Output to sound device

    # Append the generated audio to buffer
    audio_buffer.extend(tone)

def start_audio():
    """Start the audio stream."""
    global stream
    stream = sd.OutputStream(samplerate=44100, channels=1, dtype='float32', callback=audio_callback)
    stream.start()

def change_frequency(channel_index):
    """Change the frequency of the currently playing audio using channel index."""
    global current_frequency
    current_frequency = frequencies[channel_index]  # Update the current frequency

def stop_audio():
    """Stop the audio playback."""
    global stream
    if stream is not None:
        stream.stop()
        stream.close()
        stream = None

def save_audio_to_wav(filename='output.wav'):
    """Save the buffered audio data to a WAV file."""
    global audio_buffer
    audio_data = np.array(audio_buffer)
    scaled_audio = np.int16(audio_data / np.max(np.abs(audio_data)) * 32767)  # Scale to 16-bit PCM format
    write(filename, 44100, scaled_audio)  # Write audio data to WAV file

def encode_and_play(message, speed):
    """Encode a message with simple error correction and play the corresponding audio."""
    global audio_buffer
    audio_buffer = []  # Reset the audio buffer

    # Start the audio stream before playing
    start_audio()
    change_frequency(2)  # Preamble
    sd.sleep(1000)

    byte_count = 0
    checksum = 0

    for char in message:
        byte = ord(char)
        checksum ^= byte  # XOR checksum

        for i in range(8):
            if byte & (1 << i):
                change_frequency(i + 4)  # Change to channel index for "1"
                sd.sleep(int(speed))
        change_frequency(3)  # Separator
        sd.sleep(int(speed))

        byte_count += 1
        if byte_count == checksum_freq + 1:
            # Send checksum
            for i in range(8):
                if checksum & (1 << i):
                    change_frequency(i + 4)  # Change to channel index for "1"
                    sd.sleep(int(speed))
            change_frequency(3)  # Separator
            sd.sleep(int(speed))

            byte_count = 0
            checksum = 0

    # Send any remaining data with padding
    if byte_count > 0:
        while byte_count < 9:
            change_frequency(3)  # Separator (padding)
            sd.sleep(int(speed))
            byte_count += 1

        # Send final checksum
        for i in range(8):
            if checksum & (1 << i):
                change_frequency(i + 4)  # Change to channel index for "1"
                sd.sleep(int(speed))
        change_frequency(3)  # Separator
        sd.sleep(int(speed))
    change_frequency(2)  # Postamble
    sd.sleep(1000)

    # Stop audio playback at the end
    stop_audio()

    # Save the buffered audio to a WAV file for future use
    save_audio_to_wav()

# Example usage
encode_and_play("""

Title: The Beauty of Nature

Nature is a magnificent tapestry woven with vibrant colors, soothing sounds, and intricate patterns. From the towering peaks of majestic mountains to the serene tranquility of a calm lake, the natural world captivates our senses and rejuvenates our spirits.

As dawn breaks, the sun gently kisses the horizon, casting a golden glow across the landscape. Birds chirp melodiously, heralding the start of a new day, while the gentle rustle of leaves dances with the soft breeze. This morning symphony is a reminder of the beauty that surrounds us.

In the heart of the forest, sunlight filters through the canopy, creating a mosaic of light and shadow on the forest floor. Each step unveils new wonders—a delicate flower peeking through the underbrush, a squirrel playfully darting up a tree, or a stream bubbling over smooth stones, singing its timeless song.

The changing seasons bring their own unique charm. Spring awakens the earth, dressing it in a riot of colors as flowers bloom and trees burst into life. Summer invites us to bask in the sun's warm embrace, offering long days filled with adventure and exploration. Autumn paints the world in hues of gold, orange, and red, while winter blankets it in serene white, transforming landscapes into a quiet wonderland.

Nature not only offers us beauty but also teaches us valuable lessons. It reminds us of the importance of balance and harmony, showcasing the interconnectedness of all living things. Every creature, no matter how small, plays a role in maintaining the delicate ecosystem we depend on.

In our fast-paced lives, it's easy to forget the wonders of the natural world. Yet, by taking a moment to step outside, breathe in the fresh air, and observe the intricacies of nature, we can find peace and inspiration. So, let us cherish and protect this precious gift, ensuring that future generations can also experience the beauty that nature has to offer.

""", 50)```
elapt1c commented 2 hours ago

also checksums can be ditched, i included them in the python code since i was testing computer-to-computer communication using speakers and microphone and the error correction seemed to help the data get from 1 side to the other properly