kopia lustrzana https://github.com/pa3gsb/Radioberry-2.x
commit
5d901af759
|
@ -37,6 +37,8 @@ SOAPY_SDR_MODULE_UTIL(
|
|||
SoapyRadioberry.cpp
|
||||
SoapyRadioberrySettings.cpp
|
||||
SoapyRadioberryStreaming.cpp
|
||||
i2c.cpp
|
||||
i2c.h
|
||||
radioberry_ioctl.h
|
||||
|
||||
)
|
||||
|
|
|
@ -7,9 +7,19 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string.h>
|
||||
#include "radioberry_ioctl.h"
|
||||
#include "i2c.h"
|
||||
|
||||
#define TX_MAX 4800
|
||||
#define TX_MAX_BUFFER (TX_MAX * 8)
|
||||
const int npackages = 4;
|
||||
|
||||
typedef enum radioberrysdrStreamFormat {
|
||||
RADIOBERRY_SDR_CF32,
|
||||
RADIOBERRY_SDR_CS16
|
||||
} radioberrysdrStreamFormat;
|
||||
|
||||
class SoapyRadioberry : public SoapySDR::Device{
|
||||
|
||||
|
@ -62,9 +72,6 @@ class SoapyRadioberry : public SoapySDR::Device{
|
|||
long long &timeNs,
|
||||
const long timeoutUs = 100000 );
|
||||
|
||||
|
||||
|
||||
/*
|
||||
int writeStream(
|
||||
SoapySDR::Stream *stream,
|
||||
const void * const *buffs,
|
||||
|
@ -74,8 +81,6 @@ class SoapyRadioberry : public SoapySDR::Device{
|
|||
const long timeoutUs = 100000);
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/*******************************************************************
|
||||
* Sample Rate API
|
||||
******************************************************************/
|
||||
|
@ -86,6 +91,7 @@ class SoapyRadioberry : public SoapySDR::Device{
|
|||
|
||||
|
||||
std::vector<double> listBandwidths( const int direction, const size_t channel ) const;
|
||||
std::vector<double> listSampleRates( const int direction, const size_t channel ) const;
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
|
@ -117,18 +123,29 @@ class SoapyRadioberry : public SoapySDR::Device{
|
|||
|
||||
void setGain( const int direction, const size_t channel, const double value );
|
||||
|
||||
SoapySDR::Range getGainRange( const int direction, const size_t channel) const;
|
||||
SoapySDR::Range getGainRange( const int direction, const size_t channel ) const;
|
||||
|
||||
|
||||
void controlRadioberry(uint32_t command, uint32_t command_data);
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* I2C API
|
||||
******************************************************************/
|
||||
|
||||
std::string readI2C(const int addr, const size_t numBytes);
|
||||
void writeI2C(const int addr, const std::string &data);
|
||||
|
||||
private:
|
||||
|
||||
int fd_rb;
|
||||
|
||||
int sample_rate;
|
||||
int rx_frequency;
|
||||
|
||||
struct rb_info_arg_t rb_control;
|
||||
|
||||
int fd_rb;
|
||||
int sample_rate;
|
||||
int rx_frequency;
|
||||
int no_channels;
|
||||
struct rb_info_arg_t rb_control;
|
||||
std::unique_ptr<rpihw::driver::i2c> i2c_ptr;
|
||||
bool i2c_available = false;
|
||||
radioberrysdrStreamFormat streamFormat;
|
||||
uint32_t m_count;
|
||||
uint32_t m_highwater, m_lowwater;
|
||||
__useconds_t m_sleep;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "SoapyRadioberry.hpp"
|
||||
|
||||
#define RADIOBERRY_BUFFER_SIZE 4096
|
||||
|
||||
/***********************************************************************
|
||||
* Device interface
|
||||
|
@ -9,7 +10,23 @@ SoapyRadioberry::SoapyRadioberry( const SoapySDR::Kwargs &args ){
|
|||
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::SoapyRadioberry constructor called");
|
||||
|
||||
no_channels = 1;
|
||||
m_count = 0;
|
||||
m_lowwater = RADIOBERRY_BUFFER_SIZE / 3;
|
||||
m_highwater = (RADIOBERRY_BUFFER_SIZE * 2) / 3 ; // assume 64 K buffer
|
||||
m_sleep = (__useconds_t)(1000000.0 / 48000.0 * (double)(m_highwater - m_lowwater));
|
||||
m_sleep = m_sleep - m_sleep / 10;
|
||||
fd_rb = open("/dev/radioberry", O_RDWR);
|
||||
try
|
||||
{
|
||||
i2c_ptr = std::make_unique<rpihw::driver::i2c> (rpihw::driver::i2c("/dev/i2c-1"));
|
||||
i2c_available = true;
|
||||
}
|
||||
catch (std::string s)
|
||||
{
|
||||
printf("I2c not found %s", s.c_str());
|
||||
i2c_available = false;
|
||||
}
|
||||
}
|
||||
|
||||
SoapyRadioberry::~SoapyRadioberry(void){
|
||||
|
@ -26,11 +43,11 @@ void SoapyRadioberry::controlRadioberry(uint32_t command, uint32_t command_data)
|
|||
uint32_t CWX =0;
|
||||
uint32_t running = 1;
|
||||
|
||||
rb_control.rb_command = (((CWX << 1) & 0x02) | (running & 0x01));
|
||||
rb_control.rb_command = 0x04 | (((CWX << 1) & 0x02) | (running & 0x01));
|
||||
rb_control.command = command;
|
||||
rb_control.command_data = command_data;
|
||||
|
||||
fprintf(stderr, "Command = %02X command_data = %08X\n", command, command_data);
|
||||
fprintf(stderr, "RB-Command = %02X Command = %02X command_data = %08X\n", rb_control.rb_command, command, command_data);
|
||||
|
||||
if (ioctl(fd_rb, RADIOBERRY_IOC_COMMAND, &rb_control) == -1) {
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "Could not sent command to radioberry device.");
|
||||
|
@ -48,7 +65,7 @@ std::string SoapyRadioberry::getHardwareKey( void ) const
|
|||
{
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getHardwareKey called");
|
||||
|
||||
return "v2.0-beta4";
|
||||
return "v2.0-beta5";
|
||||
}
|
||||
|
||||
SoapySDR::Kwargs SoapyRadioberry::getHardwareInfo( void ) const
|
||||
|
@ -116,6 +133,27 @@ std::vector<double> SoapyRadioberry::listBandwidths( const int direction, const
|
|||
options.push_back(0.048e6);
|
||||
options.push_back(0.096e6);
|
||||
options.push_back(0.192e6);
|
||||
options.push_back(0.384e6);
|
||||
}
|
||||
if (direction == SOAPY_SDR_TX) {
|
||||
options.push_back(0.048e6);
|
||||
}
|
||||
return(options);
|
||||
}
|
||||
|
||||
std::vector<double> SoapyRadioberry::listSampleRates( const int direction, const size_t channel ) const
|
||||
{
|
||||
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::listSampleRates called");
|
||||
|
||||
|
||||
std::vector<double> options;
|
||||
|
||||
if (direction == SOAPY_SDR_RX) {
|
||||
options.push_back(0.048e6);
|
||||
options.push_back(0.096e6);
|
||||
options.push_back(0.192e6);
|
||||
options.push_back(0.384e6);
|
||||
}
|
||||
if (direction == SOAPY_SDR_TX) {
|
||||
options.push_back(0.048e6);
|
||||
|
@ -179,14 +217,13 @@ std::vector<std::string> SoapyRadioberry::listGains( const int direction, const
|
|||
return(options);
|
||||
}
|
||||
|
||||
SoapySDR::Range SoapyRadioberry::getGainRange( const int direction, const size_t channel ) const
|
||||
SoapySDR::Range SoapyRadioberry::getGainRange( const int direction, const size_t channel) const
|
||||
{
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::getGainRange called");
|
||||
|
||||
if(direction==SOAPY_SDR_RX)
|
||||
return(SoapySDR::Range(0, 60));
|
||||
return(SoapySDR::Range(0,18));
|
||||
|
||||
return(SoapySDR::Range(-12, 48));
|
||||
return(SoapySDR::Range(0,15));
|
||||
}
|
||||
|
||||
void SoapyRadioberry::setGain( const int direction, const size_t channel, const double value ) {
|
||||
|
@ -194,10 +231,22 @@ void SoapyRadioberry::setGain( const int direction, const size_t channel, const
|
|||
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::setGain called");
|
||||
|
||||
uint32_t command = 0;
|
||||
uint32_t command_data = 0x40100000 + (0x40 | (((uint32_t) (value + 12.0)) & 0x3F));
|
||||
uint32_t command_data = (0x40 | (((uint32_t)value) & 0x3F));
|
||||
|
||||
if(direction==SOAPY_SDR_RX) command = 0x14;
|
||||
if(direction==SOAPY_SDR_TX) { command = 2; }
|
||||
if (direction == SOAPY_SDR_RX)
|
||||
{
|
||||
command = 0x14;
|
||||
command_data = (0x40 | (((uint32_t)value + 12) & 0x3F));
|
||||
}
|
||||
if(direction==SOAPY_SDR_TX)
|
||||
{ // 0 -7 TX RF gain
|
||||
uint32_t z = (uint32_t)value;
|
||||
if (value > 15) z = 15;
|
||||
if (value < 0.0) z = 0;
|
||||
z = z << 28;
|
||||
command = 0x13;
|
||||
command_data = z;
|
||||
}
|
||||
|
||||
this->SoapyRadioberry::controlRadioberry(command, command_data);
|
||||
}
|
||||
|
@ -219,4 +268,43 @@ void SoapyRadioberry::setFrequency( const int direction, const size_t channel,
|
|||
this->SoapyRadioberry::controlRadioberry(command, command_data);
|
||||
}
|
||||
|
||||
// end of source.
|
||||
void SoapyRadioberry::writeI2C(const int addr, const std::string &data)
|
||||
{
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::writeI2C called");
|
||||
|
||||
if (!i2c_available)
|
||||
return;
|
||||
i2c_ptr->addr(addr);
|
||||
try
|
||||
{
|
||||
i2c_ptr->write((uint8_t *)data.c_str(), data.size());
|
||||
}
|
||||
catch (std::string s)
|
||||
{
|
||||
printf("%s", s.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string SoapyRadioberry::readI2C(const int addr, const size_t numBytes)
|
||||
{
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::readI2C called");
|
||||
|
||||
std::string data;
|
||||
|
||||
if (!i2c_available)
|
||||
return std::string("");
|
||||
i2c_ptr->addr(addr);
|
||||
data.reserve(numBytes);
|
||||
try
|
||||
{
|
||||
i2c_ptr->read((uint8_t *)data.c_str(), numBytes);
|
||||
data.resize(numBytes);
|
||||
}
|
||||
catch (std::string s)
|
||||
{
|
||||
printf("%s", s.c_str());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
// end of source.
|
||||
|
||||
|
|
|
@ -1,9 +1,37 @@
|
|||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdint.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include "SoapyRadioberry.hpp"
|
||||
|
||||
void SoapyRadioberry::setSampleRate( const int direction, const size_t channel, const double rate ) {
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::setSampleRate called");
|
||||
|
||||
this->SoapyRadioberry::controlRadioberry(0, 0x00000004);
|
||||
int irate = floor(rate);
|
||||
uint32_t ucom =0x00000004;
|
||||
uint32_t command = 0;
|
||||
|
||||
if (direction == SOAPY_SDR_TX)
|
||||
{
|
||||
command = 1;
|
||||
ucom = 0x00000004;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rate < 48001.0)
|
||||
ucom = 0x00000004;
|
||||
if (rate > 48000.0 && rate < 96001.0)
|
||||
ucom = 0x01000004;
|
||||
if (rate > 96000.0 && rate < 192001.0)
|
||||
ucom = 0x02000004;
|
||||
if (rate > 192000.0)
|
||||
ucom = 0x03000004;
|
||||
}
|
||||
|
||||
this->SoapyRadioberry::controlRadioberry(command, ucom);
|
||||
}
|
||||
|
||||
SoapySDR::RangeList SoapyRadioberry::getSampleRateRange(const int direction, const size_t channel) const
|
||||
|
@ -13,8 +41,8 @@ SoapySDR::RangeList SoapyRadioberry::getSampleRateRange(const int direction, con
|
|||
|
||||
SoapySDR::RangeList rangeList;
|
||||
|
||||
if (direction == SOAPY_SDR_RX) rangeList.push_back(SoapySDR::Range(48000.0, 192000.0, 1.0));
|
||||
if (direction == SOAPY_SDR_TX) rangeList.push_back(SoapySDR::Range(48000.0, 48000.0, 1.0));
|
||||
if (direction == SOAPY_SDR_RX) rangeList.push_back(SoapySDR::Range(48000.0, 384000.0, 48000.0));
|
||||
if (direction == SOAPY_SDR_TX) rangeList.push_back(SoapySDR::Range(48000.0, 48000.0, 48000.0));
|
||||
|
||||
return rangeList;
|
||||
}
|
||||
|
@ -26,6 +54,7 @@ std::vector<std::string> SoapyRadioberry::getStreamFormats(const int direction,
|
|||
std::vector<std::string> formats;
|
||||
|
||||
formats.push_back(SOAPY_SDR_CF32);
|
||||
formats.push_back(SOAPY_SDR_CS16);
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
@ -60,6 +89,9 @@ SoapySDR::ArgInfoList SoapyRadioberry::getStreamArgsInfo(const int direction, co
|
|||
return streamArgs;
|
||||
}
|
||||
|
||||
auto startTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
|
||||
SoapySDR::Stream *SoapyRadioberry::setupStream(
|
||||
const int direction,
|
||||
const std::string &format,
|
||||
|
@ -67,12 +99,21 @@ SoapySDR::Stream *SoapyRadioberry::setupStream(
|
|||
const SoapySDR::Kwargs &args )
|
||||
{
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "SoapyRadioberry::setupStream called");
|
||||
|
||||
startTime = std::chrono::high_resolution_clock::now();
|
||||
//check the format
|
||||
if (format == SOAPY_SDR_CF32) {
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "Using format CF32.");
|
||||
streamFormat = RADIOBERRY_SDR_CF32;
|
||||
}
|
||||
else {
|
||||
else if(format == SOAPY_SDR_CS16 && direction == SOAPY_SDR_TX)
|
||||
{
|
||||
SoapySDR_log(SOAPY_SDR_INFO, "Using format CS16.");
|
||||
streamFormat = RADIOBERRY_SDR_CS16;
|
||||
m_count = 0;
|
||||
printf("sleep %d\n", m_sleep);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"setupStream invalid format '" + format + "' -- Only CF32 is supported by SoapyRadioberrySDR module.");
|
||||
}
|
||||
|
@ -91,28 +132,132 @@ int SoapyRadioberry::readStream(
|
|||
{
|
||||
int i;
|
||||
int iq = 0;
|
||||
int16_t left_sample;
|
||||
int16_t right_sample;
|
||||
int nr_samples;
|
||||
|
||||
void *buff_base = buffs[0];
|
||||
float *target_buffer = (float *) buff_base;
|
||||
int16_t *itarget_buffer = (int16_t *) buff_base;
|
||||
|
||||
char rx_buffer[512];
|
||||
for(int ii = 0 ; ii < npackages ; ii++)
|
||||
{
|
||||
nr_samples = read(fd_rb, rx_buffer, sizeof(rx_buffer));
|
||||
//printf("nr_samples %d sample: %d %d %d %d %d %d\n",nr_samples, (int)rx_buffer[0],(int)rx_buffer[1],(int)rx_buffer[2],(int)rx_buffer[3],(int)rx_buffer[4],(int)rx_buffer[5]);
|
||||
if(streamFormat == RADIOBERRY_SDR_CF32)
|
||||
{
|
||||
for (i = 0; i < nr_samples; i += 6) {
|
||||
left_sample = (int)((signed char) rx_buffer[i]) << 16;
|
||||
left_sample |= (int)((((unsigned char)rx_buffer[i + 1]) << 8) & 0xFF00);
|
||||
left_sample |= (int)((unsigned char)rx_buffer[i + 2] & 0xFF);
|
||||
right_sample = (int)((signed char)rx_buffer[i + 3]) << 16;
|
||||
right_sample |= (int)((((unsigned char)rx_buffer[i + 4]) << 8) & 0xFF00);
|
||||
right_sample |= (int)((unsigned char)rx_buffer[i + 5] & 0xFF);
|
||||
right_sample = right_sample * -1;
|
||||
|
||||
target_buffer[iq++] = (float)left_sample / 2048.0; // 12 bit sample
|
||||
target_buffer[iq++] = (float)right_sample / 2048.0; // 12 bit sample
|
||||
//printf("nr_samples %d sample: %d %d \n", nr_samples, left_sample, right_sample);
|
||||
}
|
||||
}
|
||||
if (streamFormat == RADIOBERRY_SDR_CS16)
|
||||
{
|
||||
for (i = 0; i < nr_samples; i += 6) {
|
||||
left_sample = (int16_t)((signed char) rx_buffer[i]) << 16;
|
||||
left_sample |= (int16_t)((((unsigned char)rx_buffer[i + 1]) << 8) & 0xFF00);
|
||||
left_sample |= (int16_t)((unsigned char)rx_buffer[i + 2] & 0xFF);
|
||||
right_sample = (int16_t)((signed char)rx_buffer[i + 3]) << 16;
|
||||
right_sample |= (int16_t)((((unsigned char)rx_buffer[i + 4]) << 8) & 0xFF00);
|
||||
right_sample |= (int16_t)((unsigned char)rx_buffer[i + 5] & 0xFF);
|
||||
right_sample = right_sample * -1;
|
||||
|
||||
itarget_buffer[iq++] = left_sample << 4; // 12 bit sample
|
||||
itarget_buffer[iq++] = right_sample << 4; // 12 bit sample
|
||||
}
|
||||
}
|
||||
}
|
||||
return (npackages * nr_samples / 6); //return the number of IQ samples
|
||||
}
|
||||
|
||||
union uTxBuffer
|
||||
{
|
||||
std::uint16_t i16TxBuffer[2];
|
||||
unsigned char i8TxBuffer[4];
|
||||
};
|
||||
|
||||
int SoapyRadioberry::writeStream(SoapySDR::Stream *stream, const void * const *buffs, const size_t numElems, int &flags, const long long timeNs, const long timeoutUs)
|
||||
{
|
||||
int iq = 0;
|
||||
size_t ret;
|
||||
int left_sample;
|
||||
int right_sample;
|
||||
int nr_samples;
|
||||
|
||||
void *buff_base = buffs[0];
|
||||
float *target_buffer = (float *) buff_base;
|
||||
void const *buff_base = buffs[0];
|
||||
float *target_buffer = (float *) buff_base;
|
||||
int16_t *itarget_buffer = (int16_t *) buff_base;
|
||||
|
||||
char rx_buffer[512];
|
||||
nr_samples = read(fd_rb , rx_buffer , sizeof(rx_buffer));
|
||||
|
||||
for(i=0; i< nr_samples ; i+=6) {
|
||||
left_sample = (int)((signed char) rx_buffer[i])<<16;
|
||||
left_sample |= (int)((((unsigned char)rx_buffer[i+1])<<8)&0xFF00);
|
||||
left_sample |= (int)((unsigned char)rx_buffer[i+2]&0xFF);
|
||||
right_sample = (int)((signed char)rx_buffer[i+3]) << 16;
|
||||
right_sample |= (int)((((unsigned char)rx_buffer[i+4])<<8)&0xFF00);
|
||||
right_sample |= (int)((unsigned char)rx_buffer[i+5]&0xFF);
|
||||
|
||||
target_buffer[iq++]=(float)left_sample/8388607.0; // 24 bit sample 2^23-1
|
||||
target_buffer[iq++]=(float)right_sample/8388607.0; // 24 bit sample 2^23-1
|
||||
|
||||
uTxBuffer tx;
|
||||
|
||||
if (streamFormat == RADIOBERRY_SDR_CF32)
|
||||
{
|
||||
for (int ii = 0; ii < numElems; ii++)
|
||||
{
|
||||
float i, q;
|
||||
int16_t di, dq;
|
||||
|
||||
tx.i16TxBuffer[0] = (int16_t)(target_buffer[iq++] * 16384.0f);
|
||||
tx.i16TxBuffer[1] = (int16_t)(target_buffer[iq++] * 16384.0f);
|
||||
ret = write(fd_rb, &tx, 4 * sizeof(uint8_t));
|
||||
m_count++;
|
||||
if (ret == 0)
|
||||
{
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::duration<double> timePassed = now - startTime;
|
||||
|
||||
printf("Time passed %4.2f radioberry buffer full count %d", timePassed.count(), m_count);
|
||||
fflush(NULL);
|
||||
}
|
||||
if(m_count > m_highwater)
|
||||
{
|
||||
m_count = m_lowwater;
|
||||
usleep(m_sleep);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (streamFormat == RADIOBERRY_SDR_CS16)
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
return (nr_samples / 6); //return the number of IQ samples
|
||||
}
|
||||
//printf("SoapySDR send %d elements count %d\n", numElems, m_count);
|
||||
for (int ii = 0; ii < numElems; ii++)
|
||||
{
|
||||
//printf("%x %x %x %x\n", (itarget_buffer[j] & 0xFF00) >> 8, (itarget_buffer[j] & 0x00FF), (itarget_buffer[j+1] & 0xFF00) >> 8, (itarget_buffer[j+1] & 0x00FF));
|
||||
|
||||
tx.i8TxBuffer[0] = (unsigned char)((itarget_buffer[j] & 0xff00) >> 8);
|
||||
tx.i8TxBuffer[1] = (unsigned char)(itarget_buffer[j] & 0xff);
|
||||
tx.i8TxBuffer[2] = (unsigned char)((itarget_buffer[j + 1] & 0xff00) >> 8);
|
||||
tx.i8TxBuffer[3] = (unsigned char)(itarget_buffer[j + 1] & 0xff);
|
||||
|
||||
ret = write(fd_rb, &tx, sizeof(uint32_t));
|
||||
j += 2;
|
||||
m_count++;
|
||||
// Measure the time until a high watermark apears
|
||||
if ((m_count > m_highwater) || (ret == 0))
|
||||
{
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
//auto timePassed = std::chrono::duration_cast<std::chrono::microseconds>(now - startTime);
|
||||
std::chrono::duration<double> timePassed = now - startTime;
|
||||
//printf("Time passed %4.2f micro seconds\n", timePassed.count() * 1000000.0);
|
||||
m_count = m_lowwater;
|
||||
startTime = std::chrono::high_resolution_clock::now();
|
||||
// Time to sleep is 1/3 of buffer times 50 uSec
|
||||
|
||||
usleep(m_sleep); // (1/48K about 20usec /sample * difference between high and low water mark)
|
||||
}
|
||||
}
|
||||
}
|
||||
return numElems;
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
Title --- driver/i2c.cpp
|
||||
|
||||
Copyright (C) 2013 Giacomo Trudu - wicker25[at]gmail[dot]com
|
||||
|
||||
This file is part of Rpi-hw.
|
||||
|
||||
Rpi-hw is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation version 3 of the License.
|
||||
|
||||
Rpi-hw 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with Rpi-hw. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
namespace rpihw { // Begin main namespace
|
||||
|
||||
namespace driver { // Begin drivers namespace
|
||||
|
||||
i2c::i2c( const std::string &dev_path)
|
||||
: m_dev_path ( dev_path )
|
||||
{
|
||||
|
||||
// Open device file
|
||||
m_dev_fd = open( m_dev_path.c_str(), O_RDWR );
|
||||
|
||||
if ( m_dev_fd < 0 )
|
||||
throw "(Fatal) `i2c`: can't open I2C device \n" ;
|
||||
|
||||
}
|
||||
|
||||
void i2c::addr(uint8_t addr)
|
||||
{
|
||||
m_addr = addr;
|
||||
// Select slave device
|
||||
if(ioctl(m_dev_fd, I2C_SLAVE, addr) < 0)
|
||||
throw "(Fatal) `i2c`: can't select slave device \n";
|
||||
}
|
||||
|
||||
i2c::~i2c() {
|
||||
|
||||
// Close the device file
|
||||
close( m_dev_fd );
|
||||
}
|
||||
|
||||
void
|
||||
i2c::write( uint8_t *data, uint8_t size ) {
|
||||
|
||||
if ( ::write( m_dev_fd, data, size ) != size )
|
||||
throw "(Fatal) `i2c`: failed to write to the bus\n";
|
||||
}
|
||||
|
||||
void
|
||||
i2c::read( uint8_t *data, uint8_t size ) {
|
||||
|
||||
if ( ::read( m_dev_fd, data, size ) != size )
|
||||
throw "(Fatal) `i2c`: failed to read from the bus\n";
|
||||
}
|
||||
|
||||
void
|
||||
i2c::writeReg8( uint8_t reg, uint8_t data ) {
|
||||
|
||||
// Build the buffer to send
|
||||
m_buffer[0] = reg;
|
||||
m_buffer[1] = data;
|
||||
|
||||
// Write the data on the device
|
||||
write( m_buffer, 2 );
|
||||
}
|
||||
|
||||
uint8_t
|
||||
i2c::readReg8( uint8_t reg ) {
|
||||
|
||||
// Select the register on the device
|
||||
write( ®, 1 );
|
||||
|
||||
// Read the data from the device
|
||||
read( m_buffer, 1 );
|
||||
|
||||
return m_buffer[0];
|
||||
}
|
||||
|
||||
void
|
||||
i2c::writeReg16( uint8_t reg, uint16_t data ) {
|
||||
|
||||
// Build the buffer to send
|
||||
m_buffer[0] = reg;
|
||||
m_buffer[1] = data & 0xFF;
|
||||
m_buffer[2] = (data >> 8) & 0xFF;
|
||||
|
||||
// Write the data on the device
|
||||
write( m_buffer, 2 );
|
||||
}
|
||||
|
||||
uint16_t
|
||||
i2c::readReg16( uint8_t reg ) {
|
||||
|
||||
// Select the register on the device
|
||||
write( ®, 1 );
|
||||
|
||||
// Read the data from the device
|
||||
read( m_buffer, 2 );
|
||||
|
||||
// Merge the 16 bit data
|
||||
return (uint16_t) m_buffer[0] | ( (uint16_t) m_buffer[1] << 8 );
|
||||
}
|
||||
|
||||
} // End of drivers namespace
|
||||
|
||||
} // End of main namespace
|
||||
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
Title --- driver/i2c.hpp
|
||||
|
||||
Copyright (C) 2013 Giacomo Trudu - wicker25[at]gmail[dot]com
|
||||
|
||||
This file is part of Rpi-hw.
|
||||
|
||||
Rpi-hw is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation version 3 of the License.
|
||||
|
||||
Rpi-hw 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with Rpi-hw. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _RPI_HW_DRIVER_I2C_HPP_
|
||||
#define _RPI_HW_DRIVER_I2C_HPP_
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace rpihw { // Begin main namespace
|
||||
|
||||
namespace driver { // Begin drivers namespace
|
||||
|
||||
/*!
|
||||
@class i2c
|
||||
@brief Inter Integrated Circuit.
|
||||
*/
|
||||
class i2c {
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
@brief Constructor method.
|
||||
@param[in] dev_path The device path.
|
||||
@param[in] addr The I2C slave address.
|
||||
*/
|
||||
i2c( const std::string &dev_path);
|
||||
void addr(uint8_t addr);
|
||||
|
||||
//! Destructor method.
|
||||
virtual ~i2c();
|
||||
|
||||
/*!
|
||||
@brief Writes data on the device.
|
||||
@param[in] data The data to write on the device.
|
||||
@param[in] size Size of the data to write.
|
||||
*/
|
||||
void write( uint8_t *data, uint8_t size );
|
||||
|
||||
/*!
|
||||
@brief Reads data from the device.
|
||||
@param[in] data The buffer to store the data.
|
||||
@param[in] size Size of the data to read.
|
||||
*/
|
||||
void read( uint8_t *data, uint8_t size );
|
||||
|
||||
/*!
|
||||
@brief Writes a byte data to a register on the device.
|
||||
@param[in] reg The device register.
|
||||
@param[in] data The data to write to the register.
|
||||
*/
|
||||
void writeReg8( uint8_t reg, uint8_t data );
|
||||
|
||||
/*!
|
||||
@brief Reads a byte from a register on the device.
|
||||
@param[in] reg The device register.
|
||||
@return The data read from the register.
|
||||
*/
|
||||
uint8_t readReg8( uint8_t reg );
|
||||
|
||||
/*!
|
||||
@brief Writes a word data to a register on the device.
|
||||
@param[in] reg The device register.
|
||||
@param[in] data The data to write to the register.
|
||||
*/
|
||||
void writeReg16( uint8_t reg, uint16_t data );
|
||||
|
||||
/*!
|
||||
@brief Reads a word from a register on the device.
|
||||
@param[in] reg The device register.
|
||||
@return The data read from the register.
|
||||
*/
|
||||
uint16_t readReg16( uint8_t reg );
|
||||
|
||||
private:
|
||||
|
||||
//! The device path.
|
||||
std::string m_dev_path;
|
||||
|
||||
//! The I2C slave address.
|
||||
uint32_t m_addr;
|
||||
|
||||
//! File descriptor of the device.
|
||||
int m_dev_fd;
|
||||
|
||||
//! Data buffer used for I2C transmission.
|
||||
uint8_t m_buffer[3];
|
||||
};
|
||||
|
||||
} // End of drivers namespace
|
||||
|
||||
} // End of main namespace
|
||||
|
||||
|
||||
// Include inline methods
|
||||
//#include <rpi-hw/driver/i2c-inl.hpp>
|
||||
|
||||
#endif /* _RPI_HW_DRIVER_I2C_HPP_ */
|
|
@ -10,11 +10,11 @@
|
|||
|
||||
struct rb_info_arg_t
|
||||
{
|
||||
int major, minor;
|
||||
int major, minor;
|
||||
|
||||
int fpga;
|
||||
|
||||
float version;
|
||||
int version;
|
||||
|
||||
int rb_command;
|
||||
int command;
|
||||
|
|
Ładowanie…
Reference in New Issue