mirror of
https://github.com/niellun/FastCarPlay.git
synced 2026-06-07 09:38:25 +02:00
168 lines
4.1 KiB
C++
168 lines
4.1 KiB
C++
#include <chrono>
|
|
#include <thread>
|
|
#include <csignal>
|
|
#include <iostream>
|
|
#include <cstring>
|
|
#include <fcntl.h>
|
|
#include <cstdint>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/spi/spidev.h>
|
|
#include <pulse/simple.h>
|
|
#include <pulse/error.h>
|
|
|
|
using namespace std;
|
|
using namespace chrono;
|
|
|
|
#define SPI_DEVICE "/dev/spidev0.0"
|
|
#define SPI_SPEED_HZ 4000000
|
|
#define ADC_RATE 16000
|
|
#define BLOCK_SIZE 4096
|
|
#define ALPHA 1
|
|
#define CORR_POWER 0.1
|
|
|
|
volatile bool active = true;
|
|
int spi_fd = -1;
|
|
pa_simple *pa_handle = nullptr;
|
|
|
|
double filtered = 0.0;
|
|
double correction = 0.0;
|
|
|
|
uint8_t tx[2] = {0, 0}, rx[2] = {0, 0};
|
|
|
|
struct spi_ioc_transfer tr = {
|
|
.tx_buf = (unsigned long)tx,
|
|
.rx_buf = (unsigned long)rx,
|
|
.len = 2,
|
|
.speed_hz = SPI_SPEED_HZ,
|
|
.bits_per_word = 8};
|
|
|
|
void handler(int sig)
|
|
{
|
|
active = false;
|
|
}
|
|
|
|
void init_pulse()
|
|
{
|
|
pa_sample_spec ss = {
|
|
.format = PA_SAMPLE_S16LE,
|
|
.rate = ADC_RATE,
|
|
.channels = 1};
|
|
|
|
pa_buffer_attr ba = {
|
|
.maxlength = BLOCK_SIZE * sizeof(int16_t) * 4,
|
|
.tlength = BLOCK_SIZE * sizeof(int16_t),
|
|
.prebuf = BLOCK_SIZE * sizeof(int16_t) * 2,
|
|
.minreq = BLOCK_SIZE * sizeof(int16_t)};
|
|
|
|
int error;
|
|
pa_handle = pa_simple_new(nullptr, "ADS8320", PA_STREAM_PLAYBACK, nullptr, "ADC", &ss, nullptr, &ba, &error);
|
|
if (!pa_handle)
|
|
{
|
|
std::cerr << "PulseAudio error: " << pa_strerror(error) << std::endl;
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void spi_init()
|
|
{
|
|
spi_fd = open(SPI_DEVICE, O_RDWR);
|
|
if (spi_fd < 0)
|
|
{
|
|
std::cerr << "SPI error: " << strerror(errno) << std::endl;
|
|
exit(1);
|
|
}
|
|
|
|
uint8_t mode = SPI_MODE_0;
|
|
uint8_t bits = 8;
|
|
uint32_t speed = SPI_SPEED_HZ;
|
|
if (ioctl(spi_fd, SPI_IOC_WR_MODE, &mode) < 0)
|
|
{
|
|
std::cerr << "SPI mode error: " << strerror(errno) << std::endl;
|
|
exit(1);
|
|
}
|
|
if (ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0)
|
|
{
|
|
std::cerr << "SPI bits error: " << strerror(errno) << std::endl;
|
|
exit(1);
|
|
}
|
|
if (ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0)
|
|
{
|
|
std::cerr << "SPI speed error: " << strerror(errno) << std::endl;
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
int16_t spi_read()
|
|
{
|
|
ioctl(spi_fd, SPI_IOC_MESSAGE(1), &tr);
|
|
|
|
uint32_t raw = (rx[0] << 11) | ((rx[1]) << 1);
|
|
return static_cast<int16_t>(raw+INT16_MIN);
|
|
}
|
|
|
|
int main()
|
|
{
|
|
signal(SIGINT, handler);
|
|
signal(SIGTERM, handler);
|
|
|
|
spi_init();
|
|
init_pulse();
|
|
|
|
steady_clock::time_point next = steady_clock::now();
|
|
const duration<double> step(1.0 / ADC_RATE);
|
|
const steady_clock::duration step_duration = duration_cast<steady_clock::duration>(step);
|
|
|
|
int16_t buffer[BLOCK_SIZE];
|
|
while (active)
|
|
{
|
|
int min_val = INT16_MAX;
|
|
int max_val = INT16_MIN;
|
|
double sum = 0.0;
|
|
|
|
auto block_start = steady_clock::now();
|
|
for (int i = 0; i < BLOCK_SIZE && active; i++)
|
|
{
|
|
steady_clock::time_point now = steady_clock::now();
|
|
if (now < next)
|
|
std::this_thread::sleep_until(next);
|
|
|
|
int16_t sample = spi_read();
|
|
//filtered = ALPHA * sample + (1 - ALPHA) * filtered;
|
|
buffer[i] = sample;
|
|
|
|
if(sample<min_val)
|
|
min_val=sample;
|
|
if(sample>max_val)
|
|
max_val=sample;
|
|
|
|
sum += sample;
|
|
next += step_duration;
|
|
}
|
|
|
|
int error;
|
|
if (pa_simple_write(pa_handle, buffer, BLOCK_SIZE * sizeof(int16_t), &error) < 0) {
|
|
std::cerr << "Pulse write error: " << pa_strerror(error) << std::endl;
|
|
}
|
|
|
|
double block_time = duration_cast<duration<double>>(steady_clock::now() - block_start).count();
|
|
|
|
double avg = sum / BLOCK_SIZE;
|
|
correction = correction + avg * CORR_POWER;
|
|
|
|
double voltage = avg / 32768.0 * 5;
|
|
|
|
printf("Block: %.4fs (expected: %.4fs) | min=%6d max=%6d corr=%8.1f avg=%8.1f → %.3fV \n",
|
|
block_time, BLOCK_SIZE * 1.0 / ADC_RATE, min_val, max_val, correction, avg, voltage);
|
|
}
|
|
|
|
if (pa_handle)
|
|
{
|
|
pa_simple_drain(pa_handle, nullptr);
|
|
pa_simple_free(pa_handle);
|
|
}
|
|
|
|
if (spi_fd >= 0)
|
|
close(spi_fd);
|
|
}
|
|
|