Program Code
Program Code
#include "transmitter.hpp"
#include "mailbox.hpp"
#include <bcm_host.h>
#include <thread>
#include <chrono>
#include <cmath>
#include <fcntl.h>
#include <sys/mman.h>
#define PWM_CHANNEL_RANGE 32
#define PWM_WRITES_PER_SAMPLE 10
struct ClockRegisters {
uint32_t ctl;
uint32_t div;
};
struct PWMRegisters {
uint32_t ctl;
uint32_t status;
uint32_t dmaConf;
uint32_t reserved0;
uint32_t chn1Range;
uint32_t chn1Data;
uint32_t fifoIn;
uint32_t reserved1;
uint32_t chn2Range;
uint32_t chn2Data;
};
struct DMAControllBlock {
uint32_t transferInfo;
uint32_t srcAddress;
uint32_t dstAddress;
uint32_t transferLen;
uint32_t stride;
uint32_t nextCbAddress;
uint32_t reserved0;
uint32_t reserved1;
};
struct DMARegisters {
uint32_t ctlStatus;
uint32_t cbAddress;
uint32_t transferInfo;
uint32_t srcAddress;
uint32_t dstAddress;
uint32_t transferLen;
uint32_t stride;
uint32_t nextCbAddress;
uint32_t debug;
};
class Peripherals
public:
virtual ~Peripherals() {
munmap(peripherals, GetSize());
return instance;
private:
Peripherals() {
int memFd;
close(memFd);
if (peripherals == MAP_FAILED) {
}
}
unsigned GetSize() {
if (size == BCM2711_PERI_VIRT_BASE) {
size = 0x01000000;
return size;
void *peripherals;
};
class AllocatedMemory
public:
AllocatedMemory() = delete;
AllocatedMemory(unsigned size) {
mBoxFd = mbox_open();
memSize = size;
if (memSize % PAGE_SIZE) {
if (!memHandle) {
mbox_close(mBoxFd);
memSize = 0;
virtual ~AllocatedMemory() {
unmapmem(memAllocated, memSize);
mem_unlock(mBoxFd, memHandle);
mem_free(mBoxFd, memHandle);
mbox_close(mBoxFd);
memSize = 0;
return reinterpret_cast<uintptr_t>(memAllocated);
private:
uintptr_t memAddress;
void *memAllocated;
int mBoxFd;
};
class Device
public:
Device() {
peripherals = &Peripherals::GetInstance();
}
Device(const Device &) = delete;
protected:
Peripherals *peripherals;
};
public:
ClockDevice() = delete;
std::this_thread::sleep_for(std::chrono::microseconds(100));
virtual ~ClockDevice() {
protected:
};
public:
ClockOutput() = delete;
#ifndef GPIO21
#else
#endif
virtual ~ClockOutput() {
#ifndef GPIO21
#else
#endif
return clock->div;
private:
};
public:
PWMController() = delete;
PWMController(unsigned sampleRate) : ClockDevice(PWMCLK_BASE_OFFSET,
static_cast<unsigned>(Peripherals::GetClockFrequency() * 1000000.f * (0x01 << 12) /
(PWM_WRITES_PER_SAMPLE * PWM_CHANNEL_RANGE * sampleRate))) {
pwm->ctl = 0x00000000;
std::this_thread::sleep_for(std::chrono::microseconds(100));
pwm->ctl = PWM_CTL_CLRF1;
std::this_thread::sleep_for(std::chrono::microseconds(100));
pwm->chn1Range = PWM_CHANNEL_RANGE;
virtual ~PWMController() {
pwm->ctl = 0x00000000;
return pwm->fifoIn;
private:
};
public:
DMAController() = delete;
dma->ctlStatus = DMA_CS_RESET;
std::this_thread::sleep_for(std::chrono::microseconds(100));
dma->cbAddress = address;
virtual ~DMAController() {
dma->ctlStatus = DMA_CS_RESET;
dma->cbAddress = address;
return dma->cbAddress;
private:
};
Transmitter::Transmitter()
: output(nullptr), enable(false)
Transmitter::~Transmitter() {
std::unique_lock<std::mutex> lock(mtx);
return !enable;
});
if (output) {
delete output;
std::lock_guard<std::mutex> lock(mtx);
enable = true;
delete output;
output = nullptr;
std::lock_guard<std::mutex> lock(mtx);
enable = false;
cv.notify_all();
};
try {
if (!output) {
if (dmaChannel != 0xff) {
} else {
} catch (...) {
finally();
throw;
finally();
void Transmitter::Stop()
std::unique_lock<std::mutex> lock(mtx);
enable = false;
lock.unlock();
cv.notify_all();
if (samples.empty()) {
return;
bufferSize = samples.size();
eof = true;
PWMController pwm(sampleRate);
unsigned cbOffset = 0;
dmaCb[cbOffset].srcAddress = allocated.GetPhysicalAddress(&clkDiv[i]);
dmaCb[cbOffset].dstAddress = peripherals.GetPhysicalAddress(&output->GetDivisor());
dmaCb[cbOffset].transferLen = sizeof(uint32_t);
dmaCb[cbOffset].stride = 0;
cbOffset++;
dmaCb[cbOffset].srcAddress = allocated.GetPhysicalAddress(pwmFifoData);
dmaCb[cbOffset].dstAddress = peripherals.GetPhysicalAddress(&pwm.GetFifoIn());
dmaCb[cbOffset].stride = 0;
cbOffset++;
*pwmFifoData = 0x00000000;
std::this_thread::sleep_for(std::chrono::microseconds(BUFFER_TIME / 10));
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
samples.clear();
};
try {
while (!eof) {
std::lock_guard<std::mutex> lock(mtx);
if (!enable) {
break;
if (!samples.size()) {
break;
cbOffset = 0;
std::this_thread::sleep_for(std::chrono::microseconds(BUFFER_TIME / 10));
cbOffset += 2;
} catch (...) {
finally();
throw;
}
finally();
std::vector<Sample> samples;
unsigned sampleOffset = 0;
std::lock_guard<std::mutex> lock(mtx);
stop = true;
cv.notify_all();
txThread.join();
samples.clear();
};
try {
while (!eof) {
std::unique_lock<std::mutex> lock(mtx);
if (!start) {
});
}
if (!enable) {
break;
if (stop) {
if (samples.empty()) {
break;
lock.unlock();
lock.lock();
if (samples.empty()) {
break;
lock.unlock();
cv.notify_all();
} else {
lock.unlock();
start = false;
} catch (...) {
finally();
throw;
finally();
}
try {
while (true) {
std::vector<Sample> loadedSamples;
std::unique_lock<std::mutex> lock(mtx);
});
if (*stop) {
break;
*sampleOffset = std::chrono::duration_cast<std::chrono::microseconds>(current -
playbackStart).count() * sampleRate / 1000000;
loadedSamples = std::move(*samples);
lock.unlock();
cv.notify_all();
unsigned offset = 0;
while (true) {
break;
}
std::this_thread::yield(); // asm("nop");
current = std::chrono::system_clock::now();
} catch (...) {
std::unique_lock<std::mutex> lock(mtx);
*stop = true;
lock.unlock();
cv.notify_all();