main
eleccoder 2021-08-01 00:26:44 +02:00
rodzic c62bc512e9
commit bec0acb344
1 zmienionych plików z 204 dodań i 0 usunięć

Wyświetl plik

@ -1,4 +1,208 @@
/*
* Project 'raspi-pico-aprs-tnc'
* Copyright (C) 2021 Thomas Glau, DL3TG
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdio.h>
#include <math.h>
#include <pico/stdlib.h>
#include <pico/audio_pwm.h>
#include <ax25beacon.h>
// Do not change: ATTOW, the pico audio lib worked only @ 22050 Hz sampling frequency
#define SAMPLE_FREQ_IN_HZ (22050)
#define SEND_LOOP_DEBUG (1) // For debug
audio_buffer_pool_t* init_audio(uint sample_freq_in_hz, uint16_t audio_buffer_format)
{
const int NUM_AUDIO_BUFFERS = 3;
const int SAMPLES_PER_BUFFER = 256;
const audio_format_t audio_format = {.format = audio_buffer_format,
.sample_freq = sample_freq_in_hz,
.channel_count = 1};
audio_buffer_format_t producer_format = {.format = &audio_format,
.sample_stride = 2};
audio_buffer_pool_t* producer_pool = audio_new_producer_pool(&producer_format, NUM_AUDIO_BUFFERS, SAMPLES_PER_BUFFER);
if (!audio_pwm_setup(&audio_format, -1, &default_mono_channel_config))
{
panic("PicoAudio: Unable to open audio device.\n");
}
bool __unused is_ok = audio_pwm_default_connect(producer_pool, false);
assert(is_ok);
audio_pwm_set_enabled(true);
return producer_pool;
}
static void init(uint sample_freq_in_hz)
{
// NOTE: ATTOW, the pico audio lib worked only @ 22050 Hz sampling frequency,
// related to 48 MHz system clock
const uint SAMPLING_FREQ_REF_IN_HZ = 22050;
const uint SYSTEM_CLOCK_REF_IN_KHZ = 48000;
if (sample_freq_in_hz == SAMPLING_FREQ_REF_IN_HZ)
{
set_sys_clock_48mhz();
}
else
{
// Compensate a non-reference sampling frequency by a different system clock frequency
// To be improved: System clock may be imprecise
// set_sys_clock_khz((uint32_t)((float)SYSTEM_CLOCK_REF_IN_KHZ * (float)sample_freq_in_hz / (float)SAMPLING_FREQ_REF_IN_HZ), false);
set_sys_clock_khz(105000, false); // HACK
}
stdio_init_all();
}
static void fill_audio_buffer(audio_buffer_pool_t* audio_pool, const int16_t* pcm_data, uint num_samples)
{
uint pos = 0u;
const uint8_t volume = 128u;
while (true)
{
audio_buffer_t* buffer = take_audio_buffer(audio_pool, true);
int16_t* samples = (int16_t*)buffer->buffer->bytes;
for (uint i = 0u; i < buffer->max_sample_count; i++)
{
samples[i] = (volume * pcm_data[pos]) >> 8u;
pos++;
if (pos == num_samples)
{
pos = 0u;
}
}
buffer->sample_count = buffer->max_sample_count;
give_audio_buffer(audio_pool, buffer);
}
}
// Test tone: 1 kHz sine wave
static void send1kHz(uint sample_freq_in_hz)
{
init(sample_freq_in_hz);
const uint tone_freq_in_hz = 1000u;
const uint num_samples = sample_freq_in_hz / tone_freq_in_hz;
int16_t* sine_wave_table = malloc(num_samples * sizeof(int16_t));
if (!sine_wave_table)
{
panic("Out of memory: malloc() failed.\n");
}
for (uint i = 0u; i < num_samples; i++)
{
sine_wave_table[i] = 32767 * sinf(2.0f * (float)M_PI * (float)i / (float)num_samples);
}
audio_buffer_pool_t* audio_pool = init_audio(sample_freq_in_hz, AUDIO_BUFFER_FORMAT_PCM_S16);
while (true)
{
fill_audio_buffer(audio_pool, sine_wave_table, num_samples);
}
free(sine_wave_table);
}
static void sendAPRS_audioCallback(void* user_data, int16_t* pcm_data, size_t num_samples)
{
const uint aprs_sampl_freq_in_hz = *((const uint*)user_data);
audio_buffer_pool_t* audio_pool = init_audio(aprs_sampl_freq_in_hz, AUDIO_BUFFER_FORMAT_PCM_S16);
#if (SEND_LOOP_DEBUG == 1)
while (true)
{
#endif // SEND_LOOP_DEBUG
fill_audio_buffer(audio_pool, pcm_data, num_samples);
#if (SEND_LOOP_DEBUG == 1)
}
#endif // SEND_LOOP_DEBUG
}
static void sendAPRS(const char* call_sign_src,
const char* call_sign_dst,
const char* aprs_path_1,
const char* aprs_path_2,
const char* aprs_message,
const double latitude_in_deg,
const double longitude_in_deg,
const double altitude_in_m)
{
static const uint APRS_SAMPL_FREQ_IN_HZ = 48000u;
init(APRS_SAMPL_FREQ_IN_HZ);
ax25_beacon((void*)&APRS_SAMPL_FREQ_IN_HZ, // User data
sendAPRS_audioCallback,
call_sign_src,
call_sign_dst,
aprs_path_1,
aprs_path_2,
latitude_in_deg,
longitude_in_deg,
altitude_in_m,
aprs_message,
'/', 'O');
}
int main()
{
// send1kHz(SAMPLE_FREQ_IN_HZ); // For test & debug
// Send an APRS test message
sendAPRS("SRC", // Src call sign
"DST", // Dst call sign
"PATH1",
"PATH2",
"Test message",
10.0, // Lat in deg
20.0, // Long in deg
100.0 // Alt in m
);
return 0;
}