Merge pull request #18 from paulh002/master

update SoapyRadioberry
pull/19/head^2
Johan 2022-01-06 20:32:08 +01:00 zatwierdzone przez GitHub
commit 5d901af759
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 544 dodań i 50 usunięć

Wyświetl plik

@ -37,6 +37,8 @@ SOAPY_SDR_MODULE_UTIL(
SoapyRadioberry.cpp
SoapyRadioberrySettings.cpp
SoapyRadioberryStreaming.cpp
i2c.cpp
i2c.h
radioberry_ioctl.h
)

Wyświetl plik

@ -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;
};

Wyświetl plik

@ -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.

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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( &reg, 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( &reg, 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

Wyświetl plik

@ -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_ */

Wyświetl plik

@ -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;